本文へジャンプ

HTML5 APIの代名詞! canvasについて(基本編)

Posted by MONSTER DIVE

HTML5 API の代名詞のひとつとして注目されているcanvasについて少し考え触ってみました。

canvasとは?

canvasとはブラウザ上に画(図)を描くことのできるHTML5からサポートされたAPI。
今まではブラウザ上で画(図)を表示させるにはGIFやJPEG、PNGと言った画像フォーマットを用意する必要があったけど、このcanvasを使うことで実現可能です。

またcanvasは、FlashやJavaのプラグインを使わずに、諸々の条件やデータに応じて表示させる画(図)をインタラクティブに表示したり、アニメーションさせることが可能です。

対応ブラウザ

canvasを対応しているブラウザは以下になります。(2013.11.05 現在)

  • Google Chrome
  • Firefox
  • safari
  • IE9以上

プロジェクトによっては、まだまだIE8が必須ブラウザなので厳しいところ...。

canvasで描けるもの

canvasタグを使用して描けるものは以下のものです。

  • 図形(矩形、円、角丸、多角形)
  • パス(直線、円弧、曲線)
  • テキスト
  • 画像
  • シャドウ
  • 色(塗りつぶし、ストローク)

canvasの座標

  • 左上が(0, 0) Flashと同じ
  • 右がx座標
  • 下がy座標
  • 座標は、ピクセルの中心ではない。グリッドの境界を表す。(左上が始点)

canvasのマークアップ

canvasのマークアップは以下の感じ。

<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>canvas markup</title>
  </head>
  <body>
    <canvas width="800" height="400">
    <!-- widthが800px、heightが400pxのcanvas -->
    </canvas>
  </body>
</html>

canvasをJSでいじってみる

canvasはhtml側でマークアップしただけじゃ意味がないので、JavaScriptでゴリってみましょう。

まずはcanvasの初期設定

sampleCanvas01.coffee

    #canvas要素のノードオブジェクトを取得
    _canvas = document.querySelector('canvas')
    # 2Dコンテキストを取得
    _ctx = _canvas.getContext('2d')

canvasを使用する際には必ずおまじないに上記のコードを使用する。

短形を書いてみる

sampleCanvas02.coffee

    # まずはおまじない
    _canvas = document.querySelector('canvas')
    _ctx = _canvas.getContext('2d')

    #ここから短形を描く
    _ctx.fillStyle = '#ff00ff' #ピンク
    # x座標10、y座標20に幅200、高さ100の短形を描く
    _ctx.fillRect(10, 20, 200, 100)  # _ctx.fillRect(x, y, w, h)
    # 輪郭線の色をセットする。
    _ctx.strokeStyle = '#000' #黒  

canvasを使って何か作ってみる

細かい事を説明するのもいいのですが、何か作ってみて実際に手を使って作ってみる。
以下の条件で何か作ります。

  • ブラウザは気にしない(今回はGoogle Chrome)
  • インタラクティブなもの。
  • アニメーションさせる。
  • 仕事道具の指を負傷しているので極力タイピングしないw

この条件で考えたのが自分はMac使いなので、対応ブラウザはGoogle Chromeで。HTML5でサポートされているデバイスのマイクを使用して、マイクの音をデータとして取得してそれをcanvasで描いてみます。 * 以下ザックリですがコメントで細かく書いております。

