├── .eslintrc.json ├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── LICENSE ├── README.md ├── build ├── glsl-plugin.js └── rollup.config.js ├── dist └── tile-setter.js ├── examples ├── circles │ ├── globe.svg │ ├── index.html │ ├── light-wells.json │ ├── main.js │ ├── main.min.js │ ├── ne_50m_geography_regions_elevation_points.json │ └── styles.css ├── geojson │ ├── geojsonGeometriesLines.geojson │ ├── geojsonGeometriesPoints.geojson │ ├── globe.svg │ ├── index.html │ ├── klokantech-basic-style-geojson-sampler.json │ ├── klokantech-basic-style-geojson-usStates.json │ ├── main.js │ ├── main.min.js │ ├── styles.css │ └── us-states.geojson ├── klokan-basic │ ├── globe.svg │ ├── index.html │ ├── klokan-fill-line.json │ ├── klokantech-basic-style.json │ ├── main.js │ ├── main.min.js │ └── styles.css ├── macrostrat │ ├── globe.svg │ ├── index.html │ ├── light-macrostrat.json │ ├── macrostrat-only.json │ ├── main.js │ ├── main.min.js │ └── styles.css ├── mapbox-streets │ ├── globe.svg │ ├── index.html │ ├── main.js │ ├── main.min.js │ ├── streets-v8-noInteractive.json │ └── styles.css ├── rollup.config.js └── set-center-zoom │ ├── globe.svg │ ├── index.html │ ├── klokantech-basic-style.json │ ├── main.js │ ├── main.min.js │ └── styles.css ├── package-lock.json ├── package.json └── src ├── bounds.js ├── caches.js ├── coords.js ├── feature-coords.js ├── grid.js ├── index.js ├── metric.js ├── params.js ├── projection.js ├── raster.js ├── renderer.js ├── selection.js ├── sources.js └── tile-coords.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "globeletjs" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [12.x, 14.x, 16.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v2 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: 'npm' 29 | - name: Reconfigure git to use HTTP authentication 30 | # https://github.com/actions/setup-node/issues/214#issuecomment-842538631 31 | run: > 32 | git config --global url."https://github.com/".insteadOf 33 | ssh://git@github.com/ 34 | - run: npm ci 35 | - run: npm run build --if-present 36 | - run: npm test 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.jar 19 | *.rar 20 | *.tar 21 | *.zip 22 | 23 | # Logs and databases # 24 | ###################### 25 | *.log 26 | *.sql 27 | *.sqlite 28 | 29 | # OS generated files # 30 | ###################### 31 | .DS_Store 32 | .DS_Store? 33 | ._* 34 | .Spotlight-V100 35 | .Trashes 36 | ehthumbs.db 37 | Thumbs.db 38 | 39 | # Other # 40 | ###################### 41 | node_modules/ 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2022 Jeshurun Hembd, Ananya Roy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tile-setter 2 | 3 | ![tests](https://github.com/GlobeletJS/tile-setter/actions/workflows/node.js.yml/badge.svg) 4 | 5 | Tiled vector map powered by a lightweight WebGL renderer 6 | 7 | Rendering is guided by a [MapLibre style document][MapLibre]. See a simple 8 | [example][] using a style from [OpenMapTiles][]. 9 | 10 | [MapLibre]: https://maplibre.org/maplibre-gl-js-docs/style-spec/ 11 | [example]: https://globeletjs.github.io/tile-setter/examples/klokan-basic/index.html 12 | [OpenMapTiles]: https://openmaptiles.org/styles/ 13 | 14 | ## Installation 15 | tile-setter is provided as an ESM import 16 | ```javascript 17 | import * as tileSetter from 'tile-setter'; 18 | ``` 19 | 20 | ## Syntax 21 | ```javascript 22 | const map = tileSetter.init(params); 23 | ``` 24 | 25 | ## Parameters 26 | The supplied parameters object has the following properties: 27 | - `.context` (REQUIRED): A WebGL context wrapper, as created by the 28 | [yawgl][] method `initContext` 29 | - `.framebuffer`: A framebuffer object, as created by `context.initFramebuffer`, 30 | to which the map will be rendered. If not supplied, the map will be rendered 31 | to `context.gl.canvas` 32 | - `.center`: The initial center of the map, given as [longitude, latitude] 33 | in degrees. Default: [0.0, 0.0] 34 | - `.zoom`: The initial zoom of the map. Default: 4 35 | - `.style` (REQUIRED): A link to a MapLibre style document 36 | - `.mapboxToken`: Your API token for Mapbox services (if needed) 37 | - `.clampY`: If true (default), the scale and Y-coordinate of the map will be 38 | adjusted to ensure the viewport is not crossing the North or South limits of 39 | the world map 40 | - `.units`: The units that will be used for subsequent calls to 41 | `map.setCenterZoom` and `map.select`. Possible values: 42 | - "xy": Assumes an input [x, y] in global Web Mercator coordinates, 43 | with [0, 0] at the top left corner of the map 44 | - "radians": Assumes an input [longitude, latitude] in radians 45 | - "degrees" (DEFAULT): Assumes input [longitude, latitude] in degrees 46 | - `.projScale`: A Boolean flag indicating whether to scale style dimensions 47 | by the ratio of the projection scale at each feature, vs. the projection scale 48 | at the camera position 49 | 50 | [yawgl]: https://github.com/GlobeletJS/yawgl 51 | 52 | ## API 53 | The returned map object exposes the following properties and methods: 54 | - `gl`: A link back to the WebGL rendering context (supplied on init) 55 | - `projection`: The projection from the `units` specified on initialization 56 | to global Web Mercator coordinates. Includes 3 methods: 57 | - `projection.forward(point)`: Converts an Array of 2 coordinates from 58 | input units to global Web Mercator [X, Y] 59 | - `projection.inverse(point)`: Converts an Array of 2 coordinates from 60 | global Web Mercator [X, Y] to input units 61 | - `projection.scale(point)`: Return value scales a (differential) distance 62 | in the input coordinates to a distance in global Web Mercator coordinates 63 | - `setTransform(transform)`: Sets the map transform, where `transform` has 64 | properties `{ k, y, x }`, defined as in the [d3-zoom transform][]. Actual 65 | transform for rendering will be rounded to ensure tile pixels align with 66 | screen pixels. Return value: a flag indicating whether the transform has 67 | changed 68 | - `setCenterZoom(center, zoom)`: Sets the map transform to position 69 | the map at the supplied center and zoom. Parameters: 70 | - `center`: An array of `[x, y]` or `[longitude, latitude]` coordinates, 71 | in the units specified on initialization 72 | - `zoom`: The desired zoom level 73 | - `getViewport()`: Returns the current viewport dimensions in CSS 74 | pixels, as a 2-element array 75 | - `getTransform()`: Returns a copy of the current transform 76 | - `getZoom()`: Returns the transform scale converted to a zoom level. 77 | Zoom calculation assumes 512px tiles 78 | - `getCamPos()`: Returns the position of the camera within the current map, 79 | expressed as an array of 2 floats between 0 and 1, with `[0, 0]` 80 | corresponding to the top left corner of the map 81 | - `getScale()`: Returns the scale of the whole map relative to the current 82 | viewport dimensions, as an array of two floats 83 | - `localToGlobal([x, y])`: converts pixel coordinates [x, y] within 84 | the current map to global XY 85 | - `promise`: A Promise that resolves to an updated API, after the MapLibre 86 | style document (supplied on init) is fully loaded and parsed 87 | - `draw()`: Returns `null` until `map.promise` resolves 88 | - `select()`: Returns `null` until `map.promise` resolves 89 | 90 | All the above properties and methods are available immediately upon 91 | initialization (*synchronously*). After `map.promise` resolves, the following 92 | methods are updated or added: 93 | - `draw(params)`: Draws the map for the supplied transform. Returns a 94 | fractional number (from 0.0 to 1.0) indicating the loading status, expressed 95 | as a fraction of the tiles that are needed to render the current view. 96 | The `params` object has the following properties: 97 | - `.pixRatio`: the number of renderbuffer pixels per CSS pixel, e.g., as 98 | as returned by [window.devicePixelRatio][]. Default: 1.0 99 | - `.dzScale`: An additional scalar to be multiplied with the camera 100 | projection scale, if `projScale === true` on initialization. This can 101 | be used to account for the internal zoom being different from the 102 | requested—for example, if after `.setCenterZoom(center, zoom)`, 103 | we find that `api.getZoom() !== zoom`, due to transform rounding or 104 | `clampY === true` 105 | - `select(params)`: Finds map features near a given location. The `params` 106 | object has the following properties: 107 | - `layer` (String): The name of the layer in the MapLibre style document 108 | containing the features to be queried 109 | - `point` (Array): The location to be queried, specified as a 2-element 110 | Array of coordinates, in the units specified on initialization 111 | - `radius` (Number): The maximum pixel distance between `point` and the 112 | selected feature. Default: 5 113 | - `hideLayer(layer)`: Turns off rendering for the given layer 114 | - `showLayer(layer)`: Turns on rendering for the given layer 115 | 116 | [d3-zoom transform]: https://github.com/d3/d3-zoom/blob/master/README.md#zoom-transforms 117 | [window.devicePixelRatio]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio 118 | -------------------------------------------------------------------------------- /build/glsl-plugin.js: -------------------------------------------------------------------------------- 1 | // Plugin for .glsl and .js.glsl files 2 | export function glsl() { 3 | return { transform }; 4 | } 5 | 6 | function transform(source, id) { 7 | // Confirm filename extension is .glsl 8 | if (/\.glsl$/.test(id) === false) return; 9 | 10 | const transFunc = (/\.js\.glsl$/.test(id)) 11 | ? tagTemplateLiteral 12 | : templateLiteral; 13 | 14 | return { 15 | code: transFunc(source), 16 | map: { mappings: '' }, // No map 17 | }; 18 | } 19 | 20 | function templateLiteral(source) { 21 | // Export as a constant string, but template literal preserves line breaks 22 | return "export default `" + source + "`"; 23 | } 24 | 25 | const glslInterp = `function glslInterp(strings, ...expressions) { 26 | return strings.reduce( (acc, val, i) => acc + expressions[i-1]() + val ); 27 | } 28 | `; 29 | 30 | function tagTemplateLiteral(source) { 31 | // Export as a function that will interpolate values from an args object 32 | // NOTE: args MUST be defined where the function is called, with 33 | // property names matching the variables in the *.js.glsl file 34 | return glslInterp + "export default (args) => glslInterp`" + source + "`"; 35 | } 36 | -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve'; 2 | import commonjs from '@rollup/plugin-commonjs'; // Yuck. Needed for @turf!! 3 | import { glsl } from "./glsl-plugin.js"; 4 | import pkg from "../package.json"; 5 | 6 | export default { 7 | input: 'src/index.js', 8 | plugins: [ 9 | glsl(), 10 | resolve(), 11 | commonjs(), 12 | ], 13 | output: { 14 | file: pkg.main, 15 | //sourcemap: 'inline', 16 | format: 'esm', 17 | name: pkg.name 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /examples/circles/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 🌎 3 | 4 | -------------------------------------------------------------------------------- /examples/circles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tile-setter - beta 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 |
19 |
20 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/circles/main.js: -------------------------------------------------------------------------------- 1 | import * as yawgl from "yawgl"; 2 | import * as d3 from "d3"; 3 | import * as tileMap from "../../"; 4 | 5 | export function main() { 6 | const canvas = document.getElementById("mapCanvas"); 7 | yawgl.resizeCanvasToDisplaySize(canvas, window.devicePixelRatio); 8 | const context = yawgl.initContext(canvas); 9 | 10 | tileMap.init({ 11 | context, 12 | center: [-100, 31], 13 | zoom: 6, 14 | style: "./light-wells.json", 15 | // eslint-disable-next-line max-len 16 | mapboxToken: "pk.eyJ1IjoiamhlbWJkIiwiYSI6ImNqcHpueHpyZjBlMjAzeG9kNG9oNzI2NTYifQ.K7fqhk2Z2YZ8NIV94M-5nA", 17 | units: "xy", 18 | projScale: true, 19 | }).promise.then(api => setup(api, canvas)) 20 | .catch(console.log); 21 | } 22 | 23 | function setup(api, canvas) { 24 | const viewport = api.getViewport(); 25 | 26 | const { k, x, y } = api.getTransform(); 27 | let transform = d3.zoomIdentity 28 | .translate(x, y) 29 | .scale(k); 30 | 31 | const zoomer = d3.zoom() 32 | .scaleExtent([1 << 10, 1 << 26]) 33 | .extent([[0, 0], viewport]) 34 | .translateExtent([[-Infinity, -0.5], [Infinity, 0.5]]) 35 | .on("zoom", (event) => { 36 | transform = event.transform; 37 | }); 38 | 39 | d3.select(canvas) 40 | .call(zoomer) 41 | .call(zoomer.transform, transform); 42 | 43 | let mouse = []; 44 | d3.select(canvas).on("mousemove", (event) => { 45 | mouse = d3.pointer(event); 46 | }); 47 | 48 | document.getElementById("showWells") 49 | .addEventListener("click", () => api.showLayer("twdb-groundwater-v2")); 50 | document.getElementById("hideWells") 51 | .addEventListener("click", () => api.hideLayer("twdb-groundwater-v2")); 52 | 53 | const loadStatus = document.getElementById("loadStatus"); 54 | const infoBox = document.getElementById("info"); 55 | 56 | requestAnimationFrame(animate); 57 | function animate() { 58 | const pixRatio = window.devicePixelRatio; 59 | yawgl.resizeCanvasToDisplaySize(canvas, pixRatio); 60 | api.setTransform(transform); 61 | const percent = api.draw({ pixRatio }) * 100; 62 | loadStatus.innerHTML = (percent < 100) 63 | ? "Loading: " + percent.toFixed(0) + "%" 64 | : "Complete! " + percent.toFixed(0) + "%"; 65 | loadStatus.innerHTML += "
Mouse: " + mouse; 66 | const point = api.localToGlobal(mouse); 67 | loadStatus.innerHTML += "
Global: " + point.map(n => n.toFixed(4)); 68 | 69 | const feature = api.select({ 70 | layer: "twdb-groundwater-v2", 71 | point, // : api.localToGlobal(mouse), 72 | radius: 3, 73 | }) || api.select({ 74 | layer: "mountains", 75 | point, 76 | radius: 6, 77 | }); 78 | infoBox.innerHTML = "
" + JSON.stringify(feature, null, 2) + "
"; 79 | 80 | requestAnimationFrame(animate); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/circles/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | border: 0; 6 | margin: 0; 7 | font-family: "Noto Sans"; 8 | font-size: 14px; 9 | } 10 | .container { 11 | display: flex; 12 | flex-direction: row; 13 | height: 100vh; 14 | } 15 | #main { 16 | flex: auto; 17 | height: 100%; 18 | position: relative; 19 | } 20 | #right { 21 | flex: none; 22 | width: 600px; 23 | height: 100%; 24 | position: relative; 25 | } 26 | pre { 27 | white-space: pre-wrap; 28 | word-wrap: break-word; 29 | } 30 | #mapCanvas { 31 | width: 100%; 32 | height: 100%; 33 | display: block; 34 | background-color: gray; 35 | position: relative; 36 | } 37 | .attribution { 38 | background: rgba(255, 255, 255, 0.8); 39 | position: absolute; 40 | bottom: 0; 41 | right: 0; 42 | padding: 0 4px 0 4px; 43 | } 44 | #loadStatus { 45 | position: absolute; 46 | top: 0; 47 | right: 0; 48 | width: 20ch; 49 | text-align: right; 50 | background: rgba(60, 60, 60, 0.5); 51 | color: white; 52 | padding: 0 4px 0 4px; 53 | } 54 | -------------------------------------------------------------------------------- /examples/geojson/geojsonGeometriesLines.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type":"FeatureCollection", 3 | "features":[ 4 | {"type":"Feature", 5 | "geometry":{ 6 | "type":"LineString", 7 | "coordinates":[[40,-20],[80,20]] 8 | }, 9 | "properties":{ 10 | "name":"LineString" 11 | } 12 | }, 13 | {"type":"Feature", 14 | "geometry":{ 15 | "type":"LineString", 16 | "coordinates":[[40,20],[80,-20]] 17 | }, 18 | "properties":{ 19 | "name": "LineString" 20 | } 21 | }, 22 | {"type":"Feature", 23 | "geometry":{ 24 | "type":"Polygon", 25 | "coordinates":[[[-50,-10],[-40,10],[-30,-10],[-50,-10]]] 26 | }, 27 | "properties":{ 28 | "name": "Polygon" 29 | } 30 | }, 31 | {"type":"Feature", 32 | "geometry": 33 | {"type":"MultiLineString", 34 | "coordinates":[[[-10,-7.5],[-10,7.5]],[[10,-7.5],[10,7.5]],[[-7.5,-10],[7.5,-10]],[[-7.5,10],[7.5,10]]] 35 | }, 36 | "properties":{ 37 | "name":"MultiLineString" 38 | } 39 | }, 40 | {"type":"Feature", 41 | "geometry":{ 42 | "type":"MultiPolygon", 43 | "coordinates":[[[[-50,60],[-50,80],[-30,80],[-30,60],[-50,60]]],[[[-20,60],[-20,80],[0,80],[0,60],[-20,60]]],[[[10,60],[10,80],[30,80],[30,60],[10,60]]]] 44 | }, 45 | "properties":{ 46 | "name":"MultiPolygon" 47 | } 48 | } 49 | ]} 50 | -------------------------------------------------------------------------------- /examples/geojson/geojsonGeometriesPoints.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type":"FeatureCollection", 3 | "features":[ 4 | {"type":"Feature", 5 | "geometry":{ 6 | "type":"Point", 7 | "coordinates":[0,0] 8 | }, 9 | "properties":{ 10 | "name": "Point" 11 | } 12 | }, 13 | {"type":"Feature", 14 | "geometry":{ 15 | "type":"MultiPoint", 16 | "coordinates":[[5,0],[5,1]] 17 | }, 18 | "properties":{ 19 | "name":"MultiPoint" 20 | } 21 | } 22 | ]} 23 | -------------------------------------------------------------------------------- /examples/geojson/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 🌎 3 | 4 | -------------------------------------------------------------------------------- /examples/geojson/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tile-setter - beta 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/geojson/klokantech-basic-style-geojson-sampler.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "name": "Basic", 4 | "metadata": { 5 | "mapbox:autocomposite": false, 6 | "mapbox:type": "template", 7 | "maputnik:renderer": "mbgljs", 8 | "openmaptiles:version": "3.x", 9 | "openmaptiles:mapbox:owner": "openmaptiles", 10 | "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t" 11 | }, 12 | "sources": { 13 | "openmaptiles": { 14 | "type": "vector", 15 | "url": "https://api.maptiler.com/tiles/v3/tiles.json?key=mrAq6zQEFxOkanukNbGm" 16 | }, 17 | "geojsonSamplerPoints": { 18 | "type": "geojson", 19 | "data": "./geojsonGeometriesPoints.geojson", 20 | "minzoom" :0, 21 | "maxzoom" :14, 22 | "tileSize": 512 23 | }, 24 | "geojsonSamplerLines": { 25 | "type": "geojson", 26 | "data": "./geojsonGeometriesLines.geojson", 27 | "minzoom" :0, 28 | "maxzoom" :14, 29 | "tileSize": 512 30 | } 31 | }, 32 | "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=mrAq6zQEFxOkanukNbGm", 33 | "layers": [{ 34 | "id": "background", 35 | "paint": { 36 | "background-color": "hsl(47, 26%, 88%)" 37 | }, 38 | "type": "background" 39 | }, { 40 | "filter": ["all", ["==", "$type", "Polygon"], 41 | ["in", "class", "residential", "suburb", "neighbourhood"] 42 | ], 43 | "id": "landuse-residential", 44 | "layout": { 45 | "visibility": "visible" 46 | }, 47 | "paint": { 48 | "fill-color": "hsl(47, 13%, 86%)", 49 | "fill-opacity": 0.7 50 | }, 51 | "source": "openmaptiles", 52 | "source-layer": "landuse", 53 | "type": "fill" 54 | }, { 55 | "filter": ["==", "class", "grass"], 56 | "id": "landcover_grass", 57 | "paint": { 58 | "fill-color": "hsl(82, 46%, 72%)", 59 | "fill-opacity": 0.45 60 | }, 61 | "source": "openmaptiles", 62 | "source-layer": "landcover", 63 | "type": "fill" 64 | }, { 65 | "filter": ["==", "class", "wood"], 66 | "id": "landcover_wood", 67 | "paint": { 68 | "fill-color": "hsl(82, 46%, 72%)", 69 | "fill-opacity": { 70 | "base": 1, 71 | "stops": [ 72 | [8, 0.6], 73 | [22, 1] 74 | ] 75 | } 76 | }, 77 | "source": "openmaptiles", 78 | "source-layer": "landcover", 79 | "type": "fill" 80 | }, { 81 | "filter": ["all", ["==", "$type", "Polygon"], 82 | ["!=", "intermittent", 1] 83 | ], 84 | "id": "water", 85 | "paint": { 86 | "fill-color": "hsl(205, 56%, 73%)" 87 | }, 88 | "source": "openmaptiles", 89 | "source-layer": "water", 90 | "type": "fill", 91 | "layout": { 92 | "visibility": "visible" 93 | } 94 | }, { 95 | "filter": ["all", ["==", "$type", "Polygon"], 96 | ["==", "intermittent", 1] 97 | ], 98 | "id": "water_intermittent", 99 | "paint": { 100 | "fill-color": "hsl(205, 56%, 73%)", 101 | "fill-opacity": 0.7 102 | }, 103 | "source": "openmaptiles", 104 | "source-layer": "water", 105 | "type": "fill", 106 | "layout": { 107 | "visibility": "visible" 108 | } 109 | }, { 110 | "filter": ["==", "subclass", "ice_shelf"], 111 | "id": "landcover-ice-shelf", 112 | "layout": { 113 | "visibility": "visible" 114 | }, 115 | "paint": { 116 | "fill-color": "hsl(47, 26%, 88%)", 117 | "fill-opacity": 0.8 118 | }, 119 | "source": "openmaptiles", 120 | "source-layer": "landcover", 121 | "type": "fill" 122 | }, { 123 | "filter": ["==", "subclass", "glacier"], 124 | "id": "landcover-glacier", 125 | "layout": { 126 | "visibility": "visible" 127 | }, 128 | "paint": { 129 | "fill-color": "hsl(47, 22%, 94%)", 130 | "fill-opacity": { 131 | "base": 1, 132 | "stops": [ 133 | [0, 1], 134 | [8, 0.5] 135 | ] 136 | } 137 | }, 138 | "source": "openmaptiles", 139 | "source-layer": "landcover", 140 | "type": "fill" 141 | }, { 142 | "filter": ["all", ["in", "class", "sand"]], 143 | "id": "landcover_sand", 144 | "metadata": {}, 145 | "paint": { 146 | "fill-antialias": false, 147 | "fill-color": "rgba(232, 214, 38, 1)", 148 | "fill-opacity": 0.3 149 | }, 150 | "source": "openmaptiles", 151 | "source-layer": "landcover", 152 | "type": "fill" 153 | }, { 154 | "filter": ["==", "class", "agriculture"], 155 | "id": "landuse", 156 | "layout": { 157 | "visibility": "visible" 158 | }, 159 | "paint": { 160 | "fill-color": "#eae0d0" 161 | }, 162 | "source": "openmaptiles", 163 | "source-layer": "landuse", 164 | "type": "fill" 165 | }, { 166 | "filter": ["==", "class", "national_park"], 167 | "id": "landuse_overlay_national_park", 168 | "paint": { 169 | "fill-color": "#E1EBB0", 170 | "fill-opacity": { 171 | "base": 1, 172 | "stops": [ 173 | [5, 0], 174 | [9, 0.75] 175 | ] 176 | } 177 | }, 178 | "source": "openmaptiles", 179 | "source-layer": "landcover", 180 | "type": "fill" 181 | }, { 182 | "filter": ["all", ["==", "$type", "LineString"], 183 | ["==", "brunnel", "tunnel"] 184 | ], 185 | "id": "waterway-tunnel", 186 | "paint": { 187 | "line-color": "hsl(205, 56%, 73%)", 188 | "line-dasharray": [3, 3], 189 | "line-gap-width": { 190 | "stops": [ 191 | [12, 0], 192 | [20, 6] 193 | ] 194 | }, 195 | "line-opacity": 1, 196 | "line-width": { 197 | "base": 1.4, 198 | "stops": [ 199 | [8, 1], 200 | [20, 2] 201 | ] 202 | } 203 | }, 204 | "source": "openmaptiles", 205 | "source-layer": "waterway", 206 | "type": "line", 207 | "layout": { 208 | "visibility": "visible" 209 | } 210 | }, { 211 | "filter": ["all", ["==", "$type", "LineString"], 212 | ["!in", "brunnel", "tunnel", "bridge"], 213 | ["!=", "intermittent", 1] 214 | ], 215 | "id": "waterway", 216 | "paint": { 217 | "line-color": "hsl(205, 56%, 73%)", 218 | "line-opacity": 1, 219 | "line-width": { 220 | "base": 1.4, 221 | "stops": [ 222 | [8, 1], 223 | [20, 8] 224 | ] 225 | } 226 | }, 227 | "source": "openmaptiles", 228 | "source-layer": "waterway", 229 | "type": "line", 230 | "layout": { 231 | "visibility": "visible" 232 | } 233 | }, { 234 | "filter": ["all", ["==", "$type", "LineString"], 235 | ["!in", "brunnel", "tunnel", "bridge"], 236 | ["==", "intermittent", 1] 237 | ], 238 | "id": "waterway_intermittent", 239 | "paint": { 240 | "line-color": "hsl(205, 56%, 73%)", 241 | "line-opacity": 1, 242 | "line-width": { 243 | "base": 1.4, 244 | "stops": [ 245 | [8, 1], 246 | [20, 8] 247 | ] 248 | }, 249 | "line-dasharray": [2, 1] 250 | }, 251 | "source": "openmaptiles", 252 | "source-layer": "waterway", 253 | "type": "line", 254 | "layout": { 255 | "visibility": "visible" 256 | } 257 | }, { 258 | "filter": ["all", ["==", "$type", "LineString"], 259 | ["==", "brunnel", "tunnel"], 260 | ["==", "class", "transit"] 261 | ], 262 | "id": "tunnel_railway_transit", 263 | "layout": { 264 | "line-cap": "butt", 265 | "line-join": "miter" 266 | }, 267 | "minzoom": 0, 268 | "paint": { 269 | "line-color": "hsl(34, 12%, 66%)", 270 | "line-dasharray": [3, 3], 271 | "line-opacity": { 272 | "base": 1, 273 | "stops": [ 274 | [11, 0], 275 | [16, 1] 276 | ] 277 | } 278 | }, 279 | "source": "openmaptiles", 280 | "source-layer": "transportation", 281 | "type": "line" 282 | }, { 283 | "id": "building", 284 | "paint": { 285 | "fill-antialias": true, 286 | "fill-color": "rgba(222, 211, 190, 1)", 287 | "fill-opacity": { 288 | "base": 1, 289 | "stops": [ 290 | [13, 0], 291 | [15, 1] 292 | ] 293 | }, 294 | "fill-outline-color": { 295 | "stops": [ 296 | [15, "rgba(212, 177, 146, 0)"], 297 | [16, "rgba(212, 177, 146, 0.5)"] 298 | ] 299 | } 300 | }, 301 | "source": "openmaptiles", 302 | "source-layer": "building", 303 | "type": "fill" 304 | }, { 305 | "filter": ["==", "$type", "Point"], 306 | "id": "housenumber", 307 | "layout": { 308 | "text-field": "{housenumber}", 309 | "text-font": ["Noto Sans Regular"], 310 | "text-size": 10 311 | }, 312 | "minzoom": 17, 313 | "paint": { 314 | "text-color": "rgba(212, 177, 146, 1)" 315 | }, 316 | "source": "openmaptiles", 317 | "source-layer": "housenumber", 318 | "type": "symbol" 319 | }, { 320 | "id": "road_area_pier", 321 | "type": "fill", 322 | "metadata": {}, 323 | "source": "openmaptiles", 324 | "source-layer": "transportation", 325 | "filter": ["all", ["==", "$type", "Polygon"], 326 | ["==", "class", "pier"] 327 | ], 328 | "layout": { 329 | "visibility": "visible" 330 | }, 331 | "paint": { 332 | "fill-color": "hsl(47, 26%, 88%)", 333 | "fill-antialias": true 334 | } 335 | }, { 336 | "id": "road_pier", 337 | "type": "line", 338 | "metadata": {}, 339 | "source": "openmaptiles", 340 | "source-layer": "transportation", 341 | "filter": ["all", ["==", "$type", "LineString"], 342 | ["in", "class", "pier"] 343 | ], 344 | "layout": { 345 | "line-cap": "round", 346 | "line-join": "round" 347 | }, 348 | "paint": { 349 | "line-color": "hsl(47, 26%, 88%)", 350 | "line-width": { 351 | "base": 1.2, 352 | "stops": [ 353 | [15, 1], 354 | [17, 4] 355 | ] 356 | } 357 | } 358 | }, { 359 | "filter": ["all", ["==", "$type", "Polygon"], 360 | ["in", "brunnel", "bridge"] 361 | ], 362 | "id": "road_bridge_area", 363 | "layout": {}, 364 | "paint": { 365 | "fill-color": "hsl(47, 26%, 88%)", 366 | "fill-opacity": 0.5 367 | }, 368 | "source": "openmaptiles", 369 | "source-layer": "transportation", 370 | "type": "fill" 371 | }, { 372 | "filter": ["all", ["==", "$type", "LineString"], 373 | ["in", "class", "path", "track"] 374 | ], 375 | "id": "road_path", 376 | "layout": { 377 | "line-cap": "square", 378 | "line-join": "bevel" 379 | }, 380 | "paint": { 381 | "line-color": "hsl(0, 0%, 97%)", 382 | "line-dasharray": [1, 1], 383 | "line-width": { 384 | "base": 1.55, 385 | "stops": [ 386 | [4, 0.25], 387 | [20, 10] 388 | ] 389 | } 390 | }, 391 | "source": "openmaptiles", 392 | "source-layer": "transportation", 393 | "type": "line" 394 | }, { 395 | "filter": ["all", ["==", "$type", "LineString"], 396 | ["in", "class", "minor", "service"] 397 | ], 398 | "id": "road_minor", 399 | "layout": { 400 | "line-cap": "round", 401 | "line-join": "round" 402 | }, 403 | "paint": { 404 | "line-color": "hsl(0, 0%, 97%)", 405 | "line-width": { 406 | "base": 1.55, 407 | "stops": [ 408 | [4, 0.25], 409 | [20, 30] 410 | ] 411 | } 412 | }, 413 | "source": "openmaptiles", 414 | "source-layer": "transportation", 415 | "type": "line", 416 | "minzoom": 13 417 | }, { 418 | "filter": ["all", ["==", "$type", "LineString"], 419 | ["==", "brunnel", "tunnel"], 420 | ["==", "class", "minor_road"] 421 | ], 422 | "id": "tunnel_minor", 423 | "layout": { 424 | "line-cap": "butt", 425 | "line-join": "miter" 426 | }, 427 | "paint": { 428 | "line-color": "#efefef", 429 | "line-dasharray": [0.36, 0.18], 430 | "line-width": { 431 | "base": 1.55, 432 | "stops": [ 433 | [4, 0.25], 434 | [20, 30] 435 | ] 436 | } 437 | }, 438 | "source": "openmaptiles", 439 | "source-layer": "transportation", 440 | "type": "line" 441 | }, { 442 | "filter": ["all", ["==", "$type", "LineString"], 443 | ["==", "brunnel", "tunnel"], 444 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 445 | ], 446 | "id": "tunnel_major", 447 | "layout": { 448 | "line-cap": "butt", 449 | "line-join": "miter" 450 | }, 451 | "paint": { 452 | "line-color": "#fff", 453 | "line-dasharray": [0.28, 0.14], 454 | "line-width": { 455 | "base": 1.4, 456 | "stops": [ 457 | [6, 0.5], 458 | [20, 30] 459 | ] 460 | } 461 | }, 462 | "source": "openmaptiles", 463 | "source-layer": "transportation", 464 | "type": "line" 465 | }, { 466 | "filter": ["all", ["==", "$type", "Polygon"], 467 | ["in", "class", "runway", "taxiway"] 468 | ], 469 | "id": "aeroway-area", 470 | "layout": { 471 | "visibility": "visible" 472 | }, 473 | "metadata": { 474 | "mapbox:group": "1444849345966.4436" 475 | }, 476 | "minzoom": 4, 477 | "paint": { 478 | "fill-color": "rgba(255, 255, 255, 1)", 479 | "fill-opacity": { 480 | "base": 1, 481 | "stops": [ 482 | [13, 0], 483 | [14, 1] 484 | ] 485 | } 486 | }, 487 | "source": "openmaptiles", 488 | "source-layer": "aeroway", 489 | "type": "fill" 490 | }, { 491 | "filter": ["all", ["in", "class", "taxiway"], 492 | ["==", "$type", "LineString"] 493 | ], 494 | "id": "aeroway-taxiway", 495 | "layout": { 496 | "line-cap": "round", 497 | "line-join": "round", 498 | "visibility": "visible" 499 | }, 500 | "metadata": { 501 | "mapbox:group": "1444849345966.4436" 502 | }, 503 | "minzoom": 12, 504 | "paint": { 505 | "line-color": "rgba(255, 255, 255, 1)", 506 | "line-opacity": 1, 507 | "line-width": { 508 | "base": 1.5, 509 | "stops": [ 510 | [12, 1], 511 | [17, 10] 512 | ] 513 | } 514 | }, 515 | "source": "openmaptiles", 516 | "source-layer": "aeroway", 517 | "type": "line" 518 | }, { 519 | "filter": ["all", ["in", "class", "runway"], 520 | ["==", "$type", "LineString"] 521 | ], 522 | "id": "aeroway-runway", 523 | "layout": { 524 | "line-cap": "round", 525 | "line-join": "round", 526 | "visibility": "visible" 527 | }, 528 | "metadata": { 529 | "mapbox:group": "1444849345966.4436" 530 | }, 531 | "minzoom": 4, 532 | "paint": { 533 | "line-color": "rgba(255, 255, 255, 1)", 534 | "line-opacity": 1, 535 | "line-width": { 536 | "base": 1.5, 537 | "stops": [ 538 | [11, 4], 539 | [17, 50] 540 | ] 541 | } 542 | }, 543 | "source": "openmaptiles", 544 | "source-layer": "aeroway", 545 | "type": "line" 546 | }, { 547 | "filter": ["all", ["==", "$type", "LineString"], 548 | ["in", "class", "trunk", "primary"] 549 | ], 550 | "id": "road_trunk_primary", 551 | "layout": { 552 | "line-cap": "round", 553 | "line-join": "round" 554 | }, 555 | "paint": { 556 | "line-color": "#fff", 557 | "line-width": { 558 | "base": 1.4, 559 | "stops": [ 560 | [6, 0.5], 561 | [20, 30] 562 | ] 563 | } 564 | }, 565 | "source": "openmaptiles", 566 | "source-layer": "transportation", 567 | "type": "line" 568 | }, { 569 | "filter": ["all", ["==", "$type", "LineString"], 570 | ["in", "class", "secondary", "tertiary"] 571 | ], 572 | "id": "road_secondary_tertiary", 573 | "layout": { 574 | "line-cap": "round", 575 | "line-join": "round" 576 | }, 577 | "paint": { 578 | "line-color": "#fff", 579 | "line-width": { 580 | "base": 1.4, 581 | "stops": [ 582 | [6, 0.5], 583 | [20, 20] 584 | ] 585 | } 586 | }, 587 | "source": "openmaptiles", 588 | "source-layer": "transportation", 589 | "type": "line" 590 | }, { 591 | "filter": ["all", ["==", "$type", "LineString"], 592 | ["==", "class", "motorway"] 593 | ], 594 | "id": "road_major_motorway", 595 | "layout": { 596 | "line-cap": "round", 597 | "line-join": "round" 598 | }, 599 | "paint": { 600 | "line-color": "hsl(0, 0%, 100%)", 601 | "line-offset": 0, 602 | "line-width": { 603 | "base": 1.4, 604 | "stops": [ 605 | [8, 1], 606 | [16, 10] 607 | ] 608 | } 609 | }, 610 | "source": "openmaptiles", 611 | "source-layer": "transportation", 612 | "type": "line" 613 | }, { 614 | "filter": ["all", ["==", "class", "transit"], 615 | ["!=", "brunnel", "tunnel"] 616 | ], 617 | "id": "railway-transit", 618 | "layout": { 619 | "visibility": "visible" 620 | }, 621 | "paint": { 622 | "line-color": "hsl(34, 12%, 66%)", 623 | "line-opacity": { 624 | "base": 1, 625 | "stops": [ 626 | [11, 0], 627 | [16, 1] 628 | ] 629 | } 630 | }, 631 | "source": "openmaptiles", 632 | "source-layer": "transportation", 633 | "type": "line" 634 | }, { 635 | "filter": ["==", "class", "rail"], 636 | "id": "railway", 637 | "layout": { 638 | "visibility": "visible" 639 | }, 640 | "paint": { 641 | "line-color": "hsl(34, 12%, 66%)", 642 | "line-opacity": { 643 | "base": 1, 644 | "stops": [ 645 | [11, 0], 646 | [16, 1] 647 | ] 648 | } 649 | }, 650 | "source": "openmaptiles", 651 | "source-layer": "transportation", 652 | "type": "line" 653 | }, { 654 | "filter": ["all", ["==", "$type", "LineString"], 655 | ["==", "brunnel", "bridge"] 656 | ], 657 | "id": "waterway-bridge-case", 658 | "layout": { 659 | "line-cap": "butt", 660 | "line-join": "miter" 661 | }, 662 | "paint": { 663 | "line-color": "#bbbbbb", 664 | "line-gap-width": { 665 | "base": 1.55, 666 | "stops": [ 667 | [4, 0.25], 668 | [20, 30] 669 | ] 670 | }, 671 | "line-width": { 672 | "base": 1.6, 673 | "stops": [ 674 | [12, 0.5], 675 | [20, 10] 676 | ] 677 | } 678 | }, 679 | "source": "openmaptiles", 680 | "source-layer": "waterway", 681 | "type": "line" 682 | }, { 683 | "filter": ["all", ["==", "$type", "LineString"], 684 | ["==", "brunnel", "bridge"] 685 | ], 686 | "id": "waterway-bridge", 687 | "layout": { 688 | "line-cap": "round", 689 | "line-join": "round" 690 | }, 691 | "paint": { 692 | "line-color": "hsl(205, 56%, 73%)", 693 | "line-width": { 694 | "base": 1.55, 695 | "stops": [ 696 | [4, 0.25], 697 | [20, 30] 698 | ] 699 | } 700 | }, 701 | "source": "openmaptiles", 702 | "source-layer": "waterway", 703 | "type": "line" 704 | }, { 705 | "filter": ["all", ["==", "$type", "LineString"], 706 | ["==", "brunnel", "bridge"], 707 | ["==", "class", "minor_road"] 708 | ], 709 | "id": "bridge_minor case", 710 | "layout": { 711 | "line-cap": "butt", 712 | "line-join": "miter" 713 | }, 714 | "paint": { 715 | "line-color": "#dedede", 716 | "line-gap-width": { 717 | "base": 1.55, 718 | "stops": [ 719 | [4, 0.25], 720 | [20, 30] 721 | ] 722 | }, 723 | "line-width": { 724 | "base": 1.6, 725 | "stops": [ 726 | [12, 0.5], 727 | [20, 10] 728 | ] 729 | } 730 | }, 731 | "source": "openmaptiles", 732 | "source-layer": "transportation", 733 | "type": "line" 734 | }, { 735 | "filter": ["all", ["==", "$type", "LineString"], 736 | ["==", "brunnel", "bridge"], 737 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 738 | ], 739 | "id": "bridge_major case", 740 | "layout": { 741 | "line-cap": "butt", 742 | "line-join": "miter" 743 | }, 744 | "paint": { 745 | "line-color": "#dedede", 746 | "line-gap-width": { 747 | "base": 1.55, 748 | "stops": [ 749 | [4, 0.25], 750 | [20, 30] 751 | ] 752 | }, 753 | "line-width": { 754 | "base": 1.6, 755 | "stops": [ 756 | [12, 0.5], 757 | [20, 10] 758 | ] 759 | } 760 | }, 761 | "source": "openmaptiles", 762 | "source-layer": "transportation", 763 | "type": "line" 764 | }, { 765 | "filter": ["all", ["==", "$type", "LineString"], 766 | ["==", "brunnel", "bridge"], 767 | ["==", "class", "minor_road"] 768 | ], 769 | "id": "bridge_minor", 770 | "layout": { 771 | "line-cap": "round", 772 | "line-join": "round" 773 | }, 774 | "paint": { 775 | "line-color": "#efefef", 776 | "line-width": { 777 | "base": 1.55, 778 | "stops": [ 779 | [4, 0.25], 780 | [20, 30] 781 | ] 782 | } 783 | }, 784 | "source": "openmaptiles", 785 | "source-layer": "transportation", 786 | "type": "line" 787 | }, { 788 | "filter": ["all", ["==", "$type", "LineString"], 789 | ["==", "brunnel", "bridge"], 790 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 791 | ], 792 | "id": "bridge_major", 793 | "layout": { 794 | "line-cap": "round", 795 | "line-join": "round" 796 | }, 797 | "paint": { 798 | "line-color": "#fff", 799 | "line-width": { 800 | "base": 1.4, 801 | "stops": [ 802 | [6, 0.5], 803 | [20, 30] 804 | ] 805 | } 806 | }, 807 | "source": "openmaptiles", 808 | "source-layer": "transportation", 809 | "type": "line" 810 | }, { 811 | "filter": ["in", "admin_level", 4, 6, 8], 812 | "id": "admin_sub", 813 | "layout": { 814 | "visibility": "visible" 815 | }, 816 | "paint": { 817 | "line-color": "hsla(0, 0%, 60%, 0.5)", 818 | "line-dasharray": [2, 1] 819 | }, 820 | "source": "openmaptiles", 821 | "source-layer": "boundary", 822 | "type": "line" 823 | }, { 824 | "filter": ["all", ["<=", "admin_level", 2], 825 | ["==", "$type", "LineString"] 826 | ], 827 | "id": "admin_country", 828 | "layout": { 829 | "line-cap": "round", 830 | "line-join": "round" 831 | }, 832 | "paint": { 833 | "line-color": "hsl(0, 0%, 60%)", 834 | "line-width": { 835 | "base": 1.3, 836 | "stops": [ 837 | [3, 0.5], 838 | [22, 15] 839 | ] 840 | } 841 | }, 842 | "source": "openmaptiles", 843 | "source-layer": "boundary", 844 | "type": "line" 845 | }, { 846 | "filter": ["all", ["==", "$type", "Point"], 847 | ["==", "rank", 1] 848 | ], 849 | "id": "poi_label", 850 | "layout": { 851 | "icon-size": 1, 852 | "text-anchor": "top", 853 | "text-field": "{name:latin}\n{name:nonlatin}", 854 | "text-font": ["Noto Sans Regular"], 855 | "text-max-width": 8, 856 | "text-offset": [0, 0.5], 857 | "text-size": 11, 858 | "visibility": "visible" 859 | }, 860 | "minzoom": 14, 861 | "paint": { 862 | "text-color": "#666", 863 | "text-halo-blur": 1, 864 | "text-halo-color": "rgba(255,255,255,0.75)", 865 | "text-halo-width": 1 866 | }, 867 | "source": "openmaptiles", 868 | "source-layer": "poi", 869 | "type": "symbol" 870 | }, { 871 | "filter": ["all", ["has", "iata"]], 872 | "id": "airport-label", 873 | "layout": { 874 | "icon-size": 1, 875 | "text-anchor": "top", 876 | "text-field": "{name:latin}\n{name:nonlatin}", 877 | "text-font": ["Noto Sans Regular"], 878 | "text-max-width": 8, 879 | "text-offset": [0, 0.5], 880 | "text-size": 11, 881 | "visibility": "visible" 882 | }, 883 | "minzoom": 10, 884 | "paint": { 885 | "text-color": "#666", 886 | "text-halo-blur": 1, 887 | "text-halo-color": "rgba(255,255,255,0.75)", 888 | "text-halo-width": 1 889 | }, 890 | "source": "openmaptiles", 891 | "source-layer": "aerodrome_label", 892 | "type": "symbol" 893 | }, { 894 | "filter": ["==", "$type", "LineString"], 895 | "id": "road_major_label", 896 | "layout": { 897 | "symbol-placement": "line", 898 | "text-field": "{name:latin} {name:nonlatin}", 899 | "text-font": ["Noto Sans Regular"], 900 | "text-letter-spacing": 0.1, 901 | "text-rotation-alignment": "map", 902 | "text-size": { 903 | "base": 1.4, 904 | "stops": [ 905 | [10, 8], 906 | [20, 14] 907 | ] 908 | }, 909 | "text-transform": "uppercase" 910 | }, 911 | "paint": { 912 | "text-color": "#000", 913 | "text-halo-color": "hsl(0, 0%, 100%)", 914 | "text-halo-width": 2 915 | }, 916 | "source": "openmaptiles", 917 | "source-layer": "transportation_name", 918 | "type": "symbol" 919 | }, { 920 | "filter": ["all", ["==", "$type", "Point"], 921 | ["!in", "class", "city", "state", "country", "continent"] 922 | ], 923 | "id": "place_label_other", 924 | "layout": { 925 | "text-anchor": "center", 926 | "text-field": "{name:latin}\n{name:nonlatin}", 927 | "text-font": ["Noto Sans Regular"], 928 | "text-max-width": 6, 929 | "text-size": { 930 | "stops": [ 931 | [6, 10], 932 | [12, 14] 933 | ] 934 | }, 935 | "visibility": "visible" 936 | }, 937 | "minzoom": 8, 938 | "paint": { 939 | "text-color": "hsl(0, 0%, 25%)", 940 | "text-halo-blur": 0, 941 | "text-halo-color": "hsl(0, 0%, 100%)", 942 | "text-halo-width": 2 943 | }, 944 | "source": "openmaptiles", 945 | "source-layer": "place", 946 | "type": "symbol" 947 | }, { 948 | "filter": ["all", ["==", "$type", "Point"], 949 | ["==", "class", "city"] 950 | ], 951 | "id": "place_label_city", 952 | "layout": { 953 | "text-field": "{name:latin}\n{name:nonlatin}", 954 | "text-font": ["Noto Sans Regular"], 955 | "text-max-width": 10, 956 | "text-size": { 957 | "stops": [ 958 | [3, 12], 959 | [8, 16] 960 | ] 961 | } 962 | }, 963 | "maxzoom": 16, 964 | "paint": { 965 | "text-color": "hsl(0, 0%, 0%)", 966 | "text-halo-blur": 0, 967 | "text-halo-color": "hsla(0, 0%, 100%, 0.75)", 968 | "text-halo-width": 2 969 | }, 970 | "source": "openmaptiles", 971 | "source-layer": "place", 972 | "type": "symbol" 973 | }, { 974 | "filter": ["all", ["==", "$type", "Point"], 975 | ["==", "class", "country"], 976 | ["!has", "iso_a2"] 977 | ], 978 | "id": "country_label-other", 979 | "layout": { 980 | "text-field": "{name:latin}", 981 | "text-font": ["Noto Sans Regular"], 982 | "text-max-width": 10, 983 | "text-size": { 984 | "stops": [ 985 | [3, 12], 986 | [8, 22] 987 | ] 988 | }, 989 | "visibility": "visible" 990 | }, 991 | "maxzoom": 12, 992 | "paint": { 993 | "text-color": "hsl(0, 0%, 13%)", 994 | "text-halo-blur": 0, 995 | "text-halo-color": "rgba(255,255,255,0.75)", 996 | "text-halo-width": 2 997 | }, 998 | "source": "openmaptiles", 999 | "source-layer": "place", 1000 | "type": "symbol" 1001 | }, { 1002 | "filter": ["all", ["==", "$type", "Point"], 1003 | ["==", "class", "country"], 1004 | ["has", "iso_a2"] 1005 | ], 1006 | "id": "country_label", 1007 | "layout": { 1008 | "text-field": "{name:latin}", 1009 | "text-font": ["Noto Sans Bold"], 1010 | "text-max-width": 10, 1011 | "text-size": { 1012 | "stops": [ 1013 | [3, 12], 1014 | [8, 22] 1015 | ] 1016 | }, 1017 | "visibility": "visible" 1018 | }, 1019 | "maxzoom": 12, 1020 | "paint": { 1021 | "text-color": "hsl(0, 0%, 13%)", 1022 | "text-halo-blur": 0, 1023 | "text-halo-color": "rgba(255,255,255,0.75)", 1024 | "text-halo-width": 2 1025 | }, 1026 | "source": "openmaptiles", 1027 | "source-layer": "place", 1028 | "type": "symbol" 1029 | },{ 1030 | "id": "geojsonSamplerPoints", 1031 | "type": "circle", 1032 | "source": "geojsonSamplerPoints", 1033 | "source-layer": "geojsonSamplerPoints", 1034 | "layout": { 1035 | "visibility": "visible" 1036 | }, 1037 | "paint": { 1038 | "circle-radius": 2, 1039 | "circle-color": "red", 1040 | "circle-opacity": 1 1041 | } 1042 | }, 1043 | { 1044 | "id": "geojsonSamplerLines", 1045 | "type": "line", 1046 | "source": "geojsonSamplerLines", 1047 | "source-layer": "geojsonSamplerLines", 1048 | "layout": { 1049 | "visibility": "visible" 1050 | }, 1051 | "paint": { 1052 | "line-width": 2, 1053 | "line-color": "red", 1054 | "line-opacity": 1 1055 | } 1056 | } 1057 | ], 1058 | "id": "basic" 1059 | } 1060 | -------------------------------------------------------------------------------- /examples/geojson/klokantech-basic-style-geojson-usStates.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "name": "Basic", 4 | "metadata": { 5 | "mapbox:autocomposite": false, 6 | "mapbox:type": "template", 7 | "maputnik:renderer": "mbgljs", 8 | "openmaptiles:version": "3.x", 9 | "openmaptiles:mapbox:owner": "openmaptiles", 10 | "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t" 11 | }, 12 | "sources": { 13 | "openmaptiles": { 14 | "type": "vector", 15 | "url": "https://api.maptiler.com/tiles/v3/tiles.json?key=mrAq6zQEFxOkanukNbGm" 16 | }, 17 | "states": { 18 | "type": "geojson", 19 | "data": "./us-states.geojson", 20 | "minzoom" :0, 21 | "maxzoom" :14, 22 | "tileSize": 512 23 | } 24 | }, 25 | "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=mrAq6zQEFxOkanukNbGm", 26 | "layers": [{ 27 | "id": "background", 28 | "paint": { 29 | "background-color": "hsl(47, 26%, 88%)" 30 | }, 31 | "type": "background" 32 | }, { 33 | "filter": ["all", ["==", "$type", "Polygon"], 34 | ["in", "class", "residential", "suburb", "neighbourhood"] 35 | ], 36 | "id": "landuse-residential", 37 | "layout": { 38 | "visibility": "visible" 39 | }, 40 | "paint": { 41 | "fill-color": "hsl(47, 13%, 86%)", 42 | "fill-opacity": 0.7 43 | }, 44 | "source": "openmaptiles", 45 | "source-layer": "landuse", 46 | "type": "fill" 47 | }, { 48 | "filter": ["==", "class", "grass"], 49 | "id": "landcover_grass", 50 | "paint": { 51 | "fill-color": "hsl(82, 46%, 72%)", 52 | "fill-opacity": 0.45 53 | }, 54 | "source": "openmaptiles", 55 | "source-layer": "landcover", 56 | "type": "fill" 57 | }, { 58 | "filter": ["==", "class", "wood"], 59 | "id": "landcover_wood", 60 | "paint": { 61 | "fill-color": "hsl(82, 46%, 72%)", 62 | "fill-opacity": { 63 | "base": 1, 64 | "stops": [ 65 | [8, 0.6], 66 | [22, 1] 67 | ] 68 | } 69 | }, 70 | "source": "openmaptiles", 71 | "source-layer": "landcover", 72 | "type": "fill" 73 | }, { 74 | "filter": ["all", ["==", "$type", "Polygon"], 75 | ["!=", "intermittent", 1] 76 | ], 77 | "id": "water", 78 | "paint": { 79 | "fill-color": "hsl(205, 56%, 73%)" 80 | }, 81 | "source": "openmaptiles", 82 | "source-layer": "water", 83 | "type": "fill", 84 | "layout": { 85 | "visibility": "visible" 86 | } 87 | }, { 88 | "filter": ["all", ["==", "$type", "Polygon"], 89 | ["==", "intermittent", 1] 90 | ], 91 | "id": "water_intermittent", 92 | "paint": { 93 | "fill-color": "hsl(205, 56%, 73%)", 94 | "fill-opacity": 0.7 95 | }, 96 | "source": "openmaptiles", 97 | "source-layer": "water", 98 | "type": "fill", 99 | "layout": { 100 | "visibility": "visible" 101 | } 102 | }, { 103 | "filter": ["==", "subclass", "ice_shelf"], 104 | "id": "landcover-ice-shelf", 105 | "layout": { 106 | "visibility": "visible" 107 | }, 108 | "paint": { 109 | "fill-color": "hsl(47, 26%, 88%)", 110 | "fill-opacity": 0.8 111 | }, 112 | "source": "openmaptiles", 113 | "source-layer": "landcover", 114 | "type": "fill" 115 | }, { 116 | "filter": ["==", "subclass", "glacier"], 117 | "id": "landcover-glacier", 118 | "layout": { 119 | "visibility": "visible" 120 | }, 121 | "paint": { 122 | "fill-color": "hsl(47, 22%, 94%)", 123 | "fill-opacity": { 124 | "base": 1, 125 | "stops": [ 126 | [0, 1], 127 | [8, 0.5] 128 | ] 129 | } 130 | }, 131 | "source": "openmaptiles", 132 | "source-layer": "landcover", 133 | "type": "fill" 134 | }, { 135 | "filter": ["all", ["in", "class", "sand"]], 136 | "id": "landcover_sand", 137 | "metadata": {}, 138 | "paint": { 139 | "fill-antialias": false, 140 | "fill-color": "rgba(232, 214, 38, 1)", 141 | "fill-opacity": 0.3 142 | }, 143 | "source": "openmaptiles", 144 | "source-layer": "landcover", 145 | "type": "fill" 146 | }, { 147 | "filter": ["==", "class", "agriculture"], 148 | "id": "landuse", 149 | "layout": { 150 | "visibility": "visible" 151 | }, 152 | "paint": { 153 | "fill-color": "#eae0d0" 154 | }, 155 | "source": "openmaptiles", 156 | "source-layer": "landuse", 157 | "type": "fill" 158 | }, { 159 | "filter": ["==", "class", "national_park"], 160 | "id": "landuse_overlay_national_park", 161 | "paint": { 162 | "fill-color": "#E1EBB0", 163 | "fill-opacity": { 164 | "base": 1, 165 | "stops": [ 166 | [5, 0], 167 | [9, 0.75] 168 | ] 169 | } 170 | }, 171 | "source": "openmaptiles", 172 | "source-layer": "landcover", 173 | "type": "fill" 174 | }, { 175 | "filter": ["all", ["==", "$type", "LineString"], 176 | ["==", "brunnel", "tunnel"] 177 | ], 178 | "id": "waterway-tunnel", 179 | "paint": { 180 | "line-color": "hsl(205, 56%, 73%)", 181 | "line-dasharray": [3, 3], 182 | "line-gap-width": { 183 | "stops": [ 184 | [12, 0], 185 | [20, 6] 186 | ] 187 | }, 188 | "line-opacity": 1, 189 | "line-width": { 190 | "base": 1.4, 191 | "stops": [ 192 | [8, 1], 193 | [20, 2] 194 | ] 195 | } 196 | }, 197 | "source": "openmaptiles", 198 | "source-layer": "waterway", 199 | "type": "line", 200 | "layout": { 201 | "visibility": "visible" 202 | } 203 | }, { 204 | "filter": ["all", ["==", "$type", "LineString"], 205 | ["!in", "brunnel", "tunnel", "bridge"], 206 | ["!=", "intermittent", 1] 207 | ], 208 | "id": "waterway", 209 | "paint": { 210 | "line-color": "hsl(205, 56%, 73%)", 211 | "line-opacity": 1, 212 | "line-width": { 213 | "base": 1.4, 214 | "stops": [ 215 | [8, 1], 216 | [20, 8] 217 | ] 218 | } 219 | }, 220 | "source": "openmaptiles", 221 | "source-layer": "waterway", 222 | "type": "line", 223 | "layout": { 224 | "visibility": "visible" 225 | } 226 | }, { 227 | "filter": ["all", ["==", "$type", "LineString"], 228 | ["!in", "brunnel", "tunnel", "bridge"], 229 | ["==", "intermittent", 1] 230 | ], 231 | "id": "waterway_intermittent", 232 | "paint": { 233 | "line-color": "hsl(205, 56%, 73%)", 234 | "line-opacity": 1, 235 | "line-width": { 236 | "base": 1.4, 237 | "stops": [ 238 | [8, 1], 239 | [20, 8] 240 | ] 241 | }, 242 | "line-dasharray": [2, 1] 243 | }, 244 | "source": "openmaptiles", 245 | "source-layer": "waterway", 246 | "type": "line", 247 | "layout": { 248 | "visibility": "visible" 249 | } 250 | }, { 251 | "filter": ["all", ["==", "$type", "LineString"], 252 | ["==", "brunnel", "tunnel"], 253 | ["==", "class", "transit"] 254 | ], 255 | "id": "tunnel_railway_transit", 256 | "layout": { 257 | "line-cap": "butt", 258 | "line-join": "miter" 259 | }, 260 | "minzoom": 0, 261 | "paint": { 262 | "line-color": "hsl(34, 12%, 66%)", 263 | "line-dasharray": [3, 3], 264 | "line-opacity": { 265 | "base": 1, 266 | "stops": [ 267 | [11, 0], 268 | [16, 1] 269 | ] 270 | } 271 | }, 272 | "source": "openmaptiles", 273 | "source-layer": "transportation", 274 | "type": "line" 275 | }, { 276 | "id": "building", 277 | "paint": { 278 | "fill-antialias": true, 279 | "fill-color": "rgba(222, 211, 190, 1)", 280 | "fill-opacity": { 281 | "base": 1, 282 | "stops": [ 283 | [13, 0], 284 | [15, 1] 285 | ] 286 | }, 287 | "fill-outline-color": { 288 | "stops": [ 289 | [15, "rgba(212, 177, 146, 0)"], 290 | [16, "rgba(212, 177, 146, 0.5)"] 291 | ] 292 | } 293 | }, 294 | "source": "openmaptiles", 295 | "source-layer": "building", 296 | "type": "fill" 297 | }, { 298 | "filter": ["==", "$type", "Point"], 299 | "id": "housenumber", 300 | "layout": { 301 | "text-field": "{housenumber}", 302 | "text-font": ["Noto Sans Regular"], 303 | "text-size": 10 304 | }, 305 | "minzoom": 17, 306 | "paint": { 307 | "text-color": "rgba(212, 177, 146, 1)" 308 | }, 309 | "source": "openmaptiles", 310 | "source-layer": "housenumber", 311 | "type": "symbol" 312 | }, { 313 | "id": "road_area_pier", 314 | "type": "fill", 315 | "metadata": {}, 316 | "source": "openmaptiles", 317 | "source-layer": "transportation", 318 | "filter": ["all", ["==", "$type", "Polygon"], 319 | ["==", "class", "pier"] 320 | ], 321 | "layout": { 322 | "visibility": "visible" 323 | }, 324 | "paint": { 325 | "fill-color": "hsl(47, 26%, 88%)", 326 | "fill-antialias": true 327 | } 328 | }, { 329 | "id": "road_pier", 330 | "type": "line", 331 | "metadata": {}, 332 | "source": "openmaptiles", 333 | "source-layer": "transportation", 334 | "filter": ["all", ["==", "$type", "LineString"], 335 | ["in", "class", "pier"] 336 | ], 337 | "layout": { 338 | "line-cap": "round", 339 | "line-join": "round" 340 | }, 341 | "paint": { 342 | "line-color": "hsl(47, 26%, 88%)", 343 | "line-width": { 344 | "base": 1.2, 345 | "stops": [ 346 | [15, 1], 347 | [17, 4] 348 | ] 349 | } 350 | } 351 | }, { 352 | "filter": ["all", ["==", "$type", "Polygon"], 353 | ["in", "brunnel", "bridge"] 354 | ], 355 | "id": "road_bridge_area", 356 | "layout": {}, 357 | "paint": { 358 | "fill-color": "hsl(47, 26%, 88%)", 359 | "fill-opacity": 0.5 360 | }, 361 | "source": "openmaptiles", 362 | "source-layer": "transportation", 363 | "type": "fill" 364 | }, { 365 | "filter": ["all", ["==", "$type", "LineString"], 366 | ["in", "class", "path", "track"] 367 | ], 368 | "id": "road_path", 369 | "layout": { 370 | "line-cap": "square", 371 | "line-join": "bevel" 372 | }, 373 | "paint": { 374 | "line-color": "hsl(0, 0%, 97%)", 375 | "line-dasharray": [1, 1], 376 | "line-width": { 377 | "base": 1.55, 378 | "stops": [ 379 | [4, 0.25], 380 | [20, 10] 381 | ] 382 | } 383 | }, 384 | "source": "openmaptiles", 385 | "source-layer": "transportation", 386 | "type": "line" 387 | }, { 388 | "filter": ["all", ["==", "$type", "LineString"], 389 | ["in", "class", "minor", "service"] 390 | ], 391 | "id": "road_minor", 392 | "layout": { 393 | "line-cap": "round", 394 | "line-join": "round" 395 | }, 396 | "paint": { 397 | "line-color": "hsl(0, 0%, 97%)", 398 | "line-width": { 399 | "base": 1.55, 400 | "stops": [ 401 | [4, 0.25], 402 | [20, 30] 403 | ] 404 | } 405 | }, 406 | "source": "openmaptiles", 407 | "source-layer": "transportation", 408 | "type": "line", 409 | "minzoom": 13 410 | }, { 411 | "filter": ["all", ["==", "$type", "LineString"], 412 | ["==", "brunnel", "tunnel"], 413 | ["==", "class", "minor_road"] 414 | ], 415 | "id": "tunnel_minor", 416 | "layout": { 417 | "line-cap": "butt", 418 | "line-join": "miter" 419 | }, 420 | "paint": { 421 | "line-color": "#efefef", 422 | "line-dasharray": [0.36, 0.18], 423 | "line-width": { 424 | "base": 1.55, 425 | "stops": [ 426 | [4, 0.25], 427 | [20, 30] 428 | ] 429 | } 430 | }, 431 | "source": "openmaptiles", 432 | "source-layer": "transportation", 433 | "type": "line" 434 | }, { 435 | "filter": ["all", ["==", "$type", "LineString"], 436 | ["==", "brunnel", "tunnel"], 437 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 438 | ], 439 | "id": "tunnel_major", 440 | "layout": { 441 | "line-cap": "butt", 442 | "line-join": "miter" 443 | }, 444 | "paint": { 445 | "line-color": "#fff", 446 | "line-dasharray": [0.28, 0.14], 447 | "line-width": { 448 | "base": 1.4, 449 | "stops": [ 450 | [6, 0.5], 451 | [20, 30] 452 | ] 453 | } 454 | }, 455 | "source": "openmaptiles", 456 | "source-layer": "transportation", 457 | "type": "line" 458 | }, { 459 | "filter": ["all", ["==", "$type", "Polygon"], 460 | ["in", "class", "runway", "taxiway"] 461 | ], 462 | "id": "aeroway-area", 463 | "layout": { 464 | "visibility": "visible" 465 | }, 466 | "metadata": { 467 | "mapbox:group": "1444849345966.4436" 468 | }, 469 | "minzoom": 4, 470 | "paint": { 471 | "fill-color": "rgba(255, 255, 255, 1)", 472 | "fill-opacity": { 473 | "base": 1, 474 | "stops": [ 475 | [13, 0], 476 | [14, 1] 477 | ] 478 | } 479 | }, 480 | "source": "openmaptiles", 481 | "source-layer": "aeroway", 482 | "type": "fill" 483 | }, { 484 | "filter": ["all", ["in", "class", "taxiway"], 485 | ["==", "$type", "LineString"] 486 | ], 487 | "id": "aeroway-taxiway", 488 | "layout": { 489 | "line-cap": "round", 490 | "line-join": "round", 491 | "visibility": "visible" 492 | }, 493 | "metadata": { 494 | "mapbox:group": "1444849345966.4436" 495 | }, 496 | "minzoom": 12, 497 | "paint": { 498 | "line-color": "rgba(255, 255, 255, 1)", 499 | "line-opacity": 1, 500 | "line-width": { 501 | "base": 1.5, 502 | "stops": [ 503 | [12, 1], 504 | [17, 10] 505 | ] 506 | } 507 | }, 508 | "source": "openmaptiles", 509 | "source-layer": "aeroway", 510 | "type": "line" 511 | }, { 512 | "filter": ["all", ["in", "class", "runway"], 513 | ["==", "$type", "LineString"] 514 | ], 515 | "id": "aeroway-runway", 516 | "layout": { 517 | "line-cap": "round", 518 | "line-join": "round", 519 | "visibility": "visible" 520 | }, 521 | "metadata": { 522 | "mapbox:group": "1444849345966.4436" 523 | }, 524 | "minzoom": 4, 525 | "paint": { 526 | "line-color": "rgba(255, 255, 255, 1)", 527 | "line-opacity": 1, 528 | "line-width": { 529 | "base": 1.5, 530 | "stops": [ 531 | [11, 4], 532 | [17, 50] 533 | ] 534 | } 535 | }, 536 | "source": "openmaptiles", 537 | "source-layer": "aeroway", 538 | "type": "line" 539 | }, { 540 | "filter": ["all", ["==", "$type", "LineString"], 541 | ["in", "class", "trunk", "primary"] 542 | ], 543 | "id": "road_trunk_primary", 544 | "layout": { 545 | "line-cap": "round", 546 | "line-join": "round" 547 | }, 548 | "paint": { 549 | "line-color": "#fff", 550 | "line-width": { 551 | "base": 1.4, 552 | "stops": [ 553 | [6, 0.5], 554 | [20, 30] 555 | ] 556 | } 557 | }, 558 | "source": "openmaptiles", 559 | "source-layer": "transportation", 560 | "type": "line" 561 | }, { 562 | "filter": ["all", ["==", "$type", "LineString"], 563 | ["in", "class", "secondary", "tertiary"] 564 | ], 565 | "id": "road_secondary_tertiary", 566 | "layout": { 567 | "line-cap": "round", 568 | "line-join": "round" 569 | }, 570 | "paint": { 571 | "line-color": "#fff", 572 | "line-width": { 573 | "base": 1.4, 574 | "stops": [ 575 | [6, 0.5], 576 | [20, 20] 577 | ] 578 | } 579 | }, 580 | "source": "openmaptiles", 581 | "source-layer": "transportation", 582 | "type": "line" 583 | }, { 584 | "filter": ["all", ["==", "$type", "LineString"], 585 | ["==", "class", "motorway"] 586 | ], 587 | "id": "road_major_motorway", 588 | "layout": { 589 | "line-cap": "round", 590 | "line-join": "round" 591 | }, 592 | "paint": { 593 | "line-color": "hsl(0, 0%, 100%)", 594 | "line-offset": 0, 595 | "line-width": { 596 | "base": 1.4, 597 | "stops": [ 598 | [8, 1], 599 | [16, 10] 600 | ] 601 | } 602 | }, 603 | "source": "openmaptiles", 604 | "source-layer": "transportation", 605 | "type": "line" 606 | }, { 607 | "filter": ["all", ["==", "class", "transit"], 608 | ["!=", "brunnel", "tunnel"] 609 | ], 610 | "id": "railway-transit", 611 | "layout": { 612 | "visibility": "visible" 613 | }, 614 | "paint": { 615 | "line-color": "hsl(34, 12%, 66%)", 616 | "line-opacity": { 617 | "base": 1, 618 | "stops": [ 619 | [11, 0], 620 | [16, 1] 621 | ] 622 | } 623 | }, 624 | "source": "openmaptiles", 625 | "source-layer": "transportation", 626 | "type": "line" 627 | }, { 628 | "filter": ["==", "class", "rail"], 629 | "id": "railway", 630 | "layout": { 631 | "visibility": "visible" 632 | }, 633 | "paint": { 634 | "line-color": "hsl(34, 12%, 66%)", 635 | "line-opacity": { 636 | "base": 1, 637 | "stops": [ 638 | [11, 0], 639 | [16, 1] 640 | ] 641 | } 642 | }, 643 | "source": "openmaptiles", 644 | "source-layer": "transportation", 645 | "type": "line" 646 | }, { 647 | "filter": ["all", ["==", "$type", "LineString"], 648 | ["==", "brunnel", "bridge"] 649 | ], 650 | "id": "waterway-bridge-case", 651 | "layout": { 652 | "line-cap": "butt", 653 | "line-join": "miter" 654 | }, 655 | "paint": { 656 | "line-color": "#bbbbbb", 657 | "line-gap-width": { 658 | "base": 1.55, 659 | "stops": [ 660 | [4, 0.25], 661 | [20, 30] 662 | ] 663 | }, 664 | "line-width": { 665 | "base": 1.6, 666 | "stops": [ 667 | [12, 0.5], 668 | [20, 10] 669 | ] 670 | } 671 | }, 672 | "source": "openmaptiles", 673 | "source-layer": "waterway", 674 | "type": "line" 675 | }, { 676 | "filter": ["all", ["==", "$type", "LineString"], 677 | ["==", "brunnel", "bridge"] 678 | ], 679 | "id": "waterway-bridge", 680 | "layout": { 681 | "line-cap": "round", 682 | "line-join": "round" 683 | }, 684 | "paint": { 685 | "line-color": "hsl(205, 56%, 73%)", 686 | "line-width": { 687 | "base": 1.55, 688 | "stops": [ 689 | [4, 0.25], 690 | [20, 30] 691 | ] 692 | } 693 | }, 694 | "source": "openmaptiles", 695 | "source-layer": "waterway", 696 | "type": "line" 697 | }, { 698 | "filter": ["all", ["==", "$type", "LineString"], 699 | ["==", "brunnel", "bridge"], 700 | ["==", "class", "minor_road"] 701 | ], 702 | "id": "bridge_minor case", 703 | "layout": { 704 | "line-cap": "butt", 705 | "line-join": "miter" 706 | }, 707 | "paint": { 708 | "line-color": "#dedede", 709 | "line-gap-width": { 710 | "base": 1.55, 711 | "stops": [ 712 | [4, 0.25], 713 | [20, 30] 714 | ] 715 | }, 716 | "line-width": { 717 | "base": 1.6, 718 | "stops": [ 719 | [12, 0.5], 720 | [20, 10] 721 | ] 722 | } 723 | }, 724 | "source": "openmaptiles", 725 | "source-layer": "transportation", 726 | "type": "line" 727 | }, { 728 | "filter": ["all", ["==", "$type", "LineString"], 729 | ["==", "brunnel", "bridge"], 730 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 731 | ], 732 | "id": "bridge_major case", 733 | "layout": { 734 | "line-cap": "butt", 735 | "line-join": "miter" 736 | }, 737 | "paint": { 738 | "line-color": "#dedede", 739 | "line-gap-width": { 740 | "base": 1.55, 741 | "stops": [ 742 | [4, 0.25], 743 | [20, 30] 744 | ] 745 | }, 746 | "line-width": { 747 | "base": 1.6, 748 | "stops": [ 749 | [12, 0.5], 750 | [20, 10] 751 | ] 752 | } 753 | }, 754 | "source": "openmaptiles", 755 | "source-layer": "transportation", 756 | "type": "line" 757 | }, { 758 | "filter": ["all", ["==", "$type", "LineString"], 759 | ["==", "brunnel", "bridge"], 760 | ["==", "class", "minor_road"] 761 | ], 762 | "id": "bridge_minor", 763 | "layout": { 764 | "line-cap": "round", 765 | "line-join": "round" 766 | }, 767 | "paint": { 768 | "line-color": "#efefef", 769 | "line-width": { 770 | "base": 1.55, 771 | "stops": [ 772 | [4, 0.25], 773 | [20, 30] 774 | ] 775 | } 776 | }, 777 | "source": "openmaptiles", 778 | "source-layer": "transportation", 779 | "type": "line" 780 | }, { 781 | "filter": ["all", ["==", "$type", "LineString"], 782 | ["==", "brunnel", "bridge"], 783 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 784 | ], 785 | "id": "bridge_major", 786 | "layout": { 787 | "line-cap": "round", 788 | "line-join": "round" 789 | }, 790 | "paint": { 791 | "line-color": "#fff", 792 | "line-width": { 793 | "base": 1.4, 794 | "stops": [ 795 | [6, 0.5], 796 | [20, 30] 797 | ] 798 | } 799 | }, 800 | "source": "openmaptiles", 801 | "source-layer": "transportation", 802 | "type": "line" 803 | }, { 804 | "filter": ["in", "admin_level", 4, 6, 8], 805 | "id": "admin_sub", 806 | "layout": { 807 | "visibility": "visible" 808 | }, 809 | "paint": { 810 | "line-color": "hsla(0, 0%, 60%, 0.5)", 811 | "line-dasharray": [2, 1] 812 | }, 813 | "source": "openmaptiles", 814 | "source-layer": "boundary", 815 | "type": "line" 816 | }, { 817 | "filter": ["all", ["<=", "admin_level", 2], 818 | ["==", "$type", "LineString"] 819 | ], 820 | "id": "admin_country", 821 | "layout": { 822 | "line-cap": "round", 823 | "line-join": "round" 824 | }, 825 | "paint": { 826 | "line-color": "hsl(0, 0%, 60%)", 827 | "line-width": { 828 | "base": 1.3, 829 | "stops": [ 830 | [3, 0.5], 831 | [22, 15] 832 | ] 833 | } 834 | }, 835 | "source": "openmaptiles", 836 | "source-layer": "boundary", 837 | "type": "line" 838 | }, { 839 | "filter": ["all", ["==", "$type", "Point"], 840 | ["==", "rank", 1] 841 | ], 842 | "id": "poi_label", 843 | "layout": { 844 | "icon-size": 1, 845 | "text-anchor": "top", 846 | "text-field": "{name:latin}\n{name:nonlatin}", 847 | "text-font": ["Noto Sans Regular"], 848 | "text-max-width": 8, 849 | "text-offset": [0, 0.5], 850 | "text-size": 11, 851 | "visibility": "visible" 852 | }, 853 | "minzoom": 14, 854 | "paint": { 855 | "text-color": "#666", 856 | "text-halo-blur": 1, 857 | "text-halo-color": "rgba(255,255,255,0.75)", 858 | "text-halo-width": 1 859 | }, 860 | "source": "openmaptiles", 861 | "source-layer": "poi", 862 | "type": "symbol" 863 | }, { 864 | "filter": ["all", ["has", "iata"]], 865 | "id": "airport-label", 866 | "layout": { 867 | "icon-size": 1, 868 | "text-anchor": "top", 869 | "text-field": "{name:latin}\n{name:nonlatin}", 870 | "text-font": ["Noto Sans Regular"], 871 | "text-max-width": 8, 872 | "text-offset": [0, 0.5], 873 | "text-size": 11, 874 | "visibility": "visible" 875 | }, 876 | "minzoom": 10, 877 | "paint": { 878 | "text-color": "#666", 879 | "text-halo-blur": 1, 880 | "text-halo-color": "rgba(255,255,255,0.75)", 881 | "text-halo-width": 1 882 | }, 883 | "source": "openmaptiles", 884 | "source-layer": "aerodrome_label", 885 | "type": "symbol" 886 | }, { 887 | "filter": ["==", "$type", "LineString"], 888 | "id": "road_major_label", 889 | "layout": { 890 | "symbol-placement": "line", 891 | "text-field": "{name:latin} {name:nonlatin}", 892 | "text-font": ["Noto Sans Regular"], 893 | "text-letter-spacing": 0.1, 894 | "text-rotation-alignment": "map", 895 | "text-size": { 896 | "base": 1.4, 897 | "stops": [ 898 | [10, 8], 899 | [20, 14] 900 | ] 901 | }, 902 | "text-transform": "uppercase" 903 | }, 904 | "paint": { 905 | "text-color": "#000", 906 | "text-halo-color": "hsl(0, 0%, 100%)", 907 | "text-halo-width": 2 908 | }, 909 | "source": "openmaptiles", 910 | "source-layer": "transportation_name", 911 | "type": "symbol" 912 | }, { 913 | "filter": ["all", ["==", "$type", "Point"], 914 | ["!in", "class", "city", "state", "country", "continent"] 915 | ], 916 | "id": "place_label_other", 917 | "layout": { 918 | "text-anchor": "center", 919 | "text-field": "{name:latin}\n{name:nonlatin}", 920 | "text-font": ["Noto Sans Regular"], 921 | "text-max-width": 6, 922 | "text-size": { 923 | "stops": [ 924 | [6, 10], 925 | [12, 14] 926 | ] 927 | }, 928 | "visibility": "visible" 929 | }, 930 | "minzoom": 8, 931 | "paint": { 932 | "text-color": "hsl(0, 0%, 25%)", 933 | "text-halo-blur": 0, 934 | "text-halo-color": "hsl(0, 0%, 100%)", 935 | "text-halo-width": 2 936 | }, 937 | "source": "openmaptiles", 938 | "source-layer": "place", 939 | "type": "symbol" 940 | }, { 941 | "filter": ["all", ["==", "$type", "Point"], 942 | ["==", "class", "city"] 943 | ], 944 | "id": "place_label_city", 945 | "layout": { 946 | "text-field": "{name:latin}\n{name:nonlatin}", 947 | "text-font": ["Noto Sans Regular"], 948 | "text-max-width": 10, 949 | "text-size": { 950 | "stops": [ 951 | [3, 12], 952 | [8, 16] 953 | ] 954 | } 955 | }, 956 | "maxzoom": 16, 957 | "paint": { 958 | "text-color": "hsl(0, 0%, 0%)", 959 | "text-halo-blur": 0, 960 | "text-halo-color": "hsla(0, 0%, 100%, 0.75)", 961 | "text-halo-width": 2 962 | }, 963 | "source": "openmaptiles", 964 | "source-layer": "place", 965 | "type": "symbol" 966 | }, { 967 | "filter": ["all", ["==", "$type", "Point"], 968 | ["==", "class", "country"], 969 | ["!has", "iso_a2"] 970 | ], 971 | "id": "country_label-other", 972 | "layout": { 973 | "text-field": "{name:latin}", 974 | "text-font": ["Noto Sans Regular"], 975 | "text-max-width": 10, 976 | "text-size": { 977 | "stops": [ 978 | [3, 12], 979 | [8, 22] 980 | ] 981 | }, 982 | "visibility": "visible" 983 | }, 984 | "maxzoom": 12, 985 | "paint": { 986 | "text-color": "hsl(0, 0%, 13%)", 987 | "text-halo-blur": 0, 988 | "text-halo-color": "rgba(255,255,255,0.75)", 989 | "text-halo-width": 2 990 | }, 991 | "source": "openmaptiles", 992 | "source-layer": "place", 993 | "type": "symbol" 994 | }, { 995 | "filter": ["all", ["==", "$type", "Point"], 996 | ["==", "class", "country"], 997 | ["has", "iso_a2"] 998 | ], 999 | "id": "country_label", 1000 | "layout": { 1001 | "text-field": "{name:latin}", 1002 | "text-font": ["Noto Sans Bold"], 1003 | "text-max-width": 10, 1004 | "text-size": { 1005 | "stops": [ 1006 | [3, 12], 1007 | [8, 22] 1008 | ] 1009 | }, 1010 | "visibility": "visible" 1011 | }, 1012 | "maxzoom": 12, 1013 | "paint": { 1014 | "text-color": "hsl(0, 0%, 13%)", 1015 | "text-halo-blur": 0, 1016 | "text-halo-color": "rgba(255,255,255,0.75)", 1017 | "text-halo-width": 2 1018 | }, 1019 | "source": "openmaptiles", 1020 | "source-layer": "place", 1021 | "type": "symbol" 1022 | },{ 1023 | "id": "states", 1024 | "type": "line", 1025 | "source": "states", 1026 | "source-layer": "states", 1027 | "layout": { 1028 | "visibility": "visible" 1029 | }, 1030 | "paint": { 1031 | "line-width": 2, 1032 | "line-color": "red", 1033 | "line-opacity": 1 1034 | } 1035 | }], 1036 | "id": "basic" 1037 | } 1038 | -------------------------------------------------------------------------------- /examples/geojson/main.js: -------------------------------------------------------------------------------- 1 | import * as yawgl from "yawgl"; 2 | import * as d3 from "d3"; 3 | import * as tileMap from "../../"; 4 | 5 | export function main() { 6 | const canvas = document.getElementById("mapCanvas"); 7 | yawgl.resizeCanvasToDisplaySize(canvas, window.devicePixelRatio); 8 | const context = yawgl.initContext(canvas); 9 | 10 | tileMap.init({ 11 | context, 12 | center: [0, 30], 13 | zoom: 2, 14 | style: "klokantech-basic-style-geojson-sampler.json", 15 | }).promise.then(api => setup(api, canvas)) 16 | .catch(console.log); 17 | } 18 | 19 | function setup(api, canvas) { 20 | const viewport = api.getViewport(); 21 | 22 | const { k, x, y } = api.getTransform(); 23 | let transform = d3.zoomIdentity 24 | .translate(x, y) 25 | .scale(k); 26 | 27 | const zoomer = d3.zoom() 28 | .scaleExtent([1 << 10, 1 << 26]) 29 | .extent([[0, 0], viewport]) 30 | .translateExtent([[-Infinity, -0.5], [Infinity, 0.5]]) 31 | .on("zoom", (event) => { 32 | transform = event.transform; 33 | }); 34 | 35 | d3.select(canvas) 36 | .call(zoomer) 37 | .call(zoomer.transform, transform); 38 | 39 | const loadStatus = document.getElementById("loadStatus"); 40 | 41 | requestAnimationFrame(animate); 42 | function animate() { 43 | const pixRatio = window.devicePixelRatio; 44 | yawgl.resizeCanvasToDisplaySize(canvas, pixRatio); 45 | api.setTransform(transform); 46 | const percent = api.draw({ pixRatio }) * 100; 47 | loadStatus.innerHTML = (percent < 100) 48 | ? "Loading: " + percent.toFixed(0) + "%" 49 | : "Complete! " + percent.toFixed(0) + "%"; 50 | 51 | requestAnimationFrame(animate); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/geojson/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | border: 0; 6 | margin: 0; 7 | font-family: "Noto Sans"; 8 | font-size: 14px; 9 | } 10 | #main { 11 | width: 100%; 12 | height: 100vh; 13 | position: relative; 14 | } 15 | #mapCanvas { 16 | width: 100%; 17 | height: 100%; 18 | display: block; 19 | background-color: gray; 20 | position: relative; 21 | } 22 | .attribution { 23 | background: rgba(255, 255, 255, 0.8); 24 | position: absolute; 25 | bottom: 0; 26 | right: 0; 27 | padding: 0 4px 0 4px; 28 | } 29 | #loadStatus { 30 | position: absolute; 31 | top: 0; 32 | right: 0; 33 | width: 15ch; 34 | text-align: right; 35 | background: rgba(60, 60, 60, 0.5); 36 | color: white; 37 | padding: 0 4px 0 4px; 38 | } 39 | -------------------------------------------------------------------------------- /examples/klokan-basic/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 🌎 3 | 4 | -------------------------------------------------------------------------------- /examples/klokan-basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tile-setter - beta 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/klokan-basic/klokan-fill-line.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "name": "Basic", 4 | "metadata": { 5 | "mapbox:autocomposite": false, 6 | "mapbox:type": "template", 7 | "maputnik:renderer": "mbgljs", 8 | "openmaptiles:version": "3.x", 9 | "openmaptiles:mapbox:owner": "openmaptiles", 10 | "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t" 11 | }, 12 | "sources": { 13 | "openmaptiles": { 14 | "type": "vector", 15 | "url": "https://api.maptiler.com/tiles/v3/tiles.json?key=mrAq6zQEFxOkanukNbGm" 16 | } 17 | }, 18 | "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=mrAq6zQEFxOkanukNbGm", 19 | "layers": [{ 20 | "id": "background", 21 | "paint": { 22 | "background-color": "hsl(47, 26%, 88%)" 23 | }, 24 | "type": "background" 25 | }, { 26 | "filter": ["all", ["==", "$type", "Polygon"], 27 | ["in", "class", "residential", "suburb", "neighbourhood"] 28 | ], 29 | "id": "landuse-residential", 30 | "layout": { 31 | "visibility": "visible" 32 | }, 33 | "paint": { 34 | "fill-color": "hsl(47, 13%, 86%)", 35 | "fill-opacity": 0.7 36 | }, 37 | "source": "openmaptiles", 38 | "source-layer": "landuse", 39 | "type": "fill" 40 | }, { 41 | "filter": ["==", "class", "grass"], 42 | "id": "landcover_grass", 43 | "paint": { 44 | "fill-color": "hsl(82, 46%, 72%)", 45 | "fill-opacity": 0.45 46 | }, 47 | "source": "openmaptiles", 48 | "source-layer": "landcover", 49 | "type": "fill" 50 | }, { 51 | "filter": ["==", "class", "wood"], 52 | "id": "landcover_wood", 53 | "paint": { 54 | "fill-color": "hsl(82, 46%, 72%)", 55 | "fill-opacity": { 56 | "base": 1, 57 | "stops": [ 58 | [8, 0.6], 59 | [22, 1] 60 | ] 61 | } 62 | }, 63 | "source": "openmaptiles", 64 | "source-layer": "landcover", 65 | "type": "fill" 66 | }, { 67 | "filter": ["all", ["==", "$type", "Polygon"], 68 | ["!=", "intermittent", 1] 69 | ], 70 | "id": "water", 71 | "paint": { 72 | "fill-color": "hsl(205, 56%, 73%)" 73 | }, 74 | "source": "openmaptiles", 75 | "source-layer": "water", 76 | "type": "fill", 77 | "layout": { 78 | "visibility": "visible" 79 | } 80 | }, { 81 | "filter": ["all", ["==", "$type", "Polygon"], 82 | ["==", "intermittent", 1] 83 | ], 84 | "id": "water_intermittent", 85 | "paint": { 86 | "fill-color": "hsl(205, 56%, 73%)", 87 | "fill-opacity": 0.7 88 | }, 89 | "source": "openmaptiles", 90 | "source-layer": "water", 91 | "type": "fill", 92 | "layout": { 93 | "visibility": "visible" 94 | } 95 | }, { 96 | "filter": ["==", "subclass", "ice_shelf"], 97 | "id": "landcover-ice-shelf", 98 | "layout": { 99 | "visibility": "visible" 100 | }, 101 | "paint": { 102 | "fill-color": "hsl(47, 26%, 88%)", 103 | "fill-opacity": 0.8 104 | }, 105 | "source": "openmaptiles", 106 | "source-layer": "landcover", 107 | "type": "fill" 108 | }, { 109 | "filter": ["==", "subclass", "glacier"], 110 | "id": "landcover-glacier", 111 | "layout": { 112 | "visibility": "visible" 113 | }, 114 | "paint": { 115 | "fill-color": "hsl(47, 22%, 94%)", 116 | "fill-opacity": { 117 | "base": 1, 118 | "stops": [ 119 | [0, 1], 120 | [8, 0.5] 121 | ] 122 | } 123 | }, 124 | "source": "openmaptiles", 125 | "source-layer": "landcover", 126 | "type": "fill" 127 | }, { 128 | "filter": ["all", ["in", "class", "sand"]], 129 | "id": "landcover_sand", 130 | "metadata": {}, 131 | "paint": { 132 | "fill-antialias": false, 133 | "fill-color": "rgba(232, 214, 38, 1)", 134 | "fill-opacity": 0.3 135 | }, 136 | "source": "openmaptiles", 137 | "source-layer": "landcover", 138 | "type": "fill" 139 | }, { 140 | "filter": ["==", "class", "agriculture"], 141 | "id": "landuse", 142 | "layout": { 143 | "visibility": "visible" 144 | }, 145 | "paint": { 146 | "fill-color": "#eae0d0" 147 | }, 148 | "source": "openmaptiles", 149 | "source-layer": "landuse", 150 | "type": "fill" 151 | }, { 152 | "filter": ["==", "class", "national_park"], 153 | "id": "landuse_overlay_national_park", 154 | "paint": { 155 | "fill-color": "#E1EBB0", 156 | "fill-opacity": { 157 | "base": 1, 158 | "stops": [ 159 | [5, 0], 160 | [9, 0.75] 161 | ] 162 | } 163 | }, 164 | "source": "openmaptiles", 165 | "source-layer": "landcover", 166 | "type": "fill" 167 | }, { 168 | "filter": ["all", ["==", "$type", "LineString"], 169 | ["==", "brunnel", "tunnel"] 170 | ], 171 | "id": "waterway-tunnel", 172 | "paint": { 173 | "line-color": "hsl(205, 56%, 73%)", 174 | "line-dasharray": [3, 3], 175 | "line-gap-width": { 176 | "stops": [ 177 | [12, 0], 178 | [20, 6] 179 | ] 180 | }, 181 | "line-opacity": 1, 182 | "line-width": { 183 | "base": 1.4, 184 | "stops": [ 185 | [8, 1], 186 | [20, 2] 187 | ] 188 | } 189 | }, 190 | "source": "openmaptiles", 191 | "source-layer": "waterway", 192 | "type": "line", 193 | "layout": { 194 | "visibility": "visible" 195 | } 196 | }, { 197 | "filter": ["all", ["==", "$type", "LineString"], 198 | ["!in", "brunnel", "tunnel", "bridge"], 199 | ["!=", "intermittent", 1] 200 | ], 201 | "id": "waterway", 202 | "paint": { 203 | "line-color": "hsl(205, 56%, 73%)", 204 | "line-opacity": 1, 205 | "line-width": { 206 | "base": 1.4, 207 | "stops": [ 208 | [8, 1], 209 | [20, 8] 210 | ] 211 | } 212 | }, 213 | "source": "openmaptiles", 214 | "source-layer": "waterway", 215 | "type": "line", 216 | "layout": { 217 | "visibility": "visible" 218 | } 219 | }, { 220 | "filter": ["all", ["==", "$type", "LineString"], 221 | ["!in", "brunnel", "tunnel", "bridge"], 222 | ["==", "intermittent", 1] 223 | ], 224 | "id": "waterway_intermittent", 225 | "paint": { 226 | "line-color": "hsl(205, 56%, 73%)", 227 | "line-opacity": 1, 228 | "line-width": { 229 | "base": 1.4, 230 | "stops": [ 231 | [8, 1], 232 | [20, 8] 233 | ] 234 | }, 235 | "line-dasharray": [2, 1] 236 | }, 237 | "source": "openmaptiles", 238 | "source-layer": "waterway", 239 | "type": "line", 240 | "layout": { 241 | "visibility": "visible" 242 | } 243 | }, { 244 | "filter": ["all", ["==", "$type", "LineString"], 245 | ["==", "brunnel", "tunnel"], 246 | ["==", "class", "transit"] 247 | ], 248 | "id": "tunnel_railway_transit", 249 | "layout": { 250 | "line-cap": "butt", 251 | "line-join": "miter" 252 | }, 253 | "minzoom": 0, 254 | "paint": { 255 | "line-color": "hsl(34, 12%, 66%)", 256 | "line-dasharray": [3, 3], 257 | "line-opacity": { 258 | "base": 1, 259 | "stops": [ 260 | [11, 0], 261 | [16, 1] 262 | ] 263 | } 264 | }, 265 | "source": "openmaptiles", 266 | "source-layer": "transportation", 267 | "type": "line" 268 | }, { 269 | "id": "building", 270 | "paint": { 271 | "fill-antialias": true, 272 | "fill-color": "rgba(222, 211, 190, 1)", 273 | "fill-opacity": { 274 | "base": 1, 275 | "stops": [ 276 | [13, 0], 277 | [15, 1] 278 | ] 279 | }, 280 | "fill-outline-color": { 281 | "stops": [ 282 | [15, "rgba(212, 177, 146, 0)"], 283 | [16, "rgba(212, 177, 146, 0.5)"] 284 | ] 285 | } 286 | }, 287 | "source": "openmaptiles", 288 | "source-layer": "building", 289 | "type": "fill" 290 | }, { 291 | "id": "road_area_pier", 292 | "type": "fill", 293 | "metadata": {}, 294 | "source": "openmaptiles", 295 | "source-layer": "transportation", 296 | "filter": ["all", ["==", "$type", "Polygon"], 297 | ["==", "class", "pier"] 298 | ], 299 | "layout": { 300 | "visibility": "visible" 301 | }, 302 | "paint": { 303 | "fill-color": "hsl(47, 26%, 88%)", 304 | "fill-antialias": true 305 | } 306 | }, { 307 | "id": "road_pier", 308 | "type": "line", 309 | "metadata": {}, 310 | "source": "openmaptiles", 311 | "source-layer": "transportation", 312 | "filter": ["all", ["==", "$type", "LineString"], 313 | ["in", "class", "pier"] 314 | ], 315 | "layout": { 316 | "line-cap": "round", 317 | "line-join": "round" 318 | }, 319 | "paint": { 320 | "line-color": "hsl(47, 26%, 88%)", 321 | "line-width": { 322 | "base": 1.2, 323 | "stops": [ 324 | [15, 1], 325 | [17, 4] 326 | ] 327 | } 328 | } 329 | }, { 330 | "filter": ["all", ["==", "$type", "Polygon"], 331 | ["in", "brunnel", "bridge"] 332 | ], 333 | "id": "road_bridge_area", 334 | "layout": {}, 335 | "paint": { 336 | "fill-color": "hsl(47, 26%, 88%)", 337 | "fill-opacity": 0.5 338 | }, 339 | "source": "openmaptiles", 340 | "source-layer": "transportation", 341 | "type": "fill" 342 | }, { 343 | "filter": ["all", ["==", "$type", "LineString"], 344 | ["in", "class", "path", "track"] 345 | ], 346 | "id": "road_path", 347 | "layout": { 348 | "line-cap": "square", 349 | "line-join": "bevel" 350 | }, 351 | "paint": { 352 | "line-color": "hsl(0, 0%, 97%)", 353 | "line-dasharray": [1, 1], 354 | "line-width": { 355 | "base": 1.55, 356 | "stops": [ 357 | [4, 0.25], 358 | [20, 10] 359 | ] 360 | } 361 | }, 362 | "source": "openmaptiles", 363 | "source-layer": "transportation", 364 | "type": "line" 365 | }, { 366 | "filter": ["all", ["==", "$type", "LineString"], 367 | ["in", "class", "minor", "service"] 368 | ], 369 | "id": "road_minor", 370 | "layout": { 371 | "line-cap": "round", 372 | "line-join": "round" 373 | }, 374 | "paint": { 375 | "line-color": "hsl(0, 0%, 97%)", 376 | "line-width": { 377 | "base": 1.55, 378 | "stops": [ 379 | [4, 0.25], 380 | [20, 30] 381 | ] 382 | } 383 | }, 384 | "source": "openmaptiles", 385 | "source-layer": "transportation", 386 | "type": "line", 387 | "minzoom": 13 388 | }, { 389 | "filter": ["all", ["==", "$type", "LineString"], 390 | ["==", "brunnel", "tunnel"], 391 | ["==", "class", "minor_road"] 392 | ], 393 | "id": "tunnel_minor", 394 | "layout": { 395 | "line-cap": "butt", 396 | "line-join": "miter" 397 | }, 398 | "paint": { 399 | "line-color": "#efefef", 400 | "line-dasharray": [0.36, 0.18], 401 | "line-width": { 402 | "base": 1.55, 403 | "stops": [ 404 | [4, 0.25], 405 | [20, 30] 406 | ] 407 | } 408 | }, 409 | "source": "openmaptiles", 410 | "source-layer": "transportation", 411 | "type": "line" 412 | }, { 413 | "filter": ["all", ["==", "$type", "LineString"], 414 | ["==", "brunnel", "tunnel"], 415 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 416 | ], 417 | "id": "tunnel_major", 418 | "layout": { 419 | "line-cap": "butt", 420 | "line-join": "miter" 421 | }, 422 | "paint": { 423 | "line-color": "#fff", 424 | "line-dasharray": [0.28, 0.14], 425 | "line-width": { 426 | "base": 1.4, 427 | "stops": [ 428 | [6, 0.5], 429 | [20, 30] 430 | ] 431 | } 432 | }, 433 | "source": "openmaptiles", 434 | "source-layer": "transportation", 435 | "type": "line" 436 | }, { 437 | "filter": ["all", ["==", "$type", "Polygon"], 438 | ["in", "class", "runway", "taxiway"] 439 | ], 440 | "id": "aeroway-area", 441 | "layout": { 442 | "visibility": "visible" 443 | }, 444 | "metadata": { 445 | "mapbox:group": "1444849345966.4436" 446 | }, 447 | "minzoom": 4, 448 | "paint": { 449 | "fill-color": "rgba(255, 255, 255, 1)", 450 | "fill-opacity": { 451 | "base": 1, 452 | "stops": [ 453 | [13, 0], 454 | [14, 1] 455 | ] 456 | } 457 | }, 458 | "source": "openmaptiles", 459 | "source-layer": "aeroway", 460 | "type": "fill" 461 | }, { 462 | "filter": ["all", ["in", "class", "taxiway"], 463 | ["==", "$type", "LineString"] 464 | ], 465 | "id": "aeroway-taxiway", 466 | "layout": { 467 | "line-cap": "round", 468 | "line-join": "round", 469 | "visibility": "visible" 470 | }, 471 | "metadata": { 472 | "mapbox:group": "1444849345966.4436" 473 | }, 474 | "minzoom": 12, 475 | "paint": { 476 | "line-color": "rgba(255, 255, 255, 1)", 477 | "line-opacity": 1, 478 | "line-width": { 479 | "base": 1.5, 480 | "stops": [ 481 | [12, 1], 482 | [17, 10] 483 | ] 484 | } 485 | }, 486 | "source": "openmaptiles", 487 | "source-layer": "aeroway", 488 | "type": "line" 489 | }, { 490 | "filter": ["all", ["in", "class", "runway"], 491 | ["==", "$type", "LineString"] 492 | ], 493 | "id": "aeroway-runway", 494 | "layout": { 495 | "line-cap": "round", 496 | "line-join": "round", 497 | "visibility": "visible" 498 | }, 499 | "metadata": { 500 | "mapbox:group": "1444849345966.4436" 501 | }, 502 | "minzoom": 4, 503 | "paint": { 504 | "line-color": "rgba(255, 255, 255, 1)", 505 | "line-opacity": 1, 506 | "line-width": { 507 | "base": 1.5, 508 | "stops": [ 509 | [11, 4], 510 | [17, 50] 511 | ] 512 | } 513 | }, 514 | "source": "openmaptiles", 515 | "source-layer": "aeroway", 516 | "type": "line" 517 | }, { 518 | "filter": ["all", ["==", "$type", "LineString"], 519 | ["in", "class", "trunk", "primary"] 520 | ], 521 | "id": "road_trunk_primary", 522 | "layout": { 523 | "line-cap": "round", 524 | "line-join": "round" 525 | }, 526 | "paint": { 527 | "line-color": "#fff", 528 | "line-width": { 529 | "base": 1.4, 530 | "stops": [ 531 | [6, 0.5], 532 | [20, 30] 533 | ] 534 | } 535 | }, 536 | "source": "openmaptiles", 537 | "source-layer": "transportation", 538 | "type": "line" 539 | }, { 540 | "filter": ["all", ["==", "$type", "LineString"], 541 | ["in", "class", "secondary", "tertiary"] 542 | ], 543 | "id": "road_secondary_tertiary", 544 | "layout": { 545 | "line-cap": "round", 546 | "line-join": "round" 547 | }, 548 | "paint": { 549 | "line-color": "#fff", 550 | "line-width": { 551 | "base": 1.4, 552 | "stops": [ 553 | [6, 0.5], 554 | [20, 20] 555 | ] 556 | } 557 | }, 558 | "source": "openmaptiles", 559 | "source-layer": "transportation", 560 | "type": "line" 561 | }, { 562 | "filter": ["all", ["==", "$type", "LineString"], 563 | ["==", "class", "motorway"] 564 | ], 565 | "id": "road_major_motorway", 566 | "layout": { 567 | "line-cap": "round", 568 | "line-join": "round" 569 | }, 570 | "paint": { 571 | "line-color": "hsl(0, 0%, 100%)", 572 | "line-offset": 0, 573 | "line-width": { 574 | "base": 1.4, 575 | "stops": [ 576 | [8, 1], 577 | [16, 10] 578 | ] 579 | } 580 | }, 581 | "source": "openmaptiles", 582 | "source-layer": "transportation", 583 | "type": "line" 584 | }, { 585 | "filter": ["all", ["==", "class", "transit"], 586 | ["!=", "brunnel", "tunnel"] 587 | ], 588 | "id": "railway-transit", 589 | "layout": { 590 | "visibility": "visible" 591 | }, 592 | "paint": { 593 | "line-color": "hsl(34, 12%, 66%)", 594 | "line-opacity": { 595 | "base": 1, 596 | "stops": [ 597 | [11, 0], 598 | [16, 1] 599 | ] 600 | } 601 | }, 602 | "source": "openmaptiles", 603 | "source-layer": "transportation", 604 | "type": "line" 605 | }, { 606 | "filter": ["==", "class", "rail"], 607 | "id": "railway", 608 | "layout": { 609 | "visibility": "visible" 610 | }, 611 | "paint": { 612 | "line-color": "hsl(34, 12%, 66%)", 613 | "line-opacity": { 614 | "base": 1, 615 | "stops": [ 616 | [11, 0], 617 | [16, 1] 618 | ] 619 | } 620 | }, 621 | "source": "openmaptiles", 622 | "source-layer": "transportation", 623 | "type": "line" 624 | }, { 625 | "filter": ["all", ["==", "$type", "LineString"], 626 | ["==", "brunnel", "bridge"] 627 | ], 628 | "id": "waterway-bridge-case", 629 | "layout": { 630 | "line-cap": "butt", 631 | "line-join": "miter" 632 | }, 633 | "paint": { 634 | "line-color": "#bbbbbb", 635 | "line-gap-width": { 636 | "base": 1.55, 637 | "stops": [ 638 | [4, 0.25], 639 | [20, 30] 640 | ] 641 | }, 642 | "line-width": { 643 | "base": 1.6, 644 | "stops": [ 645 | [12, 0.5], 646 | [20, 10] 647 | ] 648 | } 649 | }, 650 | "source": "openmaptiles", 651 | "source-layer": "waterway", 652 | "type": "line" 653 | }, { 654 | "filter": ["all", ["==", "$type", "LineString"], 655 | ["==", "brunnel", "bridge"] 656 | ], 657 | "id": "waterway-bridge", 658 | "layout": { 659 | "line-cap": "round", 660 | "line-join": "round" 661 | }, 662 | "paint": { 663 | "line-color": "hsl(205, 56%, 73%)", 664 | "line-width": { 665 | "base": 1.55, 666 | "stops": [ 667 | [4, 0.25], 668 | [20, 30] 669 | ] 670 | } 671 | }, 672 | "source": "openmaptiles", 673 | "source-layer": "waterway", 674 | "type": "line" 675 | }, { 676 | "filter": ["all", ["==", "$type", "LineString"], 677 | ["==", "brunnel", "bridge"], 678 | ["==", "class", "minor_road"] 679 | ], 680 | "id": "bridge_minor case", 681 | "layout": { 682 | "line-cap": "butt", 683 | "line-join": "miter" 684 | }, 685 | "paint": { 686 | "line-color": "#dedede", 687 | "line-gap-width": { 688 | "base": 1.55, 689 | "stops": [ 690 | [4, 0.25], 691 | [20, 30] 692 | ] 693 | }, 694 | "line-width": { 695 | "base": 1.6, 696 | "stops": [ 697 | [12, 0.5], 698 | [20, 10] 699 | ] 700 | } 701 | }, 702 | "source": "openmaptiles", 703 | "source-layer": "transportation", 704 | "type": "line" 705 | }, { 706 | "filter": ["all", ["==", "$type", "LineString"], 707 | ["==", "brunnel", "bridge"], 708 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 709 | ], 710 | "id": "bridge_major case", 711 | "layout": { 712 | "line-cap": "butt", 713 | "line-join": "miter" 714 | }, 715 | "paint": { 716 | "line-color": "#dedede", 717 | "line-gap-width": { 718 | "base": 1.55, 719 | "stops": [ 720 | [4, 0.25], 721 | [20, 30] 722 | ] 723 | }, 724 | "line-width": { 725 | "base": 1.6, 726 | "stops": [ 727 | [12, 0.5], 728 | [20, 10] 729 | ] 730 | } 731 | }, 732 | "source": "openmaptiles", 733 | "source-layer": "transportation", 734 | "type": "line" 735 | }, { 736 | "filter": ["all", ["==", "$type", "LineString"], 737 | ["==", "brunnel", "bridge"], 738 | ["==", "class", "minor_road"] 739 | ], 740 | "id": "bridge_minor", 741 | "layout": { 742 | "line-cap": "round", 743 | "line-join": "round" 744 | }, 745 | "paint": { 746 | "line-color": "#efefef", 747 | "line-width": { 748 | "base": 1.55, 749 | "stops": [ 750 | [4, 0.25], 751 | [20, 30] 752 | ] 753 | } 754 | }, 755 | "source": "openmaptiles", 756 | "source-layer": "transportation", 757 | "type": "line" 758 | }, { 759 | "filter": ["all", ["==", "$type", "LineString"], 760 | ["==", "brunnel", "bridge"], 761 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 762 | ], 763 | "id": "bridge_major", 764 | "layout": { 765 | "line-cap": "round", 766 | "line-join": "round" 767 | }, 768 | "paint": { 769 | "line-color": "#fff", 770 | "line-width": { 771 | "base": 1.4, 772 | "stops": [ 773 | [6, 0.5], 774 | [20, 30] 775 | ] 776 | } 777 | }, 778 | "source": "openmaptiles", 779 | "source-layer": "transportation", 780 | "type": "line" 781 | }, { 782 | "filter": ["in", "admin_level", 4, 6, 8], 783 | "id": "admin_sub", 784 | "layout": { 785 | "visibility": "visible" 786 | }, 787 | "paint": { 788 | "line-color": "hsla(0, 0%, 60%, 0.5)", 789 | "line-dasharray": [2, 1] 790 | }, 791 | "source": "openmaptiles", 792 | "source-layer": "boundary", 793 | "type": "line" 794 | }, { 795 | "filter": ["all", ["<=", "admin_level", 2], 796 | ["==", "$type", "LineString"] 797 | ], 798 | "id": "admin_country", 799 | "layout": { 800 | "line-cap": "round", 801 | "line-join": "round" 802 | }, 803 | "paint": { 804 | "line-color": "hsl(0, 0%, 60%)", 805 | "line-width": { 806 | "base": 1.3, 807 | "stops": [ 808 | [3, 0.5], 809 | [22, 15] 810 | ] 811 | } 812 | }, 813 | "source": "openmaptiles", 814 | "source-layer": "boundary", 815 | "type": "line" 816 | }], 817 | "id": "basic" 818 | } 819 | -------------------------------------------------------------------------------- /examples/klokan-basic/klokantech-basic-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "name": "Basic", 4 | "metadata": { 5 | "mapbox:autocomposite": false, 6 | "mapbox:type": "template", 7 | "maputnik:renderer": "mbgljs", 8 | "openmaptiles:version": "3.x", 9 | "openmaptiles:mapbox:owner": "openmaptiles", 10 | "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t" 11 | }, 12 | "sources": { 13 | "openmaptiles": { 14 | "type": "vector", 15 | "url": "https://api.maptiler.com/tiles/v3/tiles.json?key=mrAq6zQEFxOkanukNbGm" 16 | } 17 | }, 18 | "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=mrAq6zQEFxOkanukNbGm", 19 | "layers": [{ 20 | "id": "background", 21 | "paint": { 22 | "background-color": "hsl(47, 26%, 88%)" 23 | }, 24 | "type": "background" 25 | }, { 26 | "filter": ["all", ["==", "$type", "Polygon"], 27 | ["in", "class", "residential", "suburb", "neighbourhood"] 28 | ], 29 | "id": "landuse-residential", 30 | "layout": { 31 | "visibility": "visible" 32 | }, 33 | "paint": { 34 | "fill-color": "hsl(47, 13%, 86%)", 35 | "fill-opacity": 0.7 36 | }, 37 | "source": "openmaptiles", 38 | "source-layer": "landuse", 39 | "type": "fill" 40 | }, { 41 | "filter": ["==", "class", "grass"], 42 | "id": "landcover_grass", 43 | "paint": { 44 | "fill-color": "hsl(82, 46%, 72%)", 45 | "fill-opacity": 0.45 46 | }, 47 | "source": "openmaptiles", 48 | "source-layer": "landcover", 49 | "type": "fill" 50 | }, { 51 | "filter": ["==", "class", "wood"], 52 | "id": "landcover_wood", 53 | "paint": { 54 | "fill-color": "hsl(82, 46%, 72%)", 55 | "fill-opacity": { 56 | "base": 1, 57 | "stops": [ 58 | [8, 0.6], 59 | [22, 1] 60 | ] 61 | } 62 | }, 63 | "source": "openmaptiles", 64 | "source-layer": "landcover", 65 | "type": "fill" 66 | }, { 67 | "filter": ["all", ["==", "$type", "Polygon"], 68 | ["!=", "intermittent", 1] 69 | ], 70 | "id": "water", 71 | "paint": { 72 | "fill-color": "hsl(205, 56%, 73%)" 73 | }, 74 | "source": "openmaptiles", 75 | "source-layer": "water", 76 | "type": "fill", 77 | "layout": { 78 | "visibility": "visible" 79 | } 80 | }, { 81 | "filter": ["all", ["==", "$type", "Polygon"], 82 | ["==", "intermittent", 1] 83 | ], 84 | "id": "water_intermittent", 85 | "paint": { 86 | "fill-color": "hsl(205, 56%, 73%)", 87 | "fill-opacity": 0.7 88 | }, 89 | "source": "openmaptiles", 90 | "source-layer": "water", 91 | "type": "fill", 92 | "layout": { 93 | "visibility": "visible" 94 | } 95 | }, { 96 | "filter": ["==", "subclass", "ice_shelf"], 97 | "id": "landcover-ice-shelf", 98 | "layout": { 99 | "visibility": "visible" 100 | }, 101 | "paint": { 102 | "fill-color": "hsl(47, 26%, 88%)", 103 | "fill-opacity": 0.8 104 | }, 105 | "source": "openmaptiles", 106 | "source-layer": "landcover", 107 | "type": "fill" 108 | }, { 109 | "filter": ["==", "subclass", "glacier"], 110 | "id": "landcover-glacier", 111 | "layout": { 112 | "visibility": "visible" 113 | }, 114 | "paint": { 115 | "fill-color": "hsl(47, 22%, 94%)", 116 | "fill-opacity": { 117 | "base": 1, 118 | "stops": [ 119 | [0, 1], 120 | [8, 0.5] 121 | ] 122 | } 123 | }, 124 | "source": "openmaptiles", 125 | "source-layer": "landcover", 126 | "type": "fill" 127 | }, { 128 | "filter": ["all", ["in", "class", "sand"]], 129 | "id": "landcover_sand", 130 | "metadata": {}, 131 | "paint": { 132 | "fill-antialias": false, 133 | "fill-color": "rgba(232, 214, 38, 1)", 134 | "fill-opacity": 0.3 135 | }, 136 | "source": "openmaptiles", 137 | "source-layer": "landcover", 138 | "type": "fill" 139 | }, { 140 | "filter": ["==", "class", "agriculture"], 141 | "id": "landuse", 142 | "layout": { 143 | "visibility": "visible" 144 | }, 145 | "paint": { 146 | "fill-color": "#eae0d0" 147 | }, 148 | "source": "openmaptiles", 149 | "source-layer": "landuse", 150 | "type": "fill" 151 | }, { 152 | "filter": ["==", "class", "national_park"], 153 | "id": "landuse_overlay_national_park", 154 | "paint": { 155 | "fill-color": "#E1EBB0", 156 | "fill-opacity": { 157 | "base": 1, 158 | "stops": [ 159 | [5, 0], 160 | [9, 0.75] 161 | ] 162 | } 163 | }, 164 | "source": "openmaptiles", 165 | "source-layer": "landcover", 166 | "type": "fill" 167 | }, { 168 | "filter": ["all", ["==", "$type", "LineString"], 169 | ["==", "brunnel", "tunnel"] 170 | ], 171 | "id": "waterway-tunnel", 172 | "paint": { 173 | "line-color": "hsl(205, 56%, 73%)", 174 | "line-dasharray": [3, 3], 175 | "line-gap-width": { 176 | "stops": [ 177 | [12, 0], 178 | [20, 6] 179 | ] 180 | }, 181 | "line-opacity": 1, 182 | "line-width": { 183 | "base": 1.4, 184 | "stops": [ 185 | [8, 1], 186 | [20, 2] 187 | ] 188 | } 189 | }, 190 | "source": "openmaptiles", 191 | "source-layer": "waterway", 192 | "type": "line", 193 | "layout": { 194 | "visibility": "visible" 195 | } 196 | }, { 197 | "filter": ["all", ["==", "$type", "LineString"], 198 | ["!in", "brunnel", "tunnel", "bridge"], 199 | ["!=", "intermittent", 1] 200 | ], 201 | "id": "waterway", 202 | "paint": { 203 | "line-color": "hsl(205, 56%, 73%)", 204 | "line-opacity": 1, 205 | "line-width": { 206 | "base": 1.4, 207 | "stops": [ 208 | [8, 1], 209 | [20, 8] 210 | ] 211 | } 212 | }, 213 | "source": "openmaptiles", 214 | "source-layer": "waterway", 215 | "type": "line", 216 | "layout": { 217 | "visibility": "visible" 218 | } 219 | }, { 220 | "filter": ["all", ["==", "$type", "LineString"], 221 | ["!in", "brunnel", "tunnel", "bridge"], 222 | ["==", "intermittent", 1] 223 | ], 224 | "id": "waterway_intermittent", 225 | "paint": { 226 | "line-color": "hsl(205, 56%, 73%)", 227 | "line-opacity": 1, 228 | "line-width": { 229 | "base": 1.4, 230 | "stops": [ 231 | [8, 1], 232 | [20, 8] 233 | ] 234 | }, 235 | "line-dasharray": [2, 1] 236 | }, 237 | "source": "openmaptiles", 238 | "source-layer": "waterway", 239 | "type": "line", 240 | "layout": { 241 | "visibility": "visible" 242 | } 243 | }, { 244 | "filter": ["all", ["==", "$type", "LineString"], 245 | ["==", "brunnel", "tunnel"], 246 | ["==", "class", "transit"] 247 | ], 248 | "id": "tunnel_railway_transit", 249 | "layout": { 250 | "line-cap": "butt", 251 | "line-join": "miter" 252 | }, 253 | "minzoom": 0, 254 | "paint": { 255 | "line-color": "hsl(34, 12%, 66%)", 256 | "line-dasharray": [3, 3], 257 | "line-opacity": { 258 | "base": 1, 259 | "stops": [ 260 | [11, 0], 261 | [16, 1] 262 | ] 263 | } 264 | }, 265 | "source": "openmaptiles", 266 | "source-layer": "transportation", 267 | "type": "line" 268 | }, { 269 | "id": "building", 270 | "paint": { 271 | "fill-antialias": true, 272 | "fill-color": "rgba(222, 211, 190, 1)", 273 | "fill-opacity": { 274 | "base": 1, 275 | "stops": [ 276 | [13, 0], 277 | [15, 1] 278 | ] 279 | }, 280 | "fill-outline-color": { 281 | "stops": [ 282 | [15, "rgba(212, 177, 146, 0)"], 283 | [16, "rgba(212, 177, 146, 0.5)"] 284 | ] 285 | } 286 | }, 287 | "source": "openmaptiles", 288 | "source-layer": "building", 289 | "type": "fill" 290 | }, { 291 | "filter": ["==", "$type", "Point"], 292 | "id": "housenumber", 293 | "layout": { 294 | "text-field": "{housenumber}", 295 | "text-font": ["Noto Sans Regular"], 296 | "text-size": 10 297 | }, 298 | "minzoom": 17, 299 | "paint": { 300 | "text-color": "rgba(212, 177, 146, 1)" 301 | }, 302 | "source": "openmaptiles", 303 | "source-layer": "housenumber", 304 | "type": "symbol" 305 | }, { 306 | "id": "road_area_pier", 307 | "type": "fill", 308 | "metadata": {}, 309 | "source": "openmaptiles", 310 | "source-layer": "transportation", 311 | "filter": ["all", ["==", "$type", "Polygon"], 312 | ["==", "class", "pier"] 313 | ], 314 | "layout": { 315 | "visibility": "visible" 316 | }, 317 | "paint": { 318 | "fill-color": "hsl(47, 26%, 88%)", 319 | "fill-antialias": true 320 | } 321 | }, { 322 | "id": "road_pier", 323 | "type": "line", 324 | "metadata": {}, 325 | "source": "openmaptiles", 326 | "source-layer": "transportation", 327 | "filter": ["all", ["==", "$type", "LineString"], 328 | ["in", "class", "pier"] 329 | ], 330 | "layout": { 331 | "line-cap": "round", 332 | "line-join": "round" 333 | }, 334 | "paint": { 335 | "line-color": "hsl(47, 26%, 88%)", 336 | "line-width": { 337 | "base": 1.2, 338 | "stops": [ 339 | [15, 1], 340 | [17, 4] 341 | ] 342 | } 343 | } 344 | }, { 345 | "filter": ["all", ["==", "$type", "Polygon"], 346 | ["in", "brunnel", "bridge"] 347 | ], 348 | "id": "road_bridge_area", 349 | "layout": {}, 350 | "paint": { 351 | "fill-color": "hsl(47, 26%, 88%)", 352 | "fill-opacity": 0.5 353 | }, 354 | "source": "openmaptiles", 355 | "source-layer": "transportation", 356 | "type": "fill" 357 | }, { 358 | "filter": ["all", ["==", "$type", "LineString"], 359 | ["in", "class", "path", "track"] 360 | ], 361 | "id": "road_path", 362 | "layout": { 363 | "line-cap": "square", 364 | "line-join": "bevel" 365 | }, 366 | "paint": { 367 | "line-color": "hsl(0, 0%, 97%)", 368 | "line-dasharray": [1, 1], 369 | "line-width": { 370 | "base": 1.55, 371 | "stops": [ 372 | [4, 0.25], 373 | [20, 10] 374 | ] 375 | } 376 | }, 377 | "source": "openmaptiles", 378 | "source-layer": "transportation", 379 | "type": "line" 380 | }, { 381 | "filter": ["all", ["==", "$type", "LineString"], 382 | ["in", "class", "minor", "service"] 383 | ], 384 | "id": "road_minor", 385 | "layout": { 386 | "line-cap": "round", 387 | "line-join": "round" 388 | }, 389 | "paint": { 390 | "line-color": "hsl(0, 0%, 97%)", 391 | "line-width": { 392 | "base": 1.55, 393 | "stops": [ 394 | [4, 0.25], 395 | [20, 30] 396 | ] 397 | } 398 | }, 399 | "source": "openmaptiles", 400 | "source-layer": "transportation", 401 | "type": "line", 402 | "minzoom": 13 403 | }, { 404 | "filter": ["all", ["==", "$type", "LineString"], 405 | ["==", "brunnel", "tunnel"], 406 | ["==", "class", "minor_road"] 407 | ], 408 | "id": "tunnel_minor", 409 | "layout": { 410 | "line-cap": "butt", 411 | "line-join": "miter" 412 | }, 413 | "paint": { 414 | "line-color": "#efefef", 415 | "line-dasharray": [0.36, 0.18], 416 | "line-width": { 417 | "base": 1.55, 418 | "stops": [ 419 | [4, 0.25], 420 | [20, 30] 421 | ] 422 | } 423 | }, 424 | "source": "openmaptiles", 425 | "source-layer": "transportation", 426 | "type": "line" 427 | }, { 428 | "filter": ["all", ["==", "$type", "LineString"], 429 | ["==", "brunnel", "tunnel"], 430 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 431 | ], 432 | "id": "tunnel_major", 433 | "layout": { 434 | "line-cap": "butt", 435 | "line-join": "miter" 436 | }, 437 | "paint": { 438 | "line-color": "#fff", 439 | "line-dasharray": [0.28, 0.14], 440 | "line-width": { 441 | "base": 1.4, 442 | "stops": [ 443 | [6, 0.5], 444 | [20, 30] 445 | ] 446 | } 447 | }, 448 | "source": "openmaptiles", 449 | "source-layer": "transportation", 450 | "type": "line" 451 | }, { 452 | "filter": ["all", ["==", "$type", "Polygon"], 453 | ["in", "class", "runway", "taxiway"] 454 | ], 455 | "id": "aeroway-area", 456 | "layout": { 457 | "visibility": "visible" 458 | }, 459 | "metadata": { 460 | "mapbox:group": "1444849345966.4436" 461 | }, 462 | "minzoom": 4, 463 | "paint": { 464 | "fill-color": "rgba(255, 255, 255, 1)", 465 | "fill-opacity": { 466 | "base": 1, 467 | "stops": [ 468 | [13, 0], 469 | [14, 1] 470 | ] 471 | } 472 | }, 473 | "source": "openmaptiles", 474 | "source-layer": "aeroway", 475 | "type": "fill" 476 | }, { 477 | "filter": ["all", ["in", "class", "taxiway"], 478 | ["==", "$type", "LineString"] 479 | ], 480 | "id": "aeroway-taxiway", 481 | "layout": { 482 | "line-cap": "round", 483 | "line-join": "round", 484 | "visibility": "visible" 485 | }, 486 | "metadata": { 487 | "mapbox:group": "1444849345966.4436" 488 | }, 489 | "minzoom": 12, 490 | "paint": { 491 | "line-color": "rgba(255, 255, 255, 1)", 492 | "line-opacity": 1, 493 | "line-width": { 494 | "base": 1.5, 495 | "stops": [ 496 | [12, 1], 497 | [17, 10] 498 | ] 499 | } 500 | }, 501 | "source": "openmaptiles", 502 | "source-layer": "aeroway", 503 | "type": "line" 504 | }, { 505 | "filter": ["all", ["in", "class", "runway"], 506 | ["==", "$type", "LineString"] 507 | ], 508 | "id": "aeroway-runway", 509 | "layout": { 510 | "line-cap": "round", 511 | "line-join": "round", 512 | "visibility": "visible" 513 | }, 514 | "metadata": { 515 | "mapbox:group": "1444849345966.4436" 516 | }, 517 | "minzoom": 4, 518 | "paint": { 519 | "line-color": "rgba(255, 255, 255, 1)", 520 | "line-opacity": 1, 521 | "line-width": { 522 | "base": 1.5, 523 | "stops": [ 524 | [11, 4], 525 | [17, 50] 526 | ] 527 | } 528 | }, 529 | "source": "openmaptiles", 530 | "source-layer": "aeroway", 531 | "type": "line" 532 | }, { 533 | "filter": ["all", ["==", "$type", "LineString"], 534 | ["in", "class", "trunk", "primary"] 535 | ], 536 | "id": "road_trunk_primary", 537 | "layout": { 538 | "line-cap": "round", 539 | "line-join": "round" 540 | }, 541 | "paint": { 542 | "line-color": "#fff", 543 | "line-width": { 544 | "base": 1.4, 545 | "stops": [ 546 | [6, 0.5], 547 | [20, 30] 548 | ] 549 | } 550 | }, 551 | "source": "openmaptiles", 552 | "source-layer": "transportation", 553 | "type": "line" 554 | }, { 555 | "filter": ["all", ["==", "$type", "LineString"], 556 | ["in", "class", "secondary", "tertiary"] 557 | ], 558 | "id": "road_secondary_tertiary", 559 | "layout": { 560 | "line-cap": "round", 561 | "line-join": "round" 562 | }, 563 | "paint": { 564 | "line-color": "#fff", 565 | "line-width": { 566 | "base": 1.4, 567 | "stops": [ 568 | [6, 0.5], 569 | [20, 20] 570 | ] 571 | } 572 | }, 573 | "source": "openmaptiles", 574 | "source-layer": "transportation", 575 | "type": "line" 576 | }, { 577 | "filter": ["all", ["==", "$type", "LineString"], 578 | ["==", "class", "motorway"] 579 | ], 580 | "id": "road_major_motorway", 581 | "layout": { 582 | "line-cap": "round", 583 | "line-join": "round" 584 | }, 585 | "paint": { 586 | "line-color": "hsl(0, 0%, 100%)", 587 | "line-offset": 0, 588 | "line-width": { 589 | "base": 1.4, 590 | "stops": [ 591 | [8, 1], 592 | [16, 10] 593 | ] 594 | } 595 | }, 596 | "source": "openmaptiles", 597 | "source-layer": "transportation", 598 | "type": "line" 599 | }, { 600 | "filter": ["all", ["==", "class", "transit"], 601 | ["!=", "brunnel", "tunnel"] 602 | ], 603 | "id": "railway-transit", 604 | "layout": { 605 | "visibility": "visible" 606 | }, 607 | "paint": { 608 | "line-color": "hsl(34, 12%, 66%)", 609 | "line-opacity": { 610 | "base": 1, 611 | "stops": [ 612 | [11, 0], 613 | [16, 1] 614 | ] 615 | } 616 | }, 617 | "source": "openmaptiles", 618 | "source-layer": "transportation", 619 | "type": "line" 620 | }, { 621 | "filter": ["==", "class", "rail"], 622 | "id": "railway", 623 | "layout": { 624 | "visibility": "visible" 625 | }, 626 | "paint": { 627 | "line-color": "hsl(34, 12%, 66%)", 628 | "line-opacity": { 629 | "base": 1, 630 | "stops": [ 631 | [11, 0], 632 | [16, 1] 633 | ] 634 | } 635 | }, 636 | "source": "openmaptiles", 637 | "source-layer": "transportation", 638 | "type": "line" 639 | }, { 640 | "filter": ["all", ["==", "$type", "LineString"], 641 | ["==", "brunnel", "bridge"] 642 | ], 643 | "id": "waterway-bridge-case", 644 | "layout": { 645 | "line-cap": "butt", 646 | "line-join": "miter" 647 | }, 648 | "paint": { 649 | "line-color": "#bbbbbb", 650 | "line-gap-width": { 651 | "base": 1.55, 652 | "stops": [ 653 | [4, 0.25], 654 | [20, 30] 655 | ] 656 | }, 657 | "line-width": { 658 | "base": 1.6, 659 | "stops": [ 660 | [12, 0.5], 661 | [20, 10] 662 | ] 663 | } 664 | }, 665 | "source": "openmaptiles", 666 | "source-layer": "waterway", 667 | "type": "line" 668 | }, { 669 | "filter": ["all", ["==", "$type", "LineString"], 670 | ["==", "brunnel", "bridge"] 671 | ], 672 | "id": "waterway-bridge", 673 | "layout": { 674 | "line-cap": "round", 675 | "line-join": "round" 676 | }, 677 | "paint": { 678 | "line-color": "hsl(205, 56%, 73%)", 679 | "line-width": { 680 | "base": 1.55, 681 | "stops": [ 682 | [4, 0.25], 683 | [20, 30] 684 | ] 685 | } 686 | }, 687 | "source": "openmaptiles", 688 | "source-layer": "waterway", 689 | "type": "line" 690 | }, { 691 | "filter": ["all", ["==", "$type", "LineString"], 692 | ["==", "brunnel", "bridge"], 693 | ["==", "class", "minor_road"] 694 | ], 695 | "id": "bridge_minor case", 696 | "layout": { 697 | "line-cap": "butt", 698 | "line-join": "miter" 699 | }, 700 | "paint": { 701 | "line-color": "#dedede", 702 | "line-gap-width": { 703 | "base": 1.55, 704 | "stops": [ 705 | [4, 0.25], 706 | [20, 30] 707 | ] 708 | }, 709 | "line-width": { 710 | "base": 1.6, 711 | "stops": [ 712 | [12, 0.5], 713 | [20, 10] 714 | ] 715 | } 716 | }, 717 | "source": "openmaptiles", 718 | "source-layer": "transportation", 719 | "type": "line" 720 | }, { 721 | "filter": ["all", ["==", "$type", "LineString"], 722 | ["==", "brunnel", "bridge"], 723 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 724 | ], 725 | "id": "bridge_major case", 726 | "layout": { 727 | "line-cap": "butt", 728 | "line-join": "miter" 729 | }, 730 | "paint": { 731 | "line-color": "#dedede", 732 | "line-gap-width": { 733 | "base": 1.55, 734 | "stops": [ 735 | [4, 0.25], 736 | [20, 30] 737 | ] 738 | }, 739 | "line-width": { 740 | "base": 1.6, 741 | "stops": [ 742 | [12, 0.5], 743 | [20, 10] 744 | ] 745 | } 746 | }, 747 | "source": "openmaptiles", 748 | "source-layer": "transportation", 749 | "type": "line" 750 | }, { 751 | "filter": ["all", ["==", "$type", "LineString"], 752 | ["==", "brunnel", "bridge"], 753 | ["==", "class", "minor_road"] 754 | ], 755 | "id": "bridge_minor", 756 | "layout": { 757 | "line-cap": "round", 758 | "line-join": "round" 759 | }, 760 | "paint": { 761 | "line-color": "#efefef", 762 | "line-width": { 763 | "base": 1.55, 764 | "stops": [ 765 | [4, 0.25], 766 | [20, 30] 767 | ] 768 | } 769 | }, 770 | "source": "openmaptiles", 771 | "source-layer": "transportation", 772 | "type": "line" 773 | }, { 774 | "filter": ["all", ["==", "$type", "LineString"], 775 | ["==", "brunnel", "bridge"], 776 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 777 | ], 778 | "id": "bridge_major", 779 | "layout": { 780 | "line-cap": "round", 781 | "line-join": "round" 782 | }, 783 | "paint": { 784 | "line-color": "#fff", 785 | "line-width": { 786 | "base": 1.4, 787 | "stops": [ 788 | [6, 0.5], 789 | [20, 30] 790 | ] 791 | } 792 | }, 793 | "source": "openmaptiles", 794 | "source-layer": "transportation", 795 | "type": "line" 796 | }, { 797 | "filter": ["in", "admin_level", 4, 6, 8], 798 | "id": "admin_sub", 799 | "layout": { 800 | "visibility": "visible" 801 | }, 802 | "paint": { 803 | "line-color": "hsla(0, 0%, 60%, 0.5)", 804 | "line-dasharray": [2, 1] 805 | }, 806 | "source": "openmaptiles", 807 | "source-layer": "boundary", 808 | "type": "line" 809 | }, { 810 | "filter": ["all", ["<=", "admin_level", 2], 811 | ["==", "$type", "LineString"] 812 | ], 813 | "id": "admin_country", 814 | "layout": { 815 | "line-cap": "round", 816 | "line-join": "round" 817 | }, 818 | "paint": { 819 | "line-color": "hsl(0, 0%, 60%)", 820 | "line-width": { 821 | "base": 1.3, 822 | "stops": [ 823 | [3, 0.5], 824 | [22, 15] 825 | ] 826 | } 827 | }, 828 | "source": "openmaptiles", 829 | "source-layer": "boundary", 830 | "type": "line" 831 | }, { 832 | "filter": ["all", ["==", "$type", "Point"], 833 | ["==", "rank", 1] 834 | ], 835 | "id": "poi_label", 836 | "layout": { 837 | "icon-size": 1, 838 | "text-anchor": "top", 839 | "text-field": "{name:latin}\n{name:nonlatin}", 840 | "text-font": ["Noto Sans Regular"], 841 | "text-max-width": 8, 842 | "text-offset": [0, 0.5], 843 | "text-size": 11, 844 | "visibility": "visible" 845 | }, 846 | "minzoom": 14, 847 | "paint": { 848 | "text-color": "#666", 849 | "text-halo-blur": 1, 850 | "text-halo-color": "rgba(255,255,255,0.75)", 851 | "text-halo-width": 1 852 | }, 853 | "source": "openmaptiles", 854 | "source-layer": "poi", 855 | "type": "symbol" 856 | }, { 857 | "filter": ["all", ["has", "iata"]], 858 | "id": "airport-label", 859 | "layout": { 860 | "icon-size": 1, 861 | "text-anchor": "top", 862 | "text-field": "{name:latin}\n{name:nonlatin}", 863 | "text-font": ["Noto Sans Regular"], 864 | "text-max-width": 8, 865 | "text-offset": [0, 0.5], 866 | "text-size": 11, 867 | "visibility": "visible" 868 | }, 869 | "minzoom": 10, 870 | "paint": { 871 | "text-color": "#666", 872 | "text-halo-blur": 1, 873 | "text-halo-color": "rgba(255,255,255,0.75)", 874 | "text-halo-width": 1 875 | }, 876 | "source": "openmaptiles", 877 | "source-layer": "aerodrome_label", 878 | "type": "symbol" 879 | }, { 880 | "filter": ["==", "$type", "LineString"], 881 | "id": "road_major_label", 882 | "layout": { 883 | "symbol-placement": "line", 884 | "text-field": "{name:latin} {name:nonlatin}", 885 | "text-font": ["Noto Sans Regular"], 886 | "text-letter-spacing": 0.1, 887 | "text-rotation-alignment": "map", 888 | "text-size": { 889 | "base": 1.4, 890 | "stops": [ 891 | [10, 8], 892 | [20, 14] 893 | ] 894 | }, 895 | "text-transform": "uppercase" 896 | }, 897 | "paint": { 898 | "text-color": "#000", 899 | "text-halo-color": "hsl(0, 0%, 100%)", 900 | "text-halo-width": 2 901 | }, 902 | "source": "openmaptiles", 903 | "source-layer": "transportation_name", 904 | "type": "symbol" 905 | }, { 906 | "filter": ["all", ["==", "$type", "Point"], 907 | ["!in", "class", "city", "state", "country", "continent"] 908 | ], 909 | "id": "place_label_other", 910 | "layout": { 911 | "text-anchor": "center", 912 | "text-field": "{name:latin}\n{name:nonlatin}", 913 | "text-font": ["Noto Sans Regular"], 914 | "text-max-width": 6, 915 | "text-size": { 916 | "stops": [ 917 | [6, 10], 918 | [12, 14] 919 | ] 920 | }, 921 | "visibility": "visible" 922 | }, 923 | "minzoom": 8, 924 | "paint": { 925 | "text-color": "hsl(0, 0%, 25%)", 926 | "text-halo-blur": 0, 927 | "text-halo-color": "hsl(0, 0%, 100%)", 928 | "text-halo-width": 2 929 | }, 930 | "source": "openmaptiles", 931 | "source-layer": "place", 932 | "type": "symbol" 933 | }, { 934 | "filter": ["all", ["==", "$type", "Point"], 935 | ["==", "class", "city"] 936 | ], 937 | "id": "place_label_city", 938 | "layout": { 939 | "text-field": "{name:latin}\n{name:nonlatin}", 940 | "text-font": ["Noto Sans Regular"], 941 | "text-max-width": 10, 942 | "text-size": { 943 | "stops": [ 944 | [3, 12], 945 | [8, 16] 946 | ] 947 | } 948 | }, 949 | "maxzoom": 16, 950 | "paint": { 951 | "text-color": "hsl(0, 0%, 0%)", 952 | "text-halo-blur": 0, 953 | "text-halo-color": "hsla(0, 0%, 100%, 0.75)", 954 | "text-halo-width": 2 955 | }, 956 | "source": "openmaptiles", 957 | "source-layer": "place", 958 | "type": "symbol" 959 | }, { 960 | "filter": ["all", ["==", "$type", "Point"], 961 | ["==", "class", "country"], 962 | ["!has", "iso_a2"] 963 | ], 964 | "id": "country_label-other", 965 | "layout": { 966 | "text-field": "{name:latin}", 967 | "text-font": ["Noto Sans Regular"], 968 | "text-max-width": 10, 969 | "text-size": { 970 | "stops": [ 971 | [3, 12], 972 | [8, 22] 973 | ] 974 | }, 975 | "visibility": "visible" 976 | }, 977 | "maxzoom": 12, 978 | "paint": { 979 | "text-color": "hsl(0, 0%, 13%)", 980 | "text-halo-blur": 0, 981 | "text-halo-color": "rgba(255,255,255,0.75)", 982 | "text-halo-width": 2 983 | }, 984 | "source": "openmaptiles", 985 | "source-layer": "place", 986 | "type": "symbol" 987 | }, { 988 | "filter": ["all", ["==", "$type", "Point"], 989 | ["==", "class", "country"], 990 | ["has", "iso_a2"] 991 | ], 992 | "id": "country_label", 993 | "layout": { 994 | "text-field": "{name:latin}", 995 | "text-font": ["Noto Sans Bold"], 996 | "text-max-width": 10, 997 | "text-size": { 998 | "stops": [ 999 | [3, 12], 1000 | [8, 22] 1001 | ] 1002 | }, 1003 | "visibility": "visible" 1004 | }, 1005 | "maxzoom": 12, 1006 | "paint": { 1007 | "text-color": "hsl(0, 0%, 13%)", 1008 | "text-halo-blur": 0, 1009 | "text-halo-color": "rgba(255,255,255,0.75)", 1010 | "text-halo-width": 2 1011 | }, 1012 | "source": "openmaptiles", 1013 | "source-layer": "place", 1014 | "type": "symbol" 1015 | }], 1016 | "id": "basic" 1017 | } 1018 | -------------------------------------------------------------------------------- /examples/klokan-basic/main.js: -------------------------------------------------------------------------------- 1 | import * as yawgl from "yawgl"; 2 | import * as d3 from "d3"; 3 | import * as tileMap from "../../"; 4 | 5 | export function main() { 6 | const canvas = document.getElementById("mapCanvas"); 7 | yawgl.resizeCanvasToDisplaySize(canvas, window.devicePixelRatio); 8 | const context = yawgl.initContext(canvas); 9 | 10 | tileMap.init({ 11 | context, 12 | center: [-73.885, 40.745], 13 | zoom: 9, 14 | style: "./klokantech-basic-style.json", 15 | }).promise.then(api => setup(api, canvas)) 16 | .catch(console.log); 17 | } 18 | 19 | function setup(api, canvas) { 20 | const viewport = api.getViewport(); 21 | 22 | const { k, x, y } = api.getTransform(); 23 | let transform = d3.zoomIdentity 24 | .translate(x, y) 25 | .scale(k); 26 | 27 | const zoomer = d3.zoom() 28 | .scaleExtent([1 << 10, 1 << 26]) 29 | .extent([[0, 0], viewport]) 30 | .translateExtent([[-Infinity, -0.5], [Infinity, 0.5]]) 31 | .on("zoom", (event) => { 32 | transform = event.transform; 33 | }); 34 | 35 | d3.select(canvas) 36 | .call(zoomer) 37 | .call(zoomer.transform, transform); 38 | 39 | requestAnimationFrame(animate); 40 | function animate() { 41 | const pixRatio = window.devicePixelRatio; 42 | yawgl.resizeCanvasToDisplaySize(canvas, pixRatio); 43 | api.setTransform(transform); 44 | api.draw({ pixRatio }); 45 | requestAnimationFrame(animate); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/klokan-basic/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | border: 0; 6 | margin: 0; 7 | font-family: "Noto Sans"; 8 | font-size: 14px; 9 | } 10 | #main { 11 | width: 100%; 12 | height: 100vh; 13 | position: relative; 14 | } 15 | #mapCanvas { 16 | width: 100%; 17 | height: 100%; 18 | background-color: gray; 19 | position: relative; 20 | } 21 | .attribution { 22 | background: rgba(255, 255, 255, 0.8); 23 | position: absolute; 24 | bottom: 0; 25 | right: 0; 26 | padding: 0 4px 0 4px; 27 | } 28 | .loadStatus { 29 | background: rgba(255, 255, 255, 0.8); 30 | position: absolute; 31 | top: 0; 32 | right: 0; 33 | padding: 0 4px 0 4px; 34 | } 35 | -------------------------------------------------------------------------------- /examples/macrostrat/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 🌎 3 | 4 | -------------------------------------------------------------------------------- /examples/macrostrat/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tile-setter - beta 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/macrostrat/macrostrat-only.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "name": "Mapbox Light", 4 | "sources": { 5 | "burwell": { 6 | "type": "vector", 7 | "tiles": ["https://tiles.macrostrat.org/carto/{z}/{x}/{y}.mvt"], 8 | "tileSize": 512 9 | } 10 | }, 11 | "sprite": "mapbox://sprites/mapbox/light-v9", 12 | "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", 13 | "visibility": "public", 14 | "layers": [ 15 | { 16 | "id": "background", 17 | "type": "background", 18 | "layout": { }, 19 | "paint": { "background-color": "hsl(55, 11%, 96%)" } 20 | }, 21 | { 22 | "id": "burwell_fill", 23 | "type": "fill", 24 | "source": "burwell", 25 | "source-layer": "units", 26 | "filter": ["!=", "color", ""], 27 | "minzoom": 0, 28 | "maxzoom": 16, 29 | "paint": { 30 | "fill-color": { 31 | "property": "color", 32 | "type": "identity" 33 | }, 34 | "fill-opacity": { 35 | "stops": [ 36 | [0, 0.5], 37 | [12, 0.3] 38 | ] 39 | }, 40 | "fill-outline-color": { 41 | "property": "color", 42 | "type": "identity" 43 | }, 44 | "fill-outline-width": { 45 | "stops": [ 46 | [0, 0.15], 47 | [1, 0.15], 48 | [2, 0.15], 49 | [3, 0.15], 50 | [4, 0.2], 51 | [5, 0.4], 52 | [6, 0.05], 53 | [7, 0.1], 54 | [8, 0.4], 55 | [9, 0.5], 56 | [10, 0.35], 57 | [11, 0.4], 58 | [12, 1], 59 | [13, 1.25], 60 | [14, 1.5], 61 | [15, 1.75], 62 | [16, 2] 63 | ] 64 | } 65 | } 66 | }, 67 | { 68 | "id": "namedFaults", 69 | "type": "line", 70 | "source": "burwell", 71 | "source-layer": "lines", 72 | "filter": [ 73 | "all", 74 | ["!=", "name", ""], 75 | ["in", "type", "fault", "normal fault", "thrust fault", "strike-slip fault", "reverse fault", "growth fault", "fault zone", "zone"] 76 | ], 77 | "minzoom": 0, 78 | "maxzoom": 16, 79 | "paint": { 80 | "line-color": "#000000", 81 | "line-width": { 82 | "stops": [ 83 | [0, 0.6], 84 | [3, 0.6], 85 | [4, 1.0], 86 | [5, 1.2], 87 | [6, 0.9], 88 | [7, 0.8], 89 | [8, 1.4], 90 | [9, 1.6], 91 | [10, 1.4], 92 | [11, 2.2], 93 | [12, 2.6], 94 | [13, 3.0], 95 | [14, 3.2], 96 | [15, 3.5], 97 | [16, 4.4] 98 | ] 99 | }, 100 | "line-opacity": 1 101 | }, 102 | "layout": { 103 | "line-join": "round", 104 | "line-cap": "round" 105 | } 106 | }, 107 | { 108 | "id": "faults", 109 | "type": "line", 110 | "source": "burwell", 111 | "source-layer": "lines", 112 | "filter": [ 113 | "all", 114 | ["==", "name", ""], 115 | ["in", "type", "fault", "normal fault", "thrust fault", "strike-slip fault", "reverse fault", "growth fault", "fault zone", "zone"] 116 | ], 117 | "minzoom": 0, 118 | "maxzoom": 16, 119 | "paint": { 120 | "line-color": "#000000", 121 | "line-width": { 122 | "stops": [ 123 | [0, 0.3], 124 | [3, 0.3], 125 | [4, 0.5], 126 | [5, 0.6], 127 | [6, 0.45], 128 | [7, 0.4], 129 | [8, 0.7], 130 | [9, 0.8], 131 | [10, 0.7], 132 | [11, 1.1], 133 | [12, 1.3], 134 | [13, 1.5], 135 | [14, 1.6], 136 | [15, 1.75], 137 | [16, 2.2] 138 | ] 139 | }, 140 | "line-opacity": 1 141 | }, 142 | "layout": { 143 | "line-join": "round", 144 | "line-cap": "round" 145 | } 146 | }, 147 | { 148 | "id": "moraines", 149 | "type": "line", 150 | "source": "burwell", 151 | "source-layer": "lines", 152 | "filter": ["==", "type", "moraine"], 153 | "minzoom": 12, 154 | "maxzoom": 16, 155 | "layout": { 156 | "line-join": "round", 157 | "line-cap": "round" 158 | }, 159 | "paint": { 160 | "line-color": "#3498DB", 161 | "line-dasharray": [1, 2], 162 | "line-width": { 163 | "stops": [ 164 | [ 10, 1 ], 165 | [ 11, 2 ], 166 | [ 12, 2 ], 167 | [ 13, 2.5 ], 168 | [ 14, 3 ], 169 | [ 15, 3 ] 170 | ] 171 | }, 172 | "line-opacity": { 173 | "stops": [ 174 | [ 10, 0.2 ], 175 | [ 13, 1 ] 176 | ] 177 | } 178 | } 179 | }, 180 | { 181 | "id": "eskers", 182 | "type": "line", 183 | "source": "burwell", 184 | "source-layer": "lines", 185 | "filter": ["==", "type", "esker"], 186 | "minzoom": 12, 187 | "maxzoom": 16, 188 | "layout": { 189 | "line-join": "round", 190 | "line-cap": "round" 191 | }, 192 | "paint": { 193 | "line-color": "#00FFFF", 194 | "line-dasharray": [1, 4], 195 | "line-width": { 196 | "stops": [ 197 | [ 10, 1 ], 198 | [ 11, 2 ], 199 | [ 12, 2 ], 200 | [ 13, 2.5 ], 201 | [ 14, 3 ], 202 | [ 15, 3 ] 203 | ] 204 | }, 205 | "line-opacity": { 206 | "stops": [ 207 | [ 10, 0.2 ], 208 | [ 13, 1 ] 209 | ] 210 | } 211 | } 212 | }, 213 | { 214 | "id": "lineaments", 215 | "type": "line", 216 | "source": "burwell", 217 | "source-layer": "lines", 218 | "filter": ["==", "type", "lineament"], 219 | "minzoom": 0, 220 | "maxzoom": 16, 221 | "layout": { 222 | "line-join": "round", 223 | "line-cap": "round" 224 | }, 225 | "paint": { 226 | "line-color": "#000000", 227 | "line-dasharray": [2, 2, 7, 2], 228 | "line-width": { 229 | "stops": [ 230 | [ 9, 1], 231 | [ 10, 1 ], 232 | [ 11, 2 ], 233 | [ 12, 2 ], 234 | [ 13, 2.5 ], 235 | [ 14, 3 ], 236 | [ 15, 3 ] 237 | ] 238 | }, 239 | "line-opacity": 1 240 | } 241 | }, 242 | { 243 | "id": "synclines", 244 | "type": "line", 245 | "source": "burwell", 246 | "source-layer": "lines", 247 | "filter": ["==", "type", "syncline"], 248 | "minzoom": 0, 249 | "maxzoom": 16, 250 | "layout": { 251 | "line-join": "round", 252 | "line-cap": "round" 253 | }, 254 | "paint": { 255 | "line-color": "#F012BE", 256 | "line-width": { 257 | "stops": [ 258 | [0, 1], 259 | [7, 0.25], 260 | [8, 0.4], 261 | [9, 0.45], 262 | [10, 0.45], 263 | [11, 0.6], 264 | [12, 0.7], 265 | [13, 0.9], 266 | [14, 1.4], 267 | [15, 1.75], 268 | [16, 2.2] 269 | ] 270 | }, 271 | "line-opacity": 1 272 | } 273 | }, 274 | { 275 | "id": "monoclines", 276 | "type": "line", 277 | "source": "burwell", 278 | "source-layer": "lines", 279 | "filter": ["==", "type", "monocline"], 280 | "minzoom": 0, 281 | "maxzoom": 16, 282 | "layout": { 283 | "line-join": "round", 284 | "line-cap": "round" 285 | }, 286 | "paint": { 287 | "line-color": "#F012BE", 288 | "line-width": { 289 | "stops": [ 290 | [0, 1], 291 | [7, 0.25], 292 | [8, 0.4], 293 | [9, 0.45], 294 | [10, 0.45], 295 | [11, 0.6], 296 | [12, 0.7], 297 | [13, 0.9], 298 | [14, 1.4], 299 | [15, 1.75], 300 | [16, 2.2] 301 | ] 302 | }, 303 | "line-opacity": 1 304 | } 305 | }, 306 | { 307 | "id": "folds", 308 | "type": "line", 309 | "source": "burwell", 310 | "source-layer": "lines", 311 | "filter": ["==", "type", "fold"], 312 | "minzoom": 0, 313 | "maxzoom": 16, 314 | "layout": { 315 | "line-join": "round", 316 | "line-cap": "round" 317 | }, 318 | "paint": { 319 | "line-color": "#F012BE", 320 | "line-width": { 321 | "stops": [ 322 | [0, 1], 323 | [7, 0.25], 324 | [8, 0.4], 325 | [9, 0.45], 326 | [10, 0.45], 327 | [11, 0.6], 328 | [12, 0.7], 329 | [13, 0.9], 330 | [14, 1.4], 331 | [15, 1.75], 332 | [16, 2.2] 333 | ] 334 | }, 335 | "line-opacity": 1 336 | } 337 | }, 338 | { 339 | "id": "dikes", 340 | "type": "line", 341 | "source": "burwell", 342 | "source-layer": "lines", 343 | "filter": ["==", "type", "dike"], 344 | "minzoom": 6, 345 | "maxzoom": 16, 346 | "layout": { 347 | "line-join": "round", 348 | "line-cap": "round" 349 | }, 350 | "paint": { 351 | "line-color": "#FF4136", 352 | "line-width": { 353 | "stops": [ 354 | [0, 1], 355 | [7, 0.25], 356 | [8, 0.4], 357 | [9, 0.45], 358 | [10, 0.45], 359 | [11, 0.6], 360 | [12, 0.7], 361 | [13, 0.9], 362 | [14, 1.4], 363 | [15, 1.75], 364 | [16, 2.2] 365 | ] 366 | }, 367 | "line-opacity": { 368 | "stops": [ 369 | [ 6, 0.2 ], 370 | [ 10, 1 ] 371 | ] 372 | } 373 | } 374 | }, 375 | { 376 | "id": "anticlines", 377 | "type": "line", 378 | "source": "burwell", 379 | "source-layer": "lines", 380 | "filter": ["==", "type", "anticline"], 381 | "minzoom": 0, 382 | "maxzoom": 16, 383 | "layout": { 384 | "line-join": "round", 385 | "line-cap": "round" 386 | }, 387 | "paint": { 388 | "line-color": "#F012BE", 389 | "line-width": { 390 | "stops": [ 391 | [0, 1], 392 | [7, 0.25], 393 | [8, 0.4], 394 | [9, 0.45], 395 | [10, 0.45], 396 | [11, 0.6], 397 | [12, 0.7], 398 | [13, 0.9], 399 | [14, 1.4], 400 | [15, 1.75], 401 | [16, 2.2] 402 | ] 403 | }, 404 | "line-opacity": 1 405 | } 406 | }, 407 | { 408 | "id": "flows", 409 | "type": "line", 410 | "source": "burwell", 411 | "source-layer": "lines", 412 | "filter": ["==", "type", "flow"], 413 | "minzoom": 0, 414 | "maxzoom": 16, 415 | "layout": { 416 | "line-join": "round", 417 | "line-cap": "round" 418 | }, 419 | "paint": { 420 | "line-color": "#FF4136", 421 | "line-width": { 422 | "stops": [ 423 | [0, 1], 424 | [7, 0.25], 425 | [8, 0.4], 426 | [9, 0.45], 427 | [10, 0.45], 428 | [11, 0.6], 429 | [12, 0.7], 430 | [13, 0.9], 431 | [14, 1.4], 432 | [15, 1.75], 433 | [16, 2.2] 434 | ] 435 | }, 436 | "line-opacity": 1 437 | } 438 | }, 439 | { 440 | "id": "sills", 441 | "type": "line", 442 | "source": "burwell", 443 | "source-layer": "lines", 444 | "filter": ["==", "type", "sill"], 445 | "minzoom": 0, 446 | "maxzoom": 16, 447 | "layout": { 448 | "line-join": "round", 449 | "line-cap": "round" 450 | }, 451 | "paint": { 452 | "line-color": "#FF4136", 453 | "line-width": { 454 | "stops": [ 455 | [0, 1], 456 | [7, 0.25], 457 | [8, 0.4], 458 | [9, 0.45], 459 | [10, 0.45], 460 | [11, 0.6], 461 | [12, 0.7], 462 | [13, 0.9], 463 | [14, 1.4], 464 | [15, 1.75], 465 | [16, 2.2] 466 | ] 467 | }, 468 | "line-opacity": 1 469 | } 470 | }, 471 | { 472 | "id": "veins", 473 | "type": "line", 474 | "source": "burwell", 475 | "source-layer": "lines", 476 | "filter": ["==", "type", "vein"], 477 | "minzoom": 0, 478 | "maxzoom": 16, 479 | "layout": { 480 | "line-join": "round", 481 | "line-cap": "round" 482 | }, 483 | "paint": { 484 | "line-color": "#FF4136", 485 | "line-width": { 486 | "stops": [ 487 | [0, 1], 488 | [7, 0.25], 489 | [8, 0.4], 490 | [9, 0.45], 491 | [10, 0.45], 492 | [11, 0.6], 493 | [12, 0.7], 494 | [13, 0.9], 495 | [14, 1.4], 496 | [15, 1.75], 497 | [16, 2.2] 498 | ] 499 | }, 500 | "line-opacity": { 501 | "stops": [ 502 | [ 6, 0.2 ], 503 | [ 10, 1 ] 504 | ] 505 | } 506 | } 507 | }, 508 | { 509 | "id": "marker_beds", 510 | "type": "line", 511 | "source": "burwell", 512 | "source-layer": "lines", 513 | "filter": ["in", "type", "marker bed", "bed"], 514 | "minzoom": 12, 515 | "maxzoom": 16, 516 | "layout": { 517 | "line-join": "round", 518 | "line-cap": "round" 519 | }, 520 | "paint": { 521 | "line-color": "#333333", 522 | "line-width": { 523 | "stops": [ 524 | [10, 0.8], 525 | [11, 0.8], 526 | [12, 0.9], 527 | [13, 0.9], 528 | [14, 1.4], 529 | [15, 1.75], 530 | [16, 2.2] 531 | ] 532 | }, 533 | "line-opacity": 1 534 | } 535 | }, 536 | { 537 | "id": "craters", 538 | "type": "line", 539 | "source": "burwell", 540 | "source-layer": "lines", 541 | "filter": ["in", "type", "crater", "impact structure"], 542 | "minzoom": 10, 543 | "maxzoom": 16, 544 | "paint": { 545 | "line-dasharray": [6, 6], 546 | "line-color": "#000000", 547 | "line-width": { 548 | "stops": [ 549 | [10, 0.6], 550 | [11, 0.6], 551 | [12, 0.72], 552 | [13, 0.72], 553 | [14, 1], 554 | [15, 1.3], 555 | [16, 1.8] 556 | ] 557 | }, 558 | "line-opacity": 1 559 | } 560 | } 561 | ], 562 | "created": "1970-01-01T00:00:00.000Z", 563 | "modified": "1970-01-01T00:00:00.000Z", 564 | "owner": "mapbox", 565 | "id": "light-v9", 566 | "draft": false 567 | } 568 | -------------------------------------------------------------------------------- /examples/macrostrat/main.js: -------------------------------------------------------------------------------- 1 | import * as yawgl from "yawgl"; 2 | import * as d3 from "d3"; 3 | import * as tileMap from "../../"; 4 | 5 | export function main() { 6 | const canvas = document.getElementById("mapCanvas"); 7 | yawgl.resizeCanvasToDisplaySize(canvas, window.devicePixelRatio); 8 | const context = yawgl.initContext(canvas); 9 | 10 | tileMap.init({ 11 | context, 12 | center: [-85.0, 36.0], 13 | zoom: 7, 14 | style: "./light-macrostrat.json", 15 | // eslint-disable-next-line max-len 16 | mapboxToken: "pk.eyJ1IjoiamhlbWJkIiwiYSI6ImNqcHpueHpyZjBlMjAzeG9kNG9oNzI2NTYifQ.K7fqhk2Z2YZ8NIV94M-5nA", 17 | }).promise.then(api => setup(api, canvas)) 18 | .catch(console.log); 19 | } 20 | 21 | function setup(api, canvas) { 22 | const viewport = api.getViewport(); 23 | 24 | const { k, x, y } = api.getTransform(); 25 | let transform = d3.zoomIdentity 26 | .translate(x, y) 27 | .scale(k); 28 | 29 | const zoomer = d3.zoom() 30 | .scaleExtent([1 << 10, 1 << 26]) 31 | .extent([[0, 0], viewport]) 32 | .translateExtent([[-Infinity, -0.5], [Infinity, 0.5]]) 33 | .on("zoom", (event) => { 34 | transform = event.transform; 35 | }); 36 | 37 | d3.select(canvas) 38 | .call(zoomer) 39 | .call(zoomer.transform, transform); 40 | 41 | const loadStatus = document.getElementById("loadStatus"); 42 | 43 | requestAnimationFrame(animate); 44 | function animate() { 45 | const pixRatio = window.devicePixelRatio; 46 | yawgl.resizeCanvasToDisplaySize(canvas, pixRatio); 47 | api.setTransform(transform); 48 | const percent = api.draw({ pixRatio }) * 100; 49 | loadStatus.innerHTML = (percent < 100) 50 | ? "Loading: " + percent.toFixed(0) + "%" 51 | : "Complete! " + percent.toFixed(0) + "%"; 52 | 53 | requestAnimationFrame(animate); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/macrostrat/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | border: 0; 6 | margin: 0; 7 | font-family: "Noto Sans"; 8 | font-size: 14px; 9 | } 10 | #main { 11 | width: 100%; 12 | height: 100vh; 13 | position: relative; 14 | } 15 | #mapCanvas { 16 | width: 100%; 17 | height: 100%; 18 | display: block; 19 | background-color: gray; 20 | position: relative; 21 | } 22 | .attribution { 23 | background: rgba(255, 255, 255, 0.8); 24 | position: absolute; 25 | bottom: 0; 26 | right: 0; 27 | padding: 0 4px 0 4px; 28 | } 29 | #loadStatus { 30 | position: absolute; 31 | top: 0; 32 | right: 0; 33 | width: 15ch; 34 | text-align: right; 35 | background: rgba(60, 60, 60, 0.5); 36 | color: white; 37 | padding: 0 4px 0 4px; 38 | } 39 | -------------------------------------------------------------------------------- /examples/mapbox-streets/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 🌎 3 | 4 | -------------------------------------------------------------------------------- /examples/mapbox-streets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tile-setter - beta 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/mapbox-streets/main.js: -------------------------------------------------------------------------------- 1 | import * as yawgl from "yawgl"; 2 | import * as d3 from "d3"; 3 | import * as tileMap from "../../"; 4 | 5 | export function main() { 6 | const canvas = document.getElementById("mapCanvas"); 7 | yawgl.resizeCanvasToDisplaySize(canvas, window.devicePixelRatio); 8 | const context = yawgl.initContext(canvas); 9 | 10 | tileMap.init({ 11 | context, 12 | center: [-73.885, 40.745], 13 | zoom: 9, 14 | // style: "mapbox://styles/mapbox/streets-v8", 15 | style: "./streets-v8-noInteractive.json", 16 | // eslint-disable-next-line max-len 17 | mapboxToken: "pk.eyJ1IjoiamhlbWJkIiwiYSI6ImNqcHpueHpyZjBlMjAzeG9kNG9oNzI2NTYifQ.K7fqhk2Z2YZ8NIV94M-5nA", 18 | }).promise.then(api => setup(api, canvas)) 19 | .catch(console.log); 20 | } 21 | 22 | function setup(api, canvas) { 23 | const viewport = api.getViewport(); 24 | 25 | const { k, x, y } = api.getTransform(); 26 | let transform = d3.zoomIdentity 27 | .translate(x, y) 28 | .scale(k); 29 | 30 | const zoomer = d3.zoom() 31 | .scaleExtent([1 << 10, 1 << 26]) 32 | .extent([[0, 0], viewport]) 33 | .translateExtent([[-Infinity, -0.5], [Infinity, 0.5]]) 34 | .on("zoom", (event) => { 35 | transform = event.transform; 36 | }); 37 | 38 | d3.select(canvas) 39 | .call(zoomer) 40 | .call(zoomer.transform, transform); 41 | 42 | const loadStatus = document.getElementById("loadStatus"); 43 | 44 | requestAnimationFrame(animate); 45 | function animate() { 46 | const pixRatio = window.devicePixelRatio; 47 | yawgl.resizeCanvasToDisplaySize(canvas, pixRatio); 48 | api.setTransform(transform); 49 | const percent = api.draw({ pixRatio }) * 100; 50 | loadStatus.innerHTML = (percent < 100) 51 | ? "Loading: " + percent.toFixed(0) + "%" 52 | : "Complete! " + percent.toFixed(0) + "%"; 53 | 54 | requestAnimationFrame(animate); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/mapbox-streets/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | border: 0; 6 | margin: 0; 7 | font-family: "Noto Sans"; 8 | font-size: 14px; 9 | } 10 | #main { 11 | width: 100%; 12 | height: 100vh; 13 | position: relative; 14 | } 15 | #mapCanvas { 16 | width: 100%; 17 | height: 100%; 18 | display: block; 19 | background-color: gray; 20 | position: relative; 21 | } 22 | .attribution { 23 | background: rgba(255, 255, 255, 0.8); 24 | position: absolute; 25 | bottom: 0; 26 | right: 0; 27 | padding: 0 4px 0 4px; 28 | } 29 | #loadStatus { 30 | position: absolute; 31 | top: 0; 32 | right: 0; 33 | width: 15ch; 34 | text-align: right; 35 | background: rgba(60, 60, 60, 0.5); 36 | color: white; 37 | padding: 0 4px 0 4px; 38 | } 39 | -------------------------------------------------------------------------------- /examples/rollup.config.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | 4 | // Get a list of the directory names 5 | const dirNames = fs 6 | .readdirSync('./', { withFileTypes: true }) 7 | .filter(d => d.isDirectory()) 8 | .map(d => d.name); 9 | 10 | // Function to make a rollup config object from a directory name 11 | function makeConfig(dir) { 12 | return { 13 | input: dir + '/main.js', 14 | plugins: [ 15 | resolve(), 16 | ], 17 | output: { 18 | file: dir + '/main.min.js', 19 | format: 'iife', 20 | name: 'app', 21 | } 22 | }; 23 | } 24 | 25 | // Export an array of config objects 26 | export default dirNames.map(makeConfig); 27 | -------------------------------------------------------------------------------- /examples/set-center-zoom/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 🌎 3 | 4 | -------------------------------------------------------------------------------- /examples/set-center-zoom/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tile-setter - beta 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 22 |
23 |

24 | 25 | 26 | 27 |

28 |

Camera Position:

29 |

Adjusted Zoom:

30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/set-center-zoom/klokantech-basic-style.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "name": "Basic", 4 | "metadata": { 5 | "mapbox:autocomposite": false, 6 | "mapbox:type": "template", 7 | "maputnik:renderer": "mbgljs", 8 | "openmaptiles:version": "3.x", 9 | "openmaptiles:mapbox:owner": "openmaptiles", 10 | "openmaptiles:mapbox:source:url": "mapbox://openmaptiles.4qljc88t" 11 | }, 12 | "sources": { 13 | "openmaptiles": { 14 | "type": "vector", 15 | "url": "https://api.maptiler.com/tiles/v3/tiles.json?key=mrAq6zQEFxOkanukNbGm" 16 | } 17 | }, 18 | "glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=mrAq6zQEFxOkanukNbGm", 19 | "layers": [{ 20 | "id": "background", 21 | "paint": { 22 | "background-color": "hsl(47, 26%, 88%)" 23 | }, 24 | "type": "background" 25 | }, { 26 | "filter": ["all", ["==", "$type", "Polygon"], 27 | ["in", "class", "residential", "suburb", "neighbourhood"] 28 | ], 29 | "id": "landuse-residential", 30 | "layout": { 31 | "visibility": "visible" 32 | }, 33 | "paint": { 34 | "fill-color": "hsl(47, 13%, 86%)", 35 | "fill-opacity": 0.7 36 | }, 37 | "source": "openmaptiles", 38 | "source-layer": "landuse", 39 | "type": "fill" 40 | }, { 41 | "filter": ["==", "class", "grass"], 42 | "id": "landcover_grass", 43 | "paint": { 44 | "fill-color": "hsl(82, 46%, 72%)", 45 | "fill-opacity": 0.45 46 | }, 47 | "source": "openmaptiles", 48 | "source-layer": "landcover", 49 | "type": "fill" 50 | }, { 51 | "filter": ["==", "class", "wood"], 52 | "id": "landcover_wood", 53 | "paint": { 54 | "fill-color": "hsl(82, 46%, 72%)", 55 | "fill-opacity": { 56 | "base": 1, 57 | "stops": [ 58 | [8, 0.6], 59 | [22, 1] 60 | ] 61 | } 62 | }, 63 | "source": "openmaptiles", 64 | "source-layer": "landcover", 65 | "type": "fill" 66 | }, { 67 | "filter": ["all", ["==", "$type", "Polygon"], 68 | ["!=", "intermittent", 1] 69 | ], 70 | "id": "water", 71 | "paint": { 72 | "fill-color": "hsl(205, 56%, 73%)" 73 | }, 74 | "source": "openmaptiles", 75 | "source-layer": "water", 76 | "type": "fill", 77 | "layout": { 78 | "visibility": "visible" 79 | } 80 | }, { 81 | "filter": ["all", ["==", "$type", "Polygon"], 82 | ["==", "intermittent", 1] 83 | ], 84 | "id": "water_intermittent", 85 | "paint": { 86 | "fill-color": "hsl(205, 56%, 73%)", 87 | "fill-opacity": 0.7 88 | }, 89 | "source": "openmaptiles", 90 | "source-layer": "water", 91 | "type": "fill", 92 | "layout": { 93 | "visibility": "visible" 94 | } 95 | }, { 96 | "filter": ["==", "subclass", "ice_shelf"], 97 | "id": "landcover-ice-shelf", 98 | "layout": { 99 | "visibility": "visible" 100 | }, 101 | "paint": { 102 | "fill-color": "hsl(47, 26%, 88%)", 103 | "fill-opacity": 0.8 104 | }, 105 | "source": "openmaptiles", 106 | "source-layer": "landcover", 107 | "type": "fill" 108 | }, { 109 | "filter": ["==", "subclass", "glacier"], 110 | "id": "landcover-glacier", 111 | "layout": { 112 | "visibility": "visible" 113 | }, 114 | "paint": { 115 | "fill-color": "hsl(47, 22%, 94%)", 116 | "fill-opacity": { 117 | "base": 1, 118 | "stops": [ 119 | [0, 1], 120 | [8, 0.5] 121 | ] 122 | } 123 | }, 124 | "source": "openmaptiles", 125 | "source-layer": "landcover", 126 | "type": "fill" 127 | }, { 128 | "filter": ["all", ["in", "class", "sand"]], 129 | "id": "landcover_sand", 130 | "metadata": {}, 131 | "paint": { 132 | "fill-antialias": false, 133 | "fill-color": "rgba(232, 214, 38, 1)", 134 | "fill-opacity": 0.3 135 | }, 136 | "source": "openmaptiles", 137 | "source-layer": "landcover", 138 | "type": "fill" 139 | }, { 140 | "filter": ["==", "class", "agriculture"], 141 | "id": "landuse", 142 | "layout": { 143 | "visibility": "visible" 144 | }, 145 | "paint": { 146 | "fill-color": "#eae0d0" 147 | }, 148 | "source": "openmaptiles", 149 | "source-layer": "landuse", 150 | "type": "fill" 151 | }, { 152 | "filter": ["==", "class", "national_park"], 153 | "id": "landuse_overlay_national_park", 154 | "paint": { 155 | "fill-color": "#E1EBB0", 156 | "fill-opacity": { 157 | "base": 1, 158 | "stops": [ 159 | [5, 0], 160 | [9, 0.75] 161 | ] 162 | } 163 | }, 164 | "source": "openmaptiles", 165 | "source-layer": "landcover", 166 | "type": "fill" 167 | }, { 168 | "filter": ["all", ["==", "$type", "LineString"], 169 | ["==", "brunnel", "tunnel"] 170 | ], 171 | "id": "waterway-tunnel", 172 | "paint": { 173 | "line-color": "hsl(205, 56%, 73%)", 174 | "line-dasharray": [3, 3], 175 | "line-gap-width": { 176 | "stops": [ 177 | [12, 0], 178 | [20, 6] 179 | ] 180 | }, 181 | "line-opacity": 1, 182 | "line-width": { 183 | "base": 1.4, 184 | "stops": [ 185 | [8, 1], 186 | [20, 2] 187 | ] 188 | } 189 | }, 190 | "source": "openmaptiles", 191 | "source-layer": "waterway", 192 | "type": "line", 193 | "layout": { 194 | "visibility": "visible" 195 | } 196 | }, { 197 | "filter": ["all", ["==", "$type", "LineString"], 198 | ["!in", "brunnel", "tunnel", "bridge"], 199 | ["!=", "intermittent", 1] 200 | ], 201 | "id": "waterway", 202 | "paint": { 203 | "line-color": "hsl(205, 56%, 73%)", 204 | "line-opacity": 1, 205 | "line-width": { 206 | "base": 1.4, 207 | "stops": [ 208 | [8, 1], 209 | [20, 8] 210 | ] 211 | } 212 | }, 213 | "source": "openmaptiles", 214 | "source-layer": "waterway", 215 | "type": "line", 216 | "layout": { 217 | "visibility": "visible" 218 | } 219 | }, { 220 | "filter": ["all", ["==", "$type", "LineString"], 221 | ["!in", "brunnel", "tunnel", "bridge"], 222 | ["==", "intermittent", 1] 223 | ], 224 | "id": "waterway_intermittent", 225 | "paint": { 226 | "line-color": "hsl(205, 56%, 73%)", 227 | "line-opacity": 1, 228 | "line-width": { 229 | "base": 1.4, 230 | "stops": [ 231 | [8, 1], 232 | [20, 8] 233 | ] 234 | }, 235 | "line-dasharray": [2, 1] 236 | }, 237 | "source": "openmaptiles", 238 | "source-layer": "waterway", 239 | "type": "line", 240 | "layout": { 241 | "visibility": "visible" 242 | } 243 | }, { 244 | "filter": ["all", ["==", "$type", "LineString"], 245 | ["==", "brunnel", "tunnel"], 246 | ["==", "class", "transit"] 247 | ], 248 | "id": "tunnel_railway_transit", 249 | "layout": { 250 | "line-cap": "butt", 251 | "line-join": "miter" 252 | }, 253 | "minzoom": 0, 254 | "paint": { 255 | "line-color": "hsl(34, 12%, 66%)", 256 | "line-dasharray": [3, 3], 257 | "line-opacity": { 258 | "base": 1, 259 | "stops": [ 260 | [11, 0], 261 | [16, 1] 262 | ] 263 | } 264 | }, 265 | "source": "openmaptiles", 266 | "source-layer": "transportation", 267 | "type": "line" 268 | }, { 269 | "id": "building", 270 | "paint": { 271 | "fill-antialias": true, 272 | "fill-color": "rgba(222, 211, 190, 1)", 273 | "fill-opacity": { 274 | "base": 1, 275 | "stops": [ 276 | [13, 0], 277 | [15, 1] 278 | ] 279 | }, 280 | "fill-outline-color": { 281 | "stops": [ 282 | [15, "rgba(212, 177, 146, 0)"], 283 | [16, "rgba(212, 177, 146, 0.5)"] 284 | ] 285 | } 286 | }, 287 | "source": "openmaptiles", 288 | "source-layer": "building", 289 | "type": "fill" 290 | }, { 291 | "filter": ["==", "$type", "Point"], 292 | "id": "housenumber", 293 | "layout": { 294 | "text-field": "{housenumber}", 295 | "text-font": ["Noto Sans Regular"], 296 | "text-size": 10 297 | }, 298 | "minzoom": 17, 299 | "paint": { 300 | "text-color": "rgba(212, 177, 146, 1)" 301 | }, 302 | "source": "openmaptiles", 303 | "source-layer": "housenumber", 304 | "type": "symbol" 305 | }, { 306 | "id": "road_area_pier", 307 | "type": "fill", 308 | "metadata": {}, 309 | "source": "openmaptiles", 310 | "source-layer": "transportation", 311 | "filter": ["all", ["==", "$type", "Polygon"], 312 | ["==", "class", "pier"] 313 | ], 314 | "layout": { 315 | "visibility": "visible" 316 | }, 317 | "paint": { 318 | "fill-color": "hsl(47, 26%, 88%)", 319 | "fill-antialias": true 320 | } 321 | }, { 322 | "id": "road_pier", 323 | "type": "line", 324 | "metadata": {}, 325 | "source": "openmaptiles", 326 | "source-layer": "transportation", 327 | "filter": ["all", ["==", "$type", "LineString"], 328 | ["in", "class", "pier"] 329 | ], 330 | "layout": { 331 | "line-cap": "round", 332 | "line-join": "round" 333 | }, 334 | "paint": { 335 | "line-color": "hsl(47, 26%, 88%)", 336 | "line-width": { 337 | "base": 1.2, 338 | "stops": [ 339 | [15, 1], 340 | [17, 4] 341 | ] 342 | } 343 | } 344 | }, { 345 | "filter": ["all", ["==", "$type", "Polygon"], 346 | ["in", "brunnel", "bridge"] 347 | ], 348 | "id": "road_bridge_area", 349 | "layout": {}, 350 | "paint": { 351 | "fill-color": "hsl(47, 26%, 88%)", 352 | "fill-opacity": 0.5 353 | }, 354 | "source": "openmaptiles", 355 | "source-layer": "transportation", 356 | "type": "fill" 357 | }, { 358 | "filter": ["all", ["==", "$type", "LineString"], 359 | ["in", "class", "path", "track"] 360 | ], 361 | "id": "road_path", 362 | "layout": { 363 | "line-cap": "square", 364 | "line-join": "bevel" 365 | }, 366 | "paint": { 367 | "line-color": "hsl(0, 0%, 97%)", 368 | "line-dasharray": [1, 1], 369 | "line-width": { 370 | "base": 1.55, 371 | "stops": [ 372 | [4, 0.25], 373 | [20, 10] 374 | ] 375 | } 376 | }, 377 | "source": "openmaptiles", 378 | "source-layer": "transportation", 379 | "type": "line" 380 | }, { 381 | "filter": ["all", ["==", "$type", "LineString"], 382 | ["in", "class", "minor", "service"] 383 | ], 384 | "id": "road_minor", 385 | "layout": { 386 | "line-cap": "round", 387 | "line-join": "round" 388 | }, 389 | "paint": { 390 | "line-color": "hsl(0, 0%, 97%)", 391 | "line-width": { 392 | "base": 1.55, 393 | "stops": [ 394 | [4, 0.25], 395 | [20, 30] 396 | ] 397 | } 398 | }, 399 | "source": "openmaptiles", 400 | "source-layer": "transportation", 401 | "type": "line", 402 | "minzoom": 13 403 | }, { 404 | "filter": ["all", ["==", "$type", "LineString"], 405 | ["==", "brunnel", "tunnel"], 406 | ["==", "class", "minor_road"] 407 | ], 408 | "id": "tunnel_minor", 409 | "layout": { 410 | "line-cap": "butt", 411 | "line-join": "miter" 412 | }, 413 | "paint": { 414 | "line-color": "#efefef", 415 | "line-dasharray": [0.36, 0.18], 416 | "line-width": { 417 | "base": 1.55, 418 | "stops": [ 419 | [4, 0.25], 420 | [20, 30] 421 | ] 422 | } 423 | }, 424 | "source": "openmaptiles", 425 | "source-layer": "transportation", 426 | "type": "line" 427 | }, { 428 | "filter": ["all", ["==", "$type", "LineString"], 429 | ["==", "brunnel", "tunnel"], 430 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 431 | ], 432 | "id": "tunnel_major", 433 | "layout": { 434 | "line-cap": "butt", 435 | "line-join": "miter" 436 | }, 437 | "paint": { 438 | "line-color": "#fff", 439 | "line-dasharray": [0.28, 0.14], 440 | "line-width": { 441 | "base": 1.4, 442 | "stops": [ 443 | [6, 0.5], 444 | [20, 30] 445 | ] 446 | } 447 | }, 448 | "source": "openmaptiles", 449 | "source-layer": "transportation", 450 | "type": "line" 451 | }, { 452 | "filter": ["all", ["==", "$type", "Polygon"], 453 | ["in", "class", "runway", "taxiway"] 454 | ], 455 | "id": "aeroway-area", 456 | "layout": { 457 | "visibility": "visible" 458 | }, 459 | "metadata": { 460 | "mapbox:group": "1444849345966.4436" 461 | }, 462 | "minzoom": 4, 463 | "paint": { 464 | "fill-color": "rgba(255, 255, 255, 1)", 465 | "fill-opacity": { 466 | "base": 1, 467 | "stops": [ 468 | [13, 0], 469 | [14, 1] 470 | ] 471 | } 472 | }, 473 | "source": "openmaptiles", 474 | "source-layer": "aeroway", 475 | "type": "fill" 476 | }, { 477 | "filter": ["all", ["in", "class", "taxiway"], 478 | ["==", "$type", "LineString"] 479 | ], 480 | "id": "aeroway-taxiway", 481 | "layout": { 482 | "line-cap": "round", 483 | "line-join": "round", 484 | "visibility": "visible" 485 | }, 486 | "metadata": { 487 | "mapbox:group": "1444849345966.4436" 488 | }, 489 | "minzoom": 12, 490 | "paint": { 491 | "line-color": "rgba(255, 255, 255, 1)", 492 | "line-opacity": 1, 493 | "line-width": { 494 | "base": 1.5, 495 | "stops": [ 496 | [12, 1], 497 | [17, 10] 498 | ] 499 | } 500 | }, 501 | "source": "openmaptiles", 502 | "source-layer": "aeroway", 503 | "type": "line" 504 | }, { 505 | "filter": ["all", ["in", "class", "runway"], 506 | ["==", "$type", "LineString"] 507 | ], 508 | "id": "aeroway-runway", 509 | "layout": { 510 | "line-cap": "round", 511 | "line-join": "round", 512 | "visibility": "visible" 513 | }, 514 | "metadata": { 515 | "mapbox:group": "1444849345966.4436" 516 | }, 517 | "minzoom": 4, 518 | "paint": { 519 | "line-color": "rgba(255, 255, 255, 1)", 520 | "line-opacity": 1, 521 | "line-width": { 522 | "base": 1.5, 523 | "stops": [ 524 | [11, 4], 525 | [17, 50] 526 | ] 527 | } 528 | }, 529 | "source": "openmaptiles", 530 | "source-layer": "aeroway", 531 | "type": "line" 532 | }, { 533 | "filter": ["all", ["==", "$type", "LineString"], 534 | ["in", "class", "trunk", "primary"] 535 | ], 536 | "id": "road_trunk_primary", 537 | "layout": { 538 | "line-cap": "round", 539 | "line-join": "round" 540 | }, 541 | "paint": { 542 | "line-color": "#fff", 543 | "line-width": { 544 | "base": 1.4, 545 | "stops": [ 546 | [6, 0.5], 547 | [20, 30] 548 | ] 549 | } 550 | }, 551 | "source": "openmaptiles", 552 | "source-layer": "transportation", 553 | "type": "line" 554 | }, { 555 | "filter": ["all", ["==", "$type", "LineString"], 556 | ["in", "class", "secondary", "tertiary"] 557 | ], 558 | "id": "road_secondary_tertiary", 559 | "layout": { 560 | "line-cap": "round", 561 | "line-join": "round" 562 | }, 563 | "paint": { 564 | "line-color": "#fff", 565 | "line-width": { 566 | "base": 1.4, 567 | "stops": [ 568 | [6, 0.5], 569 | [20, 20] 570 | ] 571 | } 572 | }, 573 | "source": "openmaptiles", 574 | "source-layer": "transportation", 575 | "type": "line" 576 | }, { 577 | "filter": ["all", ["==", "$type", "LineString"], 578 | ["==", "class", "motorway"] 579 | ], 580 | "id": "road_major_motorway", 581 | "layout": { 582 | "line-cap": "round", 583 | "line-join": "round" 584 | }, 585 | "paint": { 586 | "line-color": "hsl(0, 0%, 100%)", 587 | "line-offset": 0, 588 | "line-width": { 589 | "base": 1.4, 590 | "stops": [ 591 | [8, 1], 592 | [16, 10] 593 | ] 594 | } 595 | }, 596 | "source": "openmaptiles", 597 | "source-layer": "transportation", 598 | "type": "line" 599 | }, { 600 | "filter": ["all", ["==", "class", "transit"], 601 | ["!=", "brunnel", "tunnel"] 602 | ], 603 | "id": "railway-transit", 604 | "layout": { 605 | "visibility": "visible" 606 | }, 607 | "paint": { 608 | "line-color": "hsl(34, 12%, 66%)", 609 | "line-opacity": { 610 | "base": 1, 611 | "stops": [ 612 | [11, 0], 613 | [16, 1] 614 | ] 615 | } 616 | }, 617 | "source": "openmaptiles", 618 | "source-layer": "transportation", 619 | "type": "line" 620 | }, { 621 | "filter": ["==", "class", "rail"], 622 | "id": "railway", 623 | "layout": { 624 | "visibility": "visible" 625 | }, 626 | "paint": { 627 | "line-color": "hsl(34, 12%, 66%)", 628 | "line-opacity": { 629 | "base": 1, 630 | "stops": [ 631 | [11, 0], 632 | [16, 1] 633 | ] 634 | } 635 | }, 636 | "source": "openmaptiles", 637 | "source-layer": "transportation", 638 | "type": "line" 639 | }, { 640 | "filter": ["all", ["==", "$type", "LineString"], 641 | ["==", "brunnel", "bridge"] 642 | ], 643 | "id": "waterway-bridge-case", 644 | "layout": { 645 | "line-cap": "butt", 646 | "line-join": "miter" 647 | }, 648 | "paint": { 649 | "line-color": "#bbbbbb", 650 | "line-gap-width": { 651 | "base": 1.55, 652 | "stops": [ 653 | [4, 0.25], 654 | [20, 30] 655 | ] 656 | }, 657 | "line-width": { 658 | "base": 1.6, 659 | "stops": [ 660 | [12, 0.5], 661 | [20, 10] 662 | ] 663 | } 664 | }, 665 | "source": "openmaptiles", 666 | "source-layer": "waterway", 667 | "type": "line" 668 | }, { 669 | "filter": ["all", ["==", "$type", "LineString"], 670 | ["==", "brunnel", "bridge"] 671 | ], 672 | "id": "waterway-bridge", 673 | "layout": { 674 | "line-cap": "round", 675 | "line-join": "round" 676 | }, 677 | "paint": { 678 | "line-color": "hsl(205, 56%, 73%)", 679 | "line-width": { 680 | "base": 1.55, 681 | "stops": [ 682 | [4, 0.25], 683 | [20, 30] 684 | ] 685 | } 686 | }, 687 | "source": "openmaptiles", 688 | "source-layer": "waterway", 689 | "type": "line" 690 | }, { 691 | "filter": ["all", ["==", "$type", "LineString"], 692 | ["==", "brunnel", "bridge"], 693 | ["==", "class", "minor_road"] 694 | ], 695 | "id": "bridge_minor case", 696 | "layout": { 697 | "line-cap": "butt", 698 | "line-join": "miter" 699 | }, 700 | "paint": { 701 | "line-color": "#dedede", 702 | "line-gap-width": { 703 | "base": 1.55, 704 | "stops": [ 705 | [4, 0.25], 706 | [20, 30] 707 | ] 708 | }, 709 | "line-width": { 710 | "base": 1.6, 711 | "stops": [ 712 | [12, 0.5], 713 | [20, 10] 714 | ] 715 | } 716 | }, 717 | "source": "openmaptiles", 718 | "source-layer": "transportation", 719 | "type": "line" 720 | }, { 721 | "filter": ["all", ["==", "$type", "LineString"], 722 | ["==", "brunnel", "bridge"], 723 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 724 | ], 725 | "id": "bridge_major case", 726 | "layout": { 727 | "line-cap": "butt", 728 | "line-join": "miter" 729 | }, 730 | "paint": { 731 | "line-color": "#dedede", 732 | "line-gap-width": { 733 | "base": 1.55, 734 | "stops": [ 735 | [4, 0.25], 736 | [20, 30] 737 | ] 738 | }, 739 | "line-width": { 740 | "base": 1.6, 741 | "stops": [ 742 | [12, 0.5], 743 | [20, 10] 744 | ] 745 | } 746 | }, 747 | "source": "openmaptiles", 748 | "source-layer": "transportation", 749 | "type": "line" 750 | }, { 751 | "filter": ["all", ["==", "$type", "LineString"], 752 | ["==", "brunnel", "bridge"], 753 | ["==", "class", "minor_road"] 754 | ], 755 | "id": "bridge_minor", 756 | "layout": { 757 | "line-cap": "round", 758 | "line-join": "round" 759 | }, 760 | "paint": { 761 | "line-color": "#efefef", 762 | "line-width": { 763 | "base": 1.55, 764 | "stops": [ 765 | [4, 0.25], 766 | [20, 30] 767 | ] 768 | } 769 | }, 770 | "source": "openmaptiles", 771 | "source-layer": "transportation", 772 | "type": "line" 773 | }, { 774 | "filter": ["all", ["==", "$type", "LineString"], 775 | ["==", "brunnel", "bridge"], 776 | ["in", "class", "primary", "secondary", "tertiary", "trunk"] 777 | ], 778 | "id": "bridge_major", 779 | "layout": { 780 | "line-cap": "round", 781 | "line-join": "round" 782 | }, 783 | "paint": { 784 | "line-color": "#fff", 785 | "line-width": { 786 | "base": 1.4, 787 | "stops": [ 788 | [6, 0.5], 789 | [20, 30] 790 | ] 791 | } 792 | }, 793 | "source": "openmaptiles", 794 | "source-layer": "transportation", 795 | "type": "line" 796 | }, { 797 | "filter": ["in", "admin_level", 4, 6, 8], 798 | "id": "admin_sub", 799 | "layout": { 800 | "visibility": "visible" 801 | }, 802 | "paint": { 803 | "line-color": "hsla(0, 0%, 60%, 0.5)", 804 | "line-dasharray": [2, 1] 805 | }, 806 | "source": "openmaptiles", 807 | "source-layer": "boundary", 808 | "type": "line" 809 | }, { 810 | "filter": ["all", ["<=", "admin_level", 2], 811 | ["==", "$type", "LineString"] 812 | ], 813 | "id": "admin_country", 814 | "layout": { 815 | "line-cap": "round", 816 | "line-join": "round" 817 | }, 818 | "paint": { 819 | "line-color": "hsl(0, 0%, 60%)", 820 | "line-width": { 821 | "base": 1.3, 822 | "stops": [ 823 | [3, 0.5], 824 | [22, 15] 825 | ] 826 | } 827 | }, 828 | "source": "openmaptiles", 829 | "source-layer": "boundary", 830 | "type": "line" 831 | }, { 832 | "filter": ["all", ["==", "$type", "Point"], 833 | ["==", "rank", 1] 834 | ], 835 | "id": "poi_label", 836 | "layout": { 837 | "icon-size": 1, 838 | "text-anchor": "top", 839 | "text-field": "{name:latin}\n{name:nonlatin}", 840 | "text-font": ["Noto Sans Regular"], 841 | "text-max-width": 8, 842 | "text-offset": [0, 0.5], 843 | "text-size": 11, 844 | "visibility": "visible" 845 | }, 846 | "minzoom": 14, 847 | "paint": { 848 | "text-color": "#666", 849 | "text-halo-blur": 1, 850 | "text-halo-color": "rgba(255,255,255,0.75)", 851 | "text-halo-width": 1 852 | }, 853 | "source": "openmaptiles", 854 | "source-layer": "poi", 855 | "type": "symbol" 856 | }, { 857 | "filter": ["all", ["has", "iata"]], 858 | "id": "airport-label", 859 | "layout": { 860 | "icon-size": 1, 861 | "text-anchor": "top", 862 | "text-field": "{name:latin}\n{name:nonlatin}", 863 | "text-font": ["Noto Sans Regular"], 864 | "text-max-width": 8, 865 | "text-offset": [0, 0.5], 866 | "text-size": 11, 867 | "visibility": "visible" 868 | }, 869 | "minzoom": 10, 870 | "paint": { 871 | "text-color": "#666", 872 | "text-halo-blur": 1, 873 | "text-halo-color": "rgba(255,255,255,0.75)", 874 | "text-halo-width": 1 875 | }, 876 | "source": "openmaptiles", 877 | "source-layer": "aerodrome_label", 878 | "type": "symbol" 879 | }, { 880 | "filter": ["==", "$type", "LineString"], 881 | "id": "road_major_label", 882 | "layout": { 883 | "symbol-placement": "line", 884 | "text-field": "{name:latin} {name:nonlatin}", 885 | "text-font": ["Noto Sans Regular"], 886 | "text-letter-spacing": 0.1, 887 | "text-rotation-alignment": "map", 888 | "text-size": { 889 | "base": 1.4, 890 | "stops": [ 891 | [10, 8], 892 | [20, 14] 893 | ] 894 | }, 895 | "text-transform": "uppercase" 896 | }, 897 | "paint": { 898 | "text-color": "#000", 899 | "text-halo-color": "hsl(0, 0%, 100%)", 900 | "text-halo-width": 2 901 | }, 902 | "source": "openmaptiles", 903 | "source-layer": "transportation_name", 904 | "type": "symbol" 905 | }, { 906 | "filter": ["all", ["==", "$type", "Point"], 907 | ["!in", "class", "city", "state", "country", "continent"] 908 | ], 909 | "id": "place_label_other", 910 | "layout": { 911 | "text-anchor": "center", 912 | "text-field": "{name:latin}\n{name:nonlatin}", 913 | "text-font": ["Noto Sans Regular"], 914 | "text-max-width": 6, 915 | "text-size": { 916 | "stops": [ 917 | [6, 10], 918 | [12, 14] 919 | ] 920 | }, 921 | "visibility": "visible" 922 | }, 923 | "minzoom": 8, 924 | "paint": { 925 | "text-color": "hsl(0, 0%, 25%)", 926 | "text-halo-blur": 0, 927 | "text-halo-color": "hsl(0, 0%, 100%)", 928 | "text-halo-width": 2 929 | }, 930 | "source": "openmaptiles", 931 | "source-layer": "place", 932 | "type": "symbol" 933 | }, { 934 | "filter": ["all", ["==", "$type", "Point"], 935 | ["==", "class", "city"] 936 | ], 937 | "id": "place_label_city", 938 | "layout": { 939 | "text-field": "{name:latin}\n{name:nonlatin}", 940 | "text-font": ["Noto Sans Regular"], 941 | "text-max-width": 10, 942 | "text-size": { 943 | "stops": [ 944 | [3, 12], 945 | [8, 16] 946 | ] 947 | } 948 | }, 949 | "maxzoom": 16, 950 | "paint": { 951 | "text-color": "hsl(0, 0%, 0%)", 952 | "text-halo-blur": 0, 953 | "text-halo-color": "hsla(0, 0%, 100%, 0.75)", 954 | "text-halo-width": 2 955 | }, 956 | "source": "openmaptiles", 957 | "source-layer": "place", 958 | "type": "symbol" 959 | }, { 960 | "filter": ["all", ["==", "$type", "Point"], 961 | ["==", "class", "country"], 962 | ["!has", "iso_a2"] 963 | ], 964 | "id": "country_label-other", 965 | "layout": { 966 | "text-field": "{name:latin}", 967 | "text-font": ["Noto Sans Regular"], 968 | "text-max-width": 10, 969 | "text-size": { 970 | "stops": [ 971 | [3, 12], 972 | [8, 22] 973 | ] 974 | }, 975 | "visibility": "visible" 976 | }, 977 | "maxzoom": 12, 978 | "paint": { 979 | "text-color": "hsl(0, 0%, 13%)", 980 | "text-halo-blur": 0, 981 | "text-halo-color": "rgba(255,255,255,0.75)", 982 | "text-halo-width": 2 983 | }, 984 | "source": "openmaptiles", 985 | "source-layer": "place", 986 | "type": "symbol" 987 | }, { 988 | "filter": ["all", ["==", "$type", "Point"], 989 | ["==", "class", "country"], 990 | ["has", "iso_a2"] 991 | ], 992 | "id": "country_label", 993 | "layout": { 994 | "text-field": "{name:latin}", 995 | "text-font": ["Noto Sans Bold"], 996 | "text-max-width": 10, 997 | "text-size": { 998 | "stops": [ 999 | [3, 12], 1000 | [8, 22] 1001 | ] 1002 | }, 1003 | "visibility": "visible" 1004 | }, 1005 | "maxzoom": 12, 1006 | "paint": { 1007 | "text-color": "hsl(0, 0%, 13%)", 1008 | "text-halo-blur": 0, 1009 | "text-halo-color": "rgba(255,255,255,0.75)", 1010 | "text-halo-width": 2 1011 | }, 1012 | "source": "openmaptiles", 1013 | "source-layer": "place", 1014 | "type": "symbol" 1015 | }], 1016 | "id": "basic" 1017 | } 1018 | -------------------------------------------------------------------------------- /examples/set-center-zoom/main.js: -------------------------------------------------------------------------------- 1 | import * as yawgl from "yawgl"; 2 | import * as tileMap from "../../"; 3 | 4 | export function main() { 5 | const canvas = document.getElementById("mapCanvas"); 6 | yawgl.resizeCanvasToDisplaySize(canvas, window.devicePixelRatio); 7 | const context = yawgl.initContext(canvas); 8 | 9 | tileMap.init({ context, style: "./klokantech-basic-style.json" }) 10 | .promise.then(api => setup(api, canvas)) 11 | .catch(console.log); 12 | } 13 | 14 | function setup(api, canvas) { 15 | const loadStatus = document.getElementById("loadStatus"); 16 | const control = { 17 | longitude: document.getElementById("longitude"), 18 | latitude: document.getElementById("latitude"), 19 | zoom: document.getElementById("zoom"), 20 | }; 21 | const camPos = document.getElementById("camPos"); 22 | const actualZoom = document.getElementById("actualZoom"); 23 | 24 | requestAnimationFrame(animate); 25 | function animate() { 26 | const pixRatio = window.devicePixelRatio; 27 | yawgl.resizeCanvasToDisplaySize(canvas, pixRatio); 28 | 29 | const [longitude, latitude, zoom] = Object.values(control) 30 | .map(v => v.valueAsNumber); 31 | api.setCenterZoom([longitude, latitude], zoom); 32 | 33 | const percent = api.draw({ pixRatio }) * 100; 34 | loadStatus.innerHTML = (percent < 100) 35 | ? "Loading: " + percent.toFixed(0) + "%" 36 | : "Complete! " + percent.toFixed(0) + "%"; 37 | 38 | camPos.innerHTML = api.getCamPos().join(", "); 39 | actualZoom.innerHTML = Math.log2(api.getTransform().k) - 9; 40 | 41 | requestAnimationFrame(animate); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/set-center-zoom/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | body { 5 | border: 0; 6 | margin: 0; 7 | font-family: "Noto Sans"; 8 | font-size: 14px; 9 | } 10 | #main { 11 | width: 900px; 12 | height: 600px; 13 | position: relative; 14 | } 15 | #mapCanvas { 16 | width: 100%; 17 | height: 100%; 18 | display: block; 19 | background-color: gray; 20 | position: relative; 21 | } 22 | .attribution { 23 | background: rgba(255, 255, 255, 0.8); 24 | position: absolute; 25 | bottom: 0; 26 | right: 0; 27 | padding: 0 4px 0 4px; 28 | } 29 | #loadStatus { 30 | position: absolute; 31 | top: 0; 32 | right: 0; 33 | width: 15ch; 34 | text-align: right; 35 | background: rgba(60, 60, 60, 0.5); 36 | color: white; 37 | padding: 0 4px 0 4px; 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tile-setter", 3 | "version": "0.1.12", 4 | "description": "Tiled vector map powered by a lightweight WebGL renderer", 5 | "main": "dist/tile-setter.js", 6 | "directories": {}, 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "lint": "eslint src", 12 | "build": "npm run build-module && npm run build-examples", 13 | "build-module": "rollup -c build/rollup.config.js", 14 | "build-examples": "cd examples && rollup -c", 15 | "test": "npm run lint", 16 | "postversion": "git push && git push --tags" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/GlobeletJS/tile-setter.git" 21 | }, 22 | "keywords": [ 23 | "tiled", 24 | "vector", 25 | "map", 26 | "interactive" 27 | ], 28 | "author": "Jeshurun Hembd", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/GlobeletJS/tile-setter/issues" 32 | }, 33 | "homepage": "https://github.com/GlobeletJS/tile-setter#readme", 34 | "devDependencies": { 35 | "@rollup/plugin-commonjs": "^21.0.1", 36 | "@rollup/plugin-node-resolve": "^13.1.3", 37 | "@turf/boolean-point-in-polygon": "^6.0.1", 38 | "d3": "^6.2.0", 39 | "eslint": "^8.12.0", 40 | "eslint-config-globeletjs": "^0.0.6", 41 | "rollup": "^2.70.1", 42 | "yawgl": "^0.4.2" 43 | }, 44 | "dependencies": { 45 | "chunked-queue": "^0.1.4", 46 | "d3-tile": "github:GlobeletJS/d3-tile", 47 | "tile-batch": "^0.0.3", 48 | "tile-rack": "^1.0.4", 49 | "tile-stencil": "^0.4.12", 50 | "tile-worker": "^0.1.8" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/bounds.js: -------------------------------------------------------------------------------- 1 | import { forward } from "./projection.js"; 2 | 3 | export function initBoundsCheck(source) { 4 | const { 5 | minzoom = 0, 6 | maxzoom = 30, 7 | bounds = [-180, -90, 180, 90], 8 | scheme = "xyz", 9 | } = source; 10 | 11 | // Convert bounds to Web Mercator (the projection ASSUMED by tilejson-spec) 12 | const radianBounds = bounds.map(c => c * Math.PI / 180.0); 13 | let [xmin, ymax] = forward(radianBounds.slice(0, 2)); 14 | let [xmax, ymin] = forward(radianBounds.slice(2, 4)); 15 | // TODO: this looks weird? min/max is mathematical, regardless of scheme 16 | if (scheme === "tms") [ymin, ymax] = [ymax, ymin]; 17 | 18 | return function(z, x, y) { 19 | // Return true if out of bounds 20 | if (z < minzoom || maxzoom < z) return true; 21 | 22 | const zFac = 1 / 2 ** z; 23 | if ((x + 1) * zFac < xmin || xmax < x * zFac) return true; 24 | if ((y + 1) * zFac < ymin || ymax < y * zFac) return true; 25 | 26 | return false; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/caches.js: -------------------------------------------------------------------------------- 1 | import * as chunkedQueue from "chunked-queue"; 2 | import * as tileWorker from "tile-worker"; 3 | import { initCache } from "tile-rack"; 4 | 5 | export function initCaches({ context, glyphs, spriteData }) { 6 | const queue = chunkedQueue.init(); 7 | 8 | function addSource({ source, layers }) { 9 | const loader = initLoader(source, layers); 10 | const factory = buildFactory(loader); 11 | return initCache({ create: factory, size: 1.0 }); 12 | } 13 | 14 | function initLoader(source, layers) { 15 | switch (source.type) { 16 | case "vector": 17 | case "geojson": 18 | return tileWorker.init({ 19 | context, queue, source, glyphs, spriteData, layers, 20 | threads: (source.type === "geojson") ? 1 : 2, 21 | }); 22 | case "raster": 23 | return; // initRasterLoader(source, layers); 24 | default: return; 25 | } 26 | } 27 | 28 | return { 29 | addSource, 30 | sortTasks: queue.sortTasks, 31 | queuedTasks: queue.countTasks, 32 | }; 33 | } 34 | 35 | function buildFactory(loader) { 36 | return function(z, x, y) { 37 | const id = [z, x, y].join("/"); 38 | const tile = { z, x, y, id, priority: 0 }; 39 | 40 | function callback(err, data) { 41 | if (err) return; // console.log(err); 42 | tile.data = data; 43 | tile.ready = true; 44 | } 45 | 46 | const getPriority = () => tile.priority; 47 | const loadTask = loader.request({ z, x, y, getPriority, callback }); 48 | 49 | tile.cancel = () => { 50 | loadTask.abort(); 51 | tile.canceled = true; 52 | }; 53 | 54 | return tile; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/coords.js: -------------------------------------------------------------------------------- 1 | export function initCoords({ getViewport, center, zoom, clampY, projection }) { 2 | const { log2, min, max, round, floor } = Math; 3 | const minTileSize = 256; 4 | const logTileSize = log2(minTileSize); 5 | 6 | const transform = { 7 | k: 1, // Size of the world map, in pixels 8 | x: 0, // Rightward shift of lon = 0 from left edge of viewport, in pixels 9 | y: 0, // Downward shift of lat = 0 from top edge of viewport, in pixels 10 | }; 11 | const camPos = new Float64Array([0.5, 0.5]); 12 | const scale = new Float64Array([1.0, 1.0]); 13 | 14 | setCenterZoom(center, zoom); 15 | 16 | return { 17 | getViewport, 18 | getTransform: () => Object.assign({}, transform), 19 | getZoom: () => max(0, log2(transform.k) - 9), 20 | getCamPos: () => camPos.slice(), 21 | getScale: () => scale.slice(), 22 | 23 | setTransform, 24 | setCenterZoom, 25 | 26 | localToGlobal, 27 | }; 28 | 29 | function setTransform({ k, x, y }) { 30 | // Input transforms map coordinates [x, y] into viewport coordinates 31 | const [width, height] = getViewport(); 32 | 33 | // Round k to ensure tile pixels align with screen pixels 34 | const z = log2(k) - logTileSize; 35 | const z0 = floor(z); 36 | const tileScale = round(2 ** (z - z0) * minTileSize); 37 | const kNew = clampY 38 | ? max(2 ** z0 * tileScale, height) 39 | : 2 ** z0 * tileScale; 40 | 41 | // Adjust translation for the change in scale, and snap to pixel grid 42 | const kScale = kNew / k; 43 | // Keep the same map pixel at the center of the viewport 44 | const sx = kScale * x + (1 - kScale) * width / 2; 45 | const sy = kScale * y + (1 - kScale) * height / 2; 46 | // Limit Y so the map doesn't cross a pole 47 | const yLim = clampY 48 | ? min(max(-kNew / 2 + height, sy), kNew / 2) 49 | : sy; 50 | const [xNew, yNew] = [sx, yLim].map(round); 51 | 52 | // Make sure camera is still pointing at the original location: shift from 53 | // the center [0.5, 0.5] by the change in the translation due to rounding 54 | camPos[0] = 0.5 + (xNew - sx) / width; 55 | camPos[1] = 0.5 + (yNew - sy) / height; 56 | 57 | // Store the scale of the current map relative to the entire world 58 | scale[0] = kNew / width; 59 | scale[1] = kNew / height; 60 | 61 | // Return a flag indicating whether the transform changed 62 | const { k: kOld, x: xOld, y: yOld } = transform; 63 | if (kNew == kOld && xNew == xOld && yNew == yOld) return false; 64 | Object.assign(transform, { k: kNew, x: xNew, y: yNew }); 65 | return true; 66 | } 67 | 68 | function setCenterZoom(center, zoom) { 69 | const [width, height] = getViewport(); 70 | 71 | const k = 512 * 2 ** zoom; 72 | const [xr, yr] = projection.forward(center); 73 | const x = (0.5 - xr) * k + width / 2; 74 | const y = (0.5 - yr) * k + height / 2; 75 | 76 | return setTransform({ k, x, y }); 77 | } 78 | 79 | function localToGlobal([xl, yl]) { 80 | // Convert local map pixels to global XY 81 | const { x: tx, y: ty, k } = transform; 82 | // tx, ty is the shift of the map center (in pixels) 83 | // relative to the viewport origin (top left corner) 84 | const xg = (xl - tx) / k + 0.5; 85 | const yg = (yl - ty) / k + 0.5; 86 | // Global XY are in the range [0.0, 1.0]. Wrap values outside 87 | return [xg - floor(xg), yg - floor(yg)]; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/feature-coords.js: -------------------------------------------------------------------------------- 1 | export function transformFeatureCoords(feature, transform) { 2 | const { type, properties, geometry } = feature; 3 | 4 | return { 5 | type, properties, 6 | geometry: transformGeometry(geometry, transform), 7 | }; 8 | } 9 | 10 | function transformGeometry(geometry, transform) { 11 | const { type, coordinates } = geometry; 12 | 13 | return { 14 | type, 15 | coordinates: transformCoords(type, coordinates, transform), 16 | }; 17 | } 18 | 19 | function transformCoords(type, coordinates, transform) { 20 | switch (type) { 21 | case "Point": 22 | return transform(coordinates); 23 | 24 | case "MultiPoint": 25 | case "LineString": 26 | return coordinates.map(transform); 27 | 28 | case "MultiLineString": 29 | case "Polygon": 30 | return coordinates.map(ring => ring.map(transform)); 31 | 32 | case "MultiPolygon": 33 | return coordinates.map(polygon => { 34 | return polygon.map(ring => ring.map(transform)); 35 | }); 36 | 37 | default: 38 | throw Error("transformCoords: unknown geometry type!"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/grid.js: -------------------------------------------------------------------------------- 1 | import { initBoundsCheck } from "./bounds.js"; 2 | import * as d3 from "d3-tile"; 3 | import { getTileMetric } from "./metric.js"; 4 | 5 | export function initTileGrid({ key, source, tileCache }) { 6 | const { tileSize = 512, maxzoom = 30 } = source; 7 | const outOfBounds = initBoundsCheck(source); 8 | 9 | let numTiles = 0; 10 | 11 | // Set up the tile layout 12 | const layout = d3.tile() 13 | .tileSize(tileSize * Math.sqrt(2)) // Don't let d3-tile squeeze the tiles 14 | .maxZoom(maxzoom) 15 | .clampX(false); // Allow panning across the antimeridian 16 | 17 | function getTiles(viewport, transform) { 18 | // Get the grid of tiles needed for the current viewport 19 | layout.size(viewport); 20 | const tiles = layout(transform); 21 | 22 | // Update tile priorities based on the new grid 23 | const metric = getTileMetric(layout, tiles, 1.0); 24 | tileCache.process(tile => { tile.priority = metric(tile); }); 25 | numTiles = tileCache.drop(tile => tile.priority > 0.8); 26 | const stopCondition = ([z, x, y]) => { 27 | return outOfBounds(z, x, y) || metric({ z, x, y }) > 0.8; 28 | }; 29 | 30 | // Retrieve a tile box for every tile in the grid 31 | let tilesDone = 0; 32 | const grid = tiles.map(([x, y, z]) => { 33 | const [xw, yw, zw] = d3.tileWrap([x, y, z]); 34 | 35 | if (outOfBounds(zw, xw, yw)) { 36 | tilesDone += 1; // Count it as complete 37 | return; 38 | } 39 | 40 | const box = tileCache.retrieve([zw, xw, yw], stopCondition); 41 | if (!box) return; 42 | 43 | tilesDone += box.sw ** 2; 44 | return Object.assign(box, { x, xw, y, yw, z }); 45 | }).filter(t => t !== undefined); 46 | 47 | grid.loaded = tilesDone / tiles.length; 48 | grid.scale = tiles.scale; 49 | grid.translate = tiles.translate.slice(); 50 | 51 | return grid; 52 | } 53 | 54 | return { key, getTiles, numTiles: () => numTiles }; 55 | } 56 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { setParams } from "./params.js"; 2 | import { loadStyle } from "tile-stencil"; 3 | import { initSources } from "./sources.js"; 4 | import { initRenderer } from "./renderer.js"; 5 | import { initSelector } from "./selection.js"; 6 | 7 | export function init(userParams) { 8 | const params = setParams(userParams); 9 | 10 | // Set up dummy API 11 | const api = { 12 | gl: params.gl, 13 | projection: params.projection, 14 | draw: () => null, 15 | select: () => null, 16 | }; 17 | 18 | // Extend with coordinate methods (SEE coords.js for API) 19 | Object.assign(api, params.coords); 20 | 21 | // Get style document, parse 22 | api.promise = loadStyle(params.style, params.mapboxToken) 23 | .then( styleDoc => setup(styleDoc, params, api) ); 24 | 25 | return api; 26 | } 27 | 28 | function setup(styleDoc, params, api) { 29 | const { context, coords, projection } = params; 30 | const sources = initSources(styleDoc, context, api); 31 | 32 | // Set up interactive toggling of layer visibility 33 | styleDoc.layers.forEach(l => { 34 | // TODO: use functionalized visibility from tile-stencil? 35 | const visibility = l.layout ? l.layout.visibility : false; 36 | l.visible = (!visibility || visibility === "visible"); 37 | }); 38 | 39 | function setLayerVisibility(id, visibility) { 40 | const layer = styleDoc.layers.find(l => l.id === id); 41 | if (layer) layer.visible = visibility; 42 | } 43 | api.hideLayer = (id) => setLayerVisibility(id, false); 44 | api.showLayer = (id) => setLayerVisibility(id, true); 45 | 46 | const render = initRenderer(context, coords, styleDoc); 47 | 48 | api.draw = function({ pixRatio = 1, dzScale = 1 } = {}) { 49 | const loadStatus = sources.loadTilesets(); 50 | render(sources.tilesets, pixRatio, dzScale); 51 | return loadStatus; 52 | }; 53 | 54 | api.select = initSelector(sources, projection); 55 | 56 | return api; 57 | } 58 | -------------------------------------------------------------------------------- /src/metric.js: -------------------------------------------------------------------------------- 1 | export function getTileMetric(layout, tileset, padding = 0.595) { 2 | const { min, max, sqrt } = Math; 3 | const zoom = tileset[0][2]; 4 | const nTiles = 2 ** zoom; 5 | const scaleFac = layout.tileSize() / tileset.scale; 6 | const mapResolution = min(max(1.0 / sqrt(2), scaleFac), sqrt(2)); 7 | 8 | function wrap(x, xmax) { 9 | while (x < 0) x += xmax; 10 | while (x >= xmax) x -= xmax; 11 | return x; 12 | } 13 | 14 | // Map is viewport + padding. Store the map cornerpoints in tile units 15 | const [vpWidth, vpHeight] = layout.size(); 16 | const pad = padding * mapResolution; // In tile units 17 | const x0 = wrap(-tileset.translate[0] - pad, nTiles); 18 | const x1 = x0 + vpWidth / tileset.scale + 2 * pad; // May cross antimeridian 19 | const y0 = -tileset.translate[1] - pad; 20 | const y1 = y0 + vpHeight / tileset.scale + 2 * pad; 21 | 22 | return function(tile) { 23 | const zoomFac = 2 ** (zoom - tile.z); 24 | const tileResolution = min(1, mapResolution / zoomFac); 25 | 26 | // Convert the tile cornerpoints to tile units at MAP zoom level 27 | const tb = { 28 | x0: tile.x * zoomFac, 29 | x1: (tile.x + 1) * zoomFac, 30 | y0: tile.y * zoomFac, 31 | y1: (tile.y + 1) * zoomFac 32 | }; 33 | 34 | // Find intersections of map and tile. Be careful with the antimeridian 35 | const xOverlap = max( 36 | // Test for intersection with the tile in its raw position 37 | min(x1, tb.x1) - max(x0, tb.x0), 38 | // Test with the tile shifted across the antimeridian 39 | min(x1, tb.x1 + nTiles) - max(x0, tb.x0 + nTiles) 40 | ); 41 | const yOverlap = min(y1, tb.y1) - max(y0, tb.y0); 42 | const overlapArea = max(0, xOverlap) * max(0, yOverlap); 43 | const visibleArea = overlapArea / mapResolution ** 2; 44 | 45 | // Flip sign to put most valuable tiles at the minimum. TODO: unnecessary? 46 | return 1.0 - visibleArea * tileResolution; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /src/params.js: -------------------------------------------------------------------------------- 1 | import { getProjection } from "./projection.js"; 2 | import { initCoords } from "./coords.js"; 3 | import { initGL as initGLpaint } from "tile-batch"; 4 | 5 | export function setParams(userParams) { 6 | const gl = userParams.context.gl; 7 | if (!(gl instanceof WebGL2RenderingContext)) fail("no valid WebGL context"); 8 | 9 | const { 10 | context, 11 | framebuffer = { buffer: null, size: gl.canvas }, 12 | center = [0.0, 0.0], // ASSUMED to be in degrees! 13 | zoom = 4, 14 | style, 15 | mapboxToken, 16 | clampY = true, 17 | units = "degrees", 18 | projScale = false, 19 | } = userParams; 20 | 21 | const { buffer, size } = framebuffer; 22 | if (!(buffer instanceof WebGLFramebuffer) && buffer !== null) { 23 | fail("no valid framebuffer"); 24 | } 25 | 26 | const sizeType = 27 | (size && allPosInts(size.clientWidth, size.clientHeight)) ? "client" : 28 | (size && allPosInts(size.width, size.height)) ? "raw" : 29 | null; 30 | if (!sizeType) fail("invalid size object in framebuffer"); 31 | const getViewport = (sizeType === "client") 32 | ? () => ([size.clientWidth, size.clientHeight]) 33 | : () => ([size.width, size.height]); 34 | 35 | const validUnits = ["degrees", "radians", "xy"]; 36 | if (!validUnits.includes(units)) fail("invalid units"); 37 | const projection = getProjection(units); 38 | 39 | // Convert initial center position from degrees to the specified units 40 | if (!checkCoords(center, 2)) fail("invalid center coordinates"); 41 | const projCenter = getProjection("degrees").forward(center); 42 | if (!all0to1(...projCenter)) fail ("invalid center coordinates"); 43 | const invCenter = projection.inverse(projCenter); 44 | 45 | if (!Number.isFinite(zoom)) fail("invalid zoom value"); 46 | 47 | const coords = initCoords({ 48 | getViewport, projection, 49 | center: invCenter, 50 | zoom, clampY, 51 | }); 52 | 53 | return { 54 | gl, framebuffer, 55 | projection, coords, 56 | style, mapboxToken, 57 | context: initGLpaint({ context, framebuffer, projScale }), 58 | }; 59 | } 60 | 61 | function fail(message) { 62 | throw Error("tile-setter parameter check: " + message + "!"); 63 | } 64 | 65 | function allPosInts(...vals) { 66 | return vals.every(v => Number.isInteger(v) && v > 0); 67 | } 68 | 69 | function all0to1(...vals) { 70 | return vals.every(v => Number.isFinite(v) && v >= 0 && v <= 1); 71 | } 72 | 73 | function checkCoords(p, n) { 74 | const isArray = Array.isArray(p) || 75 | (ArrayBuffer.isView(p) && !(p instanceof DataView)); 76 | return isArray && p.length >= n && 77 | p.slice(0, n).every(Number.isFinite); 78 | } 79 | -------------------------------------------------------------------------------- /src/projection.js: -------------------------------------------------------------------------------- 1 | const { cos, tan, atan, exp, log, PI, min, max } = Math; 2 | // Maximum latitude for Web Mercator: 85.0113 degrees. Beware rounding! 3 | const maxMercLat = 2.0 * atan(exp(PI)) - PI / 2.0; 4 | const clipLat = (lat) => min(max(-maxMercLat, lat), maxMercLat); 5 | const degrees = 180.0 / PI; 6 | 7 | export function getProjection(units) { 8 | switch (units) { 9 | case "xy": 10 | return { // Input coordinates already projected to XY 11 | forward: p => p, 12 | inverse: p => p, 13 | scale: () => 1.0, 14 | }; 15 | case "radians": 16 | return { 17 | forward, 18 | inverse, 19 | scale, 20 | }; 21 | case "degrees": 22 | return { 23 | forward: (pt) => forward(pt.map(c => c / degrees)), 24 | inverse: (pt) => inverse(pt).map(c => c * degrees), 25 | scale: (pt) => scale(pt.map(c => c / degrees)), 26 | }; 27 | default: 28 | throw Error("getProjection: unknown units = " + units); 29 | } 30 | } 31 | 32 | export function forward([lon, lat]) { 33 | // Convert input longitude in radians to a Web Mercator x-coordinate 34 | // where x = 0 at lon = -PI, x = 1 at lon = +PI 35 | const x = 0.5 + 0.5 * lon / PI; 36 | 37 | // Convert input latitude in radians to a Web Mercator y-coordinate 38 | // where y = 0 at lat = maxMercLat, y = 1 at lat = -maxMercLat 39 | const y = 0.5 - 0.5 / PI * 40 | log(tan(PI / 4.0 + clipLat(lat) / 2.0)); 41 | 42 | // Clip y to the range [0, 1] (it does not wrap around) 43 | return [x, min(max(0.0, y), 1.0)]; 44 | } 45 | 46 | export function inverse([x, y]) { 47 | const lon = 2.0 * (x - 0.5) * PI; 48 | const lat = 2.0 * atan(exp(PI * (1.0 - 2.0 * y))) - PI / 2; 49 | 50 | return [lon, lat]; 51 | } 52 | 53 | export function scale(point) { 54 | const lat = clipLat(point[1]); 55 | // Return value scales a (differential) distance along the plane tangent to 56 | // the sphere at [lon, lat] to a distance in map coordinates. 57 | // NOTE: ASSUMES a sphere of radius 1! Input distances should be 58 | // pre-normalized by the appropriate radius 59 | return 1 / (2 * PI * cos(lat)); 60 | } 61 | -------------------------------------------------------------------------------- /src/raster.js: -------------------------------------------------------------------------------- 1 | export function initRasterLoader(source) { 2 | const getURL = initUrlFunc(source.tiles); 3 | 4 | function request({ z, x, y, callback }) { 5 | const href = getURL(z, x, y); 6 | const errMsg = "ERROR in loadImage for href " + href; 7 | 8 | const img = new Image(); 9 | img.onerror = () => callback(errMsg); 10 | img.onload = () => { 11 | return img.complete && img.naturalWidth !== 0 12 | ? callback(null, img) 13 | : callback(errMsg); 14 | }; 15 | img.crossOrigin = "anonymous"; 16 | img.src = href; 17 | 18 | function abort() { 19 | img.src = ""; 20 | } 21 | 22 | return { abort }; 23 | } 24 | 25 | return { request }; 26 | } 27 | 28 | function initUrlFunc(endpoints) { 29 | if (!endpoints || !endpoints.length) { 30 | throw Error("ERROR in initUrlFunc: no valid tile endpoints!"); 31 | } 32 | 33 | // Use a different endpoint for each request 34 | let index = 0; 35 | 36 | return function(z, x, y) { 37 | index = (index + 1) % endpoints.length; 38 | const endpoint = endpoints[index]; 39 | return endpoint 40 | .replace(/{z}/, z) 41 | .replace(/{x}/, x) 42 | .replace(/{y}/, y); 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/renderer.js: -------------------------------------------------------------------------------- 1 | import { getStyleFuncs } from "tile-stencil"; 2 | 3 | export function initRenderer(context, coords, style) { 4 | const { PI, cosh } = Math; 5 | const { layers, spriteData } = style; 6 | 7 | if (spriteData) context.loadSprite(spriteData.image); 8 | 9 | const painters = layers.map(layer => { 10 | const painter = context.initPainter(getStyleFuncs(layer)); 11 | return Object.assign(painter, { visible: () => layer.visible }); 12 | }); 13 | 14 | return function(tilesets, pixRatio = 1, dzScale = 1) { 15 | context.prep(); 16 | const zoom = coords.getZoom(); 17 | 18 | const localCamY = coords.getCamPos()[1] * coords.getViewport()[1]; 19 | const globalCamY = coords.localToGlobal([0.0, localCamY])[1]; 20 | const cameraScale = cosh(2 * PI * (0.5 - globalCamY)) * dzScale; 21 | 22 | painters.forEach(painter => { 23 | if (zoom < painter.minzoom || painter.maxzoom < zoom) return; 24 | if (!painter.visible()) return; 25 | const tileset = tilesets[painter.source]; 26 | painter({ tileset, zoom, pixRatio, cameraScale }); 27 | }); 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/selection.js: -------------------------------------------------------------------------------- 1 | import { getTileTransform } from "./tile-coords.js"; 2 | import { transformFeatureCoords } from "./feature-coords.js"; 3 | import booleanPointInPolygon from "@turf/boolean-point-in-polygon"; 4 | 5 | export function initSelector(sources, projection) { 6 | const tileSize = 512; // TODO: don't assume this 7 | 8 | return function({ layer, point, radius = 5 }) { 9 | const tileset = sources.getLayerTiles(layer); 10 | if (!tileset || !tileset.length) return; 11 | 12 | // Find the tile, and get the layer features 13 | const nTiles = 2 ** tileset[0].z; 14 | const [ix, iy] = projection.forward(point) 15 | .map(c => Math.floor(c * nTiles)); 16 | const tileBox = tileset.find(({ xw, yw }) => xw == ix && yw == iy); 17 | if (!tileBox) return; 18 | const dataLayer = tileBox.tile.data.layers[layer]; 19 | if (!dataLayer) return; 20 | // const { features, extent = tileSize } = dataLayer; 21 | const { features } = dataLayer; 22 | const extent = tileSize; // TODO: use data extent 23 | if (!features || !features.length) return; 24 | 25 | // Convert point to tile coordinates 26 | const transform = getTileTransform(tileBox.tile, extent, projection); 27 | const tileXY = transform.forward(point); 28 | 29 | // Find the nearest feature 30 | const { distance, feature } = features.reduce((nearest, feature) => { 31 | const distance = measureDistance(tileXY, feature.geometry); 32 | if (distance < nearest.distance) nearest = { distance, feature }; 33 | return nearest; 34 | }, { distance: Infinity }); 35 | 36 | // Threshold distance should be in units of screen pixels 37 | const threshold = radius * extent / tileset.scale * tileBox.sw; 38 | if (distance > threshold) return; 39 | 40 | // Convert feature coordinates from tile XY units back to input units 41 | return transformFeatureCoords(feature, transform.inverse); 42 | }; 43 | } 44 | 45 | export function measureDistance(pt, geometry) { 46 | const { type, coordinates } = geometry; 47 | 48 | switch (type) { 49 | case "Point": 50 | return distToPoint(coordinates, pt); 51 | case "Polygon": 52 | case "MultiPolygon": 53 | return booleanPointInPolygon(pt, geometry) ? 0 : Infinity; 54 | default: 55 | return; // Unknown feature type! 56 | } 57 | } 58 | 59 | function distToPoint(coords, pt) { 60 | const [x, y] = coords; 61 | return Math.sqrt((x - pt[0]) ** 2 + (y - pt[1]) ** 2); 62 | } 63 | -------------------------------------------------------------------------------- /src/sources.js: -------------------------------------------------------------------------------- 1 | import { initCaches } from "./caches.js"; 2 | import { initTileGrid } from "./grid.js"; 3 | 4 | export function initSources(style, context, coords) { 5 | const { sources: sourceDescriptions, glyphs, spriteData, layers } = style; 6 | 7 | const caches = initCaches({ context, glyphs, spriteData }); 8 | const tilesets = {}; 9 | const layerSources = layers.reduce((d, l) => (d[l.id] = l.source, d), {}); 10 | 11 | const grids = Object.entries(sourceDescriptions).map(([key, source]) => { 12 | const subset = layers.filter(l => l.source === key); 13 | if (!subset.length) return; 14 | 15 | const tileCache = caches.addSource({ source, layers: subset }); 16 | if (!tileCache) return; 17 | const grid = initTileGrid({ key, source, tileCache }); 18 | 19 | grid.layers = subset; 20 | return grid; 21 | }).filter(s => s !== undefined); 22 | 23 | function loadTilesets() { 24 | const viewport = coords.getViewport(); 25 | const transform = coords.getTransform(); 26 | grids.forEach(grid => { 27 | if (!grid.layers.some(l => l.visible)) return; 28 | tilesets[grid.key] = grid.getTiles(viewport, transform); 29 | }); 30 | caches.sortTasks(); 31 | const loadStatus = Object.values(tilesets).map(t => t.loaded) 32 | .reduce((s, l) => s + l) / grids.length; 33 | return loadStatus; 34 | } 35 | 36 | return { 37 | tilesets, 38 | getLayerTiles: (layer) => tilesets[layerSources[layer]], 39 | loadTilesets, 40 | queuedTasks: caches.queuedTasks, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/tile-coords.js: -------------------------------------------------------------------------------- 1 | export function getTileTransform(tile, extent, projection) { 2 | const { z, x, y } = tile; 3 | const nTiles = 2 ** z; 4 | const translate = [x, y]; 5 | 6 | const transform = { 7 | // Global XY to local tile XY 8 | forward: (pt) => pt.map((g, i) => (g * nTiles - translate[i]) * extent), 9 | 10 | // Local tile XY to global XY 11 | inverse: (pt) => pt.map((l, i) => (l / extent + translate[i]) / nTiles), 12 | }; 13 | 14 | return { 15 | forward: (pt) => transform.forward(projection.forward(pt)), 16 | inverse: (pt) => projection.inverse(transform.inverse(pt)), 17 | }; 18 | } 19 | --------------------------------------------------------------------------------