SVG地図イラストを操作するJavaScriptモジュール「MapNJ」を紹介します

![mapnj_hero](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204059/0d5c92f5-51dd-1343-6ba3-5ba9973db1e8.png)


## はじめに
こんにちは。デザインとフロントエンドの狭間をずっと漂っていた結果、猛暑の日本に辿り着いたマン :man_tone1: です。
このたび初めて技術ブログなるものを書いてみました。 

## 地図は普遍的なUI
Google Mapって素敵ですよね :smile: 
地球規模の情報量に抜群のUI。ストリートビューを使った観光の擬似体験。
時にNetflix以上に時間を溶かしてくれる存在。:shaved_ice:

一方で、観光地にあるイラストてんこ盛りの地図看板などは、その土地の楽しさや親近感を爆速で感じさせてくれたり。:stars: 

地図は情報を伝えるための普遍的なUIと言えます。

本題である、MapNJは、そんな「地図で伝えたい ！」を少しだけお手助いするスクリプトです。



## MapNJとは？

![mapnj_demo_nexus_of_r](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204059/27bb1dad-5518-b070-8ea5-ffa6dea9552a.png)


MapNJは、 **SVGで作成された地図イラストを操作できる小さなスクリプト** です。

MapNJが定義する「地図」とは、複数の **エリア** と、それに対応した **ラベル** で構成されるものを指します。

さらに幾つかの補助パーツを利用することにより、それっぽいUI :raised_hands: になります。
まずはデモをご覧ください。

