我想在Fabric.js中绘制一个带有鼠标交互的fabric.Polygon。我做了一个小的jsfiddle来显示我的实际状态:http://jsfiddle.net/Kienz/ujefxh7w/
按ESC键后,将取消“交互式绘制模式”,并最终确定多边形。但是现在多边形的位置是错误的(控件是正确的)。
有谁有主意吗?
发布于 2016-02-02 21:06:36
问题定义
当多边形被添加为静态对象时(从这个意义上说,点不会被修改),它的left, right, minX, minY, width, height和中心点可以根据提供的点来计算。
但是当一个人想要动态创建一个多边形时,问题就出现了。在调用setCoords()之后,它会计算移动框的位置,但它是基于有关宽度和高度的错误信息。
记住,,当创建1点多边形时,它的宽度和高度等于0,左上角等于1点。
解决方案
首先,修改大小
_calcDimensions()计算多边形的width、height、minX和minY。minX和minY是所有点的最小值。
这会告诉我们一些点被放置在旧中心上方的左侧和顶部有多远。我们应该使用此信息将旧的左侧移动到正确的位置。新的左上角点是由minX和minY信息转换的旧中心点。
var oldC = polygon.getCenterPoint();
polygon._calcDimensions();
polygon.set({
left: oldC.x + polygon.get('minX'),
top: oldC.y + polygon.get('minY')
});固定点
在中心移动了一些向量v (由于更改了left、right和width、height属性的结果)之后。我们需要通过v的反向更新所有的点。
var newC = polygon.getCenterPoint();
var moveX = -(newC.x-oldC.x);
var moveY = -(newC.y-oldC.y)
var adjPoints = polygon.get("points").map(function(p) {
return {
x: p.x + moveX,
y: p.y + moveY
};
});有关完整的示例,请查看以下文件:http://jsfiddle.net/orian/dyxjkmes/5/
/**
* fabric.js template for bug reports
*
* Please update the name of the jsfiddle (see Fiddle Options).
* This templates uses latest dev verison of fabric.js (https://rawgithub.com/kangax/fabric.js/master/dist/all.js).
*/
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
// Do some initializing stuff
fabric.Object.prototype.set({
transparentCorners: false,
cornerColor: 'rgba(102,153,255,0.5)',
cornerSize: 12,
padding: 7
});
// ADD YOUR CODE HERE
var mode = "add",
currentShape;
canvas.observe("mouse:move", function(event) {
var pos = canvas.getPointer(event.e);
if (mode === "edit" && currentShape) {
var points = currentShape.get("points");
points[points.length - 1].x = pos.x - currentShape.get("left");
points[points.length - 1].y = pos.y - currentShape.get("top");
currentShape.set({
points: points
});
canvas.renderAll();
}
});
canvas.observe("mouse:down", function(event) {
var pos = canvas.getPointer(event.e);
if (mode === "add") {
var polygon = new fabric.Polygon([{
x: pos.x,
y: pos.y
}, {
x: pos.x + 0.5,
y: pos.y + 0.5
}], {
fill: 'blue',
opacity: 0.5,
selectable: false
});
currentShape = polygon;
canvas.add(currentShape);
mode = "edit";
} else if (mode === "edit" && currentShape && currentShape.type === "polygon") {
var points = currentShape.get("points");
points.push({
x: pos.x - currentShape.get("left"),
y: pos.y - currentShape.get("top")
});
currentShape.set({
points: points
});
canvas.renderAll();
}
});
fabric.util.addListener(window, 'keyup', function(e) {
if (e.keyCode === 27) {
if (mode === 'edit' || mode === 'add') {
mode = 'normal';
var points = currentShape.get("points");
points.pop();
currentShape.set({
points: points
});
var oldC = currentShape.getCenterPoint();
currentShape._calcDimensions();
var xx = currentShape.get("minX");
var yy = currentShape.get("minY");
currentShape.set({
left: currentShape.get('left') + xx,
top: currentShape.get('top') + yy
});
var pCenter = currentShape.getCenterPoint();
var adjPoints = currentShape.get("points").map(function(p) {
return {
x: p.x - pCenter.x + oldC.x,
y: p.y - pCenter.y + oldC.y
};
});
currentShape.set({
points: adjPoints,
selectable: true
});
canvas.setActiveObject(currentShape);
currentShape.setCoords();
canvas.renderAll();
} else {
mode = 'add';
}
currentShape = null;
}
})canvas {
border: 1px solid #999;
}
img {
display: none;
}<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
复制和粘贴
function fixPoly(poly) {
var oldC = poly.getCenterPoint();
poly._calcDimensions();
poly.set({
left: poly.get('left') + poly.get("minX"),
top: poly.get('top') + poly.get("minY")
});
var pCenter = poly.getCenterPoint();
poly.get("points").forEach((p) => {
p.x -= pCenter.x - oldC.x;
p.y -= pCenter.y - oldC.y
});
poly.setCoords();
};发布于 2016-08-19 06:48:44
这个问题有两种解决方案,它们非常非常简单:
解决方案#1
只需从画布中删除多边形并重新创建它(使用新的fabric.Polygon(...))每增加一分!
优点和缺点:是的,你会得到一个稍微差一点的性能,因为画布将被重新渲染两次,但你可以省去每次重新计算坐标的麻烦。
您可以在下面的代码片段或this forked fiddle中查看此解决方案。
/**
* fabric.js template for bug reports
*
* Please update the name of the jsfiddle (see Fiddle Options).
* This templates uses latest dev verison of fabric.js (https://rawgithub.com/kangax/fabric.js/master/dist/all.js).
*/
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
// Do some initializing stuff
fabric.Object.prototype.set({
transparentCorners: false,
cornerColor: 'rgba(102,153,255,0.5)',
cornerSize: 12,
padding: 7
});
// ADD YOUR CODE HERE
var mode = "add",
currentShape;
canvas.observe("mouse:move", function(event) {
var pos = canvas.getPointer(event.e);
if (mode === "edit" && currentShape) {
var points = currentShape.get("points");
points[points.length - 1].x = pos.x;
points[points.length - 1].y = pos.y;
currentShape.set({
points: points
});
canvas.renderAll();
}
});
canvas.observe("mouse:down", function(event) {
var pos = canvas.getPointer(event.e);
if (mode === "add") {
var polygon = new fabric.Polygon([{
x: pos.x,
y: pos.y
}, {
x: pos.x + 0.5,
y: pos.y + 0.5
}], {
fill: 'blue',
opacity: 0.5,
selectable: false
});
currentShape = polygon;
canvas.add(currentShape);
mode = "edit";
} else if (mode === "edit" && currentShape && currentShape.type === "polygon") {
var points = currentShape.get("points");
points.push({
x: pos.x,
y: pos.y
});
canvas.remove(currentShape);
currentShape = new fabric.Polygon(points, {
fill: 'blue',
opacity: 0.5,
selectable: false
});
canvas.add(currentShape);
}
});
fabric.util.addListener(window, 'keyup', function(e) {
if (e.keyCode === 27) {
if (mode === 'edit' || mode === 'add') {
mode = 'normal';
var points = currentShape.get('points');
canvas.remove(currentShape);
currentShape = new fabric.Polygon(points, {
fill: 'blue',
opacity: 0.5,
selectable: true
});
canvas.add(currentShape);
} else {
mode = 'add';
}
currentShape = null;
}
})canvas {
border: 1px solid #999;
}
img {
display: none;
}<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
解决方案#2
每次重新计算多边形的尺寸,就像在polygon类的构造函数中一样。代码摘录:
currentShape.set({
points: points
});
currentShape._calcDimensions();
currentShape.set({
left: currentShape.minX,
top: currentShape.minY,
pathOffset: {
x: currentShape.minX + currentShape.width / 2,
y: currentShape.minY + currentShape.height / 2
}
});
currentShape.setCoords();
canvas.renderAll();优点和缺点:更好的性能(在负载很重的画布上可能很明显),但你会有更多的代码,因为你必须将它添加到两个处理程序中。
您可以在下面的代码片段或this forked fiddle中查看这一点。
/**
* fabric.js template for bug reports
*
* Please update the name of the jsfiddle (see Fiddle Options).
* This templates uses latest dev verison of fabric.js (https://rawgithub.com/kangax/fabric.js/master/dist/all.js).
*/
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
// Do some initializing stuff
fabric.Object.prototype.set({
transparentCorners: false,
cornerColor: 'rgba(102,153,255,0.5)',
cornerSize: 12,
padding: 7
});
// ADD YOUR CODE HERE
var mode = "add",
currentShape;
canvas.observe("mouse:move", function(event) {
var pos = canvas.getPointer(event.e);
if (mode === "edit" && currentShape) {
var points = currentShape.get("points");
points[points.length - 1].x = pos.x;
points[points.length - 1].y = pos.y;
currentShape.set({
points: points
});
canvas.renderAll();
}
});
canvas.observe("mouse:down", function(event) {
var pos = canvas.getPointer(event.e);
if (mode === "add") {
var polygon = new fabric.Polygon([{
x: pos.x,
y: pos.y
}, {
x: pos.x + 0.5,
y: pos.y + 0.5
}], {
fill: 'blue',
opacity: 0.5,
selectable: false
});
currentShape = polygon;
canvas.add(currentShape);
mode = "edit";
} else if (mode === "edit" && currentShape && currentShape.type === "polygon") {
var points = currentShape.get("points");
points.push({
x: pos.x,
y: pos.y
});
currentShape.set({
points: points
});
currentShape._calcDimensions();
currentShape.set({
left: currentShape.minX,
top: currentShape.minY,
pathOffset: {
x: currentShape.minX + currentShape.width / 2,
y: currentShape.minY + currentShape.height / 2
}
});
currentShape.setCoords();
canvas.renderAll();
}
});
fabric.util.addListener(window, 'keyup', function(e) {
if (e.keyCode === 27) {
if (mode === 'edit' || mode === 'add') {
mode = 'normal';
currentShape.set({
selectable: true
});
currentShape._calcDimensions();
currentShape.set({
left: currentShape.minX,
top: currentShape.minY,
pathOffset: {
x: currentShape.minX + currentShape.width / 2,
y: currentShape.minY + currentShape.height / 2
}
});
currentShape.setCoords();
canvas.renderAll();
} else {
mode = 'add';
}
currentShape = null;
}
})canvas {
border: 1px solid #999;
}
img {
display: none;
}<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
发布于 2020-03-03 17:46:24
对于那些正在寻找使用fabricjs 3的更新答案的人。
FabricJS有很多更改,其中之一是对_calcDimmensions方法的更改。它不再在对象上存储值minX和minY。相反,它会返回一个包含以下内容的对象:
{
left: minX,
top: minY,
width: width,
height: height
}因此,考虑到这一点,解决方案更新为以下内容:
currentShape.set({
points: points
});
var calcDim = currentShape._calcDimensions();
currentShape.width = calcDim.width;
currentShape.height = calcDim.height;
currentShape.set({
left: calcDim.left,
top: calcdim.top,
pathOffset: {
x: calcDim.left + currentShape.width / 2,
y: calcDim.top + currentShape.height / 2
}
});
currentShape.setCoords();
canvas.renderAll();https://stackoverflow.com/questions/26219238
复制相似问题