見出し画像

「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";

};

※注:突貫工事で作ったソースなので、細かいところは未検証


この記事が気に入ったらサポートをしてみませんか?