Mapbox GL JS で地図のサイズ変更に対応する

## はじめに

[地理院地図](https://maps.gsi.go.jp/)のように、レイヤの選択や地図の操作のために、地図とは別に操作パネルを設置しようと考えることがあります。この際、パネルを開閉したくなることが多いです。

このとき、以下の2通りの選択肢が考えられます。
1. 地図のサイズは変えずに、操作パネルを地図に重ねるように出す
2. 地図のサイズを小さくして、操作パネルを並べるように出す

ちなみに、Google マップや[地理院地図Vector](https://maps.gsi.go.jp/vector/) は1の方式、地理院地図は2の方式です（2022年10月22日現在）。

実は、2の方が、操作パネルだけではなく、**地図の領域についてもサイズ調整を行わなくてはいけない**ので、結構面倒臭いのではないかと思っています。そういうわけで、[Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) で2の方式ができないかと試していた時に躓いたので、経緯を記事に残したいと思います。

:::note warn
消化不良の記事です。
:::

本件のレポジトリは以下です。

https://github.com/mghs15/mapbox-gl-js-resize-test

## Case 1：開閉パネルのサイズを変える

サイズを変える方法はいろいろとありますが、まずは [grid](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout) を用いたレイアウトを作ります。その後、CSS の [class を追加・削除する](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/toggle)ことで、操作パネルの width を変更する方法を試してみます。用意した HTML、CSS、JavaScript は以下の通りです。

```HTML:HTML
<div id='wrap'>
  <div id='menu'>
    <div id='menuContent'>menu</div>
  </div>
  <div id='openButton' onclick="kaihei()"></div>
  <div id='map'></div>
</div>
```

```CSS:CSS
body { 
  margin: 0; 
  padding: 0; 
}

#wrap {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: grid;
  grid-template-rows: 1fr;
  grid-template-columns: auto 16px 1fr;
}

#openButton {
  background-color: #555555;
  border: solid 1px #333333;
  cursor: pointer;
}

#menu {
  background-color: #555566;
  width: 200px;
}

#menu.close {
  width: 0px;
}

#menuContent {
  background-color: #555566;
  text-align: center;
  font-size: 3em;
  color: #FFFFFF;
}
```

```JavaScript:JavaScript
const kaihei = () => {
  const ele = document.getElementById("menu");
  ele.classList.toggle("close");
}

const map = new mapboxgl.Map({
  container: 'map',
  hash: true,
  style: `./dark2.json`, // stylesheet location
  center: [139.78148, 35.768793],
  zoom: 9,
  minZoom: 4,
  maxZoom: 17.99,
  attributionControl: false,
  localIdeographFontFamily: ['MS Gothic', 'Hiragino Kaku Gothic Pro', 'sans-serif']
});

map.addControl(new mapboxgl.NavigationControl(), 'top-left');
map.addControl(new mapboxgl.ScaleControl() );
map.addControl(new mapboxgl.AttributionControl({compact: true}), 'top-right');
```


操作パネル、開閉ボタン、地図の描画エリアの3つを用意します。改変ボタンを押すと、操作パネルの要素に close というクラスを付与し、これで width の値を上書きして、操作パネルを閉じます。なお、gird のレイアウトとして、地図用の領域には 1fr を割り当ていますので、操作パネルを閉じたら、地図が（改変ボタンのエリアを残して）画面いっぱいに広がってほしいわけです。

しかしながら、このままだと、以下の画像のように地図がサイズ変更に対応できずに空白ができてしまいます。

![Case1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/8527bd7d-5135-c416-042e-7c0a691e3469.png)


デモサイト
https://mghs15.github.io/mapbox-gl-js-resize-test/case1.html

## Case 2：`map.resize()` を使う

実は、Mapbox GL JS には、コンテナのサイズが変更された際に、地図をリサイズしてくれるメソッド `resize()` が用意されています。

https://docs.mapbox.com/mapbox-gl-js/api/map/#map#resize

```diff_JavaScript
const kaihei = () => {
  const ele = document.getElementById("menu");
  ele.classList.toggle("close");
+ map.resize();
}
```

これで、操作パネルを閉じると、地図が追随して広がってくれました。

![Case2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/9e64965b-aa3a-58b0-00ba-0d7f32aa8e8d.png)

デモサイト
https://mghs15.github.io/mapbox-gl-js-resize-test/case2.html

## Case 3：CSS アニメーションを付けてみる

一方、操作パネルを閉じるとき、アニメーションを付けてみたくなります。たとえば、以下のように、0.5秒かけて開閉するようなアニメーションにしてみます。

```diff_CSS
#menu {
  background-color: #555566;
  width: 200px;
+ transition: all .5s ease-out;
}

#menu.close {
  width: 0px;
+ transition: all .5s ease-out;
}
```

すると、`map.resize()` を使っていても、地図がリサイズされません。これは、おそらく、アニメーションにより、サイズ変更に時間がかかっているため、`map.resize()` がその前に走ってしまい、適切なタイミングでリサイズができていないと思われます。

デモサイト
https://mghs15.github.io/mapbox-gl-js-resize-test/case3.html

## Case 4：setTimeout() を使ってみる

CSS アニメーションの時間を0.5秒と指定しているので、これに合わせて、`setTimeout()` でリサイズの時間を待ってみました。

```diff_JavaScript
const kaihei = () => {
  const ele = document.getElementById("menu");
  ele.classList.toggle("close");
- map.resize();  
+ setTimeout( () => {
+   map.resize();
+ }, 500 );
}
```

これで、0.5秒後にリサイズされて、結果としては地図は広がってくれましたが、**アニメーション中は空白ができたまま**になってしまいます。これでは、かっこ悪くて、あまりアニメーションしている意味がありません。

デモサイト
https://mghs15.github.io/mapbox-gl-js-resize-test/case4.html

## 最後に

取り急ぎ、ここまで調べて中断です。今後、良い方法があれば追記をします。また、アニメーションを使う際の何か良い方法をご存じの方は、ご指摘等いただけるとうれしいです。

## 参考文献

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions

https://developer.mozilla.org/ja/docs/Web/API/Element/classList

https://docs.mapbox.com/mapbox-gl-js/api/