FabricJS-移动路径时,“路径"对象不会更新 [英] FabricJS - When moving a path the 'path' object doesn't update

查看:167
本文介绍了FabricJS-移动路径时,“路径"对象不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以前,我在 Line 类/fabricjs.com/"rel =" noreferrer> FabricJS 允许用户在画布上绘制线条.现在,我需要实现曲线,但是由于Fabric的Line类不支持二次曲线,因此我重新编写了代码,以使用路径类.

Previously I was using the Line class in FabricJS to allow users to draw lines on a canvas. I now need to implement curved lines, but as Fabric's Line class doesn't support quadratic curves I have re-written my code to use the Path class instead.

以前,画一条线时,如果在画布上移动该线,x1,y1,x2和y2值将自动更新,这使得更新我创建的起点和终点锚点的位置变得容易(只是可以使用与在Adobe Illustrator中操纵锚点相同的方式操纵画布上的矩形.

Previously when drawing a Line the x1, y1, x2, and y2 values would update automatically if the line was moved on the canvas which made it easy to update the position of the start and end anchor points that I had created (just rectangles on the canvas which can be manipulated in the same way you would manipulate anchor points in Adobe Illustrator).

Path类不使用x1,y1,x2或y2,而是传递一个字符串,该字符串将转换为数组,例如M 100 100, Q 200 200 500 500.然后,这些值可用作path对象的一部分(100 100是路径起点的x和y,200 200是曲线,而500 500是终点),这意味着我可以获得起点和结束点的方式与我对Line类所做的方式类似.

The Path class doesn't use x1, y1, x2 or y2, instead you pass a string which is converted into an array e.g. M 100 100, Q 200 200 500 500. These values are then available as part of a path object (with 100 100 being the x and y of the start point of the path, 200 200 being the curve and 500 500 being the end) which means I can get the start and end points in a similar way that I did with the Line class.

问题在于,移动线本身时,路径对象不会更新. lefttop值会更新,但是我发现很难基于此手动更新路径值.我觉得我可能缺少一些明显的东西(例如,自动更新路径对象或获得增量/差异的功能,我可以用它来手动重新定位对象上的锚点:移动功能).

The issue is that the path object doesn't update when the line itself is moved. The left and top values update but I'm finding it difficult to manually update the path values based on this. I feel like I may be missing something obvious (e.g. the ability to auto-update the path object or get a delta/difference that I can use to manually reposition the anchors on the object:moving function).

下面的摘录摘自Fabric网站上的二次曲线演示.如果您拖动实际线(而不是锚点),您会看到锚点仍保持在原处.

The snippet below is taken from the quadratic curve demo on Fabric's website. If you move drag the actual line (not the anchor points) you can see that the anchor points remain where they are.

(function() {
  var canvas = this.__canvas = new fabric.Canvas('c', {
    height: 563,
    width: 1000,
  });
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

  canvas.on({
    'object:selected': onObjectSelected,
    'object:moving': onObjectMoving,
    'before:selection:cleared': onBeforeSelectionCleared
  });

  (function drawQuadratic() {

    var line = new fabric.Path('M 100 100, Q 200 200 200 200', { fill: '', stroke: 'black', objectCaching: false });
    
    console.log(line);
    
    console.log(line);

    line.selectable = true;
    canvas.add(line);

    var p1 = makeCurvePoint(200, 200, null, line, null)
    p1.name = "p1";
    canvas.add(p1);

    var p0 = makeCurveCircle(100, 100, line, p1, null);
    p0.name = "p0";
    canvas.add(p0);

    var p2 = makeCurveCircle(300, 100, null, p1, line);
    p2.name = "p2";
    canvas.add(p2);

  })();

  function makeCurveCircle(left, top, line1, line2, line3) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 5,
      radius: 12,
      fill: '#fff',
      stroke: '#666'
    });

    c.hasBorders = c.hasControls = false;

    c.line1 = line1;
    c.line2 = line2;
    c.line3 = line3;

    return c;
  }

  function makeCurvePoint(left, top, line1, line2, line3) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 8,
      radius: 14,
      fill: '#fff',
      stroke: '#666'
    });

    c.hasBorders = c.hasControls = false;

    c.line1 = line1;
    c.line2 = line2;
    c.line3 = line3;

    return c;
  }

  function onObjectSelected(e) {
    var activeObject = e.target;

    if (activeObject.name == "p0" || activeObject.name == "p2") {
      activeObject.line2.animate('opacity', '1', {
        duration: 200,
        onChange: canvas.renderAll.bind(canvas),
      });
      activeObject.line2.selectable = true;
    }
  }

  function onBeforeSelectionCleared(e) {
    var activeObject = e.target;
    if (activeObject.name == "p0" || activeObject.name == "p2") {
      activeObject.line2.animate('opacity', '0', {
        duration: 200,
        onChange: canvas.renderAll.bind(canvas),
      });
      activeObject.line2.selectable = false;
    }
    else if (activeObject.name == "p1") {
      activeObject.animate('opacity', '0', {
        duration: 200,
        onChange: canvas.renderAll.bind(canvas),
      });
      activeObject.selectable = false;
    }
  }

  function onObjectMoving(e) {
    if (e.target.name == "p0" || e.target.name == "p2") {
      var p = e.target;

      if (p.line1) {
        p.line1.path[0][1] = p.left;
        p.line1.path[0][2] = p.top;
      }
      else if (p.line3) {
        p.line3.path[1][3] = p.left;
        p.line3.path[1][4] = p.top;
      }
    }
    else if (e.target.name == "p1") {
      var p = e.target;

      if (p.line2) {
        p.line2.path[1][1] = p.left;
        p.line2.path[1][2] = p.top;
      }
    }
    else if (e.target.name == "p0" || e.target.name == "p2") {
      var p = e.target;

      p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top });
      p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top });
      p.line3 && p.line3.set({ 'x1': p.left, 'y1': p.top });
      p.line4 && p.line4.set({ 'x1': p.left, 'y1': p.top });
    }
  }
})();

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.min.js"></script>
<canvas id="c"></canvas>

