自定义控件修改Fabric Circle位置和尺寸后为何未重渲染?
问题:Fabric.js自定义控件缩放Circle时未重渲染
我查阅了Fabric官方文档及示例,自定义了两个控件用于缩放Circle组件。发现Circle的容器尺寸和控件位置已发生变化,但Fabric并未对Circle进行重渲染。想了解该问题的原因,感谢您的帮助!
代码示例
JavaScript
var canvas = (this.__canvas = new fabric.Canvas("c")); // create a rect object function Add() { var newRect = new fabric.Rect({ left: 100, top: 50, fill: "yellow", width: 200, height: 100, objectCaching: false, stroke: "lightgreen", strokeWidth: 4 }); canvas.add(newRect); } var circle = new fabric.Circle({ radius: 100, fill: "#f55", top: 100, left: 100 // visible: false }); circle.set({ borderColor: "red", cornerColor: "green", cornerSize: 12, cornerStyle: "circle", transparentCorners: false }); canvas.add(circle); canvas.setActiveObject(circle); circle.controls = updateControls(); function updateControls() { return { mt: new fabric.Control({ x: 0, y: -0.5, cursorStyle: "not-allowed", render: renderNotAllowed }), mr: new fabric.Control({ x: 0.5, y: 0, cursorStyle: "not-allowed", render: renderNotAllowed }), ml: new fabric.Control({ x: -0.5, y: 0, cursorStyle: "not-allowed", render: renderNotAllowed }), mb: new fabric.Control({ x: 0, y: 0.5, cursorStyle: "not-allowed", render: renderNotAllowed }), br: new fabric.Control({ x: 0.5, y: 0.5, cursorStyle: "crosshair", actionHandler: scaleObject }), tr: new fabric.Control({ x: 0.5, y: -0.5, cursorStyle: "crosshair", actionHandler: scaleObject }) }; } function scaleObject(eventData, transform, x, y) { var circleObject = transform.target; var xOff = 0, yOff = 0, diff = 0; if (circleObject.__corner === "tr") { var trX = circleObject["left"]; var trY = circleObject["top"] + 2 * circleObject["radius"]; xOff = x - trX; yOff = trY - y; diff = Math.max(xOff, yOff, 0); circleObject["top"] = trY - diff; circleObject["left"] = trX; } else if (circleObject.__corner === "br") { var brX = circleObject["left"]; var brY = circleObject["top"]; xOff = x - brX; yOff = y - brY; diff = Math.max(xOff, yOff, 0); } var newRadius = Math.round(diff / 2); circleObject["radius"] = newRadius; circleObject["height"] = 2 * newRadius; circleObject["width"] = 2 * newRadius; circleObject.setCoords(); canvas.requestRenderAll(); } function renderNotAllowed(ctx, left, top, styleOverride, fabricObject) { ctx.beginPath(); ctx.arc(left, top, 6, 0, 2 * Math.PI, false); ctx.fillStyle = "gray"; ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = "white"; ctx.stroke(); }
CSS
.controls { display: inline-block; }
HTML
<script src="https://unpkg.com/fabric@latest/dist/fabric.js"></script> <div class="controls"> <p> <button id="add" onclick="Add()">Add a rectangle</button> </p> </div> <canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
问题原因及解决方案
原因
你直接通过赋值修改了Circle对象的radius、top、left等属性,而没有使用Fabric提供的set()方法。Fabric内部依赖set()来标记对象为"已变更(dirty)",触发后续的重渲染逻辑。直接赋值不会触发这个标记,导致Canvas无法感知对象需要重新绘制。
解决方案
将属性赋值替换为set()方法修改,让Fabric正确检测到对象变更:
修改后的scaleObject函数:
function scaleObject(eventData, transform, x, y) { var circleObject = transform.target; var xOff = 0, yOff = 0, diff = 0; const updateProps = {}; if (circleObject.__corner === "tr") { const trX = circleObject.left; const trY = circleObject.top + 2 * circleObject.radius; xOff = x - trX; yOff = trY - y; diff = Math.max(xOff, yOff, 0); updateProps.top = trY - diff; updateProps.left = trX; } else if (circleObject.__corner === "br") { const brX = circleObject.left; const brY = circleObject.top; xOff = x - brX; yOff = y - brY; diff = Math.max(xOff, yOff, 0); } const newRadius = Math.round(diff / 2); updateProps.radius = newRadius; updateProps.height = 2 * newRadius; updateProps.width = 2 * newRadius; circleObject.set(updateProps); circleObject.setCoords(); canvas.requestRenderAll(); }
这样修改后,Fabric会正确识别Circle的属性变更,触发重渲染,你就能看到Circle的图形随控件操作更新了。
内容的提问来源于stack exchange,提问作者personax
相关产品推荐
相关产品推荐

