まずはライブラリも何も使用しない方法。
Canvasで画像を読み込む際にdataスキーマを読み込むようにします。
(SVG要素を文字列にした後、btoa()関数でbase64 エンコードされた文字列に変換します。)
var svgStr = ‘<svg>・・・</svg>’;
var img = new Image();
img.onload = function() { ctx.drawImage(img, 0, 0);};
img.src = “data:image/svg+xml;base64,” + btoa(svgStr);
これだけで、簡単に描画することができました!
ただしこの方法はIE9以下やAndroidでは動きませんでした。どうやらbtoa関数に対応していないみたいです。
続いて、「fabric,js」というCanvasを使いやすくするためのライブラリを使ってみました。
このライブラリには、SVGとCanvasを相互に転写する機能があるのでそれを利用します。
var path = fabric.loadSVGFromString(’<SVG>・・・</SVG>’,function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
obj.set({ left: canvas2.width/2, top: canvas2.height/2 });
canvas.add(obj).renderAll();
});
こんな感じで。
結果、IE9でもAndroidでも動きました!
ただし…複数のCanvasを重ねられませんでした。
Canvasを複数重ねて、レイヤーのように使いたかったのです。
スタイルシートでCanvasの位置とz-indexを指定して最初はちゃんと重ねられていたのですが、fabricライブラリ用のオブジェクトに変換した途端、縦に並んで表示されてしまいました。
設定方法があるのかもしれませんが、調べてもわからず;
対処法は、Canvasは1つだけ使うことにして、レイヤー機能は配列で管理して配列順に描画していくような処理にするとか。(配列の中身が変わったら全て再描画し直す)
あと「Canvg」という、まさにCanvasでSVGを使用するためのライブラリがあるのでこれも試そうと思ったのですが、その前に、そもそもCanvasに描画するのはPNG保存したいためであって、プレビューで画像を重ね合わせるだけならSVGのままz-indexを指定したらいいのでは?と思いつきました。。
※話の背景:
アバター作成サイトを作ろうとしています。アイテムを選択して、プレビューで画像を重ねあわせるところをCanvasで実装しようとしていました。
プレビュー用のDIVをレイヤーの数だけ用意して、それぞれz-indexでレイヤー順を指定。
アイテムを選択したら、そのアイテムのSVG要素をDIVのinnerHTMLに流し込むだけ。
うん、これで良さそう・・・
PNG画像をダウンロードする時だけCanvasを利用する方向で行こうと思います。
コメント