はじめに
NZ Topo50(ニュージーランドの地図)を出したいと言われていて、ググっても全く情報がなくて困っていました。
いくつか地図のサービスを利用してみてできないものかと試した結果になります。
結論としては、出せないものはスタイル作ればいける!(たぶん)
おそらくニッチなネタですね、これ。
更新情報
- 2024/01/31 注意点追加
対象
- 地理院のスタイル
- flutter_maplibre_glのサンプルのスタイル
- Mapbox Studioで作成したスタイル各種
- OpenTopoMapのスタイル
- Maptailer Cloutのスタイル各種
-
NZ Topo50を表示するために作成したスタイル
- 一番やりたかった
提供元 | パターン | 結果 | 備考 |
---|---|---|---|
地理院 | 標準 | 〇 | |
地理院 | 標準改 | 〇 | jsonに背景色を追加しただけ |
地理院 | 淡色地図 | 〇 | |
地理院 | 白地図 | 〇 | |
flutter_maplibre_gl | サンプルのスタイル | 〇 | |
MapBox | WMTS | ✕ | |
MapBox | ArcGIS | ✕ | タイルの提供なのでスタイルの作成が必要 |
MapBox | CARTO | ✕ | タイルの提供なのでスタイルの作成が必要 |
MapBox | Tabeau | ✕ | |
MapBox | Fulcrum | ✕ | CARTOとURL同じだった |
OpenTopoMap | ✕ | 背景の色が変わってタイルの読み込みに失敗しているのでjsonを修正すれば使えるかも? | |
MapTiler | Topo | 〇 | 当然と言えば当然 |
MapTiler | MIERUNE Streets | 〇 | 当然と言えば当然 |
MapTiler | MIERUNE Dark | 〇 | 当然と言えば当然 |
MapTiler | MIERUNE Gray | 〇 | 当然と言えば当然 |
LINZ | NZ Topo50 | 〇 | スタイル作成で表示 |
MaptTlerは当然結果かな(Maplibreの大本だし)
コード
もし、動かしたい場合はアクセストークンなどは用意してコードを修正してください。
Flutter
Flutter側は特に難しいことは何もしていませんね。
DropdownMenuItemの〇✕は地図が出たか出ないか。
あと、何度もスタイル切り替えてると地図が出なくなる事象に遭遇。
なんだろう?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final Completer<MaplibreMapController> _mapController = Completer<MaplibreMapController>();
String _style = _style_gis_std;
static const _style_gis_std = 'https://gsi-cyberjapan.github.io/gsivectortile-mapbox-gl-js/std.json';
static const _style_gis_std2 = 'https://taka-hama.sakura.ne.jp/map/gisjp/std.json';
static const _style_gis_pale = 'https://gsi-cyberjapan.github.io/gsivectortile-mapbox-gl-js/pale.json';
static const _style_gis_blank = 'https://gsi-cyberjapan.github.io/gsivectortile-mapbox-gl-js/blank.json';
static const _style_maplibre_demo = 'https://demotiles.maplibre.org/style.json';
static const _style_mapbox_wmts = 'https://api.mapbox.com/styles/v1/krohigewagm/clqmimy8100am01obh9x8257o/wmts?access_token=xxxxxxxx';
static const _style_mapbox_arcgis = 'https://api.mapbox.com/styles/v1/krohigewagm/clqmimy8100am01obh9x8257o/tiles/256/{level}/{col}/{row}@2x?access_token=xxxxxxxx';
static const _style_mapbox_carto = 'https://api.mapbox.com/styles/v1/krohigewagm/clqmimy8100am01obh9x8257o/tiles/256/{z}/{x}/{y}@2x?access_token=xxxxxxxx';
static const _style_mapbox_tabeau = 'https://api.mapbox.com/styles/v1/krohigewagm/clqmimy8100am01obh9x8257o.html?title=true&access_token=xxxxxxxx';
static const _style_mapbox_fulcrum = 'https://api.mapbox.com/styles/v1/krohigewagm/clqmimy8100am01obh9x8257o/tiles/256/{z}/{x}/{y}@2x?access_token=xxxxxxxx';
static const _style_opentopomap = 'https://hogehoge/opentopomap.json';
static const _style_maptiler_topo = 'https://api.maptiler.com/maps/topo-v2/style.json?key=xxxxxxxx';
static const _style_maptiler_jp_mierune = 'https://api.maptiler.com/maps/jp-mierune-streets/style.json?key=xxxxxxxx';
static const _style_maptiler_jp_mierune_dark = 'https://api.maptiler.com/maps/jp-mierune-dark/style.json?key=xxxxxxxx';
static const _style_maptiler_jp_mierune_gray = 'https://api.maptiler.com/maps/jp-mierune-gray/style.json?key=xxxxxxxx';
static const _style_linz_cs_w = 'https://data.linz.govt.nz/services/csw/?service=CSW&request=GetCapabilities';
static const _style_linz_topo50 = 'https://hogehoge/topo50.json';
@override
Widget build(BuildContext context) {
var textStyle = const TextStyle(color:Colors.black);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Maplibre Style Sample'),
actions: [
DropdownButton(
elevation: 2,
icon:const Icon(Icons.menu, size: 32),
items: [
DropdownMenuItem(
value:_style_gis_std,
child: Row(
children: [
_style == _style_gis_std ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]地理院 標準', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_gis_std2,
child: Row(
children: [
_style == _style_gis_std2 ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]地理院 標準改', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_gis_pale,
child: Row(
children: [
_style == _style_gis_pale ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]地理院 淡色地図', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_gis_blank,
child: Row(
children: [
_style == _style_gis_blank ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]地理院 白地図', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_maplibre_demo,
child: Row(
children: [
_style == _style_maplibre_demo ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]MapLibre demo', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_mapbox_wmts,
child: Row(
children: [
_style == _style_mapbox_wmts ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]MapBox WMTS', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_mapbox_arcgis,
child: Row(
children: [
_style == _style_mapbox_arcgis ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]MapBox ArcGIS', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_mapbox_carto,
child: Row(
children: [
_style == _style_mapbox_carto ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]MapBox CARTO', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_mapbox_tabeau,
child: Row(
children: [
_style == _style_mapbox_tabeau ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]MapBox Tabeau', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_mapbox_fulcrum,
child: Row(
children: [
_style == _style_mapbox_fulcrum ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]MapBox Fulcrum', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_mapbox_fulcrum,
child: Row(
children: [
_style == _style_mapbox_fulcrum ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]MapBox Fulcrum', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_opentopomap,
child: Row(
children: [
_style == _style_opentopomap ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]Open Topo map', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_maptiler_topo,
child: Row(
children: [
_style == _style_maptiler_topo ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]MapTiler topo', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_maptiler_jp_mierune,
child: Row(
children: [
_style == _style_maptiler_jp_mierune ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]MapTiler JP MIERUNE Streets', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_maptiler_jp_mierune_dark,
child: Row(
children: [
_style == _style_maptiler_jp_mierune_dark ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]MapTiler JP MIERUNE Dark', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_maptiler_jp_mierune_gray,
child: Row(
children: [
_style == _style_maptiler_jp_mierune_gray ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[〇]MapTiler JP MIERUNE Gray', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_linz_cs_w,
child: Row(
children: [
_style == _style_linz_cs_w ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]LINZ CS-W', style:textStyle),
],
),
),
DropdownMenuItem(
value:_style_linz_topo50,
child: Row(
children: [
_style == _style_linz_topo50 ? const Icon( Icons.check_box, size: 32) : const Icon( Icons.check_box_outline_blank, size: 32),
Text('[✕]LINZ Topo50', style:textStyle),
],
),
),
], onChanged: (String? value) {
setState(() {
_style = value!;
});
},
),
],
),
body:
MaplibreMap(
styleString: _style,
onStyleLoadedCallback: () {
debugPrint("style loaded");
},
initialCameraPosition: const CameraPosition(
target: LatLng(35.658584, 139.7454316),
zoom: 10.0,
),
onMapCreated: (MaplibreMapController controller) {
_mapController.complete(controller);
},
myLocationEnabled: true,
),
);
}
}
Topo50のスタイル
MapLibre Style Spec を適当に見ただけではだめだった。
ちゃんと読めば分かったかな?
面倒だったので、Maputnikでスタイルをエクスポートしてみたけど、うまくいかず、ChatGPTに聞いたらほぼほぼこの形で教えてくれました。
ちなみに、うまくいかなかった原因は、layersでタイルレイヤーを指定してなかった為。
しかし、情報なくて、お金がかかるのかどうなのかもわからなかった(無料プランがあることが分かったので試せた)
{
"version": 8,
"sources": {
"tiles-source": {
"type": "raster",
"tiles": [
"https://tiles-cdn.koordinates.com/services;key=xxxxx/tiles/v4/layer=50767/EPSG:3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"attribution": "Open Geospatial Consortium" }
},
"layers": [
{
"id": "background",
"type": "background",
"paint": {
"background-color": "rgb(239,239,239)"
}
},
{
"id": "tiles-layer",
"type": "raster",
"source": "tiles-source",
"minzoom": 0,
"maxzoom": 22
}
]
}
注意点
スタイルを切り替えると、シンボルがクリアされるようなので、onStyleLoadedCallbackでシンボルをMaplibreに登録するようにしたほうがよさそう。
参考
- Maputnik
- MapLibre Style Spec
-
NZ Topo50 Maps | WMTS | LINZ Data Service
- ToPo50を使う場合はここに登録が必要
- 料金等のプランは Koordinatesのサイトに載ってる
- ベクトルタイル用スタイルの書き方メモ(Mapbox, Maplibre, ArcGIS API for Javascript)
- MapLibre GL JSのスタイルファイルを読む