1 of 25

deck.gl

react-map-glを使った

データ可視化

2023/4/6 MIERUNE meetup mini #6

2 of 25

目次

  • deck.gl , react-map-gl とは
  • レイヤ表示
  • 地図表示
  • ズーム機能
  • まとめ

3 of 25

deck.gl

react-map-gl とは

4 of 25

deck.glとは

  • WebGL によるデータ可視化フレームワーク
  • Uber 社が開発した、vis.gl (オープンソースの地理空間可視化フレームワーク群) の1つ

5 of 25

deck.glとは

  • 作成できるレイヤの種類が豊富
  • 大規模なデータセットを可視化できる
  • React との親和性が高い
    • 公式ドキュメントのサンプルコードの多くはReact で書かれている
  • ベースマッププロバイダーと連携が可能
    • Google Maps、 Mapbox、 ArcGISなど

6 of 25

react-map-glとは

    • Mapbox GL JS の React ラッパー
    • vis.gl の1つ

7 of 25

レイヤ表示

8 of 25

レイヤ表示

  • deck.gl にはレイヤがたくさんある
  • 幅広いデータを表示可能
    • GeoJsonLayer: GeoJSON
    • MVTLayer: MVT
    • Tile3DLayer: 3D Tiles
    • PointCloudLayer: 点群

9 of 25

レイヤ表示

  • HeatmapLayer
    • データの空間分布を可視化する

import DeckGL from '@deck.gl/react';

import { HeatmapLayer } from '@deck.gl/aggregation-layers';

�function App({ data, viewState }) {

    const layer = new HeatmapLayer({

        id: 'heatmapLayer',

        data,

        getPosition: (d) => {

            return [d.longitude, d.latitude];

        },

        aggregation: 'SUM',

    });

�    return <DeckGL viewState={viewState} layers={[layer]} />;

}

10 of 25

レイヤ表示

  • HexagonLayer
    • データを六角形ベースに集約する

import DeckGL from '@deck.gl/react';

import { HexagonLayer } from '@deck.gl/aggregation-layers';

�function App({ data, viewState }) {

    const layer = new HexagonLayer({

        id: 'hexagon-layer',

        data,

        pickable: false,

        extruded: true,

        radius: 15000,

        elevationScale: 500,

        getPosition: (d) => {

            return [d.longitude, d.latitude];

        },

    });

�    return <DeckGL viewState={viewState} layers={[layer]} />;

}

11 of 25

レイヤ表示

  • ScatterplotLayer
    • 与えられた座標に円を描画する

import DeckGL from '@deck.gl/react';

import { ScatterplotLayer } from '@deck.gl/layers';

�function App({ data, viewState }) {

    const layer = new ScatterplotLayer({

        id: 'scatterplot-layer',

        data,

        pickable: true,

        opacity: 0.8,

        stroked: true,

        filled: true,

        radiusScale: 30,

        radiusMinPixels: 1,

        radiusMaxPixels: 100,

        lineWidthMinPixels: 1,

        getPosition: (d) => {

            return [d.longitude, d.latitude];

        },

        getRadius: 10,

        getFillColor: (d) => [255, 140, 0],

        getLineColor: (d) => [0, 0, 0],

    });

�    return <DeckGL viewState={viewState} layers={[layer]} />;

}

12 of 25

地図表示

13 of 25

地図表示

  • react-map-gl のMap コンポーネントを使うことで背景地図を表示できる

const App = () => {

    const DeckGLOverlay = (props) => {

        const overlay = useControl(() => new MapboxOverlay(props));

        overlay.setProps(props);

        return null;

    };

    // Mapboxアクセストークン

    const MAPBOX_ACCESS_TOKEN = ‘your_access_token';

    // 初期ビューポートの設定

    const INITIAL_VIEW_STATE = {

        latitude: 38.875584,

        longitude: 139.7454316,

        bearing: 0,

        pitch: 0,

        zoom: 5,

    };

    // LineLayerで使うデータ

    const data = [{ sourcePosition: [139.7454316, 38.875584], targetPosition: [145.7454316, 40.875584] }];

    // LineLayer

    const layers = [new LineLayer({ id: 'line-layer', data })];

    return (

        <div className="App">

            <Map

                initialViewState={INITIAL_VIEW_STATE}

                mapStyle="mapbox://styles/mapbox/light-v9"

                style={{ width: '100vw', height: '100vh' }}

                mapboxAccessToken={MAPBOX_ACCESS_TOKEN}

            >

                <DeckGLOverlay layers={layers} />

            </Map>

        </div>

    );

};

