canvasでWordPressサイトの背景に画像をランダムに配置する
canvas要素を使って、Webページの背景に画像をランダムに描画することができる。このサイトも背景はcanvasを使っている。
ただ、WordPressでは若干 javaScriptファイルに手直しが必要だった。
そして、モバイルビューでは表示領域が PCとは違うので、カンバスが下部まで表示されず、これも javaScriptファイルを修正した。
コレで縦持ち(portrait)では対応できたが、横持ち(landscape)では結局うまく行かず、canvasを非表示しにして body要素に背景画像を貼ることで対応。
今回はそのあたりの試行錯誤をメモしておきます。
スポンサーリンク
canvasでサイトの背景に画像をランダムに描く
これは姉妹サイト「ほんっとにはじめてのHTML5」で詳しく説明しているのでこちらを参照に。
ほんっとにはじめてのHTML5:[69-12] canvasをサイトの背景に使おう
今ご覧のサイトは、上記サイトのサンプル3「canvasに「画像(PNG)」をランダムに描いて背景にする」のソースをほぼコピペして、画像だけ差し替えて backgroud を作っている。
このサイトで使用している画像は、このようなPNGファイル。
画像サイズは、大きいものは 640 x 640px、小さいものは 345 x 345px。
サイズがバラバラでも、それに対応したjavaScriptを書くので大丈夫。
javaScriptソースはこんなかんじ
javaScriptで canvas要素を生成して、上記の画像を配置している。
javaScriptソースはこちら。
function Draw() { var bodyNode = document.getElementsByTagName('body').item(0); var containerNode = document.getElementById('contents-wrap'); var newCanvas = document.createElement('canvas'); var newDiv = document.createElement('div'); newDiv.id = 'wrapper'; newDiv.appendChild(newCanvas); bodyNode.insertBefore(newDiv, containerNode); $('canvas').attr({ height: $('#wrapper').height() }); $('canvas').attr({ width: $('#wrapper').width() }); var ctx = newCanvas.getContext('2d'); var cHall = newCanvas.width; var cW = newCanvas.width, cH = cHall - 120; var grad = ctx.createLinearGradient(0, 0, cW, cH); grad.addColorStop(0.3, '#0e195b'); grad.addColorStop(0.48, '#2d1497'); ctx.fillStyle = grad; ctx.fillRect(0, 0, cW, cH); ctx.globalAlpha = 0.4; var bgCvs1 = new Image(); bgCvs1.src = "http://ex.com/image/fthr1.png"; bgCvs1.onload = function () { for (var i = 0; i < 3; i++) { var x = Math.floor(Math.random() * cW - 320); var y = Math.floor(Math.random() * cH - 320); var angle = Math.floor(Math.random() * 360); var rad = angle * Math.PI / 180; if (angle > 360) angle = 0; var cx = x + bgCvs1.width / 2; var cy = y + bgCvs1.height / 2; ctx.setTransform(Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), cx - cx * Math.cos(rad) + cy * Math.sin(rad), cy - cx * Math.sin(rad) - cy * Math.cos(rad)); ctx.drawImage(bgCvs1, x, y); } }; //このあと var bgCvs2 = new Image(); といった調子で2つ目以降の画像を指定
canvas要素だけではウィンドウサイズを取得できないので、div#wrapper を生成し(5,6行目)、その中に canvas要素を埋め込む(7行目)。このdiv#wrapper を指定したノード(#contents-wrap)の前に挿入(8行目)。
div#wrapper はCSSでウィンドウいっぱいのサイズに指定し、canvas にはこの親divのウィンドウサイズを与えている(9〜14行目)。
HTMLとCSSはこのように
HTMLはこんな状態。
div#wrapper や canvas要素は、javaScriptで生成するのでココ↓には書かない。
<body> <!-- <div id="wrapper"><canvas></canvas></div> これがjsで生成される--> <div id="contents-wrap"> <!-- ここにすべてのコンテンツ --> </div><!--contents-wrap END--> </body>
javaScriptで生成した div#wrapper(canvas内包)の上に、コンテンツ用の div#contents-wrap が乗っかるようにするために、CSSはこのようになっている。
html, body {width:100%;} body {position:relative;} body #wrapper{/*for canvas*/ width: 100%; height:100%; min-height:100%; overflow: hidden; position: fixed;} body #contents-wrap{ position:absolute; top:0; right:0; bottom:0; left:0; width: 100%; height:100%; min-height:100%;}
#contents-wrap を親(body)に対して「position:absolute」にして、上に乗せている。
親(body)の中にある div#wrapper(canvas内包)の上に乗っかるわけで。
WordPressでは canvasで使う画像は「絶対パス」で
これでページの背景全面にcanvasで画像をランダム配置することができた。
しかし、ローカルサーバから 今ご覧のサーバにインポートしたとたん、背景の画像が消えた!
でも、canvasで描いている背景のグラデーションは効いてる。
javaScriptファイル内での画像ファイルの呼び出しは「../image/fthr1.png」と「相対パス」で書いていたが、これか?
案の定、絶対パスに書き直したら描画された。
というわけで、WordPressでは画像のパスは相対パスじゃダメ。絶対パスでね。
var bgCvs1 = new Image(); bgCvs1.src = "http://ex.com/image/fthr1.png";
スマートフォンで canvasの下部が切れる件の対処方法
PCビューでは canvasによる背景がちゃんと描画されていたが、スマホで見ると、このように下部が切れてしまう。
スマホなどのデバイスは、表示領域がウィンドウサイズとは異なるのでこうなる。
そこで、canvas用の jsを編集。
ウィンドウサイズ取得の部分で、高さから何ピクセルか引いてみることに。いろいろ試して 120px あたりにしてみた。
var ctx = newCanvas.getContext('2d'); var cHall = newCanvas.width; var cW = newCanvas.width, cH = cHall - 120;
「var cHall」は実際のカンバスの高さ(div#wrapperから取得した高さ)。ここから120px引いたものを描画時のカンバスの高さに(19行目)。これはこのあとの描画で使う。
本来のウィンドウサイズからある程度小さくしておけば(ここでは120px)、カンバスは最下部まで達する前に終わり、bodyのbackgroudに指定した色になじむだろう…という発想で。
それから、canvasのバックに斜めのグラデーションも指定しているのだが、これを端から端までグラデにしていたことも、途中で切れてみっともない原因の1つになっていた。
黒に近い紺色(#0e195b)から紺色(#2d1497)までのグラデです。bodyのbackgroudは紺色(#2d1497)を指定。
そこで、グラデも半分あたりで終わるように修正した。
var grad = ctx.createLinearGradient(0, 0, cW, cH); grad.addColorStop(0.3, '#0e195b'); grad.addColorStop(0.48, '#2d1497'); //当初は「grad.addColorStop(0.85, '#2d1497');」にしていた。
これにより、スマホの portrait(縦持ち)だけは、このように自然になじむようになった。
landscape だけメディアクエリで画像背景に差し替え
portrait では、canvasでの背景の表示は上手くいったのだが、landscape(横持ち)では相変わらず下部の背景の欠けが起こる。
そこで、メディアクエリを使って、横持ち(landscape)の場合だけ bodyに画像で背景をつけることにした。まずは別途画像を 1335 x 620px で用意。
メディアクエリは下記のとおり。
@media only screen and (max-width: 736px) and (orientation:landscape) { body #wrapper{width:0; height:0;display:none;} body {background:#2d1497 url(../images/bg_mobile2.jpg) no-repeat top left fixed; background-size:contain;} }
ブレイクポイントは、iPhone6 plus の Landscape にした(1行目)。
注目は2行目。カンバスを無効にするには、div#wrapper の高さと幅を0にすること。単に「display:none;」としただけでは無効にならなかった。
これで、横持ちのときだけは、body の backgroud が効くようになったが、iPhone6では、3行目の最後の「fixed(background-attachment: fixed;)」は効かない…。これも iOSでのバグらしい…。
まあ、背景のことだし、途中で切れて不細工なときと比べれば、これは許容範囲かな。
ということで、ここは一旦終了。
画像背景の密集度がデバイスによって違う件
本ブログサイトを、PCとスマホなどで見比べてくださった殊勝な方はお気づきだと思うが、デバイスによって画像の密集度が違うという問題点もある。
今のcanvas用のjavaScriptでは、PCビューでも、スマホビューでも、同じ個数の画像がレンダリングされる。
表示面積が違うので、当然、面積の小さいスマホでは画像が超過密ぎみになる。
画像が密集すると背景が明るくなるので、若干文字が読みづらいところも。
これは、メディアクエリを使って、スマホやタブレットの場合は canvas を使わず、素直に画像で背景を描画したほうが良いのだろうか。
だが、デバイスによってjavaScriptを切り替える方法もありそうだ。
それを探し、いずれ対処してみようと思う。(そのための実験サイトだから)
そんなわけで今のところ放置します。
Leave a Comment