お問い合わせ

ブログ

これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。

Vue3でMapboxを使用する - レイヤ、ソース編 -

okuda Okuda 2 years

レイヤを追加する

オリジナルのレイヤをセットする

4つのポイントを線と面で表示するために geojson を作成
任意の場所に設置、今回は \assets\my_geo.json とする

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "id": "My",
            "properties": {
                "name": "My neighborhood"
            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [135.41545700901753, 34.819065318110475],
                            [135.44067870224166, 34.83651233402895],
                            [135.45343746865467, 34.82472403614395],
                            [135.4309363900154, 34.81202795549663]
                        ]
                    ]
                ]
            }
        }
    ]
}

トップレベルにインポートする

import my_geo from "@/assets/my_geo.json";

トップレベルにメソッドを追加

// オリジナルのレイヤをセットする
const setMyLayer = () =>
{
    // ソースがあるかチェック
    const myLayerSource = map.getSource("my-layer-source");

    // ソースがない場合は追加
    if (!myLayerSource) {
        map.addSource("my-layer-source", {
            type: "geojson",
            data: my_geo,
        });
    }

    // レイヤを取得
    const layers = map.getStyle().layers;

    // 面のレイヤがすでにあるかチェック
    const myLayer = layers.find((layer) => layer.id === "my-fill");

    // ある場合
    if (myLayer) {
        // visibilityプロパティをトグルする
        if (map.getLayoutProperty('my-fill', 'visibility') === 'none') {
            // 面のレイヤ
            map.setLayoutProperty('my-fill', 'visibility', 'visible');
            // 線のレイヤ
            map.setLayoutProperty('my-line', 'visibility', 'visible');
            // 点のレイヤ
            map.setLayoutProperty('my-point', 'visibility', 'visible');
        } else {
            // 面のレイヤ
            map.setLayoutProperty('my-fill', 'visibility', 'none');
            // 線のレイヤ
            map.setLayoutProperty('my-line', 'visibility', 'none');
            // 点のレイヤ
            map.setLayoutProperty('my-point', 'visibility', 'none');
        }

    }
    // ない場合は追加
    else {
        // 面のレイヤ追加
        map.addLayer({
            id: "my-fill",
            type: "fill",
            source: "my-layer-source",
            'layout': {
                // デフォルトでレイヤーを表示
                'visibility': 'visible',
            },
            paint: {
                "fill-color": "#943636",
                "fill-opacity": 0.5,
            },
        });

        // 線のレイヤ追加
        map.addLayer({
            id: "my-line",
            type: "line",
            source: "my-layer-source",
            'layout': {
                // デフォルトでレイヤーを表示
                'visibility': 'visible',
                // 接続部を丸く
                'line-join': 'round',
                // 先端を丸く
                'line-cap': 'round',
            },
            paint: {
                "line-color": "#000",
                "line-width": 3,
            },
        });

        // 点のレイヤ追加
        map.addLayer({
            id: "my-point",
            type: "circle",
            source: "my-layer-source",
            'layout': {
                // デフォルトでレイヤーを表示
                'visibility': 'visible',
            },
            'paint': {
                'circle-radius': 10,
                'circle-color': '#F84C4C'
            },
        });

        // 面のレイヤをクリックするとポップアップ
        map.on("click", "my-fill", (e) =>
        {
            new mapboxgl.Popup()
                .setLngLat(e.lngLat)
                .setHTML("my layer!")
                .addTo(map);
        });
    }
};

テンプレート内にボタンを追加

    <button @click="setMyLayer">set my layer</button>

3dの建物のレイヤをセットする

トップレベルにメソッドを追加

// 3dの建物のレイヤをセットする
const setBuilding = () =>
{
    // レイヤーを取得
    const layers = map.getStyle().layers;

    // すでにあるかチェック
    const buildingLayer = layers.find(
        (layer) => layer.id === "add-3d-buildings"
    );

    // ある場合
    if (buildingLayer) {
        // visibilityプロパティをトグルする
        if (map.getLayoutProperty('add-3d-buildings', 'visibility') === 'none') {
            map.setLayoutProperty('add-3d-buildings', 'visibility', 'visible');
        } else {
            map.setLayoutProperty('add-3d-buildings', 'visibility', 'none');
        }
    }
    // ない場合は追加
    else {
        // 任意のシンボルレイヤーの下にレイヤーを挿入
        const labelLayerId = layers.find(
            (layer) => layer.type === "symbol" && layer.layout["text-field"]
        ).id;

        // MapboxStreetsの「building」レイヤー
        // ベクタータイルセットには建物の高さデータが含まる
        map.addLayer(
            {
                id: "add-3d-buildings",
                source: "composite",
                "source-layer": "building",
                'layout': {
                    // デフォルトでレイヤーを表示
                    'visibility': 'visible',
                },
                filter: ["==", "extrude", "true"],
                type: "fill-extrusion",
                minzoom: 15,
                paint: {
                    "fill-extrusion-color": "#aaa", //建物の色
                    "fill-extrusion-height": // 建物の高さ
                        [
                            "interpolate", // スムーズに追加、ニョキッと生えるようになる
                            ["linear"], // 追加時のトランジッション
                            ["zoom"], // ズームインで追加する
                            15,
                            0,
                            15.05,
                            ["get", "height"],
                        ],
                    "fill-extrusion-base": // 建物の基礎高さ
                        [
                            "interpolate",
                            ["linear"],
                            ["zoom"],
                            15,
                            0,
                            15.05,
                            ["get", "min_height"],
                        ],
                    "fill-extrusion-opacity": 0.6,
                },
            },
            labelLayerId
        );
    }
};

