CAD图在线Web测量工具代码实现(测量距离、面积、角度等)

2022-11-22,,,,

CAD如今在各个领域均得到了普遍的应用并大大提高了工程技术人员的工作效率。在桌面端,AutoCAD测量工具已经非常强大;然后在Web端,如何准确、快速的对CAD图在Web进行测量呢?

功能

能Web在线打开AutoCAD图形

测量距离

测量面积

测量角度

坐标标注

测量时能捕捉Web端CAD图形上面的坐标,提高准确度

测量时能对捕捉进行开关启用

测量时能启用正交模式

测量时能自定义右键菜单功能

能进行连续测量

测量结束后,能删除已测量的结果

效果

能Web在线打开AutoCAD图形

如果在Web网页端展示CAD图形(唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud),这个在前面的博文中已讲过,这里不再重复,有需要的朋友可下载工程源代码研究下。

测量距离

测量面积

测量角度

坐标标注

其他功能

在测量过程中,按Alt键可开启关闭捕捉;按Ctrl键可启用正交模式;按退格键可删除上一个点;按ESC键取消测量;按Enter键结束测量; 按右键弹出上下文菜单

代码实现

  1 import vjmap, { Map } from 'vjmap'
2 import { sleep } from '~/utils/ui';
3 import { getMapSnapPoints } from './snap';
4 let snapObj: any; // 设置的捕捉的实体
5 let curMeasureCmd: string; // 当前测量命令
6 export async function runMeasureCmd(map: Map, cmd: string) {
7 curMeasureCmd = cmd;
8 if (cmd != "measureCancel") {
9 // 先结束当前测量
10 await measureCancel(map);
11 if (!snapObj) {
12 // 获取地图上的捕捉点
13 snapObj = {};
14 getMapSnapPoints(map, snapObj);
15 }
16 }
17 switch (cmd) {
18 case "measureDist":
19 measureDistLoop(map, snapObj);
20 break;
21 case "measureArea":
22 measureAreaLoop(map, snapObj);
23 break;
24 case "measureAngle":
25 measureAngleLoop(map, snapObj);
26 break;
27 case "measureCoordinate":
28 measureCoordinateLoop(map, snapObj);
29 break;
30 case "measureCancel":
31 await measureCancel(map);
32 break;
33 }
34 }
35 ​
36 // 结束绘制
37 const measureCancel = async (map: Map)=> {
38 // 连续发送取消键,第一次取消当前绘制,第二次退出测量
39 map.fire("keyup", {keyCode:27});
40 await sleep(100);
41 map.fire("keyup", {keyCode:27});
42 await sleep(100);
43 map.setIsInteracting(false); // 没有进行交互操作了
44 }
45 ​
46 let popup: vjmap.Popup | null;
47 const setPopupText = (text: string, map: Map) => {
48 if (text) {
49 if (!popup) {
50 popup = new vjmap.Popup({
51 className: "my-custom-popup",
52 closeOnClick: false,
53 closeButton: false
54 })
55 .setHTML(text)
56 .setMaxWidth("500px")
57 .trackPointer()
58 .addTo(map)
59 }
60 else {
61 popup.setHTML(text);
62 }
63 } else {
64 // 如果为空时,则删除popup
65 if (popup) {
66 popup.setLngLat([0,0]); // 取消trackPointer
67 popup.remove();
68 popup = null;
69 }
70 }
71 ​
72 }
73 // 测量距离循环,直至按ESC键取消,否则测量完一条后,继续测量下一条
74 const measureDistLoop = async (map: Map, snapObj: any)=> {
75 while(true) {
76 let res = await measureDist(map, snapObj);
77 if (res.exit === true) break;
78 if (curMeasureCmd != "measureDist") break;
79 }
80 }
81 ​
82 // 测量距离
83 const measureDist = async (map: Map, snapObj: any)=> {
84 let isDrawing = false;
85 let line = await vjmap.Draw.actionDrawLineSting(map, {
86 api: {
87 getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
88 },
89 updatecoordinate: (e: any) => {
90 if (!e.lnglat) return;
91 isDrawing = true;
92 const co = map.fromLngLat(e.feature.coordinates[e.feature.coordinates.length - 1]);
93 let html = `【测量距离】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)}, ${co.y.toFixed(2)}</span>`;
94 if (e.feature.coordinates.length == 1) {
95 html += "<br/>请指定要测量的第一点的坐标位置"
96 } else {
97 let len = e.feature.coordinates.length;
98 html += `<br/>按Alt键取捕捉; Ctrl键启用正交; 退格键删除上一个点`
99 html += `<br/>距上一点距离: <span style="color: #ff0000">${getDist(map, [e.feature.coordinates[len - 2], e.feature.coordinates[len -1]])}</span>`
100 html += `; 当前总的距离: <span style="color: #ff0000">${getDist(map, e.feature.coordinates)}</span>`
101 }
102 setPopupText(html, map)
103 },
104 contextMenu: (e: any) => {
105 new vjmap.ContextMenu({
106 event: e.event.originalEvent,
107 theme: "dark", //light
108 width: "250px",
109 items: [
110 {
111 label: '确认',
112 onClick: () => {
113 // 给地图发送Enter键消息即可取消,模拟按Enter键
114 map.fire("keyup", {keyCode:13})
115 setPopupText("", map);
116 }
117 },
118 {
119 label: '取消',
120 onClick: () => {
121 // 给地图发送ESC键消息即可取消,模拟按ESC键
122 map.fire("keyup", {keyCode:27})
123 setPopupText("", map);
124 }
125 },{
126 label: '删除上一个点',
127 onClick: () => {
128 // 给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
129 map.fire("keyup", {keyCode:8})
130 }
131 },{
132 label: '结束测距',
133 onClick: () => {
134 // 给地图发送ESC键消息即可取消,模拟按ESC键
135 map.fire("keyup", {keyCode:27})
136 isDrawing = false;
137 setPopupText("", map);
138 }
139 }
140 ]
141 });
142 ​
143 }
144 });
145 if (line.cancel) {
146 setPopupText("", map);
147 return {
148 cancel: true,
149 exit: isDrawing === false // 如果还没有绘制,就取消的话,就结束测距
150 };// 取消操作
151 }
152 ​
153 let color = vjmap.randomColor();
154 let polyline = new vjmap.Polyline({
155 data: line.features[0].geometry.coordinates,
156 lineColor: color,
157 lineWidth: 2
158 });
159 polyline.addTo(map);
160 addMarkersToLine(map, line.features[0].geometry.coordinates, color, polyline.sourceId || "", snapObj);
161 return {
162 polyline
163 };
164 }
165 ​
166 ​
167 // 给线的加个点加个测量的结果值
168 const addMarkersToLine = (map: Map, coordinates: Array<[number, number]>, color: string, sourceId: string, snapObj: any) => {
169 let markerTexts: any = [];
170 for(let i = 1; i < coordinates.length; i++) {
171 let text = new vjmap.Text({
172 text: getDist(map, coordinates.slice(0, i + 1)),
173 anchor: "left",
174 offset: [3, 0], // x,y 方向像素偏移量
175 style:{ // 自定义样式
176 'cursor': 'pointer',
177 'opacity': 0.8,
178 'padding': '6px',
179 'border-radius': '12px',
180 'background-color': color,
181 'border-width': 0,
182 'box-shadow': '0px 2px 6px 0px rgba(97,113,166,0.2)',
183 'text-align': 'center',
184 'font-size': '14px',
185 'color': `#${color.substring(1).split("").map(c => (15 - parseInt(c,16)).toString(16)).join("")}`,
186 }
187 });
188 text.setLngLat(coordinates[i]).addTo(map);
189 markerTexts.push(text);
190 }
191 // 给第一个点加一个marker用来删除
192 const deletePng = "delete.png";
193 let el = document.createElement('div');
194 el.className = 'marker';
195 el.style.backgroundImage =
196 `url(${deletePng})`;
197 el.style.width = '20px';
198 el.style.height = '20px';
199 el.style.backgroundSize = '100%';
200 el.style.cursor = "pointer";
201 ​
202 el.addEventListener('click', function (e) {
203 map.removeSourceEx(sourceId); // 删除绘制的线
204 markerTexts.forEach((m: any) => m.remove());
205 markerTexts = [];
206 ​
207 // 多点了下,给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
208 map.fire("keyup", {keyCode:8})
209 });
210 // Add markers to the map.
211 let deleteMarker = new vjmap.Marker({
212 element: el,
213 anchor: 'right'
214 });
215 deleteMarker.setLngLat(coordinates[0])
216 .setOffset([-5, 0])
217 .addTo(map);
218 markerTexts.push(deleteMarker)
219 ​
220 // 把坐标加进捕捉数组中。
221 addSnapCoordinates(snapObj, coordinates);
222 }
223 // 得到距离值
224 const getDist = (map: Map, coordinates: Array<[number, number]>) => {
225 let result = vjmap.Math2D.lineDist(map.fromLngLat(coordinates));
226 let unit = "m";
227 if (result >= 1000) {
228 result /= 1000;
229 unit = "km";
230 } else if (result < 0.01) {
231 result *= 100;
232 unit = "cm";
233 }
234 return result.toFixed(2) + " " + unit;
235 }
236 // 增加捕捉点
237 const addSnapCoordinates = (snapObj: any, coordinates: Array<[number, number]>) => {
238 snapObj.features.push({
239 type: "Feature",
240 geometry: {
241 type: "LineString",
242 coordinates: [...coordinates]
243 }
244 })
245 }
246 ​
247 ​
248 ​
249 // 测量面积
250 const measureArea = async (map: Map, snapObj: any)=> {
251 let isDrawing = false;
252 let poly = await vjmap.Draw.actionDrawPolygon(map, {
253 api: {
254 getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
255 },
256 updatecoordinate: (e: any) => {
257 if (!e.lnglat) return;
258 isDrawing = true;
259 const co = map.fromLngLat(e.feature.coordinates[0][e.feature.coordinates.length - 1]);
260 let html = `【测量面积】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)}, ${co.y.toFixed(2)}</span>`;
261 if (e.feature.coordinates[0].length == 1) {
262 html += "<br/>请指定要测量的第一点的坐标位置"
263 } else {
264 html += `<br/>按Alt键取捕捉; Ctrl键启用正交; 退格键删除上一个点`
265 html += `<br/>当前面积: <span style="color: #ff0000">${getArea(map, e.feature.coordinates[0])}</span>`
266 }
267 setPopupText(html, map)
268 },
269 contextMenu: (e: any) => {
270 new vjmap.ContextMenu({
271 event: e.event.originalEvent,
272 theme: "dark", //light
273 width: "250px",
274 items: [
275 {
276 label: '确认',
277 onClick: () => {
278 // 给地图发送Enter键消息即可取消,模拟按Enter键
279 map.fire("keyup", {keyCode:13})
280 setPopupText("", map);
281 }
282 },
283 {
284 label: '取消',
285 onClick: () => {
286 // 给地图发送ESC键消息即可取消,模拟按ESC键
287 map.fire("keyup", {keyCode:27})
288 setPopupText("", map);
289 }
290 },{
291 label: '删除上一个点',
292 onClick: () => {
293 // 给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
294 map.fire("keyup", {keyCode:8})
295 }
296 },{
297 label: '结束测面积',
298 onClick: () => {
299 // 给地图发送ESC键消息即可取消,模拟按ESC键
300 map.fire("keyup", {keyCode:27})
301 isDrawing = false;
302 setPopupText("", map);
303 }
304 }
305 ]
306 });
307 ​
308 }
309 });
310 if (poly.cancel) {
311 debugger
312 setPopupText("", map);
313 return {
314 cancel: true,
315 exit: isDrawing === false // 如果还没有绘制,就取消的话,就结束测距
316 };// 取消操作
317 }
318 ​
319 let color = vjmap.randomColor();
320 let polygon = new vjmap.Polygon({
321 data: poly.features[0].geometry.coordinates[0],
322 fillColor: color,
323 fillOpacity: 0.4,
324 fillOutlineColor: color,
325 });
326 polygon.addTo(map);
327 addMarkersToPolygon(map, poly.features[0].geometry.coordinates[0], color, polygon.sourceId || "", snapObj);
328 return {
329 polygon
330 };
331 }
332 ​
333 // 测量面积循环,直至按ESC键取消,否则测量完一条后,继续测量下一条
334 const measureAreaLoop = async (map: Map, snapObj: any)=> {
335 while(true) {
336 let res = await measureArea(map, snapObj);
337 if (res.exit === true) break;
338 if (curMeasureCmd != "measureArea") break;
339 }
340 }
341 ​
342 // 给加个测量的结果值
343 const addMarkersToPolygon = (map: Map, coordinates: Array<[number, number]>, color: string, sourceId: string, snapObj: any) => {
344 let markerTexts: any = [];
345 const center = vjmap.polygonCentroid(map.fromLngLat(coordinates));
346 let text = new vjmap.Text({
347 text: getArea(map, coordinates),
348 anchor: "center",
349 offset: [0, 0], // x,y 方向像素偏移量
350 style:{ // 自定义样式
351 'cursor': 'pointer',
352 'opacity': 0.8,
353 'padding': '6px',
354 'border-radius': '12px',
355 'background-color': `#${color.substring(1).split("").map(c => (15 - parseInt(c,16)).toString(16)).join("")}`,
356 'border-width': 0,
357 'box-shadow': '0px 2px 6px 0px rgba(97,113,166,0.2)',
358 'text-align': 'center',
359 'font-size': '14px',
360 'color': color,
361 }
362 });
363 text.setLngLat(map.toLngLat(center)).addTo(map);
364 markerTexts.push(text);
365 // 给第一个点加一个marker用来删除
366 const deletePng = = "delete.png";
367 let el = document.createElement('div');
368 el.className = 'marker';
369 el.style.backgroundImage =
370 `url(${deletePng})`;
371 el.style.width = '20px';
372 el.style.height = '20px';
373 el.style.backgroundSize = '100%';
374 el.style.cursor = "pointer";
375 ​
376 el.addEventListener('click', function (e) {
377 map.removeSourceEx(sourceId); // 删除绘制的线
378 markerTexts.forEach((m: any) => m.remove());
379 markerTexts = [];
380 });
381 // Add markers to the map.
382 let deleteMarker = new vjmap.Marker({
383 element: el,
384 anchor: 'right'
385 });
386 deleteMarker.setLngLat(coordinates[0])
387 .setOffset([-5, 0])
388 .addTo(map);
389 markerTexts.push(deleteMarker)
390 ​
391 // 把坐标加进捕捉数组中。
392 addSnapCoordinates(snapObj, coordinates);
393 }
394 // 得到面积值
395 const getArea = (map: Map, coordinates: Array<[number, number]>) => {
396 let result = vjmap.calcPolygonArea(map.fromLngLat(coordinates));
397 let unit = "m²";
398 if (result >= 1e6) {
399 result /= 1e6;
400 unit = "km²";
401 } else if (result < 1.0/1e4) {
402 result *= 1e4;
403 unit = "cm²";
404 }
405 return result.toFixed(2) + " " + unit;
406 }
407 ​
408 ​
409 ​
410 // 测量角度
411 const measureAngle = async (map: Map, snapObj: any)=> {
412 let isDrawing = false;
413 let line = await vjmap.Draw.actionDrawLineSting(map, {
414 pointCount: 3,// 只需三个点,绘制完三个点后,自动结束
415 api: {
416 getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
417 },
418 updatecoordinate: (e: any) => {
419 if (!e.lnglat) return;
420 isDrawing = true;
421 const co = map.fromLngLat(e.feature.coordinates[e.feature.coordinates.length - 1]);
422 let html = `【测量角度】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)}, ${co.y.toFixed(2)}</span>`;
423 if (e.feature.coordinates.length == 1) {
424 html += "<br/>请指定要测量的第一点的坐标位置"
425 } else {
426 let len = e.feature.coordinates.length;
427 html += `<br/>按Alt键取捕捉; Ctrl键启用正交; 退格键删除上一个点`
428 html += `<br/>当前角度: <span style="color: #ff0000">${getAngle(map, e.feature.coordinates).angle}</span>`
429 }
430 setPopupText(html, map)
431 },
432 contextMenu: (e: any) => {
433 new vjmap.ContextMenu({
434 event: e.event.originalEvent,
435 theme: "dark", //light
436 width: "250px",
437 items: [
438 {
439 label: '确认',
440 onClick: () => {
441 // 给地图发送Enter键消息即可取消,模拟按Enter键
442 map.fire("keyup", {keyCode:13})
443 setPopupText("", map);
444 }
445 },
446 {
447 label: '取消',
448 onClick: () => {
449 // 给地图发送ESC键消息即可取消,模拟按ESC键
450 map.fire("keyup", {keyCode:27})
451 setPopupText("", map);
452 }
453 },{
454 label: '删除上一个点',
455 onClick: () => {
456 // 给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
457 map.fire("keyup", {keyCode:8})
458 }
459 },{
460 label: '结束测角度',
461 onClick: () => {
462 // 给地图发送ESC键消息即可取消,模拟按ESC键
463 map.fire("keyup", {keyCode:27})
464 isDrawing = false;
465 setPopupText("", map);
466 }
467 }
468 ]
469 });
470 ​
471 }
472 });
473 if (line.cancel) {
474 setPopupText("", map);
475 return {
476 cancel: true,
477 exit: isDrawing === false // 如果还没有绘制,就取消的话,就结束测距
478 };// 取消操作
479 }
480 ​
481 let color = vjmap.randomColor();
482 let polyline = new vjmap.Polyline({
483 data: line.features[0].geometry.coordinates,
484 lineColor: color,
485 lineWidth: 2
486 });
487 polyline.addTo(map);
488 addMarkersToAngle(map, line.features[0].geometry.coordinates, color, polyline.sourceId || "", snapObj);
489 return {
490 polyline
491 };
492 }
493 ​
494 // 测量角度循环,直至按ESC键取消,否则测量完一条后,继续测量下一条
495 const measureAngleLoop = async (map: Map, snapObj: any)=> {
496 while(true) {
497 let res = await measureAngle(map, snapObj);
498 if (res.exit === true) break;
499 if (curMeasureCmd != "measureAngle") break;
500 }
501 }
502 ​
503 ​
504 ​
505 // 给加个测量的结果值
506 const addMarkersToAngle = (map: Map, coordinates: Array<[number, number]>, color: string, sourceId: string, snapObj: any) => {
507 if (coordinates.length < 3) return;
508 let markerTexts: any = [];
509 let points = map.fromLngLat(coordinates);
510 let textPoint = coordinates[1];
511 let ang = getAngle(map, coordinates);
512 // 绘制注记圆弧
513 const cirleArcPath = vjmap.getCirclePolygonCoordinates(
514 points[1],
515 points[1].distanceTo(points[0]) / 4.0, 36,
516 ang.startAngle, ang.endAngle, false);
517 let path = new vjmap.Polyline({
518 data: map.toLngLat(cirleArcPath),
519 lineColor: color,
520 lineWidth: 2
521 });
522 path.addTo(map);
523 markerTexts.push(path)
524 ​
525 // @ts-ignore
526 let arcPoints = path.getData().features[0].geometry.coordinates;
527 let arcMid = arcPoints[Math.ceil(arcPoints.length / 2)];// 取中点
528 let textAngle = vjmap.radiansToDegrees(-map.fromLngLat(arcMid).angleTo(points[1])) + 90;
529 if (textAngle > 90) textAngle += 180;
530 else if (textAngle > 270) textAngle -= 180;
531 let text = new vjmap.Text({
532 text: ang.angle as string,
533 anchor: "center",
534 rotation: textAngle,
535 offset: [0, 0], // x,y 方向像素偏移量
536 style:{ // 自定义样式
537 'cursor': 'pointer',
538 'opacity': 0.8,
539 'padding': '6px',
540 'border-radius': '12px',
541 'background-color': color,
542 'border-width': 0,
543 'box-shadow': '0px 2px 6px 0px rgba(97,113,166,0.2)',
544 'text-align': 'center',
545 'font-size': '14px',
546 'color': `#${color.substring(1).split("").map(c => (15 - parseInt(c,16)).toString(16)).join("")}`,
547 }
548 });
549 text.setLngLat(arcMid).addTo(map);
550 markerTexts.push(text);
551 // 给第一个点加一个marker用来删除
552 const deletePng = = "delete.png";
553 let el = document.createElement('div');
554 el.className = 'marker';
555 el.style.backgroundImage =
556 `url(${deletePng})`;
557 el.style.width = '20px';
558 el.style.height = '20px';
559 el.style.backgroundSize = '100%';
560 el.style.cursor = "pointer";
561 ​
562 el.addEventListener('click', function (e) {
563 map.removeSourceEx(sourceId); // 删除绘制的线
564 markerTexts.forEach((m: any) => m.remove());
565 markerTexts = [];
566 });
567 // Add markers to the map.
568 let deleteMarker = new vjmap.Marker({
569 element: el,
570 anchor: 'right'
571 });
572 deleteMarker.setLngLat(coordinates[1])
573 .setOffset([-5, 0])
574 .addTo(map);
575 markerTexts.push(deleteMarker)
576 ​
577 // 把坐标加进捕捉数组中。
578 addSnapCoordinates(snapObj, coordinates);
579 }
580 // 得到角度值
581 const getAngle = (map: Map, coordinates: Array<[number, number]>) => {
582 let points = map.fromLngLat(coordinates);
583 if (points.length < 3) return { angle: 0.0 }
584 let angle1 = points[0].angleTo(points[1]);
585 let angle2 = points[2].angleTo(points[1]);
586 let angle = angle1 - angle2;
587 let deg = vjmap.radiansToDegrees(angle);//弧度转角度
588 let dir = true;
589 if (deg < 0) {
590 deg = -deg;
591 dir = !dir;
592 }
593 if (deg > 180) {
594 deg = 360 - deg;
595 dir = !dir;
596 }
597 let startAngle = !dir ? vjmap.radiansToDegrees(angle1) : vjmap.radiansToDegrees(angle2);
598 let endAngle = dir ? vjmap.radiansToDegrees(angle1) : vjmap.radiansToDegrees(angle2);
599 startAngle = startAngle < 0 ? 360 + startAngle : startAngle;
600 endAngle = endAngle < 0 ? 360 + endAngle : endAngle;
601 if (endAngle < startAngle) {
602 endAngle += 360;
603 }
604 return {
605 angle: deg.toFixed(2) + "°",
606 dir,
607 startAngle,
608 endAngle
609 }
610 }
611 ​
612 ​
613 // 测量坐标
614 const measureCoordinate = async (map: Map, snapObj: any)=> {
615 let isDrawing = false;
616 let point = await vjmap.Draw.actionDrawPoint(map, {
617 api: {
618 getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
619 },
620 updatecoordinate: (e: any) => {
621 if (!e.lnglat) return;
622 isDrawing = true;
623 const co = map.fromLngLat(e.lnglat);
624 let html = `【测量坐标】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)}, ${co.y.toFixed(2)}</span>`;
625 setPopupText(html, map)
626 },
627 contextMenu: (e: any) => {
628 new vjmap.ContextMenu({
629 event: e.event.originalEvent,
630 theme: "dark", //light
631 width: "250px",
632 items: [
633 {
634 label: '确认',
635 onClick: () => {
636 // 给地图发送Enter键消息即可取消,模拟按Enter键
637 map.fire("keyup", {keyCode:13})
638 setPopupText("", map);
639 }
640 },
641 {
642 label: '取消',
643 onClick: () => {
644 // 给地图发送ESC键消息即可取消,模拟按ESC键
645 map.fire("keyup", {keyCode:27})
646 setPopupText("", map);
647 }
648 },
649 {
650 label: '结束测坐标',
651 onClick: () => {
652 // 给地图发送ESC键消息即可取消,模拟按ESC键
653 map.fire("keyup", {keyCode:27})
654 isDrawing = false;
655 setPopupText("", map);
656 }
657 }
658 ]
659 });
660 ​
661 }
662 });
663 if (point.cancel) {
664 setPopupText("", map);
665 return {
666 cancel: true,
667 exit: isDrawing === false
668 };// 取消操作
669 }
670 ​
671 addMarkersToCoord(map, point.features[0].geometry.coordinates);
672 return {
673 point
674 };
675 }
676 ​
677 // 测量坐标循环,直至按ESC键取消
678 const measureCoordinateLoop = async (map: Map, snapObj: any)=> {
679 while(true) {
680 let res = await measureCoordinate(map, snapObj);
681 if (res.exit === true) break;
682 if (curMeasureCmd != "measureCoordinate") break;
683 }
684 }
685 ​
686 ​
687 ​
688 // 给加个点加个测量的结果值
689 const addMarkersToCoord = (map: Map, coordinates: [number, number]) => {
690 let markerTexts: any = [];
691 let co = map.fromLngLat(coordinates);
692 let content = `X: ${co.x.toFixed(2)}, Y: ${co.y.toFixed(2)}`
693 let marker = createLeaderMarker(map, coordinates, content);
694 markerTexts.push(marker);
695 ​
696 // 给第一个点加一个marker用来删除
697 const deletePng = "delete.png";
698 let el = document.createElement('div');
699 el.className = 'marker';
700 el.style.backgroundImage =
701 `url(${deletePng})`;
702 el.style.width = '20px';
703 el.style.height = '20px';
704 el.style.backgroundSize = '100%';
705 el.style.cursor = "pointer";
706 ​
707 el.addEventListener('click', function (e) {
708 markerTexts.forEach((m: any) => m.remove());
709 markerTexts = [];
710 ​
711 });
712 // Add markers to the map.
713 let deleteMarker = new vjmap.Marker({
714 element: el,
715 anchor: 'right'
716 });
717 deleteMarker.setLngLat(coordinates)
718 .setOffset([-5, 0])
719 .addTo(map);
720 markerTexts.push(deleteMarker)
721 ​
722 }
723 ​
724 // 引线标记
725 const createLeaderMarker = (map: Map, lnglat: [number, number], content: string) => {
726 let el = document.createElement('div');
727 el.className = 'marker';
728 el.style.position = 'absolute'
729 ​
730 let img = document.createElement("div");
731 img.style.backgroundImage = 'bk.png';
732 img.style.backgroundRepeat = "no-repeat"
733 img.style.height = '37px';
734 img.style.width = '100px';
735 img.style.position = 'absolute';
736 img.style.left = '-3px';
737 img.style.bottom = '-3px';
738 img.style.right = "0px"
739 el.appendChild(img);
740 ​
741 let panel = document.createElement("div");
742 panel.style.height = '50px';
743 panel.style.width = '350px';
744 panel.style.position = 'absolute';
745 panel.style.left = '97px';
746 panel.style.top = '-60px';
747 panel.style.border = "solid 1px #8E0EFF";
748 panel.style.background = 'linear-gradient(#00ffff, #00ffff) left top, linear-gradient(#00ffff, #00ffff) left top, linear-gradient(#00ffff, #00ffff) right bottom, linear-gradient(#00ffff, #00ffff) right bottom';
749 panel.style.backgroundRepeat = 'no-repeat';
750 panel.style.backgroundColor ='rgba(87,255,255, 0.3)'
751 panel.style.backgroundSize = '1px 6px, 6px 1px';
752 panel.style.fontSize = '18px';
753 panel.style.color = '#ffffff';
754 panel.innerHTML = `<div style='margin: 15px 5px 15px 5px'>${content}</div>`;
755 el.appendChild(panel);
756 ​
757 // Add markers to the map.
758 let marker = new vjmap.Marker({
759 element: el,
760 anchor: "bottom-left"
761 })
762 marker.setLngLat(lnglat)
763 .addTo(map);
764 return marker
765 }
766 ​

有需要的朋友可以在线体验下。上面的案例代码已开源。访问 (唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud) ,点击下载此案例源码即可。

 

CAD图在线Web测量工具代码实现(测量距离、面积、角度等)的相关教程结束。

《CAD图在线Web测量工具代码实现(测量距离、面积、角度等).doc》

下载本文的Word格式文档,以方便收藏与打印。