「canvas」タグについて(HTML)
久しぶりにWebまわりを実装してみたら
HTML5から利用できるようになったという「canvas」タグに
大苦戦。(解決まで3日かかった…)
<やりたかったこと>
ウィンドウサイズに合わせて、画像の縮小・拡大を
縦横比率を保ったままページに表示したい。
<実装方針>
①HTMLに「canvas」タグを埋込む。
②onLoad( )処理で、ウィンドウサイズに合わせて「canvas」の
height / widthを設定する。
③表示したい画像(image)の縦横サイズを計算して、
「canvas」上に出力する。(drawImageメソッド)
④「canvas」上に出力した画像を画像のソース(image.src)に
設定する。(toDataURLメソッド)
が、③と④で問題発生…
③drawImage( )で出力した画像が思ったように画面表示されない
【原因】
出力したい画像サイズよりも大きいcanvasサイズで
drawImage( )メソッドを実行していたため
余白がやたらある画像がHTMLで表示されていて、
ずれているように見えた。
(つまり、計算ミス)
【解決策】
canvasサイズがそのままの大きさで描画出力されるため、
出力したい画像サイズ = canvasサイズ(ぴったり)
にする。
④画像を描画chromeでは、ローカル環境における
(HTML文書のURLがfile://から始まるもの)
「toDataURL( )」の実行が許可されていない。
実行するとセキュリティエラーが発生する。
え…!ここまで来て、そんなオチ!
【理由】
悪意あるスクリプトをローカル環境で実行することによる
情報漏えい(ローカル画像のパスを直接指定し, canvas要素を使って
URL文字列化して外部に送信する)を防ぐため
…言われてみればそうだよね…(脱力)
【解決策】
ggってみると、
・chrome起動時にオプションコマンドを付加する
(--allow-file-access-from-files)
・Webサーバを利用する(ローカル環境での操作をやめる)
とのことだったので、前者を採用。
コマンドを追加した状態のショートカットを用意する。
これに加えて、chrome終了時にタスクが残らないように
設定画面での「Google Chromeを閉じた際にバックグラウンド
アプリの処理を続行する」をOFFにした。
(オプションコマンドが付いた/付いていない状態でのタスクを
引きずらないようにする)
【出典】
https://teratail.com/questions/61458
【以下、実際のソース(HTML)】
<!DOCTYPE html>
<html language="ja" class="MR0003" id="MR0003">
<!-- 文字コードセット -->
<meta charset="utf-8">
<!-- ヘッダ情報 -->
<head>
<title>
My Resume
</title>
<!-- CSS情報 -->
<link rel="stylesheet" type="text/css" href="MR000x_style.css"/>
</head>
<body class="top_page_right">
<div class="top_page_right" id="div_top_page_right">
<img id="picture_1" src="MR0003_1.JPG" title="picture_1" alt="picture_1"><img id="picture_2" src="MR0003_2.JPG" title="picture_2" alt="picture_2">
<canvas class="canvas_area" id="canvas_area_1"></canvas>
<canvas class="canvas_area" id="canvas_area_2"></canvas>
</div>
<!-- JS情報 -->
<script type="text/javascript" src="MR0003_script.js"></script>
</body>
</html>
【以下、実際のソース(Javascript)】
window.onload = function(){
var arrImg = new Array(2);
/*srcの設定
読み込む画像のsrcを配列形式で定義した変数に記載する
画像ファイル名、imageタグのID、canvasタグのIDには1から始まる連番をつける。
*/
arrImg[0]="MR0003_1.JPG";
arrImg[1]="MR0003_2.JPG";
var image = new Image();
for(var i = 0; i < arrImg.length; i++){
//srcの取得
image.src = arrImg[i];
//canvasのid情報の取得
var canvas = document.getElementById("canvas_area_" + String(i+1));
//2Dグラフィック描画を指定
var ctx = canvas.getContext("2d");
//CANVASの大きさを設定
canvas.width = document.getElementById("MR0003").clientWidth / arrImg.length;
canvas.height = document.getElementById("MR0003").clientHeight;
//CANVASの(0,0)~(MAX横幅,MAX縦幅)の範囲をクリアする
ctx.clearRect(0, 0, canvas.width, canvas.height);
//描画横幅を設定
var lngWidth;
if(image.width > canvas.width){
lngWidth = canvas.width;
} else{
lngWidth = image.width;
// CANVASの方が大きい場合、toDataURL()時にそのままのサイズで出力してしまうため
// image.widthの大きさに縮小する
canvas.width = image.width;
};
//描画縦幅を設定
var lngHeight;
if(image.height > canvas.height){
lngHeight = canvas.height;
} else{
lngHeight = image.height;
// CANVASの方が大きい場合、toDataURL()時にそのままのサイズで出力してしまうため
// image.heightの大きさに縮小する
canvas.height = image.height;
};
//描画
ctx.drawImage(image, 0, 0, lngWidth , lngHeight );
//canvasの描画結果をimg要素にセット
document.getElementById("picture_" + String(i+1)).src = canvas.toDataURL();
//キャンバスを非表示にする
canvas.style.display="none";
//2枚目以降はi-1枚目のleft+i-1枚目のwidthをi枚目のleftとして設定
if(i>0){
var lngLeft;
if(document.getElementById("picture_" + String(i)).style.left == ""){
lngLeft = 0;
}else{
lngLeft = document.getElementById("picture_" + String(i)).style.left;
};
document.getElementById("picture_" + String(i+1)).style.left = String(parseInt(lngLeft) + parseInt(document.getElementById("picture_" + String(i)).width)) + "px";
};
};
//ちらつき防止のため処理完了後に表示する
document.getElementById("div_top_page_right").style.display="inline-block";
};
※注:突貫工事で作ったソースなので、細かいところは未検証