在放大fabric js时保持对象大小和位置



我试图在缩放时保持对象大小,我试图从这个答案中得到启发,在这种情况下,编写它的人没有解决控件问题,因此,你可以看到他们在缩放时没有像这张屏幕截图中那样粘在对象上。

但我提出了这个解决方案,通过计算新的结构,在基于倒置的viewportTransform计算后更新其左侧顶部,来维护对象位置和控件。点使用结构.util.transformPoint函数

fabric.Object.prototype.transform = function(ctx) {
const obj = this;
const {
ignoreZoom,
group,
canvas,
left,
top
} = obj;
const {
contextTop,
viewportTransform,
getZoom,
requestRenderAll,
} = canvas;
var needFullTransform = (group && !group._transformDone) || (group && canvas && ctx === contextTop);
if (ignoreZoom) {
const oldP = new fabric.Point(left, top);
const newP = fabric.util.transformPoint(oldP, fabric.util.invertTransform(viewportTransform));
var zoom = 1 / getZoom();
/* // here i tried to refresh the whole canvas with requestRenderAll()
this.set({
left: newP.x,
top: newP.y,
scaleX: zoom,
scaleY: zoom,
});
this.setCoords();
requestRenderAll();
*/
// but here i try refresh the object only which is better i think
this.left = newP.x;
this.top = newP.y;
this.scaleX = zoom;
this.scaleY = zoom;
this.drawObject(ctx);
}
var m = this.calcTransformMatrix(!needFullTransform);
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}

我制作了这个代码沙盒作为我的代码的演示。正如你在这个屏幕截图中看到的,控件粘在对象周围,但整个控件相对于背景并没有保持其位置,有时它们会完全消失。我需要对象保持其相对于背景的位置。如何让它变得更好?

//编辑

我试图更好地理解缩放时会发生什么,我发现了结构。Canvas.zoomToPoint((,用于缩放(如教程中所述(

zoomToPoint: function (point, value) {
// TODO: just change the scale, preserve other transformations
var before = point, vpt = this.viewportTransform.slice(0);
point = transformPoint(point, invertTransform(this.viewportTransform));
vpt[0] = value;
vpt[3] = value;
var after = transformPoint(point, vpt);
vpt[4] += before.x - after.x;
vpt[5] += before.y - after.y;
return this.setViewportTransform(vpt);
},

我想固定对象相对于背景的位置的最好方法是应用对画布的逆变换来缩放对象。所以我写了这个函数

function getNewVpt(point, value) {
var before = point, 
vpt = canvas.viewportTransform.slice(0);
point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));
vpt[0] = value;
vpt[3] = value;
var after = fabric.util.transformPoint(point, vpt);
vpt[4] += before.x - after.x;
vpt[5] += before.y - after.y;
return vpt;
}

我用它重写了结构。Object.protype.transform

fabric.Object.prototype.transform = function (ctx) {
const obj = this;
const { ignoreZoom, group, canvas: objCanvas, left, top } = obj;
const {
contextTop,
viewportTransform,
} = objCanvas;
var needFullTransform =
(group && !group._transformDone) ||
(group && objCanvas && ctx === contextTop);
if (ignoreZoom && zoomingIsOn) {
zoomingIsOn = false;
var zoom = 1 / objCanvas.getZoom();
const oldP = new fabric.Point(left, top);
console.log('transform : oldP : ', oldP);
const newVpt = getNewVpt(oldP, zoom)
const newP = fabric.util.transformPoint(oldP, newVpt);
console.log('transform : newP : ', newP);    
// here i tried to refresh the whole canvas with requestRenderAll()
this.set({
left: newP.x,
top: newP.y,
scaleX: zoom,
scaleY: zoom
});
this.setCoords();
console.log('transform : CALLING objCanvas.requestRenderAll() ');
objCanvas.requestRenderAll();
// but here i try refresh the object only which is better i think
// this.left = newP.x;
// this.top = newP.y;
// this.scaleX = zoom;
// this.scaleY = zoom;
// this.drawObject(ctx);
}
var m = this.calcTransformMatrix(!needFullTransform);
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
};

在这里,我为第二个解决方案分叉了这个新的代码沙盒,结果似乎比前一个解决方案更好,但它仍然不完美。我可能还在做错什么?!

//编辑2

我试图将objCanvas.getZoom((而不是zoom作为第二个参数传递给getNewVpt((函数。似乎还有一些改进,但仍然不够完美

//编辑3在这个代码沙盒中,我可能使用另一个直接返回新点的函数得到了最好的结果:

function getNewPt(point, value) {
// TODO: just change the scale, preserve other transformations
var vpt = canvas.viewportTransform.slice(0);
point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));
vpt[0] = value;
vpt[3] = value;

return fabric.util.transformPoint(point, vpt);;
}

我仍然希望任何人能告诉我是否有办法改进它。正如你所看到的,三角形在缩放/去缩放后返回到其初始位置,并返回到相同的初始缩放值,这很好,但在这些初始和最终状态之间,它似乎仍然不在正确的位置。。

您只需调用zoomToPoint即可缩放,对象将保持其相对于背景的位置和比例。

尝试以下

canvas.on('mouse:wheel', function(opt) {
// console.log(opt.e.deltaY)
let zoomLevel = canvas.getZoom();
// console.log('zoom Level: ', (zoomLevel * 100).toFixed(0), '%');
zoomLevel += opt.e.deltaY * -0.01;
// Restrict scale
zoomLevel = Math.min(Math.max(.125, zoomLevel), 20);
canvas.zoomToPoint(
new fabric.Point(opt.e.offsetX, opt.e.offsetY),
zoomLevel,
);
canvas.renderAll();
})

最新更新