网站地图    收藏   

主页 > canvas引擎 > Fabricjs >

fabric.js·自定义控件,多边形

来源:未知    时间:2023-09-01 09:50 作者:小飞侠 阅读:

[导读] 此演示演示如何使用控件 api 修改多边形的形状。 这可能很难掌握,因为它需要了解内部多边形逻辑,以及锚点和变换。 在此演示中,我们将缩放和平移应用于画布,以确保代码对于许...

image.png


思路讲解:


此演示演示如何使用控件 api 修改多边形的形状。


这可能很难掌握,因为它需要了解内部多边形逻辑,以及锚点和变换。


在此演示中,我们将缩放和平移应用于画布,以确保代码对于许多应用程序来说足够通用。出于同样的原因,多边形被赋予较大的笔触宽度。


我们有一个触发 edit mode .当我们进入编辑模式时,我们为每个多边形点创建一个新控件。对于每个控件,我们附加一个调用 pointIndex 的属性,以记住控件绑定到哪个点。


这些控件使用自己的自定义位置处理程序: polygonPositionHandler 。此函数查看控件的 pointIndex,并返回该特定点的当前画布位置。通过这种方式执行交互和渲染。


为了使每个控件修改其关联点,我们需要编写一个自定义操作处理程序。


更改点位置实际上很容易: fabricObject.points[index].x = number; fabricObject.points[index].y = number; 困难的部分是确保对象在更改尺寸时保持在正确的位置。


为此,我们需要一个锚点。我们选择将多边形位置固定为点数组中不是被拖动的点的任何点的实际位置。


选择点后,我们计算其实际绝对位置:


var absolutePoint = fabric.util.transformPoint({
    x: (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x),
    y: (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y),
}, fabricObject.calcTransformMatrix());



修改多边形后,我们将使用此绝对位置。


然后,我们将拖动的点与新点交换,并重新计算多边形的宽度、高度和路径偏移量(基本上是重新初始化其尺寸)。


现在,为了保持其位置稳定,我们想知道表示锚点的点,以及它现在相对于多边形大小的位置。


var newX = (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) / fabricObject.width,
    newY = (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) / fabricObject.height;



newX 和 newY 变量现在表示点位置,对于 X 和 Y,范围为 -0.5 到 0.5。Fabric 支持范围从 0 到 1 的对象的数字原点。这让我们使用相对位置作为原点来翻译我们之前发现的旧绝对点。


fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5);


代码如下:

...html...
  <div class="controls">
    <p>
      <button id="edit" onclick="Edit()">Toggle editing polygon</button>
    </p>
  </div>
  <canvas id="c" width="500" height="400" style="border:1px solid #ccc"></canvas>
...html...
...css...
  .controls {
    display: inline-block;
  }
...css...
...js...
  var canvas = this.__canvas = new fabric.Canvas('c');
  // create a polygon object
  var points = [{
    x: 3, y: 4
  }, {
    x: 16, y: 3
  }, {
    x: 30, y: 5
  },  {
    x: 25, y: 55
  }, {
    x: 19, y: 44
  }, {
    x: 15, y: 30
  }, {
    x: 15, y: 55
  }, {
    x: 9, y: 55
  }, {
    x: 6, y: 53
  }, {
    x: -2, y: 55
  }, {
    x: -4, y: 40
  }, {
    x: 0, y: 20
  }]
  var polygon = new fabric.Polygon(points, {
    left: 100,
    top: 50,
    fill: '#D81B60',
    strokeWidth: 4,
    stroke: 'green',
    scaleX: 4,
    scaleY: 4,
    objectCaching: false,
    transparentCorners: false,
    cornerColor: 'blue',
  });
  canvas.viewportTransform = [0.7, 0, 0, 0.7, -50, 50];
  canvas.add(polygon);

  // define a function that can locate the controls.
  // this function will be used both for drawing and for interaction.
  function polygonPositionHandler(dim, finalMatrix, fabricObject) {
    var x = (fabricObject.points[this.pointIndex].x - fabricObject.pathOffset.x),
        y = (fabricObject.points[this.pointIndex].y - fabricObject.pathOffset.y);
    return fabric.util.transformPoint(
      { x: x, y: y },
      fabric.util.multiplyTransformMatrices(
        fabricObject.canvas.viewportTransform,
        fabricObject.calcTransformMatrix()
      )
    );
  }

  function getObjectSizeWithStroke(object) {
    var stroke = new fabric.Point(
      object.strokeUniform ? 1 / object.scaleX : 1, 
      object.strokeUniform ? 1 / object.scaleY : 1
    ).multiply(object.strokeWidth);
    return new fabric.Point(object.width + stroke.x, object.height + stroke.y);
  }

  // define a function that will define what the control does
  // this function will be called on every mouse move after a control has been
  // clicked and is being dragged.
  // The function receive as argument the mouse event, the current trasnform object
  // and the current position in canvas coordinate
  // transform.target is a reference to the current object being transformed,
  function actionHandler(eventData, transform, x, y) {
    var polygon = transform.target,
        currentControl = polygon.controls[polygon.__corner],
        mouseLocalPosition = polygon.toLocalPoint(new fabric.Point(x, y), 'center', 'center'),
        polygonBaseSize = getObjectSizeWithStroke(polygon),
        size = polygon._getTransformedDimensions(0, 0),
        finalPointPosition = {
          x: mouseLocalPosition.x * polygonBaseSize.x / size.x + polygon.pathOffset.x,
          y: mouseLocalPosition.y * polygonBaseSize.y / size.y + polygon.pathOffset.y
        };
    polygon.points[currentControl.pointIndex] = finalPointPosition;
    return true;
  }

  // define a function that can keep the polygon in the same position when we change its
  // width/height/top/left.
  function anchorWrapper(anchorIndex, fn) {
    return function(eventData, transform, x, y) {
      var fabricObject = transform.target,
          absolutePoint = fabric.util.transformPoint({
              x: (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x),
              y: (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y),
          }, fabricObject.calcTransformMatrix()),
          actionPerformed = fn(eventData, transform, x, y),
          newDim = fabricObject._setPositionDimensions({}),
          polygonBaseSize = getObjectSizeWithStroke(fabricObject),
          newX = (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) / polygonBaseSize.x,
          newY = (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) / polygonBaseSize.y;
      fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5);
      return actionPerformed;
    }
  }

  function Edit() {
    // clone what are you copying since you
    // may want copy and paste on different moment.
    // and you do not want the changes happened
    // later to reflect on the copy.
    var poly = canvas.getObjects()[0];
    canvas.setActiveObject(poly);
    poly.edit = !poly.edit;
    if (poly.edit) {
      var lastControl = poly.points.length - 1;
      poly.cornerStyle = 'circle';
      poly.cornerColor = 'rgba(0,0,255,0.5)';
      poly.controls = poly.points.reduce(function(acc, point, index) {
        acc['p' + index] = new fabric.Control({
          positionHandler: polygonPositionHandler,
          actionHandler: anchorWrapper(index > 0 ? index - 1 : lastControl, actionHandler),
          actionName: 'modifyPolygon',
          pointIndex: index
        });
        return acc;
      }, { });
    } else {
      poly.cornerColor = 'blue';
      poly.cornerStyle = 'rect';
      poly.controls = fabric.Object.prototype.controls;
    }
    poly.hasBorders = !poly.edit;
    canvas.requestRenderAll();
  }

...js...


以上就是fabric.js·自定义控件,多边形全部内容,感谢大家支持自学php网。

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论