�export default App;

14 of 25

地図表示

(略)

<div className="App">

    <Map

        initialViewState={INITIAL_VIEW_STATE}

        mapStyle="mapbox://styles/mapbox/light-v9"

        style={{ width: '100vw', height: '100vh' }}

        mapboxAccessToken={MAPBOX_ACCESS_TOKEN}

attributionControl={false}

    >

        <DeckGLOverlay layers={layers} />

        {/*  ユーザーの位置を特定するためのボタン */}

        <GeolocateControl />

        {/* フルスクリーンモードのマップをトグルするためのボタン */}

        <FullscreenControl />

        {/* ズームボタンとコンパス */}

        <NavigationControl />

        {/* 地図上の距離と地上の対応する距離の比率を表示 */}

        <ScaleControl />

        {/* 帰属を表示 */}

        <AttributionControl customAttribution="hogehoge"/>

    </Map>

</div>

(略)

  • react-map-gl では地図コントロール用のボタンなども簡単に配置できる

15 of 25

地図表示

  • deck.gl の公式ドキュメントの、Getting Started を参考に実装したら

  地図コントロール用のボタンが押せなかった

ハマりポイント😢

<div className="App">

    <DeckGL

      initialViewState={INITIAL_VIEW_STATE}

      controller={true}

      layers={layers}

    >

        <Map

            mapboxAccessToken={MAPBOX_ACCESS_TOKEN}

            mapStyle="mapbox://styles/mapbox/light-v9"

        >

          <GeolocateControl />

<FullscreenControl />

<NavigationControl />

<ScaleControl />

</Map>

</DeckGL>

</div>

16 of 25

地図表示

  • 原因
    • react-map-gl の要素がdeck.gl の要素よりも下に来てしまったため

ハマりポイント😢

react-map-gl

z-index: -1

deck.gl

z-index: 0

17 of 25

地図表示

  • 解決策
    • deck.gl の公式ドキュメントを漁る
      • Developer Guide に、「deck.gl を react-map-gl v7 のコントロールで使用するには、MapboxOverlay を使用する必要があります。」と書いてあった
      • Example を参考にしたところ、ボタンが押せるようになった

ハマりポイント😢

ChatGPT に聞いても解決しなかった

 「公式ドキュメントを読め高校校歌」

18 of 25

ズーム機能

19 of 25

  • react-map-gl の flyTo() を使うと指定の地点にズームすることができる

export default function App() {

const mapRef = useRef

const onSelectCity = useCallback(({longitude, latitude}) => {

mapRef.current?.flyTo({center: [longitude, latitude], duration: 2000});

}, []);

return (

<>

<Map

ref={mapRef}

initialViewState={initialViewState}

mapStyle="mapbox://styles/mapbox/dark-v9"

mapboxAccessToken={MAPBOX_TOKEN}

/>

<ControlPanel onSelectCity={onSelectCity} />

</>

);

}

ズーム機能

20 of 25

  • react-map-gl 利用時にズーム機能の実装方法が分からなかった
    • react-map-gl のAPI リファレンスに大々的に書いてない
    • ネット記事がない
      • deck.gl なら清水大先生の記事 がある
    • ChatGPT の書いたコードが動かない

ハマりポイント😢

ズーム機能

21 of 25

ズーム機能

  • 解決策
    • react-map-gl の公式ドキュメントを漁る
      • Upgrade Guide に、「FlyToInterpolator は削除されました。代わりにmap.flyTo() を使用してください。」と書いてあった
      • Example を参考にしたところ、ズーム機能を実装できた

ハマりポイント😢

 「公式ドキュメントを読め高校校歌」

22 of 25

まとめ

23 of 25

データ可視化フレームワーク

レイヤの種類が豊富

Mapbox GL JS のReact ラッパー

地図表示、地図コントロールができる

まとめ

組み合わせると

便利!

24 of 25

  • 他のマップライブラリと比べると、公式ドキュメントが充実してない

  • インターネットに文献が少ない

得た知見をアウトプットして、情報量を増やしていく!

まとめ

つらみポイント

25 of 25

ご清聴

ありがとうございました!