FabricJS - 拖动时用人工制品渲染箭头的提示

时间:2018-02-01 16:30:10

标签: fabricjs

当使用箭头绘制线条到FabricJS画布上时,箭头的尖端在拖动画布时会呈现奇怪的效果。一旦mouse:up事件触发,箭头将保持与在画布上放置人工制品时保持一致。

Example of artefacts

运行下面的代码段,然后单击并拖动将绘制箭头。

const LineWithArrow = fabric.util.createClass(fabric.Line, {
  type: 'line_with_arrow',

  initialize(element, options) {
    options || (options = {});
    this.callSuper('initialize', element, options);

    // Set default options
    this.set({
      hasBorders: false,
      hasControls: false,
    });
  },

  _render(ctx) {
    this.callSuper('_render', ctx);
    ctx.save();
    const xDiff = this.x2 - this.x1;
    const yDiff = this.y2 - this.y1;
    const angle = Math.atan2(yDiff, xDiff);
    ctx.translate((this.x2 - this.x1) / 2, (this.y2 - this.y1) / 2);
    ctx.rotate(angle);
    ctx.beginPath();
    // Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
    ctx.moveTo(5, 0);
    ctx.lineTo(-5, 5);
    ctx.lineTo(-5, -5);
    ctx.closePath();
    ctx.fillStyle = this.stroke;
    ctx.fill();
    ctx.restore();
  },
});

const drawLineWithArrow = (points) => (
  new LineWithArrow(points, {
    strokeWidth: 2,
    stroke: 'black',
  })
)

const selectLine = (points) => {
  return drawLineWithArrow(points);
}

let line;
let isDown;

const fabricCanvas = new fabric.Canvas('canvas', {
  height: 500,
  width: 500,
  targetFindTolerance: 15,
  selection: false,
  preserveObjectStacking: true,
  perPixelTargetFind: true, // To prevent the line having a selectable rectangle drawn around it and instead only have it selectable on direct click
});

fabricCanvas.on('mouse:down', (options) => {
  isDown = true;
  const pointer = fabricCanvas.getPointer(options.e);
  const points = [pointer.x, pointer.y, pointer.x, pointer.y];
  line = selectLine(points);
  fabricCanvas
    .add(line)
    .setActiveObject(line)
    .renderAll();
});

fabricCanvas.on('mouse:move', (options) => {
  if (!isDown) return;
  const pointer = fabricCanvas.getPointer(options.e);
  line.set({ x2: pointer.x, y2: pointer.y });
  fabricCanvas.renderAll();
});

fabricCanvas.on('mouse:up', () => {
  isDown = false;
  line.setCoords();
  fabricCanvas.setActiveObject(line).renderAll();
});
canvas {
  border: 1px solid grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.min.js"></script>
<canvas id="canvas"></canvas>

1 个答案:

答案 0 :(得分:3)

我认为是缓存清除的工件,因为你修改了ab对象的大小,但是Fabric不知道它。

你的箭头比线条大,但是面料却不知道它。

覆盖此功能并添加更多空间:

objectCaching: false

这只是为了解释。在您的特定情况下,您可以考虑在mousedown / mousemove上禁用objectCaching,并在mouseUp上重新启用它,或者将其禁用,将const LineWithArrow = fabric.util.createClass(fabric.Line, { type: 'line_with_arrow', hasBorders: false, hasControls: false, _getCacheCanvasDimensions() { var dim = this.callSuper('_getCacheCanvasDimensions'); dim.width += 15; // found by trial and error dim.height += 15; // found by trial and error return dim; }, _render(ctx) { this.callSuper('_render', ctx); ctx.save(); const xDiff = this.x2 - this.x1; const yDiff = this.y2 - this.y1; const angle = Math.atan2(yDiff, xDiff); ctx.translate((this.x2 - this.x1) / 2, (this.y2 - this.y1) / 2); ctx.rotate(angle); ctx.beginPath(); // Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0) ctx.moveTo(5, 0); ctx.lineTo(-5, 5); ctx.lineTo(-5, -5); ctx.closePath(); ctx.fillStyle = this.stroke; ctx.fill(); ctx.restore(); }, }); const drawLineWithArrow = (points) => ( new LineWithArrow(points, { strokeWidth: 2, stroke: 'black', }) ) const selectLine = (points) => { return drawLineWithArrow(points); } let line; let isDown; const fabricCanvas = new fabric.Canvas('canvas', { height: 500, width: 500, targetFindTolerance: 15, selection: false, preserveObjectStacking: true, perPixelTargetFind: true, // To prevent the line having a selectable rectangle drawn around it and instead only have it selectable on direct click }); fabricCanvas.on('mouse:down', (options) => { isDown = true; const pointer = fabricCanvas.getPointer(options.e); const points = [pointer.x, pointer.y, pointer.x, pointer.y]; line = selectLine(points); fabricCanvas .add(line) .setActiveObject(line) .renderAll(); }); fabricCanvas.on('mouse:move', (options) => { if (!isDown) return; const pointer = fabricCanvas.getPointer(options.e); line.set({ x2: pointer.x, y2: pointer.y }); fabricCanvas.renderAll(); }); fabricCanvas.on('mouse:up', () => { isDown = false; line.setCoords(); fabricCanvas.setActiveObject(line).renderAll(); });添加到箭头类。

&#13;
&#13;
canvas {
  border: 1px solid grey;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.min.js"></script>
<canvas id="canvas"></canvas>
&#13;
datetime
&#13;
&#13;
&#13;