AutoCAD的出現與應用使得在其應用領域內的作業效率得到了質的飛躍,同時隨著技術的不斷進步,更多的人希望能擺脫AutoCAD環境,能方便的實作Web在線看圖,圖紙批注此功能作為圖紙審核作業的一個重要作業,本文將介紹如何實作在線Web端圖紙批注功能,
實作效果圖

Web在線打開AutoCAD圖形
如果在Web網頁端展示CAD圖形(唯杰地圖云端圖紙管理平臺 https://vjmap.com/app/cloud),這個在前面的博文中已講過,這里不再重復,有需要的朋友可下載工程源代碼研究下,
圖紙批注方案比較
圖紙批注功能做為web端圖紙顯示的一個圖層,一般的技術思路可分為通過矢量圖形繪制和svg圖形這兩種方式把圖紙要批注的內容疊加到地圖圖層上,兩個方案的優缺點如下:
矢量圖形繪制:
優點:性能高,疊加效果好,支持無級放大不失真;
缺點:編輯功能較弱,表達內容有限
SVG圖形:
優點:編輯功能強,表達內容豐富
缺點:大量svg圖形會導致性能低下,放大到一定級別后會失真
總結: 鑒于圖紙批注的需求,是一個要求表達內容豐富, 同時不會存在很大資料量的需求,所以用 svg圖形方案疊加是不錯的選擇,
圖紙批注實作
SVG圖形編輯庫選型
svg圖形編輯庫采用的是github上star多達22k的開源庫Fabric.js,
Fabric.js 是一個功能強大且簡潔的 canvas 庫,它提供了一系列可操作 canvas 的 API,讓你輕松的操作 canvas,并且還提供了 SVG 轉 canvas 和 canvas 轉 SVG 的決議器供使用,
Fabric.js官網地址為http://fabricjs.com/ ,github倉庫地址為https://github.com/fabricjs/fabric.js
圖紙批注繪圖相關代碼
//繪畫方法 function drawing() { if (drawingObject) { canvas.remove(drawingObject); } var canvasObject = null; switch (drawType) { case "arrow": //箭頭 canvasObject = new fabric.Path(drawArrow(mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y, 30, 30), { stroke: strokeColor.value, fill: "rgba(255,255,255,0)", strokeWidth: strokeWidth.value }); break; case "line": //直線 canvasObject = new fabric.Line([mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y], { stroke: strokeColor.value, strokeWidth: strokeWidth.value }); break; case "dottedline": //虛線 canvasObject = new fabric.Line([mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y], { strokeDashArray: [3, 1], stroke: strokeColor.value, strokeWidth: strokeWidth.value }); break; case "circle": //正圓 var left = mouseFrom.x, top = mouseFrom.y; var radius = Math.sqrt((mouseTo.x - left) * (mouseTo.x - left) + (mouseTo.y - top) * (mouseTo.y - top)) / 2; canvasObject = new fabric.Circle({ left: left, top: top, stroke: strokeColor.value, fill: "rgba(255, 255, 255, 0)", radius: radius, strokeWidth: strokeWidth.value }); break; case "ellipse": //橢圓 var left = mouseFrom.x, top = mouseFrom.y; var radius = Math.sqrt((mouseTo.x - left) * (mouseTo.x - left) + (mouseTo.y - top) * (mouseTo.y - top)) / 2; canvasObject = new fabric.Ellipse({ left: left, top: top, stroke: strokeColor.value, fill: "rgba(255, 255, 255, 0)", originX: "center", originY: "center", rx: Math.abs(left - mouseTo.x), ry: Math.abs(top - mouseTo.y), strokeWidth: strokeWidth.value }); break; case "rectangle": //長方形 var path = "M " + mouseFrom.x + " " + mouseFrom.y + " L " + mouseTo.x + " " + mouseFrom.y + " L " + mouseTo.x + " " + mouseTo.y + " L " + mouseFrom.x + " " + mouseTo.y + " L " + mouseFrom.x + " " + mouseFrom.y + " z"; canvasObject = new fabric.Path(path, { left: left, top: top, stroke: strokeColor.value, strokeWidth: strokeWidth.value, fill: "rgba(255, 255, 255, 0)" }); //也可以使用fabric.Rect break; case "rightangle": //直角三角形 var path = "M " + mouseFrom.x + " " + mouseFrom.y + " L " + mouseFrom.x + " " + mouseTo.y + " L " + mouseTo.x + " " + mouseTo.y + " z"; canvasObject = new fabric.Path(path, { left: left, top: top, stroke: strokeColor.value, strokeWidth: strokeWidth.value, fill: "rgba(255, 255, 255, 0)" }); break; case "equilateral": //等邊三角形 var height = mouseTo.y - mouseFrom.y; canvasObject = new fabric.Triangle({ top: mouseFrom.y, left: mouseFrom.x, width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2.0, 2)), height: height, stroke: strokeColor.value, strokeWidth: strokeWidth.value, fill: "rgba(255,255,255,0)" }); break; case "text": textbox = new fabric.Textbox("", { left: mouseFrom.x - 60, top: mouseFrom.y - 20, width: 150, fontSize: 30, borderColor: "yellow", fill: strokeColor.value, hasControls: true }); canvas.add(textbox); textbox.enterEditing(); textbox.hiddenTextarea.focus(); break; case "remove": break; default: break; } if (canvasObject) { canvas.add(canvasObject); drawingObject = canvasObject; } }
SVG圖形與地圖疊加顯示
唯杰地圖 vjmap提供的sdk中有在一個地理范圍內創建一個隨縮放而縮放的div的覆寫物類DivOverlay,其型別定義如下
/**
* 在一個地理范圍內創建一個隨縮放而縮放的div的覆寫物
* 注:如果是svg,則需設定為 viewBox="0 0 width height" preserveAspectRatio="xMinYMin meet", updateDivSize選項設定為true
**/
export class DivOverlay {
options: DivOverlayOptions;
_map?: Map;
isShow: boolean;
minZoom: number;
maxZoom: number;
isRemoved: boolean;
parentContainer?: HTMLElement;
constructor(options: DivOverlayOptions);
addTo(map: Map, insertId?: string | HTMLElement): void;
private _isShow;
private _add;
private _remove;
/**
* 設定是否顯示隱藏
* @param visible 是否顯示
* @param isDisplay true的話,表示用style的display去控制隱藏顯示,dom還在檔案中,false的話,會從檔案動態清空增加
*/
setVisible(visible?: boolean, isDisplay?: boolean): void;
remove(): void;
updateBounds(bounds: [GeoPointLike, GeoPointLike, GeoPointLike, GeoPointLike] | GeoBounds): void;
updateSize(width: number, height: number): void;
private _updateZoom;
private _updateDivSize;
private _adjustCoord;
private _update;
}
?
export interface DivOverlayOptions {
/** 范圍,四個點坐標 */
bounds: [GeoPointLike, GeoPointLike, GeoPointLike, GeoPointLike] | GeoBounds;
/** html元素 */
element: HTMLElement;
/** 元素寬 */
width: number;
/** 元素高 */
height: number;
/** 顯示最大級別 */
minZoom?: number;
/** 顯示最小級別 */
maxZoom?: number;
/** 自動更新div大小,(如果需要svg放大,需要設定為true) */
updateDivSize?: boolean;
/** 放大div時,最大的div大小,超過了就像素放大了 */
maxDivSize?: number;
}
我們把fabricjs中繪制的圖形匯出為svg,然后通過DivOverlay疊加至地圖上,就可以了,相關代碼如下
?
export const createDivSvg = (map: Map, eleId: string, pt1: GeoPoint, pt2: GeoPoint, width: number, height: number, svg: string) => {
svg = svg.substring(svg.indexOf("<desc>"));
const div = document.createElement( "div" );
div.id = eleId;
div.innerHTML = `
<svg viewBox="0 0 ${width} ${height}" preserveAspectRatio="xMinYMin meet" version="1.1" xmlns="http://www.w3.org/2000/svg">
${svg}
</svg>
`;
div.style.position = 'absolute';
div.style.pointerEvents = "none"
div.style.width = width + "px";
div.style.height = height + "px";
//div.style.opacity = '0.8';
?
const divOverlay = new DivOverlay({
bounds: [[pt1.x, pt2.y], [pt1.x, pt1.y], [pt2.x, pt1.y], [pt2.x, pt2.y]],
element: div,
width: width,
height: height,
updateDivSize: true // 如果svg需要放大,需要加此引數
})
divOverlay.addTo(map);
return divOverlay;
}
let center = map.getCenter();
let anno = {
mapId: app.curMapId,
version: app.curVersion,
name: name,
darkTheme: svc.currentMapParam()?.darkMode === true ? true : false,
imgSrc: img,
zoom: map.getZoom(),
centerX: center.lng,
centerY: center.lat,
bearing: map.getBearing(),
pitch: map.getPitch(),
id: id,
pt1: canvasCoord1,
pt2: canvasCoord2,
width: canvasWidth,
height: canvasHeight,
svg: fabricCanvas.toSVG(),
json: fabricCanvas.toJSON(),
}
// 增加divSvg
let divOverlay = createDivSvg(map, id, canvasCoord1, canvasCoord2, canvasWidth, canvasHeight, anno.svg);
有需要的朋友可以在線上傳圖形創建屬于自己的圖紙批注,上面的案例代碼已開源,訪問 (唯杰地圖云端圖紙管理平臺 https://vjmap.com/app/cloud) ,點擊下載此案例原始碼即可,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/500188.html
標籤:其他
