回答編集履歴

1

代替案についてのサンプルコードを追加

2017/12/05 02:11

投稿

defghi1977
defghi1977

スコア4756

test CHANGED
@@ -19,3 +19,141 @@
19
19
  ```
20
20
 
21
21
  のようなコードを要するようです.
22
+
23
+
24
+
25
+ ---
26
+
27
+ 以下は代替案としてのHTML2canvasを用いない方法です.
28
+
29
+
30
+
31
+ HTMLツリーをSVGの`foreignObject`要素の配下とすることでHTMLグラフィックを**画像として**扱うことが可能になります. この画像を`canvas`要素に転写すればよいのです. なお動作条件として以下があります.
32
+
33
+
34
+
35
+ - 動作環境がFireFox/Chromeであること(Safari/Edgeでは動作しない)
36
+
37
+ - スクリーンに表示されている内容とは異なる結果となる(異なるスタイルを指定できる)
38
+
39
+ - Chromeでは余りに巨大なHTMLを描く際にクラッシュする可能性がある
40
+
41
+ (かつてはSVGコードとして1MB程度の制限が有った)
42
+
43
+
44
+
45
+ 以下実際のコードです.
46
+
47
+
48
+
49
+ ```HTML
50
+
51
+ <table id="drawtarget">
52
+
53
+ <caption>キャプション</caption>
54
+
55
+ <thead>
56
+
57
+ <tr><th>ヘッダー</th><th>ヘッダー</th><th>ヘッダー</th></tr>
58
+
59
+ </thead>
60
+
61
+ <tbody>
62
+
63
+ <tr><td>セル</td><td>セル</td><td>セル</td></tr>
64
+
65
+ <tr><td>セル</td><td>セル</td><td>セル</td></tr>
66
+
67
+ <tr><td>セル</td><td>セル</td><td>セル</td></tr>
68
+
69
+ <tr><td>セル</td><td>セル</td><td>セル</td></tr>
70
+
71
+ </tbody>
72
+
73
+ </table>
74
+
75
+ <img id="out"/>
76
+
77
+ ```
78
+
79
+ ```JavaScript
80
+
81
+ //HTML構造をcanvas要素に描く
82
+
83
+ //(1)描画対象のノードを取得する
84
+
85
+ const table = document.querySelector("#drawtarget");
86
+
87
+ //(2)描画対象のouterHTMLで得られたHTMLコードをSVGのforeignObject要素配下となるように埋め込む
88
+
89
+ //SVGのサイズを変更することで出力サイズを調整できる
90
+
91
+ const svgsrc = `<svg xmlns="http://www.w3.org/2000/svg" width="500px" height="500px">
92
+
93
+ <style><![CDATA[
94
+
95
+ /*ここにキャプチャ時のスタイルを指定する*/
96
+
97
+ table{
98
+
99
+ border-collapse: collapse;
100
+
101
+ }
102
+
103
+ table, th, td{
104
+
105
+ border: 1px black solid;
106
+
107
+ }
108
+
109
+ ]]></style>
110
+
111
+ <foreignObject width="100%" height="100%">
112
+
113
+ <html xmlns="http://www.w3.org/1999/xhtml">
114
+
115
+ ${table.outerHTML}
116
+
117
+ </html>
118
+
119
+ </foreignObject>
120
+
121
+ </svg>`;
122
+
123
+ //(3)得られたSVGのソースコードをdataURIスキーム形式のURL文字列に変換する
124
+
125
+ const url = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgsrc);
126
+
127
+ //(4)上記URLをImageオブジェクトに設定し, 読み込まれたらcanvas要素に転写する
128
+
129
+ const image = new Image();
130
+
131
+ image.onload = e => {
132
+
133
+ const canvas = document.createElement("canvas");
134
+
135
+ canvas.width = image.naturalWidth;
136
+
137
+ canvas.height = image.naturalHeight;
138
+
139
+ const ctx = canvas.getContext("2d");
140
+
141
+ ctx.drawImage(image, 0, 0);
142
+
143
+ out.src = canvas.toDataURL();//Safari/Edgeはここでエラーとなる
144
+
145
+ };
146
+
147
+ image.src = url;
148
+
149
+ ```
150
+
151
+ この作業を行う過程で, SVGに埋め込んだHTML構造は元のHTML文書との関係が絶たれるため(`style`属性で埋め込まれたもの以外の)**全てのスタイルが未設定**となります. そのため, SVGコードの内部に`style`要素を用意しcanvas転写専用のスタイルを埋め込むことになります.
152
+
153
+ NOTE:動作原理(SVGをimg要素で読み込む動作)上,SVGは**外部リソース(CSS, 背景画像, WEBフォント等)を参照することが出来ません**ので, 必要に応じdataURIスキームに変換した上で全てを`style`要素に埋め込むようにします.
154
+
155
+
156
+
157
+ 以下実行結果です
158
+
159
+ ![スクリプトの実行結果画像](7eeb95d18c75540b93bc02f6041c4bb6.png)