main.coffee

    'use strict'
    class @Main
        _ctx = null
        _audio = null
        _analyser = null
        _filter = null
        _width = 0
        _height = 0

        constructor: ->
        ###
         * 初期化
         * @method init
         * @public
        ###
        init: ->
            initCSS()
            _color = getRandomRGB()
             window.onload = ->
                _canvas = document.querySelector 'canvas'
                ### canvas対応ブラウザかどうかの確認 ###
                return false if not _canvas or not _canvas.getContext
                _ctx = _canvas.getContext('2d')
                _width = _canvas.width = window.innerWidth
                _height = _canvas.height = window.innerHeight
                initAudio()
        ###
         * リセットCSSの設定
         * @private
        ###
        initCSS = ->
            _styleObjArr = []
            _styleObjArr[0] = 'body, canvas { margin: 0; padding: 0;}'
            _doc = document
            if _doc.createStyleSheet
                _sheet = _doc.createStyleSheet()
                _sheet.cssText = _styleObjArr.join('')
                _sheet = undefined
            else
                _style = _doc.createElement('style')
                _style.textContent = _styleObjArr.join('')
                _head = _doc.getElementsByTagName('head')[0]
                _head.appendChild _style
                _style = undefined
                _head = undefined
            _doc = undefined
        ###
         * webkitaudioの初期化
         * @private
        ###
        initAudio = ->
            _audio = new webkitAudioContext()
            _filter = _audio.createBiquadFilter()
            _filter.type = 0
            _filter.frequency.value = 440
            _analyser = _audio.createAnalyser()
            setupMic()
        ###
         * マイクの設定
         * @private
        ###
        setupMic = ->
            _audioParam = audio: true
            _navi = navigator
            ### マイクデバイスがあるか ###
            if _navi.webkitGetUserMedia
                _navi.webkitGetUserMedia _audioParam, success, onError
            else
                alert 'no mic, go to Amazon!'
            _navi = undefined
        ###
         * マイク接続に成功したら(WebAudioリクエストに成功したら)
         * @param stream
         * @private
        ###
        success = (stream) ->
            ### audioNodeの作成 ###
            _mediaStream = _audio.createMediaStreamSource(stream)
            ### 出力Nodeのdestinationに接続 (Flashでmic使う時にmediaに接続するのと同じ)###
            _mediaStream.connect _filter
            _filter.connect _analyser
            draw()
        ###
         * 描画
         * @private
        ###
        draw = ->
            ### 既に描画されてるかもだからclearしておく ###
            _ctx.clearRect(0, 0, _width, _height)
            _bg = _ctx.createLinearGradient(0, 0, 0, _height)
            _bg.addColorStop(0, '#000000')
            _bg.addColorStop(1, '#333333')
            _ctx.fillStyle = _bg
            _bg = undefined
            _ctx.fillRect(0, 0, _width, _height)
            ### ByteArrayの作成 ###
            _ba = new Uint8Array(_analyser.frequencyBinCount)
            ### 周波数の取得 ###
            _analyser.getByteFrequencyData(_ba)
            _ctx.fillStyle = _color
            _i = -1
            _length = _ba.length
            while ++_i < _length
                ### 上 ###
                _ctx.fillRect _i << 1, 0, 5, _ba[_i] << 1
                ### 下 ###
                _ctx.fillRect _i << 1, _height, 5, ~((_ba[_i] << 1) + 1)
            requestAnimationFrame(draw)
            _ba = undefined
        ###
         * ランダムなRGB値を返します
         * @return {String}
        ###
        getRandomRGB = ->
            return '#' + ('00000' + (Math.random() * (1 << 24) | 0).toString(16)).slice(-6)
        ###
         * エラー
         * @event error event
         * @private
        ###
        onError = (event) ->
            alert('Web Audio error :: ' + event.code)

これをコンパイルしてサーバーにアップしておきました。 こちらからどうぞ。

こんな感じになります。
Sample - HTML5 canvas API

まとめ

canvasは、JavaScriptでゴニョゴニョしないと本来の力が発揮されないと思います。
が、JSでdivとかをいじるより、遥かに処理能力的にものすごく軽いです。
対応ブラウザを気にしないなら一昔前のFlashサイトの用な事まで可能だと思います。
またcanvas APIの使い方自体がActionScripに似ているので、Flasherには学習コストが低いと思います。
もちろん、そもそもがJavaScriptという一般的に使われるケースが多いスクリプトなので、Flasherじゃない人でもコードを参考にしながら美しく早いcanvasの実装が可能だと思います。

ただ、実務ベースのプロジェクトになると、その案件の対象ブラウザを気にしなくてはなりません。単にcanvasオンリーなサイトと言う訳には行かなさそうです。
どうしても実務ベースで使いたい!となれば、canvasを無理やり対応させるライブラリを使用するとか、ブラウザ分岐する処理がまだ必須な気がしますが、スマートフォンでの閲覧が圧倒的に増えてきているイマ、ユーザの状況を考慮すると、導入していく価値は十二分にある気がしています。

Recent Entries
MD EVENT REPORT
What's Hot?