Измените размер холста на масштаб с помощью Fabri c. js - PullRequest
1 голос
/ 20 января 2020

Я создаю средство просмотра документов, и каждая страница документа превращается в изображение, и все они объединяются одна за другой на html холсте.

Я использую Fabri c JS для заполнения холста изображениями. Когда я масштабирую изображения внутри холста, они отлично увеличивают и уменьшают масштаб, но сам холст остается того же размера.

Я хочу, чтобы размер холста изменялся, поэтому полосы прокрутки будут скрываться и отображаться при необходимости.

Вот код для построения и заполнения холста:

buildCanvas: function (images, length, maximumWidth, totalHeight) {
    var height = 10;

    var canvasContainer = document.getElementById("canvasContainer");
    var c = document.createElement("canvas");
    c.width = canvasContainer.offsetWidth - 20;
    c.height = totalHeight;
    engine.canvasObject = new fabric.Canvas(c);

    for (var index = 0; index < length; index++) {
        var imgInstance = new fabric.Image(images[index], {
            left: ((canvasContainer.offsetWidth / 2) - (maximumWidth / 2)),
            top: height
        });
        var ratio = 1;
        if (images[index].width > engine.maxWidth) {
            ratio = engine.maxWidth / images[index].width;
            imgInstance.scale(ratio);
            maximumWidth = engine.maxWidth;
        }
        engine.canvasObject.add(imgInstance);
        height += (images[index].height * ratio) + 15;
    }

    canvasContainer.appendChild(c);
},

, а вот код, который я использую для увеличения и уменьшения:

zoom: function (ratio) {
    var canvasContainer = document.getElementById("canvasContainer");
    var middleX = canvasContainer.offsetWidth / 2;
    var middleY = 0;

    var zoom = engine.canvasObject.getZoom();
    engine.canvasObject.setHeight(engine.canvasObject.getHeight() * ratio);
    //engine.canvasObject.setWidth(engine.canvasObject.getWidth() * (zoom + (ratio - 1)));
    engine.canvasObject.zoomToPoint({ x: middleX, y: middleY }, zoom + (ratio - 1));
}

Изменение Высота холста, как написано в этой строке:

engine.canvasObject.setHeight(engine.canvasObject.getHeight() * ratio);

, кажется, делает эту работу, но мне не удалось найти формулу для изменения ширины. Неважно, что я пытался. Когда я уменьшал изображение после нескольких щелчков, страница начинает «обрезаться» (в основном с правой стороны) из-за слишком большого изменения ширины холста.

Я думаю, что я ищу for - это способ узнать высоту и ширину фактического нарисованного изображения внутри холста.

Я пытался получить его, используя метод getImageData, а также метод toDataUrl, но они мне не подходят.

Спасибо за любую помощь

Обновление с дополнительной информацией:

  1. zoomToPoint - выполняет масштабирование данных холста на основе центральной точки по всем направлениям. В моем коде я установил middleY равным нулю, а middleX равным половине размера контейнера Canvas, поэтому масштабирование изменит размер данных вокруг этой точки, не вызывая эффекта перемещения изображения.
  2. Да, я sh холст, который нужно масштабировать в соответствии с масштабом, чтобы пользователь мог прокручивать при необходимости, или полосы прокрутки будут скрыты, когда в этом нет необходимости.
  3. Да, холст имеет правильный размер ( +/- 2-3 пикселя), округлений нет.

1 Ответ

1 голос
/ 20 января 2020

Некоторые предположения, поскольку у меня недостаточно информации.

  • Чтобы функция engine.canvasObject.zoomToPoint выполняла равномерное увеличение
  • Чтобы холст width и height должен был масштабироваться, чтобы соответствовать его содержимому после вызова zoomToPoint.
  • То, что при вызове функции zoom холст является правильным размером для текущего увеличения. То, что нет округления, когда ширина и высота холста возвращается getHeight, и устанавливается setHeight

Тогда разрешение холста можно масштабировать до (zoom + (ratio - 1)) / zoom Например ...

const currentZoom = engine.canvasObject.getZoom();
const newZoom = currentZoom + (ratio - 1);

const height = engine.canvasObject.getHeight();
const width = engine.canvasObject.getWidth();

const zoomBy = newZoom / currentZoom;  // the amount to scale canvas 

engine.canvasObject.setHeight(height * zoomBy);
engine.canvasObject.setWidth(width * zoomBy);

engine.canvasObject.zoomToPoint({ x: middleX, y: middleY }, newZoom);

Это будет работать с увеличением или уменьшением.

Примечание Величина увеличения (zoom + (ratio - 1)) может не сработать, если zoom === -(ratio - 1) в качестве результирующего увеличения будет равно нулю.

Примечание Если текущий зум очень мал и новый зум велик, размер холста может стать слишком большим. Чтобы быть в безопасности, вы должны проверить новое значение масштабирования, чтобы предотвратить очень большие холсты, которые могут испортить sh страницу или сделать ее очень медленной.

Проблема округления

Если размер холста округлен (или слитые) в целое число, то со временем эта ошибка будет расти. Это проблема, только если вы многократно увеличиваете холст.

Чтобы избежать этой ошибки, вам нужно иметь эталонный масштаб. Размер холста в определенном c масштабе.

Например,

const canvasScaleReference = {
    zoom: 2,      // At this zoom the canvas 
    width: 500,   // is 500 
    height: 1000, // by 1000
};

Это означает, что при увеличении 1 холст будет 250 на 500

. Таким образом, функция масштабирования и изменения размера холста:

const zoom = engine.canvasObject.getZoom() + (ratio - 1);

const height = canvasScaleReference.height / canvasScaleReference.zoom * zoom;
const width = canvasScaleReference.width / canvasScaleReference.zoom * zoom;

engine.canvasObject.setHeight(height);
engine.canvasObject.setWidth(width);

engine.canvasObject.zoomToPoint({ x: middleX, y: middleY }, zoom);

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

...