Newer
Older
DH_Apicture / public / static / libs / mapbox / extend / MeatureTool.js
@zhangqy zhangqy on 29 Nov 65 KB first commit
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ?
  3. module.exports = factory() :
  4. typeof define === 'function' && define.amd ? define(factory) :
  5. (global = typeof globalThis !== 'undefined' ? globalThis :
  6. global || self, global.mapboxgl1.MeatureTool = factory(global.mapboxgl1));
  7. }(window, (function (mapboxgl) {
  8.  
  9. const css = `
  10. /* Override default control style */
  11. .mapbox-gl-draw_ctrl-bottom-left,
  12. .mapbox-gl-draw_ctrl-top-left {
  13. margin-left:0;
  14. border-radius:0 4px 4px 0;
  15. }
  16. .mapbox-gl-draw_ctrl-top-right,
  17. .mapbox-gl-draw_ctrl-bottom-right {
  18. margin-right:0;
  19. border-radius:4px 0 0 4px;
  20. }
  21.  
  22. .mapbox-gl-draw_ctrl-draw-btn {
  23. border-color:rgba(0,0,0,0.9);
  24. color:rgba(255,255,255,0.5);
  25. width:30px;
  26. height:30px;
  27. }
  28.  
  29. .mapbox-gl-draw_ctrl-draw-btn.active,
  30. .mapbox-gl-draw_ctrl-draw-btn.active:hover {
  31. background-color:rgb(0 0 0/5%);
  32. }
  33. .mapbox-gl-draw_ctrl-draw-btn {
  34. background-repeat: no-repeat;
  35. background-position: center;
  36. }
  37.  
  38. .mapbox-gl-draw_point {
  39. background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20">%3Cpath d="m10 2c-3.3 0-6 2.7-6 6s6 9 6 9 6-5.7 6-9-2.7-6-6-6zm0 2c2.1 0 3.8 1.7 3.8 3.8 0 1.5-1.8 3.9-2.9 5.2h-1.7c-1.1-1.4-2.9-3.8-2.9-5.2-.1-2.1 1.6-3.8 3.7-3.8z"/>%3C/svg>');
  40. }
  41. .mapbox-gl-draw_polygon {
  42. background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20">%3Cpath d="m15 12.3v-4.6c.6-.3 1-1 1-1.7 0-1.1-.9-2-2-2-.7 0-1.4.4-1.7 1h-4.6c-.3-.6-1-1-1.7-1-1.1 0-2 .9-2 2 0 .7.4 1.4 1 1.7v4.6c-.6.3-1 1-1 1.7 0 1.1.9 2 2 2 .7 0 1.4-.4 1.7-1h4.6c.3.6 1 1 1.7 1 1.1 0 2-.9 2-2 0-.7-.4-1.4-1-1.7zm-8-.3v-4l1-1h4l1 1v4l-1 1h-4z"/>%3C/svg>');
  43. }
  44. .mapbox-gl-draw_line {
  45. background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20">%3Cpath d="m13.5 3.5c-1.4 0-2.5 1.1-2.5 2.5 0 .3 0 .6.2.9l-3.8 3.8c-.3-.1-.6-.2-.9-.2-1.4 0-2.5 1.1-2.5 2.5s1.1 2.5 2.5 2.5 2.5-1.1 2.5-2.5c0-.3 0-.6-.2-.9l3.8-3.8c.3.1.6.2.9.2 1.4 0 2.5-1.1 2.5-2.5s-1.1-2.5-2.5-2.5z"/>%3C/svg>');
  46. }
  47. .mapbox-gl-draw_trash {
  48. background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20">%3Cpath d="M10,3.4 c-0.8,0-1.5,0.5-1.8,1.2H5l-1,1v1h12v-1l-1-1h-3.2C11.5,3.9,10.8,3.4,10,3.4z M5,8v7c0,1,1,2,2,2h6c1,0,2-1,2-2V8h-2v5.5h-1.5V8h-3 v5.5H7V8H5z"/>%3C/svg>');
  49. }
  50. .mapbox-gl-draw_uncombine {
  51. background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20">%3Cpath d="m12 2c-.3 0-.5.1-.7.3l-1 1c-.4.4-.4 1 0 1.4l1 1c.4.4 1 .4 1.4 0l1-1c.4-.4.4-1 0-1.4l-1-1c-.2-.2-.4-.3-.7-.3zm4 4c-.3 0-.5.1-.7.3l-1 1c-.4.4-.4 1 0 1.4l1 1c.4.4 1 .4 1.4 0l1-1c.4-.4.4-1 0-1.4l-1-1c-.2-.2-.4-.3-.7-.3zm-7 1c-1 0-1 1-.5 1.5.3.3 1 1 1 1l-1 1s-.5.5 0 1 1 0 1 0l1-1 1 1c.5.5 1.5.5 1.5-.5v-4zm-5 3c-.3 0-.5.1-.7.3l-1 1c-.4.4-.4 1 0 1.4l4.9 4.9c.4.4 1 .4 1.4 0l1-1c.4-.4.4-1 0-1.4l-4.9-4.9c-.1-.2-.4-.3-.7-.3z"/>%3C/svg>');
  52. }
  53. .mapbox-gl-draw_combine {
  54. background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20">%3Cpath d="M12.1,2c-0.3,0-0.5,0.1-0.7,0.3l-1,1c-0.4,0.4-0.4,1,0,1.4l4.9,4.9c0.4,0.4,1,0.4,1.4,0l1-1 c0.4-0.4,0.4-1,0-1.4l-4.9-4.9C12.6,2.1,12.3,2,12.1,2z M8,8C7,8,7,9,7.5,9.5c0.3,0.3,1,1,1,1l-1,1c0,0-0.5,0.5,0,1s1,0,1,0l1-1l1,1 C11,13,12,13,12,12V8H8z M4,10c-0.3,0-0.5,0.1-0.7,0.3l-1,1c-0.4,0.4-0.4,1,0,1.4l1,1c0.4,0.4,1,0.4,1.4,0l1-1c0.4-0.4,0.4-1,0-1.4 l-1-1C4.5,10.1,4.3,10,4,10z M8,14c-0.3,0-0.5,0.1-0.7,0.3l-1,1c-0.4,0.4-0.4,1,0,1.4l1,1c0.4,0.4,1,0.4,1.4,0l1-1 c0.4-0.4,0.4-1,0-1.4l-1-1C8.5,14.1,8.3,14,8,14z"/>%3C/svg>');
  55. }
  56.  
  57. .mapboxgl-map.mouse-pointer .mapboxgl-canvas-container.mapboxgl-interactive {
  58. cursor: pointer;
  59. }
  60. .mapboxgl-map.mouse-move .mapboxgl-canvas-container.mapboxgl-interactive {
  61. cursor: move;
  62. }
  63. .mapboxgl-map.mouse-add .mapboxgl-canvas-container.mapboxgl-interactive {
  64. cursor: crosshair;
  65. }
  66. .mapboxgl-map.mouse-move.mode-direct_select .mapboxgl-canvas-container.mapboxgl-interactive {
  67. cursor: grab;
  68. cursor: -moz-grab;
  69. cursor: -webkit-grab;
  70. }
  71. .mapboxgl-map.mode-direct_select.feature-vertex.mouse-move .mapboxgl-canvas-container.mapboxgl-interactive {
  72. cursor: move;
  73. }
  74. .mapboxgl-map.mode-direct_select.feature-midpoint.mouse-pointer .mapboxgl-canvas-container.mapboxgl-interactive {
  75. cursor: cell;
  76. }
  77. .mapboxgl-map.mode-direct_select.feature-feature.mouse-move .mapboxgl-canvas-container.mapboxgl-interactive {
  78. cursor: move;
  79. }
  80. .mapboxgl-map.mode-static.mouse-pointer .mapboxgl-canvas-container.mapboxgl-interactive {
  81. cursor: grab;
  82. cursor: -moz-grab;
  83. cursor: -webkit-grab;
  84. }
  85.  
  86. .mapbox-gl-draw_boxselect {
  87. pointer-events: none;
  88. position: absolute;
  89. top: 0;
  90. left: 0;
  91. width: 0;
  92. height: 0;
  93. background: rgba(0,0,0,.1);
  94. border: 2px dotted #fff;
  95. opacity: 0.5;
  96. }
  97. .measure-move {
  98. border-radius: 3px;
  99. height: 16px;
  100. line-height: 16px;
  101. padding: 0 3px;
  102. font-size: 12px;
  103. box-shadow: 0 0 0 1px #ccc;
  104. float: right;
  105. cursor: default;
  106. }
  107.  
  108. .measure-result {
  109. border-radius: 3px;
  110. height: 16px;
  111. line-height: 16px;
  112. padding: 0 3px;
  113. font-size: 12px;
  114. box-shadow: 0 0 0 1px #ccc;
  115. float: right;
  116. cursor: default;
  117. z-index: 10;
  118. }
  119.  
  120. .close {
  121. width: 3px;
  122. height: 14px;
  123. text-align: center;
  124. border-radius: 3px;
  125. padding-top: 0px;
  126. padding-right: 10px;
  127. box-shadow: 0 0 0 0px #ccc;
  128. cursor: pointer;
  129. background: url(../measureicon/close.png) no-repeat center;
  130. border: 1px solid rgba(100, 100, 100, 0)
  131. }
  132.  
  133. .clear {
  134. width: 3px;
  135. height: 14px;
  136. text-align: center;
  137. border-radius: 3px;
  138. padding-right: 10px;
  139. box-shadow: 0 0 0 0px #ccc;
  140. cursor: pointer;
  141. float: right;
  142. background: url(../measureicon/delete.png) no-repeat center;
  143. border: 1px solid rgba(100, 100, 100, 0)
  144. }
  145.  
  146. .edit {
  147. width: 3px;
  148. height: 14px;
  149. text-align: center;
  150. border-radius: 3px;
  151. padding-right: 10px;
  152. box-shadow: 0 0 0 0px #ccc;
  153. cursor: pointer;
  154. float: right;
  155. background: url(../measureicon/edit.png) no-repeat center;
  156. border: 1px solid rgba(100, 100, 100, 0)
  157. }
  158.  
  159. .close:hover {
  160. border: 1px solid rgba(52, 98, 152, 1);
  161. }
  162.  
  163. .clear:hover {
  164. border: 1px solid rgba(52, 98, 152, 1);
  165. }
  166.  
  167. .edit:hover {
  168. border: 1px solid rgba(52, 98, 152, 1);
  169. }
  170. `;
  171. document.write(`<style type='text/css'>${css}</style>`);
  172.  
  173. return class {
  174. constructor(map) {
  175. this.map = map;
  176. }
  177.  
  178. layerDistanceList = []
  179. layerAreaList = []
  180. layerPointList = []
  181. setDistance = () => {}
  182. setArea = () => { }
  183.  
  184. /**
  185. * 测量距离
  186. * @param {*} layerId
  187. */
  188. measureDistance(layerId,isP=true,features=[],callback = ()=>{}) {
  189. this.layerDistanceList.push(layerId)
  190. var isMeasure = true
  191. const map = this.map
  192. map.doubleClickZoom.disable()
  193. let catchMark = null
  194. let isEdit = false
  195. let Geolist = []
  196. let dragPointOrder = 0
  197. let pointOnLine = [0, 0]
  198.  
  199. const jsonPoint = {
  200. type: 'FeatureCollection',
  201. features: [],
  202. }
  203. const jsonLine = {
  204. type: 'FeatureCollection',
  205. features: features,
  206. }
  207.  
  208. // 添加测量结果弹窗
  209. const ele = document.createElement('div')
  210. ele.setAttribute('class', 'measure-move')
  211. const option = {
  212. element: ele,
  213. anchor: 'left',
  214. offset: [8, 0],
  215. }
  216. const tooltip = new mapboxgl.Marker(option).setLngLat([0, 0]);
  217. if(isP) tooltip.addTo(map);
  218.  
  219. // 添加测量图层
  220. map.addSource('points' + layerId, {
  221. type: 'geojson',
  222. data: jsonPoint,
  223. })
  224. map.addSource('point-move' + layerId, {
  225. type: 'geojson',
  226. data: jsonPoint,
  227. })
  228. map.addSource('line' + layerId, {
  229. type: 'geojson',
  230. data: jsonLine,
  231. })
  232. map.addSource('line-move' + layerId, {
  233. type: 'geojson',
  234. data: jsonLine,
  235. })
  236. map.addSource('point-follow' + layerId, {
  237. type: 'geojson',
  238. data: jsonPoint,
  239. })
  240. map.addLayer({
  241. id: 'line' + layerId,
  242. type: 'line',
  243. source: 'line' + layerId,
  244. paint: {
  245. 'line-color': '#ff0000',
  246. 'line-width': 2,
  247. 'line-opacity': 0.65,
  248. },
  249. })
  250. map.addLayer({
  251. id: 'line-move' + layerId,
  252. type: 'line',
  253. source: 'line-move' + layerId,
  254. paint: {
  255. 'line-color': '#ff0000',
  256. 'line-width': 2,
  257. 'line-opacity': 0.65,
  258. 'line-dasharray': [5, 2],
  259. },
  260. })
  261. map.addLayer({
  262. id: 'points' + layerId,
  263. type: 'circle',
  264. source: 'points' + layerId,
  265. paint: {
  266. 'circle-color': '#ffffff',
  267. 'circle-radius': 3.5,
  268. 'circle-stroke-width': 1.5,
  269. 'circle-stroke-color': '#ff0000',
  270. },
  271. })
  272. map.addLayer({
  273. id: 'point-move' + layerId,
  274. type: 'circle',
  275. source: 'point-move' + layerId,
  276. paint: {
  277. 'circle-color': '#ffffff',
  278. 'circle-radius': 3.5,
  279. 'circle-stroke-width': 1.5,
  280. 'circle-stroke-color': '#ff0000',
  281. },
  282. })
  283. // 活动点可以选择用图层,也可以选择用Mark
  284. map.addLayer({
  285. id: 'point-follow' + layerId,
  286. type: 'circle',
  287. source: 'point-follow' + layerId,
  288. paint: {
  289. 'circle-color': '#199afc',
  290. 'circle-radius': 5.5,
  291. 'circle-stroke-width': 1.5,
  292. 'circle-stroke-color': '#ffffff',
  293. },
  294. })
  295.  
  296. if(features.length) return;
  297. // 清除面积测量
  298. this.setArea = () => {
  299. isMeasure = false
  300. if(map.getLayer('point-move' + layerId)) map.removeLayer('point-move' + layerId)
  301. if(map.getLayer('line-move' + layerId)) map.removeLayer('line-move' + layerId)
  302.  
  303. return isMeasure
  304. }
  305.  
  306. /**
  307. * 添加点
  308. * @param {*} _e
  309. */
  310. function addPointforJSON(_e) {
  311. if (isMeasure) {
  312. const point = {
  313. type: 'Feature',
  314. geometry: {
  315. type: 'Point',
  316. coordinates: [_e.lngLat.lng, _e.lngLat.lat],
  317. },
  318. properties: {
  319. id: String(new Date().getTime()),
  320. },
  321. }
  322. jsonPoint.features.push(point)
  323. map.getSource('points' + layerId).setData(jsonPoint)
  324. drawLine(jsonPoint)
  325. addMeasureRes(jsonPoint)
  326. }
  327. }
  328.  
  329. /**
  330. * 绘制线
  331. * @param {*} jsonPoint
  332. */
  333. function drawLine(jsonPoint) {
  334. if (jsonPoint.features.length > 1) {
  335. jsonLine.features = []
  336. for (let i = 0; i < jsonPoint.features.length - 1; i++) {
  337. const coords = jsonPoint.features[i].geometry.coordinates
  338. const next_coords = jsonPoint.features[i + 1].geometry.coordinates
  339. jsonLine.features.push({
  340. type: 'Feature',
  341. geometry: {
  342. type: 'LineString',
  343. coordinates: [coords, next_coords],
  344. },
  345. })
  346. }
  347. map.getSource('line' + layerId).setData(jsonLine)
  348. }
  349. }
  350.  
  351. /**
  352. * 添加dom
  353. * @param {*} jsonPoint 点集
  354. */
  355. function addMeasureRes(jsonPoint) {
  356.  
  357. if (isP && jsonPoint.features.length > 0) {
  358. removedom()
  359. const pointList = []
  360. for (let i = 0; i < jsonPoint.features.length; i++) {
  361. const coords = jsonPoint.features[i].geometry.coordinates
  362. pointList.push(coords)
  363.  
  364. const close = document.createElement('div')
  365. close.setAttribute('class', `measure-result ${layerId} close`)
  366. close.onclick = (__e) => {
  367. // 移除点
  368. __e.stopPropagation()
  369. removePoint(coords)
  370. map.off('mousemove', onMouseMove)
  371. map.off('mousedown', onmousedown)
  372. if (catchMark) {
  373. catchMark.remove()
  374. }
  375. }
  376.  
  377. const clear = document.createElement('div')
  378. clear.setAttribute('class', `measure-result ${layerId} clear`)
  379. clear.onclick = (__e) => {
  380. // 全部删除
  381. __e.stopPropagation()
  382. removeLayer()
  383. map.off('mousemove', onMouseMove)
  384. map.off('mousedown', onmousedown)
  385. if (catchMark) {
  386. catchMark.remove()
  387. }
  388. }
  389.  
  390. const edit = document.createElement('div')
  391. edit.setAttribute('class', `measure-result ${layerId} edit`)
  392. edit.onclick = (__e) => {
  393. // 编辑线
  394. __e.stopPropagation()
  395. map.off('mousemove', onMouseMove)
  396. map.off('mousedown', onmousedown)
  397. if (catchMark) {
  398. catchMark.remove()
  399. }
  400. editLine()
  401. }
  402.  
  403. const element = document.createElement('div')
  404. element.setAttribute('class', 'measure-result ' + layerId)
  405. const option = {
  406. element: element,
  407. anchor: 'left',
  408. offset: [8, 0],
  409. }
  410. element.innerHTML = i === 0 ? '起点' : getLength(pointList)
  411. if ((jsonPoint.features.length === i + 1) & !isMeasure) {
  412. element.appendChild(edit)
  413. element.appendChild(clear)
  414. }
  415. element.appendChild(close)
  416. new mapboxgl.Marker(option).setLngLat(coords).addTo(map)
  417. }
  418. }
  419. }
  420.  
  421. /**
  422. * 移除点
  423. * @param {*} coords 点坐标
  424. */
  425. function removePoint(coords) {
  426. if (jsonPoint.features.length > 0) {
  427. if (jsonPoint.features.length === 2) {
  428. jsonPoint.features = []
  429. jsonLine.features = []
  430. map.getSource('points' + layerId).setData(jsonPoint)
  431. map.getSource('line' + layerId).setData(jsonLine)
  432. removedom()
  433. } else {
  434. for (let i = 0; i < jsonPoint.features.length; i++) {
  435. if (
  436. (jsonPoint.features[i].geometry.coordinates[0] === coords[0]) &
  437. (jsonPoint.features[i].geometry.coordinates[1] === coords[1])
  438. ) {
  439. jsonPoint.features.splice(i, 1)
  440. }
  441. }
  442. drawLine(jsonPoint)
  443. addMeasureRes(jsonPoint)
  444. map.getSource('points' + layerId).setData(jsonPoint)
  445. }
  446. }
  447. }
  448.  
  449. /**
  450. * 计算长度
  451. * @param {*} pointList
  452. * @returns
  453. */
  454. function getLength(pointList) {
  455. const line = turf.lineString(pointList)
  456. let len = turf.length(line)
  457. if (len < 1) {
  458. len = Math.round(len * 1000) + '米'
  459. } else {
  460. len = len.toFixed(2) + '公里'
  461. }
  462. return len
  463. }
  464.  
  465. /**
  466. * 移除dom
  467. */
  468. function removedom() {
  469. const dom = document.getElementsByClassName('measure-result ' + layerId)
  470. const len = dom.length
  471. if (len) {
  472. for (let i = len - 1; i >= 0; i--) {
  473. if (dom[i]) dom[i].remove()
  474. }
  475. }
  476. }
  477.  
  478. /**
  479. * 移除图层
  480. */
  481. function removeLayer() {
  482. jsonPoint.features = []
  483. jsonLine.features = []
  484. if(map.getLayer('points' + layerId)) map.removeLayer('points' + layerId)
  485. if(map.getLayer('line' + layerId)) map.removeLayer('line' + layerId)
  486. removedom()
  487. }
  488.  
  489. /**
  490. * 鼠标move事件
  491. * @param {} _e
  492. */
  493. function mouseMove(_e) {
  494. if (isMeasure) {
  495. map.getCanvas().style.cursor = 'default'
  496. var coords = [_e.lngLat.lng, _e.lngLat.lat]
  497. const jsonp = {
  498. type: 'Feature',
  499. geometry: {
  500. type: 'Point',
  501. coordinates: coords,
  502. },
  503. }
  504. map.getSource('point-move' + layerId).setData(jsonp)
  505.  
  506. if (jsonPoint.features.length > 0) {
  507. const pointList = []
  508. for (let i = 0; i < jsonPoint.features.length; i++) {
  509. const coord = jsonPoint.features[i].geometry.coordinates
  510. pointList.push(coord)
  511. }
  512. pointList.push(coords)
  513. const prev = jsonPoint.features[jsonPoint.features.length - 1]
  514. const jsonl = {
  515. type: 'Feature',
  516. geometry: {
  517. type: 'LineString',
  518. coordinates: [prev.geometry.coordinates, coords],
  519. },
  520. }
  521. map.getSource('line-move' + layerId).setData(jsonl)
  522. ele.innerHTML = getLength(pointList)
  523. tooltip.setLngLat(coords)
  524. }
  525. }
  526. }
  527.  
  528. /**
  529. * 绘制完成
  530. * @param {*} _e
  531. */
  532. function finish(_e) {
  533. if (isMeasure) {
  534. isMeasure = false
  535. var coords = [_e.lngLat.lng, _e.lngLat.lat]
  536. removePoint(coords)
  537. if(map.getLayer('point-move' + layerId)) map.removeLayer('point-move' + layerId)
  538. if(map.getLayer('line-move' + layerId)) map.removeLayer('line-move' + layerId)
  539. map.getCanvas().style.cursor = 'default'
  540. tooltip.remove();
  541. let features = map.getSource('line'+layerId)._data.features;
  542. let coordinates = features.map(i => turf.coordAll(i)[0]);
  543. if(coordinates.length ==1) coordinates = turf.coordAll(features[0])
  544. callback(turf.lineString(coordinates));
  545. }
  546. }
  547.  
  548. map.on('click', function (_e) {
  549. addPointforJSON(_e)
  550. })
  551.  
  552. map.on('mousemove', function (_e) {
  553. mouseMove(_e)
  554. })
  555.  
  556. map.on('dblclick', function (_e) {
  557. finish(_e)
  558. })
  559.  
  560. /**
  561. * 编辑测量线
  562. */
  563. function editLine() {
  564. catchMark = createMarker()
  565. UpdataGeolist()
  566.  
  567. map.on('mousemove', onMouseMove)
  568. map.on('mousedown', onmousedown)
  569. }
  570.  
  571. function onMouseMove(e) {
  572. const moveCoord = [e.lngLat.lng, e.lngLat.lat]
  573.  
  574. if (jsonPoint.features.length > 1) {
  575. // 计算当前指针与线段最近的点
  576. pointOnLine = getNearestPointOnLine(Geolist, moveCoord) // 自己计算
  577. const screenOnLine = Object.values(map.project(pointOnLine)) // 线上屏幕坐标
  578. const screenP = [e.point.x, e.point.y]
  579. const screenDist = screenDistance(screenOnLine, screenP) // 距离
  580. if (screenDist < 15) {
  581. isEdit = true
  582. catchMark.setLngLat(pointOnLine).addTo(map)
  583. catchMark.getElement().style.display = 'block'
  584. } else {
  585. isEdit = false
  586. catchMark.getElement().style.display = 'none'
  587. }
  588. } else {
  589. isEdit = false
  590. catchMark.getElement().style.display = 'none'
  591. map.dragPan.enable()
  592. }
  593. }
  594.  
  595. function onmousedown(e) {
  596. if (isEdit) {
  597. map.dragPan.disable()
  598. let isExist = false
  599.  
  600. // 首先判断编辑点是否是存在(存在修改原来点,不存在新加点)
  601. for (let i = 0; i < jsonPoint.features.length; i++) {
  602. const coord = jsonPoint.features[i].geometry.coordinates
  603. if (coord[0] === pointOnLine[0] && coord[1] === pointOnLine[1]) {
  604. isExist = true
  605. }
  606. }
  607.  
  608. // 获取编辑点在列表中的位置
  609. dragPointOrder = getDragCoords(pointOnLine, Geolist)
  610.  
  611. if (!isExist) {
  612. // 添加编辑点
  613. const point = {
  614. type: 'Feature',
  615. geometry: {
  616. type: 'Point',
  617. coordinates: pointOnLine,
  618. },
  619. properties: {
  620. id: String(new Date().getTime()),
  621. },
  622. }
  623. jsonPoint.features.splice(dragPointOrder, 0, point)
  624.  
  625. // 更新绘制要素
  626. updataFeature()
  627. }
  628.  
  629. map.on('mousemove', onDrag)
  630. map.on('mouseup', onMouseup)
  631. }
  632. }
  633.  
  634. function onDrag(e) {
  635. // 开始计时
  636. // var start = new Date().getTime()
  637. const movePoint = [e.lngLat.lng, e.lngLat.lat]
  638.  
  639. // 点跟随鼠标移动
  640. jsonPoint.features[dragPointOrder].geometry.coordinates = movePoint
  641.  
  642. // 更新绘制要素
  643. updataFeature()
  644.  
  645. // 计时结束
  646. // var end1 = new Date().getTime()
  647. // console.log('渲染时间:', end1 - start + 'ms')
  648. }
  649.  
  650. // 更新绘制要素
  651. function updataFeature() {
  652. UpdataGeolist()
  653. map.getSource('points' + layerId).setData(jsonPoint)
  654. drawLine(jsonPoint)
  655. addMeasureRes(jsonPoint)
  656. }
  657.  
  658. function onMouseup(e) {
  659. map.off('mousemove', onDrag)
  660. map.dragPan.enable()
  661. }
  662.  
  663. // 创建Marker
  664. function createMarker() {
  665. const markerParam = {
  666. map: this.map,
  667. lngLat: [0, 0],
  668. height: 13,
  669. width: 13,
  670. size: 13,
  671. isDrag: false,
  672. cursor: 'default',
  673. }
  674. return new mapboxgl.Marker().setLngLat(markerParam.lngLat).setDraggable(false).addTo(markerParam.map);
  675. }
  676.  
  677. // 更新点集
  678. function UpdataGeolist() {
  679. Geolist = []
  680. for (let i = 0; i < jsonPoint.features.length; i++) {
  681. const coord = jsonPoint.features[i].geometry.coordinates
  682. Geolist.push(coord)
  683. }
  684. }
  685.  
  686. // 计算点到直线最近距离的点
  687. function getNearestPointOnLine(list, moveCoord) {
  688. var dis, point1, point2
  689. for (let i = 0; i < list.length - 1; i++) {
  690. const distance = getNearestDistance(moveCoord, list[i], list[i + 1])
  691. if (i === 0) {
  692. dis = distance
  693. point1 = list[i]
  694. point2 = list[i + 1]
  695. } else {
  696. if (distance < dis) {
  697. dis = distance
  698. point1 = list[i]
  699. point2 = list[i + 1]
  700. }
  701. }
  702. }
  703. const Point = getNearestPoint(moveCoord, point1, point2)
  704. return Point
  705. }
  706.  
  707. // 计算点point到线段point1, point2最近距离
  708. function getNearestDistance(point, point1, point2) {
  709. const P = {}
  710. const A = {}
  711. const B = {}
  712. P.x = point[0]
  713. P.y = point[1]
  714. A.x = point1[0]
  715. A.y = point1[1]
  716. B.x = point2[0]
  717. B.y = point2[1]
  718. // 计算向量AP和向量AB的点积
  719. const dotProduct = (P.x - A.x) * (B.x - A.x) + (P.y - A.y) * (B.y - A.y)
  720. // 计算向量AB的长度的平方
  721. const lengthSquare = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)
  722. // 计算点P到线段AB的投影点C
  723. const t = dotProduct / lengthSquare
  724. const C = { x: A.x + t * (B.x - A.x), y: A.y + t * (B.y - A.y) }
  725. // 如果点C在线段AB内,则点P到线段AB的最近距离为PC的长度;否则,点P到线段AB的最近距离为PA或PB中的较小值。
  726. const isInside = dotProduct >= 0 && dotProduct <= lengthSquare
  727. if (isInside) {
  728. return Math.sqrt((P.x - C.x) * (P.x - C.x) + (P.y - C.y) * (P.y - C.y))
  729. } else {
  730. return Math.min(
  731. Math.sqrt((P.x - A.x) * (P.x - A.x) + (P.y - A.y) * (P.y - A.y)),
  732. Math.sqrt((P.x - B.x) * (P.x - B.x) + (P.y - B.y) * (P.y - B.y))
  733. )
  734. }
  735. }
  736.  
  737. // 计算点到直线最近的点 point点坐标,point1, point2直线两个端点
  738. function getNearestPoint(point, point1, point2) {
  739. var x, y, x0, y0, x1, y1, x2, y2
  740. x0 = point[0]
  741. y0 = point[1]
  742. x1 = point1[0]
  743. y1 = point1[1]
  744. x2 = point2[0]
  745. y2 = point2[1]
  746.  
  747. if (x1 !== x2 && y1 !== y2) {
  748. const a = (y2 - y1) / (x2 - x1)
  749. const b = y1 - a * x1
  750. const k2 = -1 / a
  751. const b2 = y0 - k2 * x0
  752. x = (b2 - b) / (a - k2)
  753. y = a * x + b
  754. } else if (x1 === x2) {
  755. x = x1
  756. y = y0
  757. } else if (y1 === y2) {
  758. x = x0
  759. y = y1
  760. }
  761.  
  762. // 点不能超出线段
  763. if (x1 < x2) {
  764. if (x2 < x) {
  765. x = x2
  766. } else if (x < x1) {
  767. x = x1
  768. }
  769. } else {
  770. if (x1 < x) {
  771. x = x1
  772. } else if (x < x2) {
  773. x = x2
  774. }
  775. }
  776. if (y1 < y2) {
  777. if (y2 < y) {
  778. y = y2
  779. } else if (y < y1) {
  780. y = y1
  781. }
  782. } else {
  783. if (y1 < y) {
  784. y = y1
  785. } else if (y < y2) {
  786. y = y2
  787. }
  788. }
  789.  
  790. // 点吸附端点
  791. const screenX0 = Object.values(map.project([x0, y0])) // 屏幕坐标
  792. const screenX1 = Object.values(map.project([x1, y1])) // 屏幕坐标
  793. const screenX2 = Object.values(map.project([x2, y2])) // 屏幕坐标
  794. const screenDistX1 = screenDistance(screenX0, screenX1) // 距离
  795. const screenDistX2 = screenDistance(screenX0, screenX2) // 距离
  796. if (screenDistX1 < 10) {
  797. x = x1
  798. y = y1
  799. }
  800. if (screenDistX2 < 10) {
  801. x = x2
  802. y = y2
  803. }
  804.  
  805. return [x, y]
  806. }
  807.  
  808. // 屏幕距离
  809. function screenDistance(point1, point2) {
  810. const x2 = Math.pow(point1[0] - point2[0], 2)
  811. const y2 = Math.pow(point1[1] - point2[1], 2)
  812. const dist = Math.sqrt(x2 + y2)
  813.  
  814. return dist
  815. }
  816.  
  817. // 计算编辑点在线段上的添加位置
  818. function getDragCoords(coords, list) {
  819. var x, y, x1, y1, x2, y2
  820. let index = 0
  821. x = coords[0]
  822. y = coords[1]
  823.  
  824. for (let i = 0; i < list.length - 1; i++) {
  825. x1 = list[i][0]
  826. y1 = list[i][1]
  827. x2 = list[i + 1][0]
  828. y2 = list[i + 1][1]
  829.  
  830. if (x === x1 && y === y1) {
  831. index = i
  832. break
  833. } else {
  834. // 计算线段的长度
  835. const length = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
  836. // 计算点到线段起点的距离
  837. const distance1 = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2))
  838. // 计算点到线段终点的距离
  839. const distance2 = Math.sqrt(Math.pow(x - x2, 2) + Math.pow(y - y2, 2))
  840. // 如果点到线段两个端点的距离之和等于线段的长度,则点在线段上
  841. if (Math.abs(length - distance1 - distance2) < 0.00001) {
  842. index = i + 1
  843. break
  844. }
  845. }
  846. }
  847. return index
  848. }
  849. }
  850.  
  851. /**
  852. * 测量面积
  853. * @param {*} layerId
  854. */
  855. measureArea(layerId,isP=true,callback=()=>{}) {
  856. this.layerAreaList.push(layerId)
  857. var isMeasure = true
  858. const map = this.map
  859. map.doubleClickZoom.disable()
  860. let catchMark = null
  861. let isEdit = false
  862. let Geolist = []
  863. let dragPointOrder = 0
  864. let pointOnLine = [0, 0]
  865.  
  866. const jsonPoint = {
  867. type: 'FeatureCollection',
  868. features: [],
  869. }
  870. const jsonLine = {
  871. type: 'FeatureCollection',
  872. features: [],
  873. }
  874.  
  875. const ele = document.createElement('div')
  876. ele.setAttribute('class', 'measure-move')
  877. const option = {
  878. element: ele,
  879. anchor: 'left',
  880. offset: [8, 0],
  881. }
  882. const tooltip = new mapboxgl.Marker(option).setLngLat([0, 0]);
  883. if(isP) tooltip.addTo(map);
  884. map.addSource('points-area' + layerId, {
  885. type: 'geojson',
  886. data: jsonPoint,
  887. })
  888. map.addSource('point-move' + layerId, {
  889. type: 'geojson',
  890. data: jsonPoint,
  891. })
  892. map.addSource('line-area' + layerId, {
  893. type: 'geojson',
  894. data: jsonLine,
  895. })
  896. map.addSource('line-move' + layerId, {
  897. type: 'geojson',
  898. data: jsonLine,
  899. })
  900. map.addLayer({
  901. id: 'line-move' + layerId,
  902. type: 'line',
  903. source: 'line-move' + layerId,
  904. paint: {
  905. 'line-color': '#ff0000',
  906. 'line-width': 2,
  907. 'line-opacity': 0.65,
  908. 'line-dasharray': [5, 2],
  909. },
  910. })
  911. map.addLayer({
  912. id: 'line-area' + layerId,
  913. type: 'fill',
  914. source: 'line-area' + layerId,
  915. paint: {
  916. 'fill-color': '#ff0000',
  917. 'fill-opacity': 0.1,
  918. },
  919. })
  920. map.addLayer({
  921. id: 'line-area-stroke' + layerId,
  922. type: 'line',
  923. source: 'line-area' + layerId,
  924. paint: {
  925. 'line-color': '#ff0000',
  926. 'line-width': 2,
  927. 'line-opacity': 0.65,
  928. },
  929. })
  930. map.addLayer({
  931. id: 'points-area' + layerId,
  932. type: 'circle',
  933. source: 'points-area' + layerId,
  934. paint: {
  935. 'circle-color': '#ffffff',
  936. 'circle-radius': 3.5,
  937. 'circle-stroke-width': 1.5,
  938. 'circle-stroke-color': '#ff0000',
  939. },
  940. })
  941. map.addLayer({
  942. id: 'point-move' + layerId,
  943. type: 'circle',
  944. source: 'point-move' + layerId,
  945. paint: {
  946. 'circle-color': '#ffffff',
  947. 'circle-radius': 3.5,
  948. 'circle-stroke-width': 1.5,
  949. 'circle-stroke-color': '#ff0000',
  950. },
  951. })
  952.  
  953. this.setDistance = () => {
  954. isMeasure = false
  955. if(map.getLayer('point-move' + layerId)) map.removeLayer('point-move' + layerId)
  956. if(map.getLayer('line-move' + layerId)) map.removeLayer('line-move' + layerId)
  957.  
  958. return isMeasure
  959. }
  960.  
  961. /**
  962. * 添加点
  963. * @param {*} _e
  964. */
  965. function addPointforJSON(_e) {
  966. if (isMeasure) {
  967. const point = {
  968. type: 'Feature',
  969. geometry: {
  970. type: 'Point',
  971. coordinates: [_e.lngLat.lng, _e.lngLat.lat],
  972. },
  973. properties: {
  974. id: String(new Date().getTime()),
  975. },
  976. }
  977. jsonPoint.features.push(point)
  978. map.getSource('points-area' + layerId).setData(jsonPoint)
  979. addMeasureRes(jsonPoint)
  980. }
  981. }
  982.  
  983. /**
  984. * 添加dom
  985. * @param {*} jsonPoint 点集
  986. */
  987. function addMeasureRes(jsonPoint) {
  988. if (isP && jsonPoint.features.length > 0) {
  989. removedom()
  990. const pointList = []
  991. for (let i = 0; i < jsonPoint.features.length; i++) {
  992. const coords = jsonPoint.features[i].geometry.coordinates
  993. pointList.push(coords)
  994.  
  995. const close = document.createElement('div')
  996. close.setAttribute('class', `measure-result ${layerId} close`)
  997. close.onclick = (__e) => {
  998. // 移除点
  999. __e.stopPropagation()
  1000. removePoint(coords)
  1001. map.off('mousemove', onMouseMove)
  1002. map.off('mousedown', onmousedown)
  1003. if (catchMark) {
  1004. catchMark.remove()
  1005. }
  1006. }
  1007. if ((jsonPoint.features.length === i + 1) & !isMeasure) {
  1008. const clear = document.createElement('div')
  1009. clear.setAttribute('class', `measure-result ${layerId} clear`)
  1010. clear.onclick = (__e) => {
  1011. // 全部移除
  1012. __e.stopPropagation()
  1013. removeLayer()
  1014. map.off('mousemove', onMouseMove)
  1015. map.off('mousedown', onmousedown)
  1016. if (catchMark) {
  1017. catchMark.remove()
  1018. }
  1019. }
  1020.  
  1021. const edit = document.createElement('div')
  1022. edit.setAttribute('class', `measure-result ${layerId} edit`)
  1023. edit.onclick = (__e) => {
  1024. // 编辑
  1025. __e.stopPropagation()
  1026. map.off('mousemove', onMouseMove)
  1027. map.off('mousedown', onmousedown)
  1028. if (catchMark) {
  1029. catchMark.remove()
  1030. }
  1031. editArea()
  1032. }
  1033.  
  1034. const element = document.createElement('div')
  1035. element.setAttribute('class', 'measure-result ' + layerId)
  1036. const option = {
  1037. element: element,
  1038. anchor: 'left',
  1039. offset: [0, 0],
  1040. }
  1041. element.innerHTML = getArea(pointList)
  1042. element.appendChild(edit)
  1043. element.appendChild(clear)
  1044. element.appendChild(close)
  1045. new mapboxgl.Marker(option).setLngLat(coords).addTo(map)
  1046. } else {
  1047. const option = {
  1048. element: close,
  1049. anchor: 'left',
  1050. offset: [5, -15],
  1051. }
  1052. new mapboxgl.Marker(option).setLngLat(coords).addTo(map)
  1053. }
  1054. }
  1055. }
  1056. }
  1057.  
  1058. /**
  1059. * 计算面积
  1060. * @param {*} pointList
  1061. * @returns
  1062. */
  1063. function getArea(pointList) {
  1064. pointList.push(pointList[0])
  1065. const polygon = turf.polygon([pointList])
  1066. let area = turf.area(polygon)
  1067. if (area < 10000) {
  1068. area = Math.round(area) + '平方米'
  1069. } else {
  1070. area = (area / 1000000).toFixed(2) + '平方公里'
  1071. }
  1072. return area
  1073. }
  1074.  
  1075. /**
  1076. * 移除点
  1077. * @param {*} coords 点坐标
  1078. */
  1079. function removePoint(coords) {
  1080. if (jsonPoint.features.length > 0) {
  1081. if (jsonPoint.features.length === 3) {
  1082. jsonPoint.features = []
  1083. jsonLine.features = []
  1084. map.getSource('points-area' + layerId).setData(jsonPoint)
  1085. map.getSource('line-area' + layerId).setData(jsonLine)
  1086. removedom()
  1087. } else {
  1088. for (let i = 0; i < jsonPoint.features.length; i++) {
  1089. if (
  1090. (jsonPoint.features[i].geometry.coordinates[0] === coords[0]) &
  1091. (jsonPoint.features[i].geometry.coordinates[1] === coords[1])
  1092. ) {
  1093. jsonPoint.features.splice(i, 1)
  1094. }
  1095. }
  1096. addMeasureRes(jsonPoint)
  1097. map.getSource('points-area' + layerId).setData(jsonPoint)
  1098.  
  1099. const pointList = []
  1100. for (let i = 0; i < jsonPoint.features.length; i++) {
  1101. const coord = jsonPoint.features[i].geometry.coordinates
  1102. pointList.push(coord)
  1103. }
  1104. const pts = pointList.concat([pointList[0]])
  1105. const jsona = {
  1106. type: 'Feature',
  1107. geometry: {
  1108. type: 'Polygon',
  1109. coordinates: [pts],
  1110. },
  1111. }
  1112. map.getSource('line-area' + layerId).setData(jsona)
  1113. }
  1114. }
  1115. }
  1116.  
  1117. /**
  1118. * 移除dom
  1119. */
  1120. function removedom() {
  1121. const dom = document.getElementsByClassName('measure-result ' + layerId)
  1122. const len = dom.length
  1123. if (len) {
  1124. for (let i = len - 1; i >= 0; i--) {
  1125. if (dom[i]) dom[i].remove()
  1126. }
  1127. }
  1128. }
  1129.  
  1130. /**
  1131. * 移除图层
  1132. */
  1133. function removeLayer() {
  1134. jsonPoint.features = []
  1135. jsonLine.features = []
  1136. if(map.getLayer('points-area' + layerId)) map.removeLayer('points-area' + layerId)
  1137. if(map.getLayer('line-area' + layerId)) map.removeLayer('line-area' + layerId)
  1138. if(map.getLayer('line-area-stroke' + layerId)) map.removeLayer('line-area-stroke' + layerId)
  1139. removedom()
  1140. }
  1141.  
  1142. /**
  1143. * 鼠标move事件
  1144. * @param {} _e
  1145. */
  1146. function mouseMove(_e) {
  1147. if (isMeasure) {
  1148. map.getCanvas().style.cursor = 'default'
  1149. const coords = [_e.lngLat.lng, _e.lngLat.lat]
  1150. const jsonp = {
  1151. type: 'Feature',
  1152. geometry: {
  1153. type: 'Point',
  1154. coordinates: coords,
  1155. },
  1156. }
  1157. map.getSource('point-move' + layerId).setData(jsonp)
  1158.  
  1159. if (jsonPoint.features.length > 0) {
  1160. if (jsonPoint.features.length === 1) {
  1161. const prev = jsonPoint.features[jsonPoint.features.length - 1]
  1162. const jsonl = {
  1163. type: 'Feature',
  1164. geometry: {
  1165. type: 'LineString',
  1166. coordinates: [prev.geometry.coordinates, coords],
  1167. },
  1168. }
  1169. map.getSource('line-move' + layerId).setData(jsonl)
  1170. } else {
  1171. const json = {
  1172. type: 'FeatureCollection',
  1173. features: [],
  1174. }
  1175. map.getSource('line-move' + layerId).setData(json)
  1176.  
  1177. const pointList = []
  1178. for (let i = 0; i < jsonPoint.features.length; i++) {
  1179. const coord = jsonPoint.features[i].geometry.coordinates
  1180. pointList.push(coord)
  1181. }
  1182. pointList.push(coords)
  1183. const pts = pointList.concat([pointList[0]])
  1184. const jsona = {
  1185. type: 'Feature',
  1186. geometry: {
  1187. type: 'Polygon',
  1188. coordinates: [pts],
  1189. },
  1190. }
  1191. map.getSource('line-area' + layerId).setData(jsona)
  1192. ele.innerHTML = getArea(pointList)
  1193. tooltip.setLngLat(coords)
  1194. }
  1195. }
  1196. }
  1197. }
  1198.  
  1199. /**
  1200. * 绘制完成
  1201. * @param {*} _e
  1202. */
  1203. function finish(_e) {
  1204. if (isMeasure) {
  1205. isMeasure = false
  1206. const coords = [_e.lngLat.lng, _e.lngLat.lat]
  1207. removePoint(coords)
  1208. if(map.getLayer('point-move' + layerId)) map.removeLayer('point-move' + layerId)
  1209. if(map.getLayer('line-move' + layerId)) map.removeLayer('line-move' + layerId)
  1210. map.getCanvas().style.cursor = 'default'
  1211. tooltip.remove();
  1212. callback(map.getSource('line-area'+layerId)._data);
  1213. }
  1214. }
  1215.  
  1216. map.on('click', function (_e) {
  1217. addPointforJSON(_e)
  1218. })
  1219.  
  1220. map.on('dblclick', function (_e) {
  1221. finish(_e)
  1222. })
  1223.  
  1224. map.on('mousemove', function (_e) {
  1225. mouseMove(_e)
  1226. })
  1227.  
  1228. /**
  1229. * 编辑测量面
  1230. */
  1231. function editArea() {
  1232. catchMark = createMarker()
  1233. UpdataGeolist()
  1234.  
  1235. map.on('mousemove', onMouseMove)
  1236. map.on('mousedown', onmousedown)
  1237. }
  1238.  
  1239. function onMouseMove(e) {
  1240. const moveCoord = [e.lngLat.lng, e.lngLat.lat]
  1241.  
  1242. if (jsonPoint.features.length > 1) {
  1243. // 计算当前指针与线段的距离
  1244. pointOnLine = getNearestPointOnLine(Geolist, moveCoord) // 线上实际坐标
  1245. const screenOnLine = Object.values(map.project(pointOnLine)) // 线上屏幕坐标
  1246. const screenP = [e.point.x, e.point.y]
  1247. const screenDist = screenDistance(screenOnLine, screenP) // 距离
  1248. if (screenDist < 15) {
  1249. isEdit = true
  1250. catchMark.setLngLat(pointOnLine).addTo(map)
  1251. catchMark.getElement().style.display = 'block'
  1252. } else {
  1253. isEdit = false
  1254. catchMark.getElement().style.display = 'none'
  1255. }
  1256. } else {
  1257. isEdit = false
  1258. catchMark.getElement().style.display = 'none'
  1259. map.dragPan.enable()
  1260. }
  1261. }
  1262.  
  1263. function onmousedown(e) {
  1264. if (isEdit) {
  1265. map.dragPan.disable()
  1266. let isExist = false
  1267.  
  1268. // 首先判断编辑点是否是存在(存在修改原来点,不存在新加点)
  1269. for (let i = 0; i < jsonPoint.features.length; i++) {
  1270. const coord = jsonPoint.features[i].geometry.coordinates
  1271. if (coord[0] === pointOnLine[0] && coord[1] === pointOnLine[1]) {
  1272. isExist = true
  1273. }
  1274. }
  1275.  
  1276. // 获取编辑点在列表中的位置
  1277. dragPointOrder = getDragCoords(pointOnLine, Geolist)
  1278.  
  1279. if (!isExist) {
  1280. // 添加编辑点
  1281. const point = {
  1282. type: 'Feature',
  1283. geometry: {
  1284. type: 'Point',
  1285. coordinates: pointOnLine,
  1286. },
  1287. properties: {
  1288. id: String(new Date().getTime()),
  1289. },
  1290. }
  1291. jsonPoint.features.splice(dragPointOrder, 0, point)
  1292.  
  1293. // 更新绘制要素
  1294. updataFeature()
  1295. }
  1296.  
  1297. map.on('mousemove', onDrag)
  1298. map.on('mouseup', onMouseup)
  1299. }
  1300. }
  1301.  
  1302. function onDrag(e) {
  1303. const movePoint = [e.lngLat.lng, e.lngLat.lat]
  1304.  
  1305. // 点跟随鼠标移动
  1306. jsonPoint.features[dragPointOrder].geometry.coordinates = movePoint
  1307.  
  1308. // 更新绘制要素
  1309. updataFeature()
  1310. }
  1311.  
  1312. // 更新绘制要素
  1313. function updataFeature() {
  1314. UpdataGeolist()
  1315. const pts = Geolist
  1316. const jsona = {
  1317. type: 'Feature',
  1318. geometry: {
  1319. type: 'Polygon',
  1320. coordinates: [pts],
  1321. },
  1322. }
  1323. map.getSource('line-area' + layerId).setData(jsona)
  1324. map.getSource('points-area' + layerId).setData(jsonPoint)
  1325. addMeasureRes(jsonPoint)
  1326. }
  1327.  
  1328. function onMouseup(e) {
  1329. map.off('mousemove', onDrag)
  1330. map.dragPan.enable()
  1331. }
  1332.  
  1333. // 创建Marker
  1334. function createMarker() {
  1335. const markerParam = {
  1336. map:this.map,
  1337. lngLat: [0, 0],
  1338. height: 13,
  1339. width: 13,
  1340. size: 13,
  1341. isDrag: false,
  1342. cursor: 'default',
  1343. }
  1344. return new mapboxgl.Marker().setLngLat(markerParam.lngLat).setDraggable(false).addTo(markerParam.map);
  1345. }
  1346.  
  1347. // 更新点集
  1348. function UpdataGeolist() {
  1349. Geolist = []
  1350. for (let i = 0; i < jsonPoint.features.length; i++) {
  1351. const coord = jsonPoint.features[i].geometry.coordinates
  1352. Geolist.push(coord)
  1353. }
  1354. Geolist.push(Geolist[0])
  1355. }
  1356.  
  1357. // 计算点到直线最近距离的点
  1358. function getNearestPointOnLine(list, moveCoord) {
  1359. var dis, point1, point2
  1360. for (let i = 0; i < list.length - 1; i++) {
  1361. const distance = getNearestDistance(moveCoord, list[i], list[i + 1])
  1362. if (i === 0) {
  1363. dis = distance
  1364. point1 = list[i]
  1365. point2 = list[i + 1]
  1366. } else {
  1367. if (distance < dis) {
  1368. dis = distance
  1369. point1 = list[i]
  1370. point2 = list[i + 1]
  1371. }
  1372. }
  1373. }
  1374. const Point = getNearestPoint(moveCoord, point1, point2)
  1375. return Point
  1376. }
  1377.  
  1378. // 计算点point到线段point1, point2最近距离
  1379. function getNearestDistance(point, point1, point2) {
  1380. const P = {}
  1381. const A = {}
  1382. const B = {}
  1383. P.x = point[0]
  1384. P.y = point[1]
  1385. A.x = point1[0]
  1386. A.y = point1[1]
  1387. B.x = point2[0]
  1388. B.y = point2[1]
  1389. // 计算向量AP和向量AB的点积
  1390. const dotProduct = (P.x - A.x) * (B.x - A.x) + (P.y - A.y) * (B.y - A.y)
  1391. // 计算向量AB的长度的平方
  1392. const lengthSquare = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)
  1393. // 计算点P到线段AB的投影点C
  1394. const t = dotProduct / lengthSquare
  1395. const C = { x: A.x + t * (B.x - A.x), y: A.y + t * (B.y - A.y) }
  1396. // 如果点C在线段AB内,则点P到线段AB的最近距离为PC的长度;否则,点P到线段AB的最近距离为PA或PB中的较小值。
  1397. const isInside = dotProduct >= 0 && dotProduct <= lengthSquare
  1398. if (isInside) {
  1399. return Math.sqrt((P.x - C.x) * (P.x - C.x) + (P.y - C.y) * (P.y - C.y))
  1400. } else {
  1401. return Math.min(
  1402. Math.sqrt((P.x - A.x) * (P.x - A.x) + (P.y - A.y) * (P.y - A.y)),
  1403. Math.sqrt((P.x - B.x) * (P.x - B.x) + (P.y - B.y) * (P.y - B.y))
  1404. )
  1405. }
  1406. }
  1407.  
  1408. // 计算点到直线最近的点 point点坐标,point1, point2直线两个端点
  1409. function getNearestPoint(point, point1, point2) {
  1410. var x, y, x0, y0, x1, y1, x2, y2
  1411. x0 = point[0]
  1412. y0 = point[1]
  1413. x1 = point1[0]
  1414. y1 = point1[1]
  1415. x2 = point2[0]
  1416. y2 = point2[1]
  1417.  
  1418. if (x1 !== x2 && y1 !== y2) {
  1419. const a = (y2 - y1) / (x2 - x1)
  1420. const b = y1 - a * x1
  1421. const k2 = -1 / a
  1422. const b2 = y0 - k2 * x0
  1423. x = (b2 - b) / (a - k2)
  1424. y = a * x + b
  1425. } else if (x1 === x2) {
  1426. x = x1
  1427. y = y0
  1428. } else if (y1 === y2) {
  1429. x = x0
  1430. y = y1
  1431. }
  1432.  
  1433. // 点不能超出线段
  1434. if (x1 < x2) {
  1435. if (x2 < x) {
  1436. x = x2
  1437. } else if (x < x1) {
  1438. x = x1
  1439. }
  1440. } else {
  1441. if (x1 < x) {
  1442. x = x1
  1443. } else if (x < x2) {
  1444. x = x2
  1445. }
  1446. }
  1447. if (y1 < y2) {
  1448. if (y2 < y) {
  1449. y = y2
  1450. } else if (y < y1) {
  1451. y = y1
  1452. }
  1453. } else {
  1454. if (y1 < y) {
  1455. y = y1
  1456. } else if (y < y2) {
  1457. y = y2
  1458. }
  1459. }
  1460.  
  1461. // 点吸附端点
  1462. const screenX0 = Object.values(map.project([x0, y0])) // 屏幕坐标
  1463. const screenX1 = Object.values(map.project([x1, y1])) // 屏幕坐标
  1464. const screenX2 = Object.values(map.project([x2, y2])) // 屏幕坐标
  1465. const screenDistX1 = screenDistance(screenX0, screenX1) // 距离
  1466. const screenDistX2 = screenDistance(screenX0, screenX2) // 距离
  1467. if (screenDistX1 < 10) {
  1468. x = x1
  1469. y = y1
  1470. }
  1471. if (screenDistX2 < 10) {
  1472. x = x2
  1473. y = y2
  1474. }
  1475.  
  1476. return [x, y]
  1477. }
  1478.  
  1479. // 屏幕距离
  1480. function screenDistance(point1, point2) {
  1481. const x2 = Math.pow(point1[0] - point2[0], 2)
  1482. const y2 = Math.pow(point1[1] - point2[1], 2)
  1483. const dist = Math.sqrt(x2 + y2)
  1484.  
  1485. return dist
  1486. }
  1487.  
  1488. // 计算编辑点在线段上的添加位置
  1489. function getDragCoords(coords, list) {
  1490. var x, y, x1, y1, x2, y2
  1491. let index = 0
  1492. x = coords[0]
  1493. y = coords[1]
  1494.  
  1495. for (let i = 0; i < list.length - 1; i++) {
  1496. x1 = list[i][0]
  1497. y1 = list[i][1]
  1498. x2 = list[i + 1][0]
  1499. y2 = list[i + 1][1]
  1500.  
  1501. if (x === x1 && y === y1) {
  1502. index = i
  1503. break
  1504. } else {
  1505. // 计算线段的长度
  1506. const length = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
  1507. // 计算点到线段起点的距离
  1508. const distance1 = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2))
  1509. // 计算点到线段终点的距离
  1510. const distance2 = Math.sqrt(Math.pow(x - x2, 2) + Math.pow(y - y2, 2))
  1511. // 如果点到线段两个端点的距离之和等于线段的长度,则点在线段上
  1512. if (Math.abs(length - distance1 - distance2) < 0.00001) {
  1513. index = i + 1
  1514. break
  1515. }
  1516. }
  1517. }
  1518. return index
  1519. }
  1520. }
  1521.  
  1522. drawPoint(layerId,features=[],callback=()=>{}){
  1523. this.layerPointList.push(layerId);
  1524. const map = this.map;
  1525. map.doubleClickZoom.disable();
  1526. const jsonPoint = {
  1527. type: 'FeatureCollection',
  1528. features: features,
  1529. }
  1530. map.addSource('points' + layerId, {
  1531. type: 'geojson',
  1532. data: jsonPoint,
  1533. })
  1534. map.addLayer({
  1535. id: 'points' + layerId,
  1536. type: 'circle',
  1537. source: 'points' + layerId,
  1538. paint: {
  1539. 'circle-color': '#ffffff',
  1540. 'circle-radius': 3.5,
  1541. 'circle-stroke-width': 1.5,
  1542. 'circle-stroke-color': '#ff0000',
  1543. },
  1544. })
  1545.  
  1546. if(features.length) return;
  1547.  
  1548. /**
  1549. * 添加点
  1550. * @param {*} _e
  1551. */
  1552. function addPointforJSON(_e) {
  1553. const point = {
  1554. type: 'Feature',
  1555. geometry: {
  1556. type: 'Point',
  1557. coordinates: [_e.lngLat.lng, _e.lngLat.lat],
  1558. },
  1559. properties: {
  1560. id: String(new Date().getTime()),
  1561. },
  1562. }
  1563. jsonPoint.features.push(point)
  1564. map.getSource('points' + layerId).setData(jsonPoint);
  1565. map.off('click', addPointforJSON);
  1566. callback(point);
  1567. }
  1568. map.on('click', addPointforJSON)
  1569. }
  1570.  
  1571. drawRectangle(layerId,callback=()=>{}){
  1572. this.layerPointList.push(layerId);
  1573. const map = this.map;
  1574. map.doubleClickZoom.disable();
  1575. const jsonPoint = {
  1576. type: 'FeatureCollection',
  1577. features: [],
  1578. }
  1579. const jsonArea = {
  1580. type: 'FeatureCollection',
  1581. features: [],
  1582. }
  1583. map.addSource('points' + layerId, {
  1584. type: 'geojson',
  1585. data: jsonPoint,
  1586. });
  1587. map.addSource('line-area' + layerId, {
  1588. type: 'geojson',
  1589. data: jsonArea,
  1590. })
  1591. map.addLayer({
  1592. id: 'line-area' + layerId,
  1593. type: 'fill',
  1594. source: 'line-area' + layerId,
  1595. paint: {
  1596. 'fill-color': '#ff0000',
  1597. 'fill-opacity': 0.1,
  1598. },
  1599. })
  1600. map.addLayer({
  1601. id: 'points' + layerId,
  1602. type: 'circle',
  1603. source: 'points' + layerId,
  1604. paint: {
  1605. 'circle-color': '#ffffff',
  1606. 'circle-radius': 3.5,
  1607. 'circle-stroke-width': 1.5,
  1608. 'circle-stroke-color': '#ff0000',
  1609. },
  1610. })
  1611.  
  1612. /**
  1613. * 添加点
  1614. * @param {*} _e
  1615. */
  1616. function addPointforJSON(_e) {
  1617. const point = {
  1618. type: 'Feature',
  1619. geometry: {
  1620. type: 'Point',
  1621. coordinates: [_e.lngLat.lng, _e.lngLat.lat],
  1622. },
  1623. properties: {
  1624. id: String(new Date().getTime()),
  1625. },
  1626. }
  1627. jsonPoint.features.push(point);
  1628. if(jsonPoint.features.length == 2) {
  1629. map.off('click', addPointforJSON);
  1630. map.off('mousemove', mouseRectangle);
  1631. callback(jsonArea.features[0]);
  1632. }
  1633. map.getSource('points' + layerId).setData(jsonPoint);
  1634. }
  1635.  
  1636.  
  1637. function mouseRectangle(_e){
  1638. if(!(jsonPoint.features.length)) {
  1639. const point = {
  1640. type: 'Feature',
  1641. geometry: {
  1642. type: 'Point',
  1643. coordinates: [_e.lngLat.lng, _e.lngLat.lat],
  1644. },
  1645. properties: {
  1646. id: String(new Date().getTime()),
  1647. },
  1648. }
  1649. return (map.getSource('points' + layerId).setData({type: 'FeatureCollection', features: [point]}));
  1650. }
  1651. let coordinates = jsonPoint.features[0].geometry.coordinates;
  1652. let bbox = coordinates.concat([_e.lngLat.lng, _e.lngLat.lat]).sort((a,b)=> a-b);
  1653. let polygon = turf.bboxPolygon([bbox[2],bbox[0],bbox[3],bbox[1]]);
  1654. jsonArea.features = [polygon];
  1655. map.getSource('line-area' + layerId).setData(jsonArea);
  1656. }
  1657.  
  1658. map.on('click', addPointforJSON);
  1659.  
  1660. map.on('mousemove', mouseRectangle)
  1661. }
  1662.  
  1663. /**
  1664. * 清除所有测量要素
  1665. */
  1666. clearMeasureAll() {
  1667. const dom = document.getElementsByClassName('measure-result')
  1668. const len = dom.length
  1669. if (len) {
  1670. for (let i = len - 1; i >= 0; i--) {
  1671. if (dom[i]) dom[i].remove()
  1672. }
  1673. }
  1674. if (this.layerDistanceList) {
  1675. for (let i = 0; i < this.layerDistanceList.length; i++) {
  1676. const layerid = this.layerDistanceList[i]
  1677. try {
  1678. if(this.map.getLayer('points' + layerid)) this.map.removeLayer('points' + layerid)
  1679. if(this.map.getLayer('line' + layerid)) this.map.removeLayer('line' + layerid)
  1680. if(this.map.getLayer('point-move' + layerid)) this.map.removeLayer('point-move' + layerid)
  1681. if(this.map.getLayer('line-move' + layerid)) this.map.removeLayer('line-move' + layerid)
  1682. } catch (error) {
  1683. console.log(error)
  1684. }
  1685. }
  1686. }
  1687. this.layerDistanceList = []
  1688. if (this.layerAreaList) {
  1689. for (let i = 0; i < this.layerAreaList.length; i++) {
  1690. const layerid = this.layerAreaList[i]
  1691. try {
  1692. if(this.map.getLayer('points-area' + layerid)) this.map.removeLayer('points-area' + layerid)
  1693. if(this.map.getLayer('line-area' + layerid)) this.map.removeLayer('line-area' + layerid)
  1694. if(this.map.getLayer('line-area-stroke' + layerid)) this.map.removeLayer('line-area-stroke' + layerid)
  1695. if(this.map.getLayer('point-move' + layerid)) this.map.removeLayer('point-move' + layerid)
  1696. if(this.map.getLayer('line-move' + layerid)) this.map.removeLayer('line-move' + layerid)
  1697. } catch (error) {
  1698. console.log(error)
  1699. }
  1700. }
  1701. }
  1702. this.layerAreaList = []
  1703. if (this.layerPointList) {
  1704. for (let i = 0; i < this.layerPointList.length; i++) {
  1705. const layerid = this.layerPointList[i]
  1706. try {
  1707. if(this.map.getLayer('points' + layerid)) this.map.removeLayer('points' + layerid)
  1708. if(this.map.getLayer('line-area' + layerid)) this.map.removeLayer('line-area' + layerid)
  1709. } catch (error) {
  1710. console.log(error)
  1711. }
  1712. }
  1713. }
  1714. this.layerPointList = []
  1715. this.map.doubleClickZoom.enable()
  1716. }
  1717.  
  1718. clearById (layerid){
  1719. if(this.map.getLayer('points' + layerid)) this.map.removeLayer('points' + layerid)
  1720. if(this.map.getLayer('line' + layerid)) this.map.removeLayer('line' + layerid)
  1721. if(this.map.getLayer('point-move' + layerid)) this.map.removeLayer('point-move' + layerid)
  1722. if(this.map.getLayer('line-move' + layerid)) this.map.removeLayer('line-move' + layerid)
  1723. }
  1724. }
  1725. })));