map.service.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import NetService from '@/services/net.service'
  2. import { injectable, Service } from '@/services/service'
  3. import AMapLoader from '@amap/amap-jsapi-loader'
  4. import { useNotification } from 'naive-ui'
  5. import useStore from '@/pages/store/index'
  6. import carIcon from '@/assets/img/39.svg'
  7. @injectable
  8. export default class MapService extends Service {
  9. private netService = new NetService()
  10. private notification = useNotification()
  11. private store = useStore()
  12. private key = ''
  13. public Maps = null as Any
  14. public AMaps = null as Any
  15. public marks = {} as Any
  16. private getAllRings(feature: { geometry: { coordinates: Any[]; }; }) {
  17. const coords = feature.geometry.coordinates
  18. const rings = []
  19. for (let i = 0, len = coords.length; i < len; i++) {
  20. rings.push(coords[i][0])
  21. }
  22. return rings
  23. }
  24. private getLongestRing(feature: { geometry: { coordinates: Any[]; }; }) {
  25. const rings = this.getAllRings(feature)
  26. rings.sort((a, b) => b.length - a.length)
  27. return rings[0]
  28. }
  29. private colorRandom() {
  30. const r = Math.floor(Math.random() * 256)
  31. const g = Math.floor(Math.random() * 256)
  32. const b = Math.floor(Math.random() * 256)
  33. return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`
  34. }
  35. // 添加标点
  36. public addMark(position: number[], icon?: string, size?: { w: number, h: number }) {
  37. if (!this.Maps && !this.AMaps) return
  38. const mark = new this.AMaps!.Marker({
  39. position,
  40. cursor: 'pointer',
  41. icon: new this.AMaps.Icon({
  42. image: icon || carIcon,
  43. imageSize: new this.AMaps.Size(size?.w || 24, size?.h || 24)
  44. }),
  45. autoRotation: true,
  46. offset: new this.AMaps.Pixel(-5, -20),
  47. angle: 0,
  48. anchor: 'center',
  49. extData: '1'// 设置自定义属性
  50. })
  51. this.Maps.add(mark)
  52. return mark
  53. }
  54. // 添加路线
  55. public addLine(path: number[][], color?: string, width?: number) {
  56. if (!this.Maps && !this.AMaps) return
  57. const polyline = new this.AMaps.Polyline({
  58. path,
  59. strokeWeight: width || 5,
  60. borderWeight: width || 5, // 线条宽度,默认为 1
  61. strokeColor: color || 'red', // 线条颜色
  62. lineJoin: 'bevel', // 折线拐点连接处样式
  63. geodesic: true
  64. })
  65. this.Maps.add(polyline)
  66. return polyline
  67. }
  68. // 初始化地图
  69. public _initMap(zoom: number) {
  70. window._AMapSecurityConfig = {
  71. securityJsCode: '184c86be3bbd9a8a941bcaaf6b09c7cd'
  72. }
  73. return new Promise<void>((resolve, reject) => {
  74. AMapLoader.load({
  75. key: '0c5c83112cafefa77154769b4433c3df',
  76. version: '2.0',
  77. plugins: [ 'AMap.DistrictSearch', 'AMap.Weather', 'AMap.Bounds', 'AMap.Driving' ],
  78. AMapUI: {
  79. version: '1.1',
  80. plugins: [ 'geo/DistrictExplorer' ]
  81. }
  82. }).then((AMap) => {
  83. const map = new AMap.Map('container', { // 设置地图容器id
  84. zoom, // 设置当前显示级别
  85. expandZoomRange: true, // 开启显示范围设置
  86. zooms: [ 9, 20 ], // 最小显示级别为7,最大显示级别为20
  87. center: [ 103.062334, 30.012488 ], // 设置地图中心点位置
  88. mapStyle: 'amap://styles/grey'
  89. })
  90. // 限制位置 getBounds()
  91. const bounds = new AMap.Bounds(
  92. [ 103.395136, 30.936781 ], // 右上角经纬度 northEast
  93. [ 101.93598, 28.845463 ] // 左下角经纬度 southWest
  94. )
  95. map.setLimitBounds(bounds)
  96. // 天气
  97. const weather = new AMap.Weather()
  98. weather.getLive('雅安市', (err: any, data: Any) => {
  99. console.log('天气', err, data)
  100. if (err) {
  101. this.notification.warning({
  102. content: '天气获取失败',
  103. duration: 2000
  104. })
  105. return
  106. }
  107. this.store.setWeather(data)
  108. })
  109. // 镂空雅安 511800 adcode
  110. AMapUI.loadUI([ 'geo/DistrictExplorer' ], (DistrictExplorer: any) => {
  111. const districtExplorer = new DistrictExplorer({ map })
  112. districtExplorer.loadMultiAreaNodes([ 100000, 511800 ], (error: any, areaNodes: string | any[]) => {
  113. const countryNode = areaNodes[0]
  114. const cityNodes = areaNodes.slice(1)
  115. const path = []
  116. // 首先放置背景区域,这里是大陆的边界
  117. path.push(this.getLongestRing(countryNode.getParentFeature()))
  118. for (let i = 0, len = cityNodes.length; i < len; i++) {
  119. // 逐个放置需要镂空的市级区域
  120. path.push(...this.getAllRings(cityNodes[i].getParentFeature()))
  121. }
  122. // 绘制带环多边形
  123. const polygon = new AMap.Polygon({
  124. bubble: true,
  125. lineJoin: 'round',
  126. strokeColor: '#030E25', // 线颜色
  127. strokeOpacity: 1, // 线透明度
  128. strokeWeight: 1, // 线宽
  129. fillColor: '#030E25', // 填充色
  130. fillOpacity: 1, // 填充透明度
  131. map,
  132. path
  133. })
  134. })
  135. })
  136. this.Maps = map
  137. this.AMaps = AMap
  138. resolve()
  139. }).catch((er) => reject(er))
  140. })
  141. }
  142. // 初始化marks集合
  143. public _initMarks(key: string, checked: string[], item?: any) {
  144. this.key = key
  145. this.marks[key] = {}
  146. for (let k = 0; k < checked.length; k++) {
  147. const el = checked[k]
  148. const icon = item.option.find((er: { value: string }) => er.value === el)?.icon
  149. const newIcon = this.getIcon(icon)
  150. if (!this.marks[key][el]) this.marks[key][el] = {}
  151. if (key === 'homePage' && el !== 'bus') {
  152. // homePageMark
  153. this.getMarkData(el).then((res) => {
  154. // line 需要单独处理
  155. if (!res.length) return
  156. if (el === 'line') {
  157. for (let j = 0; j < res.length; j++) {
  158. const es = res[j]
  159. console.log('线还需要不同的Id')
  160. // 区分上下行
  161. // const upLinePaths = es.child.filter((ed: { direction: number }) => ed.direction === 1).sort((a: { stationNo: number }, b: { stationNo: number }) => a.stationNo - b.stationNo).map((ec: { lon: string; lat: string }) => ([ +ec.lon, +ec.lat ]))
  162. // const downLinePaths = es.child.filter((ed: { direction: number }) => ed.direction === 2).sort((a: { stationNo: number }, b: { stationNo: number }) => a.stationNo - b.stationNo).map((ec: { lon: string; lat: string }) => ([ +ec.lon, +ec.lat ]))
  163. // console.log('上行', upLinePaths)
  164. // console.log('下行', downLinePaths)
  165. // const color = this.colorRandom()
  166. // this.marks[this.key][el][es.paramId] = { markMap: this.addLine(upLinePaths, color) }
  167. // this.marks[this.key][el][es.paramId] = { markMap: this.addLine(downLinePaths, color) }
  168. }
  169. } else {
  170. for (let z = 0; z < res.length; z++) {
  171. const ez = res[z]
  172. this.marks[this.key][el][ez.paramId] = { ...ez, markMap: this.addMark([ +ez.lon, +ez.lat ], newIcon) }
  173. }
  174. }
  175. })
  176. }
  177. }
  178. }
  179. // 获取标点数据
  180. async getMarkData(type: string) {
  181. // line 线路 station 中途站点 maintenanceStation维修站 powerCharge充电桩 busStation场站
  182. const { data } = await this.netService.get(`/busLine/getMapElement?typeList=${type}`)
  183. return data || []
  184. }
  185. // 动态图标
  186. getIcon(imgName:string) {
  187. const url = new URL(`../../assets/img/${imgName}.svg`, import.meta.url).href
  188. return url
  189. }
  190. public destory() {
  191. if (Object.keys(this.marks).length) this.marks = {}
  192. if (this.Maps) this.Maps.destory()
  193. this.Maps = null
  194. this.AMaps = null
  195. }
  196. }