SVGでクリックできる地図をつくる

スマホがなかった古の時代、1枚画像に分割したリンクを設定したい時には「クリッカブルマップ」というものがよく使われていました。
例えば地図をクリックさせて各エリアページへの導線にしたい場合とかですね。

しかしクリッカブルマップは領域をピクセル単位で指定する必要があるため、レスポンシブの概念が登場してからとても使いにくくなってしまいました。
代わりに使われるようになったのがSVGを使った手法です。

頻繁に使う機会があるものでもない、というかほぼ地図くらいしか出番がなさそうな手法なので意外に知らない人もいるかも、と思ったので簡単な作例をまとめてみました。

画像の準備

ベクター形式の画像を用意する

まずは素材の用意です。
今回白地図はこちらから拝借いたしました。

地方エリア分け日本地図(ベクターデータ)のイラスト素材 | イラスト無料・かわいいテンプレート
https://www.sozai-library.com/sozai/2530

ベクター形式の画像ならば.aiでも.epsでも.svgでも何でも構いません。
最終的にsvgで書き出せればOKです。

SVGフォーマットで書き出し

次にイラストレーター、XDなどSVGフォーマットで書き出せるアプリケーションでパスグルーピングを調整して書き出します。
素材サイトからダウンロードしたそのままだと不要なものや背景レイヤーなど余計なオブジェクトがあったりするので整理。

それぞれクリックする単位のパスでまとめられたらグループ化して書き出します。

今回は都道府県単位で1つのパスになるようにまとめました。
(上の画像は白線が付いてますが、あとでcssでつけるので実際に使用した素材については線なしにしています。)

SVGをエディタで開いてコードを整理する

次に書き出したsvgファイルをコードエディタで開きます。
XDで書き出した直後のコードはこんな感じ。

パス名が日本語だったりグルーピングがごちゃごちゃしてるのでざくざくまとめます。
今回コード修正したのは以下のとおり。

・不要なグループを削除
・id/data属性名を変更

・コード内に書かれている塗り(fill)・線(storke)のパラメータを削除

こんな感じでコードを整えたらHTMLに貼り付けて準備完了です。

See the Pen map-00 by katsutoshi chiku (@katsutoshi-chiku) on CodePen.

今回はこのsvgコードを使ってサンプルを作っていきます。

1.ホバーイベントでエリアにリンクをつける

まずシンプルに地図のエリアごとにクリックできるリンクを張ってみます。

See the Pen map-01 by katsutoshi chiku (@katsutoshi-chiku) on CodePen.

リンクを張ってホバーイベントを発生させるだけならばjsは必要ありません。
シンプルにaタグを設置してcssで装飾するだけでOKです。

<a href="">
  <path id="kanto-01" data-name="tochigi" d="M134.16,49.577a4.873,4.873,0,0,0-1.523,4.876c.609,1.525,3.353,3.048,....577Z" transform="translate(8262.138 -1081.007)"/>
</a>

このようにsvg内のpathをaタグで囲ってあげて

    .map path{
      fill: #ccc;
      stroke: #fff;
      cursor: pointer;
      transition: 0.3s ease;
    }
    #map-01 path:hover{
      fill: #AFE2C6;
    }

こんな感じにホバー時の装飾を指定します。
ちなみにpathのパラメータで「fill」は塗りつぶし色、「storke」は線色の指定になります。

2.クリックイベントでエリアに色をつける

次にクリックしたら該当エリアに色が付くやつです。
クリックイベントはjsが必要になります。

See the Pen map-02 by katsutoshi chiku (@katsutoshi-chiku) on CodePen.

ホバーで薄い色が、クリックで濃い色が付くようにしました。

こちらは地図のsvgには触らず、jsでパスをクリックした際に「is-active」クラスを付与して色をつけてます。

#map-02 path:hover{
  fill: #EFDAAD;
}
#map-02 path.is-active{
  fill: #D8B465;
}
let paths02 = document.querySelectorAll('#map-02 path')
paths02.forEach((path)=>{
  path.addEventListener('click',function(){
    paths02.forEach((path)=>{
      path.classList.remove('is-active')
    })
    path.classList.add('is-active')
  })
})

3.クリックイベントでリストを連動させる

最後に地図とリストを連動させるやつです。
これもよくあるやつですがちょこっと面倒になってきますね。

See the Pen map-03 by katsutoshi chiku (@katsutoshi-chiku) on CodePen.

さっきのやつにリストを用意して、画像のdata属性とリストのクラスを符合させて切り替えるように書きました。

リストに都道府県のクラスを振って

<div class="map-list">
 <ul>
  <li class="is-active">市町村リスト</li>
  <li class="tochigi">
    <dl>
      <dt>栃木県</dt>
      <dd>
        <a href="">宇都宮市</a>
        <a href="">足利市</a>
        <a href="">栃木市</a>
        <a href="">佐野市</a>
        <a href="">鹿沼市</a>
        <a href="">日光市</a>
      </dd>
    </dl>
  </li>
  <li class="gunma">
   ...
  </li>
 </ul/>
</div>

jsでクリックしたdata属性を取得、そのクラス名のリストに「is-active」を付与する、という感じです。

let paths03=document.querySelectorAll('#map-03 path') let list=document.querySelectorAll('.map-list ul li')
  paths03.forEach((path)=> {
    path.addEventListener('click', function() {
        paths03.forEach((path)=> {
            path.classList.remove('is-active')
          }

        ) path.classList.add('is-active') list.forEach((item)=> {
            item.classList.remove('is-active')
          }

        ) let dataName=path.dataset.name document.querySelector(`.map-list ul li.$ {
            dataName
          }

          `).classList.add('is-active')
      }

    )
  }

)

今回は単純に表示・非表示の切り替えでやりましたが、きちんと作るならvueやらjsonやら絡める必要がでてきたりしますね…めんどうくさい。
ただキーになる要素を揃えておけば連携はそんなに難しいこともないかなと思います。

まとめ

svgで派手なアニメーションとかをやるとなるとライブラリを使ったりと若干煩雑になりますが、この程度のことならシンプルなcssとjsでできちゃうぞ、という話でした。

「なんとなくできるのは分かるんだけどどうやってるのかな?」というのは要件に出てくると少しギョッとしますよね。
こういうのを日頃ちまちま引き出しに用意しておくとちょっとだけストレスフリーになると思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA