cad面积快速测量设置(CAD图在线Web测量工具代码实现)
cad面积快速测量设置(CAD图在线Web测量工具代码实现)
CAD如今在各个领域均得到了普遍的应用并大大提高了工程技术人员的工作效率。在桌面端,AutoCAD测量工具已经非常强大;然后在Web端,如何准确、快速的对CAD图在Web进行测量呢?
功能- 能Web在线打开AutoCAD图形
- 测量距离
- 测量面积
- 测量角度
- 坐标标注
- 测量时能捕捉Web端CAD图形上面的坐标,提高准确度
- 测量时能对捕捉进行开关启用
- 测量时能启用正交模式
- 测量时能自定义右键菜单功能
- 能进行连续测量
- 测量结束后,能删除已测量的结果
如果在Web网页端展示CAD图形(唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud) 这个在前面的博文中已讲过,这里不再重复,有需要的朋友可下载工程源代码研究下。
测量距离 测量面积 测量角度 坐标标注 其他功能在测量过程中,按Alt键可开启关闭捕捉;按Ctrl键可启用正交模式;按退格键可删除上一个点;按ESC键取消测量;按Enter键结束测量; 按右键弹出上下文菜单
代码实现有需要的朋友可以在线体验下。上面的案例代码已开源。访问 (唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud) ,点击下载此案例源码即可。
import vjmap { Map } from 'vjmap'
import { sleep } from '~/utils/ui';
import { getMapSnapPoints } from './snap';
let snapObj: any; // 设置的捕捉的实体
let curMeasureCmd: string; // 当前测量命令
export async function runMeasureCmd(map: Map cmd: string) {
curMeasureCmd = cmd;
if (cmd != "measureCancel") {
// 先结束当前测量
await measureCancel(map);
if (!snapObj) {
// 获取地图上的捕捉点
snapObj = {};
getMapSnapPoints(map snapObj);
}
}
switch (cmd) {
case "measureDist":
measureDistLoop(map snapObj);
break;
case "measureArea":
measureAreaLoop(map snapObj);
break;
case "measureAngle":
measureAngleLoop(map snapObj);
break;
case "measureCoordinate":
measureCoordinateLoop(map snapObj);
break;
case "measureCancel":
await measureCancel(map);
break;
}
}
// 结束绘制
const measureCancel = async (map: Map)=> {
// 连续发送取消键,第一次取消当前绘制,第二次退出测量
map.fire("keyup" {keyCode:27});
await sleep(100);
map.fire("keyup" {keyCode:27});
await sleep(100);
map.setIsInteracting(false); // 没有进行交互操作了
}
let popup: vjmap.Popup | null;
const setPopupText = (text: string map: Map) => {
if (text) {
if (!popup) {
popup = new vjmap.Popup({
className: "my-custom-popup"
closeOnClick: false
closeButton: false
})
.setHTML(text)
.setMaxWidth("500px")
.trackPointer()
.addTo(map)
}
else {
popup.sethtml(text);
}
} else {
// 如果为空时,则删除popup
if (popup) {
popup.setLngLat([0 0]); // 取消trackPointer
popup.remove();
popup = null;
}
}
}
// 测量距离循环,直至按ESC键取消,否则测量完一条后,继续测量下一条
const measureDistLoop = async (map: Map snapObj: any)=> {
while(true) {
let res = await measureDist(map snapObj);
if (res.exit === true) break;
if (curMeasureCmd != "measureDist") break;
}
}
// 测量距离
const measureDist = async (map: Map snapObj: any)=> {
let isDrawing = false;
let line = await vjmap.Draw.actionDrawLineSting(map {
api: {
getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
}
updatecoordinate: (e: any) => {
if (!e.lnglat) return;
isDrawing = true;
const co = map.fromLngLat(e.feature.coordinates[e.feature.coordinates.length - 1]);
let html = `【测量距离】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)} ${co.y.toFixed(2)}</span>`;
if (e.feature.coordinates.length == 1) {
html = "<br/>请指定要测量的第一点的坐标位置"
} else {
let len = e.feature.coordinates.length;
html = `<br/>按Alt键取捕捉; Ctrl键启用正交; 退格键删除上一个点`
html = `<br/>距上一点距离: <span style="color: #ff0000">${getDist(map [e.feature.coordinates[len - 2] e.feature.coordinates[len -1]])}</span>`
html = `; 当前总的距离: <span style="color: #ff0000">${getDist(map e.feature.coordinates)}</span>`
}
setPopupText(html map)
}
contextMenu: (e: any) => {
new vjmap.ContextMenu({
event: e.event.originalEvent
theme: "dark" //light
width: "250px"
items: [
{
label: '确认'
onClick: () => {
// 给地图发送Enter键消息即可取消,模拟按Enter键
map.fire("keyup" {keyCode:13})
setPopupText("" map);
}
}
{
label: '取消'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
setPopupText("" map);
}
} {
label: '删除上一个点'
onClick: () => {
// 给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
map.fire("keyup" {keyCode:8})
}
} {
label: '结束测距'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
isDrawing = false;
setPopupText("" map);
}
}
]
});
}
});
if (line.cancel) {
setPopupText("" map);
return {
cancel: true
exit: isDrawing === false // 如果还没有绘制,就取消的话,就结束测距
};// 取消操作
}
let color = vjmap.randomColor();
let polyline = new vjmap.Polyline({
data: line.features[0].geometry.coordinates
lineColor: color
lineWidth: 2
});
polyline.addTo(map);
addMarkersToLine(map line.features[0].geometry.coordinates color polyline.sourceId || "" snapObj);
return {
polyline
};
}
// 给线的加个点加个测量的结果值
const addMarkersToLine = (map: Map coordinates: Array<[number number]> color: string sourceId: string snapObj: any) => {
let markerTexts: any = [];
for(let i = 1; i < coordinates.length; i ) {
let text = new vjmap.Text({
text: getDist(map coordinates.slice(0 i 1))
anchor: "left"
offset: [3 0] // x y 方向像素偏移量
style:{ // 自定义样式
'cursor': 'pointer'
'opacity': 0.8
'padding': '6px'
'border-radius': '12px'
'background-color': color
'border-width': 0
'box-shadow': '0px 2px 6px 0px rgba(97 113 166 0.2)'
'text-align': 'center'
'font-size': '14px'
'color': `#${color.substring(1).split("").map(c => (15 - parseInt(c 16)).toString(16)).join("")}`
}
});
text.setLngLat(coordinates[i]).addTo(map);
markerTexts.push(text);
}
// 给第一个点加一个marker用来删除
const deletePng = "delete.png";
let el = document.createElement('div');
el.className = 'marker';
el.style.backgroundImage =
`url(${deletePng})`;
el.style.width = '20px';
el.style.height = '20px';
el.style.backgroundSize = '100%';
el.style.cursor = "pointer";
el.addEventListener('click' function (e) {
map.removeSourceEx(sourceId); // 删除绘制的线
markerTexts.forEach((m: any) => m.remove());
markerTexts = [];
// 多点了下,给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
map.fire("keyup" {keyCode:8})
});
// Add markers to the map.
let deleteMarker = new vjmap.Marker({
element: el
anchor: 'right'
});
deleteMarker.setLngLat(coordinates[0])
.setOffset([-5 0])
.addTo(map);
markerTexts.push(deleteMarker)
// 把坐标加进捕捉数组中。
addSnapCoordinates(snapObj coordinates);
}
// 得到距离值
const getDist = (map: Map coordinates: Array<[number number]>) => {
let result = vjmap.Math2D.lineDist(map.fromLngLat(coordinates));
let unit = "m";
if (result >= 1000) {
result /= 1000;
unit = "km";
} else if (result < 0.01) {
result *= 100;
unit = "cm";
}
return result.toFixed(2) " " unit;
}
// 增加捕捉点
const addSnapCoordinates = (snapObj: any coordinates: Array<[number number]>) => {
snapObj.features.push({
type: "Feature"
geometry: {
type: "LineString"
coordinates: [...coordinates]
}
})
}
// 测量面积
const measureArea = async (map: Map snapObj: any)=> {
let isDrawing = false;
let poly = await vjmap.Draw.actionDrawPolygon(map {
api: {
getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
}
updatecoordinate: (e: any) => {
if (!e.lnglat) return;
isDrawing = true;
const co = map.fromLngLat(e.feature.coordinates[0][e.feature.coordinates.length - 1]);
let html = `【测量面积】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)} ${co.y.toFixed(2)}</span>`;
if (e.feature.coordinates[0].length == 1) {
html = "<br/>请指定要测量的第一点的坐标位置"
} else {
html = `<br/>按Alt键取捕捉; Ctrl键启用正交; 退格键删除上一个点`
html = `<br/>当前面积: <span style="color: #ff0000">${getArea(map e.feature.coordinates[0])}</span>`
}
setPopupText(html map)
}
contextMenu: (e: any) => {
new vjmap.ContextMenu({
event: e.event.originalEvent
theme: "dark" //light
width: "250px"
items: [
{
label: '确认'
onClick: () => {
// 给地图发送Enter键消息即可取消,模拟按Enter键
map.fire("keyup" {keyCode:13})
setPopupText("" map);
}
}
{
label: '取消'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
setPopupText("" map);
}
} {
label: '删除上一个点'
onClick: () => {
// 给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
map.fire("keyup" {keyCode:8})
}
} {
label: '结束测面积'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
isDrawing = false;
setPopupText("" map);
}
}
]
});
}
});
if (poly.cancel) {
debugger
setPopupText("" map);
return {
cancel: true
exit: isDrawing === false // 如果还没有绘制,就取消的话,就结束测距
};// 取消操作
}
let color = vjmap.randomColor();
let polygon = new vjmap.Polygon({
data: poly.features[0].geometry.coordinates[0]
fillColor: color
fillOpacity: 0.4
fillOutlineColor: color
});
polygon.addTo(map);
addMarkersToPolygon(map poly.features[0].geometry.coordinates[0] color polygon.sourceId || "" snapObj);
return {
polygon
};
}
// 测量面积循环,直至按ESC键取消,否则测量完一条后,继续测量下一条
const measureAreaLoop = async (map: Map snapObj: any)=> {
while(true) {
let res = await measureArea(map snapObj);
if (res.exit === true) break;
if (curMeasureCmd != "measureArea") break;
}
}
// 给加个测量的结果值
const addMarkersToPolygon = (map: Map coordinates: Array<[number number]> color: string sourceId: string snapObj: any) => {
let markerTexts: any = [];
const center = vjmap.polygonCentroid(map.fromLngLat(coordinates));
let text = new vjmap.Text({
text: getArea(map coordinates)
anchor: "center"
offset: [0 0] // x y 方向像素偏移量
style:{ // 自定义样式
'cursor': 'pointer'
'opacity': 0.8
'padding': '6px'
'border-radius': '12px'
'background-color': `#${color.substring(1).split("").map(c => (15 - parseInt(c 16)).toString(16)).join("")}`
'border-width': 0
'box-shadow': '0px 2px 6px 0px rgba(97 113 166 0.2)'
'text-align': 'center'
'font-size': '14px'
'color': color
}
});
text.setLngLat(map.toLngLat(center)).addTo(map);
markerTexts.push(text);
// 给第一个点加一个marker用来删除
const deletePng = = "delete.png";
let el = document.createElement('div');
el.className = 'marker';
el.style.backgroundImage =
`url(${deletePng})`;
el.style.width = '20px';
el.style.height = '20px';
el.style.backgroundSize = '100%';
el.style.cursor = "pointer";
el.addEventListener('click' function (e) {
map.removeSourceEx(sourceId); // 删除绘制的线
markerTexts.forEach((m: any) => m.remove());
markerTexts = [];
});
// Add markers to the map.
let deleteMarker = new vjmap.Marker({
element: el
anchor: 'right'
});
deleteMarker.setLngLat(coordinates[0])
.setOffset([-5 0])
.addTo(map);
markerTexts.push(deleteMarker)
// 把坐标加进捕捉数组中。
addSnapCoordinates(snapObj coordinates);
}
// 得到面积值
const getArea = (map: Map coordinates: Array<[number number]>) => {
let result = vjmap.calcPolygonArea(map.fromLngLat(coordinates));
let unit = "m²";
if (result >= 1e6) {
result /= 1e6;
unit = "km²";
} else if (result < 1.0/1e4) {
result *= 1e4;
unit = "cm²";
}
return result.toFixed(2) " " unit;
}
// 测量角度
const measureAngle = async (map: Map snapObj: any)=> {
let isDrawing = false;
let line = await vjmap.Draw.actionDrawLineSting(map {
pointCount: 3 // 只需三个点,绘制完三个点后,自动结束
api: {
getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
}
updatecoordinate: (e: any) => {
if (!e.lnglat) return;
isDrawing = true;
const co = map.fromLngLat(e.feature.coordinates[e.feature.coordinates.length - 1]);
let html = `【测量角度】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)} ${co.y.toFixed(2)}</span>`;
if (e.feature.coordinates.length == 1) {
html = "<br/>请指定要测量的第一点的坐标位置"
} else {
let len = e.feature.coordinates.length;
html = `<br/>按Alt键取捕捉; Ctrl键启用正交; 退格键删除上一个点`
html = `<br/>当前角度: <span style="color: #ff0000">${getAngle(map e.feature.coordinates).angle}</span>`
}
setPopupText(html map)
}
contextMenu: (e: any) => {
new vjmap.ContextMenu({
event: e.event.originalEvent
theme: "dark" //light
width: "250px"
items: [
{
label: '确认'
onClick: () => {
// 给地图发送Enter键消息即可取消,模拟按Enter键
map.fire("keyup" {keyCode:13})
setPopupText("" map);
}
}
{
label: '取消'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
setPopupText("" map);
}
} {
label: '删除上一个点'
onClick: () => {
// 给地图发送退格键Backspace消息即可删除上一个点,模拟按Backspace键
map.fire("keyup" {keyCode:8})
}
} {
label: '结束测角度'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
isDrawing = false;
setPopupText("" map);
}
}
]
});
}
});
if (line.cancel) {
setPopupText("" map);
return {
cancel: true
exit: isDrawing === false // 如果还没有绘制,就取消的话,就结束测距
};// 取消操作
}
let color = vjmap.randomColor();
let polyline = new vjmap.Polyline({
data: line.features[0].geometry.coordinates
lineColor: color
lineWidth: 2
});
polyline.addTo(map);
addMarkersToAngle(map line.features[0].geometry.coordinates color polyline.sourceId || "" snapObj);
return {
polyline
};
}
// 测量角度循环,直至按ESC键取消,否则测量完一条后,继续测量下一条
const measureAngleLoop = async (map: Map snapObj: any)=> {
while(true) {
let res = await measureAngle(map snapObj);
if (res.exit === true) break;
if (curMeasureCmd != "measureAngle") break;
}
}
// 给加个测量的结果值
const addMarkersToAngle = (map: Map coordinates: Array<[number number]> color: string sourceId: string snapObj: any) => {
if (coordinates.length < 3) return;
let markerTexts: any = [];
let points = map.fromLngLat(coordinates);
let textPoint = coordinates[1];
let ang = getAngle(map coordinates);
// 绘制注记圆弧
const cirleArcPath = vjmap.getCirclePolygonCoordinates(
points[1]
points[1].distanceTo(points[0]) / 4.0 36
ang.startAngle ang.endAngle false);
let path = new vjmap.Polyline({
data: map.toLngLat(cirleArcPath)
lineColor: color
lineWidth: 2
});
path.addTo(map);
markerTexts.push(path)
// @ts-ignore
let arcPoints = path.getData().features[0].geometry.coordinates;
let arcMid = arcPoints[Math.ceil(arcPoints.length / 2)];// 取中点
let textAngle = vjmap.radiansToDegrees(-map.fromLngLat(arcMid).angleTo(points[1])) 90;
if (textAngle > 90) textAngle = 180;
else if (textAngle > 270) textAngle -= 180;
let text = new vjmap.Text({
text: ang.angle as string
anchor: "center"
rotation: textAngle
offset: [0 0] // x y 方向像素偏移量
style:{ // 自定义样式
'cursor': 'pointer'
'opacity': 0.8
'padding': '6px'
'border-radius': '12px'
'background-color': color
'border-width': 0
'box-shadow': '0px 2px 6px 0px rgba(97 113 166 0.2)'
'text-align': 'center'
'font-size': '14px'
'color': color
}
});
text.setLngLat(arcMid).addTo(map);
markerTexts.push(text);
// 给第一个点加一个marker用来删除
const deletePng = = "delete.png";
let el = document.createElement('div');
el.className = 'marker';
el.style.backgroundImage =
`url(${deletePng})`;
el.style.width = '20px';
el.style.height = '20px';
el.style.backgroundSize = '100%';
el.style.cursor = "pointer";
el.addEventListener('click' function (e) {
map.removeSourceEx(sourceId); // 删除绘制的线
markerTexts.forEach((m: any) => m.remove());
markerTexts = [];
});
// Add markers to the map.
let deleteMarker = new vjmap.Marker({
element: el
anchor: 'right'
});
deleteMarker.setLngLat(coordinates[1])
.setOffset([-5 0])
.addTo(map);
markerTexts.push(deleteMarker)
// 把坐标加进捕捉数组中。
addSnapCoordinates(snapObj coordinates);
}
// 得到角度值
const getAngle = (map: Map coordinates: Array<[number number]>) => {
let points = map.fromLngLat(coordinates);
if (points.length < 3) return { angle: 0.0 }
let angle1 = points[0].angleTo(points[1]);
let angle2 = points[2].angleTo(points[1]);
let angle = angle1 - angle2;
let deg = vjmap.radiansToDegrees(angle);//弧度转角度
let dir = true;
if (deg < 0) {
deg = -deg;
dir = !dir;
}
if (deg > 180) {
deg = 360 - deg;
dir = !dir;
}
let startAngle = !dir ? vjmap.radiansToDegrees(angle1) : vjmap.radiansToDegrees(angle2);
let endAngle = dir ? vjmap.radiansToDegrees(angle1) : vjmap.radiansToDegrees(angle2);
startAngle = startAngle < 0 ? 360 startAngle : startAngle;
endAngle = endAngle < 0 ? 360 endAngle : endAngle;
if (endAngle < startAngle) {
endAngle = 360;
}
return {
angle: deg.toFixed(2) "°"
dir
startAngle
endAngle
}
}
// 测量坐标
const measureCoordinate = async (map: Map snapObj: any)=> {
let isDrawing = false;
let point = await vjmap.Draw.actionDrawPoint(map {
api: {
getSnapFeatures: snapObj //要捕捉的数据项在后面,通过属性features赋值
}
updatecoordinate: (e: any) => {
if (!e.lnglat) return;
isDrawing = true;
const co = map.fromLngLat(e.lnglat);
let html = `【测量坐标】当前坐标:<span style="color: #ff0000"> ${co.x.toFixed(2)} ${co.y.toFixed(2)}</span>`;
setPopupText(html map)
}
contextMenu: (e: any) => {
new vjmap.ContextMenu({
event: e.event.originalEvent
theme: "dark" //light
width: "250px"
items: [
{
label: '确认'
onClick: () => {
// 给地图发送Enter键消息即可取消,模拟按Enter键
map.fire("keyup" {keyCode:13})
setPopupText("" map);
}
}
{
label: '取消'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
setPopupText("" map);
}
}
{
label: '结束测坐标'
onClick: () => {
// 给地图发送ESC键消息即可取消,模拟按ESC键
map.fire("keyup" {keyCode:27})
isDrawing = false;
setPopupText("" map);
}
}
]
});
}
});
if (point.cancel) {
setPopupText("" map);
return {
cancel: true
exit: isDrawing === false
};// 取消操作
}
addMarkersToCoord(map point.features[0].geometry.coordinates);
return {
point
};
}
// 测量坐标循环,直至按ESC键取消
const measureCoordinateLoop = async (map: Map snapObj: any)=> {
while(true) {
let res = await measureCoordinate(map snapObj);
if (res.exit === true) break;
if (curMeasureCmd != "measureCoordinate") break;
}
}
// 给加个点加个测量的结果值
const addMarkersToCoord = (map: Map coordinates: [number number]) => {
let markerTexts: any = [];
let co = map.fromLngLat(coordinates);
let content = `X: ${co.x.toFixed(2)} Y: ${co.y.toFixed(2)}`
let marker = createLeaderMarker(map coordinates content);
markerTexts.push(marker);
// 给第一个点加一个marker用来删除
const deletePng = "delete.png";
let el = document.createElement('div');
el.className = 'marker';
el.style.backgroundImage =
`url(${deletePng})`;
el.style.width = '20px';
el.style.height = '20px';
el.style.backgroundSize = '100%';
el.style.cursor = "pointer";
el.addEventListener('click' function (e) {
markerTexts.forEach((m: any) => m.remove());
markerTexts = [];
});
// Add markers to the map.
let deleteMarker = new vjmap.Marker({
element: el
anchor: 'right'
});
deleteMarker.setLngLat(coordinates)
.setOffset([-5 0])
.addTo(map);
markerTexts.push(deleteMarker)
}
// 引线标记
const createLeaderMarker = (map: Map lnglat: [number number] content: string) => {
let el = document.createElement('div');
el.className = 'marker';
el.style.position = 'absolute'
let img = document.createElement("div");
img.style.backgroundImage = 'bk.png';
img.style.backgroundRepeat = "no-repeat"
img.style.height = '37px';
img.style.width = '100px';
img.style.position = 'absolute';
img.style.left = '-3px';
img.style.bottom = '-3px';
img.style.right = "0px"
el.appendChild(img);
let panel = document.createElement("div");
panel.style.height = '50px';
panel.style.width = '350px';
panel.style.position = 'absolute';
panel.style.left = '97px';
panel.style.top = '-60px';
panel.style.border = "solid 1px #8E0EFF";
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';
panel.style.backgroundRepeat = 'no-repeat';
panel.style.backgroundColor ='rgba(87 255 255 0.3)'
panel.style.backgroundSize = '1px 6px 6px 1px';
panel.style.fontSize = '18px';
panel.style.color = '#ffffff';
panel.innerHTML = `<div style='margin: 15px 5px 15px 5px'>${content}</div>`;
el.appendChild(panel);
// Add markers to the map.
let marker = new vjmap.Marker({
element: el
anchor: "bottom-left"
})
marker.setLngLat(lnglat)
.addTo(map);
return marker
}