From c34fe01757003f034ffe2e14ec3fe437c39f8af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 13 Jul 2025 14:15:36 -0700 Subject: [PATCH 01/30] Add preliminary vector tile loading --- data/maps.gresource.xml | 8 + data/meson.build | 3 +- data/tiles/LICENSE.md | 39 + data/tiles/README.md | 14 + data/tiles/sprites.json | 1689 +++++++++++++++++++++++++++++++++++ data/tiles/sprites.png | Bin 0 -> 45379 bytes data/tiles/sprites@2x.json | 1689 +++++++++++++++++++++++++++++++++++ data/tiles/sprites@2x.png | Bin 0 -> 108021 bytes data/tiles/style.json | 1708 ++++++++++++++++++++++++++++++++++++ src/MainWindow.vala | 10 +- src/MapWidget.vala | 32 + 11 files changed, 5186 insertions(+), 6 deletions(-) create mode 100644 data/tiles/LICENSE.md create mode 100644 data/tiles/README.md create mode 100644 data/tiles/sprites.json create mode 100644 data/tiles/sprites.png create mode 100644 data/tiles/sprites@2x.json create mode 100644 data/tiles/sprites@2x.png create mode 100644 data/tiles/style.json diff --git a/data/maps.gresource.xml b/data/maps.gresource.xml index 59816f6..e52ff8f 100644 --- a/data/maps.gresource.xml +++ b/data/maps.gresource.xml @@ -7,4 +7,12 @@ icons/pointer.svg + + + tiles/style.json + tiles/sprites.json + tiles/sprites@2x.json + tiles/sprites.png + tiles/sprites@2x.png + diff --git a/data/meson.build b/data/meson.build index 99c8def..75def5f 100644 --- a/data/meson.build +++ b/data/meson.build @@ -27,7 +27,8 @@ i18n.merge_file( install_data( 'maps.gschema.xml', - install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' + install_dir: get_option('datadir') / 'glib-2.0' / 'schemas', + rename: meson.project_name() + '.gschema.xml' ) asresources = gnome.compile_resources( diff --git a/data/tiles/LICENSE.md b/data/tiles/LICENSE.md new file mode 100644 index 0000000..7061be1 --- /dev/null +++ b/data/tiles/LICENSE.md @@ -0,0 +1,39 @@ +## Code License + +The Mapbox GL Style JSON file is originally derived from [OSM Bright from Mapbox Open Styles](https://github.com/mapbox/mapbox-gl-styles/blob/master/LICENSE.md). The modified Mapbox GL Style JSON retains the same BSD license. + +> Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +> * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of Mapbox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Design License + +The look and feel of the OSM liberty map design is also derived (although heavily altered) from [OSM Bright from Mapbox Open Styles](https://github.com/mapbox/mapbox-gl-styles/blob/master/LICENSE.md) which is licensed under the Creative Commons Attribution 3.0 license. + +The map is displaying and styling the data from [OpenMapTiles](https://openmaptiles.org/) with [CC-BY 4.0 design license](https://github.com/openmaptiles/openmaptiles/blob/master/LICENSE.md). + +The products or services using this map style need to visibly credit "OpenMapTiles.org" or reference "OpenMapTiles" with a link to http://openmaptiles.org/. For a browsable electronic map based on OpenMapTiles and OpenStreetMap data, the credit should appear in the corner of the map. For example: + +[© OpenMapTiles](https://openmaptiles.org/) +[© OpenStreetMap contributors](https://www.openstreetmap.org/copyright) + +For printed and static maps a similar attribution should be made in a textual description near the image, in the same fashion as if you cite a photograph. + +## Icons + +OSM Liberty is using the [Maki POI icon set](https://github.com/mapbox/maki/blob/master/LICENSE.txt) which is licensed under CC0 1.0 Universal. + +The right arrow was derived from [Wikipedia][wiki_arrow] which is in the public domain. + +[wiki_arrow]: https://commons.wikimedia.org/wiki/File:Arrowright.svg + +## Fonts + +OSM Liberty is using the Roboto font family (Copyright 2011 Google). +Roboto is licensed under the [Apache License, Version 2.0](https://github.com/google/roboto/blob/master/LICENSE). + diff --git a/data/tiles/README.md b/data/tiles/README.md new file mode 100644 index 0000000..0e171cf --- /dev/null +++ b/data/tiles/README.md @@ -0,0 +1,14 @@ +# OSM Liberty style + +This is the vector style used in the demo. It is taken from + at commit [539d0525](https://github.com/maputnik/osm-liberty/commit/539d0525421eb5be901ede630c49947dfe5a343f), +with a few modifications: + +- Removed the Natural Earth raster layer, since libshumate doesn't support that + yet +- Removed the 3D buildings layer, since libshumate doesn't support fill-extrusion + layers yet +- Changed the tile source URL + +OSM Liberty is covered by several licenses. See LICENSE.md, which is copied +from the upstream repository. diff --git a/data/tiles/sprites.json b/data/tiles/sprites.json new file mode 100644 index 0000000..72cefa3 --- /dev/null +++ b/data/tiles/sprites.json @@ -0,0 +1,1689 @@ +{ + "aerialway_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 284, + "y": 127 + }, + "aerialway_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 80, + "y": 190 + }, + "airfield_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 299, + "y": 127 + }, + "airfield_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 99, + "y": 190 + }, + "airport_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 314, + "y": 127 + }, + "airport_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 118, + "y": 190 + }, + "alcohol_shop_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 381, + "y": 210 + }, + "alcohol_shop_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 64, + "y": 0 + }, + "america_football_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 398, + "y": 210 + }, + "america_football_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 85, + "y": 0 + }, + "amusement_park_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 415, + "y": 210 + }, + "amusement_park_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 106, + "y": 0 + }, + "aquarium_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 432, + "y": 210 + }, + "aquarium_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 0, + "y": 64 + }, + "arrow": { + "height": 7, + "pixelRatio": 1, + "width": 20, + "x": 486, + "y": 148 + }, + "art_gallery_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 449, + "y": 210 + }, + "art_gallery_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 21, + "y": 64 + }, + "attraction_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 466, + "y": 210 + }, + "attraction_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 42, + "y": 64 + }, + "bakery_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 483, + "y": 210 + }, + "bakery_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 63, + "y": 64 + }, + "bank_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 227, + "y": 229 + }, + "bank_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 84, + "y": 64 + }, + "bar_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 244, + "y": 229 + }, + "bar_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 105, + "y": 64 + }, + "baseball_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 261, + "y": 229 + }, + "baseball_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 0, + "y": 85 + }, + "basketball_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 278, + "y": 229 + }, + "basketball_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 21, + "y": 85 + }, + "beer_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 295, + "y": 229 + }, + "beer_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 42, + "y": 85 + }, + "bicycle_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 312, + "y": 229 + }, + "bicycle_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 63, + "y": 85 + }, + "bicycle_rental_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 329, + "y": 229 + }, + "bicycle_rental_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 84, + "y": 85 + }, + "building_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 329, + "y": 127 + }, + "building_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 137, + "y": 190 + }, + "bus_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 344, + "y": 127 + }, + "bus_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 156, + "y": 190 + }, + "butcher_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 346, + "y": 229 + }, + "butcher_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 105, + "y": 85 + }, + "cafe_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 363, + "y": 229 + }, + "cafe_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 0, + "y": 106 + }, + "campsite_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 380, + "y": 229 + }, + "campsite_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 21, + "y": 106 + }, + "car_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 359, + "y": 127 + }, + "car_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 175, + "y": 190 + }, + "castle_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 397, + "y": 229 + }, + "castle_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 42, + "y": 106 + }, + "cemetery_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 414, + "y": 229 + }, + "cemetery_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 63, + "y": 106 + }, + "cinema_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 431, + "y": 229 + }, + "cinema_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 84, + "y": 106 + }, + "circle-stroked_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 374, + "y": 127 + }, + "circle-stroked_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 194, + "y": 190 + }, + "circle_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 389, + "y": 127 + }, + "circle_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 213, + "y": 190 + }, + "clothing_store_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 448, + "y": 229 + }, + "clothing_store_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 105, + "y": 106 + }, + "college_11": { + "height": 16, + "pixelRatio": 1, + "width": 16, + "x": 473, + "y": 106 + }, + "college_15": { + "height": 20, + "pixelRatio": 1, + "width": 20, + "x": 0, + "y": 190 + }, + "commercial_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 404, + "y": 127 + }, + "commercial_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 232, + "y": 190 + }, + "cricket_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 465, + "y": 229 + }, + "cricket_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 126, + "y": 64 + }, + "cross_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 419, + "y": 127 + }, + "cross_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 0, + "y": 210 + }, + "dam_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 434, + "y": 127 + }, + "dam_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 19, + "y": 210 + }, + "danger_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 482, + "y": 229 + }, + "danger_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 147, + "y": 64 + }, + "default_1": { + "height": 18, + "pixelRatio": 1, + "width": 18, + "x": 152, + "y": 229 + }, + "default_2": { + "height": 18, + "pixelRatio": 1, + "width": 25, + "x": 170, + "y": 229 + }, + "default_3": { + "height": 18, + "pixelRatio": 1, + "width": 32, + "x": 195, + "y": 229 + }, + "default_4": { + "height": 18, + "pixelRatio": 1, + "width": 39, + "x": 247, + "y": 210 + }, + "default_5": { + "height": 18, + "pixelRatio": 1, + "width": 45, + "x": 286, + "y": 210 + }, + "default_6": { + "height": 18, + "pixelRatio": 1, + "width": 50, + "x": 331, + "y": 210 + }, + "dentist_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 251, + "y": 190 + }, + "dentist_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 168, + "y": 64 + }, + "doctor_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 268, + "y": 190 + }, + "doctor_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 189, + "y": 64 + }, + "dog_park_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 285, + "y": 190 + }, + "dog_park_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 210, + "y": 64 + }, + "dot_10": { + "height": 10, + "pixelRatio": 1, + "width": 10, + "x": 499, + "y": 229 + }, + "dot_11": { + "height": 11, + "pixelRatio": 1, + "width": 11, + "x": 500, + "y": 210 + }, + "dot_9": { + "height": 9, + "pixelRatio": 1, + "width": 9, + "x": 477, + "y": 148 + }, + "drinking-water_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 302, + "y": 190 + }, + "drinking_water_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 231, + "y": 64 + }, + "embassy_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 319, + "y": 190 + }, + "embassy_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 126, + "y": 85 + }, + "entrance_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 449, + "y": 127 + }, + "entrance_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 38, + "y": 210 + }, + "fast_food_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 336, + "y": 190 + }, + "fast_food_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 147, + "y": 85 + }, + "ferry_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 464, + "y": 127 + }, + "ferry_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 57, + "y": 210 + }, + "fire-station_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 353, + "y": 190 + }, + "fire-station_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 168, + "y": 85 + }, + "fuel_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 479, + "y": 127 + }, + "fuel_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 76, + "y": 210 + }, + "garden_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 370, + "y": 190 + }, + "garden_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 189, + "y": 85 + }, + "gift_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 387, + "y": 190 + }, + "gift_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 210, + "y": 85 + }, + "golf_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 404, + "y": 190 + }, + "golf_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 231, + "y": 85 + }, + "grocery_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 421, + "y": 190 + }, + "grocery_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 126, + "y": 106 + }, + "hairdresser_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 438, + "y": 190 + }, + "hairdresser_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 147, + "y": 106 + }, + "harbor_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 494, + "y": 127 + }, + "harbor_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 95, + "y": 210 + }, + "heart_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 455, + "y": 190 + }, + "heart_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 168, + "y": 106 + }, + "heliport_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 252, + "y": 148 + }, + "heliport_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 114, + "y": 210 + }, + "hospital_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 472, + "y": 190 + }, + "hospital_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 189, + "y": 106 + }, + "ice_cream_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 489, + "y": 190 + }, + "ice_cream_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 210, + "y": 106 + }, + "industry_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 267, + "y": 148 + }, + "industry_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 133, + "y": 210 + }, + "information_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 252, + "y": 64 + }, + "information_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 231, + "y": 106 + }, + "laundry_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 269, + "y": 64 + }, + "laundry_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 127, + "y": 0 + }, + "library_11": { + "height": 16, + "pixelRatio": 1, + "width": 16, + "x": 489, + "y": 106 + }, + "library_15": { + "height": 20, + "pixelRatio": 1, + "width": 20, + "x": 20, + "y": 190 + }, + "lighthouse_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 286, + "y": 64 + }, + "lighthouse_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 148, + "y": 0 + }, + "lodging_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 303, + "y": 64 + }, + "lodging_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 169, + "y": 0 + }, + "marker_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 282, + "y": 148 + }, + "marker_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 152, + "y": 210 + }, + "monument_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 320, + "y": 64 + }, + "monument_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 190, + "y": 0 + }, + "mountain_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 337, + "y": 64 + }, + "mountain_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 211, + "y": 0 + }, + "museum_11": { + "height": 16, + "pixelRatio": 1, + "width": 16, + "x": 252, + "y": 127 + }, + "museum_15": { + "height": 20, + "pixelRatio": 1, + "width": 20, + "x": 40, + "y": 190 + }, + "music_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 354, + "y": 64 + }, + "music_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 232, + "y": 0 + }, + "park_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 371, + "y": 64 + }, + "park_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 0, + "y": 127 + }, + "parking_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 297, + "y": 148 + }, + "parking_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 171, + "y": 210 + }, + "parking_garage_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 312, + "y": 148 + }, + "parking_garage_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 190, + "y": 210 + }, + "pedestrian_polygon": { + "height": 64, + "pixelRatio": 1, + "width": 64, + "x": 0, + "y": 0 + }, + "pharmacy_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 388, + "y": 64 + }, + "pharmacy_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 21, + "y": 127 + }, + "picnic_site_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 405, + "y": 64 + }, + "picnic_site_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 42, + "y": 127 + }, + "pitch_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 422, + "y": 64 + }, + "pitch_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 63, + "y": 127 + }, + "place_of_worship_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 439, + "y": 64 + }, + "place_of_worship_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 84, + "y": 127 + }, + "playground_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 456, + "y": 64 + }, + "playground_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 105, + "y": 127 + }, + "police_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 473, + "y": 64 + }, + "police_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 126, + "y": 127 + }, + "post_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 490, + "y": 64 + }, + "post_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 147, + "y": 127 + }, + "prison_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 252, + "y": 85 + }, + "prison_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 168, + "y": 127 + }, + "railway_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 327, + "y": 148 + }, + "railway_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 209, + "y": 210 + }, + "railway_light_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 342, + "y": 148 + }, + "railway_light_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 228, + "y": 210 + }, + "railway_metro_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 357, + "y": 148 + }, + "railway_metro_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 0, + "y": 229 + }, + "ranger_station_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 269, + "y": 85 + }, + "ranger_station_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 189, + "y": 127 + }, + "religious_christian_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 286, + "y": 85 + }, + "religious_christian_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 210, + "y": 127 + }, + "religious_jewish_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 303, + "y": 85 + }, + "religious_jewish_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 231, + "y": 127 + }, + "religious_muslim_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 320, + "y": 85 + }, + "religious_muslim_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 0, + "y": 148 + }, + "restaurant_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 337, + "y": 85 + }, + "restaurant_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 21, + "y": 148 + }, + "roadblock_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 354, + "y": 85 + }, + "roadblock_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 42, + "y": 148 + }, + "rocket_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 371, + "y": 85 + }, + "rocket_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 63, + "y": 148 + }, + "school_11": { + "height": 16, + "pixelRatio": 1, + "width": 16, + "x": 268, + "y": 127 + }, + "school_15": { + "height": 20, + "pixelRatio": 1, + "width": 20, + "x": 60, + "y": 190 + }, + "shelter_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 388, + "y": 85 + }, + "shelter_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 84, + "y": 148 + }, + "shop_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 405, + "y": 85 + }, + "shop_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 105, + "y": 148 + }, + "skiing_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 422, + "y": 85 + }, + "skiing_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 126, + "y": 148 + }, + "soccer_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 439, + "y": 85 + }, + "soccer_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 147, + "y": 148 + }, + "square-stroke_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 372, + "y": 148 + }, + "square-stroke_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 19, + "y": 229 + }, + "square_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 387, + "y": 148 + }, + "square_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 38, + "y": 229 + }, + "stadium_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 456, + "y": 85 + }, + "stadium_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 168, + "y": 148 + }, + "star-stroke_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 402, + "y": 148 + }, + "star-stroke_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 57, + "y": 229 + }, + "star_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 417, + "y": 148 + }, + "star_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 76, + "y": 229 + }, + "suitcase_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 473, + "y": 85 + }, + "suitcase_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 189, + "y": 148 + }, + "sushi_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 490, + "y": 85 + }, + "sushi_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 210, + "y": 148 + }, + "swimming_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 252, + "y": 106 + }, + "swimming_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 231, + "y": 148 + }, + "telephone_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 269, + "y": 106 + }, + "telephone_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 0, + "y": 169 + }, + "tennis_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 286, + "y": 106 + }, + "tennis_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 21, + "y": 169 + }, + "theatre_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 303, + "y": 106 + }, + "theatre_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 42, + "y": 169 + }, + "toilet_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 320, + "y": 106 + }, + "toilet_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 63, + "y": 169 + }, + "town_hall_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 337, + "y": 106 + }, + "town_hall_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 84, + "y": 169 + }, + "triangle_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 432, + "y": 148 + }, + "triangle_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 95, + "y": 229 + }, + "triangle_stroked_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 447, + "y": 148 + }, + "triangle_stroked_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 114, + "y": 229 + }, + "veterinary_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 354, + "y": 106 + }, + "veterinary_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 105, + "y": 169 + }, + "volcano_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 371, + "y": 106 + }, + "volcano_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 126, + "y": 169 + }, + "warehouse_11": { + "height": 15, + "pixelRatio": 1, + "width": 15, + "x": 462, + "y": 148 + }, + "warehouse_15": { + "height": 19, + "pixelRatio": 1, + "width": 19, + "x": 133, + "y": 229 + }, + "waste_basket_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 388, + "y": 106 + }, + "waste_basket_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 147, + "y": 169 + }, + "water_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 405, + "y": 106 + }, + "water_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 168, + "y": 169 + }, + "wetland_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 422, + "y": 106 + }, + "wetland_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 189, + "y": 169 + }, + "wheelchair_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 439, + "y": 106 + }, + "wheelchair_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 210, + "y": 169 + }, + "zoo_11": { + "height": 17, + "pixelRatio": 1, + "width": 17, + "x": 456, + "y": 106 + }, + "zoo_15": { + "height": 21, + "pixelRatio": 1, + "width": 21, + "x": 231, + "y": 169 + } +} \ No newline at end of file diff --git a/data/tiles/sprites.png b/data/tiles/sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..54aa199108a95b904f64dd996e0d7964bd320784 GIT binary patch literal 45379 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⁢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 SWm6af5O})!xvX=", "rank", 20]], + "layout": { + "icon-image": "{class}_11", + "text-anchor": "top", + "text-field": "{name}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 9, + "text-offset": [0, 0.6], + "text-size": 12 + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 0.5, + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "poi_z15", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "poi", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "Point"], + [">=", "rank", 7], + ["<", "rank", 20] + ], + "layout": { + "icon-image": "{class}_11", + "text-anchor": "top", + "text-field": "{name}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 9, + "text-offset": [0, 0.6], + "text-size": 12 + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 0.5, + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "poi_z14", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "poi", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "Point"], + [">=", "rank", 1], + ["<", "rank", 7] + ], + "layout": { + "icon-image": "{class}_11", + "text-anchor": "top", + "text-field": "{name}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 9, + "text-offset": [0, 0.6], + "text-size": 12 + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 0.5, + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "poi_transit", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "poi", + "filter": ["all", ["in", "class", "bus", "rail", "airport"]], + "layout": { + "icon-image": "{class}_11", + "text-anchor": "left", + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 9, + "text-offset": [0.9, 0], + "text-size": 12 + }, + "paint": { + "text-color": "#4898ff", + "text-halo-blur": 0.5, + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "road_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "filter": ["all"], + "layout": { + "symbol-placement": "line", + "text-anchor": "center", + "text-field": "{name}", + "text-font": ["Roboto Regular"], + "text-offset": [0, 0.15], + "text-size": {"base": 1, "stops": [[13, 12], [14, 13]]} + }, + "paint": { + "text-color": "#765", + "text-halo-blur": 0.5, + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "road_shield", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 7, + "filter": ["all", ["<=", "ref_length", 6]], + "layout": { + "icon-image": "default_{ref_length}", + "icon-rotation-alignment": "viewport", + "symbol-placement": {"base": 1, "stops": [[10, "point"], [11, "line"]]}, + "symbol-spacing": 500, + "text-field": "{ref}", + "text-font": ["Roboto Regular"], + "text-offset": [0, 0.1], + "text-rotation-alignment": "viewport", + "text-size": 10, + "icon-size": 0.8 + } + }, + { + "id": "place_other", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "filter": [ + "all", + [ + "in", + "class", + "hamlet", + "island", + "islet", + "neighbourhood", + "suburb", + "quarter" + ] + ], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-letter-spacing": 0.1, + "text-max-width": 9, + "text-size": {"base": 1.2, "stops": [[12, 10], [15, 14]]}, + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#633", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "place_village", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "filter": ["all", ["==", "class", "village"]], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Regular"], + "text-max-width": 8, + "text-size": {"base": 1.2, "stops": [[10, 12], [15, 22]]} + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "place_town", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "filter": ["all", ["==", "class", "town"]], + "layout": { + "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, + "text-anchor": "bottom", + "text-field": "{name_en}", + "text-font": ["Roboto Regular"], + "text-max-width": 8, + "text-offset": [0, 0], + "text-size": {"base": 1.2, "stops": [[7, 12], [11, 16]]} + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "place_city", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 5, + "filter": ["all", ["==", "class", "city"]], + "layout": { + "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, + "text-anchor": "bottom", + "text-field": "{name_en}", + "text-font": ["Roboto Medium"], + "text-max-width": 8, + "text-offset": [0, 0], + "text-size": {"base": 1.2, "stops": [[7, 14], [11, 24]]}, + "icon-allow-overlap": true, + "icon-optional": false + }, + "paint": { + "text-color": "#333", + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1.2 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "state", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 6, + "filter": ["all", ["==", "class", "state"]], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-size": {"stops": [[4, 11], [6, 15]]}, + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#633", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "country_3", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "filter": ["all", [">=", "rank", 3], ["==", "class", "country"]], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 6.25, + "text-size": {"stops": [[3, 11], [7, 17]]}, + "text-transform": "none" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "country_2", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "filter": ["all", ["==", "rank", 2], ["==", "class", "country"]], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 6.25, + "text-size": {"stops": [[2, 11], [5, 17]]}, + "text-transform": "none" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "country_1", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "filter": ["all", ["==", "rank", 1], ["==", "class", "country"]], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-max-width": 6.25, + "text-size": {"stops": [[1, 11], [4, 17]]}, + "text-transform": "none" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + }, + { + "id": "continent", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 1, + "filter": ["all", ["==", "class", "continent"]], + "layout": { + "text-field": "{name_en}", + "text-font": ["Roboto Condensed Italic"], + "text-size": 13, + "text-transform": "uppercase", + "text-justify": "center" + }, + "paint": { + "text-color": "#633", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1 + }, + "metadata": { + "libshumate:cursor": "pointer" + } + } + ], + "id": "osm-liberty" +} diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 611f398..5c44a75 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -100,13 +100,13 @@ public class Maps.MainWindow : Adw.ApplicationWindow { style_submenu.append (_("Light"), "app.color-scheme('%s')".printf (Define.ColorScheme.FORCE_LIGHT)); style_submenu.append (_("Dark"), "app.color-scheme('%s')".printf (Define.ColorScheme.FORCE_DARK)); - var map_source_submenu = new Menu (); - map_source_submenu.append (_("Mapnik"), "win.map-source('%s')".printf (Define.MapSource.MAPNIK)); - map_source_submenu.append (_("Transport"), "win.map-source('%s')".printf (Define.MapSource.TRANSPORT)); + // var map_source_submenu = new Menu (); + // map_source_submenu.append (_("Mapnik"), "win.map-source('%s')".printf (Define.MapSource.MAPNIK)); + // map_source_submenu.append (_("Transport"), "win.map-source('%s')".printf (Define.MapSource.TRANSPORT)); var main_menu = new Menu (); main_menu.append_submenu (_("Style"), style_submenu); - main_menu.append_submenu (_("Map Source"), map_source_submenu); + // main_menu.append_submenu (_("Map Source"), map_source_submenu); var menu_button = new Gtk.MenuButton () { tooltip_text = _("Main Menu"), @@ -136,7 +136,7 @@ public class Maps.MainWindow : Adw.ApplicationWindow { width_request = 700; height_request = 500; - setup_map_source_action (); + // setup_map_source_action (); // Add the marker layer on top after selecting map source map_widget.init_marker_layers (); diff --git a/src/MapWidget.vala b/src/MapWidget.vala index b77ebcc..a153bc8 100644 --- a/src/MapWidget.vala +++ b/src/MapWidget.vala @@ -41,6 +41,38 @@ public class Maps.MapWidget : Gtk.Box { append (map_widget); base_map = map_widget.map; + + try { + load_vector_tiles (); + } catch (Error e) { + critical ("Failed to create vector map style: %s", e.message); + } + + // shumate_map_source_registry_add (self->registry, SHUMATE_MAP_SOURCE (renderer)); + } + + private void load_vector_tiles () throws Error requires (Shumate.VectorRenderer.is_supported ()) { + var bytes = resources_lookup_data ("/io/elementary/maps/tiles/style.json", NONE); + var style_json = (string) bytes.get_data (); + + var sprites_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites.json", NONE); + var sprites_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites.png"); + + var sprites_2x_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites@2x.json", NONE); + var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); + + var renderer = new Shumate.VectorRenderer ("vector-tiles", style_json); + renderer.set_max_zoom_level (22); + renderer.set_license ("© OpenMapTiles © OpenStreetMap contributors"); + + var sprites = renderer.get_sprite_sheet (); + sprites.add_page (sprites_texture, (string) sprites_json.get_data (), 1); + sprites.add_page (sprites_2x_texture, (string) sprites_2x_json.get_data (), 1); + + var map_source_registry = new Shumate.MapSourceRegistry.with_defaults (); + map_source_registry.add (renderer); + + map_widget.map_source = map_source_registry.get_by_id ("vector-tiles"); } public void init_marker_layers () { From ba48ca9898fc436fd64f2d5250ec2d0988481874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 13 Jul 2025 15:24:19 -0700 Subject: [PATCH 02/30] Use elementary palette colors --- data/tiles/style.json | 69 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/data/tiles/style.json b/data/tiles/style.json index d24cc4f..f09307a 100644 --- a/data/tiles/style.json +++ b/data/tiles/style.json @@ -1,6 +1,6 @@ { "version": 8, - "name": "OSM Liberty", + "name": "Granite", "metadata": { "maputnik:license": "https://github.com/maputnik/osm-liberty/blob/gh-pages/LICENSE.md", "maputnik:renderer": "mbgljs", @@ -78,8 +78,8 @@ "filter": ["all", ["==", "class", "grass"]], "paint": { "fill-antialias": false, - "fill-color": "rgba(176, 213, 154, 1)", - "fill-opacity": 0.3 + "fill-color": "#68b723", + "fill-opacity": 0.5 } }, { @@ -162,7 +162,7 @@ "source": "openmaptiles", "source-layer": "water", "filter": ["all", ["!=", "brunnel", "tunnel"]], - "paint": {"fill-color": "rgb(158,189,255)"} + "paint": {"fill-color": "#8cd5ff"} }, { "id": "landcover_sand", @@ -226,7 +226,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-dasharray": [0.5, 0.25], "line-width": { "base": 1.2, @@ -259,7 +259,7 @@ "filter": ["all", ["==", "ramp", 1], ["==", "brunnel", "tunnel"]], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] @@ -298,7 +298,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": {"base": 1.2, "stops": [[8, 1.5], [20, 17]]} } }, @@ -314,7 +314,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] @@ -334,7 +334,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-dasharray": [0.5, 0.25], "line-width": { "base": 1.2, @@ -372,7 +372,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fc8", + "line-color": "#ffe16b", "line-width": { "base": 1.2, "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] @@ -547,7 +547,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] @@ -584,7 +584,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] @@ -626,7 +626,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": {"base": 1.2, "stops": [[8, 1.5], [20, 17]]} } }, @@ -642,7 +642,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] @@ -663,7 +663,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] @@ -703,7 +703,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#fc8", + "line-color": "#ffe16b", "line-width": { "base": 1.2, "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] @@ -740,7 +740,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#fea", + "line-color": "#d4d4d4", "line-width": { "base": 1.2, "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] @@ -776,7 +776,7 @@ ], "layout": {"line-cap": "round", "line-join": "round"}, "paint": { - "line-color": "#fea", + "line-color": "#d4d4d4", "line-width": {"base": 1.2, "stops": [[6.5, 0], [8, 0.5], [20, 13]]} } }, @@ -792,7 +792,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fea", + "line-color": "#d4d4d4", "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} } }, @@ -812,7 +812,7 @@ "paint": { "line-color": { "base": 1, - "stops": [[5, "hsl(26, 87%, 62%)"], [6, "#fc8"]] + "stops": [[5, "#ffe16b"], [6, "#ffe16b"]] }, "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} } @@ -914,7 +914,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] @@ -945,7 +945,7 @@ "filter": ["all", ["==", "class", "link"], ["==", "brunnel", "bridge"]], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] @@ -1001,7 +1001,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": {"base": 1.2, "stops": [[8, 1.5], [20, 17]]} } }, @@ -1017,7 +1017,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] @@ -1037,7 +1037,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#e9ac77", + "line-color": "#abacae", "line-width": { "base": 1.2, "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] @@ -1074,7 +1074,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fc8", + "line-color": "#ffe16b", "line-width": { "base": 1.2, "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] @@ -1105,7 +1105,7 @@ "filter": ["all", ["==", "class", "link"], ["==", "brunnel", "bridge"]], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fea", + "line-color": "#d4d4d4", "line-width": { "base": 1.2, "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] @@ -1136,7 +1136,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fea", + "line-color": "#d4d4d4", "line-width": {"base": 1.2, "stops": [[6.5, 0], [7, 0.5], [20, 10]]} } }, @@ -1152,7 +1152,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fea", + "line-color": "#d4d4d4", "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} } }, @@ -1169,7 +1169,7 @@ ], "layout": {"line-join": "round"}, "paint": { - "line-color": "#fc8", + "line-color": "#ffe16b", "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} } }, @@ -1502,14 +1502,14 @@ ], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Roboto Medium"], "text-letter-spacing": 0.1, "text-max-width": 9, - "text-size": {"base": 1.2, "stops": [[12, 10], [15, 14]]}, + "text-size": {"base": 1.2, "stops": [[12, 16], [15, 20]]}, "text-transform": "uppercase" }, "paint": { - "text-color": "#633", + "text-color": "#333", "text-halo-color": "rgba(255,255,255,0.8)", "text-halo-width": 1.2 }, @@ -1568,6 +1568,7 @@ "source": "openmaptiles", "source-layer": "place", "minzoom": 5, + "maxzoom": 15, "filter": ["all", ["==", "class", "city"]], "layout": { "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, @@ -1576,7 +1577,7 @@ "text-font": ["Roboto Medium"], "text-max-width": 8, "text-offset": [0, 0], - "text-size": {"base": 1.2, "stops": [[7, 14], [11, 24]]}, + "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, "icon-allow-overlap": true, "icon-optional": false }, From 9a360252911be317526ff24de2ca114fb7a2fc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 13 Jul 2025 15:28:14 -0700 Subject: [PATCH 03/30] =?UTF-8?q?Roboto=20=E2=86=92=20Inter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/tiles/style.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/data/tiles/style.json b/data/tiles/style.json index f09307a..b8de645 100644 --- a/data/tiles/style.json +++ b/data/tiles/style.json @@ -1291,7 +1291,7 @@ "filter": ["all", ["==", "$type", "LineString"]], "layout": { "text-field": "{name}", - "text-font": ["Roboto Regular"], + "text-font": ["Inter Regular"], "text-max-width": 5, "text-size": 12, "symbol-placement": "line" @@ -1313,7 +1313,7 @@ "filter": ["==", "$type", "Point"], "layout": { "text-field": "{name}", - "text-font": ["Roboto Regular"], + "text-font": ["Inter Regular"], "text-max-width": 5, "text-size": 12 }, @@ -1337,7 +1337,7 @@ "icon-image": "{class}_11", "text-anchor": "top", "text-field": "{name}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 9, "text-offset": [0, 0.6], "text-size": 12 @@ -1368,7 +1368,7 @@ "icon-image": "{class}_11", "text-anchor": "top", "text-field": "{name}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 9, "text-offset": [0, 0.6], "text-size": 12 @@ -1399,7 +1399,7 @@ "icon-image": "{class}_11", "text-anchor": "top", "text-field": "{name}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 9, "text-offset": [0, 0.6], "text-size": 12 @@ -1424,7 +1424,7 @@ "icon-image": "{class}_11", "text-anchor": "left", "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 9, "text-offset": [0.9, 0], "text-size": 12 @@ -1449,7 +1449,7 @@ "symbol-placement": "line", "text-anchor": "center", "text-field": "{name}", - "text-font": ["Roboto Regular"], + "text-font": ["Inter Regular"], "text-offset": [0, 0.15], "text-size": {"base": 1, "stops": [[13, 12], [14, 13]]} }, @@ -1475,7 +1475,7 @@ "symbol-placement": {"base": 1, "stops": [[10, "point"], [11, "line"]]}, "symbol-spacing": 500, "text-field": "{ref}", - "text-font": ["Roboto Regular"], + "text-font": ["Inter Regular"], "text-offset": [0, 0.1], "text-rotation-alignment": "viewport", "text-size": 10, @@ -1502,7 +1502,7 @@ ], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Medium"], + "text-font": ["Inter Medium"], "text-letter-spacing": 0.1, "text-max-width": 9, "text-size": {"base": 1.2, "stops": [[12, 16], [15, 20]]}, @@ -1525,7 +1525,7 @@ "filter": ["all", ["==", "class", "village"]], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Regular"], + "text-font": ["Inter Regular"], "text-max-width": 8, "text-size": {"base": 1.2, "stops": [[10, 12], [15, 22]]} }, @@ -1548,7 +1548,7 @@ "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, "text-anchor": "bottom", "text-field": "{name_en}", - "text-font": ["Roboto Regular"], + "text-font": ["Inter Regular"], "text-max-width": 8, "text-offset": [0, 0], "text-size": {"base": 1.2, "stops": [[7, 12], [11, 16]]} @@ -1574,7 +1574,7 @@ "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, "text-anchor": "bottom", "text-field": "{name_en}", - "text-font": ["Roboto Medium"], + "text-font": ["Inter Medium"], "text-max-width": 8, "text-offset": [0, 0], "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, @@ -1599,7 +1599,7 @@ "filter": ["all", ["==", "class", "state"]], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-size": {"stops": [[4, 11], [6, 15]]}, "text-transform": "uppercase" }, @@ -1620,7 +1620,7 @@ "filter": ["all", [">=", "rank", 3], ["==", "class", "country"]], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 6.25, "text-size": {"stops": [[3, 11], [7, 17]]}, "text-transform": "none" @@ -1643,7 +1643,7 @@ "filter": ["all", ["==", "rank", 2], ["==", "class", "country"]], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 6.25, "text-size": {"stops": [[2, 11], [5, 17]]}, "text-transform": "none" @@ -1666,7 +1666,7 @@ "filter": ["all", ["==", "rank", 1], ["==", "class", "country"]], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-max-width": 6.25, "text-size": {"stops": [[1, 11], [4, 17]]}, "text-transform": "none" @@ -1690,7 +1690,7 @@ "filter": ["all", ["==", "class", "continent"]], "layout": { "text-field": "{name_en}", - "text-font": ["Roboto Condensed Italic"], + "text-font": ["Inter Condensed Italic"], "text-size": 13, "text-transform": "uppercase", "text-justify": "center" From 59a66959be7f8e8ec624e083651c19c1a2e229ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 13 Jul 2025 15:35:11 -0700 Subject: [PATCH 04/30] Fix river text color --- data/tiles/style.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/tiles/style.json b/data/tiles/style.json index b8de645..6200032 100644 --- a/data/tiles/style.json +++ b/data/tiles/style.json @@ -1297,7 +1297,7 @@ "symbol-placement": "line" }, "paint": { - "text-color": "#5d60be", + "text-color": "#3689e6", "text-halo-color": "rgba(255,255,255,0.7)", "text-halo-width": 1 }, @@ -1318,7 +1318,7 @@ "text-size": 12 }, "paint": { - "text-color": "#5d60be", + "text-color": "#3689e6", "text-halo-color": "rgba(255,255,255,0.7)", "text-halo-width": 1 }, From be36ecfbd5c10fa2fabd3532113ccbfb6817fb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 16 Jul 2025 14:23:52 -0700 Subject: [PATCH 05/30] Start building with Json.Builder --- src/MainWindow.vala | 2 +- src/MapStyle.vala | 70 +++++++++++++++++++++++++++++++++++++++++++++ src/MapWidget.vala | 10 +++++-- src/meson.build | 2 ++ 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/MapStyle.vala diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 206c41b..89b9e4f 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -176,7 +176,7 @@ public class Maps.MainWindow : Adw.ApplicationWindow { width_request = 450; height_request = 500; - setup_map_source_action (); + // setup_map_source_action (); // Add the marker layer on top after selecting map source map_widget.init_marker_layers (); diff --git a/src/MapStyle.vala b/src/MapStyle.vala new file mode 100644 index 0000000..5fe4262 --- /dev/null +++ b/src/MapStyle.vala @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) + */ + +public class Maps.MapStyle : Object { + public static string get_style () { + var builder = new Json.Builder (); + builder.begin_object (); + + builder.set_member_name ("version"); + builder.add_int_value (8); + + builder.set_member_name ("name"); + builder.add_string_value ("Granite Light"); + + builder.set_member_name ("sources"); + builder.begin_object (); + + builder.set_member_name ("vector-tiles"); + builder.begin_object (); + + builder.set_member_name ("type"); + builder.add_string_value ("vector"); + + builder.set_member_name ("tiles"); + builder.begin_array (); + builder.add_string_value ("https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"); + builder.end_array (); + + builder.set_member_name ("minzoom"); + builder.add_int_value (0); + + builder.set_member_name ("maxzoom"); + builder.add_int_value (14); + + builder.end_object (); + + builder.end_object (); + + builder.set_member_name ("layers"); + builder.begin_array (); + + builder.begin_object (); + + builder.set_member_name ("id"); + builder.add_string_value ("background"); + + builder.set_member_name ("type"); + builder.add_string_value ("background"); + + builder.set_member_name ("paint"); + builder.begin_object (); + builder.set_member_name ("background-color"); + builder.add_string_value ("rgb(239,239,239)"); + builder.end_object (); + + builder.end_object (); + + builder.end_array (); + + builder.end_object (); + + var generator = new Json.Generator () { + root = builder.get_root () + }; + + return generator.to_data (null); + } +} diff --git a/src/MapWidget.vala b/src/MapWidget.vala index 4920a40..a31e72e 100644 --- a/src/MapWidget.vala +++ b/src/MapWidget.vala @@ -51,8 +51,8 @@ public class Maps.MapWidget : Gtk.Box { } private void load_vector_tiles () throws Error requires (Shumate.VectorRenderer.is_supported ()) { - var bytes = resources_lookup_data ("/io/elementary/maps/tiles/style.json", NONE); - var style_json = (string) bytes.get_data (); + // var bytes = resources_lookup_data ("/io/elementary/maps/tiles/style.json", NONE); + // var style_json = (string) bytes.get_data (); var sprites_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites.json", NONE); var sprites_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites.png"); @@ -60,7 +60,7 @@ public class Maps.MapWidget : Gtk.Box { var sprites_2x_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites@2x.json", NONE); var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); - var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json); + var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, MapStyle.get_style ()); renderer.set_max_zoom_level (22); renderer.set_license ("© OpenMapTiles © OpenStreetMap contributors"); @@ -70,6 +70,10 @@ public class Maps.MapWidget : Gtk.Box { var map_source_registry = new Shumate.MapSourceRegistry.with_defaults (); map_source_registry.add (renderer); + + map_widget.map_source = map_source_registry.get_by_id (Define.MapID.EXPLORE_LIGHT); + + critical (MapStyle.get_style ()); } public void init_marker_layers () { diff --git a/src/meson.build b/src/meson.build index 61815a5..ca327ae 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,6 +17,7 @@ dependencies = [ # Version limitation for Granite.Bin dependency('granite-7', version: '>= 7.6.0'), dependency('gtk4'), + dependency ('json-glib-1.0'), dependency('libadwaita-1'), dependency('libgeoclue-2.0'), dependency('shumate-1.0'), @@ -27,6 +28,7 @@ sources = files( 'Define.vala', 'MainWindow.vala', 'MapWidget.vala', + 'MapStyle.vala', 'SearchResultItem.vala', 'Util.vala', ) From f398f64e32d17463e78404c21d022e6b46721769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 16 Jul 2025 15:11:27 -0700 Subject: [PATCH 06/30] Super basic styles --- src/MapStyle.vala | 136 +++++++++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index 5fe4262..0219704 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -5,66 +5,116 @@ public class Maps.MapStyle : Object { public static string get_style () { - var builder = new Json.Builder (); - builder.begin_object (); - - builder.set_member_name ("version"); - builder.add_int_value (8); - - builder.set_member_name ("name"); - builder.add_string_value ("Granite Light"); + string BLUEBERRY_100 = "#8cd5ff"; + string LIME_300 = "#9bdb4d"; + + var builder = new Json.Builder ().begin_object (); + + builder.set_member_name ("version").add_int_value (8); + builder.set_member_name ("name").add_string_value ("Granite Light"); + builder.set_member_name ("sources").begin_object (); + builder.set_member_name ("vector-tiles").begin_object (); + builder.set_member_name ("type").add_string_value ("vector"); + builder.set_member_name ("tiles").begin_array (); + builder.add_string_value ("https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"); + builder.end_array (); + builder.set_member_name ("minzoom").add_int_value (0); + builder.set_member_name ("maxzoom").add_int_value (14); + builder.end_object ().end_object (); + + builder.set_member_name ("layers").begin_array (); + + var background_layer = new Layer () { + id = "background", + layer_type = "background" + }; + background_layer.begin_object (builder); - builder.set_member_name ("sources"); - builder.begin_object (); + builder.set_member_name ("paint"); + builder.begin_object (); + builder.set_member_name ("background-color").add_string_value ("rgb(239,239,239)"); + builder.end_object (); - builder.set_member_name ("vector-tiles"); - builder.begin_object (); + builder.end_object (); - builder.set_member_name ("type"); - builder.add_string_value ("vector"); + var park_layer = new Layer () { + id = "park", + layer_type = "fill", + source = "vector-tiles", + source_layer = "park" + }; + park_layer.begin_object (builder); - builder.set_member_name ("tiles"); - builder.begin_array (); - builder.add_string_value ("https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"); - builder.end_array (); + builder.set_member_name ("paint"); + builder.begin_object (); + builder.set_member_name ("fill-color").add_string_value (LIME_300); + builder.set_member_name ("fill-opacity").add_double_value (0.7); + builder.set_member_name ("fill-outline-color").add_string_value ("rgba(95, 208, 100, 1)"); + builder.end_object (); - builder.set_member_name ("minzoom"); - builder.add_int_value (0); + builder.end_object (); - builder.set_member_name ("maxzoom"); - builder.add_int_value (14); + var water_layer = new Layer () { + id = "water", + layer_type = "fill", + source = "vector-tiles", + source_layer = "water" + }; + water_layer.begin_object (builder); + + builder.set_member_name ("filter"); + builder.begin_array (); + builder.add_string_value ("all"); + builder.begin_array (); + builder.add_string_value ("!="); + builder.add_string_value ("brunnel"); + builder.add_string_value ("tunnel"); + builder.end_array (); + builder.end_array (); + + builder.set_member_name ("paint"); + builder.begin_object (); + builder.set_member_name ("fill-color").add_string_value (BLUEBERRY_100); + builder.end_object (); - builder.end_object (); + builder.end_object (); - builder.end_object (); - builder.set_member_name ("layers"); - builder.begin_array (); + builder.end_array ().end_object (); - builder.begin_object (); + var generator = new Json.Generator () { + root = builder.get_root () + }; - builder.set_member_name ("id"); - builder.add_string_value ("background"); + return generator.to_data (null); + } - builder.set_member_name ("type"); - builder.add_string_value ("background"); + private class Layer : Object { + public string id { get; set; } + public string layer_type { get; set; } + public string source { get; set; } + public string source_layer { get; set; } - builder.set_member_name ("paint"); - builder.begin_object (); - builder.set_member_name ("background-color"); - builder.add_string_value ("rgb(239,239,239)"); - builder.end_object (); + public Json.Builder begin_object (Json.Builder builder) { + builder.begin_object (); - builder.end_object (); + if (id != null) { + builder.set_member_name ("id").add_string_value (id); + } - builder.end_array (); + if (layer_type != null) { + builder.set_member_name ("type").add_string_value (layer_type); + } - builder.end_object (); + if (source != null) { + builder.set_member_name ("source").add_string_value (source); + } - var generator = new Json.Generator () { - root = builder.get_root () - }; + if (source_layer != null) { + builder.set_member_name ("source-layer").add_string_value (source_layer); + } - return generator.to_data (null); + return builder; + } } } From d5bfe21118921e732c3ab78e2b1b09030b2187f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 16 Jul 2025 15:31:41 -0700 Subject: [PATCH 07/30] Labels --- src/MapStyle.vala | 87 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index 0219704..daeb405 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -32,7 +32,7 @@ public class Maps.MapStyle : Object { builder.set_member_name ("paint"); builder.begin_object (); - builder.set_member_name ("background-color").add_string_value ("rgb(239,239,239)"); + builder.set_member_name ("background-color").add_string_value ("rgb(239,239,239)"); builder.end_object (); builder.end_object (); @@ -47,9 +47,9 @@ public class Maps.MapStyle : Object { builder.set_member_name ("paint"); builder.begin_object (); - builder.set_member_name ("fill-color").add_string_value (LIME_300); - builder.set_member_name ("fill-opacity").add_double_value (0.7); - builder.set_member_name ("fill-outline-color").add_string_value ("rgba(95, 208, 100, 1)"); + builder.set_member_name ("fill-color").add_string_value (LIME_300); + builder.set_member_name ("fill-opacity").add_double_value (0.7); + builder.set_member_name ("fill-outline-color").add_string_value ("rgba(95, 208, 100, 1)"); builder.end_object (); builder.end_object (); @@ -74,11 +74,78 @@ public class Maps.MapStyle : Object { builder.set_member_name ("paint"); builder.begin_object (); - builder.set_member_name ("fill-color").add_string_value (BLUEBERRY_100); + builder.set_member_name ("fill-color").add_string_value (BLUEBERRY_100); builder.end_object (); builder.end_object (); + var place_city_layer = new Layer () { + id = "place_city", + layer_type = "symbol", + source = "vector-tiles", + source_layer = "place", + min_zoom = 5, + max_zoom = 15 + }; + place_city_layer.begin_object (builder); + + builder.set_member_name ("filter"); + builder.begin_array (); + builder.add_string_value ("all"); + builder.end_array (); + builder.add_string_value ("=="); + builder.add_string_value ("class"); + builder.add_string_value ("city"); + builder.end_array (); + builder.end_array (); + + builder.set_member_name ("layout"); + builder.begin_object (); + builder.set_member_name ("text-anchor").add_string_value ("bottom"); + builder.set_member_name ("text-field").add_string_value ("{name_en}"); + builder.set_member_name ("text-font"); + builder.begin_array (); + builder.add_string_value ("Inter Medium"); + builder.end_array (); + builder.set_member_name ("text-size"); + builder.begin_object (); + builder.set_member_name ("base").add_double_value (1.2); + builder.set_member_name ("stops"); + builder.begin_array (); + builder.begin_array (); + builder.add_int_value (7); + builder.add_int_value (14); + builder.end_array (); + builder.begin_array (); + builder.add_int_value (11); + builder.add_int_value (32); + builder.end_array (); + builder.end_array (); + builder.end_object (); + builder.end_object (); + // "layout": { + // "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, + // "text-anchor": "bottom", + // "text-field": "{name_en}", + // "text-font": ["Inter Medium"], + // "text-max-width": 8, + // "text-offset": [0, 0], + // "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, + // "icon-allow-overlap": true, + // "icon-optional": false + // }, + + builder.set_member_name ("paint"); + builder.begin_object (); + builder.set_member_name ("text-color").add_string_value ("#333"); + builder.end_object (); + + // "metadata": { + // "libshumate:cursor": "pointer" + // } + + builder.end_object (); + builder.end_array ().end_object (); @@ -90,6 +157,8 @@ public class Maps.MapStyle : Object { } private class Layer : Object { + public int max_zoom { get; set; default = -1; } + public int min_zoom { get; set; default = -1; } public string id { get; set; } public string layer_type { get; set; } public string source { get; set; } @@ -114,6 +183,14 @@ public class Maps.MapStyle : Object { builder.set_member_name ("source-layer").add_string_value (source_layer); } + if (min_zoom != -1) { + builder.set_member_name ("minzoom").add_int_value (min_zoom); + } + + if (max_zoom != -1) { + builder.set_member_name ("maxzoom").add_int_value (max_zoom); + } + return builder; } } From 252d7a7f29d8e737bf9feceb5c4d8205e353dc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 17 Jul 2025 11:42:39 -0700 Subject: [PATCH 08/30] Start to use gobject_serialize --- src/MapStyle.vala | 422 ++++++++++++++++++++++++++++----------------- src/MapWidget.vala | 8 +- 2 files changed, 263 insertions(+), 167 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index daeb405..4d7a938 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -4,194 +4,292 @@ */ public class Maps.MapStyle : Object { - public static string get_style () { - string BLUEBERRY_100 = "#8cd5ff"; - string LIME_300 = "#9bdb4d"; - - var builder = new Json.Builder ().begin_object (); - - builder.set_member_name ("version").add_int_value (8); - builder.set_member_name ("name").add_string_value ("Granite Light"); - builder.set_member_name ("sources").begin_object (); - builder.set_member_name ("vector-tiles").begin_object (); - builder.set_member_name ("type").add_string_value ("vector"); - builder.set_member_name ("tiles").begin_array (); - builder.add_string_value ("https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"); - builder.end_array (); - builder.set_member_name ("minzoom").add_int_value (0); - builder.set_member_name ("maxzoom").add_int_value (14); - builder.end_object ().end_object (); - - builder.set_member_name ("layers").begin_array (); + public int version { get; private set; } + public string name { get; construct set; } + public Sources sources { get; private set; } + public Array layers { get; private set; } + + private const string BLUEBERRY_100 = "#8cd5ff"; + private const string LIME_300 = "#9bdb4d"; + + public MapStyle (string name) { + Object (name: name); + } + + construct { + version = 8; + sources = new Sources (); var background_layer = new Layer () { id = "background", - layer_type = "background" + // type = "background", + paint = new Paint () { + background_color = "rgb(239,239,239)" + } }; - background_layer.begin_object (builder); - - builder.set_member_name ("paint"); - builder.begin_object (); - builder.set_member_name ("background-color").add_string_value ("rgb(239,239,239)"); - builder.end_object (); - - builder.end_object (); var park_layer = new Layer () { id = "park", - layer_type = "fill", + // type = "fill", source = "vector-tiles", - source_layer = "park" + source_layer = "park", + paint = new Paint () { + fill_color = LIME_300, + fill_opacity = 0.7, + fill_outline_color = "rgba(95, 208, 100, 1)" + } }; - park_layer.begin_object (builder); - - builder.set_member_name ("paint"); - builder.begin_object (); - builder.set_member_name ("fill-color").add_string_value (LIME_300); - builder.set_member_name ("fill-opacity").add_double_value (0.7); - builder.set_member_name ("fill-outline-color").add_string_value ("rgba(95, 208, 100, 1)"); - builder.end_object (); - - builder.end_object (); var water_layer = new Layer () { id = "water", - layer_type = "fill", - source = "vector-tiles", - source_layer = "water" - }; - water_layer.begin_object (builder); - - builder.set_member_name ("filter"); - builder.begin_array (); - builder.add_string_value ("all"); - builder.begin_array (); - builder.add_string_value ("!="); - builder.add_string_value ("brunnel"); - builder.add_string_value ("tunnel"); - builder.end_array (); - builder.end_array (); - - builder.set_member_name ("paint"); - builder.begin_object (); - builder.set_member_name ("fill-color").add_string_value (BLUEBERRY_100); - builder.end_object (); - - builder.end_object (); - - var place_city_layer = new Layer () { - id = "place_city", - layer_type = "symbol", + // type = "fill", source = "vector-tiles", - source_layer = "place", - min_zoom = 5, - max_zoom = 15 + source_layer = "water", + paint = new Paint () { + fill_color = BLUEBERRY_100 + } }; - place_city_layer.begin_object (builder); - - builder.set_member_name ("filter"); - builder.begin_array (); - builder.add_string_value ("all"); - builder.end_array (); - builder.add_string_value ("=="); - builder.add_string_value ("class"); - builder.add_string_value ("city"); - builder.end_array (); - builder.end_array (); - - builder.set_member_name ("layout"); - builder.begin_object (); - builder.set_member_name ("text-anchor").add_string_value ("bottom"); - builder.set_member_name ("text-field").add_string_value ("{name_en}"); - builder.set_member_name ("text-font"); - builder.begin_array (); - builder.add_string_value ("Inter Medium"); - builder.end_array (); - builder.set_member_name ("text-size"); - builder.begin_object (); - builder.set_member_name ("base").add_double_value (1.2); - builder.set_member_name ("stops"); - builder.begin_array (); - builder.begin_array (); - builder.add_int_value (7); - builder.add_int_value (14); - builder.end_array (); - builder.begin_array (); - builder.add_int_value (11); - builder.add_int_value (32); - builder.end_array (); - builder.end_array (); - builder.end_object (); - builder.end_object (); - // "layout": { - // "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, - // "text-anchor": "bottom", - // "text-field": "{name_en}", - // "text-font": ["Inter Medium"], - // "text-max-width": 8, - // "text-offset": [0, 0], - // "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, - // "icon-allow-overlap": true, - // "icon-optional": false - // }, - - builder.set_member_name ("paint"); - builder.begin_object (); - builder.set_member_name ("text-color").add_string_value ("#333"); - builder.end_object (); - - // "metadata": { - // "libshumate:cursor": "pointer" - // } - - builder.end_object (); - - - builder.end_array ().end_object (); + layers = new Array (); + layers.append_val (background_layer); + layers.append_val (park_layer); + layers.append_val (water_layer); + } + + public string to_string () { var generator = new Json.Generator () { - root = builder.get_root () + root = Json.gobject_serialize (this) }; - return generator.to_data (null); + return generator.to_data (null); } - private class Layer : Object { - public int max_zoom { get; set; default = -1; } - public int min_zoom { get; set; default = -1; } - public string id { get; set; } - public string layer_type { get; set; } - public string source { get; set; } - public string source_layer { get; set; } - - public Json.Builder begin_object (Json.Builder builder) { - builder.begin_object (); + public class Sources : Object { + public VectorTiles vector_tiles { get; private set; } - if (id != null) { - builder.set_member_name ("id").add_string_value (id); - } - - if (layer_type != null) { - builder.set_member_name ("type").add_string_value (layer_type); - } + construct { + vector_tiles = new VectorTiles (); + } - if (source != null) { - builder.set_member_name ("source").add_string_value (source); - } + public class VectorTiles : Object { + // public string type { get; private set; default = "vector"; } + public string[] tiles { get; private set; default = {"https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"}; } + public int maxzoom { get; private set; } + public int minzoom { get; private set; } - if (source_layer != null) { - builder.set_member_name ("source-layer").add_string_value (source_layer); + construct { + maxzoom = 14; + minzoom = 0; } + } + } - if (min_zoom != -1) { - builder.set_member_name ("minzoom").add_int_value (min_zoom); - } + public class Layer : Object { + public string id { get; set; } + // public string type { get; set; } + public string source { get; set; } + public string source_layer { get; set; } + public int max_zoom { get; set; } + public int min_zoom { get; set; } - if (max_zoom != -1) { - builder.set_member_name ("maxzoom").add_int_value (max_zoom); - } + // public string[] filter { get; set; } + public Paint paint { get; set; } + } - return builder; - } + public class Paint : Object { + public double fill_opacity { get; set; } + public string background_color { get; set; } + public string fill_color { get; set; } + public string fill_outline_color { get; set; } } + + // public static string get_style () { + // string BLUEBERRY_100 = "#8cd5ff"; + // string LIME_300 = "#9bdb4d"; + + // var builder = new Json.Builder ().begin_object (); + + + // builder.set_member_name ("sources").begin_object (); + // builder.set_member_name ("vector-tiles").begin_object (); + // builder.set_member_name ("type").add_string_value ("vector"); + // builder.set_member_name ("tiles").begin_array (); + // builder.add_string_value ("https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"); + // builder.end_array (); + // builder.set_member_name ("minzoom").add_int_value (0); + // builder.set_member_name ("maxzoom").add_int_value (14); + // builder.end_object ().end_object (); + + // builder.set_member_name ("layers").begin_array (); + + // var background_layer = new Layer () { + // id = "background", + // layer_type = "background" + // }; + // background_layer.begin_object (builder); + + // builder.set_member_name ("paint"); + // builder.begin_object (); + // builder.set_member_name ("background-color").add_string_value ("rgb(239,239,239)"); + // builder.end_object (); + + // builder.end_object (); + + // var park_layer = new Layer () { + // id = "park", + // layer_type = "fill", + // source = "vector-tiles", + // source_layer = "park" + // }; + // park_layer.begin_object (builder); + + // builder.set_member_name ("paint"); + // builder.begin_object (); + // builder.set_member_name ("fill-color").add_string_value (LIME_300); + // builder.set_member_name ("fill-opacity").add_double_value (0.7); + // builder.set_member_name ("fill-outline-color").add_string_value ("rgba(95, 208, 100, 1)"); + // builder.end_object (); + + // builder.end_object (); + + // var water_layer = new Layer () { + // id = "water", + // layer_type = "fill", + // source = "vector-tiles", + // source_layer = "water" + // }; + // water_layer.begin_object (builder); + + // builder.set_member_name ("filter"); + // builder.begin_array (); + // builder.add_string_value ("all"); + // builder.begin_array (); + // builder.add_string_value ("!="); + // builder.add_string_value ("brunnel"); + // builder.add_string_value ("tunnel"); + // builder.end_array (); + // builder.end_array (); + + // builder.set_member_name ("paint"); + // builder.begin_object (); + // builder.set_member_name ("fill-color").add_string_value (BLUEBERRY_100); + // builder.end_object (); + + // builder.end_object (); + + // var place_city_layer = new Layer () { + // id = "place_city", + // layer_type = "symbol", + // source = "vector-tiles", + // source_layer = "place", + // min_zoom = 5, + // max_zoom = 15 + // }; + // place_city_layer.begin_object (builder); + + // builder.set_member_name ("filter"); + // builder.begin_array (); + // builder.add_string_value ("all"); + // builder.end_array (); + // builder.add_string_value ("=="); + // builder.add_string_value ("class"); + // builder.add_string_value ("city"); + // builder.end_array (); + // builder.end_array (); + + // builder.set_member_name ("layout"); + // builder.begin_object (); + // builder.set_member_name ("text-anchor").add_string_value ("bottom"); + // builder.set_member_name ("text-field").add_string_value ("{name_en}"); + // builder.set_member_name ("text-font"); + // builder.begin_array (); + // builder.add_string_value ("Inter Medium"); + // builder.end_array (); + // builder.set_member_name ("text-size"); + // builder.begin_object (); + // builder.set_member_name ("base").add_double_value (1.2); + // builder.set_member_name ("stops"); + // builder.begin_array (); + // builder.begin_array (); + // builder.add_int_value (7); + // builder.add_int_value (14); + // builder.end_array (); + // builder.begin_array (); + // builder.add_int_value (11); + // builder.add_int_value (32); + // builder.end_array (); + // builder.end_array (); + // builder.end_object (); + // builder.end_object (); + // // "layout": { + // // "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, + // // "text-anchor": "bottom", + // // "text-field": "{name_en}", + // // "text-font": ["Inter Medium"], + // // "text-max-width": 8, + // // "text-offset": [0, 0], + // // "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, + // // "icon-allow-overlap": true, + // // "icon-optional": false + // // }, + + // builder.set_member_name ("paint"); + // builder.begin_object (); + // builder.set_member_name ("text-color").add_string_value ("#333"); + // builder.end_object (); + + // // "metadata": { + // // "libshumate:cursor": "pointer" + // // } + + // builder.end_object (); + + + // builder.end_array ().end_object (); + + // var generator = new Json.Generator () { + // root = builder.get_root () + // }; + + // return generator.to_data (null); + // } + + // private class Layer : Object { + // public int max_zoom { get; set; default = -1; } + // public int min_zoom { get; set; default = -1; } + // public string id { get; set; } + // public string layer_type { get; set; } + // public string source { get; set; } + // public string source_layer { get; set; } + + // public Json.Builder begin_object (Json.Builder builder) { + // builder.begin_object (); + + // if (id != null) { + // builder.set_member_name ("id").add_string_value (id); + // } + + // if (layer_type != null) { + // builder.set_member_name ("type").add_string_value (layer_type); + // } + + // if (source != null) { + // builder.set_member_name ("source").add_string_value (source); + // } + + // if (source_layer != null) { + // builder.set_member_name ("source-layer").add_string_value (source_layer); + // } + + // if (min_zoom != -1) { + // builder.set_member_name ("minzoom").add_int_value (min_zoom); + // } + + // if (max_zoom != -1) { + // builder.set_member_name ("maxzoom").add_int_value (max_zoom); + // } + + // return builder; + // } + // } } diff --git a/src/MapWidget.vala b/src/MapWidget.vala index a31e72e..1309f3d 100644 --- a/src/MapWidget.vala +++ b/src/MapWidget.vala @@ -51,8 +51,8 @@ public class Maps.MapWidget : Gtk.Box { } private void load_vector_tiles () throws Error requires (Shumate.VectorRenderer.is_supported ()) { - // var bytes = resources_lookup_data ("/io/elementary/maps/tiles/style.json", NONE); - // var style_json = (string) bytes.get_data (); + var style_json = new MapStyle ("granite-light").to_string (); + critical (style_json); var sprites_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites.json", NONE); var sprites_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites.png"); @@ -60,7 +60,7 @@ public class Maps.MapWidget : Gtk.Box { var sprites_2x_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites@2x.json", NONE); var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); - var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, MapStyle.get_style ()); + var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json); renderer.set_max_zoom_level (22); renderer.set_license ("© OpenMapTiles © OpenStreetMap contributors"); @@ -72,8 +72,6 @@ public class Maps.MapWidget : Gtk.Box { map_source_registry.add (renderer); map_widget.map_source = map_source_registry.get_by_id (Define.MapID.EXPLORE_LIGHT); - - critical (MapStyle.get_style ()); } public void init_marker_layers () { From 10790cd703b8b6642b422242589508bc2a363136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 18 Jul 2025 20:51:09 -0700 Subject: [PATCH 09/30] Deal with layers array --- src/MapStyle.vala | 57 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index 4d7a938..f4fd8cf 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -3,11 +3,11 @@ * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) */ -public class Maps.MapStyle : Object { +public class Maps.MapStyle : Maps.JsonObject { public int version { get; private set; } public string name { get; construct set; } public Sources sources { get; private set; } - public Array layers { get; private set; } + public Gee.ArrayList layers { get; private set; } private const string BLUEBERRY_100 = "#8cd5ff"; private const string LIME_300 = "#9bdb4d"; @@ -22,7 +22,7 @@ public class Maps.MapStyle : Object { var background_layer = new Layer () { id = "background", - // type = "background", + kind = "background", paint = new Paint () { background_color = "rgb(239,239,239)" } @@ -30,7 +30,7 @@ public class Maps.MapStyle : Object { var park_layer = new Layer () { id = "park", - // type = "fill", + kind = "fill", source = "vector-tiles", source_layer = "park", paint = new Paint () { @@ -42,7 +42,7 @@ public class Maps.MapStyle : Object { var water_layer = new Layer () { id = "water", - // type = "fill", + kind = "fill", source = "vector-tiles", source_layer = "water", paint = new Paint () { @@ -50,10 +50,10 @@ public class Maps.MapStyle : Object { } }; - layers = new Array (); - layers.append_val (background_layer); - layers.append_val (park_layer); - layers.append_val (water_layer); + layers = new Gee.ArrayList (null); + layers.add (background_layer); + layers.add (park_layer); + layers.add (water_layer); } public string to_string () { @@ -71,8 +71,8 @@ public class Maps.MapStyle : Object { vector_tiles = new VectorTiles (); } - public class VectorTiles : Object { - // public string type { get; private set; default = "vector"; } + public class VectorTiles : Maps.JsonObject { + public string kind { get; private set; default = "vector"; } public string[] tiles { get; private set; default = {"https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"}; } public int maxzoom { get; private set; } public int minzoom { get; private set; } @@ -84,9 +84,9 @@ public class Maps.MapStyle : Object { } } - public class Layer : Object { + public class Layer : Maps.JsonObject { public string id { get; set; } - // public string type { get; set; } + public string kind { get; set; } public string source { get; set; } public string source_layer { get; set; } public int max_zoom { get; set; } @@ -96,7 +96,7 @@ public class Maps.MapStyle : Object { public Paint paint { get; set; } } - public class Paint : Object { + public class Paint : Maps.JsonObject { public double fill_opacity { get; set; } public string background_color { get; set; } public string fill_color { get; set; } @@ -293,3 +293,32 @@ public class Maps.MapStyle : Object { // } // } } + +public class Maps.JsonObject : Object, Json.Serializable { + public override Json.Node serialize_property (string prop, Value val, ParamSpec spec) { + var type = spec.value_type; + + if (type.is_a (typeof (Gee.ArrayList))) { + return serialize_list (prop, val, spec); + } + + return default_serialize_property (prop, val, spec); + } + + private static Json.Node serialize_list (string prop, Value val, ParamSpec spec) { + var list = (Gee.ArrayList) val; + if (list == null) { + return new Json.Node (NULL); + } + + var array = new Json.Array (); + foreach (var object in list) { + array.add_element (Json.gobject_serialize (object)); + } + + var node = new Json.Node (ARRAY); + node.set_array (array); + + return node; + } +} From 5c8d5892c25623b3ff5474662ea9316f2fed7f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 18 Jul 2025 20:53:40 -0700 Subject: [PATCH 10/30] Dirty hacks to replace type --- src/MapStyle.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index f4fd8cf..7b4605f 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -61,7 +61,9 @@ public class Maps.MapStyle : Maps.JsonObject { root = Json.gobject_serialize (this) }; - return generator.to_data (null); + var json_string = generator.to_data (null); + + return json_string.replace ("kind", "type"); } public class Sources : Object { From 6245a46a4141bcea6425b3e821f467eadbc535eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 18 Jul 2025 20:58:40 -0700 Subject: [PATCH 11/30] cleanups and fix zoom error --- src/MapStyle.vala | 198 +++++++++++++-------------------------------- src/MapWidget.vala | 2 +- 2 files changed, 55 insertions(+), 145 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index 7b4605f..ca71e95 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -40,120 +40,6 @@ public class Maps.MapStyle : Maps.JsonObject { } }; - var water_layer = new Layer () { - id = "water", - kind = "fill", - source = "vector-tiles", - source_layer = "water", - paint = new Paint () { - fill_color = BLUEBERRY_100 - } - }; - - layers = new Gee.ArrayList (null); - layers.add (background_layer); - layers.add (park_layer); - layers.add (water_layer); - } - - public string to_string () { - var generator = new Json.Generator () { - root = Json.gobject_serialize (this) - }; - - var json_string = generator.to_data (null); - - return json_string.replace ("kind", "type"); - } - - public class Sources : Object { - public VectorTiles vector_tiles { get; private set; } - - construct { - vector_tiles = new VectorTiles (); - } - - public class VectorTiles : Maps.JsonObject { - public string kind { get; private set; default = "vector"; } - public string[] tiles { get; private set; default = {"https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"}; } - public int maxzoom { get; private set; } - public int minzoom { get; private set; } - - construct { - maxzoom = 14; - minzoom = 0; - } - } - } - - public class Layer : Maps.JsonObject { - public string id { get; set; } - public string kind { get; set; } - public string source { get; set; } - public string source_layer { get; set; } - public int max_zoom { get; set; } - public int min_zoom { get; set; } - - // public string[] filter { get; set; } - public Paint paint { get; set; } - } - - public class Paint : Maps.JsonObject { - public double fill_opacity { get; set; } - public string background_color { get; set; } - public string fill_color { get; set; } - public string fill_outline_color { get; set; } - } - - // public static string get_style () { - // string BLUEBERRY_100 = "#8cd5ff"; - // string LIME_300 = "#9bdb4d"; - - // var builder = new Json.Builder ().begin_object (); - - - // builder.set_member_name ("sources").begin_object (); - // builder.set_member_name ("vector-tiles").begin_object (); - // builder.set_member_name ("type").add_string_value ("vector"); - // builder.set_member_name ("tiles").begin_array (); - // builder.add_string_value ("https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"); - // builder.end_array (); - // builder.set_member_name ("minzoom").add_int_value (0); - // builder.set_member_name ("maxzoom").add_int_value (14); - // builder.end_object ().end_object (); - - // builder.set_member_name ("layers").begin_array (); - - // var background_layer = new Layer () { - // id = "background", - // layer_type = "background" - // }; - // background_layer.begin_object (builder); - - // builder.set_member_name ("paint"); - // builder.begin_object (); - // builder.set_member_name ("background-color").add_string_value ("rgb(239,239,239)"); - // builder.end_object (); - - // builder.end_object (); - - // var park_layer = new Layer () { - // id = "park", - // layer_type = "fill", - // source = "vector-tiles", - // source_layer = "park" - // }; - // park_layer.begin_object (builder); - - // builder.set_member_name ("paint"); - // builder.begin_object (); - // builder.set_member_name ("fill-color").add_string_value (LIME_300); - // builder.set_member_name ("fill-opacity").add_double_value (0.7); - // builder.set_member_name ("fill-outline-color").add_string_value ("rgba(95, 208, 100, 1)"); - // builder.end_object (); - - // builder.end_object (); - // var water_layer = new Layer () { // id = "water", // layer_type = "fill", @@ -179,6 +65,16 @@ public class Maps.MapStyle : Maps.JsonObject { // builder.end_object (); + var water_layer = new Layer () { + id = "water", + kind = "fill", + source = "vector-tiles", + source_layer = "water", + paint = new Paint () { + fill_color = BLUEBERRY_100 + } + }; + // var place_city_layer = new Layer () { // id = "place_city", // layer_type = "symbol", @@ -256,44 +152,58 @@ public class Maps.MapStyle : Maps.JsonObject { // return generator.to_data (null); // } - // private class Layer : Object { - // public int max_zoom { get; set; default = -1; } - // public int min_zoom { get; set; default = -1; } - // public string id { get; set; } - // public string layer_type { get; set; } - // public string source { get; set; } - // public string source_layer { get; set; } + layers = new Gee.ArrayList (null); + layers.add (background_layer); + layers.add (park_layer); + layers.add (water_layer); + } + + public string to_string () { + var generator = new Json.Generator () { + root = Json.gobject_serialize (this) + }; - // public Json.Builder begin_object (Json.Builder builder) { - // builder.begin_object (); + return generator.to_data (null).replace ("kind", "type"); + } - // if (id != null) { - // builder.set_member_name ("id").add_string_value (id); - // } + public class Sources : Object { + public VectorTiles vector_tiles { get; private set; } - // if (layer_type != null) { - // builder.set_member_name ("type").add_string_value (layer_type); - // } + construct { + vector_tiles = new VectorTiles (); + } - // if (source != null) { - // builder.set_member_name ("source").add_string_value (source); - // } + public class VectorTiles : Maps.JsonObject { + public string kind { get; private set; default = "vector"; } + public string[] tiles { get; private set; default = {"https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"}; } + public int maxzoom { get; private set; } + public int minzoom { get; private set; } - // if (source_layer != null) { - // builder.set_member_name ("source-layer").add_string_value (source_layer); - // } + construct { + maxzoom = 14; + minzoom = 0; + } + } + } - // if (min_zoom != -1) { - // builder.set_member_name ("minzoom").add_int_value (min_zoom); - // } + public class Layer : Maps.JsonObject { + public string id { get; set; } + public string kind { get; set; } + public string source { get; set; } + public string source_layer { get; set; } + public int max_zoom { get; set; } + public int min_zoom { get; set; } - // if (max_zoom != -1) { - // builder.set_member_name ("maxzoom").add_int_value (max_zoom); - // } + // public string[] filter { get; set; } + public Paint paint { get; set; } + } - // return builder; - // } - // } + public class Paint : Maps.JsonObject { + public double fill_opacity { get; set; } + public string background_color { get; set; } + public string fill_color { get; set; } + public string fill_outline_color { get; set; } + } } public class Maps.JsonObject : Object, Json.Serializable { diff --git a/src/MapWidget.vala b/src/MapWidget.vala index 1309f3d..af02110 100644 --- a/src/MapWidget.vala +++ b/src/MapWidget.vala @@ -61,7 +61,7 @@ public class Maps.MapWidget : Gtk.Box { var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json); - renderer.set_max_zoom_level (22); + renderer.set_max_zoom_level (14); renderer.set_license ("© OpenMapTiles © OpenStreetMap contributors"); var sprites = renderer.get_sprite_sheet (); From b1b67dabd5f4ef151cd84db7e024970bd3ae3e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 18 Jul 2025 21:07:10 -0700 Subject: [PATCH 12/30] More cleanup --- src/MapStyle.vala | 69 +++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index ca71e95..9e7c37e 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -40,13 +40,15 @@ public class Maps.MapStyle : Maps.JsonObject { } }; - // var water_layer = new Layer () { - // id = "water", - // layer_type = "fill", - // source = "vector-tiles", - // source_layer = "water" - // }; - // water_layer.begin_object (builder); + var water_layer = new Layer () { + id = "water", + kind = "fill", + source = "vector-tiles", + source_layer = "water", + paint = new Paint () { + fill_color = BLUEBERRY_100 + } + }; // builder.set_member_name ("filter"); // builder.begin_array (); @@ -65,25 +67,13 @@ public class Maps.MapStyle : Maps.JsonObject { // builder.end_object (); - var water_layer = new Layer () { - id = "water", - kind = "fill", + var place_city_layer = new Layer () { + id = "place_city", + kind = "symbol", source = "vector-tiles", - source_layer = "water", - paint = new Paint () { - fill_color = BLUEBERRY_100 - } - }; - - // var place_city_layer = new Layer () { - // id = "place_city", - // layer_type = "symbol", - // source = "vector-tiles", - // source_layer = "place", - // min_zoom = 5, - // max_zoom = 15 - // }; - // place_city_layer.begin_object (builder); + source_layer = "place", + min_zoom = 5, + max_zoom = 15, // builder.set_member_name ("filter"); // builder.begin_array (); @@ -131,31 +121,19 @@ public class Maps.MapStyle : Maps.JsonObject { // // "icon-optional": false // // }, - // builder.set_member_name ("paint"); - // builder.begin_object (); - // builder.set_member_name ("text-color").add_string_value ("#333"); - // builder.end_object (); - - // // "metadata": { - // // "libshumate:cursor": "pointer" - // // } - - // builder.end_object (); - - - // builder.end_array ().end_object (); - - // var generator = new Json.Generator () { - // root = builder.get_root () - // }; - - // return generator.to_data (null); - // } + paint = new Paint () { + text_color = "#333" + } + }; layers = new Gee.ArrayList (null); layers.add (background_layer); layers.add (park_layer); layers.add (water_layer); + + // // "metadata": { + // // "libshumate:cursor": "pointer" + // // } } public string to_string () { @@ -203,6 +181,7 @@ public class Maps.MapStyle : Maps.JsonObject { public string background_color { get; set; } public string fill_color { get; set; } public string fill_outline_color { get; set; } + public string text_color { get; set; } } } From 166ab193557383fbafc492aa88830683cf285382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 08:37:58 -0700 Subject: [PATCH 13/30] Add more detail --- src/MapStyle.vala | 191 ++++++++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 76 deletions(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index 9e7c37e..320c110 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -11,6 +11,7 @@ public class Maps.MapStyle : Maps.JsonObject { private const string BLUEBERRY_100 = "#8cd5ff"; private const string LIME_300 = "#9bdb4d"; + private const string SILVER_300 = "#d4d4d4"; public MapStyle (string name) { Object (name: name); @@ -23,7 +24,7 @@ public class Maps.MapStyle : Maps.JsonObject { var background_layer = new Layer () { id = "background", kind = "background", - paint = new Paint () { + paint = new Layer.Paint () { background_color = "rgb(239,239,239)" } }; @@ -33,7 +34,7 @@ public class Maps.MapStyle : Maps.JsonObject { kind = "fill", source = "vector-tiles", source_layer = "park", - paint = new Paint () { + paint = new Layer.Paint () { fill_color = LIME_300, fill_opacity = 0.7, fill_outline_color = "rgba(95, 208, 100, 1)" @@ -45,91 +46,96 @@ public class Maps.MapStyle : Maps.JsonObject { kind = "fill", source = "vector-tiles", source_layer = "water", - paint = new Paint () { + // "filter": ["all", ["!=", "brunnel", "tunnel"]], + paint = new Layer.Paint () { fill_color = BLUEBERRY_100 } }; - // builder.set_member_name ("filter"); - // builder.begin_array (); - // builder.add_string_value ("all"); - // builder.begin_array (); - // builder.add_string_value ("!="); - // builder.add_string_value ("brunnel"); - // builder.add_string_value ("tunnel"); - // builder.end_array (); - // builder.end_array (); + var road_motorway_layer = new Layer () { + id = "road_motorway", + kind = "line", + source = "vector-tiles", + source_layer = "transportation", + minzoom = 5, + // "filter": [ + // "all", + // ["!in", "brunnel", "bridge", "tunnel"], + // ["==", "class", "motorway"], + // ["!=", "ramp", 1] + // ], + layout = new Layer.Layout () { + line_cap = "round", + line_join = "round" + }, + paint = new Layer.Paint () { + line_color = new Layer.Paint.LineColor () { + base = 1 + // "stops": [[5, "#ffe16b"], [6, "#ffe16b"]] + }, + line_width = new Layer.Paint.LineWidth () { + base = 1.2 + // "stops": [[5, 0], [7, 1], [20, 18]] + } - // builder.set_member_name ("paint"); - // builder.begin_object (); - // builder.set_member_name ("fill-color").add_string_value (BLUEBERRY_100); - // builder.end_object (); + } + }; - // builder.end_object (); + var building_layer = new Layer () { + id = "building", + kind = "fill", + source = "vector-tiles", + source_layer = "building", + minzoom = 13, + paint = new Layer.Paint () { + fill_color = SILVER_300, + // "fill-outline-color": { + // "base": 1, + // "stops": [[13, "hsla(35, 6%, 79%, 0.32)"], [14, "hsl(35, 6%, 79%)"]] + // } + } + }; var place_city_layer = new Layer () { id = "place_city", kind = "symbol", source = "vector-tiles", source_layer = "place", - min_zoom = 5, - max_zoom = 15, - - // builder.set_member_name ("filter"); - // builder.begin_array (); - // builder.add_string_value ("all"); - // builder.end_array (); - // builder.add_string_value ("=="); - // builder.add_string_value ("class"); - // builder.add_string_value ("city"); - // builder.end_array (); - // builder.end_array (); - - // builder.set_member_name ("layout"); - // builder.begin_object (); - // builder.set_member_name ("text-anchor").add_string_value ("bottom"); - // builder.set_member_name ("text-field").add_string_value ("{name_en}"); - // builder.set_member_name ("text-font"); - // builder.begin_array (); - // builder.add_string_value ("Inter Medium"); - // builder.end_array (); - // builder.set_member_name ("text-size"); - // builder.begin_object (); - // builder.set_member_name ("base").add_double_value (1.2); - // builder.set_member_name ("stops"); - // builder.begin_array (); - // builder.begin_array (); - // builder.add_int_value (7); - // builder.add_int_value (14); - // builder.end_array (); - // builder.begin_array (); - // builder.add_int_value (11); - // builder.add_int_value (32); - // builder.end_array (); - // builder.end_array (); - // builder.end_object (); - // builder.end_object (); - // // "layout": { - // // "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, - // // "text-anchor": "bottom", - // // "text-field": "{name_en}", - // // "text-font": ["Inter Medium"], - // // "text-max-width": 8, - // // "text-offset": [0, 0], - // // "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, - // // "icon-allow-overlap": true, - // // "icon-optional": false - // // }, - - paint = new Paint () { + minzoom = 5, + maxzoom = 15, + + // "filter": ["all", ["==", "class", "city"]], + + layout = new Layer.Layout () { + // "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, + text_anchor = "bottom", + text_field = "{name_en}", // FIXME: Localize properly + text_font = {"Inter Medium"}, + text_max_width = 8, + text_offset = {0, 0}, + text_size = new Layer.Layout.TextSize () { + base = 1.2 + // "stops": [[7, 14], [11, 32]] + }, + icon_allow_overlap = true, + icon_optional = false + }, + paint = new Layer.Paint () { text_color = "#333" } + + // "metadata": { + // "libshumate:cursor": "pointer" + // } }; layers = new Gee.ArrayList (null); layers.add (background_layer); layers.add (park_layer); layers.add (water_layer); + layers.add (road_motorway_layer); + layers.add (building_layer); + layers.add (place_city_layer); // // "metadata": { // // "libshumate:cursor": "pointer" @@ -169,19 +175,52 @@ public class Maps.MapStyle : Maps.JsonObject { public string kind { get; set; } public string source { get; set; } public string source_layer { get; set; } - public int max_zoom { get; set; } - public int min_zoom { get; set; } + public int maxzoom { get; set; } + public int minzoom { get; set; } // public string[] filter { get; set; } + public Layout layout { get; set; } public Paint paint { get; set; } - } - public class Paint : Maps.JsonObject { - public double fill_opacity { get; set; } - public string background_color { get; set; } - public string fill_color { get; set; } - public string fill_outline_color { get; set; } - public string text_color { get; set; } + public class Paint : Maps.JsonObject { + public double fill_opacity { get; set; } + public string background_color { get; set; } + public string fill_color { get; set; } + public string fill_outline_color { get; set; } + public string text_color { get; set; } + public LineColor line_color { get; set;} + public LineWidth line_width { get; set; } + + public class LineColor : Maps.JsonObject { + public double base { get; set; } + } + + public class LineWidth : Maps.JsonObject { + public double base { get; set; } + } + } + + public class Filter : Maps.JsonObject { + + } + + public class Layout : Maps.JsonObject { + public string line_cap { get; set; } + public string line_join { get; set; } + public string text_anchor { get; set; } + public string text_field { get; set; } + public string[] text_font { get; set; } + public int text_max_width { get; set; } + public int[] text_offset { get; set; } // Type `int[]' can not be used for a GLib.Object property + public TextSize text_size { get; set; } + public string text_transform { get; set; } + public bool icon_allow_overlap { get; set; } + public bool icon_optional { get; set; } + + public class TextSize : Maps.JsonObject { + public double base { get; set; } + } + } } } From de2fac3b995a633d458f8e9d1106a18265d56a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 08:45:03 -0700 Subject: [PATCH 14/30] comments, min zoom --- src/MapStyle.vala | 2 +- src/MapWidget.vala | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/MapStyle.vala b/src/MapStyle.vala index 320c110..8949242 100644 --- a/src/MapStyle.vala +++ b/src/MapStyle.vala @@ -164,7 +164,7 @@ public class Maps.MapStyle : Maps.JsonObject { public int minzoom { get; private set; } construct { - maxzoom = 14; + maxzoom = 22; minzoom = 0; } } diff --git a/src/MapWidget.vala b/src/MapWidget.vala index af02110..8f2751a 100644 --- a/src/MapWidget.vala +++ b/src/MapWidget.vala @@ -61,7 +61,9 @@ public class Maps.MapWidget : Gtk.Box { var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json); + // FIXME: Map no longer renders past 14 renderer.set_max_zoom_level (14); + renderer.set_min_zoom_level (2); renderer.set_license ("© OpenMapTiles © OpenStreetMap contributors"); var sprites = renderer.get_sprite_sheet (); From e6b89876f6d2f2c47297d202febf9a957a7ab52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 09:06:58 -0700 Subject: [PATCH 15/30] Drop README since we're building our own style --- data/tiles/README.md | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 data/tiles/README.md diff --git a/data/tiles/README.md b/data/tiles/README.md deleted file mode 100644 index 0e171cf..0000000 --- a/data/tiles/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# OSM Liberty style - -This is the vector style used in the demo. It is taken from - at commit [539d0525](https://github.com/maputnik/osm-liberty/commit/539d0525421eb5be901ede630c49947dfe5a343f), -with a few modifications: - -- Removed the Natural Earth raster layer, since libshumate doesn't support that - yet -- Removed the 3D buildings layer, since libshumate doesn't support fill-extrusion - layers yet -- Changed the tile source URL - -OSM Liberty is covered by several licenses. See LICENSE.md, which is copied -from the upstream repository. From d19e587e744d67c5b1190be618d0004351876c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 09:11:13 -0700 Subject: [PATCH 16/30] Move map renderer stuff to its own folder --- src/meson.build | 4 +++- src/{ => renderers}/MapStyle.vala | 29 ----------------------------- 2 files changed, 3 insertions(+), 30 deletions(-) rename src/{ => renderers}/MapStyle.vala (89%) diff --git a/src/meson.build b/src/meson.build index ca327ae..8e9721e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -28,9 +28,11 @@ sources = files( 'Define.vala', 'MainWindow.vala', 'MapWidget.vala', - 'MapStyle.vala', 'SearchResultItem.vala', 'Util.vala', + + 'renderers' / 'JsonObject.vala', + 'renderers' / 'MapStyle.vala' ) executable( diff --git a/src/MapStyle.vala b/src/renderers/MapStyle.vala similarity index 89% rename from src/MapStyle.vala rename to src/renderers/MapStyle.vala index 8949242..292ecad 100644 --- a/src/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -223,32 +223,3 @@ public class Maps.MapStyle : Maps.JsonObject { } } } - -public class Maps.JsonObject : Object, Json.Serializable { - public override Json.Node serialize_property (string prop, Value val, ParamSpec spec) { - var type = spec.value_type; - - if (type.is_a (typeof (Gee.ArrayList))) { - return serialize_list (prop, val, spec); - } - - return default_serialize_property (prop, val, spec); - } - - private static Json.Node serialize_list (string prop, Value val, ParamSpec spec) { - var list = (Gee.ArrayList) val; - if (list == null) { - return new Json.Node (NULL); - } - - var array = new Json.Array (); - foreach (var object in list) { - array.add_element (Json.gobject_serialize (object)); - } - - var node = new Json.Node (ARRAY); - node.set_array (array); - - return node; - } -} From ba578371a8471387c27914da3bd1d93290e594bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 09:14:05 -0700 Subject: [PATCH 17/30] use properties --- src/Util.vala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Util.vala b/src/Util.vala index 6d1b074..0f3d1ea 100644 --- a/src/Util.vala +++ b/src/Util.vala @@ -70,21 +70,21 @@ namespace Util { var style_json = new Maps.MapStyle (Define.MapID.EXPLORE_LIGHT).to_string (); critical (style_json); + var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json) { + license = "© OpenMapTiles © OpenStreetMap contributors", + max_zoom_level = 14, // FIXME: Map no longer renders past 14 + min_zoom_level = 2 + }; + var sprites_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites.json", NONE); var sprites_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites.png"); var sprites_2x_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites@2x.json", NONE); var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); - var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json); - // FIXME: Map no longer renders past 14 - renderer.set_max_zoom_level (14); - renderer.set_min_zoom_level (2); - renderer.set_license ("© OpenMapTiles © OpenStreetMap contributors"); - var sprites = renderer.get_sprite_sheet (); sprites.add_page (sprites_texture, (string) sprites_json.get_data (), 1); - sprites.add_page (sprites_2x_texture, (string) sprites_2x_json.get_data (), 1); + sprites.add_page (sprites_2x_texture, (string) sprites_2x_json.get_data (), 2); registry.add (renderer); } From d98b951621904b1148f55c559abf0b80e449efce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 09:19:10 -0700 Subject: [PATCH 18/30] Fix zoom --- src/Util.vala | 2 +- src/renderers/MapStyle.vala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Util.vala b/src/Util.vala index 0f3d1ea..53c8775 100644 --- a/src/Util.vala +++ b/src/Util.vala @@ -72,7 +72,7 @@ namespace Util { var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json) { license = "© OpenMapTiles © OpenStreetMap contributors", - max_zoom_level = 14, // FIXME: Map no longer renders past 14 + max_zoom_level = 19, min_zoom_level = 2 }; diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 292ecad..0a21632 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -164,8 +164,8 @@ public class Maps.MapStyle : Maps.JsonObject { public int minzoom { get; private set; } construct { - maxzoom = 22; minzoom = 0; + maxzoom = 14; } } } From 6d71dc23cfa2208a1197597b27559c6118735826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 09:21:39 -0700 Subject: [PATCH 19/30] Remove old style json, add missing JsonObject --- data/tiles/style.json | 1709 --------------------------------- src/renderers/JsonObject.vala | 33 + 2 files changed, 33 insertions(+), 1709 deletions(-) delete mode 100644 data/tiles/style.json create mode 100644 src/renderers/JsonObject.vala diff --git a/data/tiles/style.json b/data/tiles/style.json deleted file mode 100644 index 6200032..0000000 --- a/data/tiles/style.json +++ /dev/null @@ -1,1709 +0,0 @@ -{ - "version": 8, - "name": "Granite", - "metadata": { - "maputnik:license": "https://github.com/maputnik/osm-liberty/blob/gh-pages/LICENSE.md", - "maputnik:renderer": "mbgljs", - "openmaptiles:version": "3.x" - }, - "sources": { - "openmaptiles": { - "type": "vector", - "tiles": ["https://tileserver.gnome.org/data/v3/{z}/{x}/{y}.pbf"], - "minzoom": 0, - "maxzoom": 14 - } - }, - "layers": [ - { - "id": "background", - "type": "background", - "paint": {"background-color": "rgb(239,239,239)"} - }, - { - "id": "park", - "type": "fill", - "source": "openmaptiles", - "source-layer": "park", - "paint": { - "fill-color": "#d8e8c8", - "fill-opacity": 0.7, - "fill-outline-color": "rgba(95, 208, 100, 1)" - } - }, - { - "id": "park_outline", - "type": "line", - "source": "openmaptiles", - "source-layer": "park", - "paint": { - "line-dasharray": [1, 1.5], - "line-color": "rgba(228, 241, 215, 1)" - } - }, - { - "id": "landuse_residential", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landuse", - "maxzoom": 8, - "filter": ["==", "class", "residential"], - "paint": { - "fill-color": { - "base": 1, - "stops": [ - [9, "hsla(0, 3%, 85%, 0.84)"], - [12, "hsla(35, 57%, 88%, 0.49)"] - ] - } - } - }, - { - "id": "landcover_wood", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landcover", - "filter": ["all", ["==", "class", "wood"]], - "paint": { - "fill-antialias": false, - "fill-color": "hsla(98, 61%, 72%, 0.7)", - "fill-opacity": 0.4 - } - }, - { - "id": "landcover_grass", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landcover", - "filter": ["all", ["==", "class", "grass"]], - "paint": { - "fill-antialias": false, - "fill-color": "#68b723", - "fill-opacity": 0.5 - } - }, - { - "id": "landcover_ice", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landcover", - "filter": ["all", ["==", "class", "ice"]], - "paint": { - "fill-antialias": false, - "fill-color": "rgba(224, 236, 236, 1)", - "fill-opacity": 0.8 - } - }, - { - "id": "landuse_cemetery", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landuse", - "filter": ["==", "class", "cemetery"], - "paint": {"fill-color": "hsl(75, 37%, 81%)"} - }, - { - "id": "landuse_hospital", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landuse", - "filter": ["==", "class", "hospital"], - "paint": {"fill-color": "#fde"} - }, - { - "id": "landuse_school", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landuse", - "filter": ["==", "class", "school"], - "paint": {"fill-color": "rgb(236,238,204)"} - }, - { - "id": "waterway_tunnel", - "type": "line", - "source": "openmaptiles", - "source-layer": "waterway", - "filter": ["all", ["==", "brunnel", "tunnel"]], - "paint": { - "line-color": "#a0c8f0", - "line-dasharray": [3, 3], - "line-gap-width": {"stops": [[12, 0], [20, 6]]}, - "line-opacity": 1, - "line-width": {"base": 1.4, "stops": [[8, 1], [20, 2]]} - } - }, - { - "id": "waterway_river", - "type": "line", - "source": "openmaptiles", - "source-layer": "waterway", - "filter": ["all", ["==", "class", "river"], ["!=", "brunnel", "tunnel"]], - "layout": {"line-cap": "round"}, - "paint": { - "line-color": "#a0c8f0", - "line-width": {"base": 1.2, "stops": [[11, 0.5], [20, 6]]} - } - }, - { - "id": "waterway_other", - "type": "line", - "source": "openmaptiles", - "source-layer": "waterway", - "filter": ["all", ["!=", "class", "river"], ["!=", "brunnel", "tunnel"]], - "layout": {"line-cap": "round"}, - "paint": { - "line-color": "#a0c8f0", - "line-width": {"base": 1.3, "stops": [[13, 0.5], [20, 6]]} - } - }, - { - "id": "water", - "type": "fill", - "source": "openmaptiles", - "source-layer": "water", - "filter": ["all", ["!=", "brunnel", "tunnel"]], - "paint": {"fill-color": "#8cd5ff"} - }, - { - "id": "landcover_sand", - "type": "fill", - "source": "openmaptiles", - "source-layer": "landcover", - "filter": ["all", ["==", "class", "sand"]], - "paint": {"fill-color": "rgba(247, 239, 195, 1)"} - }, - { - "id": "aeroway_fill", - "type": "fill", - "source": "openmaptiles", - "source-layer": "aeroway", - "minzoom": 11, - "filter": ["==", "$type", "Polygon"], - "paint": {"fill-color": "rgba(229, 228, 224, 1)", "fill-opacity": 0.7} - }, - { - "id": "aeroway_runway", - "type": "line", - "source": "openmaptiles", - "source-layer": "aeroway", - "minzoom": 11, - "filter": [ - "all", - ["==", "$type", "LineString"], - ["==", "class", "runway"] - ], - "paint": { - "line-color": "#f0ede9", - "line-width": {"base": 1.2, "stops": [[11, 3], [20, 16]]} - } - }, - { - "id": "aeroway_taxiway", - "type": "line", - "source": "openmaptiles", - "source-layer": "aeroway", - "minzoom": 11, - "filter": [ - "all", - ["==", "$type", "LineString"], - ["==", "class", "taxiway"] - ], - "paint": { - "line-color": "#f0ede9", - "line-width": {"base": 1.2, "stops": [[11, 0.5], [20, 6]]} - } - }, - { - "id": "tunnel_motorway_link_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["==", "ramp", 1], - ["==", "brunnel", "tunnel"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-dasharray": [0.5, 0.25], - "line-width": { - "base": 1.2, - "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] - } - } - }, - { - "id": "tunnel_service_track_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "service", "track"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#cfcdca", - "line-dasharray": [0.5, 0.25], - "line-width": {"base": 1.2, "stops": [[15, 1], [16, 4], [20, 11]]} - } - }, - { - "id": "tunnel_link_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "ramp", 1], ["==", "brunnel", "tunnel"]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] - } - } - }, - { - "id": "tunnel_street_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "street", "street_limited"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#cfcdca", - "line-opacity": {"stops": [[12, 0], [12.5, 1]]}, - "line-width": { - "base": 1.2, - "stops": [[12, 0.5], [13, 1], [14, 4], [20, 15]] - } - } - }, - { - "id": "tunnel_secondary_tertiary_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "secondary", "tertiary"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": {"base": 1.2, "stops": [[8, 1.5], [20, 17]]} - } - }, - { - "id": "tunnel_trunk_primary_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "primary", "trunk"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] - } - } - }, - { - "id": "tunnel_motorway_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["!=", "ramp", 1], - ["==", "brunnel", "tunnel"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-dasharray": [0.5, 0.25], - "line-width": { - "base": 1.2, - "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] - } - } - }, - { - "id": "tunnel_path_pedestrian", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "$type", "LineString"], - ["==", "brunnel", "tunnel"], - ["in", "class", "path", "pedestrian"] - ], - "paint": { - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [1, 0.75], - "line-width": {"base": 1.2, "stops": [[14, 0.5], [20, 10]]} - } - }, - { - "id": "tunnel_motorway_link", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["==", "ramp", 1], - ["==", "brunnel", "tunnel"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#ffe16b", - "line-width": { - "base": 1.2, - "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] - } - } - }, - { - "id": "tunnel_service_track", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "service", "track"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff", - "line-width": {"base": 1.2, "stops": [[15.5, 0], [16, 2], [20, 7.5]]} - } - }, - { - "id": "tunnel_link", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "ramp", 1], ["==", "brunnel", "tunnel"]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff4c6", - "line-width": { - "base": 1.2, - "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] - } - } - }, - { - "id": "tunnel_minor", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "brunnel", "tunnel"], ["in", "class", "minor"]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff", - "line-width": {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 11.5]]} - } - }, - { - "id": "tunnel_secondary_tertiary", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "secondary", "tertiary"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff4c6", - "line-width": {"base": 1.2, "stops": [[6.5, 0], [7, 0.5], [20, 10]]} - } - }, - { - "id": "tunnel_trunk_primary", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "primary", "trunk"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff4c6", - "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} - } - }, - { - "id": "tunnel_motorway", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["!=", "ramp", 1], - ["==", "brunnel", "tunnel"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#ffdaa6", - "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} - } - }, - { - "id": "tunnel_major_rail", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "brunnel", "tunnel"], ["in", "class", "rail"]], - "paint": { - "line-color": "#bbb", - "line-width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]} - } - }, - { - "id": "tunnel_major_rail_hatching", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "brunnel", "tunnel"], ["==", "class", "rail"]], - "paint": { - "line-color": "#bbb", - "line-dasharray": [0.2, 8], - "line-width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]} - } - }, - { - "id": "tunnel_transit_rail", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["in", "class", "transit"] - ], - "paint": { - "line-color": "#bbb", - "line-width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]} - } - }, - { - "id": "tunnel_transit_rail_hatching", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "tunnel"], - ["==", "class", "transit"] - ], - "paint": { - "line-color": "#bbb", - "line-dasharray": [0.2, 8], - "line-width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]} - } - }, - { - "id": "road_area_pattern", - "type": "fill", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "$type", "Polygon"]], - "paint": {"fill-pattern": "pedestrian_polygon"} - }, - { - "id": "road_motorway_link_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 12, - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "motorway"], - ["==", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] - } - } - }, - { - "id": "road_service_track_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "service", "track"] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#cfcdca", - "line-width": {"base": 1.2, "stops": [[15, 1], [16, 4], [20, 11]]} - } - }, - { - "id": "road_link_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 13, - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["!in", "class", "pedestrian", "path", "track", "service", "motorway"], - ["==", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] - } - } - }, - { - "id": "road_minor_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "$type", "LineString"], - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "minor"], - ["!=", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#cfcdca", - "line-opacity": {"stops": [[12, 0], [12.5, 1]]}, - "line-width": { - "base": 1.2, - "stops": [[12, 0.5], [13, 1], [14, 4], [20, 20]] - } - } - }, - { - "id": "road_secondary_tertiary_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "secondary", "tertiary"], - ["!=", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": {"base": 1.2, "stops": [[8, 1.5], [20, 17]]} - } - }, - { - "id": "road_trunk_primary_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "primary", "trunk"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] - } - } - }, - { - "id": "road_motorway_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 5, - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "motorway"], - ["!=", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] - } - } - }, - { - "id": "road_path_pedestrian", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 14, - "filter": [ - "all", - ["==", "$type", "LineString"], - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "path", "pedestrian"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [1, 0.7], - "line-width": {"base": 1.2, "stops": [[14, 1], [20, 10]]} - } - }, - { - "id": "road_motorway_link", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 12, - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "motorway"], - ["==", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#ffe16b", - "line-width": { - "base": 1.2, - "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] - } - } - }, - { - "id": "road_service_track", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "service", "track"] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#fff", - "line-width": {"base": 1.2, "stops": [[15.5, 0], [16, 2], [20, 7.5]]} - } - }, - { - "id": "road_link", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 13, - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "ramp", 1], - ["!in", "class", "pedestrian", "path", "track", "service", "motorway"] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#d4d4d4", - "line-width": { - "base": 1.2, - "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] - } - } - }, - { - "id": "road_minor", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "$type", "LineString"], - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "minor"] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#fff", - "line-width": {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 18]]} - } - }, - { - "id": "road_secondary_tertiary", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "secondary", "tertiary"] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "#d4d4d4", - "line-width": {"base": 1.2, "stops": [[6.5, 0], [8, 0.5], [20, 13]]} - } - }, - { - "id": "road_trunk_primary", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["in", "class", "primary", "trunk"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#d4d4d4", - "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} - } - }, - { - "id": "road_motorway", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 5, - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "motorway"], - ["!=", "ramp", 1] - ], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": { - "base": 1, - "stops": [[5, "#ffe16b"], [6, "#ffe16b"]] - }, - "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} - } - }, - { - "id": "road_major_rail", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "rail"] - ], - "paint": { - "line-color": "#bbb", - "line-width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]} - } - }, - { - "id": "road_major_rail_hatching", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "rail"] - ], - "paint": { - "line-color": "#bbb", - "line-dasharray": [0.2, 8], - "line-width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]} - } - }, - { - "id": "road_transit_rail", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "transit"] - ], - "paint": { - "line-color": "#bbb", - "line-width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]} - } - }, - { - "id": "road_transit_rail_hatching", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["!in", "brunnel", "bridge", "tunnel"], - ["==", "class", "transit"] - ], - "paint": { - "line-color": "#bbb", - "line-dasharray": [0.2, 8], - "line-width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]} - } - }, - { - "id": "road_one_way_arrow", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 15, - "filter": ["==", "oneway", 1], - "layout": {"icon-image": "arrow", "symbol-placement": "line"} - }, - { - "id": "road_one_way_arrow_opposite", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "transportation", - "minzoom": 15, - "filter": ["==", "oneway", -1], - "layout": { - "icon-image": "arrow", - "symbol-placement": "line", - "icon-rotate": 180 - } - }, - { - "id": "bridge_motorway_link_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["==", "ramp", 1], - ["==", "brunnel", "bridge"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] - } - } - }, - { - "id": "bridge_service_track_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "service", "track"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#cfcdca", - "line-width": {"base": 1.2, "stops": [[15, 1], [16, 4], [20, 11]]} - } - }, - { - "id": "bridge_link_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "class", "link"], ["==", "brunnel", "bridge"]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[12, 1], [13, 3], [14, 4], [20, 15]] - } - } - }, - { - "id": "bridge_street_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "street", "street_limited"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "hsl(36, 6%, 74%)", - "line-opacity": {"stops": [[12, 0], [12.5, 1]]}, - "line-width": { - "base": 1.2, - "stops": [[12, 0.5], [13, 1], [14, 4], [20, 25]] - } - } - }, - { - "id": "bridge_path_pedestrian_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "$type", "LineString"], - ["==", "brunnel", "bridge"], - ["in", "class", "path", "pedestrian"] - ], - "paint": { - "line-color": "hsl(35, 6%, 80%)", - "line-dasharray": [1, 0], - "line-width": {"base": 1.2, "stops": [[14, 1.5], [20, 18]]} - } - }, - { - "id": "bridge_secondary_tertiary_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "secondary", "tertiary"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": {"base": 1.2, "stops": [[8, 1.5], [20, 17]]} - } - }, - { - "id": "bridge_trunk_primary_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "primary", "trunk"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] - } - } - }, - { - "id": "bridge_motorway_casing", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["!=", "ramp", 1], - ["==", "brunnel", "bridge"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#abacae", - "line-width": { - "base": 1.2, - "stops": [[5, 0.4], [6, 0.7], [7, 1.75], [20, 22]] - } - } - }, - { - "id": "bridge_path_pedestrian", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "$type", "LineString"], - ["==", "brunnel", "bridge"], - ["in", "class", "path", "pedestrian"] - ], - "paint": { - "line-color": "hsl(0, 0%, 100%)", - "line-dasharray": [1, 0.3], - "line-width": {"base": 1.2, "stops": [[14, 0.5], [20, 10]]} - } - }, - { - "id": "bridge_motorway_link", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["==", "ramp", 1], - ["==", "brunnel", "bridge"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#ffe16b", - "line-width": { - "base": 1.2, - "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] - } - } - }, - { - "id": "bridge_service_track", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "service", "track"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff", - "line-width": {"base": 1.2, "stops": [[15.5, 0], [16, 2], [20, 7.5]]} - } - }, - { - "id": "bridge_link", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "class", "link"], ["==", "brunnel", "bridge"]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#d4d4d4", - "line-width": { - "base": 1.2, - "stops": [[12.5, 0], [13, 1.5], [14, 2.5], [20, 11.5]] - } - } - }, - { - "id": "bridge_street", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "brunnel", "bridge"], ["in", "class", "minor"]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#fff", - "line-width": {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 18]]} - } - }, - { - "id": "bridge_secondary_tertiary", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "secondary", "tertiary"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#d4d4d4", - "line-width": {"base": 1.2, "stops": [[6.5, 0], [7, 0.5], [20, 10]]} - } - }, - { - "id": "bridge_trunk_primary", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "brunnel", "bridge"], - ["in", "class", "primary", "trunk"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#d4d4d4", - "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} - } - }, - { - "id": "bridge_motorway", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "motorway"], - ["!=", "ramp", 1], - ["==", "brunnel", "bridge"] - ], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#ffe16b", - "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} - } - }, - { - "id": "bridge_major_rail", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "class", "rail"], ["==", "brunnel", "bridge"]], - "paint": { - "line-color": "#bbb", - "line-width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]} - } - }, - { - "id": "bridge_major_rail_hatching", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": ["all", ["==", "class", "rail"], ["==", "brunnel", "bridge"]], - "paint": { - "line-color": "#bbb", - "line-dasharray": [0.2, 8], - "line-width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]} - } - }, - { - "id": "bridge_transit_rail", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "transit"], - ["==", "brunnel", "bridge"] - ], - "paint": { - "line-color": "#bbb", - "line-width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]} - } - }, - { - "id": "bridge_transit_rail_hatching", - "type": "line", - "source": "openmaptiles", - "source-layer": "transportation", - "filter": [ - "all", - ["==", "class", "transit"], - ["==", "brunnel", "bridge"] - ], - "paint": { - "line-color": "#bbb", - "line-dasharray": [0.2, 8], - "line-width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]} - } - }, - { - "id": "building", - "type": "fill", - "source": "openmaptiles", - "source-layer": "building", - "minzoom": 13, - "paint": { - "fill-color": "hsl(35, 8%, 85%)", - "fill-outline-color": { - "base": 1, - "stops": [[13, "hsla(35, 6%, 79%, 0.32)"], [14, "hsl(35, 6%, 79%)"]] - } - } - }, - { - "id": "boundary_3", - "type": "line", - "source": "openmaptiles", - "source-layer": "boundary", - "minzoom": 8, - "filter": ["all", ["in", "admin_level", 3, 4]], - "layout": {"line-join": "round"}, - "paint": { - "line-color": "#9e9cab", - "line-dasharray": [5, 1], - "line-width": {"base": 1, "stops": [[4, 0.4], [5, 1], [12, 1.8]]} - } - }, - { - "id": "boundary_2_z0-4", - "type": "line", - "source": "openmaptiles", - "source-layer": "boundary", - "maxzoom": 5, - "filter": ["all", ["==", "admin_level", 2], ["!has", "claimed_by"]], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "hsl(248, 1%, 41%)", - "line-opacity": {"base": 1, "stops": [[0, 0.4], [4, 1]]}, - "line-width": {"base": 1, "stops": [[3, 1], [5, 1.2], [12, 3]]} - } - }, - { - "id": "boundary_2_z5-", - "type": "line", - "source": "openmaptiles", - "source-layer": "boundary", - "minzoom": 5, - "filter": ["all", ["==", "admin_level", 2]], - "layout": {"line-cap": "round", "line-join": "round"}, - "paint": { - "line-color": "hsl(248, 1%, 41%)", - "line-opacity": {"base": 1, "stops": [[0, 0.4], [4, 1]]}, - "line-width": {"base": 1, "stops": [[3, 1], [5, 1.2], [12, 3]]} - } - }, - { - "id": "water_name_line", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "waterway", - "filter": ["all", ["==", "$type", "LineString"]], - "layout": { - "text-field": "{name}", - "text-font": ["Inter Regular"], - "text-max-width": 5, - "text-size": 12, - "symbol-placement": "line" - }, - "paint": { - "text-color": "#3689e6", - "text-halo-color": "rgba(255,255,255,0.7)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "water_name_point", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "water_name", - "filter": ["==", "$type", "Point"], - "layout": { - "text-field": "{name}", - "text-font": ["Inter Regular"], - "text-max-width": 5, - "text-size": 12 - }, - "paint": { - "text-color": "#3689e6", - "text-halo-color": "rgba(255,255,255,0.7)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "poi_z16", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "poi", - "minzoom": 16, - "filter": ["all", ["==", "$type", "Point"], [">=", "rank", 20]], - "layout": { - "icon-image": "{class}_11", - "text-anchor": "top", - "text-field": "{name}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 9, - "text-offset": [0, 0.6], - "text-size": 12 - }, - "paint": { - "text-color": "#666", - "text-halo-blur": 0.5, - "text-halo-color": "#ffffff", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "poi_z15", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "poi", - "minzoom": 15, - "filter": [ - "all", - ["==", "$type", "Point"], - [">=", "rank", 7], - ["<", "rank", 20] - ], - "layout": { - "icon-image": "{class}_11", - "text-anchor": "top", - "text-field": "{name}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 9, - "text-offset": [0, 0.6], - "text-size": 12 - }, - "paint": { - "text-color": "#666", - "text-halo-blur": 0.5, - "text-halo-color": "#ffffff", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "poi_z14", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "poi", - "minzoom": 14, - "filter": [ - "all", - ["==", "$type", "Point"], - [">=", "rank", 1], - ["<", "rank", 7] - ], - "layout": { - "icon-image": "{class}_11", - "text-anchor": "top", - "text-field": "{name}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 9, - "text-offset": [0, 0.6], - "text-size": 12 - }, - "paint": { - "text-color": "#666", - "text-halo-blur": 0.5, - "text-halo-color": "#ffffff", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "poi_transit", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "poi", - "filter": ["all", ["in", "class", "bus", "rail", "airport"]], - "layout": { - "icon-image": "{class}_11", - "text-anchor": "left", - "text-field": "{name_en}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 9, - "text-offset": [0.9, 0], - "text-size": 12 - }, - "paint": { - "text-color": "#4898ff", - "text-halo-blur": 0.5, - "text-halo-color": "#ffffff", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "road_label", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "transportation_name", - "filter": ["all"], - "layout": { - "symbol-placement": "line", - "text-anchor": "center", - "text-field": "{name}", - "text-font": ["Inter Regular"], - "text-offset": [0, 0.15], - "text-size": {"base": 1, "stops": [[13, 12], [14, 13]]} - }, - "paint": { - "text-color": "#765", - "text-halo-blur": 0.5, - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "road_shield", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "transportation_name", - "minzoom": 7, - "filter": ["all", ["<=", "ref_length", 6]], - "layout": { - "icon-image": "default_{ref_length}", - "icon-rotation-alignment": "viewport", - "symbol-placement": {"base": 1, "stops": [[10, "point"], [11, "line"]]}, - "symbol-spacing": 500, - "text-field": "{ref}", - "text-font": ["Inter Regular"], - "text-offset": [0, 0.1], - "text-rotation-alignment": "viewport", - "text-size": 10, - "icon-size": 0.8 - } - }, - { - "id": "place_other", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "filter": [ - "all", - [ - "in", - "class", - "hamlet", - "island", - "islet", - "neighbourhood", - "suburb", - "quarter" - ] - ], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Medium"], - "text-letter-spacing": 0.1, - "text-max-width": 9, - "text-size": {"base": 1.2, "stops": [[12, 16], [15, 20]]}, - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#333", - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1.2 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "place_village", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "filter": ["all", ["==", "class", "village"]], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Regular"], - "text-max-width": 8, - "text-size": {"base": 1.2, "stops": [[10, 12], [15, 22]]} - }, - "paint": { - "text-color": "#333", - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1.2 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "place_town", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "filter": ["all", ["==", "class", "town"]], - "layout": { - "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, - "text-anchor": "bottom", - "text-field": "{name_en}", - "text-font": ["Inter Regular"], - "text-max-width": 8, - "text-offset": [0, 0], - "text-size": {"base": 1.2, "stops": [[7, 12], [11, 16]]} - }, - "paint": { - "text-color": "#333", - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1.2 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "place_city", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "minzoom": 5, - "maxzoom": 15, - "filter": ["all", ["==", "class", "city"]], - "layout": { - "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, - "text-anchor": "bottom", - "text-field": "{name_en}", - "text-font": ["Inter Medium"], - "text-max-width": 8, - "text-offset": [0, 0], - "text-size": {"base": 1.2, "stops": [[7, 14], [11, 32]]}, - "icon-allow-overlap": true, - "icon-optional": false - }, - "paint": { - "text-color": "#333", - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1.2 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "state", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "maxzoom": 6, - "filter": ["all", ["==", "class", "state"]], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Condensed Italic"], - "text-size": {"stops": [[4, 11], [6, 15]]}, - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#633", - "text-halo-color": "rgba(255,255,255,0.7)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "country_3", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "filter": ["all", [">=", "rank", 3], ["==", "class", "country"]], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 6.25, - "text-size": {"stops": [[3, 11], [7, 17]]}, - "text-transform": "none" - }, - "paint": { - "text-color": "#334", - "text-halo-blur": 1, - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "country_2", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "filter": ["all", ["==", "rank", 2], ["==", "class", "country"]], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 6.25, - "text-size": {"stops": [[2, 11], [5, 17]]}, - "text-transform": "none" - }, - "paint": { - "text-color": "#334", - "text-halo-blur": 1, - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "country_1", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "filter": ["all", ["==", "rank", 1], ["==", "class", "country"]], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Condensed Italic"], - "text-max-width": 6.25, - "text-size": {"stops": [[1, 11], [4, 17]]}, - "text-transform": "none" - }, - "paint": { - "text-color": "#334", - "text-halo-blur": 1, - "text-halo-color": "rgba(255,255,255,0.8)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - }, - { - "id": "continent", - "type": "symbol", - "source": "openmaptiles", - "source-layer": "place", - "maxzoom": 1, - "filter": ["all", ["==", "class", "continent"]], - "layout": { - "text-field": "{name_en}", - "text-font": ["Inter Condensed Italic"], - "text-size": 13, - "text-transform": "uppercase", - "text-justify": "center" - }, - "paint": { - "text-color": "#633", - "text-halo-color": "rgba(255,255,255,0.7)", - "text-halo-width": 1 - }, - "metadata": { - "libshumate:cursor": "pointer" - } - } - ], - "id": "osm-liberty" -} diff --git a/src/renderers/JsonObject.vala b/src/renderers/JsonObject.vala new file mode 100644 index 0000000..1ee2f1a --- /dev/null +++ b/src/renderers/JsonObject.vala @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) + */ + +public class Maps.JsonObject : Object, Json.Serializable { + public override Json.Node serialize_property (string prop, Value val, ParamSpec spec) { + var type = spec.value_type; + + if (type.is_a (typeof (Gee.ArrayList))) { + return serialize_list (prop, val, spec); + } + + return default_serialize_property (prop, val, spec); + } + + private static Json.Node serialize_list (string prop, Value val, ParamSpec spec) { + var list = (Gee.ArrayList) val; + if (list == null) { + return new Json.Node (NULL); + } + + var array = new Json.Array (); + foreach (var object in list) { + array.add_element (Json.gobject_serialize (object)); + } + + var node = new Json.Node (ARRAY); + node.set_array (array); + + return node; + } +} From 59d3c85931713290868aa3deab2ae360d8b0cdca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 09:54:26 -0700 Subject: [PATCH 20/30] Add some docs links, line color is a string --- src/renderers/MapStyle.vala | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 0a21632..614cf14 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -3,12 +3,16 @@ * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) */ + +// https://openmaptiles.org/docs/style/mapbox-gl-style-spec/ +// https://openmaptiles.org/schema/ public class Maps.MapStyle : Maps.JsonObject { public int version { get; private set; } public string name { get; construct set; } public Sources sources { get; private set; } public Gee.ArrayList layers { get; private set; } + private const string BANANA_300 = "#ffe16b"; private const string BLUEBERRY_100 = "#8cd5ff"; private const string LIME_300 = "#9bdb4d"; private const string SILVER_300 = "#d4d4d4"; @@ -69,10 +73,7 @@ public class Maps.MapStyle : Maps.JsonObject { line_join = "round" }, paint = new Layer.Paint () { - line_color = new Layer.Paint.LineColor () { - base = 1 - // "stops": [[5, "#ffe16b"], [6, "#ffe16b"]] - }, + line_color = BANANA_300, line_width = new Layer.Paint.LineWidth () { base = 1.2 // "stops": [[5, 0], [7, 1], [20, 18]] @@ -170,6 +171,7 @@ public class Maps.MapStyle : Maps.JsonObject { } } + // https://docs.maptiler.com/gl-style-specification/layers/ public class Layer : Maps.JsonObject { public string id { get; set; } public string kind { get; set; } @@ -182,28 +184,21 @@ public class Maps.MapStyle : Maps.JsonObject { public Layout layout { get; set; } public Paint paint { get; set; } + // https://docs.maptiler.com/gl-style-specification/layers/#paint-property public class Paint : Maps.JsonObject { public double fill_opacity { get; set; } public string background_color { get; set; } public string fill_color { get; set; } public string fill_outline_color { get; set; } public string text_color { get; set; } - public LineColor line_color { get; set;} + public string line_color { get; set;} public LineWidth line_width { get; set; } - public class LineColor : Maps.JsonObject { - public double base { get; set; } - } - public class LineWidth : Maps.JsonObject { public double base { get; set; } } } - public class Filter : Maps.JsonObject { - - } - public class Layout : Maps.JsonObject { public string line_cap { get; set; } public string line_join { get; set; } @@ -211,7 +206,7 @@ public class Maps.MapStyle : Maps.JsonObject { public string text_field { get; set; } public string[] text_font { get; set; } public int text_max_width { get; set; } - public int[] text_offset { get; set; } // Type `int[]' can not be used for a GLib.Object property + public double[] text_offset { get; set; } public TextSize text_size { get; set; } public string text_transform { get; set; } public bool icon_allow_overlap { get; set; } From 37b6b9aacd996cb50b370b77ad5e81151907c8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 11:14:34 -0700 Subject: [PATCH 21/30] Basic filters --- src/renderers/JsonObject.vala | 5 +++ src/renderers/MapStyle.vala | 78 ++++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/renderers/JsonObject.vala b/src/renderers/JsonObject.vala index 1ee2f1a..32130e4 100644 --- a/src/renderers/JsonObject.vala +++ b/src/renderers/JsonObject.vala @@ -7,6 +7,11 @@ public class Maps.JsonObject : Object, Json.Serializable { public override Json.Node serialize_property (string prop, Value val, ParamSpec spec) { var type = spec.value_type; + if (type.is_a (typeof (Maps.Expression))) { + var expression = (Maps.Expression) val; + return expression.serialize (); + } + if (type.is_a (typeof (Gee.ArrayList))) { return serialize_list (prop, val, spec); } diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 614cf14..abb403f 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -45,29 +45,30 @@ public class Maps.MapStyle : Maps.JsonObject { } }; + var water_filter = new Maps.Expression ("all"); + water_filter.add_argument ("!=", "brunnel", "tunnel"); + var water_layer = new Layer () { id = "water", kind = "fill", source = "vector-tiles", source_layer = "water", - // "filter": ["all", ["!=", "brunnel", "tunnel"]], + filter = water_filter, paint = new Layer.Paint () { fill_color = BLUEBERRY_100 } }; + var road_motorway_filter = new Maps.Expression ("all"); + road_motorway_filter.add_argument ("==", "class", "motorway"); + var road_motorway_layer = new Layer () { id = "road_motorway", kind = "line", source = "vector-tiles", source_layer = "transportation", minzoom = 5, - // "filter": [ - // "all", - // ["!in", "brunnel", "bridge", "tunnel"], - // ["==", "class", "motorway"], - // ["!=", "ramp", 1] - // ], + filter = road_motorway_filter, layout = new Layer.Layout () { line_cap = "round", line_join = "round" @@ -97,6 +98,9 @@ public class Maps.MapStyle : Maps.JsonObject { } }; + var place_city_filter = new Maps.Expression ("all"); + place_city_filter.add_argument ("==", "class", "city"); + var place_city_layer = new Layer () { id = "place_city", kind = "symbol", @@ -104,9 +108,7 @@ public class Maps.MapStyle : Maps.JsonObject { source_layer = "place", minzoom = 5, maxzoom = 15, - - // "filter": ["all", ["==", "class", "city"]], - + filter = place_city_filter, layout = new Layer.Layout () { // "icon-image": {"base": 1, "stops": [[0, "dot_9"], [8, ""]]}, text_anchor = "bottom", @@ -180,7 +182,7 @@ public class Maps.MapStyle : Maps.JsonObject { public int maxzoom { get; set; } public int minzoom { get; set; } - // public string[] filter { get; set; } + public Expression filter { get; set; } public Layout layout { get; set; } public Paint paint { get; set; } @@ -218,3 +220,57 @@ public class Maps.MapStyle : Maps.JsonObject { } } } + +// https://docs.maptiler.com/gl-style-specification/expressions/ +public class Maps.Expression : Maps.JsonObject { + public string name { get; construct set; } + public Gee.ArrayList args { get; set; } + + public Expression (string name) { + Object (name: name); + } + + construct { + args = new Gee.ArrayList (null); + } + + public void add_argument (string operator, ...) { + var argument = new Json.Array (); + + argument.add_string_element (operator); + + var list = va_list (); + while (true) { + string? string_arg = list.arg (); + if (string_arg != null) { + argument.add_string_element (string_arg); + continue; + } + + int? int_arg = list.arg (); + if (int_arg != null) { + argument.add_int_element (int_arg); + continue; + } + + break; + } + + args.add (argument); + } + + public Json.Node serialize () { + var array = new Json.Array (); + + array.add_string_element (name); + + foreach (var argument in args) { + array.add_array_element (argument); + } + + var node = new Json.Node (ARRAY); + node.set_array (array); + + return node; + } +} From e191d006a8934226fc67f1dfffea53f95504b2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 11:39:22 -0700 Subject: [PATCH 22/30] More roads --- src/renderers/MapStyle.vala | 74 +++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index abb403f..4044989 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -15,6 +15,7 @@ public class Maps.MapStyle : Maps.JsonObject { private const string BANANA_300 = "#ffe16b"; private const string BLUEBERRY_100 = "#8cd5ff"; private const string LIME_300 = "#9bdb4d"; + private const string SILVER_100 = "#fafafa"; private const string SILVER_300 = "#d4d4d4"; public MapStyle (string name) { @@ -46,7 +47,7 @@ public class Maps.MapStyle : Maps.JsonObject { }; var water_filter = new Maps.Expression ("all"); - water_filter.add_argument ("!=", "brunnel", "tunnel"); + water_filter.append ("!=", "brunnel", "tunnel"); var water_layer = new Layer () { id = "water", @@ -59,8 +60,69 @@ public class Maps.MapStyle : Maps.JsonObject { } }; + var road_minor_filter = new Maps.Expression ("all"); + // road_minor_filter.append ("==", "$type", "LineString"); // FIXME: segfault + // road_minor_filter.append ("!in", "brunnel", "bridge", "tunnel"); // FIXME: segfault + road_minor_filter.append ("in", "class", "minor"); + + var road_minor_layer = new Layer () { + id = "road_minor", + kind = "line", + source = "vector-tiles", + source_layer = "transportation", + filter = road_minor_filter, + layout = new Layer.Layout () { + line_cap = "round", + line_join = "round" + }, + paint = new Layer.Paint () { + line_color = SILVER_100 + // "line-width": {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 18]]} + } + }; + + + var road_secondary_tertiary_filter = new Maps.Expression ("all"); + road_secondary_tertiary_filter.append ("!in", "brunnel", "bridge", "tunnel"); + road_secondary_tertiary_filter.append ("in", "class", "secondary", "tertiary"); + + var road_secondary_tertiary_layer = new Layer () { + id = "road_secondary_tertiary", + kind = "line", + source = "vector-tiles", + source_layer = "transportation", + filter = road_secondary_tertiary_filter, + layout = new Layer.Layout () { + line_cap = "round", + line_join = "round" + }, + paint = new Layer.Paint () { + line_color = SILVER_100 + // "line-width": {"base": 1.2, "stops": [[6.5, 0], [8, 0.5], [20, 13]]} + } + }; + + var road_trunk_primary_filter = new Maps.Expression ("all"); + road_trunk_primary_filter.append ("!in", "brunnel", "bridge", "tunnel"); + road_trunk_primary_filter.append ("in", "class", "primary", "trunk"); + + var road_trunk_primary_layer = new Layer () { + id = "road_trunk_primary", + kind = "line", + source = "vector-tiles", + source_layer = "transportation", + filter = road_trunk_primary_filter, + layout = new Layer.Layout () { + line_join = "round" + }, + paint = new Layer.Paint () { + line_color = SILVER_100 + // "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} + } + }; + var road_motorway_filter = new Maps.Expression ("all"); - road_motorway_filter.add_argument ("==", "class", "motorway"); + road_motorway_filter.append ("==", "class", "motorway"); var road_motorway_layer = new Layer () { id = "road_motorway", @@ -99,7 +161,7 @@ public class Maps.MapStyle : Maps.JsonObject { }; var place_city_filter = new Maps.Expression ("all"); - place_city_filter.add_argument ("==", "class", "city"); + place_city_filter.append ("==", "class", "city"); var place_city_layer = new Layer () { id = "place_city", @@ -136,6 +198,9 @@ public class Maps.MapStyle : Maps.JsonObject { layers.add (background_layer); layers.add (park_layer); layers.add (water_layer); + layers.add (road_minor_layer); + layers.add (road_secondary_tertiary_layer); + layers.add (road_trunk_primary_layer); layers.add (road_motorway_layer); layers.add (building_layer); layers.add (place_city_layer); @@ -234,7 +299,7 @@ public class Maps.Expression : Maps.JsonObject { args = new Gee.ArrayList (null); } - public void add_argument (string operator, ...) { + public void append (string operator, ...) { var argument = new Json.Array (); argument.add_string_element (operator); @@ -259,6 +324,7 @@ public class Maps.Expression : Maps.JsonObject { args.add (argument); } + // FIXME: assertion 'self != NULL' failed public Json.Node serialize () { var array = new Json.Array (); From c0a2aea5c2d13b5f3d0a512b2918a03ee198134e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 11:50:26 -0700 Subject: [PATCH 23/30] Mess with some colors --- src/renderers/MapStyle.vala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 4044989..43676ba 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -14,6 +14,8 @@ public class Maps.MapStyle : Maps.JsonObject { private const string BANANA_300 = "#ffe16b"; private const string BLUEBERRY_100 = "#8cd5ff"; + private const string LATTE_50 = "#f7f0e3"; + private const string LATTE_100 = "#efdfc4"; private const string LIME_300 = "#9bdb4d"; private const string SILVER_100 = "#fafafa"; private const string SILVER_300 = "#d4d4d4"; @@ -30,7 +32,7 @@ public class Maps.MapStyle : Maps.JsonObject { id = "background", kind = "background", paint = new Layer.Paint () { - background_color = "rgb(239,239,239)" + background_color = LATTE_50 } }; @@ -42,7 +44,7 @@ public class Maps.MapStyle : Maps.JsonObject { paint = new Layer.Paint () { fill_color = LIME_300, fill_opacity = 0.7, - fill_outline_color = "rgba(95, 208, 100, 1)" + fill_outline_color = LIME_300 } }; @@ -116,7 +118,7 @@ public class Maps.MapStyle : Maps.JsonObject { line_join = "round" }, paint = new Layer.Paint () { - line_color = SILVER_100 + line_color = SILVER_300 // "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} } }; @@ -152,7 +154,7 @@ public class Maps.MapStyle : Maps.JsonObject { source_layer = "building", minzoom = 13, paint = new Layer.Paint () { - fill_color = SILVER_300, + fill_color = LATTE_100, // "fill-outline-color": { // "base": 1, // "stops": [[13, "hsla(35, 6%, 79%, 0.32)"], [14, "hsl(35, 6%, 79%)"]] From 76e248a4cb4a87b59b565e72d0e8e567e9b0441c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 11:53:20 -0700 Subject: [PATCH 24/30] lighter buildings --- src/renderers/MapStyle.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 43676ba..d13b6a3 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -15,6 +15,7 @@ public class Maps.MapStyle : Maps.JsonObject { private const string BANANA_300 = "#ffe16b"; private const string BLUEBERRY_100 = "#8cd5ff"; private const string LATTE_50 = "#f7f0e3"; + private const string LATTE_75 = "#f3e7d3"; private const string LATTE_100 = "#efdfc4"; private const string LIME_300 = "#9bdb4d"; private const string SILVER_100 = "#fafafa"; @@ -154,7 +155,7 @@ public class Maps.MapStyle : Maps.JsonObject { source_layer = "building", minzoom = 13, paint = new Layer.Paint () { - fill_color = LATTE_100, + fill_color = LATTE_75, // "fill-outline-color": { // "base": 1, // "stops": [[13, "hsla(35, 6%, 79%, 0.32)"], [14, "hsl(35, 6%, 79%)"]] From 9b1667d1ecf8d419d3a00f4ae2674d47ec567dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 11:55:38 -0700 Subject: [PATCH 25/30] Desaturate bg more --- src/renderers/MapStyle.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index d13b6a3..df53575 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -14,6 +14,7 @@ public class Maps.MapStyle : Maps.JsonObject { private const string BANANA_300 = "#ffe16b"; private const string BLUEBERRY_100 = "#8cd5ff"; + private const string LATTE_25 = "#f6f3ed"; private const string LATTE_50 = "#f7f0e3"; private const string LATTE_75 = "#f3e7d3"; private const string LATTE_100 = "#efdfc4"; @@ -33,7 +34,7 @@ public class Maps.MapStyle : Maps.JsonObject { id = "background", kind = "background", paint = new Layer.Paint () { - background_color = LATTE_50 + background_color = LATTE_25 } }; From db562d80160147e8165d666537a9e4a4ed336e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 17:05:37 -0700 Subject: [PATCH 26/30] Imply future object --- src/renderers/MapStyle.vala | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index df53575..62b3431 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -141,11 +141,10 @@ public class Maps.MapStyle : Maps.JsonObject { }, paint = new Layer.Paint () { line_color = BANANA_300, - line_width = new Layer.Paint.LineWidth () { - base = 1.2 - // "stops": [[5, 0], [7, 1], [20, 18]] - } - + // line_width = new InterpolateExpression () { + // base = 1.2 + // stops = {[5, 0], [7, 1], [20, 18]} + // } } }; @@ -182,10 +181,10 @@ public class Maps.MapStyle : Maps.JsonObject { text_font = {"Inter Medium"}, text_max_width = 8, text_offset = {0, 0}, - text_size = new Layer.Layout.TextSize () { - base = 1.2 - // "stops": [[7, 14], [11, 32]] - }, + // text_size = new InterpolateExpression () { + // base = 1.2 + // "stops": [[7, 14], [11, 32]] + // }, icon_allow_overlap = true, icon_optional = false }, @@ -263,11 +262,7 @@ public class Maps.MapStyle : Maps.JsonObject { public string fill_outline_color { get; set; } public string text_color { get; set; } public string line_color { get; set;} - public LineWidth line_width { get; set; } - - public class LineWidth : Maps.JsonObject { - public double base { get; set; } - } + // public InterpolateExpression line_width { get; set; } } public class Layout : Maps.JsonObject { @@ -278,14 +273,10 @@ public class Maps.MapStyle : Maps.JsonObject { public string[] text_font { get; set; } public int text_max_width { get; set; } public double[] text_offset { get; set; } - public TextSize text_size { get; set; } + // public InterpolateExpression text_size { get; set; } public string text_transform { get; set; } public bool icon_allow_overlap { get; set; } public bool icon_optional { get; set; } - - public class TextSize : Maps.JsonObject { - public double base { get; set; } - } } } } From ec411a81905a18fa6449af373fba3d8b19ea0edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sat, 19 Jul 2025 17:14:18 -0700 Subject: [PATCH 27/30] Start to do InterpolateExpression --- src/renderers/MapStyle.vala | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 62b3431..02e4c4e 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -141,10 +141,10 @@ public class Maps.MapStyle : Maps.JsonObject { }, paint = new Layer.Paint () { line_color = BANANA_300, - // line_width = new InterpolateExpression () { - // base = 1.2 + line_width = new InterpolateExpression () { + base_val = 1.2 // stops = {[5, 0], [7, 1], [20, 18]} - // } + } } }; @@ -262,7 +262,7 @@ public class Maps.MapStyle : Maps.JsonObject { public string fill_outline_color { get; set; } public string text_color { get; set; } public string line_color { get; set;} - // public InterpolateExpression line_width { get; set; } + public InterpolateExpression line_width { get; set; } } public class Layout : Maps.JsonObject { @@ -273,7 +273,7 @@ public class Maps.MapStyle : Maps.JsonObject { public string[] text_font { get; set; } public int text_max_width { get; set; } public double[] text_offset { get; set; } - // public InterpolateExpression text_size { get; set; } + public InterpolateExpression text_size { get; set; } public string text_transform { get; set; } public bool icon_allow_overlap { get; set; } public bool icon_optional { get; set; } @@ -281,6 +281,16 @@ public class Maps.MapStyle : Maps.JsonObject { } } +// https://docs.maptiler.com/gl-style-specification/expressions/#interpolate +public class Maps.InterpolateExpression : Maps.JsonObject { + public double base_val { get; set; } // Need to serialize as base + public Gee.ArrayList stops { get; set; } + + construct { + stops = new Gee.ArrayList (null); + } +} + // https://docs.maptiler.com/gl-style-specification/expressions/ public class Maps.Expression : Maps.JsonObject { public string name { get; construct set; } From c233b07a36ee165bbf2b4b72465200784f383908 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Tue, 22 Jul 2025 03:22:29 +0900 Subject: [PATCH 28/30] Move Shumate.MapSourceRegistry and necessary initialization into MainWindow (#162) --- src/MainWindow.vala | 34 +++++++++++++++++++++++++++++++++- src/Util.vala | 36 +++--------------------------------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 597bc7b..5443842 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -30,6 +30,7 @@ public class Maps.MainWindow : Adw.ApplicationWindow { private Gtk.SearchEntry search_entry; private Gtk.Popover search_res_popover; private MapWidget map_widget; + private Shumate.MapSourceRegistry registry; construct { title = _("Maps"); @@ -288,6 +289,14 @@ public class Maps.MainWindow : Adw.ApplicationWindow { } private void setup_map_source_action () { + registry = new Shumate.MapSourceRegistry.with_defaults (); + + try { + load_vector_tiles (); + } catch (Error e) { + critical ("Failed to create vector map style: %s", e.message); + } + var map_source_action = Application.settings.create_action ("map-source"); add_action (map_source_action); @@ -295,10 +304,33 @@ public class Maps.MainWindow : Adw.ApplicationWindow { "map-source", map_widget, "map-source", GET, (SettingsBindGetMappingShared) Util.map_source_get_mapping_cb, (SettingsBindSetMappingShared) null, - null, null + registry, null ); } + private void load_vector_tiles () throws Error requires (Shumate.VectorRenderer.is_supported ()) { + var style_json = new Maps.MapStyle (Define.MapID.EXPLORE_LIGHT).to_string (); + critical (style_json); + + var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json) { + license = "© OpenMapTiles © OpenStreetMap contributors", + max_zoom_level = 19, + min_zoom_level = 2 + }; + + var sprites_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites.json", NONE); + var sprites_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites.png"); + + var sprites_2x_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites@2x.json", NONE); + var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); + + var sprites = renderer.get_sprite_sheet (); + sprites.add_page (sprites_texture, (string) sprites_json.get_data (), 1); + sprites.add_page (sprites_2x_texture, (string) sprites_2x_json.get_data (), 2); + + registry.add (renderer); + } + private async void search_location (string term, ListStore res) { busy_start (BusyReason.SEARCHING); diff --git a/src/Util.vala b/src/Util.vala index 53c8775..34bb08d 100644 --- a/src/Util.vala +++ b/src/Util.vala @@ -33,17 +33,11 @@ namespace Util { } } - private Shumate.MapSourceRegistry registry; - public static bool map_source_get_mapping_cb (Value value, Variant variant, void* user_data) { + unowned var registry = user_data as Shumate.MapSourceRegistry; if (registry == null) { - registry = new Shumate.MapSourceRegistry.with_defaults (); - - try { - load_vector_tiles (); - } catch (Error e) { - critical ("Failed to create vector map style: %s", e.message); - } + warning ("map_source_get_mapping_cb: Invalid user_data"); + return false; } string map_source; @@ -60,32 +54,8 @@ namespace Util { return false; } - value.set_object (registry.get_by_id (map_source)); return true; } - - private void load_vector_tiles () throws Error requires (Shumate.VectorRenderer.is_supported ()) { - var style_json = new Maps.MapStyle (Define.MapID.EXPLORE_LIGHT).to_string (); - critical (style_json); - - var renderer = new Shumate.VectorRenderer (Define.MapID.EXPLORE_LIGHT, style_json) { - license = "© OpenMapTiles © OpenStreetMap contributors", - max_zoom_level = 19, - min_zoom_level = 2 - }; - - var sprites_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites.json", NONE); - var sprites_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites.png"); - - var sprites_2x_json = resources_lookup_data ("/io/elementary/maps/tiles/sprites@2x.json", NONE); - var sprites_2x_texture = Gdk.Texture.from_resource ("/io/elementary/maps/tiles/sprites@2x.png"); - - var sprites = renderer.get_sprite_sheet (); - sprites.add_page (sprites_texture, (string) sprites_json.get_data (), 1); - sprites.add_page (sprites_2x_texture, (string) sprites_2x_json.get_data (), 2); - - registry.add (renderer); - } } From f61f9b30c0dbaaac2bf3f9561b713e6b18d2905f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 21 Jul 2025 13:53:02 -0700 Subject: [PATCH 29/30] Translate more objects from json --- src/renderers/MapStyle.vala | 233 ++++++++++++++++++++++++++++++++---- 1 file changed, 211 insertions(+), 22 deletions(-) diff --git a/src/renderers/MapStyle.vala b/src/renderers/MapStyle.vala index 02e4c4e..f677a57 100644 --- a/src/renderers/MapStyle.vala +++ b/src/renderers/MapStyle.vala @@ -18,6 +18,7 @@ public class Maps.MapStyle : Maps.JsonObject { private const string LATTE_50 = "#f7f0e3"; private const string LATTE_75 = "#f3e7d3"; private const string LATTE_100 = "#efdfc4"; + private const string LIME_100 = "#d1ff82"; private const string LIME_300 = "#9bdb4d"; private const string SILVER_100 = "#fafafa"; private const string SILVER_300 = "#d4d4d4"; @@ -30,7 +31,7 @@ public class Maps.MapStyle : Maps.JsonObject { version = 8; sources = new Sources (); - var background_layer = new Layer () { + var background = new Layer () { id = "background", kind = "background", paint = new Layer.Paint () { @@ -38,7 +39,7 @@ public class Maps.MapStyle : Maps.JsonObject { } }; - var park_layer = new Layer () { + var park = new Layer () { id = "park", kind = "fill", source = "vector-tiles", @@ -50,10 +51,184 @@ public class Maps.MapStyle : Maps.JsonObject { } }; + var park_outline = new Layer () { + id = "park_outline", + kind = "line", + source = "vector-tiles", + source_layer = "park", + paint = new Layer.Paint () { + // line_dasharray = [1, 1.5], + // line_color = LIME_100 // FIXME: segfault + } + }; + + // var landuse_residential_filter = new Maps.Expression ("all"); + // landuse_residential_filter.append ("==", "class", "residential"); + + // var landuse_residential = new Layer () { + // id = "landuse_residential", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landuse", + // maxzoom = 8, + // filter = landuse_residential_filter, + // paint = new Layer.Paint () { + // // fill_color = { + // // "base": 1, + // // "stops": [ + // // [9, "hsla(0, 3%, 85%, 0.84)"], + // // [12, "hsla(35, 57%, 88%, 0.49)"] + // // ] + // // } + // } + // }; + + // var landcover_wood_filter = new Maps.Expression ("all"); + // landcover_wood_filter.append ("==", "class", "wood"); + + // var landcover_wood = new Layer () { + // id = "landcover_wood", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landcover", + // filter = landcover_wood_filter, + // paint = new Layer.Paint () { + // fill_antialias = false, + // fill_color = "hsla(98, 61%, 72%, 0.7)", + // fill_opacity = 0.4 + // } + // }; + + // var landcover_grass_filter = new Maps.Expression ("all"); + // landcover_grass_filter.append ("==", "class", "grass"); + + // var landcover_grass = new Layer () { + // id = "landcover_grass", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landcover", + // filter = landcover_grass_filter, + // paint = new Layer.Paint () { + // fill_antialias = false, + // fill_color = LIME_300, + // fill_opacity = 0.5 + // } + // }; + + // var landcover_ice_filter = new Maps.Expression ("all"); + // landcover_ice_filter.append ("==", "class", "ice"); + + // var landcover_ice = new Layer () { + // id = "landcover_ice", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landcover", + // filter = landcover_ice_filter, + // paint = new Layer.Paint () { + // fill_antialias = false, + // fill_color = "rgba(224, 236, 236, 1)", + // fill_opacity = 0.8 + // } + // }; + + // var landuse_cemetery_filter = new Maps.Expression ("all"); + // landuse_cemetery_filter.append ("==", "class", "cemetery"); + + // var landuse_cemetery = new Layer () { + // id = "landuse_cemetery", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landuse", + // filter = landuse_cemetery_filter, + // paint = new Layer.Paint () { + // fill_color = "hsl(75, 37%, 81%)" + // } + // }; + + // var landuse_hospital_filter = new Maps.Expression ("all"); + // landuse_hospital_filter.append ("==", "class", "hospital"); + + // var landuse_hospital = new Layer () { + // id = "landuse_hospital", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landuse", + // paint = new Layer.Paint () { + // fill_color = "#fde" + // } + // }; + + // var landuse_school = new Layer () { + // id = "landuse_school", + // kind = "fill", + // source = "openmaptiles", + // source_layer = "landuse", + // // "filter": ["==", "class", "school"], + // paint = new Layer.Paint () { + // fill_color = "rgb(236,238,204)" + // } + // }; + + var waterway_tunnel_filter = new Maps.Expression ("all"); + waterway_tunnel_filter.append ("==", "brunnel", "tunnel"); + + var waterway_tunnel = new Layer () { + id = "waterway_tunnel", + kind = "line", + source = "openmaptiles", + source_layer = "waterway", + filter = waterway_tunnel_filter, + // paint = new Layer.Paint () { + // line_color = "#a0c8f0", + // line_dasharray = {3, 3}, + // // line_gap_width = {"stops": [[12, 0], [20, 6]]}, + // line_opacity = 1, + // // line_width = {"base": 1.4, "stops": [[8, 1], [20, 2]]} + // } + }; + + // var waterway_river_filter = new Maps.Expression ("all"); + // waterway_river_filter.append ("==", "class", "river"); + // waterway_river_filter.append ("!=", "brunnel", "tunnel"); + + // var waterway_river = new Layer () { + // id = "waterway_river", + // kind = "line", + // source = "openmaptiles", + // source_layer = "waterway", + // filter = waterway_river_filter, + // layout = new Layer.Layout () { + // line_cap = "round" + // }, + // paint = new Layer.Paint () { + // line_color = "#a0c8f0", + // // line_width = {"base": 1.2, "stops": [[11, 0.5], [20, 6]]} + // } + // }; + + // var waterway_other_filter = new Maps.Expression ("all"); + // waterway_other_filter.append ("!=", "class", "river"); + // waterway_other_filter.append ("!=", "brunnel", "tunnel"); + + // var waterway_other = new Layer () { + // id = "waterway_other", + // kind = "line", + // source = "openmaptiles", + // source_layer = "waterway", + // filter = waterway_other_filter, + // layout = new Layer.Layout () { + // line_cap = "round" + // }, + // paint = new Layer.Paint () { + // line_color = "#a0c8f0", + // // line_width = {"base": 1.3, "stops": [[13, 0.5], [20, 6]]} + // } + // }; + var water_filter = new Maps.Expression ("all"); water_filter.append ("!=", "brunnel", "tunnel"); - var water_layer = new Layer () { + var water = new Layer () { id = "water", kind = "fill", source = "vector-tiles", @@ -69,7 +244,7 @@ public class Maps.MapStyle : Maps.JsonObject { // road_minor_filter.append ("!in", "brunnel", "bridge", "tunnel"); // FIXME: segfault road_minor_filter.append ("in", "class", "minor"); - var road_minor_layer = new Layer () { + var road_minor = new Layer () { id = "road_minor", kind = "line", source = "vector-tiles", @@ -81,7 +256,7 @@ public class Maps.MapStyle : Maps.JsonObject { }, paint = new Layer.Paint () { line_color = SILVER_100 - // "line-width": {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 18]]} + // line_width = {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 18]]} } }; @@ -90,7 +265,7 @@ public class Maps.MapStyle : Maps.JsonObject { road_secondary_tertiary_filter.append ("!in", "brunnel", "bridge", "tunnel"); road_secondary_tertiary_filter.append ("in", "class", "secondary", "tertiary"); - var road_secondary_tertiary_layer = new Layer () { + var road_secondary_tertiary = new Layer () { id = "road_secondary_tertiary", kind = "line", source = "vector-tiles", @@ -102,7 +277,7 @@ public class Maps.MapStyle : Maps.JsonObject { }, paint = new Layer.Paint () { line_color = SILVER_100 - // "line-width": {"base": 1.2, "stops": [[6.5, 0], [8, 0.5], [20, 13]]} + // line_width = {"base": 1.2, "stops": [[6.5, 0], [8, 0.5], [20, 13]]} } }; @@ -110,7 +285,7 @@ public class Maps.MapStyle : Maps.JsonObject { road_trunk_primary_filter.append ("!in", "brunnel", "bridge", "tunnel"); road_trunk_primary_filter.append ("in", "class", "primary", "trunk"); - var road_trunk_primary_layer = new Layer () { + var road_trunk_primary = new Layer () { id = "road_trunk_primary", kind = "line", source = "vector-tiles", @@ -121,14 +296,14 @@ public class Maps.MapStyle : Maps.JsonObject { }, paint = new Layer.Paint () { line_color = SILVER_300 - // "line-width": {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} + // line_width = {"base": 1.2, "stops": [[5, 0], [7, 1], [20, 18]]} } }; var road_motorway_filter = new Maps.Expression ("all"); road_motorway_filter.append ("==", "class", "motorway"); - var road_motorway_layer = new Layer () { + var road_motorway = new Layer () { id = "road_motorway", kind = "line", source = "vector-tiles", @@ -148,7 +323,7 @@ public class Maps.MapStyle : Maps.JsonObject { } }; - var building_layer = new Layer () { + var building = new Layer () { id = "building", kind = "fill", source = "vector-tiles", @@ -166,7 +341,7 @@ public class Maps.MapStyle : Maps.JsonObject { var place_city_filter = new Maps.Expression ("all"); place_city_filter.append ("==", "class", "city"); - var place_city_layer = new Layer () { + var place_city = new Layer () { id = "place_city", kind = "symbol", source = "vector-tiles", @@ -198,15 +373,26 @@ public class Maps.MapStyle : Maps.JsonObject { }; layers = new Gee.ArrayList (null); - layers.add (background_layer); - layers.add (park_layer); - layers.add (water_layer); - layers.add (road_minor_layer); - layers.add (road_secondary_tertiary_layer); - layers.add (road_trunk_primary_layer); - layers.add (road_motorway_layer); - layers.add (building_layer); - layers.add (place_city_layer); + layers.add (background); + layers.add (park); + // layers.add (park_outline); + // layers.add (landuse_residential); + // layers.add (landcover_wood); + // layers.add (landcover_grass); + // layers.add (landcover_ice); + // layers.add (landuse_cemetery); + // layers.add (landuse_hospital); + // layers.add (landuse_school); + // layers.add (waterway_tunnel); + // layers.add (waterway_river); + // layers.add (waterway_other); + layers.add (water); + layers.add (road_minor); + layers.add (road_secondary_tertiary); + layers.add (road_trunk_primary); + layers.add (road_motorway); + layers.add (building); + layers.add (place_city); // // "metadata": { // // "libshumate:cursor": "pointer" @@ -258,10 +444,13 @@ public class Maps.MapStyle : Maps.JsonObject { public class Paint : Maps.JsonObject { public double fill_opacity { get; set; } public string background_color { get; set; } + public bool fill_antialias { get; set;} public string fill_color { get; set; } public string fill_outline_color { get; set; } public string text_color { get; set; } - public string line_color { get; set;} + public string line_color { get; set; } + public double line_opacity { get; set; } + public double[] line_dasharray { get; set; } public InterpolateExpression line_width { get; set; } } From aaaca75670b17c8ecb506719630b145cc3bd396e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Tue, 22 Jul 2025 07:33:37 -0700 Subject: [PATCH 30/30] Update meson.build Co-authored-by: Ryo Nakano --- src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index 8e9721e..e61885c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,7 +17,7 @@ dependencies = [ # Version limitation for Granite.Bin dependency('granite-7', version: '>= 7.6.0'), dependency('gtk4'), - dependency ('json-glib-1.0'), + dependency('json-glib-1.0'), dependency('libadwaita-1'), dependency('libgeoclue-2.0'), dependency('shumate-1.0'),