「うごけ！道案内」の地図スクリプトを YOLP JavaScript マップ API で再生してみる

## うごけ！道案内とは

地図コマンドの羅列による地図スクリプトで地図を操作できる Web サービス。

<img width="956" alt="ugomichi.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/a24beaab-12eb-7662-634b-53c602251ea6.png">

[「うごけ！道案内」で地図プログラミング \- Yahoo\! JAPAN Tech Blog](https://techblog.yahoo.co.jp/lab/latlonglab/ugoke/)

> 「うごけ！道案内」は、MS-DOSのバッチファイル風にコマンドを並べるだけで地図を思い通りに動かせるプログラミングツールなのです。

[うごけ！道案内の使い方 \- LatLongLab](https://latlonglab.yahoo.co.jp/guide/macro.html)

> 「うごけ！道案内」は、地図を使って動きのある道案内を簡単に作成し共有できるサービスです。
> お店やサービスの所在地を紹介したり、行動記録を確認したり、アドベンチャーゲームやクイズなど、様々なシーンで活用できます。

[うごけ！道案内の使い方 \- LatLongLab](https://latlonglab.yahoo.co.jp/guide/macro.html)

> アドバンスモードではさらにインタラクティブな地図を作る手段として簡単なスクリプトで地図操作のプログラミングが可能です。
> アドバンスモードを使えば条件分岐や写真の表示などの機能を使って本格的なゲームなどのコンテンツも作成いただけます。

「うごけ！道案内」は2020年3月末でクローズされてしまう。

[LatLongLab](https://latlonglab.yahoo.co.jp/close.html)

> 約10年間にわたりサービスを運用してまいりましたLatLongLabですが、
> 誠に勝手ながら、2020年3月末をもってサービスを終了させていただくこととなりました。

## 地図スクリプト

地図スクリプトは以下のような地図コマンドとパラメータによる地図コマンドを並べたものになっている。

```
moveto 36/12/50.407,137/22/37.774
layerto 16
message 日本で一番短い鉄道って知ってます？
sleep 3000
smoveto 35/46/10.385,140/23/14.688
message それは千葉県にある
sleep 3000
layerto 6
message 芝山鉄道です。
```

## 地図コマンド

以下のように地図を操作するコマンドがある。

[うごけ！道案内の使い方 \- LatLongLab](https://latlonglab.yahoo.co.jp/guide/macro.html)

> <img width="630" alt="ugomichi-command.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/1347806f-fa20-8aa5-9227-5621e6fc9e68.png">

## 地図スクリプトを再生するサンプルコード

YOLP Yahoo! JavaScript マップ API を使用して、いくつかの地図コマンドを実現してみた (YOLP Yahoo! JavaScript マップ API は2020年10月31日にクローズ予定)。

macOS Catalina + Google Chrome 80.0.3987.149 で動作確認済み。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>「LatLongLab うごけ！道案内」風</title>

<script type="text/javascript" charset="utf-8" src="https://map.yahooapis.jp/js/V1/jsapi?appid=YOUR_APPLICATION_ID"></script>

<script>

// 「うごけ！道案内」っぽい再生をするクラス
class UgoMichi {

  // map: 地図操作オブジェクト
  // script: 地図スクリプトテキスト
  constructor(map, script) {
    this.script = script.split(/\r\n|\r|\n/);
    this.map = map;
  }

  // 地図スクリプトを再生する
  play() {
    this._doCommand(this._doCommand, this.map, this.script, 0);
  }

  // コマンドを実行する
  _doCommand(doCommand, map, script, index) {

    if(index >= script.length) {
      return; // 地図スクリプトを全部処理した
    }

    // 地図スクリプトから1行抜き出す
    const item  = script[index];

    // コマンド名とパラメータに分ける
    const sepIndex = item.indexOf(" ");
    const command  = item.substring(0, sepIndex);
    const param    = item.substring(sepIndex + 1);

    let sleepTime = 200;
    if(command === "sleep") {
      // sleep コマンド
      sleepTime = parseInt(param);
    } else {
      // sleep コマンド以外
      map[command](param);
    }

    // 再帰呼び出し
    setTimeout(doCommand, sleepTime, doCommand, map, script, ++index);
  }
}

// YOLP Yahoo! JavaScriptマップAPI を使用した地図操作クラス
// 各種コマンドに対応したメソッドを持つ
class YolpMap {
  constructor(ymap) {
    this.ymap = ymap;
  }
  // moveto 緯度,経度: 地図を指定した位置に瞬間的に移動
  moveto(param) {
    const dms = param.split(",");
    const ll = new Y.LatLng(this._dmsToDeg(dms[0]), this._dmsToDeg(dms[1]));
    this.ymap.panTo(ll, false);
  }
  // smoveto 緯度,経度: 地図を指定した位置まで連続的に移動
  smoveto(param) {
    const dms = param.split(",");
    const ll = new Y.LatLng(this._dmsToDeg(dms[0]), this._dmsToDeg(dms[1]));
    this.ymap.panTo(ll, true);
  }
  // layerto レイヤーID: レイヤー切り替え
  layerto(param) {
    const layerId = parseInt(param);
    // うごけ！道案内のレイヤーIDをYOLPのズームレベルに変換
    const zoomLevel = 20 - layerId;
    this.ymap.setZoom(zoomLevel, true);
  }
  // message 文字列: メッセージを表示
  message(param) {
    const text = param;
    this.ymap.openInfoWindow(this.ymap.getCenter(), text);
  }
  // 度分秒表記(35/59/59.999)を度(35.999999)に変換
  _dmsToDeg(dmsString) {
    const sign = dmsString.charAt(0) == "-" ? -1 : 1; // 負の値か
    const items = dmsString.split("/"); // 度/分/秒を分解
    const d = Math.abs(parseInt(items[0]));
    const m = parseInt(items[1]);
    const s = parseFloat(items[2]);
    return sign * (d + m / 60 + s / 60 / 60);
  }
}

window.onload = function() {

  // YOLP Yahoo! JavaScriptマップAPI の準備
  const ymap = new Y.Map("map");
  ymap.addControl(new Y.CenterMarkControl()); // 地図中心点を表示
  ymap.drawMap(new Y.LatLng(35, 135), 17, Y.LayerSetId.NORMAL); // 地図を表示

  // 「うごけ！道案内」っぽい処理をするクラスを使用
  const map = new YolpMap(ymap);
  const myScript = document.getElementById("my-script").innerHTML; // 地図スクリプトデータ
  const ugo = new UgoMichi(map, myScript);
  ugo.play();
}

</script>
</head>
<body>

<!-- 地図表示領域 -->
<div id="map" style="width:600px; height:430px"></div>

<!--
日本一短い鉄道 - うごけ！道案内 - LatLongLab
https://latlonglab.yahoo.co.jp/macro/watch?id=b834fc87f0ba874c24174b3de436f306
-->
<textarea id="my-script" style="display:none">moveto 36/12/50.407,137/22/37.774
layerto 16
message 日本で一番短い鉄道って知ってます？
sleep 3000
smoveto 35/46/10.385,140/23/14.688
message それは千葉県にある
sleep 3000
layerto 6
message 芝山鉄道です。
sleep 3000
message では乗ってみましょう
sleep 3000
moveto 35/45/14.756,140/23/58.567
layerto 2
message 出発進行ー！
sleep 3000
smoveto 35/45/18.881,140/23/48.28
smoveto 35/45/20.018,140/23/46.8
smoveto 35/45/26.19,140/23/41.917
smoveto 35/45/29.892,140/23/38.996
message ここからトンネルです
sleep 3000
smoveto 35/45/35.901,140/23/34.153
smoveto 35/45/42.429,140/23/29.55
smoveto 35/45/48.08,140/23/25.788
smoveto 35/45/53.666,140/23/23.587
smoveto 35/45/58.18,140/23/22.307
smoveto 35/46/2.077,140/23/20.105
smoveto 35/46/7.306,140/23/16.343
smoveto 35/46/12.502,140/23/13.021
message 東成田～。東成田～
sleep 4000
message はい。おしまいです。
sleep 3000
message 長さは2.2km。時間にして4分ほどの旅です。
sleep 3000</textarea>

</body>
</html>
```

## 本家「うごけ！道案内」と「うごけ！道案内」風の比較動画

[本家「うごけ！道案内」と「うごけ！道案内」風の比較 \- YouTube](https://www.youtube.com/watch?v=SBdH7QHBDmY)

## 参考資料

- [うごけ！道案内の使い方 \- LatLongLab](https://latlonglab.yahoo.co.jp/guide/macro.html)
- [「うごけ！道案内」で地図プログラミング \- Yahoo\! JAPAN Tech Blog](https://techblog.yahoo.co.jp/lab/latlonglab/ugoke/)
- [日本一短い鉄道 \- うごけ！道案内 \- LatLongLab](https://latlonglab.yahoo.co.jp/macro/watch?id=b834fc87f0ba874c24174b3de436f306)
- [本家「うごけ！道案内」と「うごけ！道案内」風の比較 \- YouTube](https://www.youtube.com/watch?v=SBdH7QHBDmY)
- [YOLP\(地図\):Yahoo\! JavaScriptマップAPI \- Yahoo\!デベロッパーネットワーク](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/js/)