Joh*_*ohn 3 html javascript canvas fabricjs
我知道 Fabric.js 在同一个画布中内置了拖放支持。
我们如何使它适用于多个画布?
或者来自非画布 html 元素,例如来自表格的图像?
在 Fabric.js 中可以在画布之间拖放,但涉及一些私有属性的操作。出于这个原因,不能保证它在未来版本的 Fabric.js 中有效。
工作演示: https : //jsfiddle.net/mmalex/kdbu9f3y/
视频截图: https : //youtu.be/nXZgCmIrpqQ
主要特点:
? 可以在任意数量的画布(不仅仅是两个)之间拖放,
? 可以不间断地在画布之间来回拖动,
? 可以在不中断操作的情况下转换(镜像)丢弃的图像。
第 1 步- 准备画布,加载图像,安排演示的所有内容:
//create two canvases
var canvas0El = document.getElementById("c0");
canvas0El.width = canvas0El.offsetWidth;
canvas0El.height = canvas0El.parentElement.offsetHeight;
var canvas1El = document.getElementById("c1");
canvas1El.width = canvas1El.offsetWidth;
canvas1El.height = canvas1El.parentElement.offsetHeight;
var canvas0 = new fabric.Canvas('c0');
canvas0.setBackgroundColor('rgba(19, 19, 19, 0.25)');
canvas0.renderAll();
var canvas1 = new fabric.Canvas('c1');
canvas1.setBackgroundColor('rgba(92, 18, 18, 0.25)');
canvas1.renderAll();
// add loaded image on left canvas
var onImageLoaded = function(oImg) {
oImg.originX = "center";
oImg.originY = "center";
oImg.left = this.x;
oImg.top = this.y;
canvas0.add(oImg);
oImg.canvas = canvas0;
imgArrow = oImg;
};
var config = { crossOrigin: 'anonymous' };
var baseUrl = "http://mbnsay.com/rayys/images";
var url0 = baseUrl + "/arrow-right-green.png";
var url1 = baseUrl + "/arrow-right-icon.png";
var url2 = baseUrl + "/arrow-right-blue.png";
// load some images
fabric.Image.fromURL(url0, onImageLoaded.bind({ x: 56, y: 96 }), config);
fabric.Image.fromURL(url0, onImageLoaded.bind({ x: 156, y: 96 }), config);
fabric.Image.fromURL(url1, onImageLoaded.bind({ x: 56, y: 2*96 }), config);
fabric.Image.fromURL(url1, onImageLoaded.bind({ x: 156, y: 2*96 }), config);
fabric.Image.fromURL(url2, onImageLoaded.bind({ x: 56, y: 3*96 }), config);
fabric.Image.fromURL(url2, onImageLoaded.bind({ x: 156, y: 3*96 }), config);
Run Code Online (Sandbox Code Playgroud)
第 2 步-object:moving在两个画布上订阅事件,并观察对象中心何时穿过画布边界。当物体越过边界时,它必须是
var onObjectMoving = function(p) {
var viewport = p.target.canvas.calcViewportBoundaries();
if (p.target.canvas === canvas0) {
if (p.target.left > viewport.br.x) {
console.log("Migrate: left -> center");
migrateItem(canvas0, canvas1, p.target);
return;
}
}
if (p.target.canvas === canvas1) {
if (p.target.left < viewport.tl.x) {
console.log("Migrate: center -> left");
migrateItem(canvas1, canvas0, p.target);
return;
}
}
};
canvas0.on("object:moving", onObjectMoving);
canvas1.on("object:moving", onObjectMoving);
Run Code Online (Sandbox Code Playgroud)
步骤 3 – 解决方案的核心,在不中断鼠标操作的情况下在画布之间迁移对象。很难解释,只需按照代码中的注释进行操作即可。
var migrateItem = function(fromCanvas, toCanvas, pendingImage) {
// Just drop image from old canvas
fromCanvas.remove(pendingImage);
// We're going to trick fabric.js,
// so we keep internal transforms of the source canvas,
// in order to inject it into destination canvas.
var pendingTransform = fromCanvas._currentTransform;
fromCanvas._currentTransform = null;
// Make shortcuts for fabric.util.removeListener and fabric.util.addListener
var removeListener = fabric.util.removeListener;
var addListener = fabric.util.addListener;
// Re-arrange subscriptions for source canvas
{
removeListener(fabric.document, 'mouseup', fromCanvas._onMouseUp);
removeListener(fabric.document, 'touchend', fromCanvas._onMouseUp);
removeListener(fabric.document, 'mousemove', fromCanvas._onMouseMove);
removeListener(fabric.document, 'touchmove', fromCanvas._onMouseMove);
addListener(fromCanvas.upperCanvasEl, 'mousemove', fromCanvas._onMouseMove);
addListener(fromCanvas.upperCanvasEl, 'touchmove', fromCanvas._onMouseMove, {
passive: false
});
if (isTouchDevice) {
// Wait 500ms before rebinding mousedown to prevent double triggers
// from touch devices
var _this = fromCanvas;
setTimeout(function() {
addListener(_this.upperCanvasEl, 'mousedown', _this._onMouseDown);
}, 500);
}
}
// Re-arrange subscriptions for destination canvas
{
addListener(fabric.document, 'touchend', toCanvas._onMouseUp, {
passive: false
});
addListener(fabric.document, 'touchmove', toCanvas._onMouseMove, {
passive: false
});
removeListener(toCanvas.upperCanvasEl, 'mousemove', toCanvas._onMouseMove);
removeListener(toCanvas.upperCanvasEl, 'touchmove', toCanvas._onMouseMove);
if (isTouchDevice) {
// Unbind mousedown to prevent double triggers from touch devices
removeListener(toCanvas.upperCanvasEl, 'mousedown', toCanvas._onMouseDown);
} else {
addListener(fabric.document, 'mouseup', toCanvas._onMouseUp);
addListener(fabric.document, 'mousemove', toCanvas._onMouseMove);
}
}
// We need this timer, because we want Fabric.js to complete pending render
// before we inject, because it causes some unpleasant image jumping.
setTimeout(function() {
// Add image to destination canvas,
pendingImage.scaleX *= -1;
pendingImage.canvas = toCanvas;
pendingImage.migrated = true;
toCanvas.add(pendingImage);
// and inject transforms from source canvas
toCanvas._currentTransform = pendingTransform;
// as we have mirrored the image, we mirror transforms too
toCanvas._currentTransform.scaleX *= -1;
toCanvas._currentTransform.original.scaleX *= -1;
// finally don't forget to make pasted object selected
toCanvas.setActiveObject(pendingImage);
}, 10);
};
Run Code Online (Sandbox Code Playgroud)
玩得开心!