use-g-map-cover.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. import { EFlightAreaType } from '../types/flight-area'
  2. import pin19be6b from '/@/assets/icons/pin-19be6b.svg'
  3. import pin212121 from '/@/assets/icons/pin-212121.svg'
  4. import pin2d8cf0 from '/@/assets/icons/pin-2d8cf0.svg'
  5. import pinb620e0 from '/@/assets/icons/pin-b620e0.svg'
  6. import pine23c39 from '/@/assets/icons/pin-e23c39.svg'
  7. import pineffbb00 from '/@/assets/icons/pin-ffbb00.svg'
  8. import { getRoot } from '/@/root'
  9. import rootStore from '/@/store'
  10. import { GeojsonCoordinate } from '/@/types/map'
  11. export function useGMapCover() {
  12. const root = getRoot()
  13. const AMap = root.$aMap
  14. const normalColor = '#2D8CF0'
  15. const store = rootStore
  16. const coverMap = store.state.coverMap
  17. const flightAreaColorMap = {
  18. [EFlightAreaType.DFENCE]: '#19be6b',
  19. [EFlightAreaType.NFZ]: '#ff0000',
  20. }
  21. const disableColor = '#b3b3b3'
  22. function AddCoverToMap(cover: any) {
  23. root.$map.add(cover)
  24. coverMap[cover.getExtData().id] = [cover]
  25. }
  26. function getPinIcon(color?: string) {
  27. const colorObj: {
  28. [key: number | string]: any
  29. } = {
  30. '2d8cf0': pin2d8cf0,
  31. '19be6b': pin19be6b,
  32. 212121: pin212121,
  33. b620e0: pinb620e0,
  34. e23c39: pine23c39,
  35. ffbb00: pineffbb00,
  36. }
  37. const iconName = (color?.replaceAll('#', '') || '').toLocaleLowerCase()
  38. return new AMap.Icon({
  39. image: colorObj[iconName],
  40. })
  41. }
  42. function init2DPin(name: string, coordinates: GeojsonCoordinate, color?: string, data?: {}) {
  43. const title = coordinates.map((item: any, index) => {
  44. if (index < 2) {
  45. return item.toFixed(4)
  46. }
  47. });
  48. const marker = new AMap.Marker({
  49. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  50. title: title,
  51. icon: getPinIcon(color),
  52. extData: data
  53. })
  54. const text = new AMap.Text({
  55. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  56. offset: new AMap.Pixel(20, -2),
  57. text: name,
  58. style: {
  59. backgroundColor: 'transparent',
  60. borderColor: 'transparent',
  61. },
  62. extData: {
  63. ...data,
  64. id: data.id + '_other',
  65. },
  66. })
  67. AddCoverToMap(text)
  68. marker.on('click', function (e: any) {
  69. const options = marker.getOptions()
  70. const id = options.extData.id;
  71. store.commit('SET_MAP_CLICK_ELEMENT', {
  72. id: id,
  73. type: 'DEFAULT',
  74. });
  75. })
  76. AddCoverToMap(marker)
  77. }
  78. function initPolyline(name: string, coordinates: GeojsonCoordinate[], color?: string, data?: {}) {
  79. const path = [] as GeojsonCoordinate[]
  80. coordinates.forEach(coordinate => {
  81. path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
  82. })
  83. const polyline = new AMap.Polyline({
  84. path: path,
  85. strokeColor: color || normalColor,
  86. strokeOpacity: 1,
  87. strokeWeight: 2,
  88. strokeStyle: 'solid',
  89. extData: data
  90. })
  91. const circles = path.map((item, index) => {
  92. return new AMap.Circle({
  93. center: item,
  94. radius: 0.5, // 半径
  95. strokeColor: color,
  96. fillColor: color,
  97. fillOpacity: 1,
  98. strokeWeight: 6,
  99. });
  100. })
  101. const coordinatesList = coordinates[0];
  102. const text = new AMap.Text({
  103. position: new AMap.LngLat(coordinatesList[0], coordinatesList[1]),
  104. offset: new AMap.Pixel(-30, -30),
  105. text: name,
  106. style: {
  107. backgroundColor: 'transparent',
  108. borderColor: 'transparent',
  109. },
  110. extData: {
  111. ...data,
  112. id: data.id + '_other',
  113. },
  114. })
  115. const distances = [];
  116. // 确保首尾相连
  117. const paths = [...coordinates, coordinates[0]]
  118. // 计算并显示每段线的距离
  119. for (let i = 0; i < paths.length - 1; i++) {
  120. const distance = AMap.GeometryUtil.distance(new AMap.LngLat(paths[i][0], paths[i][1]), new AMap.LngLat(paths[i + 1][0], paths[i + 1][1]));
  121. // 计算两个点之间的中点坐标
  122. const midLng = (paths[i][0] + paths[i + 1][0]) / 2;
  123. const midLat = (paths[i][1] + paths[i + 1][1]) / 2;
  124. const midPoint = new AMap.LngLat(midLng, midLat);
  125. // 在中点位置放置文本以显示距离
  126. const distanceText = new AMap.Text({
  127. position: midPoint,
  128. offset: new AMap.Pixel(-16, 10),
  129. text: `${distance.toFixed(1)} m`,// 距离
  130. style: {
  131. fontSize: '10px',
  132. color: '#FFFFFF',
  133. backgroundColor: 'rgba(0, 0, 0, 0.75)',
  134. borderColor: 'transparent',
  135. },
  136. });
  137. distances.push(distanceText);
  138. }
  139. const other = [...circles, text, ...distances]
  140. root.$map.add(other)
  141. coverMap[data.id + '_other'] = [other]
  142. polyline.on('click', function () {
  143. const options = polyline.getOptions()
  144. const id = options.extData.id;
  145. store.commit('SET_MAP_CLICK_ELEMENT', {
  146. id: id,
  147. type: 'DEFAULT',
  148. });
  149. })
  150. AddOverlayGroup(polyline)
  151. }
  152. function initPolygon(name: string, coordinates: GeojsonCoordinate[][], color?: string, data?: {}) {
  153. const path = [] as GeojsonCoordinate[]
  154. coordinates[0].forEach(coordinate => {
  155. path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
  156. })
  157. const polygon = new AMap.Polygon({
  158. path: path,
  159. strokeOpacity: 1,
  160. strokeWeight: 2,
  161. fillColor: color || normalColor,
  162. fillOpacity: 0.4,
  163. strokeColor: color || normalColor,
  164. extData: data
  165. })
  166. const circles = path.map((item, index) => {
  167. return new AMap.Circle({
  168. center: item,
  169. radius: 0.5, // 半径
  170. strokeColor: color,
  171. fillColor: color,
  172. fillOpacity: 1,
  173. strokeWeight: 6,
  174. });
  175. })
  176. const coordinatesList = coordinates[0][0];
  177. const text = new AMap.Text({
  178. position: new AMap.LngLat(coordinatesList[0], coordinatesList[1]),
  179. offset: new AMap.Pixel(-30, -30),
  180. text: name,
  181. style: {
  182. backgroundColor: 'transparent',
  183. borderColor: 'transparent',
  184. },
  185. extData: {
  186. ...data,
  187. id: data.id + '_other',
  188. },
  189. })
  190. const distances = [];
  191. // 确保首尾相连
  192. const paths = [...coordinates[0], coordinates[0][0]]
  193. // 计算并显示每段线的距离
  194. for (let i = 0; i < paths.length - 1; i++) {
  195. const distance = AMap.GeometryUtil.distance(new AMap.LngLat(paths[i][0], paths[i][1]), new AMap.LngLat(paths[i + 1][0], paths[i + 1][1]));
  196. // 计算两个点之间的中点坐标
  197. const midLng = (paths[i][0] + paths[i + 1][0]) / 2;
  198. const midLat = (paths[i][1] + paths[i + 1][1]) / 2;
  199. const midPoint = new AMap.LngLat(midLng, midLat);
  200. // 在中点位置放置文本以显示距离
  201. const distanceText = new AMap.Text({
  202. position: midPoint,
  203. offset: new AMap.Pixel(-16, 10),
  204. text: `${distance.toFixed(1)} m`,// 距离
  205. style: {
  206. fontSize: '10px',
  207. color: '#FFFFFF',
  208. backgroundColor: 'rgba(0, 0, 0, 0.75)',
  209. borderColor: 'transparent',
  210. },
  211. });
  212. distances.push(distanceText);
  213. }
  214. const other = [...circles, text, ...distances]
  215. root.$map.add(other)
  216. coverMap[data.id + '_other'] = [other]
  217. polygon.on('click', function () {
  218. const options = polygon.getOptions()
  219. const id = options.extData.id;
  220. store.commit('SET_MAP_CLICK_ELEMENT', {
  221. id: id,
  222. type: 'DEFAULT',
  223. });
  224. })
  225. AddOverlayGroup(polygon)
  226. }
  227. function getPolygonArea(coordinates: GeojsonCoordinate[][]) {
  228. const path = [] as GeojsonCoordinate[]
  229. coordinates[0].forEach(coordinate => {
  230. path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
  231. })
  232. const polygon = new AMap.Polygon({
  233. path: path,
  234. })
  235. return polygon.getArea();
  236. }
  237. function AddOverlayGroup(overlayGroup: any) {
  238. root.$map.add(overlayGroup)
  239. const id = overlayGroup.getExtData().id
  240. coverMap[id] = [...(coverMap[id] || []), overlayGroup]
  241. }
  242. function removeCoverFromMap(id: string) {
  243. coverMap[id].forEach(cover => root.$map.remove(cover))
  244. coverMap[id] = []
  245. }
  246. function getElementFromMap(id: string): any[] {
  247. return coverMap[id]
  248. }
  249. function updatePhotoElement(id: string, name: string, url: string, coordinates: [number, number]) {
  250. const icon = new AMap.Icon({
  251. size: new AMap.Size(30, 30),
  252. image: url,
  253. imageSize: new AMap.Size(30, 30)
  254. })
  255. const marker = new AMap.Marker({
  256. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  257. icon: icon,
  258. title: name,
  259. extData: {
  260. id: id
  261. }
  262. })
  263. marker.on('click', function (e: any) {
  264. const options = marker.getOptions()
  265. const id = options.extData.id;
  266. store.commit('SET_MAP_CLICK_ELEMENT', {
  267. id: id,
  268. type: 'PHOTO',
  269. });
  270. })
  271. AddCoverToMap(marker)
  272. }
  273. function updatePinElement(id: string, name: string, coordinates: GeojsonCoordinate, color?: string) {
  274. init2DPin(name, coordinates, color, {
  275. id: id,
  276. name: name
  277. })
  278. }
  279. function updatePolylineElement(id: string, name: string, coordinates: GeojsonCoordinate[], color?: string) {
  280. initPolyline(name, coordinates, color, {
  281. id: id,
  282. name: name
  283. })
  284. }
  285. function updatePolygonElement(id: string, name: string, coordinates: GeojsonCoordinate[][], color?: string) {
  286. initPolygon(name, coordinates, color, {
  287. id: id,
  288. name: name
  289. })
  290. }
  291. function initTextInfo(content: string, coordinates: GeojsonCoordinate, id: string) {
  292. const info = new AMap.Text({
  293. text: content,
  294. position: new AMap.LngLat(coordinates[0], coordinates[1]),
  295. extData: { id: id, type: 'text' },
  296. anchor: 'top-center',
  297. style: {
  298. background: 'none',
  299. borderStyle: 'none',
  300. fontSize: '16px',
  301. },
  302. })
  303. AddOverlayGroup(info)
  304. }
  305. function initFlightAreaCircle(name: string, radius: number, position: GeojsonCoordinate, data: { id: string, type: EFlightAreaType, enable: boolean }) {
  306. const circle = new AMap.Circle({
  307. strokeColor: data.enable ? flightAreaColorMap[data.type] : disableColor,
  308. strokeOpacity: 1,
  309. strokeWeight: 6,
  310. extData: data,
  311. strokeStyle: 'dashed',
  312. strokeDasharray: EFlightAreaType.NFZ === data.type ? [10, 2] : [10, 1, 2],
  313. fillColor: flightAreaColorMap[data.type],
  314. fillOpacity: EFlightAreaType.NFZ === data.type && data.enable ? 0.3 : 0,
  315. radius: radius,
  316. center: new AMap.LngLat(position[0], position[1]),
  317. })
  318. AddOverlayGroup(circle)
  319. initTextInfo(name, position, data.id)
  320. }
  321. function updateFlightAreaCircle(id: string, name: string, radius: number, position: GeojsonCoordinate, enable: boolean, type: EFlightAreaType) {
  322. const elements = getElementFromMap(id)
  323. if (elements && elements.length > 0) {
  324. let textIndex = elements.findIndex(ele => ele.getExtData()?.type === 'text')
  325. if (textIndex === -1) {
  326. textIndex = 1
  327. initTextInfo(name, position, id)
  328. } else {
  329. const text = elements[textIndex]
  330. text.setText(name)
  331. text.setPosition(position)
  332. }
  333. const element = elements[textIndex ^ 1]
  334. const options = element.getOptions()
  335. options.fillOpacity = EFlightAreaType.NFZ === type && enable ? 0.3 : 0
  336. options.strokeColor = enable ? flightAreaColorMap[type] : disableColor
  337. options.radius = radius
  338. options.center = new AMap.LngLat(position[0], position[1])
  339. element.setOptions(options)
  340. } else {
  341. initFlightAreaCircle(name, radius, position, { id, type, enable })
  342. }
  343. }
  344. function calcPolygonPosition(coordinate: GeojsonCoordinate[]): GeojsonCoordinate {
  345. const index = coordinate.length - 1
  346. return [(coordinate[0][0] + coordinate[index][0]) / 2.0, (coordinate[0][1] + coordinate[index][1]) / 2]
  347. }
  348. function initFlightAreaPolygon(name: string, coordinates: GeojsonCoordinate[], data: { id: string, type: EFlightAreaType, enable: boolean }) {
  349. const path = [] as GeojsonCoordinate[]
  350. coordinates.forEach(coordinate => {
  351. path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
  352. })
  353. const polygon = new AMap.Polygon({
  354. path: path,
  355. strokeColor: data.enable ? flightAreaColorMap[data.type] : disableColor,
  356. strokeOpacity: 1,
  357. strokeWeight: 4,
  358. draggable: true,
  359. extData: data,
  360. strokeStyle: 'dashed',
  361. strokeDasharray: EFlightAreaType.NFZ === data.type ? [10, 2] : [10, 1, 2],
  362. fillColor: flightAreaColorMap[data.type],
  363. fillOpacity: EFlightAreaType.NFZ === data.type && data.enable ? 0.3 : 0,
  364. })
  365. AddOverlayGroup(polygon)
  366. initTextInfo(name, calcPolygonPosition(coordinates), data.id)
  367. }
  368. function updateFlightAreaPolygon(id: string, name: string, coordinates: GeojsonCoordinate[], enable: boolean, type: EFlightAreaType) {
  369. const elements = getElementFromMap(id)
  370. if (elements && elements.length > 0) {
  371. let textIndex = elements.findIndex(ele => ele.getExtData()?.type === 'text')
  372. if (textIndex === -1) {
  373. textIndex = 1
  374. initTextInfo(name, calcPolygonPosition(coordinates), id)
  375. } else {
  376. const text = elements[textIndex]
  377. text.setText(name)
  378. text.setPosition(calcPolygonPosition(coordinates))
  379. }
  380. const element = elements[textIndex ^ 1]
  381. const options = element.getOptions()
  382. const path = [] as GeojsonCoordinate[]
  383. coordinates.forEach(coordinate => {
  384. path.push(new AMap.LngLat(coordinate[0], coordinate[1]))
  385. })
  386. options.path = path
  387. options.fillOpacity = EFlightAreaType.NFZ === type && enable ? 0.3 : 0
  388. options.strokeColor = enable ? flightAreaColorMap[type] : disableColor
  389. element.setOptions(options)
  390. } else {
  391. initFlightAreaPolygon(name, coordinates, { id, type, enable })
  392. }
  393. }
  394. return {
  395. init2DPin,
  396. initPolyline,
  397. initPolygon,
  398. getPolygonArea,
  399. removeCoverFromMap,
  400. getElementFromMap,
  401. updatePhotoElement,
  402. updatePinElement,
  403. updatePolylineElement,
  404. updatePolygonElement,
  405. initFlightAreaCircle,
  406. initFlightAreaPolygon,
  407. updateFlightAreaPolygon,
  408. updateFlightAreaCircle,
  409. calcPolygonPosition,
  410. }
  411. }