我想在Fabric.js中使用鼠标交互绘制fabric.Polygon
。
我做了一个小jsfiddle来显示我的实际状态:http://jsfiddle.net/Kienz/ujefxh7w/
按下ESC键后,"交互式绘图模式"取消并完成多边形。但现在多边形的位置是错误的(控件是正确的)。
有人有想法吗?
答案 0 :(得分:1)
当多边形作为静态对象添加时(从某种意义上说,这些点不会被修改),它可以根据提供的点计算left, right, minX, minY, width, height
和中心点。
但是当想要动态创建多边形时,就会出现问题。
在调用setCoords()
后,它会计算移动框的位置,但它会根据有关宽度和高度的错误信息来计算。
记住,创建1磅多边形时,宽度和高度等于0,左上角等于该点。
_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>
&#13;
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();
};
答案 1 :(得分:1)
这个问题有两个解决方案,非常简单:
只需从画布中删除多边形并在每个添加的点上重新创建它(使用新的fabric.Polygon(...))!
优点&amp;缺点:是的,你会得到稍差的表现,因为画布会被重新渲染两次,但你每次都会省去重新计算坐标的麻烦。
您可以在下面的代码段或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;
}
})
&#13;
canvas {
border: 1px solid #999;
}
img {
display: none;
}
&#13;
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
&#13;
每次重新计算多边形尺寸,就像在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();
优点&amp;缺点:更好的性能(在负载很重的画布上可能会很明显),但是你必须有更多的代码才能将它们添加到两个处理程序中。
您可以在下面的代码段或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;
}
})
&#13;
canvas {
border: 1px solid #999;
}
img {
display: none;
}
&#13;
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
&#13;
答案 2 :(得分:0)
对于那些寻求使用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();
答案 3 :(得分:-1)
你可以解决“跳跃”问题。通过在初始化时设置originX和originY点来实现多边形。
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,
originX: pos.x,
originY: pos.y
});
见这里: http://jsfiddle.net/ujefxh7w/48/
我不知道选择框移动的原因。
编辑:发现重新加载画布对象修复了选择框
序列化并加载序列化对象可以解决问题:
var json = JSON.stringify(canvas);
canvas.loadFromJSON(json, function() {
canvas.renderAll();
});