テンプレート内にボタンを追加

    <button @click="setBuilding">set building</button>

等高線のレイヤをセットする

トップレベルにメソッドを追加

// 等高線のレイヤをセットする
const setContour = () =>
{
    // ソースがあるかチェック
    const contourSource = map.getSource("contour");

    // ソースがない場合は追加
    if (!contourSource) {
        map.addSource("contour", {
            type: "vector",
            url: 'mapbox://mapbox.mapbox-terrain-v2'
        });
    }

    // レイヤを取得
    const layers = map.getStyle().layers;

    // 面のレイヤがすでにあるかチェック
    const contourLayer = layers.find((layer) => layer.id === "contour-vector");

    // ある場合
    if (contourLayer) {
        if (map.getLayoutProperty('contour-vector', 'visibility') === 'none') {
            map.setLayoutProperty('contour-vector', 'visibility', 'visible');
        } else {
            // 面のレイヤ
            map.setLayoutProperty('contour-vector', 'visibility', 'none');
        }
    }
    // ない場合は追加
    else {
        map.addLayer({
            'id': 'contour-vector',
            'type': 'line',
            'source': 'contour',
            'source-layer': 'contour',
            'layout': {
                'visibility': 'visible',
                'line-join': 'round',
                'line-cap': 'round'
            },
            'paint': {
                'line-color': '#877b59',
                'line-width': 1
            }
        });
    }
}

テンプレート内にボタンを追加

    <button @click="setContour">set contour</button>

空のレイヤをセットする

次の「- 空に太陽を反映編 -」も参照

onMounted のなかの map on load イベントで空レイヤを追加

        // 空のレイヤをセット
        map.addLayer({
            'id': 'sky',
            'type': 'sky',
            'paint': {
                // 空をグラデーションにする
                'sky-type': 'gradient',
                // 空を表現する
                'sky-gradient': [
                        'interpolate',
                        ['linear'],
                        ['sky-radial-progress'],
                        0.8,
                        'rgba(135, 206, 235, 1.0)',
                        1,
                        'rgba(0,0,0,0.1)'
                    ],
                'sky-gradient-center': [0, 0],
                'sky-gradient-radius': 90,
                'sky-opacity': [
                    'interpolate',
                    ['exponential', 0.1],
                    ['zoom'],
                    5,
                    0,
                    22,
                    1
                ]
            }
        });

ソースを追加する

3dの地形のソースをセットする

トップレベルにメソッドを追加

const set3d = () =>
{
    // `mapbox-dem`ソースがすでにあるかチェック
    const terrainSource = map.getSource("mapbox-dem");

    // ない場合は追加
    if (!terrainSource) {
        map.addSource("mapbox-dem", {
            type: "raster-dem",
            url: "mapbox://mapbox.mapbox-terrain-dem-v1",
            tileSize: 512,
            maxzoom: 14,
        });
    }

    // exaggeration 地形の仕様を取得
    const terrain = map.getTerrain();

    // 誇張度をつかってトグルする
    if (terrain?.exaggeration === 1.5) {
        // DEMソースを誇張された高さの解除
        map.setTerrain({source: "mapbox-dem", exaggeration: 0});
    } else {
        // DEMソースを誇張された高さの地形レイヤーとして追加
        map.setTerrain({source: "mapbox-dem", exaggeration: 1.5});
    }
};

テンプレート内にボタンを追加

    <button @click="set3d">set 3d</button>

フォグレイヤをセットする

トップレベルにメソッドを追加

// フォグを追加
const setFog = () =>
{
    const fog = map.getFog();

    if (!fog) {
        map.setFog({
            'range': [-1, 1.5],
            'color': 'white',
            'horizon-blend': 0.1
        });
    } else {
        if (fog.color === 'white') {
            map.setFog({'color': 'rgba(255, 255, 255, 0)'});
        } else {
            map.setFog({'color': 'white'});
        }
    };
}

テンプレート内にボタンを追加

    <button @click="setFog">set fog</button>
Vue3でMapboxを使用する - レイヤ、ソース編 - 2022-03-05 18:25:47

コメントはありません。

4702

お気軽に
お問い合わせください。

お問い合わせ
gomibako@aska-ltd.jp