便利な地図表示ライブラリ Leaflet(と OpenStreetMap)を使って表示する地図は原則的には上が北になります。これを変更して(つまり地図を回転させて、上が北側にならないようにして)表示することに挑戦してみました。

最初は「やり方をググれば見つかるだろう」と軽く考えていたのですが、これはどうやらかなり難しいらしく、Stackoverflow で同様の質問を見つけましたが、ここでの回答には「Leaflet ネイティブで用意された方法は存在しない」「簡単な方法はない」とされています。かなりハードル高そうです。。

ネイティブには用意されていない、、簡単ではないものを自力で解決する、、 言うは簡単ですが実際には細かな調整含めて結構面倒なものでした。ただ一応サンプルとして動く形にできましたので、公開&紹介します。

まず、ソースコードはこちらに用意しました。実装は index.html ファイルを参照してください(バックエンドなしにこのファイル1つだけで実装しています):
https://github.com/dotnsf/om


実際に動く様子を確認・体験できるように github ページも用意しました。スマホのブラウザでこちらにアクセスしてください:
https://dotnsf.github.io/om/


なお、このページでは DeviceOrientation イベントをハンドリングしているため、環境によっては事前準備が必要です。こちらのページでも紹介しているように Android や iOS 12.1 以下の場合は事前設定不要です(ページを表示すればそのまま動きます)。 iOS 12.2 以上 13.0 未満の場合は URL 先にアクセスする前に予め Safari の設定で「モーションと画面の向きのアクセス」を ON にしておいてください(この設定後に URL にアクセスすれば動きます):
2020011001



また iOS 13.0 以上の場合は事前の準備は不要ですが、ページロード直後の初期状態で表示される「センサーの有効化」というボタンをクリックしてから「許可」してください:
2020011002


いずれの環境においても上記の準備を済ませた上でアクセスすると、東京を中心とした関東の地図が表示されます。また画面の中心には赤字でこのスマホデバイスの横方向への傾き角度が表示されます:
2020011701


スマホを横方向に傾けると、その傾きに合わせて地図が画面内で回転して表示されます。下図ではスマホを向かって右側に(時計回り方向に)傾けています。スマホの傾きに関係なく、常に真上(下図では左上方向)が北になります:
2020011700


実際に動かしている様子を動画にしました:



以下、技術的な解説を加えていきます。

まず CSS で body など地図を表示する要素のサイズを width も height も 100% に指定して、全画面で地図が表示されるようにしています。

そして回転処理そのものは地図を表示する <div> 要素に CSS の transform: rotate() 属性を適用して実現しています。今回の例では <div id="demoMap"> 内に Leaflet 地図を表示していますが、デバイスの傾き(角度: deg)を検知して、
 $('#demoMap').css( 'transform', 'rotate(-'+deg+'deg)' );
という処理を実行することで <div> ごと回転をかけて表示しています(加えて deg の数値を <div id="me"> 内で表示していますが、こちらは特別な処理をしていないため、詳細は省略します)。

ただこれだけだとうまくいきません。Leaflet の仕様なのか、CSS transform の仕様なのか「もともと表示されている要素が回転して表示される」らしく、縦 100% 横 100% の画面を回転させると、角度によっては表示されない部分が出来てしまうのでした:
2020011801



↑黒がスマホ本体(黒枠の中だけが実際に表示される)、左側は本体画面に地図が表示されている。スマホを回転させて表示すると、元の地図の矩形部分は表示されるが、表示しきれない部分(黄色の部分)が生じる。実際には黄色部分はグレーで表示されてしまいます。


この状況を回避するための工夫を加えています。具体的には <div id="demoMap"> のサイズを width, height ともに 200% に指定して実際のスマホ画面の4倍の面積のエリアをロードするようにしています(更に left と top を -50% にして、そのロードしたエリアの中心部分だけを表示するよう調整しています。こうすることで表示された画面の中心を軸に画面が自然に回転するようになります)。細かいことですが、この仕様に合わせて <div id="me"> の位置もこの変更に合わせて調整したり、(表示位置がズレないよう)画面にスクロールバーが出ないよう CSS で抑制したりしています:
2020011802


↑地図部分を実画面サイズよりも大きくすることで、回転させても表示不可エリアが生じないように調整しています。


こうした工夫によってなんとか実現できました。ただ地図上に書かれた文字が斜めになってしまうのはさすがにどうしようもないです。その辺りは地図 API 側でサポートしてくれるのを待つしかないかなあ。。

なお index.html 内の JavaScript 変数 lat(緯度), lng(経度)が地図の中心点座標、zoom がズームレベルです。これらの値を変えると表示するエリアや拡大縮小レベルを変えることができますので、自分の環境で挑戦してみたい方は是非挑戦してみてください。