From 0fe90f06c99aa7f0f0992703150879a77c81294f Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Mon, 5 Feb 2024 12:43:05 +0100 Subject: [PATCH 1/6] Add trolley bay layer --- assets/layers/trolley_bay/license_info.json | 13 ++ assets/layers/trolley_bay/trolley_bay.json | 206 ++++++++++++++++++ assets/layers/trolley_bay/trolley_bay.svg | 12 + .../trolley_bay/trolley_bay.svg.license | 2 + assets/themes/shops/shops.json | 5 +- 5 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 assets/layers/trolley_bay/license_info.json create mode 100644 assets/layers/trolley_bay/trolley_bay.json create mode 100644 assets/layers/trolley_bay/trolley_bay.svg create mode 100644 assets/layers/trolley_bay/trolley_bay.svg.license diff --git a/assets/layers/trolley_bay/license_info.json b/assets/layers/trolley_bay/license_info.json new file mode 100644 index 0000000000..f2a2da71ba --- /dev/null +++ b/assets/layers/trolley_bay/license_info.json @@ -0,0 +1,13 @@ +[ + { + "path": "trolley_bay.svg", + "license": "CC-BY-SA 3.0", + "authors": [ + "Manuel Campagnoli", + "Robin van der Linde" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Shopping_Cart.svg" + ] + } +] \ No newline at end of file diff --git a/assets/layers/trolley_bay/trolley_bay.json b/assets/layers/trolley_bay/trolley_bay.json new file mode 100644 index 0000000000..be9d7625fc --- /dev/null +++ b/assets/layers/trolley_bay/trolley_bay.json @@ -0,0 +1,206 @@ +{ + "id": "trolley_bay", + "name": { + "en": "Trolley Bays" + }, + "description": { + "en": "Find trolley bays for shopping trolleys." + }, + "title": { + "en": "Trolley Bay" + }, + "source": { + "osmTags": "amenity=trolley_bay" + }, + "minzoom": 13, + "allowMove": { + "enableImproveAccuracy": true, + "enableRelocation": true + }, + "deletion": true, + "tagRenderings": [ + { + "id": "covered", + "question": { + "en": "Is this trolley bay covered?" + }, + "mappings": [ + { + "if": "covered=yes", + "then": { + "en": "This trolley bay is covered" + } + }, + { + "if": "covered=no", + "then": { + "en": "This trolley bay is not covered" + } + } + ] + }, + { + "id": "deposit", + "question": { + "en": "Is a deposit (e.g. a coin) required for the trolleys?" + }, + "mappings": [ + { + "if": "trolley:deposit=yes", + "then": { + "en": "A deposit is required for the trolleys" + } + }, + { + "if": "trolley:deposit=no", + "then": { + "en": "No deposit is required for the trolleys" + } + } + ] + }, + { + "id": "denominations", + "condition": { + "and": [ + "trolley:deposit=yes", + "_currency~.*EUR.*" + ] + }, + "question": { + "en": "What coins are accepted for the deposit?" + }, + "multiAnswer": true, + "mappings": [ + { + "if": "trolley:deposit:denominations=0.50 EUR", + "icon": "./assets/layers/questions/denominations/eur/50cent.svg", + "then": { + "en": "50 cent coins are accepted", + "de": "50-Cent-Münzen werden akzeptiert", + "nl": "Munten van 50 cent worden geaccepteerd", + "nb_NO": "50-cent mynter aksepteres", + "fr": "Les pièces de 50 cents sont acceptées", + "pl": "Akceptowane są monety 50-centowe", + "ca": "S'accepten monedes de 50 cèntims", + "es": "Se aceptan monedas de 50 céntimos", + "cs": "Jsou přijímány mince v hodnotě 50 centů", + "id": "Koin 50 sen diterima" + } + }, + { + "if": "trolley:deposit:denominations=1 EUR", + "icon": "./assets/layers/questions/denominations/eur/1euro.svg", + "then": { + "en": "1 euro coins are accepted", + "de": "1-Euro-Münzen werden akzeptiert", + "nl": "Munten van 1 euro worden geaccepteerd", + "nb_NO": "1-euro mynter aksepteres", + "fr": "Les pièces de 1 euro sont acceptées", + "pl": "Akceptowane są monety 1 euro", + "ca": "S'accepten monedes de 1 euro", + "es": "Se aceptan monedas de 1 euro", + "cs": "Jsou přijímány mince v hodnotě 1 eura" + }, + "hideInAnswer": "_currency!~.*EUR.*" + }, + { + "if": "trolley:deposit:denominations=2 EUR", + "icon": "./assets/layers/questions/denominations/eur/2euro.svg", + "then": { + "en": "2 euro coins are accepted", + "de": "2-Euro-Münzen werden akzeptiert", + "nl": "Munten van 2 euro worden geaccepteerd", + "nb_NO": "2-euro mynter aksepteres", + "fr": "Les pièces de 2 euros sont acceptées", + "pl": "Akceptowane są monety 2 euro", + "ca": "S'accepten monedes de 2 euros", + "es": "Se aceptan monedas de 2 euros", + "cs": "Jsou přijímány mince v hodnotě 2 euro" + }, + "hideInAnswer": "_currency!~.*EUR.*" + } + ] + }, + { + "id": "cart_types", + "question": { + "en": "What kind of special trolleys are available?" + }, + "multiAnswer": true, + "mappings": [ + { + "if": "trolley:magnifier=yes", + "ifnot": "trolley:magnifier=no", + "then": { + "en": "Trolleys with a magnifier are available" + } + }, + { + "if": "trolley:wheelchair=yes", + "ifnot": "trolley:wheelchair=no", + "then": { + "en": "Trolleys for wheelchair users are available" + } + }, + { + "if": "trolley:children=yes", + "ifnot": "trolley:children=no", + "then": { + "en": "Trolleys for children are available" + } + }, + { + "if": "trolley:seats=yes", + "ifnot": "trolley:seats=no", + "then": { + "en": "Trolleys with seats for children are available" + } + }, + { + "if": "trolley:flatbed=yes", + "ifnot": "trolley:flatbed=no", + "then": { + "en": "Trolleys with a flatbed are available" + } + }, + { + "if": "trolley:vertical=yes", + "ifnot": "trolley:vertical=no", + "then": { + "en": "Vertical trolleys for sheet-like goods are available" + } + } + ] + }, + { + "id": "indoor" + } + ], + "presets": [ + { + "title": { + "en": "a trolley bay" + }, + "tags": [ + "amenity=trolley_bay" + ], + "description": { + "en": "A trolley bay for parking shopping carts." + } + } + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "./assets/layers/trolley_bay/trolley_bay.svg" + } + ] + } + ] +} \ No newline at end of file diff --git a/assets/layers/trolley_bay/trolley_bay.svg b/assets/layers/trolley_bay/trolley_bay.svg new file mode 100644 index 0000000000..6ab9e54559 --- /dev/null +++ b/assets/layers/trolley_bay/trolley_bay.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/layers/trolley_bay/trolley_bay.svg.license b/assets/layers/trolley_bay/trolley_bay.svg.license new file mode 100644 index 0000000000..2beb24295d --- /dev/null +++ b/assets/layers/trolley_bay/trolley_bay.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Manuel Campagnoli; Robin van der Linde +SPDX-License-Identifier: CC-BY-SA 3.0 \ No newline at end of file diff --git a/assets/themes/shops/shops.json b/assets/themes/shops/shops.json index 0024d9837c..b19b67260b 100644 --- a/assets/themes/shops/shops.json +++ b/assets/themes/shops/shops.json @@ -52,7 +52,8 @@ "layers": [ "shops", "pharmacy", - "ice_cream" + "ice_cream", + "trolley_bay" ], "widenFactor": 3 -} +} \ No newline at end of file From faa1d59d2bac54bdee15869b15bd267b96e59d14 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Mon, 5 Feb 2024 13:08:30 +0100 Subject: [PATCH 2/6] Add shelter to nature theme --- assets/themes/nature/nature.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assets/themes/nature/nature.json b/assets/themes/nature/nature.json index 50bc46930f..c92b0a0e1d 100644 --- a/assets/themes/nature/nature.json +++ b/assets/themes/nature/nature.json @@ -52,7 +52,8 @@ "bench", "picnic_table", "toilet", - "guidepost" + "guidepost", + "shelter" ], "override": { "minzoom": 16 @@ -60,4 +61,4 @@ } ], "widenFactor": 2 -} +} \ No newline at end of file From ff481d73e9c350d60e414cf7671985cd3c2376d7 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Sat, 10 Feb 2024 23:54:05 +0100 Subject: [PATCH 3/6] Commons download script --- scripts/downloadCommons.ts | 296 +++++++++++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 scripts/downloadCommons.ts diff --git a/scripts/downloadCommons.ts b/scripts/downloadCommons.ts new file mode 100644 index 0000000000..78cb8e217c --- /dev/null +++ b/scripts/downloadCommons.ts @@ -0,0 +1,296 @@ +/** + * Script to download images from Wikimedia Commons, and save them together with license information. + */ + +import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs" +import { unescape } from "querystring" +import SmallLicense from "../src/Models/smallLicense" + +interface ExtMetadataProp { + value: string + source: string + hidden: string +} + +interface ImageQueryAPIResponse { + continue: { + iistart: string + continue: string + } + query: { + normalized?: { + from: string + to: string + }[] + pages: { + [key: string]: { + pageid: number + ns: number + title: string + imagerepository: string + imageinfo?: { + user: string + url: string + descriptionurl: string + descriptionshorturl: string + extmetadata?: { + DateTime: ExtMetadataProp + ObjectName: ExtMetadataProp + CommonsMetadataExtension?: ExtMetadataProp + Categories?: ExtMetadataProp + Assessments?: ExtMetadataProp + ImageDescription?: ExtMetadataProp + DateTimeOriginal?: ExtMetadataProp + Credit?: ExtMetadataProp + Artist?: ExtMetadataProp + LicenseShortName?: ExtMetadataProp + UsageTerms?: ExtMetadataProp + AttributionRequired?: ExtMetadataProp + Copyrighted?: ExtMetadataProp + Restrictions?: ExtMetadataProp + License?: ExtMetadataProp + } + }[] + } + } + } +} + +interface CategoryMember { + pageid: number + ns: number + title: string +} + +interface CategoryQueryAPIResponse { + batchcomplete: string + query: { + categorymembers: CategoryMember[] + } +} + +interface TemplateQueryAPIResponse { + batchcomplete: string + query: { + normalized?: { + from: string + to: string + }[] + pages: { + [key: string]: { + pageid: number + ns: number + title: string + templates?: { + ns: number + title: string + }[] + } + } + } +} + +// Map license names of Wikimedia Commons to different names +const licenseMapping = {} + +// Map template names to license names +const templateMapping = { + "Template:PD": "Public Domain", +} + +async function main(args: string[]) { + if (args.length < 2) { + console.log("Usage: downloadCommons.ts .. ") + console.log( + "Example: npx vite-node downloadCommons.ts -- assets/svg https://commons.wikimedia.org/wiki/File:Example.jpg" + ) + process.exit(1) + } + const [outputFolder, ...urls] = args + + for (const url of urls) { + // Download details from the API + const commonsFileNamePath = url.split("/").pop() + if (commonsFileNamePath !== undefined) { + const commonsFileName = commonsFileNamePath.split("?").shift() + + if (commonsFileName !== undefined) { + console.log(`Processing ${commonsFileName}...`) + + const baseUrl = url.split("/").slice(0, 3).join("/") + + // Check if it is a file or a category + if (url.includes("Category:")) { + // Download all files in the category + const apiUrl = `${baseUrl}/w/api.php?action=query&format=json&list=categorymembers&cmtitle=${commonsFileName}&cmlimit=250&cmtype=file` + const response = await fetch(apiUrl) + const apiDetails: CategoryQueryAPIResponse = await response.json() + for (const member of apiDetails.query.categorymembers) { + await downloadImage(member.title, outputFolder, baseUrl) + } + } else { + await downloadImage(commonsFileName, outputFolder, baseUrl) + } + } else { + console.log( + "\x1b[31m%s\x1b[0m", + `URL ${url} doesn't seem to contain a filename or category! Skipping...` + ) + continue + } + } else { + console.log( + "\x1b[31m%s\x1b[0m", + `URL ${url} doesn't seem to be a valid URL! Skipping...` + ) + continue + } + } +} + +async function downloadImage(filename: string, outputFolder: string, baseUrl: string) { + const apiUrl = `${baseUrl}/w/api.php?action=query&format=json&prop=imageinfo&iiprop=url|extmetadata|user&iimetadataversion=latest&titles=${filename}` + const response = await fetch(apiUrl) + const apiDetails: ImageQueryAPIResponse = await response.json() + const missingPage = apiDetails.query.pages["-1"] + + // Check if the file exists, locally or externally + if (missingPage !== undefined) { + // Image does not exist locally, check if it exists externally + if ( + apiDetails.query.pages["-1"].imagerepository !== "local" && + apiDetails.query.pages["-1"].imagerepository !== "" + ) { + // Check if we actually have image info + if (missingPage.imageinfo?.length !== undefined && missingPage.imageinfo.length > 0) { + const externalUrl = missingPage.imageinfo[0].descriptionurl + const externalBase = externalUrl.split("/").slice(0, 3).join("/") + + const externalFilenamePath = externalUrl.split("/").pop() + if (externalFilenamePath !== undefined) { + const externalFilename = externalFilenamePath.split("?").shift() + console.log( + `\x1b[33m%s\x1b[0m`, + `${filename} is external, re-running with ${externalUrl}...` + ) + if (externalFilename !== undefined) { + await downloadImage(externalFilename, outputFolder, externalBase) + return + } else { + // Edge case + console.log( + `\x1b[33m%s\x1b[0m`, + `External URL ${externalUrl} doesn't seem to contain a filename or category! Skipping...` + ) + } + } else { + // Edge case + console.log( + `\x1b[33m%s\x1b[0m`, + `External URL ${externalUrl} doesn't seem to be a valid URL! Skipping...` + ) + return + } + } else { + console.log( + `\x1b[33m%s\x1b[0m`, + `${filename} does not have image info!, skipping...` + ) + } + } + console.log(`\x1b[33m%s\x1b[0m`, `${filename} does not exist!, skipping...`) + } else { + // Harvest useful information + const wikiPage = apiDetails.query.pages[Object.keys(apiDetails.query.pages)[0]] + + // Check if we actually have image info + if (wikiPage.imageinfo?.length !== undefined && wikiPage.imageinfo.length > 0) { + const wikiUrl = wikiPage.imageinfo[0].descriptionurl + const fileUrl = wikiPage.imageinfo[0].url + const author = + wikiPage.imageinfo[0].extmetadata?.Artist?.value || wikiPage.imageinfo[0].user + let license = wikiPage.imageinfo[0].extmetadata?.LicenseShortName?.value || null + + // Check if the output folder exists + if (!existsSync(outputFolder)) { + const parts = outputFolder.split("/") + for (let i = 0; i < parts.length; i++) { + const part = parts.slice(0, i + 1).join("/") + if (!existsSync(part)) { + console.log(`Creating folder ${part}`) + mkdirSync(part) + } + } + } + + // Check if the license is present + if (!license) { + console.log( + `${filename} does not have a license, falling back to checking template...` + ) + const templateUrl = `${baseUrl}/w/api.php?action=query&format=json&prop=templates&titles=${filename}&tllimit=500` + const templateResponse = await fetch(templateUrl) + const templateDetails: TemplateQueryAPIResponse = await templateResponse.json() + + // Loop through all templates and check if one of them is a license + const wikiPage = + templateDetails.query.pages[Object.keys(templateDetails.query.pages)[0]] + if (wikiPage.templates) { + for (const template of wikiPage.templates) { + if (templateMapping[template.title]) { + console.log( + `Found license ${templateMapping[template.title]} for ${filename}` + ) + license = templateMapping[template.title] + } + } + } + + // If no license was found, skip the file + if (!license) { + // Log in yellow + console.log( + `\x1b[33m%s\x1b[0m`, + `No license found for ${filename}, skipping...` + ) + return + } + } + + // Download the file and save it + const cleanFileName = unescape(filename).replace("File:", "") + console.log( + `Downloading ${cleanFileName} from ${fileUrl} and saving it to ${outputFolder}/${cleanFileName}...` + ) + const fileResponse = await fetch(fileUrl) + const fileBuffer = await fileResponse.arrayBuffer() + const file = Buffer.from(fileBuffer) + const filePath = `${outputFolder}/${cleanFileName}` + writeFileSync(filePath, file) + + // Save the license information + const licenseInfo: SmallLicense = { + path: cleanFileName, + license: licenseMapping[license] || license, + authors: [author], + sources: [wikiUrl], + } + + const licensePath = `${outputFolder}/license_info.json` + if (!existsSync(licensePath)) { + // Create the file if it doesn't exist + writeFileSync(licensePath, JSON.stringify([licenseInfo], null, 2)) + } else { + // Append to the file if it does exist + const licenseFile = await readFileSync(licensePath, "utf8") + const licenseData = JSON.parse(licenseFile) + licenseData.push(licenseInfo) + writeFileSync(licensePath, JSON.stringify(licenseData, null, 2)) + } + } else { + console.log(`\x1b[33m%s\x1b[0m`, `${filename} does not have image info!, skipping...`) + } + } +} + +main(process.argv.slice(2)) From 57d6f21eb6e8b8961bedd2cf8dc5716390be9453 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Sat, 10 Feb 2024 23:54:25 +0100 Subject: [PATCH 4/6] Add parking space types --- assets/layers/parking_spaces/hgv.svg | 9 +++++++ assets/layers/parking_spaces/hgv.svg.license | 2 ++ .../layers/parking_spaces/license_info.json | 18 +++++++++++++ .../parking_spaces/parking_space_private.svg | 6 +++++ .../parking_space_private.svg.license | 2 ++ .../layers/parking_spaces/parking_spaces.json | 25 ++++++++++++++++++- 6 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 assets/layers/parking_spaces/hgv.svg create mode 100644 assets/layers/parking_spaces/hgv.svg.license create mode 100644 assets/layers/parking_spaces/parking_space_private.svg create mode 100644 assets/layers/parking_spaces/parking_space_private.svg.license diff --git a/assets/layers/parking_spaces/hgv.svg b/assets/layers/parking_spaces/hgv.svg new file mode 100644 index 0000000000..f7aab188c5 --- /dev/null +++ b/assets/layers/parking_spaces/hgv.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/assets/layers/parking_spaces/hgv.svg.license b/assets/layers/parking_spaces/hgv.svg.license new file mode 100644 index 0000000000..2de8e7ea06 --- /dev/null +++ b/assets/layers/parking_spaces/hgv.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: MarianSigler +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/parking_spaces/license_info.json b/assets/layers/parking_spaces/license_info.json index b375368435..5d3f3deb45 100644 --- a/assets/layers/parking_spaces/license_info.json +++ b/assets/layers/parking_spaces/license_info.json @@ -1,4 +1,14 @@ [ + { + "path": "hgv.svg", + "license": "CC0-1.0", + "authors": [ + "MarianSigler" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Sinnbild_LKW.svg" + ] + }, { "path": "parking_space.svg", "license": "CC0-1.0", @@ -6,5 +16,13 @@ "Robin van der Linde" ], "sources": [] + }, + { + "path": "parking_space_private.svg", + "license": "CC0-1.0", + "authors": [ + "Robin van der Linde" + ], + "sources": [] } ] \ No newline at end of file diff --git a/assets/layers/parking_spaces/parking_space_private.svg b/assets/layers/parking_spaces/parking_space_private.svg new file mode 100644 index 0000000000..47805b50f8 --- /dev/null +++ b/assets/layers/parking_spaces/parking_space_private.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/layers/parking_spaces/parking_space_private.svg.license b/assets/layers/parking_spaces/parking_space_private.svg.license new file mode 100644 index 0000000000..75299f8845 --- /dev/null +++ b/assets/layers/parking_spaces/parking_space_private.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Robin van der Linde +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/parking_spaces/parking_spaces.json b/assets/layers/parking_spaces/parking_spaces.json index ab10f4bf4f..1ece3a3fe5 100644 --- a/assets/layers/parking_spaces/parking_spaces.json +++ b/assets/layers/parking_spaces/parking_spaces.json @@ -37,6 +37,13 @@ "de": "Behindertenparkplatz", "cs": "Parkovací místo pro osoby se zdravotním postižením" } + }, + { + "if": "parking_space=charging", + "then": { + "en": "Electric Vehicle Charging Parking Space", + "nl": "Parkeerplek voor opladen van elektrische voertuigen" + } } ] }, @@ -50,6 +57,22 @@ { "if": "parking_space=disabled", "then": "./assets/layers/toilet/wheelchair.svg" + }, + { + "if": "parking_space=charging", + "then": "./assets/themes/charging_stations/plug.svg" + }, + { + "if": "parking_space=private", + "then": "./assets/layers/parking_spaces/parking_space_private.svg" + }, + { + "if": "parking_space=bus", + "then": "./assets/layers/transit_stops/bus_stop.svg" + }, + { + "if": "parking_space=hgv", + "then": "./assets/layers/parking_spaces/hgv.svg" } ] } @@ -264,4 +287,4 @@ ] } ] -} +} \ No newline at end of file From dcda948ca5eb2f2d8fe0f1d6bb104430aa2bc2b4 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Sat, 10 Feb 2024 23:54:41 +0100 Subject: [PATCH 5/6] Fix onwheels parking icon, add charging to parking --- assets/themes/onwheels/onwheels.json | 16 ++-------------- assets/themes/parkings/parkings.json | 8 +++++++- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/assets/themes/onwheels/onwheels.json b/assets/themes/onwheels/onwheels.json index 5a5ab9b322..4ecb2532c3 100644 --- a/assets/themes/onwheels/onwheels.json +++ b/assets/themes/onwheels/onwheels.json @@ -268,19 +268,7 @@ }, "pointRendering": [ { - "marker": [ - { - "mappings": null - } - ], - "iconSize": "40,40", - "anchor": "center", - "iconBadges": [ - { - "if": "parking_space=disabled", - "then": "./assets/layers/toilet/wheelchair.svg" - } - ] + "iconSize": "40,40" } ], "name": { @@ -599,4 +587,4 @@ }, "enableDownload": true, "widenFactor": 2 -} +} \ No newline at end of file diff --git a/assets/themes/parkings/parkings.json b/assets/themes/parkings/parkings.json index c9a18cfb2a..9d96a04daa 100644 --- a/assets/themes/parkings/parkings.json +++ b/assets/themes/parkings/parkings.json @@ -58,7 +58,13 @@ "layers": [ "parking", "parking_spaces", - "parking_ticket_machine" + "parking_ticket_machine", + { + "builtin": "charging_station", + "override": { + "minzoom": 18 + } + } ], "widenFactor": 1.2 } \ No newline at end of file From 0e1d14e5bb27ce64fd7181db971b312ecb91259e Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Sun, 11 Feb 2024 00:12:09 +0100 Subject: [PATCH 6/6] Change minzoom for trolley bay --- assets/layers/trolley_bay/trolley_bay.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/layers/trolley_bay/trolley_bay.json b/assets/layers/trolley_bay/trolley_bay.json index be9d7625fc..b8a84b359e 100644 --- a/assets/layers/trolley_bay/trolley_bay.json +++ b/assets/layers/trolley_bay/trolley_bay.json @@ -12,7 +12,7 @@ "source": { "osmTags": "amenity=trolley_bay" }, - "minzoom": 13, + "minzoom": 18, "allowMove": { "enableImproveAccuracy": true, "enableRelocation": true