简而言之,我正在开发一个项目,其中有两个画布:一个支持缩放和绘图的画布,另一个画布-第一个画布的副本,应该显示不缩放的一般视图。不幸的是,我不了解如何实现此功能,因为第二个画布还显示了缩放图片。请帮忙!这是我所拥有的一个小例子:
var c1 = document.getElementById("scale");
var c2 = document.getElementById("static");
var canvas = this.__canvas = new fabric.Canvas(c1, {
isDrawingMode: true
});
var ctx1 = c1.getContext("2d");
var ctx2 = c2.getContext("2d");
function copy() {
var imgData = ctx1.getImageData(0, 0, 512, 512);
ctx2.putImageData(imgData, 0, 0);
}
fabric.Image.fromURL(
"https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
img => {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
},
{
crossOrigin: "Annoymous"
}
);
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom + delta/200;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
setInterval(() => {
copy();
}, 10)
canvas {
border: 1px solid black;
}
#static {
position: relative;
top: -300px;
left: 500px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js"> </script>
This is interactive canvas
<canvas id="scale" width="300" height="300"></canvas>
<canvas id="static"width="300" height="300"></canvas>
没有完美的解决方案,因为fabricJS不支持在更多目标上进行渲染。
这里有一个toCanvasElement方法可创建到另一个画布的副本,但是它不允许您指定要在其上绘制的画布。
所以这里我在做什么,在某个时候:
有一个额外的副本,可以在现代硬件上快速运行,以至于您根本不在乎,但最好在toCanvasElement方法中添加canvas参数,以便立即在指定的画布上进行绘制
除此之外,在发射该副本时还有一个问题。“ after:render”不是一个好主意,它会永远循环播放,并且还会在缩放更改时重新绘制,这不是您想要的。
现在我使用object:add,也可以添加object:modified,也许还有其他东西,但是理想情况下,当您运行某些会更改某些图形属性的代码时,可以在需要时手动调用副本。
var c1 = document.getElementById("scale");
var c2 = document.getElementById("static");
var canvas = this.__canvas = new fabric.Canvas(c1, {
isDrawingMode: true
});
var ctx2 = c2.getContext("2d");
function copy(copiedCanvas) {
ctx2.drawImage(copiedCanvas,0,0);
}
fabric.Image.fromURL(
"https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
img => {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
},
{
crossOrigin: "Annoymous"
}
);
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom + delta/200;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
function afterRender() {
var originalVP = canvas.viewportTransform;
canvas.viewportTransform = [1, 0, 0, 1, 0, 0];
copy(canvas.toCanvasElement());
canvas.viewportTransform = originalVP;
}
canvas.on('object:added', afterRender);
canvas.on('object:modified', afterRender);
canvas {
border: 1px solid black;
}
#static {
position: relative;
top: -300px;
left: 500px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js"> </script>
This is interactive canvas
<canvas id="scale" width="300" height="300"></canvas>
<canvas id="static"width="300" height="300"></canvas>
这太棒了!!!非常感谢@AndreaBogazzi!
对不起,但我发现了一个小错误。左画布顺序与右画布不匹配。请看这张图片我的密码笔
那是因为您使用的是keepObjectStacking false。选择时放在顶部的对象在导出期间不可用。其他解决方案也是如此。
所以,如果我使用* preseveObjectStacking:true *并手动将对象发送到前端,这行得通吗?
是的,但我不建议这样做。将一个对象放在UP可以更好地可视化您在做什么(缩放/移动),但是右侧的设计代表了左侧画布的一般情况,并且该对象应该在堆栈中的正确位置。这些是UX选项,因此应该采取。该应用程序是您的,您可以根据需要进行操作。