Snap.svgで弾力のあるボタンを作る

#はじめに

今回、線を引くsvgアニメーション以外で汎用性のある使い方がないかと思い、クリックしたときに変形するボタンを作成してみました！
その手段としてSnap.svgを利用します。


完成版はこちら
[DEMO](https://codepen.io/nitta_shiori/full/OQEbOy)
![ボタンイメージ](https://i.gyazo.com/840b0060a5d7ca22800e2d01a4d951ac.png)

**目次**

- Snap.svgとは？
- 準備編
- 実装編
- おわりに

#Snap.svgとは？
svgを扱うためのJavaScriptライブラリーです。jQueryでDOM取得からサイズ、色、アニメーションを制御することができます。

#準備編

- Snap.svg
- svgデータ（ボタンの座布団になる部分）

##Snap.svg導入
公式サイトからファイルをダウンロード。
snap.svg-min.jsを使用します。
http://snapsvg.io/

```
Snap.svg-0.5.1/
├─ ***
└─ dist/
  └─ snap.svg-min.js
```
npmからもダウンロードできます。
https://github.com/adobe-webplatform/Snap.svg

##svgデータの作成（ボタンの座布団になる部分）
座布団とは赤いベタの部分です。
ボタンのアニメーション前とアニメーション後の2つのデータを用意します！

####アニメーション前svg作成

![アニメーション前svg](https://i.gyazo.com/2af241a57053c65175ad069a8995584e.png)

①イラストレーターで矩形を作成。今回サイズは400*60にしました。
②ツールバーにある、`オブジェクト > アートボード > オブジェクト全体に合わせる`でアートボードを矩形にフィットさせます。

③Cmd+Shift+S（書き出し形式）でsvgを保存

![代替テキスト](https://i.gyazo.com/dc29f3f3cbf7269b495f74dccc34d56a.png)

④下記のサイトでsvgデータ軽量化
https://jakearchibald.github.io/svgomg/
svgを形成する**d属性**を取得したいのでこちらで最適化します。

####アニメーション後svg作成

![アニメーション後svg](https://i.gyazo.com/209d3f98139fab783cee57188628df3e.png)

①アニメーション前①②と同様の工程が終わってる矩形を好きな形に変えてください。
このときアートボードからはみ出るような編集を行うとオブジェクトが切れたような表示になるので、
アートボード内に収まるよう編集してください。
DEMO版では以下のように作成してます。
`効果 > ワープ > でこぼこ  > 垂直方向、カーブ-20%`

②Cmd+Shift+S（書き出し形式）でsvgを保存

③svgをエディターで開いたときに**d属性**がない場合は、
アニメーション前④の工程と同様にsvgを最適化してください。

#実装編
準備が終わったところでようやく実装です！
HTML、SCSS、Javascriptそれぞれ解説していきます。

##HTML

```HTML
<div class="active-button">
  <a class="active-area" href="#">
    <span class="text">CLICK ME!<i class="fas fa-angle-right"></i></span>
    <span class="box-wrap">
      // svgデータをコピペ
      <svg class="box"　xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 400 60">
      </svg>
    </span>
  </a>
</div>
```

`.box-wrap`の中身は先ほどの通常時svgデータをコピペして、クラスを与えます。
またボタンは可変してほしいのでwidthとheightに100%を指定します。
pathタグは一旦ここでは削除します。（Javascriptのときに解説）

##SCSS

```SCSS
.active-button {
  width: 400px; //ボタンの幅はここで変更できます
  margin: auto;
  @media screen and(max-width: 768px) {
    width: 300px;
  }
  .active-area {
    display: block;
    position: relative;
    color: #ffffff;
  }
  .text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translateY(-50%) translateX(-50%);
    z-index: 100;
    width: 100%;
    text-align: center;
    i {
      display: inline-block;
      position: absolute;
      font-size: 18px;
      margin-left: 15px;
    }
  }
  .box-wrap {
    position: relative;
    width: 100%;
    display: inline-block;
  }
  .box {
    width: 100%;
    height: 100%;
    fill: #e81e25; //ボタンの背景色はfillから変更できます
    display: inline-block;
  }
}
```

`.active-button`のwidthがボタンの幅になるのですが400以外の数値でも調整できます👌
拡大しても劣化しないのはsvgならではですね！ありがたい！
ただし高さも変わりますので注意してください。

##Javascript
まず[jQuery](http://jquery.com/download/)と先ほどダウンロードした`snap.svg-min.js`を読み込んでください。

```js

// アニメーション前のパス
var pathFrom = 'M0 0h400v60H0z';
// アニメーション後のパス
var pathTo = 'M0,0c133.333,0,266.667,0,400,0c-6.335,19.498-6.335,40.502,0,60c-133.333,0-266.667,0-400,0C6.335,40.502,6.335,19.498,0,0';
var duration = 100; // アニメーション時間
var easing = mina.easein; // Snap.svgで定義されているイージング関数
var svg = Snap('.box'); // Snap.svgを定義
var active = $('.active-area'); // クリックされるエリアを取得
var path = svg.path(pathFrom); // svgのpathの初期値をpathFromにする

// イベント発火
active.on('mousedown touchstart',function(){
  path.animate({path: pathTo}, duration, easing);
}).on('mouseup touchend',function(){
  path.animate({path: pathFrom}, duration, easing);
});
```
pathFromにはアニメーション前のsvgの**d属性**、
pathToにはアニメーション後のsvgの**d属性**を入れます。
durationとeasingはお好みで設定してください。
pathに初期値となるアニメーション前のパスを定義します。これを設定することでHTMLでも自動にd属性が付与されます。

完成版はこちら
[DEMO](https://codepen.io/nitta_shiori/full/OQEbOy)

#おわりに
型さえ作ればあとはjsで値を変えるだけなので楽ちんです！
今回は弾力性のあるボタンを作成しましたが、パスの値やイージング関数を変更すればもっとぷるぷるでぐにゃぐにゃなものが作れそうです。
アイディア次第ではおもしろいものができるのではないでしょうか。