import NetService from '@/services/net.service' import { injectable, Service } from '@/services/service' import AMapLoader from '@amap/amap-jsapi-loader' import { useNotification } from 'naive-ui' import useStore from '@/pages/store/index' import carIcon from '@/assets/img/39.svg' @injectable export default class MapService extends Service { private netService = new NetService() private notification = useNotification() private store = useStore() private key = '' public Maps = null as Any public AMaps = null as Any public marks = {} as Any private getAllRings(feature: { geometry: { coordinates: Any[]; }; }) { const coords = feature.geometry.coordinates const rings = [] for (let i = 0, len = coords.length; i < len; i++) { rings.push(coords[i][0]) } return rings } private getLongestRing(feature: { geometry: { coordinates: Any[]; }; }) { const rings = this.getAllRings(feature) rings.sort((a, b) => b.length - a.length) return rings[0] } private colorRandom() { const r = Math.floor(Math.random() * 256) const g = Math.floor(Math.random() * 256) const b = Math.floor(Math.random() * 256) return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}` } // 添加标点 public addMark(position: number[], icon?: string, size?: { w: number, h: number }) { if (!this.Maps && !this.AMaps) return const mark = new this.AMaps!.Marker({ position, cursor: 'pointer', icon: new this.AMaps.Icon({ image: icon || carIcon, imageSize: new this.AMaps.Size(size?.w || 24, size?.h || 24) }), autoRotation: true, offset: new this.AMaps.Pixel(-5, -20), angle: 0, anchor: 'center', extData: '1'// 设置自定义属性 }) this.Maps.add(mark) return mark } // 添加路线 public addLine(path: number[][], color?: string, width?: number) { if (!this.Maps && !this.AMaps) return const polyline = new this.AMaps.Polyline({ path, strokeWeight: width || 5, borderWeight: width || 5, // 线条宽度,默认为 1 strokeColor: color || 'red', // 线条颜色 lineJoin: 'bevel', // 折线拐点连接处样式 geodesic: true }) this.Maps.add(polyline) return polyline } // 初始化地图 public _initMap(zoom: number) { window._AMapSecurityConfig = { securityJsCode: '184c86be3bbd9a8a941bcaaf6b09c7cd' } return new Promise((resolve, reject) => { AMapLoader.load({ key: '0c5c83112cafefa77154769b4433c3df', version: '2.0', plugins: [ 'AMap.DistrictSearch', 'AMap.Weather', 'AMap.Bounds', 'AMap.Driving' ], AMapUI: { version: '1.1', plugins: [ 'geo/DistrictExplorer' ] } }).then((AMap) => { const map = new AMap.Map('container', { // 设置地图容器id zoom, // 设置当前显示级别 expandZoomRange: true, // 开启显示范围设置 zooms: [ 9, 20 ], // 最小显示级别为7,最大显示级别为20 center: [ 103.062334, 30.012488 ], // 设置地图中心点位置 mapStyle: 'amap://styles/grey' }) // 限制位置 getBounds() const bounds = new AMap.Bounds( [ 103.395136, 30.936781 ], // 右上角经纬度 northEast [ 101.93598, 28.845463 ] // 左下角经纬度 southWest ) map.setLimitBounds(bounds) // 天气 const weather = new AMap.Weather() weather.getLive('雅安市', (err: any, data: Any) => { console.log('天气', err, data) if (err) { this.notification.warning({ content: '天气获取失败', duration: 2000 }) return } this.store.setWeather(data) }) // 镂空雅安 511800 adcode AMapUI.loadUI([ 'geo/DistrictExplorer' ], (DistrictExplorer: any) => { const districtExplorer = new DistrictExplorer({ map }) districtExplorer.loadMultiAreaNodes([ 100000, 511800 ], (error: any, areaNodes: string | any[]) => { const countryNode = areaNodes[0] const cityNodes = areaNodes.slice(1) const path = [] // 首先放置背景区域,这里是大陆的边界 path.push(this.getLongestRing(countryNode.getParentFeature())) for (let i = 0, len = cityNodes.length; i < len; i++) { // 逐个放置需要镂空的市级区域 path.push(...this.getAllRings(cityNodes[i].getParentFeature())) } // 绘制带环多边形 const polygon = new AMap.Polygon({ bubble: true, lineJoin: 'round', strokeColor: '#030E25', // 线颜色 strokeOpacity: 1, // 线透明度 strokeWeight: 1, // 线宽 fillColor: '#030E25', // 填充色 fillOpacity: 1, // 填充透明度 map, path }) }) }) this.Maps = map this.AMaps = AMap resolve() }).catch((er) => reject(er)) }) } // 初始化marks集合 public _initMarks(key: string, checked: string[], item?: any) { this.key = key this.marks[key] = {} for (let k = 0; k < checked.length; k++) { const el = checked[k] const icon = item.option.find((er: { value: string }) => er.value === el)?.icon const newIcon = this.getIcon(icon) if (!this.marks[key][el]) this.marks[key][el] = {} if (key === 'homePage' && el !== 'bus') { // homePageMark this.getMarkData(el).then((res) => { // line 需要单独处理 if (!res.length) return if (el === 'line') { for (let j = 0; j < res.length; j++) { const es = res[j] const paths = es.child?.sort((a: { stationNo: number }, b: { stationNo: number }) => a.stationNo - b.stationNo).map((ec: { lon: string; lat: string }) => ([ +ec.lon, +ec.lat ])) const color = this.colorRandom() this.marks[this.key][el][es.paramId] = { markMap: this.addLine(paths, color) } } } else { for (let z = 0; z < res.length; z++) { const ez = res[z] this.marks[this.key][el][ez.paramId] = { ...ez, markMap: this.addMark([ +ez.lon, +ez.lat ], newIcon) } } } }) } } } // 获取标点数据 async getMarkData(type: string) { // line 线路 station 中途站点 maintenanceStation维修站 powerCharge充电桩 busStation场站 const { data } = await this.netService.get(`/busLine/getMapElement?typeList=${type}`) return data || [] } // 动态图标 getIcon(imgName:string) { const url = new URL(`../../assets/img/${imgName}.svg`, import.meta.url).href return url } public destory() { if (Object.keys(this.marks).length) this.marks = {} if (this.Maps) this.Maps.destory() this.Maps = null this.AMaps = null } }