web-dev-qa-db-ja.com

fabric.jsは、画面に合わせてキャンバスのサイズを変更します

私は現在、ionicとcordovaを使用してモバイルデバイス(AndroidとiPhone)でアプリケーションを開発しています。写真を編集したいのですが。私はそれを行うためにfabric.jsライブラリを使用します。 Fabric.jsは、画像やその他のアイテムをキャンバスに変換します。次に、キャンバスに画像(ステッカー)を追加し、画像(dataURL)としてエクスポートします。したがって、キャンバスのサイズは品質要因であるため非常に重要です(小さなキャンバスに基づいて画像をエクスポートすると、品質が低下します)。キャンバスのサイズは約607 * 1080ピクセルです(写真を撮ったデバイスによって異なります)。品質を落とさずに画面に合わせたい(以下で説明するように、品質を落とさずにキャンバスのサイズを変更することはできません)。

私は3つのアイデアを試しましたが、誰もうまくいきませんでした。

  1. キャンバスのサイズを変更:品質が失われます(エクスポートされた画像はキャンバスサイズになります)
  2. Adapt viewport:cordovaはモバイルデバイスのビューポートを変更することを許可していません。回避策はありますが、デザインが壊れます(非常に小さいナビゲーションバー、小さいメニューなど)。
  3. CSS3ズームプロパティを使用:デスクトップではチャームのように機能しますが、モバイルデバイスではイベントマッピングの問題があります(iOSでは試していませんが、問題はAndroidWebviewで発生しました)。イベントマッピングはズームされません。キャンバスはズームアウトされていますが、キャンバス要素を操作することはできません。キャンバス要素(ステッカー)がx:100 y:100にある場合、ズームプロパティを0.5に設定すると、要素は(50,50)に配置され、(100,100)には配置されなくなります。 Androidウェブビューのズームプロパティに応じてイベントマッピングを修正する方法はありますか?

それを行う他の方法があるかどうかはわかりませんが、私はこの問題に3日間立ち往生しており、フォーラム、fabricjs doc、およびgoogleに多くの時間を費やしており、実用的な解決策が見つかりません。私を助けることができる何か他のもの。

編集:以下に2つの実用的な解決策があります。cssでそれを行う方法を確認するために私の答えを確認してください。

9
X4V1

1. cssを使用して、キャンバスの適切な解像度を設定します。

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

canvas.width = 800;
canvas.height = 600;

css:

/* media query 1 */
    #canvas{
       width: 400px;
       height: 250px; 
    }

/* media query 2 */
#canvas{
       width: 200px;
       height: 120px; 
    }

長所:

すべての解像度は、キャンバスの幅と高さ(800/600)で示されます。

短所:

正方形のキャンバスのアスペクト比(1:1)、cssの高さに基づいて計算する必要がある奇妙なアスペクト比の出力に関する問題にうまく適合します。

original height / original width * new width = new height;

これはCSSの私のリーグから外れています...

少し前にfabric.jsgitの問題のセクションを読んでください。ここでは、処理が遅く、オブジェクトのトランザクションが正しくないため、テクニック(cssサイズ変更)は推奨されていません。これは変更される可能性があります。テストしたところ、オブジェクトのサイズが正しくありません(ランダムな色のピクセル、トランザクションの影はキャンバスに残ります、言い換えれば混乱)

2.送信する必要があるときに、キャンバスのサイズを正確なサイズ(解像度)に変更してから、画像を生成します

ウィンドウのサイズ変更(レスポンシブキャンバス)でキャンバスのサイズを変更するだけです。正確な寸法にエクスポートする必要がある場合は、キャンバスを正確なピクセル解像度にサイズ変更するか、別のキャンバスを非表示にする必要があります。

この例は、1:1の比率のキャンバス用です(キャンバスと内部のオブジェクトにアスペクト比を適用する必要があります)。

$(window).resize(function (){
 if (canvas.width != $(".container").width()) {
            var scaleMultiplier = $(".container").width() / canvas.width;
            var objects = canvas.getObjects();
            for (var i in objects) {
                objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
                objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
                objects[i].left = objects[i].left * scaleMultiplier;
                objects[i].top = objects[i].top * scaleMultiplier;
                objects[i].setCoords();
            }

            canvas.setWidth(canvas.getWidth() * scaleMultiplier);
            canvas.setHeight(canvas.getHeight() * scaleMultiplier);
            canvas.renderAll();
            canvas.calcOffset();
        }
});

エクスポートキャンバスデータの送信時に、キャンバスのサイズを希望の解像度に変更します。

function GetCanvasAtResoution(newWidth)
  {
    if (canvas.width != newWidth) {
                var scaleMultiplier = newWidth / canvas.width;
                var objects = canvas.getObjects();
                for (var i in objects) {
                    objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
                    objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
                    objects[i].left = objects[i].left * scaleMultiplier;
                    objects[i].top = objects[i].top * scaleMultiplier;
                    objects[i].setCoords();
                }

                canvas.setWidth(canvas.getWidth() * scaleMultiplier);
                canvas.setHeight(canvas.getHeight() * scaleMultiplier);
                canvas.renderAll();
                canvas.calcOffset();
            }
     return canvas.toDataURL();
   }
   );

1:1とは異なる比率では大した問題ではなく、高さのスケールマルチプレイヤーも計算する必要があります。比率はわかりやすいです: http://andrew.hedges.name/experiments/aspect_ratio/

12
SilentTremor

キャンバスをコピーせずにそれを行うためのトリックを見つけました。このソリューションはcssズームプロパティに非常に近いですが、イベントは正しく処理されます。

これは、キャンバスを半分のサイズで表示する例です。

-webkit-transform : scale(0.5);
-webkit-transform-Origin : 0 0;
3
X4V1