簡體   English   中英

使用 Fabric.js 更改每次縮放的畫布大小

[英]Change canvas size per zoom using Fabric.js

我正在構建一個文檔查看器,文檔的每一頁都變成了一個圖像,並且所有頁面都在一個 html 畫布上一個接一個地組合在一起。

我正在使用 FabricJS 用圖像填充畫布。 當我縮放畫布內的圖像時,它們會完美地放大和縮小,但畫布本身保持相同的大小。

我希望畫布大小發生變化,以便滾動條在需要時隱藏和顯示。

這是構建和填充畫布的代碼:

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

似乎可以完成這項工作,但我未能找到更改寬度的公式。 無論我嘗試過什么 當我在幾次單擊后縮小頁面時,由於畫布寬度減少的變化太大,頁面開始被“剪切”(主要在右側)。

我想我正在尋找的是一種了解畫布內實際繪制圖像的高度和寬度的方法。

我嘗試使用 getImageData 方法和 toDataUrl 方法獲取它,但它們對我沒有好處。

謝謝你的幫助

更新額外信息:

  1. zoomToPoint - 基於所有方向的中心點對畫布數據進行縮放。 在我的代碼中,我將 middleY 設置為零,將 middleX 設置為畫布容器大小的一半,因此縮放將圍繞該點調整數據大小,而不會導致圖像移動的效果。
  2. 是的,我希望畫布根據縮放比例進行縮放,這樣用戶就可以在需要時滾動,或者在不需要時隱藏滾動條。
  3. 是的,畫布大小正確(+/- 2-3 像素),並且沒有進行四舍五入。

一些假設,因為我沒有足夠的信息。

  • 函數engine.canvasObject.zoomToPoint執行統一縮放
  • 在調用zoomToPoint之后,必須縮放畫布widthheight以適合其內容。
  • 當函數 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))可能會失敗,因為結果縮放為零。

注意如果縮放當前縮放非常小而新縮放很大,則畫布尺寸可能會變得太大。 為安全起見,您應該審查新的縮放值以防止可能使頁面崩潰或使其變得非常緩慢的非常大的畫布。

舍入問題

如果畫布大小四舍五入(或舍入)為整數,則隨着時間的推移,此錯誤會增加。 只有在多次縮放畫布時才會出現此問題。

為避免此錯誤,您需要有一個參考比例。 畫布在特定比例下的大小。

例如

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

這意味着在縮放 1 時畫布是 250 x 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);

因為這使用固定參考,舍入誤差不能累積。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM