Визуализируйте штрих bru sh на нижнем холсте, прежде чем поднять мышь - PullRequest
1 голос
/ 13 апреля 2020

Я пытаюсь отрисовать рисунок немедленно на нижнем холсте перед событием мыши.

Я нашел несколько тем, описывающих это, но я не понимаю, как я могу использовать его в своем проекте.

Эмуляция свободного рисунка с помощью fabri cjs

Ткани - Как отобразить содержимое без рисунка перед наведением мыши

Как чтобы программно свободно рисовать, используя Fabri c js?

Мой кодовый блок пример

var canvas = this.__canvas = new fabric.Canvas('c', {
  isDrawingMode: true
});
  
canvas {
  border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js"></script>   
<canvas id="c" width="300" height="300"></canvas>

1 Ответ

2 голосов
/ 26 апреля 2020

Я думаю, что вы попали в проблему XY. В комментарии объясняется, что вам нужно, и вы спрашиваете, как сделать что-то, что, по вашему мнению, является способом обойти это.

Вы настраиваете конкретное приложение, которое клонирует холст в состоянии c представление на другом холсте, при каждом событии after: render.

Теперь свободный рисунок bru sh не вызывает событие after: render, и даже если это произошло, bru sh не отображается на вашем холст перед мышью: событие up.

Таким образом, чтобы решить вашу проблему, вы должны поместить bru sh на нижний холст, чтобы существующий код нашел его.

Это очень трудно сделать, потому что это значит возиться с внутренним логикой c библиотеки. Почему вы можете просто копировать верхний холст каждый раз, когда добавляется новый сегмент bru sh? это, очевидно, позволит вам достичь цели.

Мой ответ и фрагмент не идеальны и не учитывают прозрачные кисти, которые много раз просто копируют себя.

Другое решение будет иметь второй холст stati c поверх первого, для обработки этих средних этапов.

var c1 = document.getElementById("scale");
var c2 = document.getElementById("static");

var ctx1 = c1.getContext("2d");
var ctx2 = c2.getContext("2d");

var canvas = this.__canvas = new fabric.Canvas(c1, {
  isDrawingMode: true,
  renderOnAddRemove: false 
});
  
canvas.add(new fabric.Rect({ top: 100, left: 100, width: 50, height: 50, fill: '#f55' }),
            new fabric.Circle({ top: 140, left: 130, radius: 75, fill: 'green' }),
            new fabric.Triangle({ top: 100, left: 110, width: 100, height: 100, fill: 'blue' }))


fabric.Image.fromURL(
  "https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
  img => {
    img.scaleToWidth(canvas.width);
    canvas.setBackgroundImage(img);
    canvas.requestRenderAll();
  },
  {
    crossOrigin: "Annoymous"
  }
);


canvas.on('mouse:wheel', function(opt) {
  var delta = opt.e.deltaY;
  var pointer = canvas.getPointer(opt.e);
  var zoom = canvas.getZoom();
  zoom += delta / 500;
  if (zoom > 10) zoom = 10;
  if (zoom < 0.5) zoom = 0.5;
  canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
  this.requestRenderAll();
  opt.e.preventDefault();
  opt.e.stopPropagation();
});


fabric.StaticCanvas.prototype.drawCopyOnCanvas = function(canvasEl) {
  // save values
  var scaledWidth = this.width,
      scaledHeight = this.height,
      vp = this.viewportTransform,
      originalInteractive = this.interactive,
      newVp = [1, 0, 0, 1, 0, 0],
      originalRetina = this.enableRetinaScaling,
      originalContextTop = this.contextTop;
  // reset
  this.contextTop = null;
  this.enableRetinaScaling = false;
  this.interactive = false;
  this.viewportTransform = newVp;
  this.calcViewportBoundaries();
  // draw on copy
  this.renderCanvas(canvasEl.getContext('2d'), this._objects);
  // restore values
  this.viewportTransform = vp;
  this.calcViewportBoundaries();
  this.interactive = originalInteractive;
  this.enableRetinaScaling = originalRetina;
  this.contextTop = originalContextTop;
}

function afterRender() {
  // remove 'after:render' listener as canvas.toCanvasElement()
  // calls renderCanvas(), which results in an infinite recursion
  canvas.off('after:render', afterRender);
  // draw c1 contents on c2
  canvas.drawCopyOnCanvas(c2);
  
  setTimeout(() => {
    // re-attach the listener in the next event loop
    canvas.on('after:render', afterRender);
  });
}

function copyThePencil() {
  if (this._isCurrentlyDrawing) {
    ctx2.save();
    var m = fabric.util.invertTransform(this.viewportTransform);
    ctx2.transform.apply(ctx2, m);
    ctx2.drawImage(this.upperCanvasEl, 0, 0, this.upperCanvasEl.width / this.getRetinaScaling(), this.upperCanvasEl.height / this.getRetinaScaling())
    ctx2.restore();
  }
}

canvas.on('after:render', afterRender);

canvas.on('mouse:move', copyThePencil);





















var $ = function(id){return document.getElementById(id)};

  fabric.Object.prototype.transparentCorners = false;

  var drawingModeEl = $('drawing-mode'),
      drawingOptionsEl = $('drawing-mode-options'),
      drawingColorEl = $('drawing-color'),
      drawingShadowColorEl = $('drawing-shadow-color'),
      drawingLineWidthEl = $('drawing-line-width'),
      drawingShadowWidth = $('drawing-shadow-width'),
      drawingShadowOffset = $('drawing-shadow-offset'),
      clearEl = $('clear-canvas');

  clearEl.onclick = function() { canvas.clear() };

  drawingModeEl.onclick = function() {
    canvas.isDrawingMode = !canvas.isDrawingMode;
    if (canvas.isDrawingMode) {
      drawingModeEl.innerHTML = 'Cancel drawing mode';
      drawingOptionsEl.style.display = '';
    }
    else {
      drawingModeEl.innerHTML = 'Enter drawing mode';
      drawingOptionsEl.style.display = 'none';
    }
  };

  if (fabric.PatternBrush) {
    var vLinePatternBrush = new fabric.PatternBrush(canvas);
    vLinePatternBrush.getPatternSrc = function() {

      var patternCanvas = fabric.document.createElement('canvas');
      patternCanvas.width = patternCanvas.height = 10;
      var ctx = patternCanvas.getContext('2d');

      ctx.strokeStyle = this.color;
      ctx.lineWidth = 5;
      ctx.beginPath();
      ctx.moveTo(0, 5);
      ctx.lineTo(10, 5);
      ctx.closePath();
      ctx.stroke();

      return patternCanvas;
    };

    var hLinePatternBrush = new fabric.PatternBrush(canvas);
    hLinePatternBrush.getPatternSrc = function() {

      var patternCanvas = fabric.document.createElement('canvas');
      patternCanvas.width = patternCanvas.height = 10;
      var ctx = patternCanvas.getContext('2d');

      ctx.strokeStyle = this.color;
      ctx.lineWidth = 5;
      ctx.beginPath();
      ctx.moveTo(5, 0);
      ctx.lineTo(5, 10);
      ctx.closePath();
      ctx.stroke();

      return patternCanvas;
    };

    var squarePatternBrush = new fabric.PatternBrush(canvas);
    squarePatternBrush.getPatternSrc = function() {

      var squareWidth = 10, squareDistance = 2;

      var patternCanvas = fabric.document.createElement('canvas');
      patternCanvas.width = patternCanvas.height = squareWidth + squareDistance;
      var ctx = patternCanvas.getContext('2d');

      ctx.fillStyle = this.color;
      ctx.fillRect(0, 0, squareWidth, squareWidth);

      return patternCanvas;
    };

    var diamondPatternBrush = new fabric.PatternBrush(canvas);
    diamondPatternBrush.getPatternSrc = function() {

      var squareWidth = 10, squareDistance = 5;
      var patternCanvas = fabric.document.createElement('canvas');
      var rect = new fabric.Rect({
        width: squareWidth,
        height: squareWidth,
        angle: 45,
        fill: this.color
      });

      var canvasWidth = rect.getBoundingRect().width;

      patternCanvas.width = patternCanvas.height = canvasWidth + squareDistance;
      rect.set({ left: canvasWidth / 2, top: canvasWidth / 2 });

      var ctx = patternCanvas.getContext('2d');
      rect.render(ctx);

      return patternCanvas;
    };

    var img = new Image();
    img.src = 'https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg';

    var texturePatternBrush = new fabric.PatternBrush(canvas);
    texturePatternBrush.source = img;
  }

  $('drawing-mode-selector').onchange = function() {

    if (this.value === 'hline') {
      canvas.freeDrawingBrush = vLinePatternBrush;
    }
    else if (this.value === 'vline') {
      canvas.freeDrawingBrush = hLinePatternBrush;
    }
    else if (this.value === 'square') {
      canvas.freeDrawingBrush = squarePatternBrush;
    }
    else if (this.value === 'diamond') {
      canvas.freeDrawingBrush = diamondPatternBrush;
    }
    else if (this.value === 'texture') {
      canvas.freeDrawingBrush = texturePatternBrush;
    }
    else {
      canvas.freeDrawingBrush = new fabric[this.value + 'Brush'](canvas);
    }

    if (canvas.freeDrawingBrush) {
      canvas.freeDrawingBrush.color = drawingColorEl.value;
      canvas.freeDrawingBrush.width = parseInt(drawingLineWidthEl.value, 10) || 1;
      canvas.freeDrawingBrush.shadow = new fabric.Shadow({
        blur: parseInt(drawingShadowWidth.value, 10) || 0,
        offsetX: 0,
        offsetY: 0,
        affectStroke: true,
        color: drawingShadowColorEl.value,
      });
    }
  };

  drawingColorEl.onchange = function() {
    canvas.freeDrawingBrush.color = this.value;
  };
  drawingShadowColorEl.onchange = function() {
    canvas.freeDrawingBrush.shadow.color = this.value;
  };
  drawingLineWidthEl.onchange = function() {
    canvas.freeDrawingBrush.width = parseInt(this.value, 10) || 1;
    this.previousSibling.innerHTML = this.value;
  };
  drawingShadowWidth.onchange = function() {
    canvas.freeDrawingBrush.shadow.blur = parseInt(this.value, 10) || 0;
    this.previousSibling.innerHTML = this.value;
  };
  drawingShadowOffset.onchange = function() {
    canvas.freeDrawingBrush.shadow.offsetX = parseInt(this.value, 10) || 0;
    canvas.freeDrawingBrush.shadow.offsetY = parseInt(this.value, 10) || 0;
    this.previousSibling.innerHTML = this.value;
  };

  if (canvas.freeDrawingBrush) {
    canvas.freeDrawingBrush.color = drawingColorEl.value;
    canvas.freeDrawingBrush.width = parseInt(drawingLineWidthEl.value, 10) || 1;
    canvas.freeDrawingBrush.shadow = new fabric.Shadow({
      blur: parseInt(drawingShadowWidth.value, 10) || 0,
      offsetX: 0,
      offsetY: 0,
      affectStroke: true,
      color: drawingShadowColorEl.value,
    });
  }
canvas {
  border: 1px solid black;
}
#static {
  position: relative;
  top: -300px;
  left: 330px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.js"></script>
This is interactive canvas
<canvas id="scale" width="300" height="300"></canvas>
<canvas id="static" width="300" height="300"></canvas>
<div style="display: inline-block; margin: 0px 0px 0px 210px">
  <button id="drawing-mode" class="btn btn-info">Cancel drawing mode</button><br>
  <button id="clear-canvas" class="btn btn-info">Clear</button><br>

  <div id="drawing-mode-options">
    <label for="drawing-mode-selector">Mode:</label>
    <select id="drawing-mode-selector">
      <option>Pencil</option>
      <option>Circle</option>
      <option>Spray</option>
      <option>Pattern</option>

      <option>hline</option>
      <option>vline</option>
      <option>square</option>
      <option>diamond</option>
      <option>texture</option>
    </select><br>

    <label for="drawing-line-width">Line width:</label>
    <span class="info">30</span><input type="range" value="30" min="0" max="150" id="drawing-line-width"><br>

    <label for="drawing-color">Line color:</label>
    <input type="color" value="#005E7A" id="drawing-color"><br>

    <label for="drawing-shadow-color">Shadow color:</label>
    <input type="color" value="#005E7A" id="drawing-shadow-color"><br>

    <label for="drawing-shadow-width">Shadow width:</label>
    <span class="info">0</span><input type="range" value="0" min="0" max="50" id="drawing-shadow-width"><br>

    <label for="drawing-shadow-offset">Shadow offset:</label>
    <span class="info">0</span><input type="range" value="0" min="0" max="50" id="drawing-shadow-offset"><br>
  </div>
</div>
...