推荐答案

这可能不是一个完美的解决方案.您需要从路径对象计算路径的终点.然后将其设置为所有三个圆圈.而且目前尚无法将路径设置为路径对象,因此您需要使用从点算出的路径来创建新的路径对象.

This might not be a perfect solution. You need to calculate your path's end points from the path object. Then set it to all three circles. And there is no way to set path to a path object for now, so you need to create a new path object with the calculated path from points.

演示

DEMO

(function() {
  var line;
  var canvas = this.__canvas = new fabric.Canvas('c', {
    selection: false,
    perPixelTargetFind: true,
    targetFindTolerance: 10
  });
  fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

  canvas.on({
    'object:moving': onObjectMoving,
    'object:modified': reinitpath
  });

  line = new fabric.Path('M 100 100 Q 200, 200, 300, 100', {
    fill: '',
    stroke: 'black',
    name: 'line',
    hasControls: false,
    hasBorders: false,
    objectCaching:false

  });
  canvas.add(line);

  var p1 = makeCurvePoint(200, 200, null, line, null)
  p1.name = "p1";
  canvas.add(p1);

  var p0 = makeCurveCircle(100, 100, line, p1, null);
  p0.name = "p0";
  canvas.add(p0);

  var p2 = makeCurveCircle(300, 100, null, p1, line);
  p2.name = "p2";
  canvas.add(p2);

  function makeCurveCircle(left, top, line1, line2, line3) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 5,
      radius: 12,
      fill: '#fff',
      stroke: '#666'
    });

    c.hasBorders = c.hasControls = false;

    c.line1 = line1;
    c.line2 = line2;
    c.line3 = line3;

    return c;
  }

  function makeCurvePoint(left, top, line1, line2, line3) {
    var c = new fabric.Circle({
      left: left,
      top: top,
      strokeWidth: 8,
      radius: 14,
      fill: '#fff',
      stroke: '#666'
    });

    c.hasBorders = c.hasControls = false;
    setLineToCircle(c, line1, line2, line3)

    return c;
  }


  function onObjectMoving(e) {
    var p = e.target;
    if (p.name == "p0" || p.name == "p2") {
      if (p.line1) {
        p.line1.path[0][1] = p.left;
        p.line1.path[0][2] = p.top;
      } else if (p.line3) {
        p.line3.path[1][3] = p.left;
        p.line3.path[1][4] = p.top;
      }
    } else if (p.name == "p1") {
      if (p.line2) {
        p.line2.path[1][1] = p.left;
        p.line2.path[1][2] = p.top;
      }
    } else if (p.name == "line") {

      var transformedPoints = getTransformedPoint(p);
      p0.left = transformedPoints[0].x;
      p0.top = transformedPoints[0].y;
      p2.left = transformedPoints[1].x;
      p2.top = transformedPoints[1].y;
      p1.left = transformedPoints[2].x;
      p1.top = transformedPoints[2].y;

    }
  }

  function reinitpath(e) {
    p0.setCoords();
    p1.setCoords();
    p2.setCoords();
    canvas.remove(line);
    var path = line.path;
    if (e.target.name == 'line') {
      var transformedPoints = getTransformedPoint(line);
      path = [
        [],
        []
      ];
      path[0][0] = 'M';
      path[0][1] = transformedPoints[0].x;
      path[0][2] = transformedPoints[0].y;
      path[1][0] = 'Q';
      path[1][1] = transformedPoints[2].x;
      path[1][2] = transformedPoints[2].y;
      path[1][3] = transformedPoints[1].x;
      path[1][4] = transformedPoints[1].y;

    };
    line = new fabric.Path(path, {
      fill: '',
      stroke: 'black',
      name: 'line',
      hasControls: false,
      hasBorders: false,
      objectCaching:false
    });
    canvas.add(line);
    setLineToCircle(p1, null, line, null)
    setLineToCircle(p0, line, p1, null);
    setLineToCircle(p2, null, p1, line);

  }

  function getTransformedPoint(p) {
    var points = [];
    var path = p.path;
    points.push(new fabric.Point(path[0][1], path[0][2]));
    points.push(new fabric.Point(path[1][3], path[1][4]));
    points.push(new fabric.Point(path[1][1], path[1][2]));
    var matrix = line.calcTransformMatrix();
    return points.map(function(p) {
        return new fabric.Point(p.x - line.minX - line.width / 2, p.y - line.minY - line.height / 2);
      })
      .map(function(p) {
        return fabric.util.transformPoint(p, matrix);
      });
  }

  function setLineToCircle(circle, line1, line2, line3) {
    circle.line1 = line1;
    circle.line2 = line2;
    circle.line3 = line3;
  }
})();

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>

<canvas id="c" width="600" height="600"></canvas>

这篇关于FabricJS-移动路径时,“路径"对象不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