CanvasでMaterial Design風ボタン

人のソースを見て勉強しようシリーズ第一弾。

CanvasでMaterial Design風ボタン（ボタンを押すと半透明な円が広がるアニメーションのやつ）を実装してる人がいたので、ソースを写経＋ちょこっといじってみた。

[CanvasでMaterial Design風ボタン](http://jsdo.it/matsui_a/3NwO)

[お手本ソース](http://codepen.io/Fischaela/pen/ahgIy)

![sample1.gif](https://qiita-image-store.s3.amazonaws.com/0/3140/17243f9e-5237-0dd3-03ce-df56b103c071.gif)


以下、解読したソースのまとめ。

# HTML

```html
<h1>Material Design Buttons</h1>
<section class="container">
  <button class="btn color material-design" data-color="#004740">Button1</button>
  <button class="btn btn-round color material-design" data-color="#ffffff">Button2</button>
  <button class="btn btn-border color material-design" data-color="#004740">Button3</button>
  <button class="btn btn-border btn-round color material-design" data-color="#00897b">Button4</button>
</section>
```

# CSS

```scss
* {
  box-sizing: border-box;
  outline: none;
}

@import url(http://fonts.googleapis.com/css?family=Open+Sans:300);

body {
  font-family: 'Open Sans', sans-serif;
  font-size: 100%;
  font-weight: 300;
  line-height: 1.5em;
  text-align: center;
  backgrorund: #FFF;
}

h1 {
  color: #666666;
  font-size: 2rem;
  line-height: 1.5em;
  margin:2em 0 2em 0;
}

$color: #00897b;

.btn {
  border: none;
  color: white;
  overflow: hidden;
  margin: 1rem;
  padding: 0;
  text-transform: uppercase;
  width: 150px;
  height: 40px;
  &.color {
    background-color: $color;
  }
}

.btn-border {
  &.color {
    background-color: transparent;
    border: 2px solid $color;
    color: $color;
  }
}

.btn-round {
  border-radius: 10em;
}

.material-design {
  position: relative;
  canvas {
    opacity: 0.25;
    position: absolute;
    top: 0;
    left: 0;
  }
}

.container {
  display: flex;            //Flexboxコンテナーを作る
  flex-direction: row;      //HTMLの書き順で、左から右に配置
  flex-wrap: wrap;          //折り返しを許可
  justify-content: center;  //水平方向:中央揃え
  align-items: flex-start;  //垂直方向の:上揃え
  align-content: center;    //行:中央揃え
  margin: 0 auto;
  max-width: 46rem;
}
```

##フォント

GoogleのWebフォントを使用 => [Open Sans Light 300](https://www.google.com/fonts/specimen/Open+Sans)


```scss
@import url(http://fonts.googleapis.com/css?family=Open+Sans:300);

body {
  font-family: 'Open Sans', sans-serif;
}
```

## Flexbox
上下中央配置や、レスポンシブでの調整に便利なやつ。
（=普段IEを無視して書けることがそんなに無いから、毎回書き方を忘れてしまうやつ）

参考：[今こそ未来！CSS3のFlexboxを基本から理解して、使い倒そう！ | 株式会社LIG](http://liginc.co.jp/web/html-css/css/21024#a8)


# JS

```js
var canvas = {},
    centerX = 0, //押されたx座標位置
    centerY = 0, //押されたy座標位置
    color = '',  //描画色
    containers = document.getElementsByClassName('material-design'),
    context = {},
    element = {},
    radius = 0,

    //requestAnimationFrame()でアニメーションさせる
    //未対応のブラウザにはsetTimeout()
    requestAnimFrame = function () {
      return (
        window.requestAnimationFrame       || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     || 
        function (callback) {
          window.setTimeout(callback, 1000 / 60);
        }
      );
    } (),
      
    init = function () {
      containers = Array.prototype.slice.call(containers); //オブジェクトを配列に変換
      for (var i = 0; i < containers.length; i += 1) {
        canvas = document.createElement('canvas');
        containers[i].appendChild(canvas);
        canvas.addEventListener('click', press, false);
        canvas.width  = canvas.offsetWidth;
        canvas.height = canvas.offsetHeight;
      }
    },
    //押されたときの処理
    press = function (event) {
      color = event.toElement.parentElement.dataset.color; // data-colorの値を取得
      element = event.toElement;
      context = element.getContext('2d');
      radius = 0; //円の大きさを初期値に
      centerX = event.offsetX; //押されたx座標位置
      centerY = event.offsetY; //押されたy座標位置
      context.clearRect(0, 0, element.width, element.height); //矩形をクリア
      draw();
    },
    //描画更新処理
    draw = function () {
      context.beginPath(); //描画開始
      context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false); //正円の描画
      context.fillStyle = color;
      context.fill(); //パス図形を描画
      radius += 8; //円の描画スピード
      if (radius <= element.width) {
        requestAnimFrame(draw); //矩形の幅を超えるまで円を描画
      } else {
         context.clearRect(0, 0, element.width, element.height);
      }
    };

init();
```