1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

記事投稿キャンペーン 「2024年!初アウトプットをしよう」

flutter_maplibre_glでstyleをいろいろ試してみる ※2024/01/31更新

Last updated at Posted at 2024-01-28

はじめに

NZ Topo50(ニュージーランドの地図)を出したいと言われていて、ググっても全く情報がなくて困っていました。
いくつか地図のサービスを利用してみてできないものかと試した結果になります。

結論としては、出せないものはスタイル作ればいける!(たぶん)

おそらくニッチなネタですね、これ。

更新情報

  • 2024/01/31 注意点追加

対象

提供元 パターン 結果 備考
地理院 標準
地理院 標準改 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でタイルレイヤーを指定してなかった為。
しかし、情報なくて、お金がかかるのかどうなのかもわからなかった(無料プランがあることが分かったので試せた)

topo50.json
{
  "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に登録するようにしたほうがよさそう。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?