
npm install fabric4.3.0template div classapp-container el-row el-col :span2 el-button classbtn clickonRect(1)漏液排除/el-button el-button classbtn clickonRect(2)限高/el-button el-button stylemargin-top: 20px; clickonStringfy typesuccess保存/el-button /el-col el-col :span20 div classcanvas_box canvas idcanvas width1500 height750/canvas /div /el-col el-col :span2 el-form :modelselectionOptions label-positiontop el-form-item label名称 v-showselectionOptions.nameType el-input v-modelselectionOptions.name/el-input /el-form-item el-form-item label限高值m v-showselectionOptions.nameType 2 el-input typenumber v-modelselectionOptions.altitude :max0.8 :min0/el-input /el-form-item /el-form /el-col /el-row /div /template script import { fabric } from fabric import { getRecentMap } from /api/dispatch/cartography import mapConfig from /api/mapConfig/mapConfig var canvas null let isPanning false; // 是否处于平移状态 let panStartX 0; // 平移起始 X 坐标 let panStartY 0; // 平移起始 Y 坐标 let isDragging false; // 是否正在拖拽用于区分点击和拖拽 let isSelection false export default { data() { return { jsonStr: , mapData: null, baseUrl: import.meta.env.VITE_APP_BASE_API, selectionOptions: {} } }, created() { this.getMapData() }, mounted() { canvas new fabric.Canvas(canvas) canvas.on(selection:created, (e) { isSelection true if (e.selected.length 1) { this.selectionOptions e.selected[0] } else { this.selectionOptions {} } }) canvas.on(selection:updated, (e) { isSelection true if (e.selected.length 1) { this.selectionOptions e.selected[0] } else { this.selectionOptions {} } }); canvas.on(mouse:wheel, function(opt) { const delta opt.e.deltaY; // 滚动方向 let zoom canvas.getZoom(); // 当前缩放比例 zoom * 0.999 ** delta; // 计算新缩放比例指数运算手感更自然 if (zoom 20) zoom 20; // 设置最大缩放倍数 if (zoom 0.01) zoom 0.01; // 设置最小缩放倍数 // 以鼠标指针为中心进行缩放 const point new fabric.Point(opt.e.offsetX, opt.e.offsetY); canvas.zoomToPoint(point, zoom); opt.e.preventDefault(); // 阻止页面滚动 opt.e.stopPropagation(); }); // 鼠标按下准备平移 canvas.on(mouse:down, function(opt) { if (!opt.target) { isSelection false } document.onkeydown e { if (e.key Delete) { canvas.remove(opt.target) } } const isLeftButton (opt.e.button 1 || opt.e.which 1); if (isLeftButton !isSelection) { // 记录起始位置 panStartX opt.e.clientX; panStartY opt.e.clientY; isPanning true; isDragging false; // 关键取消默认的框选行为避免干扰 canvas.selection false; canvas.defaultCursor grab; } }); // 鼠标移动执行平移 canvas.on(mouse:move, function(opt) { if (isPanning opt.e) { const currentX opt.e.clientX; const currentY opt.e.clientY; // 计算鼠标移动距离像素 const deltaX currentX - panStartX; const deltaY currentY - panStartY; // 判断是否达到拖拽阈值防止误触 if (!isDragging (Math.abs(deltaX) 5 || Math.abs(deltaY) 5)) { isDragging true; canvas.defaultCursor grabbing; } // 如果达到拖拽阈值执行平移 if (isDragging) { const delta new fabric.Point(deltaX, deltaY); canvas.relativePan(delta); canvas.renderAll(); // 更新起始位置避免累加 panStartX currentX; panStartY currentY; } } }); // 鼠标释放结束平移 canvas.on(mouse:up, function() { if (isPanning) { isPanning false; isDragging false; canvas.selection true; // 恢复框选功能 canvas.defaultCursor default; canvas.renderAll(); } }); // 鼠标离开画布紧急终止平移防止卡死 canvas.on(mouse:out, function() { if (isPanning) { isPanning false; isDragging false; canvas.selection true; canvas.defaultCursor default; canvas.renderAll(); } }); }, methods: { onStringfy() { let data canvas.toJSON([name, xmapId, altitude, nameType]) const jsonStr JSON.stringify(data) console.log(data) let params { xmapId: data.objects[0].xmapId, jsonData: jsonStr } mapConfig.edit(params).then(res { this.$modal.msgSuccess(保存成功); }) }, onRect(type) { let that this if (type 1) { const rect new fabric.Rect({ name: 漏液排除, nameType: 1, left: 10, top: 10, fill: green, width: 100, height: 100, opacity: 0.3, xmapId: that.mapData.mapId }) canvas.add(rect) } else if (type 2) { const rect new fabric.Rect({ altitude: 0.8, name: 限高, nameType: 2, left: 10, top: 10, fill: red, width: 100, height: 100, opacity: 0.3, xmapId: that.mapData.mapId }) canvas.add(rect) } }, loadSVG(url) { let that this fabric.loadSVGFromURL(this.baseUrl url, (objects, options) { // console.log(options) const svgGroup fabric.util.groupSVGElements(objects, options); svgGroup.scaleToWidth(options.viewBoxWidth); svgGroup.set({ xmapId: that.mapData.mapId, left: 0, top: 0, selectable: false, evented: false, }); canvas.add(svgGroup); canvas.renderAll(); }); }, getMapData() { getRecentMap().then(res { console.log(res.data) if (res.code 200 res.data) { this.mapData res.data this.getMapConfig(res.data.mapId) } }) }, getMapConfig(xmapId) { mapConfig.getByMapId(xmapId).then(res { let objects [] res.data.map(item { objects.push(JSON.parse(item.jsonData)) }) let params { objects: objects } console.log(params) canvas.loadFromJSON(JSON.stringify(params)) this.loadSVG(this.mapData.cadUrl) }) } } } /script style scoped langless .canvas_box { margin: 0 20px; #canvas { border: 1px solid #ccc; margin: auto; background-color: rgba(208, 208, 208, 0.2); } } .btn { width: 88px; margin: 0 0 10px 0; } /style类别核心类/命名空间主要功能关键方法/属性示例画布 (Canvas)fabric.Canvas(交互) /fabric.StaticCanvas(非交互)所有图形对象的容器负责渲染、事件分发、视口变换、序列化等 。add(),remove(),renderAll(),toJSON(),toSVG(),viewportTransform。图形对象 (Objects)fabric.Object(基类), 及其子类Rect,Circle,Ellipse,Line,Polygon,Path,FabricText,IText,FabricImage等 。画布上的可视元素拥有位置、尺寸、填充、描边、旋转、缩放等属性 。set(),get(),scale(),rotate(),setCoords(),calcTransformMatrix(),toObject()。变换与工具 (Transforms Utils)fabric.util矩阵运算、坐标空间转换、角度计算、DOM 辅助、动画工具等 。transformPoint(),multiplyTransformMatrices(),invertTransform(),qrDecompose(),animate(),degreesToRadians()。交互与事件 (Interaction Events)fabric.Canvas实例内置选择、拖拽、缩放、旋转、倾斜等交互功能并抛出相应事件 。on(mouse:down, ...),on(object:moving, ...),on(selection:created, ...)。画笔与自由绘制 (Brushes)fabric.PencilBrush,fabric.CircleBrush,fabric.SprayBrush等 。实现自由绘制功能将鼠标轨迹转换为Path或图形集合 。需启用画布的isDrawingMode属性并选择画笔类型。图像与滤镜 (Images Filters)fabric.FabricImage及各种filters(如BlurFilter,ColorMatrixFilter) 。加载、显示和处理图像。滤镜使用 WebGL 加速 。fabric.FabricImage.fromURL(),image.filters.push(new fabric.filters.BlurFilter()),image.applyFilters()。组合与组 (Grouping)fabric.Group将多个对象组合成一个逻辑单元作为一个整体进行变换和操作 。new fabric.Group([obj1, obj2]),group.add(),group.remove()。序列化 (Serialization)fabric.Object和fabric.Canvas的方法将画布或对象序列化为 JSON 以保存状态或从 JSON 恢复 。canvas.toJSON(),canvas.loadFromJSON(),rect.toObject()。动画 (Animations)fabric.util.animate一个轻量级的动画工具用于在指定时间内改变对象属性 。fabric.util.animate({ startValue: 0, endValue: 100, onChange: (v) rect.set(left, v) })。