From f373c219e189d02349227def750fc927d61d62aa Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 16 Mar 2025 03:09:51 +0100 Subject: [PATCH 1/5] feat: style serving This PR adds style serving to the features we support. Resolves #1607 I am not quite certain if `sources` is something that works for styles.. The key to the dict not playing any role is somewhat counterintuitive. --- Cargo.lock | 176 +- Cargo.toml | 1 + debian/config.yaml | 7 + docs/src/config-file.md | 20 + docs/src/sources-styles.md | 24 + docs/src/using.md | 8 +- martin/Cargo.toml | 7 +- martin/src/args/root.rs | 18 +- martin/src/config.rs | 27 +- martin/src/lib.rs | 2 + martin/src/srv/mod.rs | 3 + martin/src/srv/server.rs | 10 + martin/src/srv/styles.rs | 45 + martin/src/styles/mod.rs | 318 +++ martin/src/utils/error.rs | 4 + martin/tests/mb_server_test.rs | 2 + martin/tests/pg_server_test.rs | 1 + martin/tests/pmt_server_test.rs | 2 + tests/config.yaml | 6 + tests/expected/auto/catalog_auto.json | 11 + tests/expected/auto/save_config.yaml | 3 + tests/expected/auto_mini/catalog_auto.json | 1 + tests/expected/configured/catalog_cfg.json | 11 + tests/expected/configured/save_config.yaml | 4 + .../configured/style_maplibre_demo.1.json | 544 +++++ .../configured/style_maplibre_demo.json | 544 +++++ .../style_src2_maptiler_basic.1.json | 1840 +++++++++++++++++ .../configured/style_src2_maptiler_basic.json | 1840 +++++++++++++++++ tests/fixtures/styles/maplibre_demo.json | 239 +++ .../fixtures/styles/src2/maptiler_basic.json | 815 ++++++++ .../styles/src2/osm-liberty-lite.json | 196 ++ tests/test.sh | 8 +- 32 files changed, 6679 insertions(+), 58 deletions(-) create mode 100644 docs/src/sources-styles.md create mode 100644 martin/src/srv/styles.rs create mode 100644 martin/src/styles/mod.rs create mode 100644 tests/expected/configured/style_maplibre_demo.1.json create mode 100644 tests/expected/configured/style_maplibre_demo.json create mode 100644 tests/expected/configured/style_src2_maptiler_basic.1.json create mode 100644 tests/expected/configured/style_src2_maptiler_basic.json create mode 100644 tests/fixtures/styles/maplibre_demo.json create mode 100644 tests/fixtures/styles/src2/maptiler_basic.json create mode 100644 tests/fixtures/styles/src2/osm-liberty-lite.json diff --git a/Cargo.lock b/Cargo.lock index 560e02448..feddb1c6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,9 +508,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97d56060ee67d285efb8001fec9d2a4c710c32efd2e14b5cbb5ba71930fc2d" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" [[package]] name = "bindgen" @@ -599,7 +599,7 @@ dependencies = [ "futures-util", "hex", "home", - "http 1.3.0", + "http 1.3.1", "http-body-util", "hyper 1.6.0", "hyper-named-pipe", @@ -1895,9 +1895,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "cfg-if", "crunchy", @@ -2017,9 +2017,9 @@ dependencies = [ [[package]] name = "http" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a761d192fbf18bdef69f5ceedd0d1333afcbda0ee23840373b8317570d23c65" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -2044,7 +2044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.0", + "http 1.3.1", ] [[package]] @@ -2055,7 +2055,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.0", + "http 1.3.1", "http-body 1.0.1", "pin-project-lite", ] @@ -2104,7 +2104,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.3.0", + "http 1.3.1", "http-body 1.0.1", "httparse", "httpdate", @@ -2137,7 +2137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.3.0", + "http 1.3.1", "hyper 1.6.0", "hyper-util", "rustls", @@ -2157,7 +2157,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.3.0", + "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", "pin-project-lite", @@ -2661,7 +2661,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2706,9 +2706,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" @@ -2818,6 +2818,7 @@ dependencies = [ "spreet", "static-files", "subst", + "tempfile", "testcontainers-modules", "thiserror 2.0.12", "tiff", @@ -3163,9 +3164,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "oorandom" @@ -3595,9 +3596,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a" +checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" dependencies = [ "proc-macro2", "syn 2.0.100", @@ -3803,9 +3804,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -3984,15 +3985,15 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.12" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "989e327e510263980e231de548a33e63d34962d29ae61b467389a1a09627a254" dependencies = [ "base64 0.22.1", "bytes", "futures-core", "futures-util", - "http 1.3.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", "hyper 1.6.0", @@ -4053,9 +4054,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", @@ -4082,9 +4083,9 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rsa" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" dependencies = [ "const-oid", "digest", @@ -4193,7 +4194,7 @@ dependencies = [ "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys 0.9.2", + "linux-raw-sys 0.9.3", "windows-sys 0.59.0", ] @@ -5055,11 +5056,10 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.18.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" dependencies = [ - "cfg-if", "fastrand", "getrandom 0.3.1", "once_cell", @@ -5399,9 +5399,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -5738,9 +5738,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.15.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ "getrandom 0.3.1", ] @@ -5987,8 +5987,8 @@ checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ "windows-implement", "windows-interface", - "windows-result", - "windows-strings", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] @@ -6022,13 +6022,13 @@ checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" [[package]] name = "windows-registry" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.52.6", + "windows-result 0.3.1", + "windows-strings 0.3.1", + "windows-targets 0.53.0", ] [[package]] @@ -6040,16 +6040,34 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6101,13 +6119,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6120,6 +6154,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6132,6 +6172,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6144,12 +6190,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6162,6 +6220,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6174,6 +6238,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6186,6 +6256,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6198,11 +6274,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index dfe030d08..22b2d3c7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,6 +84,7 @@ sqlite-hashes = { version = "0.9.0", default-features = false, features = ["md5" sqlx = { version = "0.8.3", features = ["sqlite", "runtime-tokio"] } static-files = "0.2" subst = { version = "0.3", features = ["yaml"] } +tempfile = "3.17.1" testcontainers-modules = { version = "0.11.6", features = ["postgres"] } thiserror = "2" tiff = "0.9.1" diff --git a/debian/config.yaml b/debian/config.yaml index 30b9ad27e..080fb0141 100644 --- a/debian/config.yaml +++ b/debian/config.yaml @@ -44,3 +44,10 @@ cache_size_mb: 512 # fonts: # - /path/to/font/file.ttf # - /path/to/font_dir + +# styles: +# paths: +# - /path/to/styles_dir +# - /path/to/maplibre_style.json +# sources: +# styles1: /path/to/styles_dir2 diff --git a/docs/src/config-file.md b/docs/src/config-file.md index c01271141..e707c9300 100644 --- a/docs/src/config-file.md +++ b/docs/src/config-file.md @@ -230,4 +230,24 @@ fonts: # A list of *.otf, *.ttf, and *.ttc font files and dirs to search recursively. - /path/to/font/file.ttf - /path/to/font_dir + +# We support serving styles +# In the future, we plan on adding support for rendering too +styles: + paths: + # each json file in this directory will published as a style + # The name of the file will be used as the style name + - /path/to/styles_dir + # will be published as maplibre_style + - /path/to/maplibre_style.json + sources: + # each json file in this directory will publish as style + # The filename will be used as the styles' id + # + # source_name1 will be logged and can be useful for debugging + source_name1: /path/to/styles_dir1 + # will be published as style2 + # + # source_name2 will be logged and can be useful for debugging + source_name2: /path/to/style2.json ``` diff --git a/docs/src/sources-styles.md b/docs/src/sources-styles.md new file mode 100644 index 000000000..6abc4491d --- /dev/null +++ b/docs/src/sources-styles.md @@ -0,0 +1,24 @@ +## Style Sources + +Martin will serve your styles as needed by MapLibre. + +To edit these styles, we recomend using . + +### API + +Martin can serve [MapLibre Style Spec](https://maplibre.org/maplibre-style-spec/). +Currently any valid [`JSON`](https://json.org) file can be used, but in the future, there will be additional optimisations resulting in usage restrictions. + +You can use the `/catalog` api to see all the ``s. + +### Map Style + +You can use the `/style/` api to get ``. + +Changes or removals of styles are reflected immediately, but additions are not. +A restart of martin is required to see new styles. + +### Add server-side raster tile rendering + +This is not implemented yet, but there is a plan to add it. +Please see for more information. diff --git a/docs/src/using.md b/docs/src/using.md index 3e5c40567..95428022c 100644 --- a/docs/src/using.md +++ b/docs/src/using.md @@ -14,6 +14,7 @@ Martin data is available via the HTTP `GET` endpoints: | `/sdf_sprite/{spriteID}[@2x].{json,png}` | [SDF Sprite sources](sources-sprites.md) | | `/font/{font}/{start}-{end}` | [Font source](sources-fonts.md) | | `/font/{font1},…,{fontN}/{start}-{end}` | [Composite Font source](sources-fonts.md) | +| `/style/{style}` | [Style source](sources-styles.md) | | `/health` | Martin server health check: returns 200 `OK` | ### Duplicate Source ID @@ -69,7 +70,12 @@ curl localhost:3000/catalog | jq "end": 65533 }, ... - } + }, + "styles": { + "maplibre_demo": { + "path": "path/to/maplibre_demo.json", + }, + }, } ``` diff --git a/martin/Cargo.toml b/martin/Cargo.toml index 6dc5a5dd7..7649a2e2c 100644 --- a/martin/Cargo.toml +++ b/martin/Cargo.toml @@ -52,13 +52,14 @@ name = "bench" harness = false [features] -default = ["webui", "fonts", "lambda", "mbtiles", "pmtiles", "cog", "postgres", "sprites"] +default = ["webui", "fonts", "lambda", "mbtiles", "pmtiles", "cog", "postgres", "sprites", "styles"] webui = ["dep:actix-web-static-files", "dep:static-files", "dep:walkdir"] fonts = ["dep:bit-set", "dep:pbf_font_tools"] lambda = ["dep:lambda-web"] mbtiles = ["dep:mbtiles"] pmtiles = ["dep:pmtiles"] cog = ["dep:tiff", "dep:png"] +styles = ["dep:walkdir", "tokio/fs"] postgres = ["dep:deadpool-postgres", "dep:json-patch", "dep:postgis", "dep:postgres", "dep:postgres-protocol", "dep:semver", "dep:tokio-postgres-rustls"] sprites = ["dep:spreet", "tokio/fs"] bless-tests = [] @@ -109,6 +110,7 @@ tilejson.workspace = true tokio = { workspace = true, features = ["io-std"] } tokio-postgres-rustls = { workspace = true, optional = true } url.workspace = true +walkdir = { workspace = true, optional = true } [build-dependencies] walkdir = { workspace = true, optional = true } @@ -119,10 +121,11 @@ anyhow.workspace = true criterion.workspace = true ctor.workspace = true indoc.workspace = true -insta = { workspace = true, features = ["yaml"] } +insta = { workspace = true, features = ["json", "yaml"] } pprof.workspace = true rstest.workspace = true testcontainers-modules.workspace = true +tempfile.workspace = true [lints] workspace = true diff --git a/martin/src/args/root.rs b/martin/src/args/root.rs index b3f625524..3039ef48f 100644 --- a/martin/src/args/root.rs +++ b/martin/src/args/root.rs @@ -64,13 +64,17 @@ pub struct MetaArgs { #[command()] pub struct ExtraArgs { /// Export a directory with SVG files as a sprite source. Can be specified multiple times. - #[arg(short, long)] + #[arg(short = 's', long)] #[cfg(feature = "sprites")] pub sprite: Vec, /// Export a font file or a directory with font files as a font source (recursive). Can be specified multiple times. #[arg(short, long)] #[cfg(feature = "fonts")] pub font: Vec, + /// Export a style file or a directory with style files as a style source (recursive). Can be specified multiple times. + #[arg(short = 'S', long)] + #[cfg(feature = "styles")] + pub style: Vec, } impl Args { @@ -121,6 +125,11 @@ impl Args { config.cog = parse_file_args(&mut cli_strings, &["tif", "tiff"], false); } + #[cfg(feature = "styles")] + if !self.extras.style.is_empty() { + config.styles = FileConfigEnum::new(self.extras.style); + } + #[cfg(feature = "sprites")] if !self.extras.sprite.is_empty() { config.sprites = FileConfigEnum::new(self.extras.sprite); @@ -149,7 +158,12 @@ fn is_url(s: &str, extension: &[&str]) -> bool { false } -#[cfg(any(feature = "pmtiles", feature = "mbtiles", feature = "cog"))] +#[cfg(any( + feature = "pmtiles", + feature = "mbtiles", + feature = "cog", + feature = "styles" +))] pub fn parse_file_args( cli_strings: &mut Arguments, extensions: &[&str], diff --git a/martin/src/config.rs b/martin/src/config.rs index dcbb6d64a..51e5e2ebb 100644 --- a/martin/src/config.rs +++ b/martin/src/config.rs @@ -24,10 +24,13 @@ use crate::file_config::FileConfigEnum; use crate::fonts::FontSources; use crate::source::{TileInfoSources, TileSources}; #[cfg(feature = "sprites")] -use crate::sprites::{SpriteConfig, SpriteSources}; -use crate::srv::{RESERVED_KEYWORDS, SrvConfig}; -use crate::utils::{CacheValue, MainCache, OptMainCache, init_aws_lc_tls, parse_base_path}; -use crate::{IdResolver, MartinResult}; +use crate::sprites::SpriteSources; +use crate::srv::{SrvConfig, RESERVED_KEYWORDS}; +#[cfg(feature = "styles")] +use crate::styles::StyleSources; +use crate::utils::{init_aws_lc_tls, parse_base_path, CacheValue, MainCache, OptMainCache}; +use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources}; +use crate::{IdResolver, MartinResult, OptOneMany}; pub type UnrecognizedValues = HashMap; @@ -38,6 +41,8 @@ pub struct ServerState { pub sprites: SpriteSources, #[cfg(feature = "fonts")] pub fonts: FontSources, + #[cfg(feature = "styles")] + pub styles: StyleSources, } #[serde_with::skip_serializing_none] @@ -66,7 +71,11 @@ pub struct Config { #[cfg(feature = "sprites")] #[serde(default, skip_serializing_if = "FileConfigEnum::is_none")] - pub sprites: FileConfigEnum, + pub sprites: FileConfigEnum, + + #[cfg(feature = "styles")] + #[serde(default, skip_serializing_if = "FileConfigEnum::is_none")] + pub styles: FileConfigEnum, #[cfg(feature = "fonts")] #[serde(default, skip_serializing_if = "OptOneMany::is_none")] @@ -103,6 +112,9 @@ impl Config { #[cfg(feature = "sprites")] res.extend(self.sprites.finalize("sprites.")); + #[cfg(feature = "styles")] + res.extend(self.styles.finalize("styles.")); + // TODO: support for unrecognized fonts? // res.extend(self.fonts.finalize("fonts.")?); @@ -123,6 +135,9 @@ impl Config { #[cfg(feature = "sprites")] let is_empty = is_empty && self.sprites.is_empty(); + #[cfg(feature = "styles")] + let is_empty = is_empty && self.styles.is_empty(); + #[cfg(feature = "fonts")] let is_empty = is_empty && self.fonts.is_empty(); @@ -160,6 +175,8 @@ impl Config { sprites: SpriteSources::resolve(&mut self.sprites)?, #[cfg(feature = "fonts")] fonts: FontSources::resolve(&mut self.fonts)?, + #[cfg(feature = "styles")] + styles: StyleSources::resolve(&mut self.styles)?, cache, }) } diff --git a/martin/src/lib.rs b/martin/src/lib.rs index c40f1b628..36118be8f 100644 --- a/martin/src/lib.rs +++ b/martin/src/lib.rs @@ -31,6 +31,8 @@ pub mod pmtiles; pub mod sprites; pub mod srv; +#[cfg(feature = "styles")] +mod styles; #[cfg(test)] #[path = "utils/test_utils.rs"] mod test_utils; diff --git a/martin/src/srv/mod.rs b/martin/src/srv/mod.rs index 8a59d30ef..9519ef325 100644 --- a/martin/src/srv/mod.rs +++ b/martin/src/srv/mod.rs @@ -15,3 +15,6 @@ pub use tiles_info::{SourceIDsRequest, merge_tilejson}; #[cfg(feature = "sprites")] mod sprites; + +#[cfg(feature = "styles")] +mod styles; diff --git a/martin/src/srv/server.rs b/martin/src/srv/server.rs index 3f4c29afd..acb977fe2 100644 --- a/martin/src/srv/server.rs +++ b/martin/src/srv/server.rs @@ -48,6 +48,8 @@ pub struct Catalog { pub sprites: crate::sprites::SpriteCatalog, #[cfg(feature = "fonts")] pub fonts: crate::fonts::FontCatalog, + #[cfg(feature = "styles")] + pub styles: crate::styles::StyleCatalog, } impl Catalog { @@ -58,6 +60,8 @@ impl Catalog { sprites: state.sprites.get_catalog()?, #[cfg(feature = "fonts")] fonts: state.fonts.get_catalog(), + #[cfg(feature = "styles")] + styles: state.styles.get_catalog(), }) } } @@ -123,6 +127,9 @@ pub fn router(cfg: &mut web::ServiceConfig, #[allow(unused_variables)] usr_cfg: #[cfg(feature = "fonts")] cfg.service(crate::srv::fonts::get_font); + #[cfg(feature = "styles")] + cfg.service(crate::srv::styles::get_style_json); + #[cfg(feature = "webui")] { // TODO: this can probably be simplified with a wrapping middleware, @@ -169,6 +176,9 @@ pub fn new_server(config: SrvConfig, state: ServerState) -> MartinResult<(Server #[cfg(feature = "fonts")] let app = app.app_data(Data::new(state.fonts.clone())); + #[cfg(feature = "styles")] + let app = app.app_data(Data::new(state.styles.clone())); + app.app_data(Data::new(catalog.clone())) .app_data(Data::new(config.clone())) .wrap(cors_middleware) diff --git a/martin/src/srv/styles.rs b/martin/src/srv/styles.rs new file mode 100644 index 000000000..0db7f9908 --- /dev/null +++ b/martin/src/srv/styles.rs @@ -0,0 +1,45 @@ +use crate::styles::StyleSources; +use actix_web::http::header::ContentType; +use actix_web::middleware; +use actix_web::web::{Data, Path}; +use actix_web::{HttpResponse, route}; +use log::error; +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +struct StyleRequest { + style_id: String, +} + +#[route( + "/style/{style_id}", + method = "GET", + wrap = "middleware::Compress::default()" +)] +async fn get_style_json(path: Path, styles: Data) -> HttpResponse { + let style_id = &path.style_id; + let Some(path) = styles.style_json_path(style_id) else { + return HttpResponse::NotFound() + .content_type(ContentType::plaintext()) + .body("No such style exists"); + }; + let Ok(style_content) = tokio::fs::read_to_string(&path).await else { + // the file was likely deleted after martin was launched and collected the file list + // TODO: change this to a server error and log appropriately once the watch mode is here + return HttpResponse::NotFound() + .content_type(ContentType::plaintext()) + .body("No such style exists"); + }; + match serde_json::from_str::(&style_content) { + Ok(value) => HttpResponse::Ok().json(value), + Err(e) => { + error!("Failed to parse style JSON {e:?} for style {style_id} at {path:?}"); + + HttpResponse::BadRequest() + .content_type(ContentType::plaintext()) + .body(format!( + "The requested style {style_id} is malformed: {e:?}" + )) + } + } +} diff --git a/martin/src/styles/mod.rs b/martin/src/styles/mod.rs new file mode 100644 index 000000000..8629ed625 --- /dev/null +++ b/martin/src/styles/mod.rs @@ -0,0 +1,318 @@ +use dashmap::{DashMap, Entry}; +use log::{info, warn}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::path::{Path, PathBuf}; + +use crate::config::UnrecognizedValues; +use crate::file_config::{ConfigExtras, FileConfigEnum, FileResult}; + +pub type StyleResult = Result; + +#[derive(thiserror::Error, Debug)] +pub enum StyleError { + #[error("IO error {0}: {1}")] + IoError(std::io::Error, PathBuf), + #[error("Walk directory error {0}: {1}")] + DirectoryWalking(walkdir::Error, PathBuf), +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] +pub struct CatalogStyleEntry { + pub path: PathBuf, +} + +pub type StyleCatalog = DashMap; + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct StyleConfig { + #[serde(flatten)] + pub unrecognized: UnrecognizedValues, +} + +impl ConfigExtras for StyleConfig { + fn get_unrecognized(&self) -> &UnrecognizedValues { + &self.unrecognized + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(test, serde_with::skip_serializing_none, derive(serde::Serialize))] +pub struct StyleSources(DashMap); + +#[derive(Clone, Debug)] +#[cfg_attr(test, serde_with::skip_serializing_none, derive(serde::Serialize))] +pub struct StyleSource { + path: PathBuf, +} + +impl StyleSources { + pub fn resolve(config: &mut FileConfigEnum) -> FileResult { + let Some(cfg) = config.extract_file_config(None)? else { + return Ok(Self::default()); + }; + + let mut results = Self::default(); + let mut configs = BTreeMap::new(); + + if let Some(sources) = cfg.sources { + for (id, source) in sources { + configs.insert(id.clone(), source.clone()); + results.add_sources(&id, &source.abs_path()?); + } + }; + + let mut paths_with_names = Vec::new(); + for path in cfg.paths { + let Some(name) = path.file_name() else { + warn!("Ignoring style source with no name from {path:?}"); + continue; + }; + paths_with_names.push(path.clone()); + results.add_sources(name.to_string_lossy().as_ref(), &path); + } + + *config = FileConfigEnum::new_extended(paths_with_names, configs, cfg.custom); + + Ok(results) + } + + /// retrieve a styles' `PathBuf` from the internal catalog + pub fn style_json_path(&self, style_id: &str) -> Option { + let style_id = style_id.trim_end_matches(".json").trim(); + let item = self.0.get(style_id)?; + Some(item.path.clone()) + } + + /// an external representation of the internal catalog + #[must_use] + pub fn get_catalog(&self) -> StyleCatalog { + let entries = StyleCatalog::new(); + for source in &self.0 { + entries.insert( + source.key().clone(), + CatalogStyleEntry { + path: source.path.clone(), + }, + ); + } + entries + } + + /// Adds all the contained files in the given file/directory as style sources. + fn add_sources(&mut self, id: &str, base_path: &PathBuf) { + match list_contained_files(base_path) { + Ok(contained_paths) => { + for child_path in contained_paths { + let Some(name) = child_path.file_name() else { + assert!( + !base_path.is_file(), + "base_path cannot be a file without name as otherwise the id would not exist" + ); + warn!( + "Ignoring {child_path:?} of style source {id} from {base_path:?} because it has no name" + ); + continue; + }; + let name = name + .to_string_lossy() + .trim_end_matches(".json") + .trim() + .to_string(); + self.add_single_source(name, child_path); + } + } + Err(e) => warn!("Ignoring style source {id} from {base_path:?} because of {e}"), + } + } + + /// add a single file with an id to the internal catalog + fn add_single_source(&mut self, id: String, path: PathBuf) { + assert!(path.is_file()); + assert!(!id.is_empty()); + match self.0.entry(id) { + Entry::Occupied(v) => { + warn!( + "Ignoring duplicate style source {id} from {new_path} because it was already configured for {old_path}", + id = v.key(), + old_path = v.get().path.display(), + new_path = path.display() + ); + } + Entry::Vacant(v) => { + info!( + "Configured style source {id} to {new_path}", + id = v.key(), + new_path = path.display() + ); + v.insert(StyleSource { path }); + } + } + } +} + +/// Returns a vector of file paths in a given directory (or file) +/// +/// It ignores hidden files (files whose names begin with `.`) but it does follow symlinks. +/// Will also return file paths in sub-directories recursively. +/// +/// # Errors +/// +/// This function will return an error if Rust's underlying [`read_dir`](std::fs::read_dir) returns an error. +fn list_contained_files(source_path: &Path) -> StyleResult> { + let working_directory = std::env::current_dir().ok(); + let mut contained_files = Vec::new(); + let it = walkdir::WalkDir::new(source_path) + .follow_links(true) + .into_iter() + .filter_entry(|e| e.depth() == 0 || !is_hidden(e)); + for entry in it { + let entry = + entry.map_err(|e| StyleError::DirectoryWalking(e, source_path.to_path_buf()))?; + if entry.path().is_file() { + // path should be relative to the working directory in the catalog + let relative_path = match working_directory { + Some(ref work_dir) => entry + .path() + .strip_prefix(work_dir.as_path()) + .unwrap_or_else(|_| entry.path()) + .to_owned(), + None => entry.into_path(), + }; + contained_files.push(relative_path); + } + } + Ok(contained_files) +} + +/// Returns `true` if `entry`'s file name starts with `.`, `false` otherwise. +fn is_hidden(entry: &walkdir::DirEntry) -> bool { + entry + .file_name() + .to_str() + .is_some_and(|s| s.starts_with('.')) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + #[test] + fn test_add_single_source() { + use std::fs::File; + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("maplibre_demo.json"); + File::create(path.clone()).unwrap(); + + let mut style_sources = StyleSources::default(); + style_sources.add_single_source("maplibre_demo".to_string(), path.clone()); + + assert_eq!(style_sources.0.len(), 1); + let maplibre_demo = style_sources.0.get("maplibre_demo").unwrap(); + assert_eq!(maplibre_demo.path, path); + } + + #[actix_rt::test] + async fn test_styles_resolve() { + let style_dir = PathBuf::from("../tests/fixtures/styles/"); + let mut cfg = FileConfigEnum::new(vec![ + style_dir.join("maplibre_demo.json"), + style_dir.join("src2"), + ]); + + let styles = StyleSources::resolve(&mut cfg).unwrap(); + assert_eq!(styles.0.len(), 3); + insta::with_settings!({sort_maps => true}, { + insta::assert_yaml_snapshot!(styles, @r#" + maplibre_demo: + path: "../tests/fixtures/styles/maplibre_demo.json" + maptiler_basic: + path: "../tests/fixtures/styles/src2/maptiler_basic.json" + osm-liberty-lite: + path: "../tests/fixtures/styles/src2/osm-liberty-lite.json" + "#); + }); + } + + #[actix_rt::test] + async fn test_style_external() { + let style_dir = PathBuf::from("../tests/fixtures/styles/"); + let mut cfg = FileConfigEnum::new(vec![ + style_dir.join("maplibre_demo.json"), + style_dir.join("src2"), + ]); + + let styles = StyleSources::resolve(&mut cfg).unwrap(); + assert_eq!(styles.0.len(), 3); + + let catalog = styles.get_catalog(); + + insta::with_settings!({sort_maps => true}, { + insta::assert_json_snapshot!(catalog, @r#" + { + "maplibre_demo": { + "path": "../tests/fixtures/styles/maplibre_demo.json" + }, + "maptiler_basic": { + "path": "../tests/fixtures/styles/src2/maptiler_basic.json" + }, + "osm-liberty-lite": { + "path": "../tests/fixtures/styles/src2/osm-liberty-lite.json" + } + } + "#); + }); + + assert_eq!(styles.style_json_path("NON_EXISTENT"), None); + assert_eq!( + styles.style_json_path("maplibre_demo.json"), + Some(style_dir.join("maplibre_demo.json")) + ); + assert_eq!(styles.style_json_path("src2"), None); + let src2_dir = style_dir.join("src2"); + assert_eq!( + styles.style_json_path("maptiler_basic"), + Some(src2_dir.join("maptiler_basic.json")) + ); + assert_eq!( + styles.style_json_path("maptiler_basic.json"), + Some(src2_dir.join("maptiler_basic.json")) + ); + assert_eq!( + styles.style_json_path("osm-liberty-lite.json"), + Some(src2_dir.join("osm-liberty-lite.json")) + ); + } + + #[test] + fn test_list_contained_files() { + use std::fs::File; + let dir = tempfile::tempdir().unwrap(); + + let file1 = dir.path().join("file1.txt"); + File::create(&file1).unwrap(); + let hidden_file2 = dir.path().join(".hidden.txt"); + File::create(&hidden_file2).unwrap(); + + let subdir = dir.path().join("subdir"); + std::fs::create_dir(&subdir).unwrap(); + let subdir_file2 = subdir.join("file2.txt"); + File::create(&subdir_file2).unwrap(); + + let hidden_subdir2 = dir.path().join(".subdir2"); + std::fs::create_dir(&hidden_subdir2).unwrap(); + let transitively_hidden_file3 = hidden_subdir2.join("file3.txt"); + File::create(&transitively_hidden_file3).unwrap(); + + let mut result = list_contained_files(dir.path()).unwrap(); + result.sort(); + assert_eq!(result, vec![file1, subdir_file2]); + } + + #[test] + fn test_list_contained_files_error() { + let result = list_contained_files(&PathBuf::from("/non_existent")); + assert!(result.is_err()); + } +} diff --git a/martin/src/utils/error.rs b/martin/src/utils/error.rs index 68dc3850e..56ffdba21 100644 --- a/martin/src/utils/error.rs +++ b/martin/src/utils/error.rs @@ -77,6 +77,10 @@ pub enum MartinError { #[error(transparent)] SpriteError(#[from] crate::sprites::SpriteError), + #[cfg(feature = "styles")] + #[error(transparent)] + StyleError(#[from] crate::styles::StyleError), + #[cfg(feature = "fonts")] #[error(transparent)] FontError(#[from] crate::fonts::FontError), diff --git a/martin/tests/mb_server_test.rs b/martin/tests/mb_server_test.rs index 1d37c9c78..57d8850cb 100644 --- a/martin/tests/mb_server_test.rs +++ b/martin/tests/mb_server_test.rs @@ -56,6 +56,7 @@ async fn mbt_get_catalog() { assert_yaml_snapshot!(body, @r" fonts: {} sprites: {} + styles: {} tiles: m_json: content_type: application/json @@ -87,6 +88,7 @@ async fn mbt_get_catalog_gzip() { assert_yaml_snapshot!(body, @r" fonts: {} sprites: {} + styles: {} tiles: m_json: content_type: application/json diff --git a/martin/tests/pg_server_test.rs b/martin/tests/pg_server_test.rs index 5e693c0c9..77cb4d895 100644 --- a/martin/tests/pg_server_test.rs +++ b/martin/tests/pg_server_test.rs @@ -55,6 +55,7 @@ postgres: assert_yaml_snapshot!(body, @r#" fonts: {} sprites: {} + styles: {} tiles: "-function.withweired---_-characters": content_type: application/x-protobuf diff --git a/martin/tests/pmt_server_test.rs b/martin/tests/pmt_server_test.rs index e9ad729f8..f27c4f5be 100644 --- a/martin/tests/pmt_server_test.rs +++ b/martin/tests/pmt_server_test.rs @@ -54,6 +54,7 @@ async fn pmt_get_catalog() { assert_yaml_snapshot!(body, @r" fonts: {} sprites: {} + styles: {} tiles: stamen_toner__raster_CC-BY-ODbL_z3: content_type: image/png @@ -72,6 +73,7 @@ async fn pmt_get_catalog_gzip() { assert_yaml_snapshot!(body, @r" fonts: {} sprites: {} + styles: {} tiles: p_png: content_type: image/png diff --git a/tests/config.yaml b/tests/config.yaml index b7343e958..762905b3f 100644 --- a/tests/config.yaml +++ b/tests/config.yaml @@ -190,3 +190,9 @@ cog: fonts: - tests/fixtures/fonts/overpass-mono-regular.ttf - tests/fixtures/fonts + +styles: + sources: + style-src1: tests/fixtures/styles/src2 + paths: + - tests/fixtures/styles/maplibre_demo.json diff --git a/tests/expected/auto/catalog_auto.json b/tests/expected/auto/catalog_auto.json index ade46b4e0..0a72a7bce 100644 --- a/tests/expected/auto/catalog_auto.json +++ b/tests/expected/auto/catalog_auto.json @@ -24,6 +24,17 @@ ] } }, + "styles": { + "maplibre_demo": { + "path": "tests/fixtures/styles/maplibre_demo.json" + }, + "maptiler_basic": { + "path": "tests/fixtures/styles/src2/maptiler_basic.json" + }, + "osm-liberty-lite": { + "path": "tests/fixtures/styles/src2/osm-liberty-lite.json" + } + }, "tiles": { "-function.withweired---_-characters": { "content_type": "application/x-protobuf", diff --git a/tests/expected/auto/save_config.yaml b/tests/expected/auto/save_config.yaml index 1b71a500b..3aeae2d22 100644 --- a/tests/expected/auto/save_config.yaml +++ b/tests/expected/auto/save_config.yaml @@ -263,6 +263,9 @@ cog: rgba_u8: tests/fixtures/cog/rgba_u8.tif rgba_u8_nodata: tests/fixtures/cog/rgba_u8_nodata.tiff sprites: tests/fixtures/sprites/src1 +styles: +- tests/fixtures/styles/maplibre_demo.json +- tests/fixtures/styles/src2 fonts: - tests/fixtures/fonts/overpass-mono-regular.ttf - tests/fixtures/fonts diff --git a/tests/expected/auto_mini/catalog_auto.json b/tests/expected/auto_mini/catalog_auto.json index 3ee8c46e9..594e70d46 100644 --- a/tests/expected/auto_mini/catalog_auto.json +++ b/tests/expected/auto_mini/catalog_auto.json @@ -1,6 +1,7 @@ { "fonts": {}, "sprites": {}, + "styles": {}, "tiles": { "webp2": { "content_type": "image/webp", diff --git a/tests/expected/configured/catalog_cfg.json b/tests/expected/configured/catalog_cfg.json index b10815433..be0ce7c06 100644 --- a/tests/expected/configured/catalog_cfg.json +++ b/tests/expected/configured/catalog_cfg.json @@ -29,6 +29,17 @@ ] } }, + "styles": { + "maplibre_demo": { + "path": "tests/fixtures/styles/maplibre_demo.json" + }, + "maptiler_basic": { + "path": "tests/fixtures/styles/src2/maptiler_basic.json" + }, + "osm-liberty-lite": { + "path": "tests/fixtures/styles/src2/osm-liberty-lite.json" + } + }, "tiles": { "MixPoints": { "content_type": "application/x-protobuf", diff --git a/tests/expected/configured/save_config.yaml b/tests/expected/configured/save_config.yaml index fa6723f96..8b8d28561 100644 --- a/tests/expected/configured/save_config.yaml +++ b/tests/expected/configured/save_config.yaml @@ -175,6 +175,10 @@ sprites: paths: tests/fixtures/sprites/src1 sources: mysrc: tests/fixtures/sprites/src2 +styles: + paths: tests/fixtures/styles/maplibre_demo.json + sources: + style-src1: tests/fixtures/styles/src2 fonts: - tests/fixtures/fonts/overpass-mono-regular.ttf - tests/fixtures/fonts diff --git a/tests/expected/configured/style_maplibre_demo.1.json b/tests/expected/configured/style_maplibre_demo.1.json new file mode 100644 index 000000000..df5470a12 --- /dev/null +++ b/tests/expected/configured/style_maplibre_demo.1.json @@ -0,0 +1,544 @@ +{ + "bearing": 0, + "center": [ + 17.65431710431244, + 32.954120326746775 + ], + "glyphs": "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf", + "id": "43f36e14-e3f5-43c1-84c0-50a9c80dc5c7", + "layers": [ + { + "filter": [ + "all" + ], + "id": "background", + "layout": { + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "background-color": "#D8F2FF" + }, + "type": "background" + }, + { + "filter": [ + "all" + ], + "id": "coastline", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "maxzoom": 24, + "minzoom": 0, + "paint": { + "line-blur": 0.5, + "line-color": "#198EC8", + "line-width": { + "stops": [ + [ + 0, + 2 + ], + [ + 6, + 6 + ], + [ + 14, + 9 + ], + [ + 22, + 18 + ] + ] + } + }, + "source": "maplibre", + "source-layer": "countries", + "type": "line" + }, + { + "filter": [ + "all" + ], + "id": "countries-fill", + "layout": { + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "fill-color": [ + "match", + [ + "get", + "ADM0_A3" + ], + [ + "ARM", + "ATG", + "AUS", + "BTN", + "CAN", + "COG", + "CZE", + "GHA", + "GIN", + "HTI", + "ISL", + "JOR", + "KHM", + "KOR", + "LVA", + "MLT", + "MNE", + "MOZ", + "PER", + "SAH", + "SGP", + "SLV", + "SOM", + "TJK", + "TUV", + "UKR", + "WSM" + ], + "#D6C7FF", + [ + "AZE", + "BGD", + "CHL", + "CMR", + "CSI", + "DEU", + "DJI", + "GUY", + "HUN", + "IOA", + "JAM", + "LBN", + "LBY", + "LSO", + "MDG", + "MKD", + "MNG", + "MRT", + "NIU", + "NZL", + "PCN", + "PYF", + "SAU", + "SHN", + "STP", + "TTO", + "UGA", + "UZB", + "ZMB" + ], + "#EBCA8A", + [ + "AGO", + "ASM", + "ATF", + "BDI", + "BFA", + "BGR", + "BLZ", + "BRA", + "CHN", + "CRI", + "ESP", + "HKG", + "HRV", + "IDN", + "IRN", + "ISR", + "KNA", + "LBR", + "LCA", + "MAC", + "MUS", + "NOR", + "PLW", + "POL", + "PRI", + "SDN", + "TUN", + "UMI", + "USA", + "USG", + "VIR", + "VUT" + ], + "#C1E599", + [ + "ARE", + "ARG", + "BHS", + "CIV", + "CLP", + "DMA", + "ETH", + "GAB", + "GRD", + "HMD", + "IND", + "IOT", + "IRL", + "IRQ", + "ITA", + "KOS", + "LUX", + "MEX", + "NAM", + "NER", + "PHL", + "PRT", + "RUS", + "SEN", + "SUR", + "TZA", + "VAT" + ], + "#E7E58F", + [ + "AUT", + "BEL", + "BHR", + "BMU", + "BRB", + "CYN", + "DZA", + "EST", + "FLK", + "GMB", + "GUM", + "HND", + "JEY", + "KGZ", + "LIE", + "MAF", + "MDA", + "NGA", + "NRU", + "SLB", + "SOL", + "SRB", + "SWZ", + "THA", + "TUR", + "VEN", + "VGB" + ], + "#98DDA1", + [ + "AIA", + "BIH", + "BLM", + "BRN", + "CAF", + "CHE", + "COM", + "CPV", + "CUB", + "ECU", + "ESB", + "FSM", + "GAZ", + "GBR", + "GEO", + "KEN", + "LTU", + "MAR", + "MCO", + "MDV", + "NFK", + "NPL", + "PNG", + "PRY", + "QAT", + "SLE", + "SPM", + "SYC", + "TCA", + "TKM", + "TLS", + "VNM", + "WEB", + "WSB", + "YEM", + "ZWE" + ], + "#83D5F4", + [ + "ABW", + "ALB", + "AND", + "ATC", + "BOL", + "COD", + "CUW", + "CYM", + "CYP", + "EGY", + "FJI", + "GGY", + "IMN", + "KAB", + "KAZ", + "KWT", + "LAO", + "MLI", + "MNP", + "MSR", + "MYS", + "NIC", + "NLD", + "PAK", + "PAN", + "PRK", + "ROU", + "SGS", + "SVN", + "SWE", + "TGO", + "TWN", + "VCT", + "ZAF" + ], + "#B1BBF9", + [ + "ATA", + "GRL" + ], + "#FFFFFF", + "#EAB38F" + ] + }, + "source": "maplibre", + "source-layer": "countries", + "type": "fill" + }, + { + "id": "countries-boundary", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": { + "stops": [ + [ + 3, + 0.5 + ], + [ + 6, + 1 + ] + ] + }, + "line-width": { + "stops": [ + [ + 1, + 1 + ], + [ + 6, + 2 + ], + [ + 14, + 6 + ], + [ + 22, + 12 + ] + ] + } + }, + "source": "maplibre", + "source-layer": "countries", + "type": "line" + }, + { + "filter": [ + "all", + [ + "!=", + "name", + "International Date Line" + ] + ], + "id": "geolines", + "layout": { + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "line-color": "#1077B0", + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": 1 + }, + "source": "maplibre", + "source-layer": "geolines", + "type": "line" + }, + { + "filter": [ + "all", + [ + "!=", + "name", + "International Date Line" + ] + ], + "id": "geolines-label", + "layout": { + "symbol-placement": "line", + "text-field": "{name}", + "text-font": [ + "Open Sans Semibold" + ], + "text-size": { + "stops": [ + [ + 2, + 12 + ], + [ + 6, + 16 + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 24, + "minzoom": 1, + "paint": { + "text-color": "#1077B0", + "text-halo-blur": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 1 + }, + "source": "maplibre", + "source-layer": "geolines", + "type": "symbol" + }, + { + "filter": [ + "all" + ], + "id": "countries-label", + "layout": { + "text-field": { + "stops": [ + [ + 2, + "{ABBREV}" + ], + [ + 4, + "{NAME}" + ] + ] + }, + "text-font": [ + "Open Sans Semibold" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 2, + 10 + ], + [ + 4, + 12 + ], + [ + 6, + 16 + ] + ] + }, + "text-transform": { + "stops": [ + [ + 0, + "uppercase" + ], + [ + 2, + "none" + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 24, + "minzoom": 2, + "paint": { + "text-color": "rgba(8, 37, 77, 1)", + "text-halo-blur": { + "stops": [ + [ + 2, + 0.2 + ], + [ + 6, + 0 + ] + ] + }, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": { + "stops": [ + [ + 2, + 1 + ], + [ + 6, + 1.6 + ] + ] + } + }, + "source": "maplibre", + "source-layer": "centroids", + "type": "symbol" + } + ], + "metadata": { + "maptiler:copyright": "This style was generated on MapTiler Cloud. Usage is governed by the license terms in https://github.com/maplibre/demotiles/blob/gh-pages/LICENSE", + "openmaptiles:version": "3.x" + }, + "name": "MapLibre", + "pitch": 0, + "projection": { + "type": "globe" + }, + "sources": { + "maplibre": { + "type": "vector", + "url": "https://demotiles.maplibre.org/tiles/tiles.json" + } + }, + "version": 8, + "zoom": 0.8619833357855968 +} diff --git a/tests/expected/configured/style_maplibre_demo.json b/tests/expected/configured/style_maplibre_demo.json new file mode 100644 index 000000000..df5470a12 --- /dev/null +++ b/tests/expected/configured/style_maplibre_demo.json @@ -0,0 +1,544 @@ +{ + "bearing": 0, + "center": [ + 17.65431710431244, + 32.954120326746775 + ], + "glyphs": "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf", + "id": "43f36e14-e3f5-43c1-84c0-50a9c80dc5c7", + "layers": [ + { + "filter": [ + "all" + ], + "id": "background", + "layout": { + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "background-color": "#D8F2FF" + }, + "type": "background" + }, + { + "filter": [ + "all" + ], + "id": "coastline", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "maxzoom": 24, + "minzoom": 0, + "paint": { + "line-blur": 0.5, + "line-color": "#198EC8", + "line-width": { + "stops": [ + [ + 0, + 2 + ], + [ + 6, + 6 + ], + [ + 14, + 9 + ], + [ + 22, + 18 + ] + ] + } + }, + "source": "maplibre", + "source-layer": "countries", + "type": "line" + }, + { + "filter": [ + "all" + ], + "id": "countries-fill", + "layout": { + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "fill-color": [ + "match", + [ + "get", + "ADM0_A3" + ], + [ + "ARM", + "ATG", + "AUS", + "BTN", + "CAN", + "COG", + "CZE", + "GHA", + "GIN", + "HTI", + "ISL", + "JOR", + "KHM", + "KOR", + "LVA", + "MLT", + "MNE", + "MOZ", + "PER", + "SAH", + "SGP", + "SLV", + "SOM", + "TJK", + "TUV", + "UKR", + "WSM" + ], + "#D6C7FF", + [ + "AZE", + "BGD", + "CHL", + "CMR", + "CSI", + "DEU", + "DJI", + "GUY", + "HUN", + "IOA", + "JAM", + "LBN", + "LBY", + "LSO", + "MDG", + "MKD", + "MNG", + "MRT", + "NIU", + "NZL", + "PCN", + "PYF", + "SAU", + "SHN", + "STP", + "TTO", + "UGA", + "UZB", + "ZMB" + ], + "#EBCA8A", + [ + "AGO", + "ASM", + "ATF", + "BDI", + "BFA", + "BGR", + "BLZ", + "BRA", + "CHN", + "CRI", + "ESP", + "HKG", + "HRV", + "IDN", + "IRN", + "ISR", + "KNA", + "LBR", + "LCA", + "MAC", + "MUS", + "NOR", + "PLW", + "POL", + "PRI", + "SDN", + "TUN", + "UMI", + "USA", + "USG", + "VIR", + "VUT" + ], + "#C1E599", + [ + "ARE", + "ARG", + "BHS", + "CIV", + "CLP", + "DMA", + "ETH", + "GAB", + "GRD", + "HMD", + "IND", + "IOT", + "IRL", + "IRQ", + "ITA", + "KOS", + "LUX", + "MEX", + "NAM", + "NER", + "PHL", + "PRT", + "RUS", + "SEN", + "SUR", + "TZA", + "VAT" + ], + "#E7E58F", + [ + "AUT", + "BEL", + "BHR", + "BMU", + "BRB", + "CYN", + "DZA", + "EST", + "FLK", + "GMB", + "GUM", + "HND", + "JEY", + "KGZ", + "LIE", + "MAF", + "MDA", + "NGA", + "NRU", + "SLB", + "SOL", + "SRB", + "SWZ", + "THA", + "TUR", + "VEN", + "VGB" + ], + "#98DDA1", + [ + "AIA", + "BIH", + "BLM", + "BRN", + "CAF", + "CHE", + "COM", + "CPV", + "CUB", + "ECU", + "ESB", + "FSM", + "GAZ", + "GBR", + "GEO", + "KEN", + "LTU", + "MAR", + "MCO", + "MDV", + "NFK", + "NPL", + "PNG", + "PRY", + "QAT", + "SLE", + "SPM", + "SYC", + "TCA", + "TKM", + "TLS", + "VNM", + "WEB", + "WSB", + "YEM", + "ZWE" + ], + "#83D5F4", + [ + "ABW", + "ALB", + "AND", + "ATC", + "BOL", + "COD", + "CUW", + "CYM", + "CYP", + "EGY", + "FJI", + "GGY", + "IMN", + "KAB", + "KAZ", + "KWT", + "LAO", + "MLI", + "MNP", + "MSR", + "MYS", + "NIC", + "NLD", + "PAK", + "PAN", + "PRK", + "ROU", + "SGS", + "SVN", + "SWE", + "TGO", + "TWN", + "VCT", + "ZAF" + ], + "#B1BBF9", + [ + "ATA", + "GRL" + ], + "#FFFFFF", + "#EAB38F" + ] + }, + "source": "maplibre", + "source-layer": "countries", + "type": "fill" + }, + { + "id": "countries-boundary", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": { + "stops": [ + [ + 3, + 0.5 + ], + [ + 6, + 1 + ] + ] + }, + "line-width": { + "stops": [ + [ + 1, + 1 + ], + [ + 6, + 2 + ], + [ + 14, + 6 + ], + [ + 22, + 12 + ] + ] + } + }, + "source": "maplibre", + "source-layer": "countries", + "type": "line" + }, + { + "filter": [ + "all", + [ + "!=", + "name", + "International Date Line" + ] + ], + "id": "geolines", + "layout": { + "visibility": "visible" + }, + "maxzoom": 24, + "paint": { + "line-color": "#1077B0", + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": 1 + }, + "source": "maplibre", + "source-layer": "geolines", + "type": "line" + }, + { + "filter": [ + "all", + [ + "!=", + "name", + "International Date Line" + ] + ], + "id": "geolines-label", + "layout": { + "symbol-placement": "line", + "text-field": "{name}", + "text-font": [ + "Open Sans Semibold" + ], + "text-size": { + "stops": [ + [ + 2, + 12 + ], + [ + 6, + 16 + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 24, + "minzoom": 1, + "paint": { + "text-color": "#1077B0", + "text-halo-blur": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 1 + }, + "source": "maplibre", + "source-layer": "geolines", + "type": "symbol" + }, + { + "filter": [ + "all" + ], + "id": "countries-label", + "layout": { + "text-field": { + "stops": [ + [ + 2, + "{ABBREV}" + ], + [ + 4, + "{NAME}" + ] + ] + }, + "text-font": [ + "Open Sans Semibold" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 2, + 10 + ], + [ + 4, + 12 + ], + [ + 6, + 16 + ] + ] + }, + "text-transform": { + "stops": [ + [ + 0, + "uppercase" + ], + [ + 2, + "none" + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 24, + "minzoom": 2, + "paint": { + "text-color": "rgba(8, 37, 77, 1)", + "text-halo-blur": { + "stops": [ + [ + 2, + 0.2 + ], + [ + 6, + 0 + ] + ] + }, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": { + "stops": [ + [ + 2, + 1 + ], + [ + 6, + 1.6 + ] + ] + } + }, + "source": "maplibre", + "source-layer": "centroids", + "type": "symbol" + } + ], + "metadata": { + "maptiler:copyright": "This style was generated on MapTiler Cloud. Usage is governed by the license terms in https://github.com/maplibre/demotiles/blob/gh-pages/LICENSE", + "openmaptiles:version": "3.x" + }, + "name": "MapLibre", + "pitch": 0, + "projection": { + "type": "globe" + }, + "sources": { + "maplibre": { + "type": "vector", + "url": "https://demotiles.maplibre.org/tiles/tiles.json" + } + }, + "version": 8, + "zoom": 0.8619833357855968 +} diff --git a/tests/expected/configured/style_src2_maptiler_basic.1.json b/tests/expected/configured/style_src2_maptiler_basic.1.json new file mode 100644 index 000000000..6965885d6 --- /dev/null +++ b/tests/expected/configured/style_src2_maptiler_basic.1.json @@ -0,0 +1,1840 @@ +{ + "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}", + "id": "basic", + "layers": [ + { + "id": "background", + "paint": { + "background-color": "hsl(47, 26%, 88%)" + }, + "type": "background" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "in", + "class", + "residential", + "suburb", + "neighbourhood" + ] + ], + "id": "landuse-residential", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(47, 13%, 86%)", + "fill-opacity": 0.7 + }, + "source": "openmaptiles", + "source-layer": "landuse", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "grass" + ], + "id": "landcover_grass", + "paint": { + "fill-color": "hsl(82, 46%, 72%)", + "fill-opacity": 0.45 + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "wood" + ], + "id": "landcover_wood", + "paint": { + "fill-color": "hsl(82, 46%, 72%)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 8, + 0.6 + ], + [ + 22, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "!=", + "intermittent", + 1 + ], + [ + "!=", + "brunnel", + "tunnel" + ] + ], + "id": "water", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(205, 56%, 73%)" + }, + "source": "openmaptiles", + "source-layer": "water", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "id": "water_intermittent", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(205, 56%, 73%)", + "fill-opacity": 0.7 + }, + "source": "openmaptiles", + "source-layer": "water", + "type": "fill" + }, + { + "filter": [ + "==", + "subclass", + "ice_shelf" + ], + "id": "landcover-ice-shelf", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(47, 26%, 88%)", + "fill-opacity": 0.8 + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "==", + "subclass", + "glacier" + ], + "id": "landcover-glacier", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(47, 22%, 94%)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 0, + 1 + ], + [ + 8, + 0.5 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "in", + "class", + "sand" + ] + ], + "id": "landcover_sand", + "metadata": {}, + "paint": { + "fill-antialias": false, + "fill-color": "rgba(232, 214, 38, 1)", + "fill-opacity": 0.3 + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "agriculture" + ], + "id": "landuse", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#eae0d0" + }, + "source": "openmaptiles", + "source-layer": "landuse", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "national_park" + ], + "id": "landuse_overlay_national_park", + "paint": { + "fill-color": "#E1EBB0", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 5, + 0 + ], + [ + 9, + 0.75 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "id": "waterway-tunnel", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "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 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "!in", + "brunnel", + "tunnel", + "bridge" + ], + [ + "!=", + "intermittent", + 1 + ] + ], + "id": "waterway", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-opacity": 1, + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 1 + ], + [ + 20, + 8 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "!in", + "brunnel", + "tunnel", + "bridge" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "id": "waterway_intermittent", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-dasharray": [ + 2, + 1 + ], + "line-opacity": 1, + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 1 + ], + [ + 20, + 8 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "transit" + ] + ], + "id": "tunnel_railway_transit", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "minzoom": 0, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "id": "building", + "paint": { + "fill-antialias": true, + "fill-color": "rgba(222, 211, 190, 1)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 15, + 1 + ] + ] + }, + "fill-outline-color": { + "stops": [ + [ + 15, + "rgba(212, 177, 146, 0)" + ], + [ + 16, + "rgba(212, 177, 146, 0.5)" + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "building", + "type": "fill" + }, + { + "filter": [ + "==", + "$type", + "Point" + ], + "id": "housenumber", + "layout": { + "text-field": "{housenumber}", + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10 + }, + "minzoom": 17, + "paint": { + "text-color": "rgba(212, 177, 146, 1)" + }, + "source": "openmaptiles", + "source-layer": "housenumber", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "pier" + ] + ], + "id": "road_area_pier", + "layout": { + "visibility": "visible" + }, + "metadata": {}, + "paint": { + "fill-antialias": true, + "fill-color": "hsl(47, 26%, 88%)" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "pier" + ] + ], + "id": "road_pier", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "metadata": {}, + "paint": { + "line-color": "hsl(47, 26%, 88%)", + "line-width": { + "base": 1.2, + "stops": [ + [ + 15, + 1 + ], + [ + 17, + 4 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "in", + "brunnel", + "bridge" + ] + ], + "id": "road_bridge_area", + "layout": {}, + "paint": { + "fill-color": "hsl(47, 26%, 88%)", + "fill-opacity": 0.5 + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "path", + "track" + ] + ], + "id": "road_path", + "layout": { + "line-cap": "square", + "line-join": "bevel" + }, + "paint": { + "line-color": "hsl(0, 0%, 97%)", + "line-dasharray": [ + 1, + 1 + ], + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "minor", + "service" + ] + ], + "id": "road_minor", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "minzoom": 13, + "paint": { + "line-color": "hsl(0, 0%, 97%)", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "id": "tunnel_minor", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#efefef", + "line-dasharray": [ + 0.36, + 0.18 + ], + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "id": "tunnel_major", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#fff", + "line-dasharray": [ + 0.28, + 0.14 + ], + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "in", + "class", + "runway", + "taxiway" + ] + ], + "id": "aeroway-area", + "layout": { + "visibility": "visible" + }, + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "minzoom": 4, + "paint": { + "fill-color": "rgba(255, 255, 255, 1)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "aeroway", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "in", + "class", + "taxiway" + ], + [ + "==", + "$type", + "LineString" + ] + ], + "id": "aeroway-taxiway", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "minzoom": 12, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 1 + ], + [ + 17, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "aeroway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "in", + "class", + "runway" + ], + [ + "==", + "$type", + "LineString" + ] + ], + "id": "aeroway-runway", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "minzoom": 4, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.5, + "stops": [ + [ + 11, + 4 + ], + [ + 17, + 50 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "aeroway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "trunk", + "primary" + ] + ], + "id": "road_trunk_primary", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "id": "road_secondary_tertiary", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 20 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "motorway" + ] + ], + "id": "road_major_motorway", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-offset": 0, + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 1 + ], + [ + 16, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "transit" + ], + [ + "!=", + "brunnel", + "tunnel" + ] + ], + "id": "railway-transit", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "==", + "class", + "rail" + ], + "id": "railway", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "id": "waterway-bridge-case", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#bbbbbb", + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "id": "waterway-bridge", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "id": "bridge_minor case", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#dedede", + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "id": "bridge_major case", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#dedede", + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "id": "bridge_minor", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#efefef", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "id": "bridge_major", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "in", + "admin_level", + 4, + 6, + 8 + ], + "id": "admin_sub", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsla(0, 0%, 60%, 0.5)", + "line-dasharray": [ + 2, + 1 + ] + }, + "source": "openmaptiles", + "source-layer": "boundary", + "type": "line" + }, + { + "filter": [ + "all", + [ + "<=", + "admin_level", + 2 + ], + [ + "==", + "$type", + "LineString" + ], + [ + "!has", + "claimed_by" + ] + ], + "id": "admin_country_z0-4", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "maxzoom": 5, + "minzoom": 0, + "paint": { + "line-color": "hsl(0, 0%, 60%)", + "line-width": { + "base": 1.3, + "stops": [ + [ + 3, + 0.5 + ], + [ + 22, + 15 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "boundary", + "type": "line" + }, + { + "filter": [ + "all", + [ + "<=", + "admin_level", + 2 + ], + [ + "==", + "$type", + "LineString" + ] + ], + "id": "admin_country_z5-", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "minzoom": 5, + "paint": { + "line-color": "hsl(0, 0%, 60%)", + "line-width": { + "base": 1.3, + "stops": [ + [ + 3, + 0.5 + ], + [ + 22, + 15 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "boundary", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "rank", + 1 + ] + ], + "id": "poi_label", + "layout": { + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-offset": [ + 0, + 0.5 + ], + "text-size": 11, + "visibility": "visible" + }, + "minzoom": 14, + "paint": { + "text-color": "#666", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1 + }, + "source": "openmaptiles", + "source-layer": "poi", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "has", + "iata" + ] + ], + "id": "airport-label", + "layout": { + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-offset": [ + 0, + 0.5 + ], + "text-size": 11, + "visibility": "visible" + }, + "minzoom": 10, + "paint": { + "text-color": "#666", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1 + }, + "source": "openmaptiles", + "source-layer": "aerodrome_label", + "type": "symbol" + }, + { + "filter": [ + "==", + "$type", + "LineString" + ], + "id": "road_major_label", + "layout": { + "symbol-placement": "line", + "text-field": "{name:latin} {name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-letter-spacing": 0.1, + "text-rotation-alignment": "map", + "text-size": { + "base": 1.4, + "stops": [ + [ + 10, + 8 + ], + [ + 20, + 14 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "minzoom": 13, + "paint": { + "text-color": "#000", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "transportation_name", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "!in", + "class", + "city", + "state", + "country", + "continent" + ] + ], + "id": "place_label_other", + "layout": { + "text-anchor": "center", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 6, + "text-size": { + "stops": [ + [ + 6, + 10 + ], + [ + 12, + 14 + ] + ] + }, + "visibility": "visible" + }, + "minzoom": 8, + "paint": { + "text-color": "hsl(0, 0%, 25%)", + "text-halo-blur": 0, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "city" + ] + ], + "id": "place_label_city", + "layout": { + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 16 + ] + ] + } + }, + "maxzoom": 16, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 0, + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "country" + ], + [ + "!has", + "iso_a2" + ] + ], + "id": "country_label-other", + "layout": { + "text-field": "{name:latin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 22 + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 12, + "paint": { + "text-color": "hsl(0, 0%, 13%)", + "text-halo-blur": 0, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "country" + ], + [ + "has", + "iso_a2" + ] + ], + "id": "country_label", + "layout": { + "text-field": "{name:latin}", + "text-font": [ + "Noto Sans Bold" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 22 + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 12, + "paint": { + "text-color": "hsl(0, 0%, 13%)", + "text-halo-blur": 0, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + } + ], + "metadata": { + "mapbox:autocomposite": false, + "mapbox:type": "template", + "maputnik:renderer": "mbgljs", + "openmaptiles:mapbox:owner": "openmaptiles", + "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t", + "openmaptiles:version": "3.x" + }, + "name": "Basic", + "sources": { + "openmaptiles": { + "type": "vector", + "url": "https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key={key}" + } + }, + "sprite": "https://openmaptiles.github.io/maptiler-basic-gl-style/sprite", + "version": 8 +} diff --git a/tests/expected/configured/style_src2_maptiler_basic.json b/tests/expected/configured/style_src2_maptiler_basic.json new file mode 100644 index 000000000..6965885d6 --- /dev/null +++ b/tests/expected/configured/style_src2_maptiler_basic.json @@ -0,0 +1,1840 @@ +{ + "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}", + "id": "basic", + "layers": [ + { + "id": "background", + "paint": { + "background-color": "hsl(47, 26%, 88%)" + }, + "type": "background" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "in", + "class", + "residential", + "suburb", + "neighbourhood" + ] + ], + "id": "landuse-residential", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(47, 13%, 86%)", + "fill-opacity": 0.7 + }, + "source": "openmaptiles", + "source-layer": "landuse", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "grass" + ], + "id": "landcover_grass", + "paint": { + "fill-color": "hsl(82, 46%, 72%)", + "fill-opacity": 0.45 + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "wood" + ], + "id": "landcover_wood", + "paint": { + "fill-color": "hsl(82, 46%, 72%)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 8, + 0.6 + ], + [ + 22, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "!=", + "intermittent", + 1 + ], + [ + "!=", + "brunnel", + "tunnel" + ] + ], + "id": "water", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(205, 56%, 73%)" + }, + "source": "openmaptiles", + "source-layer": "water", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "id": "water_intermittent", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(205, 56%, 73%)", + "fill-opacity": 0.7 + }, + "source": "openmaptiles", + "source-layer": "water", + "type": "fill" + }, + { + "filter": [ + "==", + "subclass", + "ice_shelf" + ], + "id": "landcover-ice-shelf", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(47, 26%, 88%)", + "fill-opacity": 0.8 + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "==", + "subclass", + "glacier" + ], + "id": "landcover-glacier", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "hsl(47, 22%, 94%)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 0, + 1 + ], + [ + 8, + 0.5 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "in", + "class", + "sand" + ] + ], + "id": "landcover_sand", + "metadata": {}, + "paint": { + "fill-antialias": false, + "fill-color": "rgba(232, 214, 38, 1)", + "fill-opacity": 0.3 + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "agriculture" + ], + "id": "landuse", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#eae0d0" + }, + "source": "openmaptiles", + "source-layer": "landuse", + "type": "fill" + }, + { + "filter": [ + "==", + "class", + "national_park" + ], + "id": "landuse_overlay_national_park", + "paint": { + "fill-color": "#E1EBB0", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 5, + 0 + ], + [ + 9, + 0.75 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "landcover", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ] + ], + "id": "waterway-tunnel", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "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 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "!in", + "brunnel", + "tunnel", + "bridge" + ], + [ + "!=", + "intermittent", + 1 + ] + ], + "id": "waterway", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-opacity": 1, + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 1 + ], + [ + 20, + 8 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "!in", + "brunnel", + "tunnel", + "bridge" + ], + [ + "==", + "intermittent", + 1 + ] + ], + "id": "waterway_intermittent", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-dasharray": [ + 2, + 1 + ], + "line-opacity": 1, + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 1 + ], + [ + 20, + 8 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "transit" + ] + ], + "id": "tunnel_railway_transit", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "minzoom": 0, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "id": "building", + "paint": { + "fill-antialias": true, + "fill-color": "rgba(222, 211, 190, 1)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 15, + 1 + ] + ] + }, + "fill-outline-color": { + "stops": [ + [ + 15, + "rgba(212, 177, 146, 0)" + ], + [ + 16, + "rgba(212, 177, 146, 0.5)" + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "building", + "type": "fill" + }, + { + "filter": [ + "==", + "$type", + "Point" + ], + "id": "housenumber", + "layout": { + "text-field": "{housenumber}", + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10 + }, + "minzoom": 17, + "paint": { + "text-color": "rgba(212, 177, 146, 1)" + }, + "source": "openmaptiles", + "source-layer": "housenumber", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "pier" + ] + ], + "id": "road_area_pier", + "layout": { + "visibility": "visible" + }, + "metadata": {}, + "paint": { + "fill-antialias": true, + "fill-color": "hsl(47, 26%, 88%)" + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "pier" + ] + ], + "id": "road_pier", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "metadata": {}, + "paint": { + "line-color": "hsl(47, 26%, 88%)", + "line-width": { + "base": 1.2, + "stops": [ + [ + 15, + 1 + ], + [ + 17, + 4 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "in", + "brunnel", + "bridge" + ] + ], + "id": "road_bridge_area", + "layout": {}, + "paint": { + "fill-color": "hsl(47, 26%, 88%)", + "fill-opacity": 0.5 + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "path", + "track" + ] + ], + "id": "road_path", + "layout": { + "line-cap": "square", + "line-join": "bevel" + }, + "paint": { + "line-color": "hsl(0, 0%, 97%)", + "line-dasharray": [ + 1, + 1 + ], + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "minor", + "service" + ] + ], + "id": "road_minor", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "minzoom": 13, + "paint": { + "line-color": "hsl(0, 0%, 97%)", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "id": "tunnel_minor", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#efefef", + "line-dasharray": [ + 0.36, + 0.18 + ], + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "tunnel" + ], + [ + "in", + "class", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "id": "tunnel_major", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#fff", + "line-dasharray": [ + 0.28, + 0.14 + ], + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "in", + "class", + "runway", + "taxiway" + ] + ], + "id": "aeroway-area", + "layout": { + "visibility": "visible" + }, + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "minzoom": 4, + "paint": { + "fill-color": "rgba(255, 255, 255, 1)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "aeroway", + "type": "fill" + }, + { + "filter": [ + "all", + [ + "in", + "class", + "taxiway" + ], + [ + "==", + "$type", + "LineString" + ] + ], + "id": "aeroway-taxiway", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "minzoom": 12, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 1 + ], + [ + 17, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "aeroway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "in", + "class", + "runway" + ], + [ + "==", + "$type", + "LineString" + ] + ], + "id": "aeroway-runway", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "metadata": { + "mapbox:group": "1444849345966.4436" + }, + "minzoom": 4, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": { + "base": 1.5, + "stops": [ + [ + 11, + 4 + ], + [ + 17, + 50 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "aeroway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "trunk", + "primary" + ] + ], + "id": "road_trunk_primary", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ], + "id": "road_secondary_tertiary", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 20 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "motorway" + ] + ], + "id": "road_major_motorway", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-offset": 0, + "line-width": { + "base": 1.4, + "stops": [ + [ + 8, + 1 + ], + [ + 16, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "class", + "transit" + ], + [ + "!=", + "brunnel", + "tunnel" + ] + ], + "id": "railway-transit", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "==", + "class", + "rail" + ], + "id": "railway", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "id": "waterway-bridge-case", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#bbbbbb", + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ] + ], + "id": "waterway-bridge", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "waterway", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "id": "bridge_minor case", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#dedede", + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "id": "bridge_major case", + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "#dedede", + "line-gap-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + }, + "line-width": { + "base": 1.6, + "stops": [ + [ + 12, + 0.5 + ], + [ + 20, + 10 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "==", + "class", + "minor_road" + ] + ], + "id": "bridge_minor", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#efefef", + "line-width": { + "base": 1.55, + "stops": [ + [ + 4, + 0.25 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "brunnel", + "bridge" + ], + [ + "in", + "class", + "primary", + "secondary", + "tertiary", + "trunk" + ] + ], + "id": "bridge_major", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": { + "base": 1.4, + "stops": [ + [ + 6, + 0.5 + ], + [ + 20, + 30 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "transportation", + "type": "line" + }, + { + "filter": [ + "in", + "admin_level", + 4, + 6, + 8 + ], + "id": "admin_sub", + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "hsla(0, 0%, 60%, 0.5)", + "line-dasharray": [ + 2, + 1 + ] + }, + "source": "openmaptiles", + "source-layer": "boundary", + "type": "line" + }, + { + "filter": [ + "all", + [ + "<=", + "admin_level", + 2 + ], + [ + "==", + "$type", + "LineString" + ], + [ + "!has", + "claimed_by" + ] + ], + "id": "admin_country_z0-4", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "maxzoom": 5, + "minzoom": 0, + "paint": { + "line-color": "hsl(0, 0%, 60%)", + "line-width": { + "base": 1.3, + "stops": [ + [ + 3, + 0.5 + ], + [ + 22, + 15 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "boundary", + "type": "line" + }, + { + "filter": [ + "all", + [ + "<=", + "admin_level", + 2 + ], + [ + "==", + "$type", + "LineString" + ] + ], + "id": "admin_country_z5-", + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "minzoom": 5, + "paint": { + "line-color": "hsl(0, 0%, 60%)", + "line-width": { + "base": 1.3, + "stops": [ + [ + 3, + 0.5 + ], + [ + 22, + 15 + ] + ] + } + }, + "source": "openmaptiles", + "source-layer": "boundary", + "type": "line" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "rank", + 1 + ] + ], + "id": "poi_label", + "layout": { + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-offset": [ + 0, + 0.5 + ], + "text-size": 11, + "visibility": "visible" + }, + "minzoom": 14, + "paint": { + "text-color": "#666", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1 + }, + "source": "openmaptiles", + "source-layer": "poi", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "has", + "iata" + ] + ], + "id": "airport-label", + "layout": { + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-offset": [ + 0, + 0.5 + ], + "text-size": 11, + "visibility": "visible" + }, + "minzoom": 10, + "paint": { + "text-color": "#666", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1 + }, + "source": "openmaptiles", + "source-layer": "aerodrome_label", + "type": "symbol" + }, + { + "filter": [ + "==", + "$type", + "LineString" + ], + "id": "road_major_label", + "layout": { + "symbol-placement": "line", + "text-field": "{name:latin} {name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-letter-spacing": 0.1, + "text-rotation-alignment": "map", + "text-size": { + "base": 1.4, + "stops": [ + [ + 10, + 8 + ], + [ + 20, + 14 + ] + ] + }, + "text-transform": "uppercase", + "visibility": "visible" + }, + "minzoom": 13, + "paint": { + "text-color": "#000", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "transportation_name", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "!in", + "class", + "city", + "state", + "country", + "continent" + ] + ], + "id": "place_label_other", + "layout": { + "text-anchor": "center", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 6, + "text-size": { + "stops": [ + [ + 6, + 10 + ], + [ + 12, + 14 + ] + ] + }, + "visibility": "visible" + }, + "minzoom": 8, + "paint": { + "text-color": "hsl(0, 0%, 25%)", + "text-halo-blur": 0, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "city" + ] + ], + "id": "place_label_city", + "layout": { + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 16 + ] + ] + } + }, + "maxzoom": 16, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 0, + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "country" + ], + [ + "!has", + "iso_a2" + ] + ], + "id": "country_label-other", + "layout": { + "text-field": "{name:latin}", + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 22 + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 12, + "paint": { + "text-color": "hsl(0, 0%, 13%)", + "text-halo-blur": 0, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + }, + { + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "country" + ], + [ + "has", + "iso_a2" + ] + ], + "id": "country_label", + "layout": { + "text-field": "{name:latin}", + "text-font": [ + "Noto Sans Bold" + ], + "text-max-width": 10, + "text-size": { + "stops": [ + [ + 3, + 12 + ], + [ + 8, + 22 + ] + ] + }, + "visibility": "visible" + }, + "maxzoom": 12, + "paint": { + "text-color": "hsl(0, 0%, 13%)", + "text-halo-blur": 0, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + }, + "source": "openmaptiles", + "source-layer": "place", + "type": "symbol" + } + ], + "metadata": { + "mapbox:autocomposite": false, + "mapbox:type": "template", + "maputnik:renderer": "mbgljs", + "openmaptiles:mapbox:owner": "openmaptiles", + "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t", + "openmaptiles:version": "3.x" + }, + "name": "Basic", + "sources": { + "openmaptiles": { + "type": "vector", + "url": "https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key={key}" + } + }, + "sprite": "https://openmaptiles.github.io/maptiler-basic-gl-style/sprite", + "version": 8 +} diff --git a/tests/fixtures/styles/maplibre_demo.json b/tests/fixtures/styles/maplibre_demo.json new file mode 100644 index 000000000..c79a0e574 --- /dev/null +++ b/tests/fixtures/styles/maplibre_demo.json @@ -0,0 +1,239 @@ +{ + "id": "43f36e14-e3f5-43c1-84c0-50a9c80dc5c7", + "name": "MapLibre", + "projection": {"type": "globe"}, + "zoom": 0.8619833357855968, + "pitch": 0, + "center": [ + 17.65431710431244, + 32.954120326746775 + ], + "glyphs": "https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "#D8F2FF" + }, + "filter": ["all"], + "layout": { + "visibility": "visible" + }, + "maxzoom": 24 + }, + { + "id": "coastline", + "type": "line", + "paint": { + "line-blur": 0.5, + "line-color": "#198EC8", + "line-width": { + "stops": [ + [0,2], + [6,6], + [14,9], + [22,18] + ] + } + }, + "filter": ["all"], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "source": "maplibre", + "maxzoom": 24, + "minzoom": 0, + "source-layer": "countries" + }, + { + "id": "countries-fill", + "type": "fill", + "paint": { + "fill-color": [ + "match", + ["get","ADM0_A3"], + ["ARM","ATG","AUS","BTN","CAN","COG","CZE","GHA","GIN","HTI","ISL","JOR","KHM","KOR","LVA","MLT","MNE","MOZ","PER","SAH","SGP","SLV","SOM","TJK","TUV","UKR","WSM"], + "#D6C7FF", + ["AZE","BGD","CHL","CMR","CSI","DEU","DJI","GUY","HUN","IOA","JAM","LBN","LBY","LSO","MDG","MKD","MNG","MRT","NIU","NZL","PCN","PYF","SAU","SHN","STP","TTO","UGA","UZB","ZMB"], + "#EBCA8A", + ["AGO","ASM","ATF","BDI","BFA","BGR","BLZ","BRA","CHN","CRI","ESP","HKG","HRV","IDN","IRN","ISR","KNA","LBR","LCA","MAC","MUS","NOR","PLW","POL","PRI","SDN","TUN","UMI","USA","USG","VIR","VUT"], + "#C1E599", + ["ARE","ARG","BHS","CIV","CLP","DMA","ETH","GAB","GRD","HMD","IND","IOT","IRL","IRQ","ITA","KOS","LUX","MEX","NAM","NER","PHL","PRT","RUS","SEN","SUR","TZA","VAT"], + "#E7E58F", + ["AUT","BEL","BHR","BMU","BRB","CYN","DZA","EST","FLK","GMB","GUM","HND","JEY","KGZ","LIE","MAF","MDA","NGA","NRU","SLB","SOL","SRB","SWZ","THA","TUR","VEN","VGB"], + "#98DDA1", + ["AIA","BIH","BLM","BRN","CAF","CHE","COM","CPV","CUB","ECU","ESB","FSM","GAZ","GBR","GEO","KEN","LTU","MAR","MCO","MDV","NFK","NPL","PNG","PRY","QAT","SLE","SPM","SYC","TCA","TKM","TLS","VNM","WEB","WSB","YEM","ZWE"], + "#83D5F4", + ["ABW","ALB","AND","ATC","BOL","COD","CUW","CYM","CYP","EGY","FJI","GGY","IMN","KAB","KAZ","KWT","LAO","MLI","MNP","MSR","MYS","NIC","NLD","PAK","PAN","PRK","ROU","SGS","SVN","SWE","TGO","TWN","VCT","ZAF"], + "#B1BBF9", + ["ATA","GRL"], + "#FFFFFF", + "#EAB38F" + ] + }, + "filter": ["all"], + "layout": { + "visibility": "visible" + }, + "source": "maplibre", + "maxzoom": 24, + "source-layer": "countries" + }, + { + "id": "countries-boundary", + "type": "line", + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-width": { + "stops": [ + [1,1], + [6,2], + [14,6], + [22,12] + ] + }, + "line-opacity": { + "stops": [ + [3,0.5], + [6,1] + ] + } + }, + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "source": "maplibre", + "maxzoom": 24, + "source-layer": "countries" + }, + { + "id": "geolines", + "type": "line", + "paint": { + "line-color": "#1077B0", + "line-opacity": 1, + "line-dasharray": [3,3] + }, + "filter": [ + "all", + [ + "!=", + "name", + "International Date Line" + ] + ], + "layout": { + "visibility": "visible" + }, + "source": "maplibre", + "maxzoom": 24, + "source-layer": "geolines" + }, + { + "id": "geolines-label", + "type": "symbol", + "paint": { + "text-color": "#1077B0", + "text-halo-blur": 1, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": 1 + }, + "filter": [ + "all", + [ + "!=", + "name", + "International Date Line" + ] + ], + "layout": { + "text-font": [ + "Open Sans Semibold" + ], + "text-size": { + "stops": [ + [2,12], + [6,16] + ] + }, + "text-field": "{name}", + "visibility": "visible", + "symbol-placement": "line" + }, + "source": "maplibre", + "maxzoom": 24, + "minzoom": 1, + "source-layer": "geolines" + }, + { + "id": "countries-label", + "type": "symbol", + "paint": { + "text-color": "rgba(8, 37, 77, 1)", + "text-halo-blur": { + "stops": [ + [2,0.2], + [6,0] + ] + }, + "text-halo-color": "rgba(255, 255, 255, 1)", + "text-halo-width": { + "stops": [ + [2,1], + [6,1.6] + ] + } + }, + "filter": [ + "all" + ], + "layout": { + "text-font": [ + "Open Sans Semibold" + ], + "text-size": { + "stops": [ + [2,10], + [4,12], + [6,16] + ] + }, + "text-field": { + "stops": [ + [2,"{ABBREV}"], + [4,"{NAME}"] + ] + }, + "visibility": "visible", + "text-max-width": 10, + "text-transform": { + "stops": [ + [0,"uppercase"], + [2,"none"] + ] + } + }, + "source": "maplibre", + "maxzoom": 24, + "minzoom": 2, + "source-layer": "centroids" + } + ], + "bearing": 0, + "sources": { + "maplibre": { + "url": "https://demotiles.maplibre.org/tiles/tiles.json", + "type": "vector" + } + }, + "version": 8, + "metadata": { + "maptiler:copyright": "This style was generated on MapTiler Cloud. Usage is governed by the license terms in https://github.com/maplibre/demotiles/blob/gh-pages/LICENSE", + "openmaptiles:version": "3.x" + } +} diff --git a/tests/fixtures/styles/src2/maptiler_basic.json b/tests/fixtures/styles/src2/maptiler_basic.json new file mode 100644 index 000000000..d8e664468 --- /dev/null +++ b/tests/fixtures/styles/src2/maptiler_basic.json @@ -0,0 +1,815 @@ +{ + "version": 8, + "name": "Basic", + "metadata": { + "mapbox:autocomposite": false, + "mapbox:type": "template", + "maputnik:renderer": "mbgljs", + "openmaptiles:version": "3.x", + "openmaptiles:mapbox:owner": "openmaptiles", + "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t" + }, + "sources": { + "openmaptiles": { + "type": "vector", + "url": "https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key={key}" + } + }, + "sprite": "https://openmaptiles.github.io/maptiler-basic-gl-style/sprite", + "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}", + "layers": [ + { + "id": "background", + "type": "background", + "paint": {"background-color": "hsl(47, 26%, 88%)"} + }, + { + "id": "landuse-residential", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landuse", + "filter": [ + "all", + ["==", "$type", "Polygon"], + ["in", "class", "residential", "suburb", "neighbourhood"] + ], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "hsl(47, 13%, 86%)", "fill-opacity": 0.7} + }, + { + "id": "landcover_grass", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "filter": ["==", "class", "grass"], + "paint": {"fill-color": "hsl(82, 46%, 72%)", "fill-opacity": 0.45} + }, + { + "id": "landcover_wood", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "filter": ["==", "class", "wood"], + "paint": { + "fill-color": "hsl(82, 46%, 72%)", + "fill-opacity": {"base": 1, "stops": [[8, 0.6], [22, 1]]} + } + }, + { + "id": "water", + "type": "fill", + "source": "openmaptiles", + "source-layer": "water", + "filter": [ + "all", + ["==", "$type", "Polygon"], + ["!=", "intermittent", 1], + ["!=", "brunnel", "tunnel"] + ], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "hsl(205, 56%, 73%)"} + }, + { + "id": "water_intermittent", + "type": "fill", + "source": "openmaptiles", + "source-layer": "water", + "filter": ["all", ["==", "$type", "Polygon"], ["==", "intermittent", 1]], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "hsl(205, 56%, 73%)", "fill-opacity": 0.7} + }, + { + "id": "landcover-ice-shelf", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "filter": ["==", "subclass", "ice_shelf"], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "hsl(47, 26%, 88%)", "fill-opacity": 0.8} + }, + { + "id": "landcover-glacier", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "filter": ["==", "subclass", "glacier"], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "hsl(47, 22%, 94%)", + "fill-opacity": {"base": 1, "stops": [[0, 1], [8, 0.5]]} + } + }, + { + "id": "landcover_sand", + "type": "fill", + "metadata": {}, + "source": "openmaptiles", + "source-layer": "landcover", + "filter": ["all", ["in", "class", "sand"]], + "paint": { + "fill-antialias": false, + "fill-color": "rgba(232, 214, 38, 1)", + "fill-opacity": 0.3 + } + }, + { + "id": "landuse", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landuse", + "filter": ["==", "class", "agriculture"], + "layout": {"visibility": "visible"}, + "paint": {"fill-color": "#eae0d0"} + }, + { + "id": "landuse_overlay_national_park", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "filter": ["==", "class", "national_park"], + "paint": { + "fill-color": "#E1EBB0", + "fill-opacity": {"base": 1, "stops": [[5, 0], [9, 0.75]]} + } + }, + { + "id": "waterway-tunnel", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "tunnel"] + ], + "layout": {"visibility": "visible"}, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "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", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["!in", "brunnel", "tunnel", "bridge"], + ["!=", "intermittent", 1] + ], + "layout": {"visibility": "visible"}, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-opacity": 1, + "line-width": {"base": 1.4, "stops": [[8, 1], [20, 8]]} + } + }, + { + "id": "waterway_intermittent", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["!in", "brunnel", "tunnel", "bridge"], + ["==", "intermittent", 1] + ], + "layout": {"visibility": "visible"}, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-dasharray": [2, 1], + "line-opacity": 1, + "line-width": {"base": 1.4, "stops": [[8, 1], [20, 8]]} + } + }, + { + "id": "tunnel_railway_transit", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 0, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "tunnel"], + ["==", "class", "transit"] + ], + "layout": {"line-cap": "butt", "line-join": "miter"}, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-dasharray": [3, 3], + "line-opacity": {"base": 1, "stops": [[11, 0], [16, 1]]} + } + }, + { + "id": "building", + "type": "fill", + "source": "openmaptiles", + "source-layer": "building", + "paint": { + "fill-antialias": true, + "fill-color": "rgba(222, 211, 190, 1)", + "fill-opacity": {"base": 1, "stops": [[13, 0], [15, 1]]}, + "fill-outline-color": { + "stops": [ + [15, "rgba(212, 177, 146, 0)"], + [16, "rgba(212, 177, 146, 0.5)"] + ] + } + } + }, + { + "id": "housenumber", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "housenumber", + "minzoom": 17, + "filter": ["==", "$type", "Point"], + "layout": { + "text-field": "{housenumber}", + "text-font": ["Noto Sans Regular"], + "text-size": 10 + }, + "paint": {"text-color": "rgba(212, 177, 146, 1)"} + }, + { + "id": "road_area_pier", + "type": "fill", + "metadata": {}, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": ["all", ["==", "$type", "Polygon"], ["==", "class", "pier"]], + "layout": {"visibility": "visible"}, + "paint": {"fill-antialias": true, "fill-color": "hsl(47, 26%, 88%)"} + }, + { + "id": "road_pier", + "type": "line", + "metadata": {}, + "source": "openmaptiles", + "source-layer": "transportation", + "filter": ["all", ["==", "$type", "LineString"], ["in", "class", "pier"]], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "hsl(47, 26%, 88%)", + "line-width": {"base": 1.2, "stops": [[15, 1], [17, 4]]} + } + }, + { + "id": "road_bridge_area", + "type": "fill", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "Polygon"], + ["in", "brunnel", "bridge"] + ], + "layout": {}, + "paint": {"fill-color": "hsl(47, 26%, 88%)", "fill-opacity": 0.5} + }, + { + "id": "road_path", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "class", "path", "track"] + ], + "layout": {"line-cap": "square", "line-join": "bevel"}, + "paint": { + "line-color": "hsl(0, 0%, 97%)", + "line-dasharray": [1, 1], + "line-width": {"base": 1.55, "stops": [[4, 0.25], [20, 10]]} + } + }, + { + "id": "road_minor", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "class", "minor", "service"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "hsl(0, 0%, 97%)", + "line-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]} + } + }, + { + "id": "tunnel_minor", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "tunnel"], + ["==", "class", "minor_road"] + ], + "layout": {"line-cap": "butt", "line-join": "miter"}, + "paint": { + "line-color": "#efefef", + "line-dasharray": [0.36, 0.18], + "line-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]} + } + }, + { + "id": "tunnel_major", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "tunnel"], + ["in", "class", "primary", "secondary", "tertiary", "trunk"] + ], + "layout": {"line-cap": "butt", "line-join": "miter"}, + "paint": { + "line-color": "#fff", + "line-dasharray": [0.28, 0.14], + "line-width": {"base": 1.4, "stops": [[6, 0.5], [20, 30]]} + } + }, + { + "id": "aeroway-area", + "type": "fill", + "metadata": {"mapbox:group": "1444849345966.4436"}, + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 4, + "filter": [ + "all", + ["==", "$type", "Polygon"], + ["in", "class", "runway", "taxiway"] + ], + "layout": {"visibility": "visible"}, + "paint": { + "fill-color": "rgba(255, 255, 255, 1)", + "fill-opacity": {"base": 1, "stops": [[13, 0], [14, 1]]} + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "metadata": {"mapbox:group": "1444849345966.4436"}, + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 12, + "filter": [ + "all", + ["in", "class", "taxiway"], + ["==", "$type", "LineString"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": {"base": 1.5, "stops": [[12, 1], [17, 10]]} + } + }, + { + "id": "aeroway-runway", + "type": "line", + "metadata": {"mapbox:group": "1444849345966.4436"}, + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 4, + "filter": [ + "all", + ["in", "class", "runway"], + ["==", "$type", "LineString"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": {"base": 1.5, "stops": [[11, 4], [17, 50]]} + } + }, + { + "id": "road_trunk_primary", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "class", "trunk", "primary"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "#fff", + "line-width": {"base": 1.4, "stops": [[6, 0.5], [20, 30]]} + } + }, + { + "id": "road_secondary_tertiary", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "class", "secondary", "tertiary"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "#fff", + "line-width": {"base": 1.4, "stops": [[6, 0.5], [20, 20]]} + } + }, + { + "id": "road_major_motorway", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "class", "motorway"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "hsl(0, 0%, 100%)", + "line-offset": 0, + "line-width": {"base": 1.4, "stops": [[8, 1], [16, 10]]} + } + }, + { + "id": "railway-transit", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "class", "transit"], + ["!=", "brunnel", "tunnel"] + ], + "layout": {"visibility": "visible"}, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-opacity": {"base": 1, "stops": [[11, 0], [16, 1]]} + } + }, + { + "id": "railway", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": ["==", "class", "rail"], + "layout": {"visibility": "visible"}, + "paint": { + "line-color": "hsl(34, 12%, 66%)", + "line-opacity": {"base": 1, "stops": [[11, 0], [16, 1]]} + } + }, + { + "id": "waterway-bridge-case", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "bridge"] + ], + "layout": {"line-cap": "butt", "line-join": "miter"}, + "paint": { + "line-color": "#bbbbbb", + "line-gap-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]}, + "line-width": {"base": 1.6, "stops": [[12, 0.5], [20, 10]]} + } + }, + { + "id": "waterway-bridge", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "bridge"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "hsl(205, 56%, 73%)", + "line-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]} + } + }, + { + "id": "bridge_minor case", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "bridge"], + ["==", "class", "minor_road"] + ], + "layout": {"line-cap": "butt", "line-join": "miter"}, + "paint": { + "line-color": "#dedede", + "line-gap-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]}, + "line-width": {"base": 1.6, "stops": [[12, 0.5], [20, 10]]} + } + }, + { + "id": "bridge_major case", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "bridge"], + ["in", "class", "primary", "secondary", "tertiary", "trunk"] + ], + "layout": {"line-cap": "butt", "line-join": "miter"}, + "paint": { + "line-color": "#dedede", + "line-gap-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]}, + "line-width": {"base": 1.6, "stops": [[12, 0.5], [20, 10]]} + } + }, + { + "id": "bridge_minor", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "bridge"], + ["==", "class", "minor_road"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "#efefef", + "line-width": {"base": 1.55, "stops": [[4, 0.25], [20, 30]]} + } + }, + { + "id": "bridge_major", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "brunnel", "bridge"], + ["in", "class", "primary", "secondary", "tertiary", "trunk"] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-color": "#fff", + "line-width": {"base": 1.4, "stops": [[6, 0.5], [20, 30]]} + } + }, + { + "id": "admin_sub", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "filter": ["in", "admin_level", 4, 6, 8], + "layout": {"visibility": "visible"}, + "paint": {"line-color": "hsla(0, 0%, 60%, 0.5)", "line-dasharray": [2, 1]} + }, + { + "id": "admin_country_z0-4", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "minzoom": 0, + "maxzoom": 5, + "filter": [ + "all", + ["<=", "admin_level", 2], + ["==", "$type", "LineString"], + ["!has", "claimed_by"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(0, 0%, 60%)", + "line-width": {"base": 1.3, "stops": [[3, 0.5], [22, 15]]} + } + }, + { + "id": "admin_country_z5-", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "minzoom": 5, + "filter": [ + "all", + ["<=", "admin_level", 2], + ["==", "$type", "LineString"] + ], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "paint": { + "line-color": "hsl(0, 0%, 60%)", + "line-width": {"base": 1.3, "stops": [[3, 0.5], [22, 15]]} + } + }, + { + "id": "poi_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "poi", + "minzoom": 14, + "filter": ["all", ["==", "$type", "Point"], ["==", "rank", 1]], + "layout": { + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 8, + "text-offset": [0, 0.5], + "text-size": 11, + "visibility": "visible" + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1 + } + }, + { + "id": "airport-label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "aerodrome_label", + "minzoom": 10, + "filter": ["all", ["has", "iata"]], + "layout": { + "icon-size": 1, + "text-anchor": "top", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 8, + "text-offset": [0, 0.5], + "text-size": 11, + "visibility": "visible" + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 1 + } + }, + { + "id": "road_major_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 13, + "filter": ["==", "$type", "LineString"], + "layout": { + "symbol-placement": "line", + "text-field": "{name:latin} {name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-letter-spacing": 0.1, + "text-rotation-alignment": "map", + "text-size": {"base": 1.4, "stops": [[10, 8], [20, 14]]}, + "text-transform": "uppercase", + "visibility": "visible" + }, + "paint": { + "text-color": "#000", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + } + }, + { + "id": "place_label_other", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 8, + "filter": [ + "all", + ["==", "$type", "Point"], + ["!in", "class", "city", "state", "country", "continent"] + ], + "layout": { + "text-anchor": "center", + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 6, + "text-size": {"stops": [[6, 10], [12, 14]]}, + "visibility": "visible" + }, + "paint": { + "text-color": "hsl(0, 0%, 25%)", + "text-halo-blur": 0, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 2 + } + }, + { + "id": "place_label_city", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 16, + "filter": ["all", ["==", "$type", "Point"], ["==", "class", "city"]], + "layout": { + "text-field": "{name:latin}\n{name:nonlatin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 10, + "text-size": {"stops": [[3, 12], [8, 16]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 0, + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 2 + } + }, + { + "id": "country_label-other", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 12, + "filter": [ + "all", + ["==", "$type", "Point"], + ["==", "class", "country"], + ["!has", "iso_a2"] + ], + "layout": { + "text-field": "{name:latin}", + "text-font": ["Noto Sans Regular"], + "text-max-width": 10, + "text-size": {"stops": [[3, 12], [8, 22]]}, + "visibility": "visible" + }, + "paint": { + "text-color": "hsl(0, 0%, 13%)", + "text-halo-blur": 0, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + } + }, + { + "id": "country_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 12, + "filter": [ + "all", + ["==", "$type", "Point"], + ["==", "class", "country"], + ["has", "iso_a2"] + ], + "layout": { + "text-field": "{name:latin}", + "text-font": ["Noto Sans Bold"], + "text-max-width": 10, + "text-size": {"stops": [[3, 12], [8, 22]]}, + "visibility": "visible" + }, + "paint": { + "text-color": "hsl(0, 0%, 13%)", + "text-halo-blur": 0, + "text-halo-color": "rgba(255,255,255,0.75)", + "text-halo-width": 2 + } + } + ], + "id": "basic" +} diff --git a/tests/fixtures/styles/src2/osm-liberty-lite.json b/tests/fixtures/styles/src2/osm-liberty-lite.json new file mode 100644 index 000000000..455f2682e --- /dev/null +++ b/tests/fixtures/styles/src2/osm-liberty-lite.json @@ -0,0 +1,196 @@ +{ + "version": 8, + "name": "OSM Liberty", + "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", + "url": "https://api.maptiler.com/tiles/v3-openmaptiles/tiles.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL" + }, + "natural_earth_shaded_relief": { + "maxzoom": 6, + "tileSize": 256, + "tiles": [ + "https://klokantech.github.io/naturalearthtiles/tiles/natural_earth_2_shaded_relief.raster/{z}/{x}/{y}.png" + ], + "type": "raster" + } + }, + "sprite": "https://maputnik.github.io/osm-liberty/sprites/osm-liberty", + "glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": {"background-color": "rgb(239,239,239)"} + }, + { + "id": "natural_earth", + "type": "raster", + "source": "natural_earth_shaded_relief", + "maxzoom": 6, + "paint": {"raster-opacity": {"base": 1.5, "stops": [[0, 0.6], [6, 0.1]]}} + }, + { + "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": "water", + "type": "fill", + "source": "openmaptiles", + "source-layer": "water", + "filter": ["all", ["!=", "brunnel", "tunnel"]], + "paint": {"fill-color": "rgb(158,189,255)"} + }, + { + "id": "boundary_2_z0-4", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "filter": ["all", ["==", "admin_level", 2], ["!has", "claimed_by"]], + "layout": { + "line-cap": "round", + "line-join": "round", + "visibility": "visible" + }, + "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": ["Roboto Regular"], + "text-max-width": 5, + "text-size": 12, + "symbol-placement": "line" + }, + "paint": { + "text-color": "#5d60be", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1 + } + }, + { + "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 + } + }, + { + "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", + "visibility": "visible" + }, + "paint": { + "text-color": "#334", + "text-halo-blur": 1, + "text-halo-color": "rgba(255,255,255,0.8)", + "text-halo-width": 1 + } + }, + { + "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 + } + }, + { + "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 + } + }, + { + "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 + } + } + ], + "id": "osm-liberty" +} diff --git a/tests/test.sh b/tests/test.sh index e94328365..aada9acac 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -244,7 +244,7 @@ LOG_FILE="${LOG_DIR}/${TEST_NAME}.txt" TEST_OUT_DIR="${TEST_OUT_BASE_DIR}/${TEST_NAME}" mkdir -p "$TEST_OUT_DIR" -ARG=(--default-srid 900913 --auto-bounds calc --save-config "${TEST_OUT_DIR}/save_config.yaml" tests/fixtures/mbtiles tests/fixtures/pmtiles tests/fixtures/cog "$STATICS_URL/webp2.pmtiles" --sprite tests/fixtures/sprites/src1 --font tests/fixtures/fonts/overpass-mono-regular.ttf --font tests/fixtures/fonts) +ARG=(--default-srid 900913 --auto-bounds calc --save-config "${TEST_OUT_DIR}/save_config.yaml" tests/fixtures/mbtiles tests/fixtures/pmtiles tests/fixtures/cog "$STATICS_URL/webp2.pmtiles" --sprite tests/fixtures/sprites/src1 --font tests/fixtures/fonts/overpass-mono-regular.ttf --font tests/fixtures/fonts --style tests/fixtures/styles/maplibre_demo.json --style tests/fixtures/styles/src2 ) export DATABASE_URL="$MARTIN_DATABASE_URL" set -x @@ -431,6 +431,12 @@ test_jsn sdf_spr_cmp_2 sdf_sprite/src1,mysrc@2x.json test_png spr_cmp_2x sprite/src1,mysrc@2x.png test_png sdf_spr_cmp_2 sdf_sprite/src1,mysrc@2x.png +# Test styles +test_jsn style_src2_maptiler_basic style/maptiler_basic +test_jsn style_src2_maptiler_basic.1 style/maptiler_basic.json +test_jsn style_maplibre_demo style/maplibre_demo +test_jsn style_maplibre_demo.1 style/maplibre_demo.json + # Test fonts test_font font_1 font/Overpass%20Mono%20Light/0-255 test_font font_2 font/Overpass%20Mono%20Regular/0-255 From 13db0a2b31c48ee6876972c19658d7c40878316f Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sun, 16 Mar 2025 03:07:58 +0100 Subject: [PATCH 2/5] basic tile rendering fix clippy issue --- Cargo.lock | 108 ++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + martin/Cargo.toml | 2 + martin/src/srv/server.rs | 2 + martin/src/srv/styles.rs | 33 ++++++++++++ martin/src/styles/mod.rs | 17 ++++++ 6 files changed, 162 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index feddb1c6e..07361bee3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "actix-codec" @@ -867,6 +867,16 @@ dependencies = [ "cc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -1109,6 +1119,65 @@ version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f211af61d8efdd104f96e57adf5e426ba1bc3ed7a4ead616e15e5881fd79c4d" +[[package]] +name = "cxx" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342b09ea23e087717542308a865984555782302855f29427540bbe02d5e8a28a" +dependencies = [ + "cc", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3ff8c449a5074983677c19c894eadc62b6a82ade4d6316547798eb79342ae5" +dependencies = [ + "cc", + "codespan-reporting", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.100", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40399fddbf3977647bfff7453dacffc6b5701b19a282a283369a870115d0a049" +dependencies = [ + "clap", + "codespan-reporting", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9161673896b799047e79a245927e7921787ad016eed6770227f3f23de2746c7" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff513230582d396298cc00e8fb3d9a752822f85137c323fac4227ac5be6c268" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.100", +] + [[package]] name = "darling" version = "0.20.10" @@ -2692,6 +2761,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +dependencies = [ + "cc", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2768,6 +2846,18 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "maplibre_native" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d7bdeb2591e591ece93d285c5e445cbca9d40c04efdb7a689cd6ca7ac6e09e" +dependencies = [ + "cmake", + "cxx", + "cxx-build", + "walkdir", +] + [[package]] name = "martin" version = "0.15.0" @@ -2794,6 +2884,7 @@ dependencies = [ "json-patch", "lambda-web", "log", + "maplibre_native", "martin-tile-utils", "mbtiles", "moka", @@ -4314,6 +4405,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scratch" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" + [[package]] name = "sdf_glyph_renderer" version = "1.0.1" @@ -5067,6 +5164,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "testcontainers" version = "0.23.3" diff --git a/Cargo.toml b/Cargo.toml index 22b2d3c7a..46d267d13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ itertools = "0.14" json-patch = "4" lambda-web = { version = "0.2.1", features = ["actix4"] } log = "0.4" +maplibre_native = "0.1.1" martin-tile-utils = { path = "./martin-tile-utils", version = "0.6.0" } mbtiles = { path = "./mbtiles", version = "0.12.0" } md5 = "0.7.0" diff --git a/martin/Cargo.toml b/martin/Cargo.toml index 7649a2e2c..b00e22843 100644 --- a/martin/Cargo.toml +++ b/martin/Cargo.toml @@ -60,6 +60,7 @@ mbtiles = ["dep:mbtiles"] pmtiles = ["dep:pmtiles"] cog = ["dep:tiff", "dep:png"] styles = ["dep:walkdir", "tokio/fs"] +styles_rendering = ["styles", "dep:maplibre_native"] postgres = ["dep:deadpool-postgres", "dep:json-patch", "dep:postgis", "dep:postgres", "dep:postgres-protocol", "dep:semver", "dep:tokio-postgres-rustls"] sprites = ["dep:spreet", "tokio/fs"] bless-tests = [] @@ -82,6 +83,7 @@ itertools.workspace = true json-patch = { workspace = true, optional = true } lambda-web = { workspace = true, optional = true } log.workspace = true +maplibre_native = { workspace = true, optional = true } martin-tile-utils.workspace = true mbtiles = { workspace = true, optional = true } moka.workspace = true diff --git a/martin/src/srv/server.rs b/martin/src/srv/server.rs index acb977fe2..4bbbf5396 100644 --- a/martin/src/srv/server.rs +++ b/martin/src/srv/server.rs @@ -129,6 +129,8 @@ pub fn router(cfg: &mut web::ServiceConfig, #[allow(unused_variables)] usr_cfg: #[cfg(feature = "styles")] cfg.service(crate::srv::styles::get_style_json); + #[cfg(feature = "styles_rendering")] + cfg.service(crate::srv::styles::get_style_rendered); #[cfg(feature = "webui")] { diff --git a/martin/src/srv/styles.rs b/martin/src/srv/styles.rs index 0db7f9908..c7f26e0a8 100644 --- a/martin/src/srv/styles.rs +++ b/martin/src/srv/styles.rs @@ -43,3 +43,36 @@ async fn get_style_json(path: Path, styles: Data) -> } } } + +#[cfg(feature = "styles_rendering")] +#[derive(Deserialize, Debug)] +struct StyleRenderRequest { + style_id: String, + z: u8, + x: u32, + y: u32, +} + +#[cfg(feature = "styles_rendering")] +#[route("/style/{style_id}/{z}/{x}/{y}.png", method = "GET")] +async fn get_style_rendered( + path: Path, + styles: Data, +) -> HttpResponse { + let style_id = &path.style_id; + let Some(style_path) = styles.style_json_path(style_id) else { + return HttpResponse::NotFound() + .content_type(ContentType::plaintext()) + .body("No such style exists"); + }; + let xyz = martin_tile_utils::TileCoord { + z: path.z, + x: path.x, + y: path.y, + }; + log::trace!("Rendering style {style_id} ({style_path:?}) at {xyz}"); + + HttpResponse::Ok() + .content_type(ContentType.png()) + .body(styles.render(path, xyz)) +} diff --git a/martin/src/styles/mod.rs b/martin/src/styles/mod.rs index 8629ed625..b4463ad8e 100644 --- a/martin/src/styles/mod.rs +++ b/martin/src/styles/mod.rs @@ -85,6 +85,23 @@ impl StyleSources { Some(item.path.clone()) } + // assumptions: + // - martin is not an interacive renderer (think 60fps, embedded) + // - We are not rendering the same tile all the time (instead, it is cached) + // + // For now, we only use a static renderer which is optimized for our kind of usage + // In the future, we may consider adding support for smarter rendering including a pool of renderers. + #[cfg(feature = "styles_rendering")] + pub fn render( + &self, + path: &Path, + zxy: martin_tile_utils::TileCoord, + ) -> StyleResult, Error> { + let mut map = maplibre_native::ImageRendererOptions::new().build_static_renderer(); + map.set_style_path(path); + Ok(map.render_static(zxy.z, zxy.x, zxy.y)) + } + /// an external representation of the internal catalog #[must_use] pub fn get_catalog(&self) -> StyleCatalog { From 271a288c00576c9ac030c680ad9e23016ff46d99 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 16 Mar 2025 02:20:41 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- martin/src/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/martin/src/config.rs b/martin/src/config.rs index 51e5e2ebb..589276f92 100644 --- a/martin/src/config.rs +++ b/martin/src/config.rs @@ -10,6 +10,7 @@ use log::info; use serde::{Deserialize, Serialize}; use subst::VariableMap; +use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources}; use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources}; #[cfg(any(feature = "fonts", feature = "postgres"))] use crate::OptOneMany; @@ -25,11 +26,10 @@ use crate::fonts::FontSources; use crate::source::{TileInfoSources, TileSources}; #[cfg(feature = "sprites")] use crate::sprites::SpriteSources; -use crate::srv::{SrvConfig, RESERVED_KEYWORDS}; +use crate::srv::{RESERVED_KEYWORDS, SrvConfig}; #[cfg(feature = "styles")] use crate::styles::StyleSources; -use crate::utils::{init_aws_lc_tls, parse_base_path, CacheValue, MainCache, OptMainCache}; -use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources}; +use crate::utils::{CacheValue, MainCache, OptMainCache, init_aws_lc_tls, parse_base_path}; use crate::{IdResolver, MartinResult, OptOneMany}; pub type UnrecognizedValues = HashMap; From 22575b974418b7ebf3b9fcc57e1c28aae80efbb4 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Mon, 7 Apr 2025 18:21:02 +0200 Subject: [PATCH 4/5] merge fixes --- martin/src/config.rs | 5 +- martin/src/lib.rs | 2 - martin/src/styles/mod.rs | 98 +-------------------------------------- martin/src/utils/error.rs | 4 -- 4 files changed, 2 insertions(+), 107 deletions(-) diff --git a/martin/src/config.rs b/martin/src/config.rs index fa2e119a3..227ec5b9e 100644 --- a/martin/src/config.rs +++ b/martin/src/config.rs @@ -10,7 +10,6 @@ use log::info; use serde::{Deserialize, Serialize}; use subst::VariableMap; -use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources}; use crate::MartinError::{ConfigLoadError, ConfigParseError, ConfigWriteError, NoSources}; #[cfg(any(feature = "fonts", feature = "postgres"))] use crate::OptOneMany; @@ -23,10 +22,8 @@ use crate::OptOneMany; use crate::file_config::FileConfigEnum; use crate::source::{TileInfoSources, TileSources}; use crate::srv::{RESERVED_KEYWORDS, SrvConfig}; -#[cfg(feature = "styles")] -use crate::styles::StyleSources; use crate::utils::{CacheValue, MainCache, OptMainCache, init_aws_lc_tls, parse_base_path}; -use crate::{IdResolver, MartinResult, OptOneMany}; +use crate::{IdResolver, MartinResult}; pub type UnrecognizedValues = HashMap; diff --git a/martin/src/lib.rs b/martin/src/lib.rs index 86b421ba3..3c7c2c1f7 100644 --- a/martin/src/lib.rs +++ b/martin/src/lib.rs @@ -33,8 +33,6 @@ pub mod srv; #[cfg(feature = "styles")] pub mod styles; -#[cfg(feature = "styles")] -mod styles; #[cfg(test)] #[path = "utils/tests.rs"] mod tests; diff --git a/martin/src/styles/mod.rs b/martin/src/styles/mod.rs index 723f19199..a1f002121 100644 --- a/martin/src/styles/mod.rs +++ b/martin/src/styles/mod.rs @@ -49,10 +49,6 @@ impl StyleSources { if let Some(sources) = cfg.sources { for (id, source) in sources { -<<<<<<< HEAD - configs.insert(id.clone(), source.clone()); - results.add_sources(&id, &source.abs_path()?); -======= if source.get_path().is_file() { configs.insert(id.clone(), source.clone()); results.add_style(id, source.into_path()); @@ -61,21 +57,10 @@ impl StyleSources { "style {id} (pointing to {source:?}) is not a file. To prevent footguns, we ignore directories for 'sources'. To use directories, specify them as 'paths' or specify each file in 'sources' instead." ); } ->>>>>>> main } }; let mut paths_with_names = Vec::new(); -<<<<<<< HEAD - for path in cfg.paths { - let Some(name) = path.file_name() else { - warn!("Ignoring style source with no name from {path:?}"); - continue; - }; - paths_with_names.push(path.clone()); - results.add_sources(name.to_string_lossy().as_ref(), &path); - } -======= for base_path in cfg.paths { let files = list_contained_files(&base_path, "json")?; if files.is_empty() { @@ -98,7 +83,6 @@ impl StyleSources { } paths_with_names.sort_unstable(); paths_with_names.dedup(); ->>>>>>> main *config = FileConfigEnum::new_extended(paths_with_names, configs, cfg.custom); @@ -106,17 +90,13 @@ impl StyleSources { } /// retrieve a styles' `PathBuf` from the internal catalog -<<<<<<< HEAD -======= #[must_use] ->>>>>>> main pub fn style_json_path(&self, style_id: &str) -> Option { let style_id = style_id.trim_end_matches(".json").trim(); let item = self.0.get(style_id)?; Some(item.path.clone()) } -<<<<<<< HEAD // assumptions: // - martin is not an interacive renderer (think 60fps, embedded) // - We are not rendering the same tile all the time (instead, it is cached) @@ -134,8 +114,6 @@ impl StyleSources { Ok(map.render_static(zxy.z, zxy.x, zxy.y)) } -======= ->>>>>>> main /// an external representation of the internal catalog #[must_use] pub fn get_catalog(&self) -> StyleCatalog { @@ -151,44 +129,10 @@ impl StyleSources { entries } -<<<<<<< HEAD - /// Adds all the contained files in the given file/directory as style sources. - fn add_sources(&mut self, id: &str, base_path: &PathBuf) { - match list_contained_files(base_path) { - Ok(contained_paths) => { - for child_path in contained_paths { - let Some(name) = child_path.file_name() else { - assert!( - !base_path.is_file(), - "base_path cannot be a file without name as otherwise the id would not exist" - ); - warn!( - "Ignoring {child_path:?} of style source {id} from {base_path:?} because it has no name" - ); - continue; - }; - let name = name - .to_string_lossy() - .trim_end_matches(".json") - .trim() - .to_string(); - self.add_single_source(name, child_path); - } - } - Err(e) => warn!("Ignoring style source {id} from {base_path:?} because of {e}"), - } - } - - /// add a single file with an id to the internal catalog - fn add_single_source(&mut self, id: String, path: PathBuf) { - assert!(path.is_file()); - assert!(!id.is_empty()); -======= /// add a single style file with an id to the internal catalog fn add_style(&mut self, id: String, path: PathBuf) { debug_assert!(path.is_file()); debug_assert!(!id.is_empty()); ->>>>>>> main match self.0.entry(id) { Entry::Occupied(v) => { warn!( @@ -218,11 +162,7 @@ impl StyleSources { /// # Errors /// /// This function will return an error if Rust's underlying [`read_dir`](std::fs::read_dir) returns an error. -<<<<<<< HEAD -fn list_contained_files(source_path: &Path) -> StyleResult> { -======= fn list_contained_files(source_path: &Path, filter_extension: &str) -> FileResult> { ->>>>>>> main let working_directory = std::env::current_dir().ok(); let mut contained_files = Vec::new(); let it = walkdir::WalkDir::new(source_path) @@ -230,11 +170,6 @@ fn list_contained_files(source_path: &Path, filter_extension: &str) -> FileResul .into_iter() .filter_entry(|e| e.depth() == 0 || !is_hidden(e)); for entry in it { -<<<<<<< HEAD - let entry = - entry.map_err(|e| StyleError::DirectoryWalking(e, source_path.to_path_buf()))?; - if entry.path().is_file() { -======= let entry = entry.map_err(|e| FileError::DirectoryWalking(e, source_path.to_path_buf()))?; if entry.path().is_file() && entry @@ -242,7 +177,6 @@ fn list_contained_files(source_path: &Path, filter_extension: &str) -> FileResul .extension() .is_some_and(|ext| ext == filter_extension) { ->>>>>>> main // path should be relative to the working directory in the catalog let relative_path = match working_directory { Some(ref work_dir) => entry @@ -268,45 +202,28 @@ fn is_hidden(entry: &walkdir::DirEntry) -> bool { #[cfg(test)] mod tests { -<<<<<<< HEAD - use super::*; - use std::path::PathBuf; -======= use crate::file_config::FileConfigSrc; use super::*; ->>>>>>> main + #[test] fn test_add_single_source() { use std::fs::File; let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("maplibre_demo.json"); -<<<<<<< HEAD - File::create(path.clone()).unwrap(); - - let mut style_sources = StyleSources::default(); - style_sources.add_single_source("maplibre_demo".to_string(), path.clone()); - -======= File::create(&path).unwrap(); let mut style_sources = StyleSources::default(); assert_eq!(style_sources.0.len(), 0); style_sources.add_style("maplibre_demo".to_string(), path.clone()); ->>>>>>> main assert_eq!(style_sources.0.len(), 1); let maplibre_demo = style_sources.0.get("maplibre_demo").unwrap(); assert_eq!(maplibre_demo.path, path); } -<<<<<<< HEAD - #[actix_rt::test] - async fn test_styles_resolve() { -======= #[test] fn test_styles_resolve_paths() { ->>>>>>> main let style_dir = PathBuf::from("../tests/fixtures/styles/"); let mut cfg = FileConfigEnum::new(vec![ style_dir.join("maplibre_demo.json"), @@ -327,10 +244,6 @@ mod tests { }); } -<<<<<<< HEAD - #[actix_rt::test] - async fn test_style_external() { -======= #[test] fn test_styles_resolve_sources() { let style_dir = PathBuf::from("../tests/fixtures/styles/"); @@ -361,7 +274,6 @@ mod tests { #[test] fn test_style_external() { ->>>>>>> main let style_dir = PathBuf::from("../tests/fixtures/styles/"); let mut cfg = FileConfigEnum::new(vec![ style_dir.join("maplibre_demo.json"), @@ -430,22 +342,14 @@ mod tests { let transitively_hidden_file3 = hidden_subdir2.join("file3.txt"); File::create(&transitively_hidden_file3).unwrap(); -<<<<<<< HEAD - let mut result = list_contained_files(dir.path()).unwrap(); -======= let mut result = list_contained_files(dir.path(), "txt").unwrap(); ->>>>>>> main result.sort(); assert_eq!(result, vec![file1, subdir_file2]); } #[test] fn test_list_contained_files_error() { -<<<<<<< HEAD - let result = list_contained_files(&PathBuf::from("/non_existent")); -======= let result = list_contained_files(&PathBuf::from("/non_existent"), "txt"); ->>>>>>> main assert!(result.is_err()); } } diff --git a/martin/src/utils/error.rs b/martin/src/utils/error.rs index 56ffdba21..68dc3850e 100644 --- a/martin/src/utils/error.rs +++ b/martin/src/utils/error.rs @@ -77,10 +77,6 @@ pub enum MartinError { #[error(transparent)] SpriteError(#[from] crate::sprites::SpriteError), - #[cfg(feature = "styles")] - #[error(transparent)] - StyleError(#[from] crate::styles::StyleError), - #[cfg(feature = "fonts")] #[error(transparent)] FontError(#[from] crate::fonts::FontError), From efa970c714339984d3f7918b6f0c03e401d70724 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 16:23:14 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/src/sources-styles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/sources-styles.md b/docs/src/sources-styles.md index 86d560b4e..7402e82a3 100644 --- a/docs/src/sources-styles.md +++ b/docs/src/sources-styles.md @@ -22,4 +22,4 @@ A restart of Martin is required to see new styles. ### Server-side raster tile rendering -TODO, document \ No newline at end of file +TODO, document