├── .dockerignore ├── .eslintrc ├── .github └── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── .gitignore ├── .nvmrc ├── CODEOWNERS ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── PULL_REQUEST_TEMPLATE.md ├── Procfile ├── README.md ├── app.js ├── assets └── sprite │ ├── create-sprite-svgs.js │ └── svg │ ├── .gitignore │ ├── aqua-diagonal-1px.svg │ ├── aqua-diagonal-2px.svg │ ├── aqua-diagonal-3px.svg │ ├── aqua-diagonal-4px.svg │ ├── aqua-diagonal-5px.svg │ ├── aqua-diagonal-6px.svg │ ├── aqua_dark-diagonal-1px.svg │ ├── aqua_dark-diagonal-2px.svg │ ├── aqua_dark-diagonal-3px.svg │ ├── aqua_dark-diagonal-4px.svg │ ├── aqua_dark-diagonal-5px.svg │ ├── aqua_dark-diagonal-6px.svg │ ├── aqua_desaturated-diagonal-1px.svg │ ├── aqua_desaturated-diagonal-2px.svg │ ├── aqua_desaturated-diagonal-3px.svg │ ├── aqua_desaturated-diagonal-4px.svg │ ├── aqua_desaturated-diagonal-5px.svg │ ├── aqua_desaturated-diagonal-6px.svg │ ├── aqua_light-diagonal-1px.svg │ ├── aqua_light-diagonal-2px.svg │ ├── aqua_light-diagonal-3px.svg │ ├── aqua_light-diagonal-4px.svg │ ├── aqua_light-diagonal-5px.svg │ ├── aqua_light-diagonal-6px.svg │ ├── blue-diagonal-1px.svg │ ├── blue-diagonal-2px.svg │ ├── blue-diagonal-3px.svg │ ├── blue-diagonal-4px.svg │ ├── blue-diagonal-5px.svg │ ├── blue-diagonal-6px.svg │ ├── blue_dark-diagonal-1px.svg │ ├── blue_dark-diagonal-2px.svg │ ├── blue_dark-diagonal-3px.svg │ ├── blue_dark-diagonal-4px.svg │ ├── blue_dark-diagonal-5px.svg │ ├── blue_dark-diagonal-6px.svg │ ├── blue_desaturated-diagonal-1px.svg │ ├── blue_desaturated-diagonal-2px.svg │ ├── blue_desaturated-diagonal-3px.svg │ ├── blue_desaturated-diagonal-4px.svg │ ├── blue_desaturated-diagonal-5px.svg │ ├── blue_desaturated-diagonal-6px.svg │ ├── blue_light-diagonal-1px.svg │ ├── blue_light-diagonal-2px.svg │ ├── blue_light-diagonal-3px.svg │ ├── blue_light-diagonal-4px.svg │ ├── blue_light-diagonal-5px.svg │ ├── blue_light-diagonal-6px.svg │ ├── chartreuse-diagonal-1px.svg │ ├── chartreuse-diagonal-2px.svg │ ├── chartreuse-diagonal-3px.svg │ ├── chartreuse-diagonal-4px.svg │ ├── chartreuse-diagonal-5px.svg │ ├── chartreuse-diagonal-6px.svg │ ├── chartreuse_dark-diagonal-1px.svg │ ├── chartreuse_dark-diagonal-2px.svg │ ├── chartreuse_dark-diagonal-3px.svg │ ├── chartreuse_dark-diagonal-4px.svg │ ├── chartreuse_dark-diagonal-5px.svg │ ├── chartreuse_dark-diagonal-6px.svg │ ├── chartreuse_desaturated-diagonal-1px.svg │ ├── chartreuse_desaturated-diagonal-2px.svg │ ├── chartreuse_desaturated-diagonal-3px.svg │ ├── chartreuse_desaturated-diagonal-4px.svg │ ├── chartreuse_desaturated-diagonal-5px.svg │ ├── chartreuse_desaturated-diagonal-6px.svg │ ├── chartreuse_light-diagonal-1px.svg │ ├── chartreuse_light-diagonal-2px.svg │ ├── chartreuse_light-diagonal-3px.svg │ ├── chartreuse_light-diagonal-4px.svg │ ├── chartreuse_light-diagonal-5px.svg │ ├── chartreuse_light-diagonal-6px.svg │ ├── fuchsia-diagonal-1px.svg │ ├── fuchsia-diagonal-2px.svg │ ├── fuchsia-diagonal-3px.svg │ ├── fuchsia-diagonal-4px.svg │ ├── fuchsia-diagonal-5px.svg │ ├── fuchsia-diagonal-6px.svg │ ├── fuchsia_dark-diagonal-1px.svg │ ├── fuchsia_dark-diagonal-2px.svg │ ├── fuchsia_dark-diagonal-3px.svg │ ├── fuchsia_dark-diagonal-4px.svg │ ├── fuchsia_dark-diagonal-5px.svg │ ├── fuchsia_dark-diagonal-6px.svg │ ├── fuchsia_desaturated-diagonal-1px.svg │ ├── fuchsia_desaturated-diagonal-2px.svg │ ├── fuchsia_desaturated-diagonal-3px.svg │ ├── fuchsia_desaturated-diagonal-4px.svg │ ├── fuchsia_desaturated-diagonal-5px.svg │ ├── fuchsia_desaturated-diagonal-6px.svg │ ├── fuchsia_light-diagonal-1px.svg │ ├── fuchsia_light-diagonal-2px.svg │ ├── fuchsia_light-diagonal-3px.svg │ ├── fuchsia_light-diagonal-4px.svg │ ├── fuchsia_light-diagonal-5px.svg │ ├── fuchsia_light-diagonal-6px.svg │ ├── gold-diagonal-1px.svg │ ├── gold-diagonal-2px.svg │ ├── gold-diagonal-3px.svg │ ├── gold-diagonal-4px.svg │ ├── gold-diagonal-5px.svg │ ├── gold-diagonal-6px.svg │ ├── gold_dark-diagonal-1px.svg │ ├── gold_dark-diagonal-2px.svg │ ├── gold_dark-diagonal-3px.svg │ ├── gold_dark-diagonal-4px.svg │ ├── gold_dark-diagonal-5px.svg │ ├── gold_dark-diagonal-6px.svg │ ├── gold_desaturated-diagonal-1px.svg │ ├── gold_desaturated-diagonal-2px.svg │ ├── gold_desaturated-diagonal-3px.svg │ ├── gold_desaturated-diagonal-4px.svg │ ├── gold_desaturated-diagonal-5px.svg │ ├── gold_desaturated-diagonal-6px.svg │ ├── gold_light-diagonal-1px.svg │ ├── gold_light-diagonal-2px.svg │ ├── gold_light-diagonal-3px.svg │ ├── gold_light-diagonal-4px.svg │ ├── gold_light-diagonal-5px.svg │ ├── gold_light-diagonal-6px.svg │ ├── green-diagonal-1px.svg │ ├── green-diagonal-2px.svg │ ├── green-diagonal-3px.svg │ ├── green-diagonal-4px.svg │ ├── green-diagonal-5px.svg │ ├── green-diagonal-6px.svg │ ├── green_dark-diagonal-1px.svg │ ├── green_dark-diagonal-2px.svg │ ├── green_dark-diagonal-3px.svg │ ├── green_dark-diagonal-4px.svg │ ├── green_dark-diagonal-5px.svg │ ├── green_dark-diagonal-6px.svg │ ├── green_desaturated-diagonal-1px.svg │ ├── green_desaturated-diagonal-2px.svg │ ├── green_desaturated-diagonal-3px.svg │ ├── green_desaturated-diagonal-4px.svg │ ├── green_desaturated-diagonal-5px.svg │ ├── green_desaturated-diagonal-6px.svg │ ├── green_light-diagonal-1px.svg │ ├── green_light-diagonal-2px.svg │ ├── green_light-diagonal-3px.svg │ ├── green_light-diagonal-4px.svg │ ├── green_light-diagonal-5px.svg │ ├── green_light-diagonal-6px.svg │ ├── indigo-diagonal-1px.svg │ ├── indigo-diagonal-2px.svg │ ├── indigo-diagonal-3px.svg │ ├── indigo-diagonal-4px.svg │ ├── indigo-diagonal-5px.svg │ ├── indigo-diagonal-6px.svg │ ├── indigo_dark-diagonal-1px.svg │ ├── indigo_dark-diagonal-2px.svg │ ├── indigo_dark-diagonal-3px.svg │ ├── indigo_dark-diagonal-4px.svg │ ├── indigo_dark-diagonal-5px.svg │ ├── indigo_dark-diagonal-6px.svg │ ├── indigo_desaturated-diagonal-1px.svg │ ├── indigo_desaturated-diagonal-2px.svg │ ├── indigo_desaturated-diagonal-3px.svg │ ├── indigo_desaturated-diagonal-4px.svg │ ├── indigo_desaturated-diagonal-5px.svg │ ├── indigo_desaturated-diagonal-6px.svg │ ├── indigo_light-diagonal-1px.svg │ ├── indigo_light-diagonal-2px.svg │ ├── indigo_light-diagonal-3px.svg │ ├── indigo_light-diagonal-4px.svg │ ├── indigo_light-diagonal-5px.svg │ ├── indigo_light-diagonal-6px.svg │ ├── orange-diagonal-1px.svg │ ├── orange-diagonal-2px.svg │ ├── orange-diagonal-3px.svg │ ├── orange-diagonal-4px.svg │ ├── orange-diagonal-5px.svg │ ├── orange-diagonal-6px.svg │ ├── orange_dark-diagonal-1px.svg │ ├── orange_dark-diagonal-2px.svg │ ├── orange_dark-diagonal-3px.svg │ ├── orange_dark-diagonal-4px.svg │ ├── orange_dark-diagonal-5px.svg │ ├── orange_dark-diagonal-6px.svg │ ├── orange_desaturated-diagonal-1px.svg │ ├── orange_desaturated-diagonal-2px.svg │ ├── orange_desaturated-diagonal-3px.svg │ ├── orange_desaturated-diagonal-4px.svg │ ├── orange_desaturated-diagonal-5px.svg │ ├── orange_desaturated-diagonal-6px.svg │ ├── orange_light-diagonal-1px.svg │ ├── orange_light-diagonal-2px.svg │ ├── orange_light-diagonal-3px.svg │ ├── orange_light-diagonal-4px.svg │ ├── orange_light-diagonal-5px.svg │ ├── orange_light-diagonal-6px.svg │ ├── purple-diagonal-1px.svg │ ├── purple-diagonal-2px.svg │ ├── purple-diagonal-3px.svg │ ├── purple-diagonal-4px.svg │ ├── purple-diagonal-5px.svg │ ├── purple-diagonal-6px.svg │ ├── purple_dark-diagonal-1px.svg │ ├── purple_dark-diagonal-2px.svg │ ├── purple_dark-diagonal-3px.svg │ ├── purple_dark-diagonal-4px.svg │ ├── purple_dark-diagonal-5px.svg │ ├── purple_dark-diagonal-6px.svg │ ├── purple_desaturated-diagonal-1px.svg │ ├── purple_desaturated-diagonal-2px.svg │ ├── purple_desaturated-diagonal-3px.svg │ ├── purple_desaturated-diagonal-4px.svg │ ├── purple_desaturated-diagonal-5px.svg │ ├── purple_desaturated-diagonal-6px.svg │ ├── purple_light-diagonal-1px.svg │ ├── purple_light-diagonal-2px.svg │ ├── purple_light-diagonal-3px.svg │ ├── purple_light-diagonal-4px.svg │ ├── purple_light-diagonal-5px.svg │ ├── purple_light-diagonal-6px.svg │ ├── red-diagonal-1px.svg │ ├── red-diagonal-2px.svg │ ├── red-diagonal-3px.svg │ ├── red-diagonal-4px.svg │ ├── red-diagonal-5px.svg │ ├── red-diagonal-6px.svg │ ├── red_dark-diagonal-1px.svg │ ├── red_dark-diagonal-2px.svg │ ├── red_dark-diagonal-3px.svg │ ├── red_dark-diagonal-4px.svg │ ├── red_dark-diagonal-5px.svg │ ├── red_dark-diagonal-6px.svg │ ├── red_desaturated-diagonal-1px.svg │ ├── red_desaturated-diagonal-2px.svg │ ├── red_desaturated-diagonal-3px.svg │ ├── red_desaturated-diagonal-4px.svg │ ├── red_desaturated-diagonal-5px.svg │ ├── red_desaturated-diagonal-6px.svg │ ├── red_light-diagonal-1px.svg │ ├── red_light-diagonal-2px.svg │ ├── red_light-diagonal-3px.svg │ ├── red_light-diagonal-4px.svg │ ├── red_light-diagonal-5px.svg │ ├── red_light-diagonal-6px.svg │ ├── teal-diagonal-1px.svg │ ├── teal-diagonal-2px.svg │ ├── teal-diagonal-3px.svg │ ├── teal-diagonal-4px.svg │ ├── teal-diagonal-5px.svg │ ├── teal-diagonal-6px.svg │ ├── teal_dark-diagonal-1px.svg │ ├── teal_dark-diagonal-2px.svg │ ├── teal_dark-diagonal-3px.svg │ ├── teal_dark-diagonal-4px.svg │ ├── teal_dark-diagonal-5px.svg │ ├── teal_dark-diagonal-6px.svg │ ├── teal_desaturated-diagonal-1px.svg │ ├── teal_desaturated-diagonal-2px.svg │ ├── teal_desaturated-diagonal-3px.svg │ ├── teal_desaturated-diagonal-4px.svg │ ├── teal_desaturated-diagonal-5px.svg │ ├── teal_desaturated-diagonal-6px.svg │ ├── teal_light-diagonal-1px.svg │ ├── teal_light-diagonal-2px.svg │ ├── teal_light-diagonal-3px.svg │ ├── teal_light-diagonal-4px.svg │ ├── teal_light-diagonal-5px.svg │ ├── teal_light-diagonal-6px.svg │ ├── yellow-diagonal-1px.svg │ ├── yellow-diagonal-2px.svg │ ├── yellow-diagonal-3px.svg │ ├── yellow-diagonal-4px.svg │ ├── yellow-diagonal-5px.svg │ ├── yellow-diagonal-6px.svg │ ├── yellow_dark-diagonal-1px.svg │ ├── yellow_dark-diagonal-2px.svg │ ├── yellow_dark-diagonal-3px.svg │ ├── yellow_dark-diagonal-4px.svg │ ├── yellow_dark-diagonal-5px.svg │ ├── yellow_dark-diagonal-6px.svg │ ├── yellow_desaturated-diagonal-1px.svg │ ├── yellow_desaturated-diagonal-2px.svg │ ├── yellow_desaturated-diagonal-3px.svg │ ├── yellow_desaturated-diagonal-4px.svg │ ├── yellow_desaturated-diagonal-5px.svg │ ├── yellow_desaturated-diagonal-6px.svg │ ├── yellow_light-diagonal-1px.svg │ ├── yellow_light-diagonal-2px.svg │ ├── yellow_light-diagonal-3px.svg │ ├── yellow_light-diagonal-4px.svg │ ├── yellow_light-diagonal-5px.svg │ └── yellow_light-diagonal-6px.svg ├── data ├── base │ └── style.json ├── layer-groups │ ├── aerials.json │ ├── amendments-pending.json │ ├── amendments.json │ ├── appendixj-designated-mdistricts.json │ ├── arterials.json │ ├── assembly-districts.json │ ├── bike-routes.json │ ├── bk-qn-mh-boundary.json │ ├── boat-launches.json │ ├── boroughs.json │ ├── building-footprints.json │ ├── business-improvement-districts.json │ ├── census-blocks.json │ ├── census-tracts.json │ ├── cho-greater-transit-zone.json │ ├── cho-transit-zones.json │ ├── choropleths.json │ ├── citibike-stations.json │ ├── citymap.json │ ├── coastal-zone-boundary.json │ ├── commercial-overlay-patterns.json │ ├── commercial-overlays.json │ ├── community-district-tabulation-areas.json │ ├── community-districts.json │ ├── e-designations.json │ ├── effective-flood-insurance-rate-2007.json │ ├── factfinder--boroughs.json │ ├── factfinder--ccds.json │ ├── factfinder--cdtas.json │ ├── factfinder--census-blocks.json │ ├── factfinder--census-tracts-2020.json │ ├── factfinder--census-tracts.json │ ├── factfinder--cities.json │ ├── factfinder--community-districts.json │ ├── factfinder--districts.json │ ├── factfinder--neighborhood-tabulation-areas.json │ ├── factfinder--ntas.json │ ├── factfinder--pumas.json │ ├── factfinder--zip-codes.json │ ├── ferries.json │ ├── floodplain-efirm2007.json │ ├── floodplain-pfirm2015.json │ ├── fresh.json │ ├── historic-districts.json │ ├── inclusionary-housing.json │ ├── industrial-business-zones.json │ ├── landmarks.json │ ├── limited-height-districts.json │ ├── low-density-growth-mgmt-areas.json │ ├── mandatory-inclusionary-housing.json │ ├── name-changes.json │ ├── neighborhood-tabulation-areas.json │ ├── ny-senate-districts.json │ ├── nyc-council-districts-combined.json │ ├── nyc-council-districts.json │ ├── nyc-pumas.json │ ├── paper-streets.json │ ├── pierhead-bulkhead-lines.json │ ├── preliminary-flood-insurance-rate-2015.json │ ├── preliminary-flood-insurance-rate.json │ ├── sidewalks.json │ ├── special-purpose-districts.json │ ├── special-purpose-subdistricts.json │ ├── stair-streets.json │ ├── street-centerlines.json │ ├── street-direction-arrows.json │ ├── street-sections.json │ ├── subway.json │ ├── tax-lots.json │ ├── three-d-buildings.json │ ├── transit-zones.json │ ├── transportation-structures.json │ ├── waterfront-access--entry-points.json │ ├── waterfront-access--publicly-owned.json │ ├── waterfront-access--wpaas.json │ ├── waterfront-access-plan.json │ ├── zip-codes.json │ ├── zoning-districts.json │ ├── zoning-for-accessibility.json │ ├── zoning-map-amendments-pending.json │ ├── zoning-map-amendments.json │ └── zoning-map-index.json └── sources │ ├── admin-boundaries.json │ ├── aerials-1924.json │ ├── aerials-1951.json │ ├── aerials-1996.json │ ├── aerials-20012.json │ ├── aerials-2004.json │ ├── aerials-2006.json │ ├── aerials-2008.json │ ├── aerials-2010.json │ ├── aerials-2012.json │ ├── aerials-2014.json │ ├── aerials-2016.json │ ├── aerials-2018.json │ ├── aerials-2020.json │ ├── aerials-2022.json │ ├── boat-launches.json │ ├── census-geoms-2020.json │ ├── census-geoms-plus.json │ ├── census-geoms.json │ ├── choropleths.json │ ├── citibike-stations.json │ ├── digital-citymap.json │ ├── effective-flood-insurance-rate-2007.json │ ├── factfinder--admin-boundaries.json │ ├── ferries.json │ ├── floodplains.json │ ├── landmark-historic.json │ ├── nyc-council-districts-combined.json │ ├── paws.json │ ├── planimetrics.json │ ├── pluto.json │ ├── preliminary-flood-insurance-rate.json │ ├── supporting-zoning.json │ ├── transportation.json │ ├── zoning-districts.json │ └── zoning-map-amendments.json ├── newrelic.js ├── package.json ├── process-data ├── .gitignore ├── etl │ ├── acs_2023.csv │ ├── build_choropleths.ipynb │ ├── choropleths.json │ ├── decennial_2010.csv │ ├── decennial_2020.csv │ └── nta_boundaries.csv └── requirements.txt ├── public └── static │ ├── sprite.json │ ├── sprite.png │ ├── sprite@2x.json │ ├── sprite@2x.png │ └── v3.json ├── routes └── v1 │ ├── base.js │ ├── index.js │ ├── layer-groups.js │ └── sources.js ├── schemas ├── layer-group.js ├── layer.js └── source.js ├── scripts └── aliased-views │ ├── README.md │ ├── update_carto_views.py │ └── view_lookup.csv ├── serializers └── layer-groups.js ├── tasks └── migrate-meta-from-layer-group-to-source.js ├── test ├── acceptance │ ├── routes.layer-group.test.js │ └── routes.layer-groups.error-handling.test.js ├── unit │ ├── carto-response.json │ └── utils.structure-carto-source.test.js └── validations │ ├── data.js │ └── eslint.js ├── utils ├── build-mapbox-style.js ├── carto.js ├── deep-merge-with-array-replace.js ├── local-resources-utilities │ ├── -load-json.js │ ├── find-all.js │ ├── find.js │ ├── index.js │ └── where.js ├── structure-carto-source.js └── structure-regular-source.js └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | /process-data 2 | /node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parserOptions": { 4 | "ecmaVersion": 2018, 5 | "sourceType": "module" 6 | }, 7 | "extends": [ 8 | "airbnb-base" 9 | ], 10 | "env": { 11 | "node": true, 12 | "mocha": true 13 | }, 14 | "rules": { 15 | "func-names": 0, 16 | "camelcase": 0, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a report to help us improve the code 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature Request" 3 | about: Suggest an idea 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /assets/sprite/svg/* 3 | 4 | **/.DS_Store 5 | newrelic_agent.log 6 | 7 | .env 8 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @NYCPlanning/Engineering 2 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | #### User Story 3 | As a {type of user}, I want {some goal} so that {some reason} 4 | 5 | #### Description 6 | What's it all about? 7 | 8 | 9 | #### What should happen: 10 | 11 | #### What happened instead: 12 | 13 | #### How to reproduce this bug: 14 | 15 | 1. Step one 16 | 2. ??? 17 | 3. Error 18 | 19 | #### Browser(s) and Device(s) observed on: 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As a work of the government, this project is in the 2 | public domain within the United States. 3 | 4 | Additionally, we waive copyright and related rights in the work 5 | worldwide through the CC0 1.0 Universal public domain dedication. 6 | 7 | ## CC0 1.0 Universal summary 8 | 9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode). 10 | 11 | ### No copyright 12 | 13 | The person who associated a work with this deed has dedicated the work to 14 | the public domain by waiving all rights to the work worldwide 15 | under copyright law, including all related and neighboring rights, to the 16 | extent allowed by law. 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | ### Other information 22 | 23 | In no way are the patent or trademark rights of any person affected by CC0, 24 | nor are the rights that other persons may have in the work or in how the 25 | work is used, such as publicity or privacy rights. 26 | 27 | Unless expressly stated otherwise, the person who associated a work with 28 | this deed makes no warranties about the work, and disclaims liability for 29 | all uses of the work, to the fullest extent permitted by applicable law. 30 | When using or citing the work, you should not imply endorsement by the 31 | author or the affirmer. 32 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ### Summary 6 | 15 | 16 | #### Tasks/Bug Numbers 17 | - Fixes AB#1234 18 | 21 | - Related AB#1235 22 | - Reverses AB#1222 23 | 24 | ### Technical Explanation 25 | 37 | 38 | ### Any other info you think would help a reviewer understand this PR? 39 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node app.js 2 | -------------------------------------------------------------------------------- /assets/sprite/svg/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/aqua_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/blue_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/chartreuse_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/fuchsia_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/gold_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/green_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/indigo_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/orange_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/purple_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/red_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/teal_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_dark-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_dark-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_dark-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_dark-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_dark-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_dark-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_desaturated-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_desaturated-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_desaturated-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_desaturated-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_desaturated-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_desaturated-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_light-diagonal-1px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_light-diagonal-2px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_light-diagonal-3px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_light-diagonal-4px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_light-diagonal-5px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/sprite/svg/yellow_light-diagonal-6px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/layer-groups/amendments-pending.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "amendments-pending", 3 | "legend": { 4 | "label": "Pending City Map Alterations", 5 | "tooltip": "Proposed Alterations to the City Map that have been approved in public review but have not yet been officially enacted. These alterations have not yet taken effect and are shown for illustrative purposes.", 6 | "icon": { 7 | "type": "fa-icon", 8 | "layers": [ 9 | { 10 | "fa-icon": "square", 11 | "color": "rgba(240, 15, 130, 0.4)", 12 | "transform": "left-2 down-2" 13 | }, 14 | { 15 | "fa-icon": "square", 16 | "color": "rgba(240, 15, 130, 0.4)", 17 | "transform": "right-2 up-2" 18 | } 19 | ] 20 | } 21 | }, 22 | "layers": [ 23 | { 24 | "before": "place_other", 25 | "style": { 26 | "id": "citymap-amendments-fill-pending", 27 | "type": "fill", 28 | "source": "digital-citymap", 29 | "source-layer": "amendments", 30 | "paint": { 31 | "fill-color": "rgba(240, 15, 130, 0.4)" 32 | }, 33 | "layout": {}, 34 | "filter": [ 35 | "==", 36 | "status", 37 | "13" 38 | ] 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /data/layer-groups/amendments.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "amendments", 3 | "visible": true, 4 | "legend": { 5 | "label": "Adopted City Map Alterations", 6 | "tooltip": "An index of alterations to the City Map. Alteration Maps show changes made to the City Map and, when they are the most recent in an area, serve as an official record of the City Map in the area they depict.", 7 | "icon": { 8 | "type": "fa-icon", 9 | "layers": [ 10 | { 11 | "fa-icon": "square", 12 | "color": "rgba(174, 86, 31, 0.4)", 13 | "transform": "left-2 down-2" 14 | }, 15 | { 16 | "fa-icon": "square", 17 | "color": "rgba(174, 86, 31, 0.4)", 18 | "transform": "right-2 up-2" 19 | } 20 | ] 21 | } 22 | }, 23 | "layers": [ 24 | { 25 | "before": "place_other", 26 | "style": { 27 | "id": "citymap-amendments-fill", 28 | "type": "fill", 29 | "source": "digital-citymap", 30 | "source-layer": "amendments", 31 | "paint": { 32 | "fill-color": "rgba(174, 86, 31, 0.2)" 33 | }, 34 | "layout": {}, 35 | "filter": [ 36 | "==", 37 | "status", 38 | "14" 39 | ] 40 | } 41 | } 42 | ], 43 | "legendConfig": { 44 | "items": [ 45 | { 46 | "type": "area", 47 | "label": "City Map Alterations", 48 | "style": { 49 | "stroke": "none", 50 | "fill": "rgba(174, 86, 31, 0.4)" 51 | } 52 | } 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /data/layer-groups/bike-routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "bike-routes", 3 | "legend": { 4 | "label": "Bike Routes", 5 | "icon": { 6 | "type": "line", 7 | "layers": [ 8 | { 9 | "stroke": "rgba(18, 237, 18, 0.3)", 10 | "stroke-width": 2.5 11 | } 12 | ] 13 | } 14 | }, 15 | "layers": [ 16 | { 17 | "before": "place_other", 18 | "style": { 19 | "id": "bike_routes", 20 | "source": "transportation", 21 | "source-layer": "bike-routes", 22 | "type": "line", 23 | "paint": { 24 | "line-color": "rgba(18, 237, 18, 0.3)", 25 | "line-width": { 26 | "stops": [ 27 | [ 28 | 10, 29 | 0.5 30 | ], 31 | [ 32 | 15, 33 | 8 34 | ] 35 | ] 36 | } 37 | } 38 | } 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /data/layer-groups/bk-qn-mh-boundary.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "bk-qn-mh-boundary", 3 | "legend": { 4 | "label": "Borough Boundaries", 5 | "icon": { 6 | "type": "line", 7 | "layers": [ 8 | { 9 | "fill": "none", 10 | "stroke-width": "2.5", 11 | "stroke": "rgba(50,100,100,0.4)" 12 | } 13 | ] 14 | } 15 | }, 16 | "layers": [ 17 | { 18 | "tooltipable": true, 19 | "tooltipTemplate": "{{{boro_boundary}}}", 20 | "style": { 21 | "id": "bk-qn-mh-boundary-line", 22 | "type": "line", 23 | "source": "admin-boundaries", 24 | "source-layer": "bk-qn-mh-boundary", 25 | "paint": { 26 | "line-color": "rgba(50,100,100,0.4)", 27 | "line-width": { 28 | "stops": [ 29 | [ 30 | 10, 31 | 3 32 | ], 33 | [ 34 | 13, 35 | 4 36 | ], 37 | [ 38 | 15, 39 | 5 40 | ] 41 | ] 42 | } 43 | } 44 | } 45 | } 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /data/layer-groups/boat-launches.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "boat-launches", 3 | "legend": { 4 | "label": "Boat Launches", 5 | "icon": { 6 | "type": "fa-icon", 7 | "layers": [ 8 | { 9 | "fa-icon": "circle", 10 | "color": "rgba(75, 0, 122, 1)", 11 | "transform": "shrink-4" 12 | }, 13 | { 14 | "fa-icon": "circle", 15 | "color": "rgba(179, 179, 255, 1)", 16 | "transform": "shrink-10" 17 | } 18 | ] 19 | } 20 | }, 21 | "layers": [ 22 | { 23 | "before": "place_other", 24 | "style": { 25 | "id": "boat-launches", 26 | "type": "circle", 27 | "source": "boat-launches", 28 | "source-layer": "boat-launches", 29 | "paint": { 30 | "circle-color": "rgba(179, 179, 255, 1)", 31 | "circle-radius": { 32 | "stops": [ 33 | [9, 1], 34 | [14, 2], 35 | [16, 3] 36 | ] 37 | }, 38 | "circle-stroke-color": "rgba(75, 0, 122, 1)", 39 | "circle-stroke-width": { 40 | "stops": [ 41 | [9, 1], 42 | [14, 2], 43 | [16, 3] 44 | ] 45 | } 46 | } 47 | }, 48 | "tooltipable": true, 49 | "tooltipTemplate": "{{{name}}}" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /data/layer-groups/boroughs.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "boroughs", 3 | "legend": { 4 | "label": "Boroughs", 5 | "icon": { 6 | "type": "line", 7 | "layers": [ 8 | { 9 | "stroke": "#edbd12", 10 | "stroke-width": 4, 11 | "stroke-opacity": 0.5 12 | }, 13 | { 14 | "stroke": "#7a6000", 15 | "stroke-width": 1.5, 16 | "stroke-opacity": 0.8 17 | } 18 | ] 19 | } 20 | }, 21 | "layers": [ 22 | { 23 | "style": { 24 | "id": "boroughs-line-glow", 25 | "type": "line", 26 | "source": "admin-boundaries", 27 | "source-layer": "boroughs", 28 | "paint": { 29 | "line-color": "#edbd12", 30 | "line-opacity": 0.5, 31 | "line-width": { 32 | "stops": [ 33 | [ 34 | 11, 35 | 4 36 | ], 37 | [ 38 | 16, 39 | 8 40 | ] 41 | ] 42 | } 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "boroughs-line", 49 | "type": "line", 50 | "source": "admin-boundaries", 51 | "source-layer": "boroughs", 52 | "paint": { 53 | "line-color": "#7a6000", 54 | "line-opacity": 0.8, 55 | "line-width": { 56 | "stops": [ 57 | [ 58 | 11, 59 | 1 60 | ], 61 | [ 62 | 16, 63 | 3 64 | ] 65 | ] 66 | } 67 | }, 68 | "layout": { 69 | "line-join": "round", 70 | "line-cap": "round" 71 | } 72 | } 73 | } 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /data/layer-groups/building-footprints.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "building-footprints", 3 | "visible": true, 4 | "legend": { 5 | "label": "Building Footprints", 6 | "tooltip": "Building footprints based on OpenStreetMap data", 7 | "icon": { 8 | "type": "fa-icon", 9 | "layers": [ 10 | { 11 | "fa-icon": "square", 12 | "prefix": "far", 13 | "color": "rgba(175, 175, 175, 1)" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "building-footprints", 22 | "type": "fill", 23 | "source": "openmaptiles", 24 | "source-layer": "building", 25 | "minzoom": 15, 26 | "paint": { 27 | "fill-opacity": { 28 | "stops": [ 29 | [ 30 | 15, 31 | 0 32 | ], 33 | [ 34 | 16, 35 | 0.3 36 | ] 37 | ] 38 | }, 39 | "fill-color": "rgba(175, 175, 175, 1)" 40 | } 41 | } 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /data/layer-groups/business-improvement-districts.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "business-improvement-districts", 3 | "visible": false, 4 | "legend": { 5 | "label": "Business Improvement Districts", 6 | "tooltip": "A Business Improvement District (BID) is a geographical area where local stakeholders oversee and fund the maintenance, improvement, and promotion of their commercial district.", 7 | "icon": { 8 | "type": "rectangle", 9 | "layers": [ 10 | { 11 | "fill": "rgba(118, 66, 10, 0.2)", 12 | "stroke": "rgba(118, 66, 10, 0.6)", 13 | "stroke-dasharray": "1" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "business-improvement-districts-line", 22 | "type": "line", 23 | "source": "supporting-zoning", 24 | "source-layer": "business-improvement-districts", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(118, 66, 10, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "business-improvement-districts-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "business-improvement-districts", 52 | "paint": { 53 | "fill-color": "rgba(118, 66, 10, 0.2)" 54 | } 55 | }, 56 | "highlightable": true, 57 | "tooltipable": true, 58 | "tooltipTemplate": "{{{bid}}}" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /data/layer-groups/cho-greater-transit-zone.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "cho-greater-transit-zone", 3 | "legend": { 4 | "label": "Greater Transit Zone", 5 | "tooltip": "The rules for Qualifying Residential Sites are modified by a lot’s relationship to the Greater Transit Zone. Being located within the Greater Transit Zone may allow for more or different development opportunities.", 6 | "infolink": "https://zr.planning.nyc.gov", 7 | "icon": { 8 | "type": "rectangle", 9 | "layers": [ 10 | { 11 | "fill": "rgba(254, 113, 37, 0.3)", 12 | "stroke": "rgba(254, 113, 37, 0.6)", 13 | "stroke-dasharray": "1" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "cho-greater-transit-zone-line", 22 | "type": "line", 23 | "source": "supporting-zoning", 24 | "source-layer": "cho-greater-transit-zone", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(254, 113, 37, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "cho-greater-transit-zone-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "cho-greater-transit-zone", 52 | "paint": { 53 | "fill-color": "rgba(254, 113, 37, 0.3)" 54 | }, 55 | "layout": {} 56 | }, 57 | "highlightable": true, 58 | "tooltipable": true, 59 | "tooltipTemplate": "Greater Transit Zone" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/layer-groups/choropleths.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "choropleths", 3 | "title": "Thematic Maps (NTAs)", 4 | "titleTooltip": "Neighborhood Tabulation Area maps for selected variables", 5 | "visible": false, 6 | "legend": { 7 | "label": "Thematic Maps (NTAs)", 8 | "icon": { 9 | "type": "line", 10 | "layers": [ 11 | { 12 | "stroke": "#2929ed", 13 | "stroke-width": 4, 14 | "stroke-opacity": 0.3 15 | }, 16 | { 17 | "stroke": "#00007a", 18 | "stroke-width": 1.5, 19 | "stroke-opacity": 0.6 20 | } 21 | ] 22 | } 23 | }, 24 | "layers": [ 25 | { 26 | "style": { 27 | "id": "choropleth-nta-fill", 28 | "type": "fill", 29 | "source": "choropleths", 30 | "paint": { "fill-opacity": 0.6, "fill-color": "#994d4d" } 31 | } 32 | }, 33 | { 34 | "style": { 35 | "id": "choropleth-nta-line", 36 | "type": "line", 37 | "source": "choropleths", 38 | "paint": { 39 | "line-width": { 40 | "stops": [ 41 | [10, 2], 42 | [14, 5] 43 | ] 44 | }, 45 | "line-opacity": 0.6, 46 | "line-color": "#994d4d", 47 | "line-translate-anchor": "map" 48 | } 49 | } 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /data/layer-groups/citibike-stations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "citibike-stations", 3 | "legend": { 4 | "label": "Citibike Stations", 5 | "icon": { 6 | "type": "fa-icon", 7 | "layers": [ 8 | { 9 | "fa-icon": "circle", 10 | "color": "rgba(18, 157, 237, 1)", 11 | "transform": "shrink-4" 12 | }, 13 | { 14 | "fa-icon": "circle", 15 | "color": "rgba(179, 227, 255, 1)", 16 | "transform": "shrink-10" 17 | } 18 | ] 19 | } 20 | }, 21 | "layers": [ 22 | { 23 | "before": "place_other", 24 | "style": { 25 | "id": "citibike-stations", 26 | "type": "circle", 27 | "source": "citibike-stations", 28 | "source-layer": "citibike-stations", 29 | "paint": { 30 | "circle-color": "rgba(179, 227, 255, 1)", 31 | "circle-radius": { 32 | "stops": [ 33 | [9, 1], 34 | [14, 2], 35 | [16, 3] 36 | ] 37 | }, 38 | "circle-stroke-color": "rgba(18, 157, 237, 1)", 39 | "circle-stroke-width": { 40 | "stops": [ 41 | [9, 1], 42 | [14, 2], 43 | [16, 3] 44 | ] 45 | } 46 | } 47 | }, 48 | "tooltipable": true, 49 | "tooltipTemplate": "{{{name}}}" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /data/layer-groups/coastal-zone-boundary.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "coastal-zone-boundary", 3 | "legend": { 4 | "label": "Coastal Zone Boundary", 5 | "tooltip": "Projects within the coastal zone boundary are subject to additional review under the Waterfront Revitalization Program", 6 | "infolink": "https://www1.nyc.gov/site/planning/data-maps/open-data/dwn-wrp.page", 7 | "icon": { 8 | "type": "rectangle", 9 | "layers": [ 10 | { 11 | "fill": "rgba(93, 198, 228, 0.2)", 12 | "stroke": "rgba(93, 198, 228, 0.6)", 13 | "stroke-dasharray": "1" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "coastal-zone-boundary-line", 22 | "type": "line", 23 | "source": "supporting-zoning", 24 | "source-layer": "coastal-zone-boundary", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(93, 198, 228, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "coastal-zone-boundary-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "coastal-zone-boundary", 52 | "paint": { 53 | "fill-color": "rgba(93, 198, 228, 0.2)" 54 | }, 55 | "layout": {} 56 | }, 57 | "highlightable": true, 58 | "tooltipable": true, 59 | "tooltipTemplate": "Coastal Zone Boundary" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/layer-groups/factfinder--zip-codes.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "factfinder--zip-codes", 3 | "legend": { 4 | "label": "ZIP Codes", 5 | "icon": { 6 | "type": "line", 7 | "layers": [ 8 | { 9 | "stroke": "#ff6699", 10 | "stroke-width": 4, 11 | "stroke-opacity": 0.3 12 | }, 13 | { 14 | "stroke": "#ff6699", 15 | "stroke-width": 1.5, 16 | "stroke-opacity": 0.6 17 | } 18 | ] 19 | } 20 | }, 21 | "layers": [ 22 | { 23 | "style": { 24 | "id": "zip-code-line-glow", 25 | "type": "line", 26 | "source": "factfinder--admin-boundaries", 27 | "source-layer": "zip-codes", 28 | "paint": { 29 | "line-color": "#ff6699", 30 | "line-opacity": 0.3, 31 | "line-width": { 32 | "stops": [ 33 | [ 34 | 11, 35 | 4 36 | ], 37 | [ 38 | 16, 39 | 8 40 | ] 41 | ] 42 | } 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "zip-code-line", 49 | "type": "line", 50 | "source": "factfinder--admin-boundaries", 51 | "source-layer": "codes", 52 | "paint": { 53 | "line-color": "#ff6699", 54 | "line-opacity": 0.6, 55 | "line-width": { 56 | "stops": [ 57 | [ 58 | 11, 59 | 1 60 | ], 61 | [ 62 | 16, 63 | 3 64 | ] 65 | ] 66 | } 67 | }, 68 | "layout": { 69 | "line-join": "round", 70 | "line-cap": "round" 71 | } 72 | } 73 | } 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /data/layer-groups/historic-districts.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "historic-districts", 3 | "legend": { 4 | "label": "Historic Districts", 5 | "tooltip": "Areas designated by the NYC Landmarks Preservation Commission that possess historical significance and to which special zoning regulations apply", 6 | "icon": { 7 | "type": "rectangle", 8 | "layers": [ 9 | { 10 | "fill": "rgba(70, 130, 180, 0.2)", 11 | "stroke": "rgba(70, 130, 180, 0.6)", 12 | "stroke-dasharray": "1" 13 | } 14 | ] 15 | } 16 | }, 17 | "layers": [ 18 | { 19 | "style": { 20 | "id": "historic-districts-line", 21 | "type": "line", 22 | "source": "landmark-historic", 23 | "source-layer": "historic-districts", 24 | "paint": { 25 | "line-width": { 26 | "stops": [ 27 | [ 28 | 11, 29 | 1 30 | ], 31 | [ 32 | 12, 33 | 3 34 | ] 35 | ] 36 | }, 37 | "line-color": "rgba(70, 130, 180, 0.6)", 38 | "line-dasharray": [ 39 | 1, 40 | 1 41 | ] 42 | } 43 | } 44 | }, 45 | { 46 | "style": { 47 | "id": "historic-districts-fill", 48 | "type": "fill", 49 | "source": "landmark-historic", 50 | "source-layer": "historic-districts", 51 | "paint": { 52 | "fill-color": "rgba(70, 130, 180, 0.2)" 53 | }, 54 | "layout": {} 55 | }, 56 | "highlightable": true, 57 | "tooltipable": true, 58 | "tooltipTemplate": "{{{area_name}}}" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /data/layer-groups/inclusionary-housing.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "inclusionary-housing", 3 | "legend": { 4 | "label": "Inclusionary Housing Designated Areas", 5 | "tooltip": "Areas where zoning incentives are offered to encourage the creation of permanently affordable housing", 6 | "infolink": "https://www1.nyc.gov/site/planning/zoning/districts-tools/inclusionary-housing.page", 7 | "icon": { 8 | "type": "rectangle", 9 | "layers": [ 10 | { 11 | "fill": "rgba(229, 115, 0, 0.2)", 12 | "stroke": "rgba(229, 115, 0, 0.6)", 13 | "stroke-dasharray": "1" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "inclusionary-housing-line", 22 | "type": "line", 23 | "source": "supporting-zoning", 24 | "source-layer": "inclusionary-housing", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(229, 115, 0, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "inclusionary-housing-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "inclusionary-housing", 52 | "paint": { 53 | "fill-color": "rgba(229, 115, 0, 0.2)", 54 | "fill-opacity": 0.2 55 | }, 56 | "layout": {} 57 | }, 58 | "highlightable": true, 59 | "tooltipable": true, 60 | "tooltipTemplate": "{{{projectnam}}}" 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /data/layer-groups/industrial-business-zones.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "industrial-business-zones", 3 | "legend": { 4 | "label": "Industrial Business Zones", 5 | "tooltip": "Industrial Business Zones (IBZs) are areas where expanded business services are available for industrial and manufacturing businesses. This designation fosters high-performing business districts by creating competitive advantages over locating in areas outside of New York City.", 6 | "icon": { 7 | "type": "rectangle", 8 | "layers": [ 9 | { 10 | "fill": "rgba(43, 10, 118, 0.2)", 11 | "stroke": "rgba(43, 10, 118, 0.6)", 12 | "stroke-dasharray": "1" 13 | } 14 | ] 15 | } 16 | }, 17 | "layers": [ 18 | { 19 | "style": { 20 | "id": "industrial-business-zones-line", 21 | "type": "line", 22 | "source": "supporting-zoning", 23 | "source-layer": "industrial-business-zones", 24 | "paint": { 25 | "line-width": { 26 | "stops": [ 27 | [ 28 | 11, 29 | 1 30 | ], 31 | [ 32 | 12, 33 | 3 34 | ] 35 | ] 36 | }, 37 | "line-color": "rgba(43, 10, 118, 0.6)", 38 | "line-dasharray": [ 39 | 1, 40 | 1 41 | ] 42 | } 43 | } 44 | }, 45 | { 46 | "style": { 47 | "id": "industrial-business-zones-fill", 48 | "type": "fill", 49 | "source": "supporting-zoning", 50 | "source-layer": "industrial-business-zones", 51 | "paint": { 52 | "fill-color": "rgba(43, 10, 118, 0.2)" 53 | }, 54 | "layout": {} 55 | }, 56 | "highlightable": true, 57 | "tooltipable": true, 58 | "tooltipTemplate": "{{{name}}} IBZ" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /data/layer-groups/sidewalks.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "sidewalks", 3 | "legend": { 4 | "label": "Sidewalks", 5 | "icon": { 6 | "type": "fa-icon", 7 | "layers": [ 8 | { 9 | "fa-icon": "rectangle", 10 | "color": "rgba(84, 84, 84, 0.5)" 11 | } 12 | ] 13 | } 14 | }, 15 | "layers": [ 16 | { 17 | "style": { 18 | "id": "sidewalks-line", 19 | "type": "line", 20 | "source": "planimetrics", 21 | "source-layer": "sidewalks", 22 | "paint": { 23 | "line-width": { 24 | "stops": [ 25 | [ 26 | 11, 27 | 1 28 | ], 29 | [ 30 | 12, 31 | 3 32 | ] 33 | ] 34 | }, 35 | "line-color": "rgba(84, 84, 84, 0)" 36 | } 37 | } 38 | }, 39 | { 40 | "style": { 41 | "id": "sidewalks-fill", 42 | "type": "fill", 43 | "source": "planimetrics", 44 | "source-layer": "sidewalks", 45 | "paint": { 46 | "fill-color": "rgba(84, 84, 84, 1)", 47 | "fill-opacity": 0.2 48 | } 49 | } 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /data/layer-groups/special-purpose-districts.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "special-purpose-districts", 3 | "legend": { 4 | "label": "Special Purpose Districts", 5 | "tooltip": "The regulations for special purpose districts are designed to supplement and modify the underlying zoning in order to respond to distinctive neighborhoods with particular issues and goals", 6 | "icon": { 7 | "type": "fa-icon", 8 | "layers": [ 9 | { 10 | "fa-icon": "square", 11 | "color": "rgba(94,102,51, 1)" 12 | } 13 | ] 14 | } 15 | }, 16 | "layers": [ 17 | { 18 | "style": { 19 | "id": "zoning-sp-line", 20 | "type": "line", 21 | "source": "supporting-zoning", 22 | "source-layer": "special-purpose-districts", 23 | "paint": { 24 | "line-width": { 25 | "stops": [ 26 | [ 27 | 11, 28 | 1 29 | ], 30 | [ 31 | 12, 32 | 3 33 | ] 34 | ] 35 | }, 36 | "line-color": "rgba(94,102,51, 0.6)", 37 | "line-dasharray": [ 38 | 1, 39 | 1 40 | ] 41 | } 42 | } 43 | }, 44 | { 45 | "style": { 46 | "id": "zoning-sp-fill", 47 | "type": "fill", 48 | "source": "supporting-zoning", 49 | "source-layer": "special-purpose-districts", 50 | "paint": { 51 | "fill-color": "#5E6633", 52 | "fill-opacity": 0.2 53 | } 54 | } 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /data/layer-groups/special-purpose-subdistricts.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "special-purpose-subdistricts", 3 | "legend": { 4 | "label": "Special Purpose Subdistricts", 5 | "tooltip": "Areas within Special Purpose Districts where unique rules apply. Special Purpose Subdistrict data is currently incomplete. See the Zoning Resolution for a complete description of the special purpose district.", 6 | "infolink": "https://zr.planning.nyc.gov", 7 | "icon": { 8 | "type": "fa-icon", 9 | "layers": [ 10 | { 11 | "fa-icon": "square", 12 | "color": "#8DA610" 13 | } 14 | ] 15 | } 16 | }, 17 | "layers": [ 18 | { 19 | "style": { 20 | "id": "zoning-sp-sd-line", 21 | "type": "line", 22 | "source": "supporting-zoning", 23 | "source-layer": "special-purpose-subdistricts", 24 | "paint": { 25 | "line-width": { 26 | "stops": [ 27 | [ 28 | 11, 29 | 1 30 | ], 31 | [ 32 | 12, 33 | 3 34 | ] 35 | ] 36 | }, 37 | "line-color": "#8DA610", 38 | "line-dasharray": [ 39 | 1, 40 | 1 41 | ], 42 | "line-opacity": 0.6 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "zoning-sp-sd-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "special-purpose-subdistricts", 52 | "paint": { 53 | "fill-color": "#8DA610", 54 | "fill-opacity": 0.2 55 | }, 56 | "layout": {} 57 | }, 58 | "highlightable": true, 59 | "clickable": true, 60 | "tooltipable": true, 61 | "tooltipTemplate": "{{{spname}}} - {{{subdist}}}" 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /data/layer-groups/street-centerlines.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "street-centerlines", 3 | "legend": { 4 | "label": "Street Names", 5 | "tooltip": "Legal street names as shown on the City Map" 6 | }, 7 | "visible": true, 8 | "layers": [ 9 | { 10 | "before": "place_country_major", 11 | "style": { 12 | "id": "citymap-street-centerlines-symbol", 13 | "type": "symbol", 14 | "source": "digital-citymap", 15 | "source-layer": "street-centerlines", 16 | "minzoom": 13, 17 | "layout": { 18 | "text-field": "{streetname}{streetwidth}", 19 | "text-keep-upright": true, 20 | "symbol-placement": "line", 21 | "text-size": 12 22 | }, 23 | "paint": { 24 | "text-color": "rgba(37, 37, 37, 1)", 25 | "text-halo-color": "#fff", 26 | "text-translate": [ 27 | 0, 28 | 0 29 | ], 30 | "text-halo-width": 2, 31 | "text-halo-blur": 1 32 | } 33 | } 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /data/layer-groups/street-sections.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "street-sections", 3 | "visible": true, 4 | "legend": { 5 | "label": "Final Section Map", 6 | "tooltip": "An index of New York City Final Section maps that include the boundaries of each borough's Final Section maps (except for Staten Island), maintained by each borough. Both Final Section maps and Alteration maps comprise the City Map of New York City.", 7 | "icon": { 8 | "type": "line", 9 | "layers": [ 10 | { 11 | "stroke": "#2B7C3B", 12 | "stroke-linecap": "round", 13 | "stroke-dasharray": [2, 2] 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "before": "place_other", 21 | "style": { 22 | "id": "street-sections", 23 | "type": "line", 24 | "source": "digital-citymap", 25 | "source-layer": "street-sections", 26 | "layout": {}, 27 | "paint": { 28 | "line-color": "rgba(43, 124, 59, 0.4)", 29 | "line-dasharray": [2, 1], 30 | "line-width": 2 31 | } 32 | } 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /data/layer-groups/three-d-buildings.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "three-d-buildings", 3 | "legend": { 4 | "label": "3D Buildings", 5 | "tooltip": "Extruded building height from OpenStreetMap data" 6 | }, 7 | "layers": [ 8 | { 9 | "style": { 10 | "id": "three-d-buildings", 11 | "type": "fill-extrusion", 12 | "source": "openmaptiles", 13 | "source-layer": "building", 14 | "minzoom": 0, 15 | "paint": { 16 | "fill-extrusion-color": "rgba(203, 203, 203, 1)", 17 | "fill-extrusion-opacity": 0.95, 18 | "fill-extrusion-translate": [ 19 | 3, 20 | 0 21 | ], 22 | "fill-extrusion-height": { 23 | "property": "render_height", 24 | "type": "identity" 25 | }, 26 | "fill-extrusion-base": { 27 | "property": "render_min_height", 28 | "type": "identity" 29 | } 30 | } 31 | } 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /data/layer-groups/transit-zones.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "transit-zones", 3 | "legend": { 4 | "label": "Appendix I", 5 | "tooltip": "Transit-accessible areas where special streetscape and special parking requirements apply.", 6 | "infolink": "https://www1.nyc.gov/site/planning/zoning/glossary.page#transit_zone", 7 | "icon": { 8 | "type": "rectangle", 9 | "layers": [ 10 | { 11 | "fill": "rgba(49, 151, 149, 0.2)", 12 | "stroke": "rgba(49, 151, 149, 0.6)", 13 | "stroke-dasharray": "1" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "transit-zones-line", 22 | "type": "line", 23 | "source": "supporting-zoning", 24 | "source-layer": "transit-zones", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(49, 151, 149, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "transit-zones-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "transit-zones", 52 | "paint": { 53 | "fill-color": "rgba(49, 151, 149, 0.2)" 54 | }, 55 | "layout": {} 56 | }, 57 | "highlightable": true, 58 | "tooltipable": true, 59 | "tooltipTemplate": "Appendix I" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/layer-groups/transportation-structures.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "transportation-structures", 3 | "legend": { 4 | "label": "Transportation Structures", 5 | "tooltip": "Bridges, tunnels, rail bridges, pedestrian/bike bridge, railroad viaducts, and overpasses", 6 | "icon": { 7 | "type": "fa-icon", 8 | "layers": [ 9 | { 10 | "fa-icon": "rectangle", 11 | "color": "rgba(84, 84, 84, 0.5)" 12 | } 13 | ] 14 | } 15 | }, 16 | "layers": [ 17 | { 18 | "style": { 19 | "id": "transportation-structures-line", 20 | "type": "line", 21 | "source": "planimetrics", 22 | "source-layer": "transportation-structures", 23 | "paint": { 24 | "line-width": { 25 | "stops": [ 26 | [ 27 | 11, 28 | 1 29 | ], 30 | [ 31 | 12, 32 | 3 33 | ] 34 | ] 35 | }, 36 | "line-color": "rgba(84, 84, 84, 0)" 37 | } 38 | } 39 | }, 40 | { 41 | "style": { 42 | "id": "transportation-structures-fill", 43 | "type": "fill", 44 | "source": "planimetrics", 45 | "source-layer": "transportation-structures", 46 | "paint": { 47 | "fill-color": "rgba(84, 84, 84, 1)", 48 | "fill-opacity": 0.2 49 | } 50 | } 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /data/layer-groups/waterfront-access--entry-points.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "waterfront-access--entry-points", 3 | "legend": { 4 | "label": "Entry Points", 5 | "icon": { 6 | "type": "fa-icon", 7 | "layers": [ 8 | { 9 | "fa-icon": "circle", 10 | "color": "rgba(0, 122, 0, 1)", 11 | "transform": "shrink-4" 12 | }, 13 | { 14 | "fa-icon": "circle", 15 | "color": "rgba(179, 255, 179, 1)", 16 | "transform": "shrink-10" 17 | } 18 | ] 19 | } 20 | }, 21 | "layers": [ 22 | { 23 | "before": "place_other", 24 | "style": { 25 | "id": "wpaas-entry-points", 26 | "type": "circle", 27 | "source": "paws", 28 | "source-layer": "paws_entry_points", 29 | "minzoom":14, 30 | "paint": { 31 | "circle-color": "rgba(179, 255, 179, 1)", 32 | "circle-radius": { 33 | "stops": [ 34 | [14, 2], 35 | [16, 4] 36 | ] 37 | }, 38 | "circle-stroke-color": "rgba(0, 122, 0, 1)", 39 | "circle-stroke-width": { 40 | "stops": [ 41 | [14, 2], 42 | [16, 3] 43 | ] 44 | }, 45 | "circle-opacity": { 46 | "stops": [ 47 | [14, 0.5], 48 | [16, 1] 49 | ] 50 | }, 51 | "circle-stroke-opacity": { 52 | "stops": [ 53 | [14, 0.5], 54 | [16, 1] 55 | ] 56 | } 57 | } 58 | }, 59 | "tooltipable": true 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/layer-groups/waterfront-access--publicly-owned.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "waterfront-access--publicly-owned", 3 | "legend": { 4 | "label": "Public Parks and Facilities", 5 | "icon": { 6 | "type": "rectangle", 7 | "layers": [ 8 | { 9 | "fill": "rgba(178, 201, 134, 1)", 10 | "stroke": "rgba(178, 201, 134, 0.6)", 11 | "stroke-width": "2" 12 | } 13 | ] 14 | } 15 | }, 16 | "layers": [ 17 | { 18 | "before": "building", 19 | "style": { 20 | "id": "publicly-owned-waterfront-fill", 21 | "type": "fill", 22 | "source": "paws", 23 | "source-layer": "publiclyownedwaterfront", 24 | "paint": { 25 | "fill-color": "rgba(178, 201, 134, 1)" 26 | } 27 | } 28 | }, 29 | { 30 | "style": { 31 | "id": "publicly-owned-waterfront-overlay", 32 | "type": "fill", 33 | "source": "paws", 34 | "source-layer": "publiclyownedwaterfront", 35 | "paint": { 36 | "fill-color": "rgba(178, 201, 134, 0.5)" 37 | } 38 | }, 39 | "highlightable": true, 40 | "clickable": true, 41 | "tooltipable": true, 42 | "tooltipTemplate": "{{{park_name}}}" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /data/layer-groups/waterfront-access-plan.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "waterfront-access-plan", 3 | "legend": { 4 | "label": "Waterfront Access Plan", 5 | "tooltip": "These areas reflect site specific modification of waterfront public access requirements for waterfront parcels with unique conditions and opportunities", 6 | "infolink": "https://www1.nyc.gov/site/planning/zoning/districts-tools/waterfront-zoning.page", 7 | "icon": { 8 | "type": "rectangle", 9 | "layers": [ 10 | { 11 | "fill": "rgba(0, 164, 210, 0.2)", 12 | "stroke": "rgba(0, 164, 210, 0.6)", 13 | "stroke-dasharray": "1" 14 | } 15 | ] 16 | } 17 | }, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "waterfront-access-plan-line", 22 | "type": "line", 23 | "source": "supporting-zoning", 24 | "source-layer": "waterfront-access-plan", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(0, 164, 210, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "waterfront-access-plan-fill", 49 | "type": "fill", 50 | "source": "supporting-zoning", 51 | "source-layer": "waterfront-access-plan", 52 | "paint": { 53 | "fill-color": "rgba(0, 164, 210, 0.2)" 54 | }, 55 | "layout": {} 56 | }, 57 | "highlightable": true, 58 | "tooltipable": true, 59 | "tooltipTemplate": "Waterfront Access Plan - {{{name}}}" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/layer-groups/zip-codes.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "zip-codes", 3 | "legend": { 4 | "label": "Zipcodes", 5 | "icon": { 6 | "type": "line", 7 | "layers": [ 8 | { 9 | "stroke": "#ff6699", 10 | "stroke-width": 4, 11 | "stroke-opacity": 0.3 12 | }, 13 | { 14 | "stroke": "#ff6699", 15 | "stroke-width": 1.5, 16 | "stroke-opacity": 0.6 17 | } 18 | ] 19 | } 20 | }, 21 | "layers": [ 22 | { 23 | "style": { 24 | "id": "zip-code-line-glow", 25 | "type": "line", 26 | "source": "factfinder--admin-boundaries", 27 | "source-layer": "zip-codes", 28 | "paint": { 29 | "line-color": "#ff6699", 30 | "line-opacity": 0.3, 31 | "line-width": { 32 | "stops": [ 33 | [ 34 | 11, 35 | 4 36 | ], 37 | [ 38 | 16, 39 | 8 40 | ] 41 | ] 42 | } 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "zip-code-line", 49 | "type": "line", 50 | "source": "factfinder--admin-boundaries", 51 | "source-layer": "codes", 52 | "paint": { 53 | "line-color": "#ff6699", 54 | "line-opacity": 0.6, 55 | "line-width": { 56 | "stops": [ 57 | [ 58 | 11, 59 | 1 60 | ], 61 | [ 62 | 16, 63 | 3 64 | ] 65 | ] 66 | } 67 | }, 68 | "layout": { 69 | "line-join": "round", 70 | "line-cap": "round" 71 | } 72 | } 73 | } 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /data/layer-groups/zoning-for-accessibility.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "zoning-for-accessibility", 3 | "legend": { 4 | "label": "Zoning For Accessibility", 5 | "tooltip": "Transit-adjacent areas where applicable developments and enlargements require additional consultation with the MTA or relevant transit agencies.", 6 | "infolink": "https://zr.planning.nyc.gov/article-vi/chapter-6" 7 | }, 8 | "layers": [ 9 | { 10 | "before": "place_state", 11 | "style": { 12 | "id": "zfa-line", 13 | "type": "line", 14 | "source": "supporting-zoning", 15 | "source-layer": "zoning-for-accessibility", 16 | "paint": { 17 | "line-width": { 18 | "stops": [ 19 | [ 20 | 11, 21 | 1 22 | ], 23 | [ 24 | 12, 25 | 3 26 | ] 27 | ] 28 | }, 29 | "line-color": "#0039A6" 30 | } 31 | } 32 | }, 33 | { 34 | "highlightable": true, 35 | "clickable": true, 36 | "tooltipable": true, 37 | "tooltipTemplate": "Transit-adjacent area - {{{station_na}}} Station", 38 | "style": { 39 | "id": "zfa-fill", 40 | "type": "fill", 41 | "source": "supporting-zoning", 42 | "source-layer": "zoning-for-accessibility", 43 | "paint": { 44 | "fill-color": "rgba(0, 57, 16, 0.5)", 45 | "fill-opacity": { 46 | "stops": [ 47 | [ 48 | 15, 49 | 0.1 50 | ], 51 | [ 52 | 16, 53 | 0.1 54 | ] 55 | ] 56 | }, 57 | "fill-antialias": true 58 | } 59 | } 60 | } 61 | ] 62 | } -------------------------------------------------------------------------------- /data/layer-groups/zoning-map-amendments-pending.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "zoning-map-amendments-pending", 3 | "legend": { 4 | "label": "Pending Zoning Map Amendments", 5 | "tooltip": "Changes to the Zoning Map that are currently undergoing public review", 6 | "icon": { 7 | "type": "rectangle", 8 | "layers": [ 9 | { 10 | "fill": "rgba(176, 31, 31, 0.6)", 11 | "stroke": "rgba(176, 31, 31, 0.6)", 12 | "stroke-dasharray": "1" 13 | } 14 | ] 15 | } 16 | }, 17 | "visible": false, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "zmacert-line", 22 | "type": "line", 23 | "source": "zoning-map-amendments", 24 | "source-layer": "zoning-map-amendments-pending", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(176, 31, 31, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "zmacert-fill", 49 | "type": "fill", 50 | "source": "zoning-map-amendments", 51 | "source-layer": "zoning-map-amendments-pending", 52 | "paint": { 53 | "fill-color": "rgba(176, 31, 31, 0.6)" 54 | } 55 | }, 56 | "highlightable": true, 57 | "clickable": true, 58 | "tooltipable": true, 59 | "tooltipTemplate": "{{{project_na}}}" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/layer-groups/zoning-map-amendments.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "zoning-map-amendments", 3 | "legend": { 4 | "label": "Zoning Map Amendments", 5 | "tooltip": "Changes to the Zoning Map that have been adopted since 2002", 6 | "icon": { 7 | "type": "rectangle", 8 | "layers": [ 9 | { 10 | "fill": "rgba(159, 199, 62, 0.6)", 11 | "stroke": "rgba(159, 199, 62, 0.6)", 12 | "stroke-dasharray": "1" 13 | } 14 | ] 15 | } 16 | }, 17 | "visible": false, 18 | "layers": [ 19 | { 20 | "style": { 21 | "id": "zma-line", 22 | "type": "line", 23 | "source": "zoning-map-amendments", 24 | "source-layer": "zoning-map-amendments", 25 | "paint": { 26 | "line-width": { 27 | "stops": [ 28 | [ 29 | 11, 30 | 1 31 | ], 32 | [ 33 | 12, 34 | 3 35 | ] 36 | ] 37 | }, 38 | "line-color": "rgba(159, 199, 62, 0.6)", 39 | "line-dasharray": [ 40 | 1, 41 | 1 42 | ] 43 | } 44 | } 45 | }, 46 | { 47 | "style": { 48 | "id": "zma-fill", 49 | "type": "fill", 50 | "source": "zoning-map-amendments", 51 | "source-layer": "zoning-map-amendments", 52 | "paint": { 53 | "fill-color": "rgba(159, 199, 62, 0.6)" 54 | } 55 | }, 56 | "highlightable": true, 57 | "clickable": true, 58 | "tooltipable": true, 59 | "tooltipTemplate": "{{{project_na}}} - Effective {{{effectiveformatted}}}" 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /data/sources/aerials-1924.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-1924", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/Ortho_1924_Mosaic/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-1951.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-1951", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_1951/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-1996.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-1996", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/Ortho_1996_Mosaic/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-20012.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-20012", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2001_2/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2004.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2004", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Ortho_2004/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2006.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2006", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2006/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2008.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2008", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2008/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2010.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2010", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2010/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2012.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2012", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2012/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2014.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2014", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2014/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2016.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2016", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2016/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/sources/aerials-2018.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2018", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2018/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } -------------------------------------------------------------------------------- /data/sources/aerials-2020.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2020", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_-_2020/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } -------------------------------------------------------------------------------- /data/sources/aerials-2022.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "aerials-2022", 3 | "type": "raster", 4 | "tiles": [ 5 | "https://tiles.arcgis.com/tiles/yG5s3afENB5iO9fj/arcgis/rest/services/NYC_Orthos_2022/MapServer/tile/{z}/{y}/{x}" 6 | ], 7 | "tileSize": 256, 8 | "meta": { 9 | "description": "NYC OTI GIS Aerial Photography Tile Layers (TMS)", 10 | "url": [ 11 | "https://tiles.arcgis.com/tiles/" 12 | ], 13 | "updated_at": "n/a" 14 | } 15 | } -------------------------------------------------------------------------------- /data/sources/boat-launches.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "boat-launches", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "boat-launches", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id, link, name FROM wam_hpb_launches" 8 | } 9 | ], 10 | "meta": { 11 | "description": "Human Powered Boat Launches", 12 | "url": [ 13 | "https://www1.nyc.gov/site/planning/data-maps/open-data/dwn-waterfront.page" 14 | ], 15 | "updated_at": "December 2019" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /data/sources/census-geoms-2020.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "census-geoms-2020", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "census-geoms-tracts-2020", 7 | "sql": "SELECT the_geom_webmercator, ct2020, ctlabel as geolabel, boroct2020, nta2020, boroct2020 AS geoid, boroct2020 AS id, 7 as pop, 9 as hh FROM pff_2020_census_tracts_21c", 8 | "dataPipeline": false 9 | }, 10 | { 11 | "id": "census-geoms-blocks-2020", 12 | "sql": "SELECT the_geom_webmercator, ct2020, borocode || ct2020 AS boroct2020, cb2020, boroname, borocode, bctcb2020, bctcb2020 AS geoid, geoid AS id, bctcb2020 as geolabel FROM pff_2020_census_blocks_21c", 13 | "dataPipeline": false 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /data/sources/census-geoms-plus.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "census-geoms-plus", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "census-geoms-tracts", 7 | "sql": "SELECT the_geom_webmercator, ct2010, ctlabel as geolabel, boroct2010, ntacode, boroct2010 AS geoid, boroct2010 AS id, 7 as pop, 9 as hh FROM dcp_census_tracts_2010", 8 | "dataPipeline": true 9 | }, 10 | { 11 | "id": "census-geoms-blocks", 12 | "sql": "SELECT the_geom_webmercator, ct2010, borocode || ct2010 AS boroct2010, cb2010, borocode, bctcb2010, bctcb2010 AS geoid, bctcb2010 AS id, (ct2010::float / 100)::text || ' - ' || cb2010 as geolabel FROM dcp_census_blocks_2010", 13 | "dataPipeline": true 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /data/sources/census-geoms.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "census-geoms", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "census-geoms-tracts", 7 | "sql": "SELECT the_geom_webmercator, ct2010, ctlabel as geolabel, boroct2010, ntacode, boroct2010 AS geoid, boroct2010 AS id FROM dcp_census_tracts_2010", 8 | "dataPipeline": true 9 | }, 10 | { 11 | "id": "census-geoms-blocks", 12 | "sql": "SELECT the_geom_webmercator, ct2010, borocode || ct2010 AS boroct2010, cb2010, borocode, bctcb2010, bctcb2010 AS geoid, bctcb2010 AS id, (ct2010::float / 100)::text || ' - ' || cb2010 as geolabel FROM dcp_census_blocks_2010", 13 | "dataPipeline": true 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /data/sources/citibike-stations.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "citibike-stations", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "citibike-stations", 7 | "sql": "SELECT the_geom_webmercator, station::json->>'name' AS name, station::json->>'capacity' AS capacity, station::json->>'bikes_available' AS bikes_available, station::json->>'docks_available' AS docks_available FROM citibike_stations WHERE station::json->>'capacity' <> '0'" 8 | } 9 | ], 10 | "meta": { 11 | "description": "Citibike Stations", 12 | "url": [ 13 | "https://layer.bicyclesharing.net/map/v1/nyc/map-inventory" 14 | ], 15 | "updated_at": "October 2018, synced every hour" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /data/sources/effective-flood-insurance-rate-2007.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "effective-flood-insurance-rate-2007", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "effective-flood-insurance-rate-2007", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, CASE WHEN fld_zone IN ('A', 'A0', 'AE') THEN 'A' WHEN fld_zone = 'VE' THEN 'V' END as fld_zone FROM floodplain_firm2007 WHERE fld_zone IN ('A', 'A0', 'AE') OR fld_zone = 'VE'" 8 | } 9 | ], 10 | "minzoom": 0, 11 | "meta": { 12 | "description": "Effective Flood Insurance Rate Maps (FIRMs) data are available at FEMA Flood Map Service Center", 13 | "url": [ 14 | "https://msc.fema.gov/portal" 15 | ], 16 | "updated_at": "September 2017" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /data/sources/ferries.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ferries", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "ferry-routes", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id, route_name FROM nyc_ferry_routes_v202205" 8 | }, 9 | { 10 | "id": "ferry-landings", 11 | "sql": "SELECT the_geom_webmercator, name, link FROM nyc_ferry_landings_v202205 WHERE status <> 'Inactive'" 12 | } 13 | ], 14 | "minzoom": 0, 15 | "meta": { 16 | "description": "Ferry Routes and Landings, NYC Department of City Planning Waterfront Division", 17 | "url": [ 18 | "https://planninglabs.carto.com/api/v2/sql?q=SELECT * FROM nyc_ferry_routes_v202205s&format=SHP", 19 | "https://planninglabs.carto.com/api/v2/sql?q=SELECT * FROM nyc_ferry_landings_v202205&format=SHP" 20 | ], 21 | "updated_at": "May 2022" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data/sources/floodplains.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "floodplains", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "effective-flood-insurance-rate-2007", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, CASE WHEN fld_zone IN ('A', 'A0', 'AE') THEN 'A' WHEN fld_zone = 'VE' THEN 'V' WHEN fld_zone = '0.2 PCT ANNUAL CHANCE FLOOD HAZARD' THEN 'Shaded X' END as fld_zone FROM fema_firm WHERE fld_zone IN ('A', 'A0', 'AE') OR fld_zone = 'VE' OR fld_zone = '0.2 PCT ANNUAL CHANCE FLOOD HAZARD'" 8 | }, 9 | { 10 | "id": "preliminary-flood-insurance-rate", 11 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, CASE WHEN fld_zone IN ('A', 'A0', 'AE') THEN 'A' WHEN fld_zone = 'VE' THEN 'V' WHEN fld_zone = '0.2 PCT ANNUAL CHANCE FLOOD HAZARD' THEN 'Shaded X' END as fld_zone FROM fema_pfirm WHERE fld_zone IN ('A', 'A0', 'AE') OR fld_zone = 'VE' OR fld_zone = '0.2 PCT ANNUAL CHANCE FLOOD HAZARD'" 12 | } 13 | ], 14 | "meta": { 15 | "description": "Flood Insurance Rate Data provided by FEMA", 16 | "url": [ 17 | "http://www.region2coastal.com/view-flood-maps-data/view-preliminary-flood-map-data/" 18 | ], 19 | "updated_at": "November 2018" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data/sources/landmark-historic.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "landmark-historic", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "historic-districts", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, area_name FROM lpc_historic_districts WHERE status_of_ = 'DESIGNATED'", 8 | "dataPipeline": true 9 | }, 10 | { 11 | "id": "landmarks", 12 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, lm_name, lm_type FROM lpc_individual_and_interior_landmarks WHERE (lm_type = 'Individual Landmark' OR lm_type = 'Interior Landmark') AND last_actio = 'DESIGNATED'", 13 | "dataPipeline": true 14 | }, 15 | { 16 | "id": "scenic-landmarks", 17 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, scen_lm_na FROM lpc_scenic_landmarks WHERE last_actio = 'DESIGNATED'", 18 | "dataPipeline": true 19 | } 20 | ], 21 | "minzoom": 0, 22 | "meta": { 23 | "description": "Designated and Calendared Buildings and Sites, NYC Open Data Portal", 24 | "url": [ 25 | "https://data.cityofnewyork.us/Housing-Development/Designated-and-Calendared-Buildings-and-Sites/ncre-qhxs" 26 | ], 27 | "updated_at": "July 2021" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /data/sources/nyc-council-districts-combined.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "nyc-council-districts-combined", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "nyc-council-districts-combined", 7 | "sql": "SELECT *, '2024' AS year FROM dcp_city_council_districts UNION SELECT *, '2013' AS year FROM dcp_city_council_districts_2013" 8 | } 9 | ], 10 | "meta": { 11 | "description": "Data layer for displaying the current NYC Council Districts 2013-2023 and the upcoming NYC Council Districts 2024-2033", 12 | "url": [ 13 | "https://council.nyc.gov/districts/" 14 | ], 15 | "updated_at": "May 2023" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /data/sources/planimetrics.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "planimetrics", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "sidewalks", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id FROM sidewalks_v201809" 8 | }, 9 | { 10 | "id": "transportation-structures", 11 | "sql": "SELECT the_geom_webmercator, cartodb_id FROM transportation_structures_v201809" 12 | } 13 | ], 14 | "minzoom": 0, 15 | "meta": { 16 | "description": "NYC Planimetrics Database, Department of Information Technology & Telecommunications (DoITT)", 17 | "url": [ 18 | "https://data.cityofnewyork.us/City-Government/Sidewalk/vfx9-tbb6", 19 | "https://data.cityofnewyork.us/City-Government/Transportation-Structures/h9sf-7bej" 20 | ], 21 | "updated_at": "26 February 2019" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data/sources/pluto.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "pluto", 3 | "type": "cartovector", 4 | "minzoom": 12, 5 | "source-layers": [ 6 | { 7 | "id": "pluto", 8 | "sql": "SELECT bbl AS id, the_geom_webmercator, bbl, lot, landuse, address, numfloors, notes FROM dcp_mappluto", 9 | "dataPipeline": true 10 | }, 11 | { 12 | "id": "block-centroids", 13 | "sql": "SELECT the_geom_webmercator, block FROM dof_dtm_block_centroids", 14 | "dataPipeline": true 15 | } 16 | ], 17 | "buffersize": { 18 | "mvt": 10 19 | }, 20 | "meta": { 21 | "description": "MapPLUTO™, Bytes of the Big Apple", 22 | "url": [ 23 | "https://www1.nyc.gov/site/planning/data-maps/open-data/dwn-pluto-mappluto.page#mappluto" 24 | ], 25 | "updated_at": "November 2022" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /data/sources/preliminary-flood-insurance-rate.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "preliminary-flood-insurance-rate", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "preliminary-flood-insurance-rate", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, CASE WHEN fld_zone IN ('A', 'A0', 'AE') THEN 'A' WHEN fld_zone = 'VE' THEN 'V' WHEN fld_zone = '0.2 PCT ANNUAL CHANCE FLOOD HAZARD' THEN 'Shaded X' END as fld_zone FROM floodplain_pfirm2015 WHERE fld_zone IN ('A', 'A0', 'AE') OR fld_zone = 'VE'" 8 | } 9 | ], 10 | "minzoom": 0, 11 | "meta": { 12 | "description": "Flood Insurance Rate Data provided by FEMA", 13 | "url": [ 14 | "http://www.region2coastal.com/view-flood-maps-data/view-preliminary-flood-map-data/" 15 | ], 16 | "updated_at": "November 2018" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /data/sources/transportation.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "transportation", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "bike-routes", 7 | "sql": "SELECT the_geom_webmercator, cartodb_id FROM bike_routes" 8 | }, 9 | { 10 | "id": "subway-routes", 11 | "sql": "SELECT the_geom_webmercator, rt_symbol FROM mta_subway_routes" 12 | }, 13 | { 14 | "id": "subway-stops", 15 | "sql": "SELECT the_geom_webmercator, name FROM mta_subway_stops" 16 | }, 17 | { 18 | "id": "subway-entrances", 19 | "sql": "SELECT the_geom_webmercator, cartodb_id FROM mta_subway_entrances" 20 | } 21 | ], 22 | "minzoom": 0, 23 | "meta": { 24 | "description": "NYC Subway Lines and Stops - Originally Sourced from NYC DoITT GIS, combined with SI Railway data from Baruch College NYC Mass Transit Spatial Layers | Subway entrances from NYC Open Data", 25 | "url": [ 26 | "https://planninglabs.carto.com/api/v2/sql?q=SELECT * FROM mta_subway_stops&format=SHP", 27 | "https://planninglabs.carto.com/api/v2/sql?q=SELECT * FROM mta_subway_routes&format=SHP", 28 | "https://data.cityofnewyork.us/Transportation/Subway-Entrances/drex-xx56", 29 | "https://www.baruch.cuny.edu/confluence/display/geoportal/NYC+Mass+Transit+Spatial+Layers" 30 | ], 31 | "updated_at": "21 November 2017" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /data/sources/zoning-districts.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "zoning-districts", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "zoning-districts", 7 | "sql": "SELECT cartodb_id AS id, * FROM (SELECT the_geom_webmercator, zonedist, CASE WHEN SUBSTRING(zonedist, 3, 1) = '-' THEN LEFT(zonedist, 2) WHEN SUBSTRING(zonedist, 3, 1) ~ E'[A-Z]' THEN LEFT(zonedist, 2) WHEN SUBSTRING(zonedist, 3, 1) ~ E'[0-9]' THEN LEFT(zonedist, 3) ELSE zonedist END as primaryzone, cartodb_id FROM dcp_zoning_districts) a", 8 | "dataPipeline": true 9 | } 10 | ], 11 | "buffersize": { 12 | "mvt": 10 13 | }, 14 | "meta": { 15 | "description": "NYC GIS Zoning Features, Bytes of the Big Apple", 16 | "url": [ 17 | "https://www1.nyc.gov/site/planning/data-maps/open-data.page" 18 | ], 19 | "data_date": "March 2023", 20 | "updated_at": "March 2023" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /data/sources/zoning-map-amendments.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "zoning-map-amendments", 3 | "type": "cartovector", 4 | "source-layers": [ 5 | { 6 | "id": "zoning-map-amendments", 7 | "sql": "SELECT * FROM (SELECT the_geom_webmercator, to_char(effective, 'MM/DD/YYYY') as effectiveformatted, extract(epoch from effective) * 1000 as effective_epoch, cartodb_id AS id, ulurpno, status, project_na FROM dcp_zoning_map_amendments WHERE status = 'Adopted') a", 8 | "dataPipeline": true 9 | }, 10 | { 11 | "id": "zoning-map-amendments-pending", 12 | "sql": "SELECT the_geom_webmercator, cartodb_id AS id, ulurpno, status, project_na FROM dcp_zoning_map_amendments WHERE status = 'Certified'", 13 | "dataPipeline": true 14 | } 15 | ], 16 | "buffersize": { 17 | "mvt": 10 18 | }, 19 | "meta": { 20 | "description": "NYC GIS Zoning Features, Bytes of the Big Apple", 21 | "url": [ 22 | "https://www1.nyc.gov/site/planning/data-maps/open-data/dwn-gis-zoning.page" 23 | ], 24 | "data_date": "December 2022", 25 | "updated_at": "December 2022" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /newrelic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * New Relic agent configuration. 3 | * 4 | * See lib/config/default.js in the agent distribution for a more complete 5 | * description of configuration variables and their potential values. 6 | */ 7 | 8 | exports.config = { 9 | /** 10 | * Array of application names. 11 | */ 12 | app_name: ['Layers API (Production)'], 13 | /** 14 | * Your New Relic license key. 15 | */ 16 | license_key: process.env.NEW_RELIC_LICENSE_KEY, 17 | logging: { 18 | /** 19 | * Level at which to log. 'trace' is most useful to New Relic when diagnosing 20 | * issues with the agent, 'info' and higher will impose the least overhead on 21 | * production applications. 22 | */ 23 | level: 'info', 24 | }, 25 | /** 26 | * When true, all request headers except for those listed in attributes.exclude 27 | * will be captured for all traces, unless otherwise specified in a destination's 28 | * attributes include/exclude lists. 29 | */ 30 | allow_all_headers: true, 31 | attributes: { 32 | /** 33 | * Prefix of attributes to exclude from all destinations. Allows * as wildcard 34 | * at end. 35 | * 36 | * NOTE: If excluding headers, they must be in camelCase form to be filtered. 37 | * 38 | * @env NEW_RELIC_ATTRIBUTES_EXCLUDE 39 | */ 40 | exclude: [ 41 | 'request.headers.cookie', 42 | 'request.headers.authorization', 43 | 'request.headers.proxyAuthorization', 44 | 'request.headers.setCookie*', 45 | 'request.headers.x*', 46 | 'response.headers.cookie', 47 | 'response.headers.authorization', 48 | 'response.headers.proxyAuthorization', 49 | 'response.headers.setCookie*', 50 | 'response.headers.x*', 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "labs-layers-api", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "https://github.com/NYCPlanning/labs-layers-api.git", 6 | "author": "NYC Planning ", 7 | "license": "MIT", 8 | "dependencies": { 9 | "@koa/cors": "2", 10 | "@sentry/node": "^6.18.2", 11 | "@sentry/tracing": "^6.18.2", 12 | "array-unique": "^0.3.2", 13 | "deepmerge": "2.1.1", 14 | "dotenv": "^16.0.0", 15 | "joi": "13.5.2", 16 | "jsonapi-serializer": "3.5.6", 17 | "koa": "^2.5.2", 18 | "koa-bodyparser": "^4.2.1", 19 | "koa-router": "^7.4.0", 20 | "koa-static": "^5.0.0", 21 | "load-json-file": "^5.0.0", 22 | "nock": "^13.3.1", 23 | "node-fetch": "^2.2.0", 24 | "nodemon": "^1.18.4", 25 | "rsvp": "^4.8.3" 26 | }, 27 | "devDependencies": { 28 | "chai": "^4.3.7", 29 | "chai-http": "^4.3.0", 30 | "chai-things": "^0.2.0", 31 | "eslint": "^6.0.1", 32 | "eslint-config-airbnb-base": "^13.2.0", 33 | "eslint-plugin-ember": "^5.2.0", 34 | "eslint-plugin-import": "^2.12.0", 35 | "glob": "^7.1.2", 36 | "mocha": "^5.2.0" 37 | }, 38 | "scripts": { 39 | "postinstall": "npm run create-sprite-svgs", 40 | "start": "node app.js", 41 | "dev": "nodemon --inspect app.js", 42 | "test": "PORT=3001 NODE_ENV=test node ./node_modules/mocha/bin/mocha ./test/**/*.js --exit", 43 | "watch-tests": "nodemon --exec 'npm run test || true'", 44 | "create-sprite-svgs": "node ./assets/sprite/create-sprite-svgs.js", 45 | "migrate-meta": "node ./tasks/migrate-meta-from-layer-group-to-source.js" 46 | }, 47 | "engines": { 48 | "node": "20.x" 49 | }, 50 | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" 51 | } 52 | -------------------------------------------------------------------------------- /process-data/.gitignore: -------------------------------------------------------------------------------- 1 | venv -------------------------------------------------------------------------------- /process-data/requirements.txt: -------------------------------------------------------------------------------- 1 | asttokens==2.2.1 2 | attrs==22.2.0 3 | backcall==0.2.0 4 | black==23.1.0 5 | certifi==2022.12.7 6 | click==8.1.3 7 | click-plugins==1.1.1 8 | cligj==0.7.2 9 | comm==0.1.2 10 | debugpy==1.6.6 11 | decorator==5.1.1 12 | executing==1.2.0 13 | Fiona==1.9.1 14 | geopandas==0.12.2 15 | ipykernel==6.21.3 16 | ipython==8.11.0 17 | jedi==0.18.2 18 | jupyter_client==8.0.3 19 | jupyter_core==5.3.0 20 | matplotlib-inline==0.1.6 21 | munch==2.5.0 22 | mypy-extensions==1.0.0 23 | nest-asyncio==1.5.6 24 | numpy==1.24.2 25 | packaging==23.0 26 | pandas==1.5.3 27 | parso==0.8.3 28 | pathspec==0.11.1 29 | pexpect==4.8.0 30 | pickleshare==0.7.5 31 | platformdirs==3.1.1 32 | prompt-toolkit==3.0.38 33 | psutil==5.9.4 34 | ptyprocess==0.7.0 35 | pure-eval==0.2.2 36 | Pygments==2.14.0 37 | pyproj==3.4.1 38 | python-dateutil==2.8.2 39 | pytz==2022.7.1 40 | pyzmq==25.0.2 41 | shapely==2.0.1 42 | six==1.16.0 43 | stack-data==0.6.2 44 | tokenize-rt==5.0.0 45 | tornado==6.2 46 | traitlets==5.9.0 47 | wcwidth==0.2.6 48 | -------------------------------------------------------------------------------- /public/static/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NYCPlanning/labs-layers-api/65bfc8a129bdc7ce19e6651a3873d1f293087fbe/public/static/sprite.png -------------------------------------------------------------------------------- /public/static/sprite@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NYCPlanning/labs-layers-api/65bfc8a129bdc7ce19e6651a3873d1f293087fbe/public/static/sprite@2x.png -------------------------------------------------------------------------------- /routes/v1/base.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router'); 2 | const style = require('../../data/base/style.json'); 3 | 4 | const router = new Router(); 5 | 6 | const HOST = process.env.HOST || 'http://localhost:3000'; 7 | 8 | router.get('/style.json', async (ctx) => { 9 | style.sources.openmaptiles.url = style.sources.openmaptiles.url.replace('{{HOSTNAME}}', HOST); 10 | style.sprite = style.sprite.replace('{{HOSTNAME}}', HOST); 11 | 12 | ctx.body = style; 13 | }); 14 | 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /routes/v1/index.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router'); 2 | const layerGroups = require('./layer-groups'); 3 | const sources = require('./sources'); 4 | const base = require('./base'); 5 | 6 | const router = new Router(); 7 | 8 | router.use('/v1/layer-groups', layerGroups.routes()); 9 | router.use('/v1/sources', sources.routes()); 10 | router.use('/v1/base', base.routes()); 11 | 12 | router.get('/v1', async (ctx) => { 13 | ctx.body = { 14 | status: 'v1 is working', 15 | }; 16 | }); 17 | 18 | module.exports = router; 19 | -------------------------------------------------------------------------------- /routes/v1/sources.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router'); 2 | const { findAll, where } = require('../../utils/local-resources-utilities'); 3 | 4 | const router = new Router(); 5 | 6 | router.get('/', async (ctx) => { 7 | // const config = ctx.request.query; 8 | // const { sources: ids } = config; 9 | 10 | const data = await findAll('sources'); 11 | 12 | ctx.body = { 13 | data: data.map((resource) => { 14 | const { id } = resource; 15 | 16 | return { 17 | id, 18 | type: 'sources', 19 | attributes: resource, 20 | }; 21 | }), 22 | }; 23 | }); 24 | 25 | router.post('/', async (ctx) => { 26 | const config = ctx.request.body; 27 | const { sources: ids } = config; 28 | 29 | const data = await where('sources', { id: ids }); 30 | 31 | ctx.body = { data }; 32 | }); 33 | 34 | module.exports = router; 35 | -------------------------------------------------------------------------------- /schemas/layer-group.js: -------------------------------------------------------------------------------- 1 | const Joi = require('joi'); 2 | const layerSchema = require('./layer'); 3 | 4 | const legendIconSchema = Joi.object().keys({ 5 | type: Joi.string().valid( 6 | 'line', 7 | 'rectangle', 8 | 'fa-icon', 9 | 'square-hatch', 10 | ).required(), 11 | layers: Joi.when('type', { 12 | is: 'fa-icon', 13 | then: Joi.array().items( 14 | Joi.object().keys({ 15 | 'fa-icon': Joi.string().required(), 16 | }).unknown(), 17 | ), 18 | otherwise: Joi.array().items(Joi.object()), 19 | }), 20 | }); 21 | 22 | const legendItemSchema = Joi.object().keys({ 23 | label: Joi.string().required(), 24 | tooltip: Joi.string(), 25 | icon: legendIconSchema, 26 | }); 27 | 28 | module.exports = Joi.object().keys({ 29 | id: Joi.string().required(), 30 | visible: Joi.boolean(), 31 | filter: Joi.array(), 32 | title: Joi.string(), 33 | titleTooltip: Joi.string(), 34 | legend: Joi.object().keys({ 35 | label: Joi.string().required(), 36 | tooltip: Joi.string(), 37 | infolink: Joi.string(), 38 | icon: legendIconSchema, 39 | items: Joi.array().items( 40 | legendItemSchema, 41 | ), 42 | }), 43 | layerVisibilityType: Joi.string(), 44 | 45 | meta: Joi.object(), 46 | layers: Joi.array().items( 47 | layerSchema, 48 | ), 49 | legendConfig: Joi.object(), 50 | legendIcon: Joi.string(), 51 | legendColor: Joi.string(), 52 | }); 53 | -------------------------------------------------------------------------------- /schemas/layer.js: -------------------------------------------------------------------------------- 1 | const Joi = require('joi'); 2 | 3 | module.exports = Joi.object({ 4 | style: Joi.object().required(), 5 | displayName: Joi.string(), 6 | before: Joi.string(), 7 | clickable: Joi.boolean(), 8 | highlightable: Joi.boolean(), 9 | tooltipable: Joi.boolean(), 10 | tooltipTemplate: Joi.string(), 11 | }); 12 | -------------------------------------------------------------------------------- /schemas/source.js: -------------------------------------------------------------------------------- 1 | const Joi = require('joi'); 2 | 3 | module.exports = Joi.object().keys({ 4 | id: Joi.string().required(), 5 | type: Joi.valid( 6 | 'vector', 7 | 'raster', 8 | 'geojson', 9 | 'cartovector', 10 | ), 11 | data: Joi.object().when('type', { 12 | is: 'geojson', 13 | then: Joi.required() 14 | }), 15 | minzoom: Joi.number(), 16 | maxzoom: Joi.number(), 17 | 'source-layers': Joi.array().items(Joi.object()) 18 | .when('type', { 19 | is: 'cartovector', 20 | then: Joi.required(), 21 | }), 22 | tiles: Joi.array().items(Joi.string()).when('type', { 23 | is: 'raster', 24 | then: Joi.required(), 25 | }), 26 | tileSize: Joi.number().when('type', { 27 | is: 'raster', 28 | then: Joi.required(), 29 | }), 30 | buffersize: Joi.object().keys({ 31 | mvt: Joi.number(), 32 | }), 33 | meta: Joi.object(), 34 | }); 35 | -------------------------------------------------------------------------------- /tasks/migrate-meta-from-layer-group-to-source.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { findAll } = require('../utils/local-resources-utilities'); 3 | 4 | (async () => { 5 | const layerGroups = await findAll('layer-groups'); 6 | const sources = await findAll('sources'); 7 | 8 | layerGroups.forEach((layerGroup) => { 9 | const layerGroupMeta = layerGroup.meta; 10 | 11 | layerGroup.layers.forEach((layer) => { 12 | const matchingSource = sources.find(source => source.id === layer.style.source); 13 | if (matchingSource) matchingSource.meta = layerGroupMeta || {}; 14 | }); 15 | }); 16 | 17 | sources.forEach((source) => { 18 | fs.writeFile(`./data/sources/${source.id}.json`, JSON.stringify(source, null, 2) + "\n", (err) => { // eslint-disable-line 19 | if (err) { 20 | return console.log(err); 21 | } 22 | 23 | console.log(source.id, ' has been saved'); 24 | }); 25 | }); 26 | 27 | layerGroups.forEach((layerGroup) => { 28 | delete layerGroup.meta; // eslint-disable-line 29 | 30 | fs.writeFile(`./data/layer-groups/${layerGroup.id}.json`, JSON.stringify(layerGroup, null, 2) + "\n", (err) => { // eslint-disable-line 31 | if (err) { 32 | return console.log(err); 33 | } 34 | 35 | console.log(layerGroup.id, ' has been saved'); 36 | }); 37 | }); 38 | })(); 39 | -------------------------------------------------------------------------------- /test/acceptance/routes.layer-groups.error-handling.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const chaiHttp = require('chai-http'); 3 | const chaiThings = require('chai-things'); 4 | const nock = require('nock'); 5 | const server = require('../../app'); 6 | 7 | chai.use(chaiThings); 8 | chai.use(chaiHttp); 9 | 10 | describe('POST /layer-groups', () => { 11 | after(() => { 12 | nock.cleanAll(); 13 | }); 14 | 15 | it('handles an error response from Carto', (done) => { 16 | const tempNock = nock('https://planninglabs.carto.com') 17 | .post('/api/v1/map') 18 | .reply(500, { error: ['timeout'] }); 19 | 20 | chai.request(server) 21 | .post('/v1/layer-groups') 22 | .set('content-type', 'application/json') 23 | .send({ 24 | 'layer-groups': [ 25 | { id: 'zoning-districts', visible: false }, 26 | ], 27 | }) 28 | .end((err, res) => { 29 | res.status.should.equal(500); 30 | done(); 31 | }); 32 | 33 | tempNock.isDone(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/unit/utils.structure-carto-source.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const nock = require('nock'); 3 | const { find } = require('../../utils/local-resources-utilities'); 4 | 5 | const getSource = require('../../utils/structure-carto-source'); 6 | 7 | const should = chai.should(); 8 | 9 | const cartoResponse = require('./carto-response.json'); 10 | 11 | 12 | describe('structure-carto-source util', () => { 13 | it('should return a source with the correct id', async () => { 14 | const scope = nock('https://planninglabs.carto.com') 15 | .post('/api/v1/map') 16 | .reply(200, cartoResponse); 17 | 18 | try { 19 | const source = await find('sources', 'pluto'); 20 | const cartoSource = await getSource([source]); 21 | 22 | should.exist(cartoSource[0].id); 23 | should.exist(cartoSource[0].type); 24 | should.exist(cartoSource[0].tiles); 25 | cartoSource[0].type.should.equal('vector'); 26 | } catch (e) { 27 | throw new Error(e); 28 | } 29 | scope.isDone(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/validations/data.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | 5 | const layerGroupSchema = require('../../schemas/layer-group'); 6 | const sourceSchema = require('../../schemas/source'); 7 | const { find } = require('../../utils/local-resources-utilities'); 8 | 9 | const getFilenames = resourceName => fs.readdirSync(path.resolve(__dirname, `../../data/${resourceName}`)); 10 | 11 | const should = chai.should(); 12 | 13 | function testLayerGroup(filename) { 14 | it(`validates layer-groups/${filename}`, async () => { 15 | const layerGroup = await find('layer-groups', filename.split('.')[0]); 16 | const { error } = layerGroupSchema.validate(layerGroup); 17 | should.not.exist(error); 18 | }); 19 | } 20 | 21 | function testSource(filename) { 22 | it(`validates sources/${filename}`, async () => { 23 | const source = await find('sources', filename.split('.')[0]); 24 | const { error } = sourceSchema.validate(source); 25 | should.not.exist(error); 26 | }); 27 | } 28 | 29 | describe('Data validations', async () => { 30 | const layerGroupFilenames = getFilenames('layer-groups'); 31 | const sourceFilenames = getFilenames('sources'); 32 | 33 | layerGroupFilenames.forEach(filename => testLayerGroup(filename)); 34 | sourceFilenames.forEach(filename => testSource(filename)); 35 | }); 36 | -------------------------------------------------------------------------------- /test/validations/eslint.js: -------------------------------------------------------------------------------- 1 | const glob = require('glob'); 2 | const { CLIEngine } = require('eslint'); 3 | const { assert } = require('chai'); 4 | 5 | const paths = glob.sync('./+(app|test|routes|utils)/**/*.js'); 6 | const engine = new CLIEngine({ 7 | envs: ['node', 'mocha'], 8 | useEslintrc: true, 9 | }); 10 | 11 | const { results } = engine.executeOnFiles(paths); 12 | 13 | function formatMessages(messages) { 14 | const errors = messages.map(message => `${message.line}:${message.column} ${message.message.slice(0, -1)} - ${message.ruleId}\n`); 15 | 16 | return `\n${errors.join('')}`; 17 | } 18 | 19 | function generateTest(result) { 20 | const { filePath, messages } = result; 21 | 22 | it(`validates ${filePath}`, () => { 23 | if (messages.length > 0) { 24 | assert.fail(false, true, formatMessages(messages)); 25 | } 26 | }); 27 | } 28 | 29 | describe('ESLint', () => { 30 | results.forEach(result => generateTest(result)); 31 | }); 32 | -------------------------------------------------------------------------------- /utils/carto.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const ENV = process.env; 4 | 5 | // 'dcpadmin' is the staging carto account 6 | // 'planninglabs' is the production carto account 7 | const cartoUsername = ENV.CARTO_USERNAME || 'planninglabs'; 8 | const cartoDomain = `${cartoUsername}.carto.com`; 9 | 10 | 11 | const carto = { 12 | cartoDomain, 13 | 14 | getVectorTileTemplate(sourceConfig) { 15 | const layers = sourceConfig['source-layers'].map((sourceLayer) => { 16 | const { id, sql, dataPipeline } = sourceLayer; 17 | 18 | return { 19 | id, 20 | type: 'mapnik', 21 | dataPipeline, 22 | options: { 23 | sql, 24 | }, 25 | }; 26 | }); 27 | 28 | // const layersNotInPipeline = layers.filter(layer => !layer.dataPipeline); 29 | const layersInPipeline = layers.filter(layer => layer.dataPipeline); 30 | // these layers are also in staging (dcpadmin) 31 | 32 | const params = { 33 | version: '1.3.0', 34 | layers: cartoUsername === 'planninglabs' ? layers : layersInPipeline, 35 | }; 36 | 37 | // if buffersize is defined in the source json, add it to the carto params 38 | if (sourceConfig.buffersize) params.buffersize = sourceConfig.buffersize; 39 | 40 | return fetch(`https://${cartoDomain}/api/v1/map`, { 41 | method: 'POST', 42 | headers: { 43 | 'Content-Type': 'application/json', 44 | }, 45 | body: JSON.stringify(params), 46 | }) 47 | .then((response) => { 48 | if (!response.ok) { 49 | throw response; 50 | } 51 | 52 | return response.json(); 53 | }) 54 | .catch(response => response.json().then((resolved) => { 55 | throw new Error(resolved.errors); 56 | })); 57 | }, 58 | }; 59 | 60 | module.exports = carto; 61 | -------------------------------------------------------------------------------- /utils/deep-merge-with-array-replace.js: -------------------------------------------------------------------------------- 1 | const merge = require('deepmerge'); 2 | 3 | const overwriteMerge = (destinationArray, sourceArray) => { 4 | const merged = merge({ ...destinationArray }, { ...sourceArray }, { arrayMerge: overwriteMerge }); 5 | 6 | return Object.keys(merged) 7 | .map(k => parseInt(k, 10)) 8 | .reduce((acc, curr) => { 9 | acc[curr] = merged[curr]; 10 | 11 | return acc; 12 | }, []); 13 | }; 14 | 15 | module.exports = (a, b, c = {}) => merge(a, b, merge({ arrayMerge: overwriteMerge }, c)); 16 | -------------------------------------------------------------------------------- /utils/local-resources-utilities/-load-json.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { sync: loadJsonFile } = require('load-json-file'); 3 | const fs = require('fs'); 4 | 5 | const availableResources = fs.readdirSync( 6 | path.resolve(__dirname, '../../data'), 7 | ); 8 | 9 | const fileNames = availableResources.reduce((resourceCollections, resourceName) => { 10 | const resourceCollectionsMut = resourceCollections; 11 | 12 | const filesHash = fs.readdirSync( 13 | path.resolve(__dirname, `../../data/${resourceName}`), 14 | ) 15 | .reduce((resourceValues, fileName) => { 16 | const resourceValuesMut = resourceValues; 17 | const identifier = fileName.split('.')[0]; 18 | 19 | // generate a new object for this 20 | resourceValuesMut[identifier] = Object.assign( 21 | {}, 22 | loadJsonFile( 23 | path.resolve(__dirname, `../../data/${resourceName}/${fileName}`), 24 | ), 25 | ); 26 | 27 | return resourceValues; 28 | }, {}); 29 | 30 | resourceCollectionsMut[resourceName] = filesHash; 31 | 32 | return resourceCollections; 33 | }, {}); 34 | 35 | // exports a hash of resources keyed by resource name and identifier 36 | module.exports = fileNames; 37 | -------------------------------------------------------------------------------- /utils/local-resources-utilities/find-all.js: -------------------------------------------------------------------------------- 1 | const fileNames = require('./-load-json'); 2 | 3 | module.exports = resourceName => Object.values(fileNames[resourceName]); 4 | -------------------------------------------------------------------------------- /utils/local-resources-utilities/find.js: -------------------------------------------------------------------------------- 1 | // findOne(type, id) 2 | const fileNames = require('./-load-json'); 3 | 4 | module.exports = (resourceName, identifier) => fileNames[resourceName][identifier]; 5 | -------------------------------------------------------------------------------- /utils/local-resources-utilities/index.js: -------------------------------------------------------------------------------- 1 | const findAll = require('./find-all'); 2 | const find = require('./find'); 3 | const where = require('./where'); 4 | 5 | module.exports = { 6 | findAll, 7 | find, 8 | where, 9 | }; 10 | -------------------------------------------------------------------------------- /utils/local-resources-utilities/where.js: -------------------------------------------------------------------------------- 1 | // findOne(type, id) 2 | const fileNames = require('./-load-json'); 3 | 4 | module.exports = (resourceName, { id: ids }) => { 5 | if (ids) { 6 | return Promise.all( 7 | ids.map( 8 | identifier => fileNames[resourceName][identifier], 9 | ), 10 | ); 11 | } 12 | 13 | return new Error('Only querying by id is supported.'); 14 | }; 15 | -------------------------------------------------------------------------------- /utils/structure-carto-source.js: -------------------------------------------------------------------------------- 1 | const carto = require('./carto'); 2 | 3 | module.exports = async (sourceConfigs) => { 4 | const cartoVectorSourceLayers = sourceConfigs 5 | .filter(({ type }) => type === 'cartovector') 6 | .map(({ 'source-layers': sourceLayers }) => sourceLayers) 7 | // flatten the array 8 | .reduce((acc, curr) => [...curr, ...acc], []); 9 | 10 | const anonymousMapTiles = await carto.getVectorTileTemplate({ 11 | 'source-layers': cartoVectorSourceLayers, 12 | }); 13 | 14 | return sourceConfigs.map((source) => { 15 | if (source.type !== 'cartovector') return source; 16 | 17 | const { layergroupid } = anonymousMapTiles; 18 | const { layers } = anonymousMapTiles.metadata; 19 | const sourceLayerIds = source['source-layers'].map(sourceLayer => sourceLayer.id); 20 | const baseUrl = `https://${carto.cartoDomain}/api/v1/map`; 21 | const ids = layers 22 | .filter(tile => sourceLayerIds.includes(tile.id)) 23 | .map(layer => layer.id) 24 | // find the indices of set intersections of layer ids 25 | .map(layerId => layers.map(layer => layer.id).indexOf(layerId)) 26 | .join(); 27 | 28 | 29 | return { 30 | ...source, 31 | type: 'vector', 32 | tiles: [`${baseUrl}/${layergroupid}/${ids}/{z}/{x}/{y}.mvt`], 33 | }; 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /utils/structure-regular-source.js: -------------------------------------------------------------------------------- 1 | module.exports = async (sourceConfig) => { 2 | const { id } = sourceConfig; 3 | 4 | const source = {}; 5 | source[id] = { 6 | ...sourceConfig, 7 | }; 8 | 9 | return source; 10 | }; 11 | --------------------------------------------------------------------------------