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测量工具代码实现(测量距离、面积、角度等)的更多相关文章

  1. CAD图与互联网地图网页端相互叠加显示技术分析和实现

    需求分析 之前相关的博文中介绍了如果在Web网页端展示CAD图形(唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud),当一些CAD图纸有实际地理坐标位置时,如地形图等, ...

  2. 如何在Web前端实现CAD图文字全文搜索功能之技术分享

    现状 在CAD看图过程中我们经常会需要用到查找文字的功能,在AutoCAD软件查找一个文字时,可以通过打开左下角输入命令find,输入查找的文字,然后设置查找范围,就可以搜索到需要查询的文字.但在We ...

  3. 美图秀秀 web开发图片编辑器

    美图秀秀web开发平台 http://open.web.meitu.com/wiki/ 1.环境配置 1.1.设置crossdomain.xml 下载crossdomain.xml文件,把解压出来的c ...

  4. SSH WebShell: SSH在线WEB管理器安装教程 - VPS管理百科

    SSH WebShell: SSH在线WEB管理器安装教程 - VPS管理百科 SSH WebShell: SSH在线WEB管理器安装教程 本站原创 [基于 署名-非商业使用-相同方式分享 2.5 协 ...

  5. 在线web编辑器

    真正在线编辑的在线web编辑器 最近正在研究开发一款在线web编辑器架构,这是一款真正傻瓜式的web编辑器,可以在正常浏览页面的情况进行编辑,经过测试,对于一般网页页面来说非常好用方便,操作更简单. ...

  6. 真正在线编辑的在线web编辑器

    最近正在研究开发一款在线web编辑器架构,这是一款真正傻瓜式的web编辑器,可以在正常浏览页面的情况进行编辑,经过测试,对于一般网页页面来说非常好用方便,操作更简单. 一般的在线web编辑器虽说提供了 ...

  7. 在线WEB开发编辑器,edt.df5d.com

    在线WEB开发编辑器,http://edt.df5d.com 本地服务端下载 : https://pan.baidu.com/s/11SlcoU_D-KbzGFbs-_9Dpg 即可加载本地磁盘,也可 ...

  8. QQ,MSN,Skype在线客服代码

    QQ,MSN,Skype在线客服代码 在网站建设时,为了更好的实施网站的营销型,会用到QQ,MSN等在线交流,以便客户能够快捷方便的联系我们.在这里,提供QQ,MSN的在线客服代码给大家分享: 1.Q ...

  9. 在线运行HTML代码器

    在线运行HTML代码器(二)和前面的(一)大同小异,关键部分为JS代码,这次是把运行器所有的JS功能集中放在一起.以下为HTML代码: <!DOCTYPE html PUBLIC "- ...

  10. 基于jquery打造的网页右侧自动收缩浮动在线客服代码

    基于jquery打造的网页右侧自动收缩浮动在线QQ客服代码, 当前比较流行的一款QQ在线jquery特效代码, 代码中还带有IE6下PNG图片透明的特效,如果想研究IE6下PNG透明的同学也可以下载研 ...

随机推荐

  1. zTree开发下拉树

    最近,因为工作需要一个树形下拉框的组件,经过查资料一般有两种的实现方法.其一,就是使用zTree实现:其二,就是使用easyUI实现.因为公司的前端不是使用easyUI设计的,故这里我选择了zTree ...

  2. mysql服务器配置

      mysql的配置文件 /etc/mysql/my.cnf 发现如下配置 # Instead of skip-networking the default is now to listen only ...

  3. PDF 补丁丁 0.4.2.1023 测试版使用手册发布

    由于 PDF 补丁丁新版本增加的功能颇多,界面也重新设计过,因此,使用手册需要作比较大幅度的改动才能与软件相匹配. 目前,使用手册已经撰写了一部分,但新增功能的介绍和新界面的截图还没完成,有2/3的内 ...

  4. 15款效果很酷的最新jQuery/CSS3特效

    很久没来博客园发表文章了,今天就分享15款效果很酷的最新jQuery/CSS3特效,废话不说,一起来看看吧. 1.3D图片上下翻牌切换 一款基于jQuery+CSS3实现的3D图片上下翻牌切换效果,支 ...

  5. WatiN框架学习二——对弹窗的处理

    以IE为例,WatiN处理弹出窗口: IE ie = new IE("string"); //打开指定web页 ie.Button(Find.ById("string&q ...

  6. 【转帖】error C2296: “^”: 非法,左操作数包含“double”类型

    想要实现 ,写的C++程序为 double x; x=2^3; 结果程序总是出现这样的错误:error C2296: “^”: 非法,左操作数包含“double”类型 后来才发现操作符“^”,在C++ ...

  7. Java接口自动化测试之TestNG测试报告ExtentReports的应用(三)

    pom.xml导入包 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=" ...

  8. 关于Django部分

    1  安装 执行pip安装即可 pip install Django 2 开启项目 3 项目新建后所在位置: 4 开启端口命令 python manage.py runserver 0.0.0.0:9 ...

  9. dubbo的三种运行方式

    1.Tomcat容器内启动 pom.xml 文件中 <build> <resources> <resource> <directory>src/main ...

  10. 1-Python3从入门到实战—基础之语法

    Python从入门到实战系列--目录 编码格式 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串 # -*- coding=utf-8 -*- 也可以 ...