20m61 / Sonotecture

0 stars 0 forks source link

利用者の座標取得と地図上での表示 #15

Open 20m61 opened 1 month ago

20m61 commented 1 month ago

目的

手順

1. 必要なモジュールのインストール

まず、必要なモジュールをインストールします。deck.gl@luma.gl/core@luma.gl/engineなどを追加します。

yarn add @deck.gl/core @deck.gl/layers @luma.gl/core @luma.gl/engine

また、次のようにnext.config.jsでホストを0.0.0.0に設定し、モバイルでのデバッグも可能にします。

touch next.config.js

次に、next.config.jsに以下の設定を追加します。

module.exports = {
  devIndicators: {
    autoPrerender: false,
  },
  serverRuntimeConfig: {
    host: "0.0.0.0",
    port: 3000,
  },
};

2. データ取得のエラーハンドリング

次に、ユーザーの位置情報とデバイスの向きの取得で発生するPromiseエラーの適切な処理を行います。

lib/getUserLocation.ts
export const getUserLocation = (): Promise<{ latitude: number; longitude: number }> => {
  return new Promise((resolve, reject) => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          resolve({
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          });
        },
        (error) => {
          console.error("Error obtaining location:", error);
          reject(error);
        }
      );
    } else {
      console.error("Geolocation is not supported by this browser.");
      reject(new Error("Geolocation not supported."));
    }
  });
};
lib/deviceOrientation.ts
export const getDeviceOrientation = (callback: (alpha: number) => void) => {
  if (window.DeviceOrientationEvent) {
    window.addEventListener(
      "deviceorientation",
      (event) => {
        const alpha = event.alpha; // 北を基準にデバイスの方位を取得
        callback(alpha);
      },
      true
    );
  } else {
    console.error("Device Orientation is not supported on this device.");
  }
};

3. PLATEAUデータを利用した地図表示

PLATEAUデータをpublicフォルダに配置し、deck.glで読み込めるようにします。

  1. plateau.geojsonpublic/plateau/フォルダに保存。

  2. app/page.tsxでユーザーの座標と向きを使って、deck.gl上にPLATEAUデータを表示するコードを実装します。

app/page.tsx
'use client';

import { useEffect, useState } from "react";
import { Deck } from "@deck.gl/core";
import { GeoJsonLayer } from "@deck.gl/layers";
import { getUserLocation } from "../lib/getUserLocation";
import { getDeviceOrientation } from "../lib/deviceOrientation";

export default function Home() {
  const [userLocation, setUserLocation] = useState<{ latitude: number; longitude: number } | null>(null);
  const [bearing, setBearing] = useState(0); // デバイスの向き

  useEffect(() => {
    // ユーザーの位置情報を取得
    getUserLocation()
      .then((location) => {
        setUserLocation(location);
      })
      .catch((error) => {
        console.error("Error obtaining location", error);
      });

    // デバイスの方角(向き)を取得
    getDeviceOrientation((alpha) => {
      setBearing(alpha); // 方角を更新
    });
  }, []);

  // 初期表示のビューを設定
  const initialViewState = {
    longitude: userLocation?.longitude || 139.6917, // 東京都の経度をデフォルト
    latitude: userLocation?.latitude || 35.6895, // 東京都の緯度をデフォルト
    zoom: 14,
    pitch: 45,
    bearing, // デバイスの向きを反映
  };

  const layers = [
    new GeoJsonLayer({
      id: "buildings-layer",
      data: "/plateau/plateau.geojson", // publicディレクトリ内のGeoJSONファイル
      extruded: true,
      getFillColor: [255, 140, 0],
      getElevation: (d) => d.properties.height || 0, // 建物の高さを反映
    }),
  ];

  // deck.glの地図表示
  useEffect(() => {
    if (userLocation) {
      new Deck({
        initialViewState,
        controller: true,
        layers,
      });
    }
  }, [userLocation, bearing]);

  return <div id="map" style={{ width: "100%", height: "100vh" }} />;
}

4. Unhandled Promise Rejectionエラーの確認

JavaScriptのコンソールで、Promise Rejectionが発生している箇所を追跡するために、以下のようにunhandledrejectionイベントを使用してエラーハンドリングを改善します。

window.addEventListener('unhandledrejection', function (event) {
  console.error('Unhandled promise rejection:', event.reason); // 詳細なエラーメッセージを出力
});