useAMap.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. import AMapLoader from '@amap/amap-jsapi-loader';
  2. import { nanoid } from 'nanoid';
  3. import { deepClone, initDrag } from '@/utils';
  4. import { mergeGeoJsonPolygons, wgs_gcj_encrypts } from '@/utils/gisUtils';
  5. import carImg from '@/assets/images/car.png';
  6. import { getImageUrl, iconList } from '@/views/globalMap/data/mapData';
  7. export function useAMap(options) {
  8. let AMap, map, scale, cluster;
  9. const markers = {
  10. point: []
  11. };
  12. let clickMarker = null;
  13. let addPoints = [];
  14. let layers = [];
  15. let defaultLayer;
  16. // 标绘图层
  17. const plotLayers = [];
  18. // 标绘层级
  19. let activeLayerkey;
  20. // 显示信息框
  21. let infoWindow;
  22. // 初始化事件
  23. const initMap = (options) => {
  24. window._AMapSecurityConfig = {
  25. securityJsCode: options.securityJsCode
  26. };
  27. AMapLoader.load({
  28. key: options.key, // 申请好的Web端开发者Key,首次调用 load 时必填
  29. version: !!options.version ? options.version : '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
  30. plugins: options.plugins
  31. ? options.plugins
  32. : [
  33. 'AMap.Scale',
  34. 'AMap.RangingTool',
  35. 'AMap.MouseTool',
  36. 'AMap.PolygonEditor',
  37. 'AMap.MarkerCluster',
  38. 'AMap.DistrictSearch',
  39. 'AMap.MoveAnimation',
  40. 'AMap.Driving',
  41. 'AMap.Geocoder',
  42. 'AMap.PlaceSearch',
  43. 'AMap.GeoJSON'
  44. ]
  45. }).then((res) => {
  46. AMap = res;
  47. defaultLayer = AMap.createDefaultLayer();
  48. map = new AMap.Map(options.el ? options.el : 'aMap', {
  49. WebGLParams: {
  50. preserveDrawingBuffer: true
  51. },
  52. layers: [defaultLayer],
  53. // 是否为3D地图模式
  54. // viewMode: '3D',
  55. pitch: options.pitch,
  56. // 初始化地图级别
  57. zoom: options.zoom ? options.zoom : 11,
  58. // 初始化地图中心点位置
  59. center: options.center,
  60. // 是否可拖拽
  61. dragEnable: options.dragEnable,
  62. // 是否允许通过鼠标滚轮来缩放
  63. scrollWheel: options.scrollWheel,
  64. maxZoom: options.maxZoom ? options.maxZoom : 20
  65. });
  66. // 初始化比例尺
  67. if (options.showScale) {
  68. scale = new AMap.Scale();
  69. map.addControl(scale);
  70. }
  71. if (typeof options.onLoadCompleted === 'function') {
  72. options.onLoadCompleted(AMap, map);
  73. }
  74. });
  75. };
  76. const getAMap = () => {
  77. return AMap;
  78. };
  79. const getMap = () => {
  80. return map;
  81. };
  82. const getScale = () => {
  83. return scale;
  84. };
  85. const initLayer = (type: string) => {
  86. if (defaultLayer) {
  87. map.removeLayer(defaultLayer);
  88. defaultLayer = null;
  89. }
  90. let keys = ['http://t0.tianditu.gov.cn/vec_w/wmts', 'http://t0.tianditu.gov.cn/cva_w/wmts'];
  91. if (type === 'satellite') {
  92. keys = ['http://t0.tianditu.gov.cn/img_w/wmts', 'http://t0.tianditu.gov.cn/cia_w/wmts'];
  93. }
  94. const layer = new AMap.TileLayer.WMTS({
  95. url: keys[0],
  96. blend: false,
  97. tileSize: 256,
  98. params: {
  99. Layer: 'img',
  100. Version: '1.0.0',
  101. Format: 'tiles',
  102. TileMatrixSet: 'w',
  103. STYLE: 'default',
  104. tk: 'a8df87f1695d224d2679aa805c1268d9'
  105. }
  106. });
  107. const layerMark = new AMap.TileLayer.WMTS({
  108. url: keys[1],
  109. blend: false,
  110. tileSize: 256,
  111. params: {
  112. Layer: type === 'satellite' ? 'cia' : 'cva',
  113. Version: '1.0.0',
  114. Format: 'tiles',
  115. TileMatrixSet: 'w',
  116. STYLE: 'default',
  117. tk: 'a8df87f1695d224d2679aa805c1268d9'
  118. }
  119. });
  120. return [layer, layerMark];
  121. };
  122. // 切换地图
  123. const switchMap = (type: string) => {
  124. layers.forEach((layer) => {
  125. map.removeLayer(layer);
  126. });
  127. layers = initLayer(type);
  128. layers.forEach((layer) => {
  129. layer.setMap(map);
  130. });
  131. };
  132. // 添加搜索的标记的
  133. const addSearchMarker = (item) => {
  134. map.setZoom(18);
  135. map.setCenter(item.lnglat);
  136. // 获取到上一次的搜索标记并移除
  137. const index = addPoints.findIndex((m) => {
  138. return m.dataType === 'search';
  139. });
  140. if (index > -1) {
  141. addPoints.splice(index, 1);
  142. }
  143. addMarker([item], true);
  144. clickMarker = item;
  145. options.onMarkerClick(item);
  146. };
  147. // 添加多个点
  148. const addMarker = (points, notClean?: boolean) => {
  149. if (!notClean) {
  150. addPoints = points;
  151. } else {
  152. addPoints.push(...points);
  153. }
  154. clearMarker('point');
  155. const count = points.length;
  156. const _renderClusterMarker = function (context) {
  157. // 聚合中点个数
  158. const clusterCount = context.count;
  159. const div = document.createElement('div');
  160. div.style.backgroundColor = 'rgba(78,179,211,.5)';
  161. const size = Math.round(25 + Math.pow(clusterCount / count, 1 / 5) * 20);
  162. div.style.width = div.style.height = size + 'px';
  163. div.style.border = 'solid 1px rgba(78,179,211,1)';
  164. div.style.borderRadius = size / 2 + 'px';
  165. div.innerHTML = context.count;
  166. div.style.lineHeight = size + 'px';
  167. div.style.color = '#ffffff';
  168. div.style.fontSize = '12px';
  169. div.style.textAlign = 'center';
  170. context.marker.setOffset(new AMap.Pixel(-size / 2, -size / 2));
  171. context.marker.setContent(div);
  172. context.marker.on('click', (e) => {
  173. const bounds = e.target.getBounds();
  174. map.setZoomAndCenter(map.getZoom() + 1, bounds.getCenter());
  175. });
  176. };
  177. const _renderMarker = function (context) {
  178. const content =
  179. '<div style="display: flex;flex-direction: column;align-items: center;justify-content: center">' +
  180. '<div style="background: url(' +
  181. context.data[0].icon +
  182. ') no-repeat; width: ' +
  183. context.data[0].size[0] +
  184. 'px;height: ' +
  185. context.data[0].size[1] +
  186. 'px;cursor: pointer; background-size: cover"></div>' +
  187. // '<div style="font-size: 36px;white-space: nowrap">'+ context.data[0].name +'</div>' +
  188. '</div>';
  189. const offset = new AMap.Pixel(-9, -9);
  190. context.marker.setContent(content);
  191. context.marker.setOffset(offset);
  192. context.marker.setExtData(context.data[0]);
  193. context.marker.on('click', function (e) {
  194. const extData = e.target.getExtData();
  195. let index = 0;
  196. let index2 = 0;
  197. for (let i = 0; i < addPoints.length; i++) {
  198. if (addPoints[i].id === extData.id && addPoints[i].imageHover) {
  199. addPoints[i].icon = addPoints[i].imageHover;
  200. e.target.setContent(content);
  201. index++;
  202. } else if (!!clickMarker) {
  203. const extData2 = clickMarker.getExtData();
  204. if (addPoints[i].id === extData2.id) {
  205. addPoints[i].icon = addPoints[i].image;
  206. clickMarker.setContent(content);
  207. index2++;
  208. }
  209. }
  210. if ((!!clickMarker && index === 1 && index2 === 1) || (!clickMarker && index === 1)) {
  211. break;
  212. }
  213. }
  214. addMarker(addPoints);
  215. clickMarker = e.target;
  216. options.onMarkerClick(extData);
  217. });
  218. };
  219. cluster = new AMap.MarkerCluster(
  220. map, //地图实例
  221. addPoints, //海量点数据,数据中需包含经纬度信息字段 lnglat
  222. {
  223. gridSize: 30, //数据聚合计算时网格的像素大小
  224. renderClusterMarker: _renderClusterMarker, //上述步骤的自定义聚合点样式
  225. renderMarker: _renderMarker //上述步骤的自定义非聚合点样式
  226. }
  227. );
  228. points.forEach((item) => {
  229. markers['point'].push(item);
  230. });
  231. };
  232. // 添加多个点2 后台做点聚合
  233. const addMarker2 = (obj) => {
  234. // 新增图层
  235. if (!plotLayers['points2']) {
  236. plotLayers['points2'] = new AMap.OverlayGroup({
  237. zIndex: 10, // 设置图层层级
  238. visible: true
  239. });
  240. map.add(plotLayers['points2']);
  241. } else {
  242. plotLayers['points2'].clearOverlays();
  243. addPoints = [];
  244. }
  245. let hideInfoFlag = true;
  246. Object.keys(obj).forEach((key: string) => {
  247. const data = obj[key];
  248. if (clickMarker) {
  249. const extData = clickMarker.getExtData();
  250. if (data.id === extData.id) {
  251. hideInfoFlag = false;
  252. data.isHover = true;
  253. }
  254. }
  255. if (data.type === '3') {
  256. // 聚合点
  257. const div = document.createElement('div');
  258. div.style.backgroundColor = 'rgba(78,179,211,.5)';
  259. const size = Math.round(25 + Math.pow(1 / 5, 1 / 5) * 20);
  260. div.style.width = div.style.height = size + 'px';
  261. div.style.border = 'solid 1px rgba(78,179,211,1)';
  262. div.style.borderRadius = size / 2 + 'px';
  263. div.innerHTML = data.count;
  264. div.style.lineHeight = size + 'px';
  265. div.style.color = '#ffffff';
  266. div.style.fontSize = '12px';
  267. div.style.textAlign = 'center';
  268. const marker = new AMap.Marker({
  269. position: [data.longitude, data.latitude],
  270. content: div,
  271. anchor: 'center',
  272. offset: new AMap.Pixel(0, 0),
  273. map: map
  274. });
  275. marker.setContent(div);
  276. marker.on('click', (e) => {
  277. const bounds = e.target.getBounds();
  278. map.setZoomAndCenter(map.getZoom() + 1, bounds.getCenter());
  279. });
  280. plotLayers['points2'].addOverlay(marker);
  281. addPoints.push(data);
  282. } else {
  283. // 单个点
  284. const iconConfig = iconList[data.dataType] || iconList.common;
  285. data.image = iconConfig.image;
  286. data.imageHover = iconConfig.imageHover;
  287. data.size = iconConfig.size;
  288. if (data.materia_name) {
  289. data.name = data.materia_name;
  290. }
  291. if (data.dataType === 43) {
  292. data.showName = true;
  293. }
  294. if (!data.id) {
  295. data.id = nanoid(8);
  296. }
  297. data.lnglat = [data.longitude, data.latitude];
  298. const marker = new AMap.Marker({
  299. position: [data.longitude, data.latitude],
  300. content: getContent(data.isHover ? data.imageHover : data.image, data.size),
  301. anchor: 'bottom-center',
  302. offset: new AMap.Pixel(0, 0),
  303. map: map
  304. });
  305. marker.setExtData(data);
  306. marker.on('click', function (e) {
  307. const extData = e.target.getExtData();
  308. let index = 0;
  309. let index2 = 0;
  310. for (let i = 0; i < addPoints.length; i++) {
  311. if (addPoints[i].id === extData.id) {
  312. marker.setContent(getContent(data.imageHover, data.size));
  313. index++;
  314. } else if (!!clickMarker) {
  315. const extData2 = clickMarker.getExtData();
  316. if (addPoints[i].id === extData2.id) {
  317. clickMarker.setContent(getContent(extData2.image, extData2.size));
  318. index2++;
  319. }
  320. }
  321. if ((!!clickMarker && index === 1 && index2 === 1) || (!clickMarker && index === 1)) {
  322. break;
  323. }
  324. }
  325. clickMarker = e.target;
  326. options.onMarkerClick(extData);
  327. });
  328. plotLayers['points2'].addOverlay(marker);
  329. addPoints.push(data);
  330. if (data.isHover) {
  331. options.onMarkerClick(data);
  332. }
  333. }
  334. });
  335. if (hideInfoFlag) {
  336. clickMarker = null;
  337. hideInfo();
  338. }
  339. };
  340. const getContent = (icon: string, size: number[], name?: string, color?: string = '#000') => {
  341. let content =
  342. '<div style="display: flex;flex-direction: column;align-items: center;justify-content: center;cursor: pointer">' +
  343. '<div style="background: url(' +
  344. icon +
  345. ') no-repeat; width: ' +
  346. size[0] +
  347. 'px;height: ' +
  348. size[1] +
  349. 'px;cursor: pointer; background-size: cover"></div>';
  350. if (!!name) {
  351. content += '<div style="font-size: 16px;white-space: nowrap; font-weight: bold;color:' + color + '">' + name + '</div>';
  352. }
  353. content += '</div>';
  354. return content;
  355. };
  356. // 清除所有标加
  357. const clearMarker = (id) => {
  358. if (!cluster || !markers[id]) return;
  359. cluster.setMap(null);
  360. markers[id] = [];
  361. };
  362. const clearMarker2 = (id) => {
  363. if (!!plotLayers['points2']) {
  364. plotLayers['points2'].clearOverlays();
  365. addPoints = [];
  366. }
  367. clickMarker = null;
  368. hideInfo();
  369. };
  370. let addressMarker;
  371. // 设置灾害地点 单独图册
  372. const setAddress = (data) => {
  373. addressMarker = new AMap.Marker({
  374. position: [data.longitude, data.latitude],
  375. content: getContent(data.image, data.size, data.name),
  376. anchor: 'bottom-center',
  377. offset: new AMap.Pixel(0, 16),
  378. map: map
  379. });
  380. if (!plotLayers['address']) {
  381. plotLayers['address'] = new AMap.OverlayGroup({
  382. zIndex: 10, // 设置图层层级
  383. visible: true
  384. });
  385. map.add(plotLayers['address']);
  386. } else {
  387. plotLayers['address'].clearOverlays();
  388. }
  389. plotLayers['address'].addOverlay(addressMarker);
  390. };
  391. const showInfo = (content, position, offsetY, isCustom) => {
  392. hideInfo();
  393. // 实例化InfoWindow
  394. infoWindow = new AMap.InfoWindow({
  395. // 完全自定义
  396. isCustom: isCustom,
  397. autoMove: false,
  398. offset: new AMap.Pixel(0, offsetY ? offsetY : 0) // 信息窗体的偏移量
  399. // 可以根据需要设置其他InfoWindow的属性
  400. });
  401. const lnglat = new AMap.LngLat(position[0], position[1]);
  402. // 打开InfoWindow,并设置其内容和位置
  403. infoWindow.setContent(content);
  404. infoWindow.open(map, lnglat);
  405. initDrag(infoWindow.dom);
  406. // 解决2.0版本无法滚动问题
  407. infoWindow.on('mouseover', () => map.setStatus({ zoomEnable: false }));
  408. infoWindow.on('mouseout', () => map.setStatus({ zoomEnable: true }));
  409. };
  410. const hideInfo = (e?: any) => {
  411. map.setStatus({ zoomEnable: true });
  412. if (!!infoWindow) {
  413. infoWindow.close();
  414. if (!!clickMarker && e) {
  415. const extData = clickMarker.getExtData ? clickMarker.getExtData() : clickMarker;
  416. for (let i = 0; i < addPoints.length; i++) {
  417. if (addPoints[i].id === extData.id) {
  418. addPoints[i].icon = addPoints[i].image;
  419. clickMarker.setContent(getContent(addPoints[i].icon, addPoints[i].size));
  420. clickMarker = null;
  421. // addMarker(addPoints);
  422. break;
  423. }
  424. }
  425. }
  426. }
  427. };
  428. let maskPolygon;
  429. const creatMask = (options, name = '茂名市') => {
  430. new AMap.DistrictSearch({
  431. extensions: 'all',
  432. subdistrict: 0
  433. }).search(name, function (status, result) {
  434. // 外多边形坐标数组和内多边形坐标数组
  435. const outer = [
  436. new AMap.LngLat(-360, 90, true),
  437. new AMap.LngLat(-360, -90, true),
  438. new AMap.LngLat(360, -90, true),
  439. new AMap.LngLat(360, 90, true)
  440. ];
  441. options.forEach((option) => {
  442. const holes = result.districtList[0].boundaries;
  443. const pathArray = [outer];
  444. pathArray.push.apply(pathArray, holes);
  445. maskPolygon = new AMap.Polygon({
  446. pathL: pathArray,
  447. strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
  448. strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
  449. strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
  450. fillColor: option.fillColor ? option.fillColor : '#10243b',
  451. fillOpacity: option.fillOpacity ? option.fillOpacity : 0.65
  452. });
  453. maskPolygon.setPath(pathArray);
  454. map.add(maskPolygon);
  455. });
  456. });
  457. };
  458. const removeMask = () => {
  459. if (!!maskPolygon) {
  460. map.remove(maskPolygon);
  461. maskPolygon = null;
  462. }
  463. };
  464. let maskPolygon2 = [];
  465. const creatMask2 = (data, option) => {
  466. if (maskPolygon2 && maskPolygon2.length > 0) {
  467. maskPolygon2.forEach((polygon) => {
  468. polygon.show();
  469. });
  470. } else {
  471. // data = convertCoordinates(data);
  472. // 遮罩部分
  473. // const outer = [
  474. // new AMap.LngLat(-180, 90, true),
  475. // new AMap.LngLat(-180, -90, true),
  476. // new AMap.LngLat(180, -90, true),
  477. // new AMap.LngLat(180, 90, true)
  478. // ];
  479. // const pathArray = [outer];
  480. // 合并区边界
  481. // const data2 = mergeGeoJsonPolygons(data);
  482. // data2.geometry.coordinates.forEach((coords) => {
  483. // pathArray.push(coords[0]);
  484. // });
  485. // const maskPolygon = new AMap.Polygon({
  486. // path: pathArray,
  487. // strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
  488. // strokeOpacity: 1,
  489. // strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
  490. // fillColor: option.fillColor ? option.fillColor : '#10243b',
  491. // fillOpacity: option.fillOpacity ? option.fillOpacity : 0.65
  492. // });
  493. // maskPolygon2.push(maskPolygon);
  494. // map.add(maskPolygon);
  495. // 边界部分
  496. data.features.forEach((feature) => {
  497. if (feature.geometry.type === 'Polygon') {
  498. const polygonPath = feature.geometry.coordinates[0].map((coord) => {
  499. return [coord[0], coord[1]];
  500. });
  501. const polygon = new AMap.Polyline({
  502. path: polygonPath,
  503. strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
  504. strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
  505. strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
  506. clickable: false
  507. });
  508. maskPolygon2.push(polygon);
  509. map.add(polygon);
  510. } else if (feature.geometry.type === 'MultiPolygon') {
  511. feature.geometry.coordinates.forEach((polygonCoords) => {
  512. const polygonPath = polygonCoords.map((ring) => {
  513. return ring.map((coord) => {
  514. return [coord[0], coord[1]];
  515. });
  516. });
  517. const outerPath = polygonPath[0];
  518. const innerPaths = polygonPath.slice(1);
  519. const polygon = new AMap.Polyline({
  520. path: outerPath,
  521. holes: innerPaths,
  522. strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
  523. strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
  524. strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
  525. clickable: false
  526. });
  527. maskPolygon2.push(polygon);
  528. map.add(polygon);
  529. });
  530. }
  531. });
  532. }
  533. };
  534. const removeMask2 = (isHidden) => {
  535. if (maskPolygon2 && maskPolygon2.length > 0) {
  536. maskPolygon2.forEach((polygon) => {
  537. polygon.hide();
  538. });
  539. if (!isHidden) {
  540. maskPolygon2 = [];
  541. }
  542. }
  543. };
  544. let moveMarker, movePolyline, movePassedPolyline, timerId;
  545. const trackPlayback = (lineArr, speed = 1000) => {
  546. if (timerId) {
  547. clearTimeout(timerId);
  548. }
  549. movePolyline?.remove();
  550. movePassedPolyline?.remove();
  551. moveMarker?.remove();
  552. const icon = new AMap.Icon({
  553. size: new AMap.Size(13, 26),
  554. image: carImg
  555. });
  556. moveMarker = new AMap.Marker({
  557. map: map,
  558. position: lineArr[0],
  559. icon: icon,
  560. anchor: 'center'
  561. });
  562. // 绘制轨迹
  563. movePolyline = new AMap.Polyline({
  564. map: map,
  565. path: lineArr,
  566. showDir: true,
  567. strokeColor: '#28F', //线颜色
  568. // strokeOpacity: 1, //线透明度
  569. strokeWeight: 6 //线宽
  570. // strokeStyle: "solid" //线样式
  571. });
  572. movePassedPolyline = new AMap.Polyline({
  573. map: map,
  574. strokeColor: '#AF5', //线颜色
  575. strokeWeight: 6 //线宽
  576. });
  577. moveMarker.on('moving', function (e) {
  578. movePassedPolyline.setPath(e.passedPath);
  579. map.setCenter(e.target.getPosition(), true);
  580. });
  581. // moveMarker.on('moveend', function (e) {
  582. // index++;
  583. // if (index === lineArr.length - 1) {
  584. // timerId = setTimeout(() => {
  585. // movePolyline.remove();
  586. // movePassedPolyline.remove();
  587. // moveMarker.remove();
  588. // }, 5000);
  589. // }
  590. // });
  591. moveMarker.moveAlong(lineArr, {
  592. // 每一段的时长
  593. duration: speed, //可根据实际采集时间间隔设置
  594. // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
  595. autoRotation: true
  596. });
  597. return { movePolyline, movePassedPolyline, moveMarker };
  598. };
  599. const drawData = (data) => {
  600. const res = [];
  601. data.forEach((item) => {
  602. let graphic;
  603. if (['rectangle', 'polygon', 'anyLine'].includes(item.type)) {
  604. graphic = new AMap.Polygon({
  605. path: item.path,
  606. strokeColor: item.strokeColor,
  607. strokeOpacity: item.strokeOpacity,
  608. strokeWeight: item.strokeWeight,
  609. fillColor: item.fillColor,
  610. fillOpacity: item.fillOpacity
  611. });
  612. graphic._opts.extData = {
  613. id: item.id
  614. };
  615. map.add(graphic);
  616. res.push(graphic);
  617. } else if (item.type === 'circle') {
  618. graphic = new AMap.Circle({
  619. center: item.center,
  620. radius: item.radius * 100000,
  621. strokeColor: item.strokeColor,
  622. strokeOpacity: item.strokeOpacity,
  623. strokeWeight: item.strokeWeight,
  624. fillColor: item.fillColor,
  625. fillOpacity: item.fillOpacity
  626. });
  627. graphic._opts.extData = {
  628. id: item.id
  629. };
  630. map.add(graphic);
  631. res.push(graphic);
  632. } else if (item.type === 'straightLine') {
  633. graphic = new AMap.Polyline({
  634. path: item.path,
  635. strokeColor: item.strokeColor,
  636. strokeOpacity: item.strokeOpacity,
  637. strokeWeight: item.strokeWeight,
  638. strokeStyle: item.strokeStyle
  639. });
  640. graphic._opts.extData = {
  641. id: item.id
  642. };
  643. map.add(graphic);
  644. res.push(graphic);
  645. } else if (item.type === 'text') {
  646. const { text } = addText(item);
  647. res.push(text);
  648. } else if (item.type === 'measureArea') {
  649. graphic = new AMap.Polygon({
  650. path: item.path,
  651. strokeColor: item.strokeColor,
  652. strokeOpacity: item.strokeOpacity,
  653. strokeWeight: item.strokeWeight,
  654. fillColor: item.fillColor,
  655. fillOpacity: item.fillOpacity
  656. });
  657. graphic._opts.extData = {
  658. id: item.id
  659. };
  660. map.add(graphic);
  661. // 计算区域面积
  662. const area = Math.round(AMap.GeometryUtil.ringArea(item.path));
  663. const text = new AMap.Text({
  664. position: item.path[item.path.length - 1],
  665. text: '区域面积' + area + '平方米',
  666. offset: new AMap.Pixel(-20, -20)
  667. });
  668. text._opts.extData = {
  669. id: item.id
  670. };
  671. data.area = area;
  672. map.add([graphic, text]);
  673. // res.push(text);
  674. } else if (item.type === 'marker') {
  675. // 创建标注点
  676. const marker = new AMap.Marker({
  677. position: new AMap.LngLat(item.longitude, item.latitude), // 标注点的位置
  678. icon: new AMap.Icon({
  679. size: item.size, //图标所处区域大小
  680. image: item.icon
  681. }),
  682. size: item.size
  683. });
  684. marker._opts.extData = {
  685. id: item.id
  686. };
  687. marker.setLabel({
  688. content: '<div>' + item.title + '</div>',
  689. direction: 'top'
  690. });
  691. map.add(marker);
  692. res.push(marker);
  693. }
  694. });
  695. return res;
  696. };
  697. const addText = (options) => {
  698. // 文本覆盖物的样式
  699. const textStyle = {
  700. fontSize: options.fontSize,
  701. color: options.fontColor,
  702. borderColor: 'transparent',
  703. backgroundColor: 'transparent',
  704. borderWidth: 0,
  705. cursor: 'pointer' // 鼠标悬停时显示指针
  706. };
  707. // 创建文本覆盖物
  708. const text = new AMap.Text({
  709. text: options.text, // 文本内容,可以根据需要自定义
  710. position: options.lnglat, // 文本位置(经纬度)
  711. style: textStyle, // 文本样式
  712. zIndex: 100, // 文本层级
  713. draggable: false // 是否可拖动(可选)
  714. });
  715. // 将文本覆盖物添加到地图
  716. map.add(text);
  717. const id = nanoid();
  718. text._opts.extData = {
  719. id: id
  720. };
  721. const data: any = deepClone(options);
  722. data.id = id;
  723. return { text, data };
  724. };
  725. const convertCoordinates = (geoJson) => {
  726. const features = geoJson.features.map((feature) => {
  727. const geometry = feature.geometry;
  728. let newGeometry;
  729. if (geometry.type === 'Point') {
  730. const [x, y] = geometry.coordinates;
  731. const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
  732. newGeometry = { ...geometry, coordinates: [obj.lng, obj.lat] };
  733. } else if (geometry.type === 'MultiPoint') {
  734. const newCoordinates = geometry.coordinates.map((coords) => {
  735. const [x, y] = coords;
  736. const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
  737. return [obj.lng, obj.lat];
  738. });
  739. newGeometry = { ...geometry, coordinates: newCoordinates };
  740. } else if (geometry.type === 'LineString') {
  741. const newCoordinates = geometry.coordinates.map((coords) => {
  742. const [x, y] = coords;
  743. const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
  744. return [obj.lng, obj.lat];
  745. });
  746. newGeometry = { ...geometry, coordinates: newCoordinates };
  747. } else if (geometry.type === 'MultiLineString') {
  748. const newCoordinates = geometry.coordinates.map((line) =>
  749. line.map((coords) => {
  750. const [x, y] = coords;
  751. const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
  752. return [obj.lng, obj.lat];
  753. })
  754. );
  755. newGeometry = { ...geometry, coordinates: newCoordinates };
  756. } else if (geometry.type === 'Polygon') {
  757. const newCoordinates = geometry.coordinates.map((polygon) =>
  758. polygon.map((coords) => {
  759. const [x, y] = coords;
  760. const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
  761. return [obj.lng, obj.lat];
  762. })
  763. );
  764. newGeometry = { ...geometry, coordinates: newCoordinates };
  765. } else if (geometry.type === 'MultiPolygon') {
  766. const newCoordinates = geometry.coordinates.map((polygon) =>
  767. polygon.map((ring) =>
  768. ring.map((coords) => {
  769. const [x, y] = coords;
  770. const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
  771. return [obj.lng, obj.lat];
  772. })
  773. )
  774. );
  775. newGeometry = { ...geometry, coordinates: newCoordinates };
  776. }
  777. return { ...feature, geometry: newGeometry };
  778. });
  779. return { ...geoJson, features };
  780. };
  781. onMounted(() => {
  782. initMap(options);
  783. });
  784. return {
  785. initMap,
  786. getAMap,
  787. getMap,
  788. switchMap,
  789. addMarker,
  790. addMarker2,
  791. addSearchMarker,
  792. clearMarker,
  793. clearMarker2,
  794. getScale,
  795. showInfo,
  796. hideInfo,
  797. creatMask,
  798. removeMask,
  799. creatMask2,
  800. removeMask2,
  801. trackPlayback,
  802. drawData,
  803. setAddress
  804. };
  805. }