地図のスタイルを変える
地図のベクタースタイルに「道路を白く」「ラベルを消す」「水域を暗く」といった調整を、ルールとして宣言的にかけるパッケージです。同じルールが Android・iOS でもそのまま使えます。
01 · 概要
ルールは「どのレイヤーに(セレクタ)」「何をするか(パッチ)」の組の並びです。セレクタはレイヤー ID ではなく 役割(道路・水域・ラベル…)で書けます。OpenMapTiles・Shortbread・Mapbox Streets のスキーマは自動で見分けるので、スタイルごとに違うレイヤー ID を調べる必要はありません。
createVectorStyle() が返す値を、どの *MapView にも mapStyle として渡します。React では style が要素自身の CSS なので、名前は mapStyle です(Android・iOS では style)。
rasteriser に VectorTileRasteriserラスタライザーを渡さずにベクター非対応の地図へ渡すと、何も描かずに黙るのではなく、診断に「このスタイルは使えない」と出します。
02 · インストール
npm install @mapconductor/js-sdk-core @mapconductor/js-vectorstyle
ベクター非対応の地図でも使うなら、ラスタライザーの入った react-vectortile も入れます(ベクタータイルレイヤー の Service Worker の準備も要ります)。
npm install @mapconductor/react-vectortile
ESM のみです。ルールのコンパイラは wasm(約 190 KB)で、import.meta.url からの相対で読み込みます。Vite ならそのまま動きます。別の場所から配るときは wasmUrl で指定します。
03 · 基本の使い方
document を省くと、地図がいま描いているスタイル('currentDesign')を調整します。下の例は MapLibre の既定のデザインを、道路だけが見える白黒の地図にします。
import { useMemo } from 'react';
import { buildStyleRules, createVectorStyle, LayerRole } from '@mapconductor/js-vectorstyle';
import { MapLibreMapView2D, useMapLibreViewState } from '@mapconductor/react-for-maplibre';
export function RoadsOnlyMap() {
const state = useMapLibreViewState();
const mapStyle = useMemo(
() => createVectorStyle({
rules: buildStyleRules((r) => {
r.all({ color: '#000000' });
r.role(LayerRole.label, { visible: false });
r.role(LayerRole.roadCasing, { color: '#303030' });
r.role(LayerRole.road, { color: '#ffffff', widthScale: 1.4 });
}),
}),
[],
);
return (
<MapLibreMapView2D
state={state}
mapStyle={mapStyle}
onStyleDiagnostics={(messages) => console.warn(messages)}
/>
);
}自前のスタイルを使うときは document に { url } か { text } を渡します。
04 · ルールの書き方
ルールは上から順に当たり、CSS と同じく項目ごとに後のものが勝ちます。まず all で全体を決め、役割ごとに上書きしていくのが基本です。
buildStyleRules((r) => {
r.all({ colorFilter: { darken: 0.55 } });
r.role(LayerRole.water, { color: 'rgb(10,28,43)' });
r.role(LayerRole.road, { color: '#d0d0d0' });
r.layerId('poi-*', { visible: false });
r.kind('symbol', { opacity: 0.8 });
});* と ? が使える。ルールを JSON で持つ
ルールは JSON の文書でもあります。サーバーから配ったり、アプリの版をまたいで保存したりするときは、この形で持って parseStyleRules() で読みます。同じ文書が Android・iOS でも読めます。
{
"schemaVersion": 1,
"rules": [
{ "selector": "all", "patch": { "colorFilter": { "darken": 0.55 } } },
{ "selector": { "role": "water" }, "patch": { "color": "rgb(10,28,43)" } }
]
}import { createVectorStyle, parseStyleRules } from '@mapconductor/js-vectorstyle';
const rules = parseStyleRules(await (await fetch('/night.rules.json')).text());
const mapStyle = createVectorStyle({ rules });05 · ベクター非対応の地図で使う
VectorTileRasteriser を rasteriser に渡すと、スタイルをラスタータイルに描いて重ねます。プロバイダ自身の地図は None のデザインにして消しておきます。
import { useMemo } from 'react';
import { createVectorStyle } from '@mapconductor/js-vectorstyle';
import { VectorTileRasteriser } from '@mapconductor/react-vectortile';
import { GoogleMapDesign, GoogleMapView2D, useGoogleMapViewState } from '@mapconductor/react-for-googlemaps';
const state = useGoogleMapViewState({
apiKey: import.meta.env.VITE_GOOGLE_MAPS_API_KEY,
mapDesignType: GoogleMapDesign.None,
});
const rasteriser = useMemo(() => new VectorTileRasteriser(), []);
const mapStyle = useMemo(
() => createVectorStyle({
document: { url: 'https://tiles.versatiles.org/assets/styles/colorful/style.json' },
rules,
rasteriser,
}),
[rules, rasteriser],
);
<GoogleMapView2D state={state} mapStyle={mapStyle} style={{ height: 480 }} />new すると別のスタイルとみなされ、地図が毎回作り直されます。useMemo などで1つを持ち続けてください。06 · 主なオプション
{ url, headers? }・{ text }・'currentDesign'。NO_STYLE_RULES なら元のまま。'reload' なら調整済みの文書を丸ごと渡す(正しいが重い)。診断は *MapView の onStyleDiagnostics でも受け取れます。省くとコンソールに出ます。「何にも当たらなかったルール」は、見た目では「ほとんど効いている」としか分からないので、作っている間は見えるところに出しておくのがおすすめです。