[デモ - Nexus of R](https://mapnj.masa-sumimoto.com/ja/demo-nexus-of-r/)


このように、**エリアのアクティブ・非アクティブ状態を管理し、それに付随したデザインを提供すること** がMapNJの役割になります。


## 最大の特徴

MapNJ最大の特徴（目的）は、**デザイナーとエンジニアの役割分担**にあります。

デザイナーはデザインソフト上で、MapNJ独自の命名ルールを利用しデザインを行う必要があります。
これにより、SVGをコード上に展開した時点で既にMapNJの最低限の機能が使える状態になります。

以後、デザイン修正が起こるたびに、このルールに用い、デザイナーとエンジニアは連携を維持します。


### 意外に意思疎通が難しい2つの世界

デザインとコードの作業分担が行われている現場などでは、互いの責任が曖昧になりがちです。
また、異なる領域に特化したメンバー同士がアサインされた場合、相手の作業内容を想像することすら困難なケースもあります。

「共有すべきルール」をあらかじめ提示することで、相互理解や歩み寄りが生まれたら良いなと感じ、この形を選びました。

そのため、解説サイトの「[デザイン素材素材作成](https://mapnj.masa-sumimoto.com/ja/usage/#design-source-setup)」では、Nodeモジュールの紹介サイトでありながら、一番にデザイナーの作業内容を詳細に示すことを心がけました。




## チュートリアル　:older_man:

ここでは実際に、いくつかの機能を使い、シンプルなUIを作ってみようかと思います。

また、[解説サイト](https://mapnj.masa-sumimoto.com/ja/) では網羅的な情報を掲載しておりますので、もしこのサンプルで、MapNJに興味を持ってくださった方は、是非こちらもご覧ください... :pray_tone1: 嬉 :cat: 


では、チュートリアルです!!

### 1. 基本コードを実装

![sig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204059/97d6068c-4eae-6b31-187d-6f6e187762b7.png)


本来、操作対象には地図イラストのようなものを想定していますが、今回は極力説明をシンプルにしたいため、「信号機」のような見た目のものを題材にします。

画像はFigmaの画面のスクリーンショットです。それぞれのデザインノードの名前はMapNJの命名規則に従っています。これを素材としてsvgを書き出します。

:::note info
**Tips**
Figmaの場合、SVG書き出し画面で「ID属性を含める」のチェックを入れた上で書き出しを行います。
:::

```html

<!-- [1] svgをラップする任意の要素を準備 -->
<div id="your-mapnj">
  <!--[2] デザインしたSVG要素の貼り付け -->
  <svg width="600" height="400" viewBox="0 0 600 400" fill="none" xmlns="http://www.w3.org/2000/svg">
    <circle id="mapnj-area-blue" cx="204" cy="200" r="40" fill="#0EA5E9" />
    <circle id="mapnj-area-yellow" cx="300" cy="200" r="40" fill="#EAB308" />
    <circle id="mapnj-area-red" cx="396" cy="200" r="40" fill="#EF4444" />
  </svg>
</div>

<!-- [3] MapNJをCDNで利用 -->
<script src="https://cdn.jsdelivr.net/npm/mapnj@latest/dist/MapNJ.min.js"></script>

<!-- [4] インスタンス化 -->
<script>
  const mapnj = new MapNJ("#your-mapnj");
</script>

```

HTML側を準備しましょう。

1.  任意のラップタグを用意し、ID属性を付与します。(IDはyour-mapnjとしました。)
2. Figmaより書き出されたSVGソースを貼り付けます。3つの丸を描いただけのものなので、SVGコードは非常にシンプルです。SVGの内包するタグには`mapnj-area-xx id属性` が付与されています。これら要素を、MapNJでは **エリア** と呼びます。
3. MapNJを読み込みます。今回はCDN `https://cdn.jsdelivr.net/...` を利用します。
4. ラップ要素のID名を第一引数としてインスタンス化します。

このコードだけで、とりあえずの状態管理機能が実装された状態になります。
是非、このコードをお手元のhtmlファイルのbodyタグに貼り、プレビューしてみてください。

:::note info
**Tips**
SVGを書き出す際にid属性ではなく、data-name属性を利用する方法も存在します。
:::

:::note info
**Tips**
MapNJの利用は、「Nodeモジュール」「CDN」「Github Releaseから直接ソースをDL」の3つの方法があります。
:::



### 2. デザイン調整

```javascript
const mapnj = new MapNJ("#your-mapnj", {
  areaDefaultFillColor: "#555",
});
```
次に、少しデザインを調整してみます。
現在、エリアの「通常時（非アクティブ時）」の色はグレーです。もう少し濃いグレーに変更してみます。
先ほどのインスタンス化コードの第二引数を利用しオプションを渡します。上記のように訂正してください。
これでエリアの色が変更されました。


:::note info
**Tips**
非アクティブ時・アクティブ時のいずれの状態も、エリアの「塗り」および「線」の色を自由に操作することが可能です。

また例では一括で色を指定していますが、エリア個別に色を指定することも可能です。

さらに、（今回のサンプルには登場しませんが） 「ラベル」においても同じルールを適用することが可能です。

[MapNJオプション](https://mapnj.masa-sumimoto.com/ja/advanced-usage/)
:::

### 3. 連動コンテンツを追加

```html
<div>
  <div data-mapnj="content" data-area-id="blue">青です!</div>
  <div data-mapnj="content" data-area-id="yellow">黄です!</div>
  <div data-mapnj="content" data-area-id="red">赤です!</div>
</div>
```

上記のコードを `<div id="mapnj">` 内の、どこか適当なところに配置してください。
その上でいずれかのエリアをクリックしてください。
これらのコンテンツが連動し、表示・非表示されます。

:::note info
**Tips**
これはオプションパーツと呼ばれるもので `data-mapnj` 属性を付与することで、特定の動作を行うパーツとして扱うことが可能になります。 :bug:

[MapNJオプションパーツ](https://mapnj.masa-sumimoto.com/ja/advanced-usage/#option-parts)
:::



### 4. 操作パーツを追加

```html
<div>
  <button data-mapnj="selector" data-area-id="blue">青になれ!</button>
  <button data-mapnj="selector" data-area-id="yellow">黄になれ!</button>
  <button data-mapnj="selector" data-area-id="red">赤になれ!</button>
</div>
```

上記のコードを `<div id="mapnj">` 内の、どこか適当なところに配置してください。
いずれかのbuttonをクリックすると、エリアとコンテンツが連動します。



### 5. イベントの利用

```javascript
mapnj.on("AREA_CHANGE", (mapnj) => {
  if (mapnj.state.activeAreaId === "red") {
    alert("赤だから気をつけて!!");
  }
});
```

最後に、イベントを利用してみます。
mapnj定数に格納しているインスタンスに対し、onメソッドを実行します。 `AREA_CHANGE` イベントはその名の通り、エリアが切り替わった際に発火します。第二引数に渡したコールバック関数内では、mapnjのインスタンスをそのまま受け取れるため、ここでは、現在選択されているエリアのIDを判別し、アラートを表示するスクリプトを加えてみました。


## 最後に

41歳にして初めて技術ブログなるものを書いてみました。

普段は、WEBの技術を極力お仕事とは切り離し、デザインやアートとして気軽に楽しめるような、環境作りやモチベーションを大切にしています。

共感いただける人がいたら嬉しいです。 :relaxed:

他にもFigmaプラグインなども作っているのですが、機会があればそれも紹介したいと思います。では!!  :bug: :bug: :bug:


## リファレンス

https://mapnj.masa-sumimoto.com/ja/advanced-usage/#events

https://www.npmjs.com/package/mapnj

https://github.com/masa-sumimoto/mapnj/releases

https://www.jsdelivr.com/package/npm/mapnj


## CHANGE LOG

24.08.16 : v0.2.0リリースに伴い、変更点に則しテキストを修正