Сохраните dataImage canvas перед рендерингом - PullRequest
0 голосов
/ 10 февраля 2020

Я занимаюсь разработкой проекта, в котором у меня есть два полотна. Первый холст поддерживает масштабирование и рисование, второй холст является дубликатом первого холста, который должен отображать общий вид первого холста без масштабирования. Я уже спрашивал об этом здесь , и это то, что у меня есть сейчас. В этом решении я копирую состояние холста перед масштабированием, используя функцию toDataURL. Но это очень медленный путь, и у меня плохая производительность. Я попытался использовать getImageData, а получил не то, что ожидал . Также я пытался играть с функциями after:render и before:render, но безрезультатно, пожалуйста, посмотрите this . Что я делаю не так?

1 Ответ

1 голос
/ 10 февраля 2020

1) Fabri c. js увеличивает холст, если devicePixelRatio равен> 1. Вот почему вы получаете увеличенное изображение, когда рисуете пиксели, полученные из getImageData(). Лучше было бы использовать drawImage() и указать ширину / высоту назначения, чтобы ваш браузер решал, следует ли уменьшать или увеличивать эти пиксели в соответствии с размерами исходного изображения.

2) Вы Право насчет сброса преобразования окна просмотра, но этого недостаточно - вам следует применить это новое преобразование и каким-то образом перерисовать холст. Это то, что делает Fabri c. js, когда вы вызываете toDataURL() - он вызывает toCanvasElement(), который создает копию canvas и отображает все объекты на нем. Ваша реализация должна отражать эту логику c.

В приведенном ниже решении представлен метод drawOnCopyCanvas(), который является исправленной версией toCanvasElement(). Вместо этого он не использует промежуточный холст и dr aws непосредственно на поставляемом холсте.

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);
  });
}

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