首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Fabric.js:如何用鼠标绘制多边形

Fabric.js:如何用鼠标绘制多边形
EN

Stack Overflow用户
提问于 2014-10-06 23:09:04
回答 4查看 7.8K关注 0票数 5

我想在Fabric.js中绘制一个带有鼠标交互的fabric.Polygon。我做了一个小的jsfiddle来显示我的实际状态:http://jsfiddle.net/Kienz/ujefxh7w/

按ESC键后,将取消“交互式绘制模式”,并最终确定多边形。但是现在多边形的位置是错误的(控件是正确的)。

有谁有主意吗?

EN

回答 4

Stack Overflow用户

发布于 2016-02-02 21:06:36

问题定义

当多边形被添加为静态对象时(从这个意义上说,点不会被修改),它的left, right, minX, minY, width, height和中心点可以根据提供的点来计算。

但是当一个人想要动态创建一个多边形时,问题就出现了。在调用setCoords()之后,它会计算移动框的位置,但它是基于有关宽度和高度的错误信息。

记住,,当创建1点多边形时,它的宽度和高度等于0,左上角等于1点。

解决方案

首先,修改大小

_calcDimensions()计算多边形的widthheightminXminYminXminY是所有点的最小值。

这会告诉我们一些点被放置在旧中心上方的左侧和顶部有多远。我们应该使用此信息将旧的左侧移动到正确的位置。新的左上角点是由minXminY信息转换的旧中心点。

代码语言:javascript
复制
var oldC = polygon.getCenterPoint();
polygon._calcDimensions();
polygon.set({
  left: oldC.x + polygon.get('minX'),
  top: oldC.y + polygon.get('minY')
});

固定点

在中心移动了一些向量v (由于更改了leftrightwidthheight属性的结果)之后。我们需要通过v的反向更新所有的点。

代码语言:javascript
复制
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/

代码语言:javascript
复制
/**
 * 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;
      }
    })
代码语言:javascript
复制
canvas {
  border: 1px solid #999;
}

img {
  display: none;
}
代码语言:javascript
复制
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

复制和粘贴

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2016-08-19 06:48:44

这个问题有两种解决方案,它们非常非常简单:

解决方案#1

只需从画布中删除多边形并重新创建它(使用新的fabric.Polygon(...))每增加一分!

优点和缺点:是的,你会得到一个稍微差一点的性能,因为画布将被重新渲染两次,但你可以省去每次重新计算坐标的麻烦。

您可以在下面的代码片段或this forked fiddle中查看此解决方案。

代码语言:javascript
复制
/**
 * 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;
  }
})
代码语言:javascript
复制
canvas {
  border: 1px solid #999;
}
img {
  display: none;
}
代码语言:javascript
复制
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

解决方案#2

每次重新计算多边形的尺寸,就像在polygon类的构造函数中一样。代码摘录:

代码语言:javascript
复制
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中查看这一点。

代码语言:javascript
复制
/**
 * 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;
  }
})
代码语言:javascript
复制
canvas {
  border: 1px solid #999;
}
img {
  display: none;
}
代码语言:javascript
复制
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

票数 1
EN

Stack Overflow用户

发布于 2020-03-03 17:46:24

对于那些正在寻找使用fabricjs 3的更新答案的人。

FabricJS有很多更改,其中之一是对_calcDimmensions方法的更改。它不再在对象上存储值minX和minY。相反,它会返回一个包含以下内容的对象:

代码语言:javascript
复制
  {
    left: minX,
    top: minY,
    width: width,
    height: height
  }

因此,考虑到这一点,解决方案更新为以下内容:

代码语言:javascript
复制
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();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26219238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档