お詫びと訂正(2016年12月5日追記)
記事初出時に React v15.3.2 では foreignObject
要素がサポートされてない、と記しましたがこちらは誤りでした。
React v15.0.0 のリリースノートにてSVGの全ての要素をサポートした、とあるのですが、このタイミングではまだ公式ドキュメントが更新されていませんでした。
また v15.2.x では一部の属性が使用不可と判定されてしまって、コンポーネントのレンダリング自体は意図通りになるものの使用には不安を感じさせる挙動となっていました。
React V15.2.x ではuse
要素やforeignObject
要素の子要素に必要なxmlns:*
属性が使用不可であると警告される
しかし、最近になって公式ドキュメントのリライトが始まって、もともと存在した「Reactで使用できる要素と属性の一覧」ページが思いっきり削除されました(当該コミット)。
そこで気になって現時点で最新バージョンである v15.4.0 で試したところ、use
要素やforeignObject
要素が前述の警告もなく普通に使用できたので自分の勘違いに気付いた次第です。
手元でバージョンをさかのぼって試したところ、v15.3.0 以上ならば問題なく動作するようです。
したがって記事初出時の記載は完全に誤りです。
ここに訂正しお詫びいたします。
大変失礼しました。
このスライドについて
2016年10月19日(水)
SVGおじさん 松田さん 主催
「まぼろしのSVG勉強会 その2」 発表資料
いまさらなネタかもしれないけど許せ
※ 「まぼろし」というのは弊社のことです
これはHTMLから作った画像です
しかもフロントだけで実現可能!
デモ作った
git clone git@github.com:haribote/react-dom-imager-demo.git
cd react-dom-imager-demo && npm install
npm start
いきなり種明かし
HTMLを画像化する手順
- 画像化したいHTMLを作る
- (1)のHTMLをSVGの
foreignObject
要素で囲む - (2)のSVGを
canvas
要素に描画する
MDNに全部書いてある
DOM オブジェクトを Canvas に描画する - HTML | MDN
コード例
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 1280" width="960" height="1280">
<style>
h1 {
color: red;
}
</style>
<g>
<foreignObject x="0" y="0" width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml">
<h1>Hello, world!</h1>
</div>
</foreignObject>
</g>
</svg>
SVGをCanvasに描画する
// canvas要素とコンテキスト、SVGを読み込むimage要素を用意
const canvasEl = document.getElementById('canvas');
const context = canvasEl.getContext('2d');
const imageEl = new Image();
// SVGコードをBlobにしてURLを発行する
const staticSvgBlob = new Blob(['<svg xmlns...'], { type: 'image/svg+xml' });
const url = URL.createObjectURL(staticSvgBlob);
// SVGが読み込まれたらcanvas要素に描画する
imageEl.onload = () => {
context.clearRect(0, 0, canvasEl.width, canvasEl.height);
context.drawImage(imageEl, 0, 0);
URL.revokeObjectURL(url); // URL解放
};
// CORS設定をしてSVGを画像として読み込む
imageEl.crossOrigin = 'Anonymous';
imageEl.src = url;
最重要ポイント
Canvasに描画するSVGは完全にスタンドアロンでなくてはならない
つまり描画に必要な情報はすべてぶっ込むべし!
BlobにするときのMIME
new Blob(['<svg xmlns...'], { type: 'image/svg+xml' });
文字コードは不要
MDNに書かれている通りに
image/svg+xml;charset=utf-8
とすると一部のブラウザでSVGがぶっ壊れる
(なんでだろう?)
ルートのSVGに必要な属性
xmlns
viewBox
width
height
CSSの埋め込み
style
要素にCSSを文字列展開して直接ぶっ込む!
<style>
h1 {
color: red;
}
</style>
画像の埋め込み
Base64エンコードしてDataURLでぶっ込む!
<img src="data:image/png;base64,iVBOR..." width="400" height="382" alt="" />
フォントとか
画像同様にDataURLにする必要がある
- データの再頒布にあたるので著作権とか注意
- アイコンはフォントじゃなくてSVGでおk
残念なお知らせ
- IEってなんですか?
-
foreignObject
要素の含まれたSVGをCanvasに描き出すとtainted
とされてtoDataURL
などが使えなくなる -
ReactだとforeignObject
要素がサポートされてないからdangerouslySetInnerHTML
でぶっ込まざるをえないv15.3.2 時点将来的にはサポートされるはず
※1ページ目の訂正をお読みください。