├── .gitignore
├── LICENSE
├── README.md
├── data
├── create-data.js
├── flows.json
├── input
│ ├── input-topo.json
│ └── metro-to-metro-2014-2018.csv
├── msas.json
└── topo.json
├── full
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── rollup.config.js
├── snowpack.config.json
├── snowpack
│ └── index.html
├── src
│ ├── App.svelte
│ ├── MapControls.svelte
│ ├── index.html
│ ├── index.js
│ ├── map
│ │ ├── Control.svelte
│ │ ├── Curve.svelte
│ │ ├── GeoJson.svelte
│ │ ├── Leaflet.svelte
│ │ ├── Pane.svelte
│ │ ├── Polyline.svelte
│ │ ├── Popup.svelte
│ │ ├── Tooltip.svelte
│ │ ├── curves.ts
│ │ ├── leaflet.curve.js
│ │ └── popup.ts
│ ├── types.ts
│ └── utils.css
├── static
│ └── favicon.png
├── svelte.config.js
├── tailwind.config.js
└── tsconfig.json
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
└── skeleton
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── rollup.config.js
├── snowpack.config.json
├── snowpack
└── index.html
├── src
├── App.svelte
├── MapControls.svelte
├── index.html
├── index.js
├── map
│ ├── Control.svelte
│ ├── Curve.svelte
│ ├── GeoJson.svelte
│ ├── Leaflet.svelte
│ ├── Pane.svelte
│ ├── Polyline.svelte
│ ├── Popup.svelte
│ ├── Tooltip.svelte
│ ├── curves.ts
│ ├── leaflet.curve.js
│ └── popup.ts
├── types.ts
└── utils.css
├── static
└── favicon.png
├── svelte.config.js
├── tailwind.config.js
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2020 Daniel Imfeld
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Svelte and Leaflet Demo
2 |
3 | This is a demo application using Svelte and Leaflet to visualize the US Census "Metro Area-to-Metro Area Migration Flows” dataset.
4 |
5 | If you like this, check out my [Svelte MapLibre library](https://github.com/dimfeld/svelte-maplibre) too.
6 |
7 | This repository contains two versions of the application. The `full` directory is the
8 | finished product, while the `skeleton` directory just contains a basic shell that renders nothing, which I
9 | filled in during the presentation to build into the complete app.
10 |
11 | Developed for a [presentation to JavascriptLA](https://www.youtube.com/watch?v=-klB-EocorE&t=770s) (video) on November 11, 2020.
12 |
13 |
14 |
15 | ## References
16 |
17 | ### Concepts
18 |
19 | * [Metropolitan Statistical Areas (US Census)](https://www.census.gov/topics/housing/housing-patterns/about/core-based-statistical-areas.html)
20 | * [Wikipedia on MSAs](https://en.wikipedia.org/wiki/Metropolitan_statistical_area)
21 | * [Creating Consistently Curved Lines in Leaflet](https://medium.com/@ryancatalani/creating-consistently-curved-lines-on-leaflet-b59bc03fa9dc)
22 | * [geojson.io](https://geojson.io) for playing with GeoJSON.
23 |
24 | ### Software
25 |
26 | * [Svelte](https://svelte.dev)
27 | * [Leaflet](https://leafletjs.com/)
28 | * [Tailwind CSS](https://tailwindcss.com)
29 | * [Leaflet Curve Plugin](https://github.com/elfalem/Leaflet.curve)
30 | * [TopoJSON](https://github.com/topojson/topojson)
31 | * [Turf.js](https://turfjs.org/) for manipulating GeoJSON
32 |
33 | ### Data
34 |
35 | * [MSA Migration Data](https://www.census.gov/data/tables/2018/demo/geographic-mobility/metro-to-metro-migration.html)
36 | * Specifically [this file](https://www2.census.gov/programs-surveys/demo/tables/geographic-mobility/2018/metro-to-metro-migration/metro-to-metro-2014-2018.xlsx)
37 | * [Shape data for MSAs](https://www.census.gov/geographies/mapping-files/time-series/geo/carto-boundary-file.html)
38 | * We used [cb_2018_us_cbsa_500k.zip](https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_cbsa_500k.zip)
39 | * And converted from ESRI Shapefile to TopoJson using [MapShaper](https://mapshaper.org/)
40 |
--------------------------------------------------------------------------------
/data/create-data.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const dsv = require('d3-dsv');
3 | const fs = require('fs');
4 | const topojson = require('topojson-client');
5 | const topojsonServer= require('topojson-server');
6 | const turf = require('@turf/turf');
7 |
8 | function formatNumber(s) {
9 | return +s.replace(/,/g, '');
10 | }
11 |
12 | let metroData = dsv.csvParseRows(fs.readFileSync('input/metro-to-metro-2014-2018.csv').toString(), (row, i) => {
13 | if(i < 4) {
14 | // SKip useless header rows.
15 | return;
16 | }
17 |
18 | if(row[0].length !== 5) {
19 | // Skip footer data and blank rows at the end
20 | return;
21 | }
22 |
23 | return {
24 | destination: {
25 | id: row[0].toString().padStart(5, '0'),
26 | population: formatNumber(row[3]),
27 | totalIncoming: formatNumber(row[9]),
28 | },
29 | source: {
30 | id: row[1].toString().padStart(5, '0'),
31 | population: formatNumber(row[16]),
32 | totalOutgoing: formatNumber(row[22]),
33 | },
34 | flow: formatNumber(row[26]),
35 | };
36 | });
37 |
38 | console.log(`Got ${metroData.length} rows`);
39 |
40 | let topoData = JSON.parse(fs.readFileSync('input/input-topo.json'));
41 |
42 | let geojson = topojson.feature(topoData, 'cb_2018_us_cbsa_500k');
43 | let msaData = new Map();
44 |
45 | for(let feature of geojson.features) {
46 | let centroid;
47 |
48 | if(feature.geometry.type === 'MultiPolygon') {
49 | // For MultiPolygons, find the area of the largest polygon and use the centroid
50 | // of that one. This is mostly to make Oahu look correct, for which the GeoJSON
51 | // has a lot of huge outliers.
52 | let largest = feature.geometry.coordinates.map((c) => {
53 | let poly = turf.polygon(c);
54 | return {
55 | area: turf.area(poly),
56 | poly,
57 | }
58 | }).sort((a, b) => b.area - a.area);
59 |
60 | centroid = turf.centerOfMass(largest[0].poly);
61 | } else {
62 | centroid = turf.centerOfMass(feature);
63 | }
64 |
65 |
66 | msaData.set(feature.properties.CBSAFP, {
67 | id: feature.properties.CBSAFP,
68 | centroid: centroid.geometry.coordinates
69 | });
70 | }
71 |
72 | let flowMap = new Map();
73 | let missingGeo = new Set();
74 |
75 | for(let {source, destination, flow} of metroData) {
76 | let reverse = destination.id < source.id;
77 | let flowKey = reverse ? `${destination.id}:${source.id}` : `${source.id}:${destination.id}`;
78 | let flowAmount = reverse ? -flow : flow;
79 |
80 | flowMap.set(flowKey, (flowMap.get(flowKey) || 0) + flowAmount);
81 |
82 | let sourceData = msaData.get(source.id);
83 | if(!sourceData) {
84 | missingGeo.add(source.id);
85 | } else {
86 | sourceData.population = source.population;
87 | sourceData.totalOutgoing = source.totalOutgoing;
88 | }
89 |
90 | let destData = msaData.get(destination.id);
91 | if(!destData) {
92 | missingGeo.add(destination.id);
93 | } else {
94 | destData.totalIncoming = destination.totalIncoming;
95 | destData.population = destination.population;
96 | }
97 | }
98 |
99 | let flows = Array.from(flowMap.entries(), ([key, count]) => {
100 | return [...key.split(':'), count];
101 | });
102 |
103 | // Just a sanity check to make sure we're including everything relevant.
104 | // console.log(Array.from(missingGeo));
105 |
106 | let msaOutput = Array.from(msaData.values()).filter((msa) => msa.population > 0);
107 | let presentMsas = new Set(msaOutput.map((m) => m.id));
108 | let presentFeatures = geojson.features.filter((f) => presentMsas.has(f.properties.CBSAFP));
109 | let outputGeojson = {
110 | ...geojson,
111 | features: presentFeatures,
112 | };
113 |
114 |
115 | console.log(`Saving ${msaOutput.length} MSAs`);
116 | fs.writeFileSync('flows.json', JSON.stringify(flows));
117 | fs.writeFileSync('msas.json', JSON.stringify(msaOutput));
118 |
119 | // A lot of the MSAs in the topojson don't show up in the data, so regenerate the topojson with only
120 | // the ones we use, to save space.
121 | let outputTopo = topojsonServer.topology({ msas: outputGeojson }, 1e4);
122 | fs.writeFileSync('topo.json', JSON.stringify(outputTopo));
123 |
--------------------------------------------------------------------------------
/data/msas.json:
--------------------------------------------------------------------------------
1 | [{"id":"31340","centroid":[-79.21977891047733,37.365007890476114],"population":253138,"totalOutgoing":9085,"totalIncoming":11977},{"id":"42220","centroid":[-122.88740026603415,38.52828177524599],"population":492180,"totalOutgoing":18369,"totalIncoming":20895},{"id":"46140","centroid":[-96.16628997642798,36.250429001181224],"population":970210,"totalOutgoing":25994,"totalIncoming":23709},{"id":"41740","centroid":[-116.73529906444958,33.034139142546564],"population":3252610,"totalOutgoing":147720,"totalIncoming":121572},{"id":"38220","centroid":[-91.94990428356924,34.07729500756963],"population":90885,"totalOutgoing":2976,"totalIncoming":3047},{"id":"14500","centroid":[-105.36193923007293,40.092500283088576],"population":308489,"totalOutgoing":25639,"totalIncoming":31231},{"id":"39140","centroid":[-112.55389570526312,34.599902656938625],"population":215405,"totalOutgoing":10395,"totalIncoming":16635},{"id":"17020","centroid":[-121.60067881718864,39.66694281780381],"population":222941,"totalOutgoing":10160,"totalIncoming":11787},{"id":"43620","centroid":[-96.99004692377005,43.499691698979184],"population":252091,"totalOutgoing":7604,"totalIncoming":6702},{"id":"12260","centroid":[-81.98295170744763,33.46102934542993],"population":580641,"totalOutgoing":20002,"totalIncoming":22769},{"id":"17460","centroid":[-81.68380546014906,41.375381390799284],"population":2046425,"totalOutgoing":57844,"totalIncoming":44825},{"id":"13980","centroid":[-80.5329043588124,37.12087104192895],"population":175119,"totalOutgoing":9468,"totalIncoming":12920},{"id":"29340","centroid":[-93.25968701224674,30.017396213718882],"population":203921,"totalOutgoing":5438,"totalIncoming":5707},{"id":"25220","centroid":[-90.40568037648428,30.626636203208832],"population":125818,"totalOutgoing":4618,"totalIncoming":7758},{"id":"13140","centroid":[-94.07154790501706,30.303792311161406],"population":404323,"totalOutgoing":14889,"totalIncoming":14933},{"id":"36420","centroid":[-97.50388721250954,35.42985046501356],"population":1336724,"totalOutgoing":34392,"totalIncoming":42038},{"id":"43580","centroid":[-96.37218109041784,42.5787816017505],"population":167837,"totalOutgoing":6307,"totalIncoming":4662},{"id":"17140","centroid":[-84.42749135307402,39.07151768440855],"population":2132196,"totalOutgoing":55385,"totalIncoming":57022},{"id":"28940","centroid":[-84.13737797974203,36.04483426105577],"population":852363,"totalOutgoing":24630,"totalIncoming":29106},{"id":"16740","centroid":[-80.86701971460855,35.18875887227213],"population":2412915,"totalOutgoing":76289,"totalIncoming":97592},{"id":"29100","centroid":[-91.3196905529119,43.77926687816804],"population":132162,"totalOutgoing":4787,"totalIncoming":6158},{"id":"14260","centroid":[-116.14320362848551,43.01607263136109],"population":673971,"totalOutgoing":18765,"totalIncoming":27305},{"id":"31740","centroid":[-96.50693496360074,39.344468086857454],"population":96228,"totalOutgoing":8478,"totalIncoming":7989},{"id":"36540","centroid":[-95.99912545099612,41.29007801301011],"population":908343,"totalOutgoing":28890,"totalIncoming":25456},{"id":"16620","centroid":[-81.49149214857404,38.27182066855662],"population":216009,"totalOutgoing":7075,"totalIncoming":5773},{"id":"24220","centroid":[-96.84448447189662,47.83596694760277],"population":98825,"totalOutgoing":5462,"totalIncoming":5883},{"id":"42700","centroid":[-81.34103964869955,27.34330637810145],"population":98928,"totalOutgoing":4431,"totalIncoming":5311},{"id":"41900","centroid":[-67.06192286413253,18.05679353321019],"population":128924,"totalOutgoing":4206,"totalIncoming":1639},{"id":"25980","centroid":[-81.60192171681346,31.795824964211093],"population":77608,"totalOutgoing":9909,"totalIncoming":8350},{"id":"31420","centroid":[-83.71489824090753,32.85769224592142],"population":224766,"totalOutgoing":8187,"totalIncoming":9476},{"id":"22180","centroid":[-78.98032229484184,35.03703155081214],"population":374117,"totalOutgoing":28518,"totalIncoming":27228},{"id":"36260","centroid":[-112.81593316153676,41.432685135409265],"population":638146,"totalOutgoing":25526,"totalIncoming":26919},{"id":"34100","centroid":[-83.38178898598201,36.11065357632416],"population":115128,"totalOutgoing":4765,"totalIncoming":4557},{"id":"11260","centroid":[-149.54231176769417,62.243491196453064],"population":403607,"totalOutgoing":25899,"totalIncoming":13966},{"id":"24340","centroid":[-85.48829758566254,42.99925614279305],"population":1028518,"totalOutgoing":27681,"totalIncoming":33408},{"id":"34060","centroid":[-79.80450680607628,39.527333370489934],"population":133829,"totalOutgoing":6309,"totalIncoming":8547},{"id":"18140","centroid":[-82.83679650791015,39.96812976867252],"population":2008095,"totalOutgoing":54422,"totalIncoming":63748},{"id":"29180","centroid":[-92.06613828117446,30.038906972249364],"population":479942,"totalOutgoing":11920,"totalIncoming":12248},{"id":"30300","centroid":[-116.94375697729701,46.2691194824595],"population":61593,"totalOutgoing":1970,"totalIncoming":1848},{"id":"35380","centroid":[-89.96758873001606,29.92697750733387],"population":1254161,"totalOutgoing":41877,"totalIncoming":33961},{"id":"22500","centroid":[-79.80842175561793,34.15200972987542],"population":205095,"totalOutgoing":7713,"totalIncoming":4683},{"id":"36140","centroid":[-74.80020362953559,39.148997013084184],"population":92453,"totalOutgoing":4746,"totalIncoming":5184},{"id":"44100","centroid":[-89.69690932330046,39.829612183549834],"population":208642,"totalOutgoing":8039,"totalIncoming":6132},{"id":"38660","centroid":[-66.68409907834922,18.05876428095343],"population":308909,"totalOutgoing":10152,"totalIncoming":4945},{"id":"39300","centroid":[-71.39955459137273,41.723544970476354],"population":1586887,"totalOutgoing":43512,"totalIncoming":47827},{"id":"48620","centroid":[-97.39821176777117,37.62500408894324],"population":635534,"totalOutgoing":18682,"totalIncoming":15745},{"id":"47460","centroid":[-118.24886492086351,46.2570273915684],"population":62362,"totalOutgoing":4701,"totalIncoming":4588},{"id":"24500","centroid":[-111.34703577926652,47.30795615031704],"population":80290,"totalOutgoing":3767,"totalIncoming":2896},{"id":"42540","centroid":[-75.89573319515033,41.32322473625947],"population":547868,"totalOutgoing":14602,"totalIncoming":17443},{"id":"42660","centroid":[-121.82784982136688,47.56424534880192],"population":3710762,"totalOutgoing":128518,"totalIncoming":145500},{"id":"22380","centroid":[-111.77048412887488,35.838745842923096],"population":133556,"totalOutgoing":10983,"totalIncoming":15480},{"id":"20700","centroid":[-75.33952719840845,41.058054297214326],"population":165358,"totalOutgoing":8249,"totalIncoming":8617},{"id":"43340","centroid":[-93.66877801421967,32.489844158445926],"population":439551,"totalOutgoing":13566,"totalIncoming":8934},{"id":"15380","centroid":[-78.7366732807765,42.910912073333485],"population":1118557,"totalOutgoing":26569,"totalIncoming":23092},{"id":"31540","centroid":[-89.5922313304881,43.08016174346716],"population":632143,"totalOutgoing":25668,"totalIncoming":27520},{"id":"21340","centroid":[-105.54101514166565,31.51313026928414],"population":828790,"totalOutgoing":37659,"totalIncoming":28661},{"id":"25020","centroid":[-66.08366279440585,18.01318419212889],"population":78002,"totalOutgoing":3428,"totalIncoming":2082},{"id":"43900","centroid":[-81.84751676209912,34.83788182921987],"population":321982,"totalOutgoing":10762,"totalIncoming":14641},{"id":"37460","centroid":[-85.46600497553251,30.14387915275368],"population":196163,"totalOutgoing":13050,"totalIncoming":13120},{"id":"33100","centroid":[-80.50634703066498,26.158451057188888],"population":5950963,"totalOutgoing":168383,"totalIncoming":135187},{"id":"19100","centroid":[-97.02520651941224,32.81815007407698],"population":7073136,"totalOutgoing":174694,"totalIncoming":210743},{"id":"17900","centroid":[-81.04244820242344,34.09175636407194],"population":783433,"totalOutgoing":29902,"totalIncoming":45785},{"id":"46300","centroid":[-114.5707827199849,42.435776754139184],"population":103379,"totalOutgoing":3256,"totalIncoming":3879},{"id":"40900","centroid":[-120.99755984590989,38.78047331307332],"population":2234520,"totalOutgoing":76258,"totalIncoming":91162},{"id":"32820","centroid":[-89.81524205822987,35.00767851302501],"population":1329162,"totalOutgoing":35239,"totalIncoming":27800},{"id":"17980","centroid":[-84.90874943363866,32.44143568439897],"population":299121,"totalOutgoing":18668,"totalIncoming":21323},{"id":"33860","centroid":[-86.40324881587512,32.36060607309142],"population":367426,"totalOutgoing":15717,"totalIncoming":14094},{"id":"24860","centroid":[-82.41384714797529,34.68510962676439],"population":860443,"totalOutgoing":29319,"totalIncoming":35635},{"id":"27740","centroid":[-82.33446532743953,36.2537735254266],"population":198227,"totalOutgoing":8455,"totalIncoming":7770},{"id":"21660","centroid":[-122.84748431819197,43.938812054112475],"population":355864,"totalOutgoing":14875,"totalIncoming":20800},{"id":"25500","centroid":[-78.87570896796332,38.51051893673159],"population":126310,"totalOutgoing":6111,"totalIncoming":9712},{"id":"35100","centroid":[-77.09052081591807,35.0980767321262],"population":123616,"totalOutgoing":9884,"totalIncoming":9143},{"id":"19300","centroid":[-87.72256116936462,30.727487407618867],"population":203155,"totalOutgoing":7202,"totalIncoming":9002},{"id":"13220","centroid":[-81.16090087447847,37.906225756952445],"population":121633,"totalOutgoing":4659,"totalIncoming":2370},{"id":"47580","centroid":[-83.63636626996761,32.40760349892759],"population":184808,"totalOutgoing":8999,"totalIncoming":10263},{"id":"44060","centroid":[-117.57179821352764,48.193781776028565],"population":533762,"totalOutgoing":16941,"totalIncoming":26655},{"id":"41620","centroid":[-113.01050683378543,40.47058044650397],"population":1158370,"totalOutgoing":49088,"totalIncoming":49770},{"id":"21820","centroid":[-146.56541764353884,64.80776589773697],"population":98721,"totalOutgoing":8109,"totalIncoming":6530},{"id":"49700","centroid":[-121.51790280966848,39.15531623053985],"population":167342,"totalOutgoing":6573,"totalIncoming":7642},{"id":"41940","centroid":[-121.37589299789371,36.90949358071908],"population":1945356,"totalOutgoing":99399,"totalIncoming":79904},{"id":"44940","centroid":[-80.38225222171829,33.916203139291575],"population":105829,"totalOutgoing":5541,"totalIncoming":4523},{"id":"41060","centroid":[-94.47205066087514,45.58587308091638],"population":189506,"totalOutgoing":7560,"totalIncoming":10317},{"id":"36500","centroid":[-122.83319043733889,46.925775520231866],"population":266590,"totalOutgoing":15452,"totalIncoming":18367},{"id":"12100","centroid":[-74.6609700321421,39.47773155227118],"population":266175,"totalOutgoing":12405,"totalIncoming":10897},{"id":"45940","centroid":[-74.70176101939649,40.283435828545635],"population":362173,"totalOutgoing":21625,"totalIncoming":21789},{"id":"41980","centroid":[-66.1123693422472,18.275973893289088],"population":2175385,"totalOutgoing":69797,"totalIncoming":19624},{"id":"40220","centroid":[-79.94656107968719,37.28608232816075],"population":309262,"totalOutgoing":12308,"totalIncoming":11408},{"id":"47260","centroid":[-76.41859093209567,36.65593723621089],"population":1679761,"totalOutgoing":78316,"totalIncoming":84131},{"id":"44140","centroid":[-72.64650755068901,42.2300493436416],"population":616521,"totalOutgoing":19770,"totalIncoming":25141},{"id":"25420","centroid":[-77.10119105984485,40.3266673702821],"population":550827,"totalOutgoing":23464,"totalIncoming":29285},{"id":"38900","centroid":[-122.4783185975509,45.5983759472492],"population":2366884,"totalOutgoing":81891,"totalIncoming":91348},{"id":"41180","centroid":[-90.35010113339519,38.73525508262465],"population":2781797,"totalOutgoing":69459,"totalIncoming":55196},{"id":"17780","centroid":[-96.48889476123075,30.756520219991113],"population":239369,"totalOutgoing":17678,"totalIncoming":23731},{"id":"19060","centroid":[-78.80448665442918,39.53168750445143],"population":98135,"totalOutgoing":3359,"totalIncoming":3754},{"id":"45060","centroid":[-76.0335575068406,43.154462537297924],"population":646394,"totalOutgoing":23837,"totalIncoming":21935},{"id":"41700","centroid":[-98.60229521832419,29.42873039378048],"population":2366874,"totalOutgoing":79967,"totalIncoming":89939},{"id":"31020","centroid":[-122.68100400226278,46.19323987280277],"population":104016,"totalOutgoing":5326,"totalIncoming":5305},{"id":"21060","centroid":[-85.97382100177786,37.73766099775791],"population":146148,"totalOutgoing":9600,"totalIncoming":10684},{"id":"22140","centroid":[-108.32061074817807,36.50852088437349],"population":126364,"totalOutgoing":3776,"totalIncoming":3338},{"id":"22660","centroid":[-105.46112895154045,40.66638258794885],"population":327681,"totalOutgoing":21256,"totalIncoming":26189},{"id":"28420","centroid":[-119.25441823552399,46.36350775271266],"population":279687,"totalOutgoing":9153,"totalIncoming":10183},{"id":"20260","centroid":[-92.4088043961568,47.33330112188319],"population":273447,"totalOutgoing":8622,"totalIncoming":9802},{"id":"24780","centroid":[-77.37449156406194,35.593294232215754],"population":167381,"totalOutgoing":8406,"totalIncoming":13786},{"id":"13460","centroid":[-121.22809710522333,43.91503508154249],"population":178401,"totalOutgoing":8989,"totalIncoming":10459},{"id":"13780","centroid":[-76.02513032369178,42.16450392520661],"population":238686,"totalOutgoing":7225,"totalIncoming":8737},{"id":"44700","centroid":[-121.27139472032621,37.93475533294045],"population":710953,"totalOutgoing":25194,"totalIncoming":34232},{"id":"42340","centroid":[-81.30183662429062,32.130531741995064],"population":369738,"totalOutgoing":21472,"totalIncoming":24281},{"id":"47300","centroid":[-118.80049103028645,36.22016751847846],"population":454050,"totalOutgoing":12409,"totalIncoming":10476},{"id":"33780","centroid":[-83.53749019063018,41.9286876022383],"population":148086,"totalOutgoing":5991,"totalIncoming":6019},{"id":"36100","centroid":[-82.05666044768752,29.210211612045185],"population":337696,"totalOutgoing":14886,"totalIncoming":20921},{"id":"29020","centroid":[-86.11696747101327,40.48360849957797],"population":81382,"totalOutgoing":2814,"totalIncoming":2622},{"id":"14740","centroid":[-122.67208706111458,47.61330080104672],"population":253936,"totalOutgoing":14046,"totalIncoming":18856},{"id":"29700","centroid":[-99.33151352433725,27.761106815162783],"population":267920,"totalOutgoing":6613,"totalIncoming":2740},{"id":"47900","centroid":[-77.47440167659462,38.83347350869931],"population":6028387,"totalOutgoing":241889,"totalIncoming":202058},{"id":"16980","centroid":[-87.96272988109011,41.7026425816275],"population":9479646,"totalOutgoing":249120,"totalIncoming":157098},{"id":"14540","centroid":[-86.40699796500394,37.03861985431623],"population":162646,"totalOutgoing":5015,"totalIncoming":9195},{"id":"19660","centroid":[-81.2196847468417,29.17403443571755],"population":616189,"totalOutgoing":26471,"totalIncoming":36211},{"id":"11640","centroid":[-66.75693181763114,18.413105077616844],"population":186348,"totalOutgoing":6513,"totalIncoming":2677},{"id":"15540","centroid":[-73.03078304900261,44.687205361243976],"population":211401,"totalOutgoing":7021,"totalIncoming":8287},{"id":"37620","centroid":[-81.46279153670406,39.138850185148584],"population":90617,"totalOutgoing":2047,"totalIncoming":2042},{"id":"40140","centroid":[-116.12967898106672,34.55164941228395],"population":4405214,"totalOutgoing":141272,"totalIncoming":180455},{"id":"37860","centroid":[-87.15617709585277,30.688030127472842],"population":468141,"totalOutgoing":27760,"totalIncoming":33434},{"id":"39660","centroid":[-102.8998870018002,44.19147075411888],"population":141783,"totalOutgoing":6127,"totalIncoming":5783},{"id":"17300","centroid":[-87.56251500383206,36.746850892735395],"population":277162,"totalOutgoing":22186,"totalIncoming":20085},{"id":"15980","centroid":[-81.81996015587278,26.57911278376274],"population":695126,"totalOutgoing":25676,"totalIncoming":37381},{"id":"21500","centroid":[-80.0328125970671,41.992588491583675],"population":273533,"totalOutgoing":10666,"totalIncoming":8478},{"id":"46660","centroid":[-83.24154726536817,30.829427579777885],"population":142124,"totalOutgoing":6808,"totalIncoming":6616},{"id":"23420","centroid":[-119.64931830532569,36.75819028709072],"population":960098,"totalOutgoing":27652,"totalIncoming":27872},{"id":"25060","centroid":[-89.01966023778509,30.500499271580654],"population":384229,"totalOutgoing":17041,"totalIncoming":16974},{"id":"13740","centroid":[-108.71762646524164,45.780694639088594],"population":167921,"totalOutgoing":4964,"totalIncoming":3698},{"id":"47220","centroid":[-75.11074900436931,39.37383979027761],"population":151678,"totalOutgoing":7016,"totalIncoming":7152},{"id":"34820","centroid":[-78.66399551501094,33.987011906768835],"population":435176,"totalOutgoing":18014,"totalIncoming":25547},{"id":"26380","centroid":[-90.66592032576123,29.48518510844245],"population":207307,"totalOutgoing":3805,"totalIncoming":4526},{"id":"25180","centroid":[-77.90090478449689,39.546796684036416],"population":258129,"totalOutgoing":10915,"totalIncoming":13025},{"id":"19460","centroid":[-87.10257006757875,34.49064044157397],"population":150094,"totalOutgoing":4397,"totalIncoming":4557},{"id":"33700","centroid":[-120.99768288501825,37.55914038668041],"population":529199,"totalOutgoing":18199,"totalIncoming":19309},{"id":"25540","centroid":[-72.57734416463256,41.734626624770506],"population":1196226,"totalOutgoing":43609,"totalIncoming":38729},{"id":"49180","centroid":[-80.34581022887306,36.07663632289534],"population":649949,"totalOutgoing":23888,"totalIncoming":26886},{"id":"33460","centroid":[-93.34558708746027,45.06500504822576],"population":3507277,"totalOutgoing":85245,"totalIncoming":72698},{"id":"40340","centroid":[-92.33807183463539,43.955988600268086],"population":213452,"totalOutgoing":7609,"totalIncoming":6139},{"id":"30860","centroid":[-111.76898127262625,41.88956578583493],"population":131717,"totalOutgoing":8126,"totalIncoming":7648},{"id":"29820","centroid":[-115.01353269152919,36.21523038060011],"population":2081248,"totalOutgoing":66197,"totalIncoming":89802},{"id":"10580","centroid":[-73.94198887191097,42.788511888199935],"population":867402,"totalOutgoing":29156,"totalIncoming":29421},{"id":"39580","centroid":[-78.46086692967947,35.75724983934009],"population":1264270,"totalOutgoing":49638,"totalIncoming":63012},{"id":"28740","centroid":[-74.25854419873329,41.88813506957871],"population":176659,"totalOutgoing":6450,"totalIncoming":7544},{"id":"40060","centroid":[-77.47356546772028,37.46200713206555],"population":1254237,"totalOutgoing":44014,"totalIncoming":48251},{"id":"22520","centroid":[-87.72396499192521,34.80826223327141],"population":143797,"totalOutgoing":3896,"totalIncoming":4990},{"id":"10420","centroid":[-81.34953563728817,41.14871834295054],"totalIncoming":25996,"population":694922,"totalOutgoing":25964},{"id":"23060","centroid":[-85.21678156814913,41.005417509260475],"population":425413,"totalOutgoing":11487,"totalIncoming":10784},{"id":"14010","centroid":[-88.86172500906028,40.41065466216124],"population":187284,"totalOutgoing":10640,"totalIncoming":9832},{"id":"17860","centroid":[-92.30967054318971,38.990627405086855],"population":172016,"totalOutgoing":12607,"totalIncoming":12553},{"id":"28140","centroid":[-94.4443728819982,38.93714640889055],"population":2077504,"totalOutgoing":61043,"totalIncoming":58075},{"id":"16700","centroid":[-80.04430040052706,33.042564787300336],"population":742044,"totalOutgoing":32733,"totalIncoming":36082},{"id":"27620","centroid":[-92.09170757893568,38.63980693046525],"population":149098,"totalOutgoing":5369,"totalIncoming":5956},{"id":"32780","centroid":[-122.72849953452875,42.432189539550954],"population":210823,"totalOutgoing":9217,"totalIncoming":9206},{"id":"47380","centroid":[-97.0897947810793,31.426423527468597],"population":257731,"totalOutgoing":11668,"totalIncoming":14788},{"id":"37340","centroid":[-80.73226959232124,28.29371773976019],"population":560204,"totalOutgoing":23068,"totalIncoming":30913},{"id":"24300","centroid":[-108.46643085982707,39.018288696041466],"population":145239,"totalOutgoing":5480,"totalIncoming":7123},{"id":"34580","centroid":[-121.7188267196097,48.47842988014873],"population":120510,"totalOutgoing":5263,"totalIncoming":7331},{"id":"42100","centroid":[-122.00184086940025,37.05618005990083],"population":267744,"totalOutgoing":14662,"totalIncoming":16607},{"id":"33660","centroid":[-88.20646580584146,30.791515923583663],"population":412116,"totalOutgoing":13419,"totalIncoming":9697},{"id":"49340","centroid":[-71.92740065428318,42.22281378315466],"population":931291,"totalOutgoing":38882,"totalIncoming":32356},{"id":"45460","centroid":[-87.34400269963203,39.39190431106162],"population":164641,"totalOutgoing":5312,"totalIncoming":7705},{"id":"49620","centroid":[-76.72651209153926,39.91995754038726],"population":438249,"totalOutgoing":15814,"totalIncoming":15592},{"id":"13380","centroid":[-121.71193056834014,48.826226623246114],"population":208926,"totalOutgoing":9384,"totalIncoming":12726},{"id":"15680","centroid":[-76.60578224076886,38.30243517206398],"population":109171,"totalOutgoing":6911,"totalIncoming":7548},{"id":"27340","centroid":[-77.4327682842837,34.732385746450596],"population":181494,"totalOutgoing":21744,"totalIncoming":26682},{"id":"32900","centroid":[-120.71765470093608,37.1918924082313],"population":263220,"totalOutgoing":11150,"totalIncoming":12137},{"id":"39340","centroid":[-112.35258355061582,39.86451873693232],"population":575335,"totalOutgoing":30466,"totalIncoming":35465},{"id":"18700","centroid":[-123.42926986192019,44.491792332533976],"population":85988,"totalOutgoing":8742,"totalIncoming":10182},{"id":"10380","centroid":[-66.9534689756726,18.33539940264403],"totalIncoming":3598,"population":313882,"totalOutgoing":11704},{"id":"30700","centroid":[-96.87081354342973,40.819917365586676],"population":313184,"totalOutgoing":10669,"totalIncoming":14738},{"id":"11100","centroid":[-101.90950753932285,35.248874790386566],"population":262324,"totalOutgoing":11114,"totalIncoming":6424},{"id":"19820","centroid":[-83.23270891674714,42.719197307387844],"population":4273143,"totalOutgoing":98787,"totalIncoming":74200},{"id":"12700","centroid":[-70.291468420632,41.72418368535354],"population":212809,"totalOutgoing":9007,"totalIncoming":7154},{"id":"46520","centroid":[-157.9728605595027,21.457323759506384],"population":973539,"totalOutgoing":47717,"totalIncoming":38438},{"id":"31080","centroid":[-118.1410681044627,34.2496393902452],"population":13137459,"totalOutgoing":365670,"totalIncoming":245061},{"id":"31140","centroid":[-85.6708501495599,38.33675203722141],"population":1270956,"totalOutgoing":32289,"totalIncoming":28094},{"id":"41860","centroid":[-121.90851662387782,37.784168943536024],"population":4595540,"totalOutgoing":184898,"totalIncoming":161240},{"id":"35980","centroid":[-72.10147788985178,41.48660940080825],"population":264050,"totalOutgoing":14311,"totalIncoming":15670},{"id":"30980","centroid":[-94.82943331799872,32.371668943870944],"population":210866,"totalOutgoing":7331,"totalIncoming":9651},{"id":"41420","centroid":[-122.90336622467568,44.903397729642734],"population":407228,"totalOutgoing":17094,"totalIncoming":19562},{"id":"18580","centroid":[-97.56268025061628,27.864816672583437],"population":440791,"totalOutgoing":16452,"totalIncoming":19299},{"id":"28700","centroid":[-82.44261316218726,36.607772296987434],"population":301786,"totalOutgoing":8525,"totalIncoming":8834},{"id":"34900","centroid":[-122.33051904043957,38.506480285894746],"population":141071,"totalOutgoing":8073,"totalIncoming":6165},{"id":"46540","centroid":[-75.18139031450718,43.33741583693321],"population":289015,"totalOutgoing":8123,"totalIncoming":8528},{"id":"39820","centroid":[-122.04050796713213,40.763707918289],"population":176576,"totalOutgoing":7066,"totalIncoming":6858},{"id":"12940","centroid":[-91.13278442388855,30.57107481378725],"population":815741,"totalOutgoing":23096,"totalIncoming":26238},{"id":"41500","centroid":[-121.23919425672122,36.21715708349306],"population":423784,"totalOutgoing":20754,"totalIncoming":20682},{"id":"27180","centroid":[-88.85288475274106,35.60953450327306],"population":128199,"totalOutgoing":3600,"totalIncoming":2728},{"id":"24020","centroid":[-73.64881609880116,43.443544914574424],"population":125045,"totalOutgoing":4616,"totalIncoming":4553},{"id":"10540","centroid":[-122.53499247914424,44.488877520668105],"population":120610,"totalOutgoing":6686,"totalIncoming":7829},{"id":"49020","centroid":[-78.4738799350256,39.272173420725615],"population":133790,"totalOutgoing":5429,"totalIncoming":5747},{"id":"27140","centroid":[-90.22046404367492,32.31702056348438],"population":570495,"totalOutgoing":14195,"totalIncoming":14697},{"id":"16020","centroid":[-89.769817820826,37.32447086546932],"population":95624,"totalOutgoing":3595,"totalIncoming":3228},{"id":"37100","centroid":[-119.07822973852554,34.47159530368873],"population":839769,"totalOutgoing":33561,"totalIncoming":28054},{"id":"29540","centroid":[-76.24772926979058,40.042432784975034],"population":529775,"totalOutgoing":17884,"totalIncoming":18580},{"id":"15180","centroid":[-97.52221536102066,26.131957825040303],"population":419983,"totalOutgoing":11813,"totalIncoming":5707},{"id":"33740","centroid":[-92.2845926860352,32.68685412885709],"population":176439,"totalOutgoing":4924,"totalIncoming":4025},{"id":"41140","centroid":[-94.78382951670349,39.83408306897171],"population":124005,"totalOutgoing":5105,"totalIncoming":5010},{"id":"35620","centroid":[-74.08870824935313,40.92247434472604],"population":19847550,"totalOutgoing":460501,"totalIncoming":232214},{"id":"37980","centroid":[-75.30194655041657,39.90563296376845],"population":5988725,"totalOutgoing":158969,"totalIncoming":143308},{"id":"26420","centroid":[-95.40393444250026,29.790532809740483],"population":6593374,"totalOutgoing":148881,"totalIncoming":175013},{"id":"43300","centroid":[-96.67771954901613,33.62676954269254],"population":123250,"totalOutgoing":3757,"totalIncoming":6965},{"id":"16580","centroid":[-88.29452175254535,40.226682984475275],"population":225693,"totalOutgoing":14261,"totalIncoming":21216},{"id":"16820","centroid":[-78.5763212668309,37.85206592495693],"population":224492,"totalOutgoing":14055,"totalIncoming":15675},{"id":"16860","centroid":[-85.3591460699924,35.051976733387896],"population":542050,"totalOutgoing":15221,"totalIncoming":18067},{"id":"48660","centroid":[-98.49141100190886,33.77468570466272],"population":145742,"totalOutgoing":8357,"totalIncoming":9486},{"id":"22900","centroid":[-94.56609692852284,35.190475176615124],"population":276746,"totalOutgoing":7331,"totalIncoming":7457},{"id":"15260","centroid":[-81.63656665242503,31.3117918471666],"population":113211,"totalOutgoing":4024,"totalIncoming":4735},{"id":"15500","centroid":[-79.39943745370725,36.04374084677399],"population":157351,"totalOutgoing":7031,"totalIncoming":8196},{"id":"33340","centroid":[-88.17241810671469,43.17664265606479],"population":1561879,"totalOutgoing":45034,"totalIncoming":36695},{"id":"26620","centroid":[-86.73466871109687,34.783200579777294],"population":440895,"totalOutgoing":16284,"totalIncoming":18854},{"id":"12420","centroid":[-97.65444553568648,30.262591026848387],"population":1990877,"totalOutgoing":81180,"totalIncoming":108135},{"id":"49420","centroid":[-120.73846602924971,46.457064301265916],"population":244791,"totalOutgoing":6521,"totalIncoming":7168},{"id":"24420","centroid":[-123.55547496511662,42.36547434583094],"population":82481,"totalOutgoing":3008,"totalIncoming":4800},{"id":"31460","centroid":[-119.76266847019161,37.21798987825665],"population":154618,"totalOutgoing":9386,"totalIncoming":7264},{"id":"48900","centroid":[-77.90104635852381,34.46678960137711],"population":275693,"totalOutgoing":14570,"totalIncoming":17510},{"id":"17420","centroid":[-84.66739478870895,35.13454861084555],"population":120066,"totalOutgoing":5171,"totalIncoming":4527},{"id":"44300","centroid":[-77.81994987928034,40.91932652827721],"population":149848,"totalOutgoing":9219,"totalIncoming":15524},{"id":"33540","centroid":[-113.92370936350243,47.036511978448026],"population":112126,"totalOutgoing":4361,"totalIncoming":5474},{"id":"23460","centroid":[-86.03477283528302,34.04525586637633],"population":101586,"totalOutgoing":3024,"totalIncoming":2941},{"id":"26820","centroid":[-112.42791815514842,43.62250568343766],"population":138261,"totalOutgoing":4451,"totalIncoming":6340},{"id":"28660","centroid":[-97.7877004524827,31.208098208640425],"population":420634,"totalOutgoing":31732,"totalIncoming":35758},{"id":"18020","centroid":[-85.89758711112447,39.2059563988753],"population":80471,"totalOutgoing":4011,"totalIncoming":3146},{"id":"26300","centroid":[-93.15042061317482,34.576663889086696],"population":97080,"totalOutgoing":3746,"totalIncoming":4093},{"id":"46060","centroid":[-111.78992646107346,32.09742837271627],"population":989984,"totalOutgoing":42440,"totalIncoming":49778},{"id":"19380","centroid":[-84.14194765456716,39.82946598162232],"population":786968,"totalOutgoing":30496,"totalIncoming":30989},{"id":"48540","centroid":[-80.84132068632847,39.97477030390249],"population":141036,"totalOutgoing":3447,"totalIncoming":3638},{"id":"23580","centroid":[-83.81966535896163,34.31691030750534],"population":191354,"totalOutgoing":6864,"totalIncoming":8675},{"id":"38060","centroid":[-112.07046317841404,33.1857083135379],"population":4539283,"totalOutgoing":129467,"totalIncoming":177642},{"id":"26140","centroid":[-82.4786448195623,28.84907710339455],"population":140360,"totalOutgoing":7103,"totalIncoming":8733},{"id":"44180","centroid":[-93.17706845346412,37.36168148523521],"population":445982,"totalOutgoing":12986,"totalIncoming":16209},{"id":"10740","centroid":[-106.47157567375328,35.12222665430155],"population":897771,"totalOutgoing":28944,"totalIncoming":26097},{"id":"24580","centroid":[-88.07653663391626,44.77289829912982],"population":312887,"totalOutgoing":10096,"totalIncoming":9631},{"id":"47020","centroid":[-97.19500226091074,28.727940426666294],"population":99172,"totalOutgoing":3794,"totalIncoming":2675},{"id":"40380","centroid":[-77.50789820520173,42.96592493293086],"population":1056347,"totalOutgoing":30712,"totalIncoming":32024},{"id":"41100","centroid":[-113.50476315077788,37.28037884998011],"population":156174,"totalOutgoing":8654,"totalIncoming":10665},{"id":"14100","centroid":[-76.45900346948467,41.04427663065203],"population":83493,"totalOutgoing":4016,"totalIncoming":4157},{"id":"31900","centroid":[-82.53648847855189,40.77465496144519],"population":120636,"totalOutgoing":4192,"totalIncoming":4632},{"id":"21140","centroid":[-85.85874458965431,41.597391184383454],"population":202631,"totalOutgoing":7971,"totalIncoming":5890},{"id":"48060","centroid":[-75.91801709961582,44.05013302116186],"population":113268,"totalOutgoing":11881,"totalIncoming":8771},{"id":"19140","centroid":[-84.8480995796864,34.79627410981646],"population":142012,"totalOutgoing":4053,"totalIncoming":3427},{"id":"11540","centroid":[-88.37116354457027,44.28901993165939],"population":234922,"totalOutgoing":10192,"totalIncoming":7941},{"id":"16220","centroid":[-106.79849288524338,42.962052574291235],"population":80056,"totalOutgoing":2263,"totalIncoming":1834},{"id":"16060","centroid":[-89.19025838181076,37.761850439857106],"population":122569,"totalOutgoing":5767,"totalIncoming":6827},{"id":"16180","centroid":[-119.74740325350957,39.151144767211186],"population":52685,"totalOutgoing":2669,"totalIncoming":3954},{"id":"14020","centroid":[-86.6759445363331,39.23470426942268],"population":153660,"totalOutgoing":9350,"totalIncoming":15532},{"id":"40980","centroid":[-84.05317847142034,43.33504071670162],"population":191176,"totalOutgoing":7255,"totalIncoming":5912},{"id":"29420","centroid":[-113.75795050174551,35.7040898051281],"population":198939,"totalOutgoing":10850,"totalIncoming":14813},{"id":"28020","centroid":[-85.78378319272896,42.2484849184587],"population":327243,"totalOutgoing":14459,"totalIncoming":16441},{"id":"27900","centroid":[-94.33994411547722,37.056553557884506],"population":175107,"totalOutgoing":5608,"totalIncoming":4971},{"id":"19740","centroid":[-104.93314657647944,39.44279358856491],"population":2793498,"totalOutgoing":111643,"totalIncoming":120185},{"id":"22420","centroid":[-83.70670520204465,43.02171299220497],"population":409690,"totalOutgoing":16155,"totalIncoming":11522},{"id":"11180","centroid":[-93.46504628364463,42.03623014976688],"totalIncoming":8939,"population":90534,"totalOutgoing":7130},{"id":"39380","centroid":[-104.5127376595403,38.17352376438713],"population":161359,"totalOutgoing":6241,"totalIncoming":6957},{"id":"17820","centroid":[-104.6577870938409,38.84251223637318],"population":685984,"totalOutgoing":46857,"totalIncoming":57150},{"id":"42680","centroid":[-80.60622672349265,27.694315330059652],"population":145426,"totalOutgoing":6042,"totalIncoming":9209},{"id":"34740","centroid":[-86.15203523059672,43.291243445926135],"population":171068,"totalOutgoing":6700,"totalIncoming":6328},{"id":"13020","centroid":[-83.99174516321874,43.708044443559494],"population":104447,"totalOutgoing":3695,"totalIncoming":2561},{"id":"36220","centroid":[-102.54288036515717,31.86919144747354],"population":155773,"totalOutgoing":8009,"totalIncoming":7869},{"id":"38540","centroid":[-112.22461111322681,42.668485465951214],"population":83412,"totalOutgoing":4420,"totalIncoming":3984},{"id":"23900","centroid":[-77.21787447860055,39.87148854725977],"population":101394,"totalOutgoing":5561,"totalIncoming":5325},{"id":"36780","centroid":[-88.6446497061956,44.06888075803715],"population":165035,"totalOutgoing":7887,"totalIncoming":10431},{"id":"26900","centroid":[-86.20613178327208,39.747420338213566],"population":1982144,"totalOutgoing":60649,"totalIncoming":54501},{"id":"25620","centroid":[-89.22874264440281,31.187400112436592],"population":145365,"totalOutgoing":6717,"totalIncoming":5988},{"id":"31180","centroid":[-101.64468450229714,33.46855690493853],"population":300064,"totalOutgoing":14942,"totalIncoming":20168},{"id":"21420","centroid":[-97.78271674649967,36.37906374416364],"population":61031,"totalOutgoing":2830,"totalIncoming":2837},{"id":"32420","centroid":[-67.10998367118528,18.19536622946558],"population":92476,"totalOutgoing":4190,"totalIncoming":4461},{"id":"19780","centroid":[-93.9404423008203,41.547817923637474],"population":616933,"totalOutgoing":17947,"totalIncoming":22327},{"id":"44420","centroid":[-79.1289058462202,38.16288220060635],"population":118094,"totalOutgoing":4958,"totalIncoming":5851},{"id":"42200","centroid":[-120.02227679764468,34.72481221658118],"population":429155,"totalOutgoing":20370,"totalIncoming":25772},{"id":"19500","centroid":[-88.96155322725211,39.8599901075048],"population":105138,"totalOutgoing":2981,"totalIncoming":3295},{"id":"37900","centroid":[-89.51590241892289,40.78915913062872],"population":373669,"totalOutgoing":13409,"totalIncoming":8795},{"id":"27260","centroid":[-81.79207453642587,30.236717546084236],"population":1430040,"totalOutgoing":54526,"totalIncoming":72138},{"id":"43100","centroid":[-87.94536378123698,43.721173783633056],"population":114275,"totalOutgoing":3887,"totalIncoming":3173},{"id":"16300","centroid":[-91.63135045555875,42.091475788065615],"population":264105,"totalOutgoing":8907,"totalIncoming":9334},{"id":"12220","centroid":[-85.35547075770234,32.60113416783121],"population":152075,"totalOutgoing":10146,"totalIncoming":12756},{"id":"45220","centroid":[-84.28616754438579,30.40501967205732],"population":364852,"totalOutgoing":19992,"totalIncoming":28003},{"id":"13900","centroid":[-100.99126203004337,46.72679975498895],"population":127572,"totalOutgoing":3653,"totalIncoming":3267},{"id":"17660","centroid":[-116.70181080180137,47.67437162664832],"population":150739,"totalOutgoing":5568,"totalIncoming":6675},{"id":"30780","centroid":[-92.39717184322248,34.75721003166211],"population":728049,"totalOutgoing":22852,"totalIncoming":18137},{"id":"45500","centroid":[-94.21373923046791,33.4736080275712],"population":148783,"totalOutgoing":5236,"totalIncoming":3318},{"id":"38860","centroid":[-70.47130038828529,43.69605958345985],"population":521417,"totalOutgoing":17606,"totalIncoming":17801},{"id":"30620","centroid":[-84.10579330952636,40.77153662710219],"population":101852,"totalOutgoing":3356,"totalIncoming":3059},{"id":"27500","centroid":[-89.07157642092481,42.671234437311014],"population":160046,"totalOutgoing":4998,"totalIncoming":5361},{"id":"35660","centroid":[-86.41225880868762,41.95468625367055],"population":152651,"totalOutgoing":7625,"totalIncoming":6721},{"id":"19340","centroid":[-90.46591106833837,41.39686827032191],"population":380587,"totalOutgoing":11577,"totalIncoming":8775},{"id":"22220","centroid":[-94.12156702563081,36.1961676435836],"population":509526,"totalOutgoing":14820,"totalIncoming":21312},{"id":"27100","centroid":[-84.42341882132878,42.24848551825214],"population":156145,"totalOutgoing":5835,"totalIncoming":6312},{"id":"20500","centroid":[-79.09963176006767,35.9909467769231],"population":546072,"totalOutgoing":36334,"totalIncoming":36331},{"id":"32580","centroid":[-98.18119802486879,26.396880420165537],"population":837883,"totalOutgoing":17702,"totalIncoming":12910},{"id":"30020","centroid":[-98.43475868360694,34.52407866679185],"population":121514,"totalOutgoing":9802,"totalIncoming":11909},{"id":"20220","centroid":[-90.88245416449409,42.468812140657064],"population":93604,"totalOutgoing":2577,"totalIncoming":3850},{"id":"38940","centroid":[-80.45072607608947,27.219825778587783],"population":445780,"totalOutgoing":18239,"totalIncoming":28837},{"id":"27860","centroid":[-90.64839888489159,35.69817032567709],"population":126995,"totalOutgoing":3692,"totalIncoming":3168},{"id":"22540","centroid":[-88.48826251948759,43.753572395420186],"population":101606,"totalOutgoing":3963,"totalIncoming":3341},{"id":"43780","centroid":[-86.13411026639889,41.77363022242228],"population":316043,"totalOutgoing":15439,"totalIncoming":13800},{"id":"29740","centroid":[-106.83278215672763,32.352644461436995],"population":210381,"totalOutgoing":9508,"totalIncoming":9853},{"id":"43420","centroid":[-109.75117157356337,31.879611254127507],"population":123799,"totalOutgoing":10259,"totalIncoming":10038},{"id":"28100","centroid":[-87.86183762937728,41.13770405798336],"population":110694,"totalOutgoing":4579,"totalIncoming":3832},{"id":"38340","centroid":[-73.20635221592082,42.37069953329378],"population":125567,"totalOutgoing":4165,"totalIncoming":3942},{"id":"39740","centroid":[-75.9259741645684,40.41630727291276],"population":409910,"totalOutgoing":14976,"totalIncoming":16025},{"id":"45540","centroid":[-82.080985062211,28.704766040560447],"population":116849,"totalOutgoing":5550,"totalIncoming":7968},{"id":"39900","centroid":[-119.6591086711893,40.619030981041625],"population":443039,"totalOutgoing":16532,"totalIncoming":21041},{"id":"10180","centroid":[-99.71769650063735,32.44969932393424],"totalIncoming":11121,"population":162660,"totalOutgoing":8270},{"id":"16940","centroid":[-104.68949403577261,41.30694883566864],"population":97212,"totalOutgoing":5214,"totalIncoming":3637},{"id":"24260","centroid":[-98.2795617134842,41.03317649838205],"population":84537,"totalOutgoing":2702,"totalIncoming":1854},{"id":"29940","centroid":[-95.29257873461856,38.88466463815761],"population":114185,"totalOutgoing":9561,"totalIncoming":11218},{"id":"27780","centroid":[-78.71370941539489,40.495272877437046],"population":133057,"totalOutgoing":4117,"totalIncoming":4230},{"id":"26980","centroid":[-91.64997619750302,41.51135123512182],"population":163705,"totalOutgoing":11655,"totalIncoming":10643},{"id":"48140","centroid":[-89.75908304696436,44.89829046231593],"population":134036,"totalOutgoing":4073,"totalIncoming":3195},{"id":"21300","centroid":[-76.76003638118401,42.141265147830616],"population":86451,"totalOutgoing":2975,"totalIncoming":2087},{"id":"19180","centroid":[-87.73281327338208,40.18341523940647],"population":78150,"totalOutgoing":2442,"totalIncoming":1990},{"id":"34620","centroid":[-85.39690272508862,40.22754482906938],"population":111621,"totalOutgoing":5773,"totalIncoming":7127},{"id":"39540","centroid":[-88.0612073920038,42.74745742049676],"population":193334,"totalOutgoing":8082,"totalIncoming":8156},{"id":"10500","centroid":[-84.17391944810625,31.58949466834173],"population":150960,"totalOutgoing":5509,"totalIncoming":5271},{"id":"24140","centroid":[-78.00400023169554,35.36396076797352],"population":120861,"totalOutgoing":4796,"totalIncoming":5993},{"id":"11500","centroid":[-85.82603932702473,33.771416634176816],"population":113503,"totalOutgoing":5278,"totalIncoming":4199},{"id":"21780","centroid":[-87.57908517187951,37.971134644816615],"population":309600,"totalOutgoing":7584,"totalIncoming":7687},{"id":"23540","centroid":[-82.47649744396945,29.68845853623631],"population":274531,"totalOutgoing":20375,"totalIncoming":22847},{"id":"46220","centroid":[-87.72184802108808,33.168059876396434],"population":232081,"totalOutgoing":9076,"totalIncoming":14161},{"id":"25940","centroid":[-80.87702455268884,32.41047982001975],"population":204011,"totalOutgoing":13240,"totalIncoming":15746},{"id":"41540","centroid":[-75.46388778699028,38.42022849493691],"population":389110,"totalOutgoing":13383,"totalIncoming":17862},{"id":"34940","centroid":[-81.3475645583453,26.110720035312877],"population":349519,"totalOutgoing":16240,"totalIncoming":21459},{"id":"29460","centroid":[-81.69758641360337,27.948880567459803],"population":650823,"totalOutgoing":31573,"totalIncoming":38490},{"id":"46340","centroid":[-95.2691739475883,32.37503229025402],"population":219583,"totalOutgoing":7710,"totalIncoming":9475},{"id":"31860","centroid":[-94.13558645727755,44.15442979546815],"population":97204,"totalOutgoing":5687,"totalIncoming":5900},{"id":"18880","centroid":[-86.36565856676295,30.665735230310172],"population":260138,"totalOutgoing":19018,"totalIncoming":19416},{"id":"36980","centroid":[-87.06949180936147,37.69966364813021],"population":116785,"totalOutgoing":3821,"totalIncoming":3094},{"id":"27980","centroid":[-156.3372350736001,20.7908111049152],"population":161711,"totalOutgoing":5550,"totalIncoming":5694},{"id":"16540","centroid":[-77.72128395290827,39.9274116712345],"population":152849,"totalOutgoing":6297,"totalIncoming":5253},{"id":"34980","centroid":[-86.72447551722279,36.08907196544388],"population":1812296,"totalOutgoing":53127,"totalIncoming":73298},{"id":"13820","centroid":[-86.81387443367989,33.46381824816824],"population":1129024,"totalOutgoing":32198,"totalIncoming":32894},{"id":"38300","centroid":[-79.83095629379706,40.43902359434117],"population":2314794,"totalOutgoing":57703,"totalIncoming":51019},{"id":"36740","centroid":[-81.36301633193351,28.434337565472667],"population":2364996,"totalOutgoing":99470,"totalIncoming":135072},{"id":"47940","centroid":[-92.47118614183225,42.53622808413449],"population":166451,"totalOutgoing":6781,"totalIncoming":5653},{"id":"12580","centroid":[-76.67615419470228,39.384567506050836],"population":2757814,"totalOutgoing":97429,"totalIncoming":86593},{"id":"33140","centroid":[-86.73996211078939,41.545987035115836],"population":106702,"totalOutgoing":4860,"totalIncoming":6904},{"id":"46700","centroid":[-121.93285046213879,38.269975082016096],"population":424606,"totalOutgoing":20714,"totalIncoming":27776},{"id":"35300","centroid":[-72.93225009147011,41.410625415587546],"population":849990,"totalOutgoing":34174,"totalIncoming":30634},{"id":"48700","centroid":[-77.06452304915689,41.343400913143014],"population":113062,"totalOutgoing":3140,"totalIncoming":3407},{"id":"40660","centroid":[-85.2142581296146,34.263186341927494],"population":95299,"totalOutgoing":2798,"totalIncoming":3516},{"id":"30460","centroid":[-84.43306110060375,38.09051543000129],"population":491535,"totalOutgoing":17403,"totalIncoming":21231},{"id":"30140","centroid":[-76.45770982026379,40.36722516805555],"population":135606,"totalOutgoing":5922,"totalIncoming":6958},{"id":"25260","centroid":[-119.81554108803869,36.07534832037939],"population":144677,"totalOutgoing":9208,"totalIncoming":12391},{"id":"39460","centroid":[-81.91224150204987,26.90548578911923],"population":168903,"totalOutgoing":8680,"totalIncoming":13732},{"id":"24660","centroid":[-79.7916006321928,36.0258629113403],"population":743039,"totalOutgoing":27732,"totalIncoming":30428},{"id":"20740","centroid":[-91.28218722845894,44.938827419154634],"population":162212,"totalOutgoing":4942,"totalIncoming":5925},{"id":"11460","centroid":[-83.83876239846369,42.253217458740885],"population":350526,"totalOutgoing":25718,"totalIncoming":31312},{"id":"33220","centroid":[-84.38812678463356,43.6468437790163],"population":82317,"totalOutgoing":3544,"totalIncoming":2784},{"id":"49660","centroid":[-80.56761579430864,41.237835726531216],"population":542353,"totalOutgoing":16091,"totalIncoming":12961},{"id":"22020","centroid":[-96.96548624878402,46.91781759820481],"population":229006,"totalOutgoing":9352,"totalIncoming":10744},{"id":"12060","centroid":[-84.33973325935013,33.73263991714003],"population":5667591,"totalOutgoing":161709,"totalIncoming":174130},{"id":"15940","centroid":[-81.25348334362806,40.71864738275839],"population":398656,"totalOutgoing":12292,"totalIncoming":9779},{"id":"42140","centroid":[-105.97626349685544,35.506908157466405],"population":147130,"totalOutgoing":5852,"totalIncoming":5696},{"id":"29620","centroid":[-84.60697424405832,42.713309101757446],"population":459253,"totalOutgoing":18620,"totalIncoming":25934},{"id":"25860","centroid":[-81.4542776651643,35.81289868584043],"population":359093,"totalOutgoing":9757,"totalIncoming":11545},{"id":"26580","centroid":[-82.37912183152388,38.3813673809656],"population":357961,"totalOutgoing":9917,"totalIncoming":6684},{"id":"20940","centroid":[-115.36535522772137,33.03950915319923],"population":176937,"totalOutgoing":6185,"totalIncoming":5189},{"id":"29200","centroid":[-86.92955045438244,40.51432462012345],"population":205655,"totalOutgoing":10680,"totalIncoming":14526},{"id":"35840","centroid":[-82.32228618930826,27.347841264841087],"population":759244,"totalOutgoing":29443,"totalIncoming":43783},{"id":"31700","centroid":[-71.71609235403028,42.91534104717215],"population":398223,"totalOutgoing":13426,"totalIncoming":19218},{"id":"11020","centroid":[-78.34860335594603,40.48099294918067],"population":122936,"totalOutgoing":3839,"totalIncoming":3122},{"id":"27060","centroid":[-76.47363388288318,42.45202606694531],"population":96907,"totalOutgoing":7547,"totalIncoming":10370},{"id":"44220","centroid":[-83.78386631783063,39.916810922033875],"population":132200,"totalOutgoing":5549,"totalIncoming":5859},{"id":"40420","centroid":[-89.04205850701764,42.33161398863439],"population":334722,"totalOutgoing":10454,"totalIncoming":11465},{"id":"41660","centroid":[-100.67301215802212,31.363696705227767],"population":116314,"totalOutgoing":6321,"totalIncoming":7217},{"id":"12540","centroid":[-118.72992035400243,35.34286311159376],"population":864685,"totalOutgoing":30492,"totalIncoming":35524},{"id":"30340","centroid":[-70.20647067514312,44.16580195756288],"population":106155,"totalOutgoing":3711,"totalIncoming":4175},{"id":"12980","centroid":[-85.00558678788316,42.24654529798705],"population":132955,"totalOutgoing":5128,"totalIncoming":5511},{"id":"11700","centroid":[-82.68267400715612,35.600657745068844],"population":441165,"totalOutgoing":14690,"totalIncoming":17975},{"id":"45780","centroid":[-83.78234870268784,41.49830923047687],"population":594339,"totalOutgoing":18526,"totalIncoming":18312},{"id":"14460","centroid":[-71.10062404834406,42.55813693694584],"population":4731478,"totalOutgoing":153369,"totalIncoming":131200},{"id":"33260","centroid":[-101.99102164810996,32.08972148080117],"population":164728,"totalOutgoing":9835,"totalIncoming":10740},{"id":"12620","centroid":[-68.64945660203469,45.400641306819914],"population":147532,"totalOutgoing":3780,"totalIncoming":5118},{"id":"24540","centroid":[-104.39245245005208,40.55484536679784],"population":282322,"totalOutgoing":14404,"totalIncoming":22811},{"id":"48260","centroid":[-80.70425939278111,40.3880275427839],"population":116503,"totalOutgoing":3476,"totalIncoming":4224},{"id":"45820","centroid":[-95.8031383995934,39.04381679977791],"population":232020,"totalOutgoing":9135,"totalIncoming":6569},{"id":"40580","centroid":[-77.79847169525515,35.94100415498621],"population":146596,"totalOutgoing":5861,"totalIncoming":4711},{"id":"45300","centroid":[-82.40541663109217,28.1540144965835],"population":2953610,"totalOutgoing":103404,"totalIncoming":126404},{"id":"10900","centroid":[-75.40382030262701,40.7893607694078],"population":822660,"totalOutgoing":29613,"totalIncoming":31113},{"id":"10780","centroid":[-92.54184166879028,31.33055771099685],"totalIncoming":3974,"population":152082,"totalOutgoing":4148},{"id":"12020","centroid":[-83.21379954849613,33.94903147816022],"population":189170,"totalOutgoing":8686,"totalIncoming":19815},{"id":"20100","centroid":[-75.5684255670387,39.08617433361269],"population":169248,"totalOutgoing":7135,"totalIncoming":10092},{"id":"42020","centroid":[-120.40451813478877,35.38708294060535],"population":272731,"totalOutgoing":13875,"totalIncoming":19728},{"id":"49740","centroid":[-113.90555686431634,32.769387136219066],"population":200078,"totalOutgoing":9222,"totalIncoming":10354},{"id":"20020","centroid":[-85.46174589331966,31.252927115465717],"population":147581,"totalOutgoing":4306,"totalIncoming":3102},{"id":"14860","centroid":[-73.38930511594414,41.27119694190032],"population":934440,"totalOutgoing":40512,"totalIncoming":32038},{"id":"48300","centroid":[-120.26559993027507,47.818484704321094],"population":116405,"totalOutgoing":4044,"totalIncoming":3535}]
--------------------------------------------------------------------------------
/full/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const jsRules = {
2 | 'no-unused-vars': ['warn', { args: 'none' }],
3 | 'no-return-await': 'warn',
4 | 'no-use-before-define': 'error',
5 | 'no-mixed-spaces-and-tabs': 'error',
6 | 'no-trailing-spaces': 'warn',
7 | };
8 |
9 | module.exports = {
10 | env: {
11 | browser: true,
12 | es6: true,
13 | node: true,
14 | },
15 | parser: '@typescript-eslint/parser',
16 | parserOptions: {
17 | project: 'tsconfig.json',
18 | ecmaVersion: 2019,
19 | sourceType: 'module',
20 | },
21 | overrides: [
22 | {
23 | files: ['**/*.svelte'],
24 | parser: 'espree',
25 | processor: 'svelte3/svelte3',
26 | extends: ['eslint:recommended'],
27 | rules: jsRules,
28 | },
29 | {
30 | files: ['**/*.js'],
31 | extends: ['eslint:recommended'],
32 | rules: jsRules,
33 | },
34 | ],
35 | plugins: ['@typescript-eslint/eslint-plugin', 'svelte3'],
36 | extends: [
37 | 'plugin:@typescript-eslint/eslint-recommended',
38 | 'prettier/@typescript-eslint',
39 | ],
40 | rules: {},
41 | };
42 |
--------------------------------------------------------------------------------
/full/.gitignore:
--------------------------------------------------------------------------------
1 | public
2 | public/bundle.*
3 | public/utils.*
4 | build
5 | ### Node ###
6 | # Logs
7 | logs
8 | *.log
9 | npm-debug.log*
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 | *.pid.lock
16 |
17 | # node-waf configuration
18 | .lock-wscript
19 |
20 | # Compiled binary addons (http://nodejs.org/api/addons.html)
21 | build/Release
22 |
23 | # Dependency directories
24 | node_modules
25 | jspm_packages
26 |
27 | # Optional npm cache directory
28 | .npm
29 |
30 | # Optional eslint cache
31 | .eslintcache
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
36 | # Output of 'npm pack'
37 | *.tgz
38 |
39 | ### Git ###
40 | *.orig
41 |
42 | ### macOS ###
43 | .DS_Store
44 | .AppleDouble
45 | .LSOverride
46 |
47 | # Thumbnails
48 | ._*
49 | # Files that might appear in the root of a volume
50 | .DocumentRevisions-V100
51 | .fseventsd
52 | .Spotlight-V100
53 | .TemporaryItems
54 | .Trashes
55 | .VolumeIcon.icns
56 | .com.apple.timemachine.donotpresent
57 | # Directories potentially created on remote AFP share
58 | .AppleDB
59 | .AppleDesktop
60 | Network Trash Folder
61 | Temporary Items
62 | .apdisk
63 |
--------------------------------------------------------------------------------
/full/.prettierignore:
--------------------------------------------------------------------------------
1 | .git/*
2 | .DS_Store
3 |
4 | license
5 | yarn.lock
6 | .travis.yml
7 |
8 | .yarnclean
9 | .eslintignore
10 | .prettierignore
11 | .npmignore
12 | .gitignore
13 | .dockerignore
14 |
15 | dist
16 | build
17 | packages/*/lib/app
18 | consoles/*/lib/app
19 |
20 | *.ico
21 | *.html
22 | *.log
23 | *.svg
24 | *.map
25 | *.png
26 | *.snap
27 | *.ttf
28 | *.sh
29 | *.txt
--------------------------------------------------------------------------------
/full/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "arrowParens": "always"
5 | }
6 |
--------------------------------------------------------------------------------
/full/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Daniel Imfeld
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/full/README.md:
--------------------------------------------------------------------------------
1 | This is the full version of the Svelte Leaflet demo application, developed before the talk to show what we're aiming for.
2 |
3 | To run:
4 |
5 | 1. Install dependencies with yarn, npm, pnpm, etc.
6 | 2. `npm run dev` to start the Snowpack development server.
7 |
--------------------------------------------------------------------------------
/full/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-leaflet-demo",
3 | "author": "Daniel Imfeld",
4 | "license": "MIT",
5 | "version": "0.0.2",
6 | "scripts": {
7 | "clean": "rimraf public",
8 | "rollup": "rollup -c",
9 | "rollup:watch": "rollup -c -w",
10 | "copy-snowpack-templates": "copyfiles -u 1 snowpack/* public",
11 | "build": "NODE_ENV=production run-s clean rollup",
12 | "dev": "npm-run-all clean copy-snowpack-templates start:snowpack",
13 | "dev:rollup": "NODE_ENV=development npm-run-all clean --parallel start:dev rollup:watch",
14 | "start": "sirv public --single -H 0.0.0.0",
15 | "start:dev": "NODE_ENV=development sirv public --single --dev -H 0.0.0.0",
16 | "start:snowpack": "NODE_ENV=development snowpack dev"
17 | },
18 | "dependencies": {
19 | "@elfalem/leaflet-curve": "^0.6.0",
20 | "d3-scale": "^3.2.3",
21 | "just-flush": "^1.1.0",
22 | "leaflet": "~1.6",
23 | "sirv-cli": "^0.4.4"
24 | },
25 | "devDependencies": {
26 | "@babel/core": "^7.10.0",
27 | "@babel/plugin-proposal-class-properties": "^7.8.3",
28 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
29 | "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
30 | "@babel/plugin-proposal-optional-chaining": "^7.8.3",
31 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
32 | "@babel/plugin-transform-runtime": "^7.9.0",
33 | "@babel/preset-env": "^7.10.0",
34 | "@babel/preset-typescript": "^7.9.0",
35 | "@babel/runtime": "^7.10.0",
36 | "@fullhuman/postcss-purgecss": "^3.0.0",
37 | "@rollup/plugin-babel": "^5.0.3",
38 | "@rollup/plugin-commonjs": "^15.0.0",
39 | "@rollup/plugin-html": "^0.2.0",
40 | "@rollup/plugin-json": "^4.1.0",
41 | "@rollup/plugin-node-resolve": "^8.1.0",
42 | "@rollup/plugin-replace": "^2.3.3",
43 | "@snowpack/app-scripts-svelte": "^1.9.2",
44 | "@snowpack/plugin-postcss": "^1.0.7",
45 | "@tailwindcss/ui": "^0.6.2",
46 | "@types/d3-scale": "^3.2.1",
47 | "@types/leaflet": "^1.5.19",
48 | "@types/topojson-client": "^3.0.0",
49 | "@typescript-eslint/eslint-plugin": "^2.26.0",
50 | "@typescript-eslint/parser": "^2.26.0",
51 | "autoprefixer": "^9",
52 | "babel-eslint": "^10.0.3",
53 | "copyfiles": "^2.4.0",
54 | "cssnano": "^4.1.10",
55 | "eslint": "^6.8.0",
56 | "eslint-config-prettier": "^6.10.1",
57 | "eslint-plugin-svelte3": "^2.7.3",
58 | "lodash.template": "^4.5.0",
59 | "npm-run-all": "^4.1.5",
60 | "postcss": "^7",
61 | "postcss-cli": "^6.1.3",
62 | "postcss-import": "^12.0.1",
63 | "prettier": "^2",
64 | "prettier-plugin-svelte": "^1",
65 | "rimraf": "^3.0.2",
66 | "rollup": "^2.10.0",
67 | "rollup-plugin-copy": "^3.3.0",
68 | "rollup-plugin-livereload": "^2.0.0",
69 | "rollup-plugin-postcss": "^3.0.0",
70 | "rollup-plugin-svelte": "^6",
71 | "rollup-plugin-terser": "^7.0.0",
72 | "snowpack": "^2.16.1",
73 | "svelte": "^3.29.4",
74 | "svelte-preprocess": "^4.5.2",
75 | "tailwindcss": "^1.9.0",
76 | "typescript": "^4.0.5"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/full/postcss.config.js:
--------------------------------------------------------------------------------
1 | const production = process.env.NODE_ENV !== 'development';
2 | const purgecss = require('@fullhuman/postcss-purgecss');
3 | const cssnano = require('cssnano');
4 |
5 | module.exports = {
6 | plugins: [
7 | require('postcss-import')(),
8 | require('tailwindcss'),
9 | require('autoprefixer'),
10 | production &&
11 | purgecss({
12 | content: ['./src/**/*.html', './static/**/*.html', './src/**/*.svelte'],
13 | whitelistPatterns: [/^svelte-/],
14 | defaultExtractor: (content) => {
15 | const regExp = new RegExp(/[A-Za-z0-9-_:/.]+/g);
16 |
17 | const matchedTokens = [];
18 |
19 | let match = regExp.exec(content);
20 | // To make sure that you do not lose any tailwind classes used in class directive.
21 | // https://github.com/tailwindcss/discuss/issues/254#issuecomment-517918397
22 | while (match) {
23 | if (match[0].startsWith('class:')) {
24 | matchedTokens.push(match[0].substring(6));
25 | } else {
26 | matchedTokens.push(match[0]);
27 | }
28 |
29 | match = regExp.exec(content);
30 | }
31 |
32 | return matchedTokens;
33 | },
34 | }),
35 | production && cssnano(),
36 | ].filter(Boolean),
37 | };
38 |
--------------------------------------------------------------------------------
/full/rollup.config.js:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import template from 'lodash.template';
3 | import svelte from 'rollup-plugin-svelte';
4 | import resolve from '@rollup/plugin-node-resolve';
5 | import replace from '@rollup/plugin-replace';
6 | import commonjs from '@rollup/plugin-commonjs';
7 | import livereload from 'rollup-plugin-livereload';
8 | import { terser } from 'rollup-plugin-terser';
9 | import postcss from 'rollup-plugin-postcss';
10 | import babel from '@rollup/plugin-babel';
11 | import json from '@rollup/plugin-json';
12 | import html, { makeHtmlAttributes } from '@rollup/plugin-html';
13 | import copy from 'rollup-plugin-copy';
14 |
15 | const production = process.env.NODE_ENV !== 'development';
16 |
17 | const babelConfig = {
18 | extensions: ['.js', '.mjs', '.html', '.svelte', '.ts'],
19 | babelHelpers: 'bundled',
20 | exclude: ['node_modules/@babel/**', 'static/**', 'build/**', 'public/**'],
21 | presets: [
22 | ['@babel/preset-env', { targets: { esmodules: true } }],
23 | '@babel/preset-typescript',
24 | ],
25 | plugins: [
26 | '@babel/plugin-syntax-dynamic-import',
27 | '@babel/proposal-class-properties',
28 | '@babel/plugin-proposal-object-rest-spread',
29 | '@babel/plugin-proposal-nullish-coalescing-operator',
30 | '@babel/plugin-proposal-optional-chaining',
31 | ],
32 | };
33 |
34 | export default {
35 | input: 'src/index.js',
36 | output: {
37 | dir: 'public',
38 | entryFileNames: '[name].[hash].js',
39 | chunkFileNames: '[name].[hash].js',
40 | assetFileNames: '[name].[hash][extname]',
41 | sourcemap: production ? true : 'inline',
42 | format: 'esm',
43 | manualChunks(id) {
44 | if (id.includes('node_modules')) {
45 | return 'vendor';
46 | } else if (id.endsWith('.json')) {
47 | return 'data';
48 | }
49 | },
50 | },
51 | plugins: [
52 | svelte({
53 | preprocess: require('./svelte.config').preprocess,
54 | // enable run-time checks when not in production
55 | dev: !production,
56 | // extract any component CSS out into
57 | // a separate file — better for performance
58 | // css: css => {
59 | // css.write('public/bundle.css');
60 | // },
61 | // Instead, emit CSS as a file for processing through rollup
62 | emitCss: true,
63 | }),
64 | postcss({
65 | extract: true,
66 | }),
67 |
68 | resolve({
69 | mainFields: ['module', 'browser', 'main'],
70 | extensions: ['.mjs', '.js', '.json', '.ts', '.svelte'],
71 | dedupe: ['svelte'],
72 | }),
73 | copy({
74 | targets: [{ src: 'static/**/*', dest: 'public/' }],
75 | }),
76 | commonjs(),
77 | babel(babelConfig),
78 | json(),
79 |
80 | replace({
81 | 'process.env.NODE_ENV': JSON.stringify(
82 | process.env.NODE_ENV || 'development'
83 | ),
84 | }),
85 |
86 | // Watch the `public` directory and refresh the
87 | // browser on changes when not in production
88 | !production && livereload('public'),
89 |
90 | // If we're building for production (npm run build
91 | // instead of npm run dev), minify
92 | production && terser(),
93 |
94 | html({
95 | title: 'Metro Flow Visualizer',
96 | template: ({ attributes, files, publicPath, title }) => {
97 | let templateFile = fs.readFileSync('src/index.html');
98 |
99 | // This is adapted from the default template function in the HTML plugin.
100 | const scripts = (files.js || [])
101 | .map(({ fileName }) => {
102 | const attrs = makeHtmlAttributes(attributes.script);
103 | return ``;
104 | })
105 | .join('\n');
106 |
107 | const links = (files.css || [])
108 | .map(({ fileName }) => {
109 | const attrs = makeHtmlAttributes(attributes.link);
110 | return ``;
111 | })
112 | .join('\n');
113 |
114 | let exec = template(templateFile.toString());
115 | return exec({
116 | attributes,
117 | title,
118 | scripts,
119 | links,
120 | htmlAttributes: makeHtmlAttributes(attributes.html),
121 | });
122 | },
123 | }),
124 | ],
125 | watch: {
126 | clearScreen: false,
127 | },
128 | };
129 |
--------------------------------------------------------------------------------
/full/snowpack.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@snowpack/app-scripts-svelte",
3 | "scripts": {},
4 | "plugins": [
5 | "@snowpack/plugin-postcss"
6 | ],
7 | "mount": {
8 | "../data": "/data"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/full/snowpack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Metro Flow Visualizer
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/full/src/App.svelte:
--------------------------------------------------------------------------------
1 |
208 |
209 |
217 |
218 | (loaded = true)} />
219 |
220 |
221 |
222 |
223 | {#if loaded || document.readyState === 'complete'}
224 |
225 |
232 | {#each allShownMsas as msa (msa.id)}
233 | (clickMsa = msa)}
240 | on:mouseover={() => {
241 | hoverMsa = msa;
242 | hoveringInList = false;
243 | }}
244 | on:mouseout={() => {
245 | if (hoverMsa === msa) {
246 | hoverMsa = undefined;
247 | }
248 | }} />
249 | {/each}
250 |
251 |
252 | {#if showLines}
253 | {#each lines as line}
254 |
261 | {/each}
262 | {/if}
263 |
264 |
265 | {/if}
266 |
267 |
268 |
271 | {#if listMsa}
272 |
273 |
Top Sources
274 | {#each listMsa.incoming.slice(0, 10) as msa}
275 |
(clickMsa = msas.get(msa.id))}
278 | on:mouseover={() => {
279 | hoverMsa = msas.get(msa.id);
280 | hoveringInList = true;
281 | }}
282 | on:mouseout={() => (hoverMsa = null)}>
283 | {msas.get(msa.id).name}
284 | : {msa.count}
285 |
286 | {/each}
287 |
288 |
289 |
290 |
Top Destinations
291 | {#each listMsa.outgoing.slice(0, 10) as msa}
292 |
{
295 | hoverMsa = msas.get(msa.id);
296 | hoveringInList = true;
297 | }}
298 | on:mouseout={() => (hoverMsa = null)}
299 | on:click={() => (clickMsa = msas.get(msa.id))}>
300 | {msas.get(msa.id).name}
301 | : {msa.count}
302 |
303 | {/each}
304 |
305 | {/if}
306 |
307 |
308 |
--------------------------------------------------------------------------------
/full/src/MapControls.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
23 |
24 |
27 |
41 |
56 |
57 |
58 |
61 | Regions
62 |
67 |
72 |
77 |
78 |
79 | Show top
80 |
85 | flows
86 |
87 |
88 |
89 | {#if infoMsa}
90 |
93 |
94 |
95 | Name: |
96 | {infoMsa.name} |
97 |
98 |
99 | Incoming: |
100 |
101 | {infoMsa.totalIncoming}
102 | ({Math.abs((infoMsa.totalIncoming / infoMsa.population) * 100).toFixed(1)}%)
103 | |
104 |
105 |
106 | Outgoing: |
107 |
108 | {infoMsa.totalOutgoing}
109 | ({Math.abs((infoMsa.totalOutgoing / infoMsa.population) * 100).toFixed(1)}%)
110 | |
111 |
112 |
113 | Net Flow: |
114 |
115 | {infoMsa.net}
116 | ({Math.abs(infoMsa.netAsPercent).toFixed(1)}%)
117 | |
118 |
119 |
120 |
121 | {/if}
122 |
--------------------------------------------------------------------------------
/full/src/index.html:
--------------------------------------------------------------------------------
1 |
2 | >
3 |
4 |
5 |
6 |
7 | <%= title %>
8 |
9 |
10 | <%= links %>
11 |
12 |
13 |
14 | <%= scripts %>
15 |
16 |
17 |
--------------------------------------------------------------------------------
/full/src/index.js:
--------------------------------------------------------------------------------
1 | import './utils.css';
2 | import App from './App.svelte';
3 |
4 | const app = new App({
5 | target: document.body,
6 | });
7 |
8 | export default app;
9 |
10 | // Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
11 | // Learn more: https://www.snowpack.dev/#hot-module-replacement
12 | if (import.meta.hot) {
13 | import.meta.hot.accept();
14 | import.meta.hot.dispose(() => {
15 | app.$destroy();
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/full/src/map/Control.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
42 |
43 |
44 |
45 | {#if control}
46 |
47 | {/if}
48 |
49 |
50 |
--------------------------------------------------------------------------------
/full/src/map/Curve.svelte:
--------------------------------------------------------------------------------
1 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/full/src/map/GeoJson.svelte:
--------------------------------------------------------------------------------
1 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/full/src/map/Leaflet.svelte:
--------------------------------------------------------------------------------
1 |
55 |
56 |
61 |
62 |
63 | {#if map}
64 |
65 | {/if}
66 |
67 |
--------------------------------------------------------------------------------
/full/src/map/Pane.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/full/src/map/Polyline.svelte:
--------------------------------------------------------------------------------
1 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/full/src/map/Popup.svelte:
--------------------------------------------------------------------------------
1 |
45 |
46 |
47 |
48 | {#if showContents}
49 |
50 | {/if}
51 |
52 |
53 |
--------------------------------------------------------------------------------
/full/src/map/Tooltip.svelte:
--------------------------------------------------------------------------------
1 |
53 |
54 |
55 |
56 | {#if showContents}
57 |
58 | {/if}
59 |
60 |
61 |
--------------------------------------------------------------------------------
/full/src/map/curves.ts:
--------------------------------------------------------------------------------
1 | import * as L from 'leaflet';
2 |
3 | const curveMidpointTheta = Math.PI / 10;
4 | const cosCurveMidpointTheta = Math.cos(curveMidpointTheta);
5 |
6 | function calculateCurve(from: L.LatLng, to: L.LatLng) {
7 | let lineAngle = Math.atan2(to.lat - from.lat, to.lng - from.lng);
8 | let lineMidPointDistance =
9 | Math.sqrt((to.lng - from.lng) ** 2 + (to.lat - from.lat) ** 2) / 2;
10 | let hypotenuse = lineMidPointDistance / cosCurveMidpointTheta;
11 | let totalTheta = lineAngle + curveMidpointTheta;
12 |
13 | return L.latLng(
14 | hypotenuse * Math.sin(totalTheta) + from.lat,
15 | hypotenuse * Math.cos(totalTheta) + from.lng
16 | );
17 | }
18 |
19 | export default function makeLineCoordinates(
20 | map: L.Map,
21 | from: L.LatLng,
22 | to: L.LatLng,
23 | reverse: boolean
24 | ): (string | [number, number])[] {
25 | let curveMidpoint = calculateCurve(reverse ? to : from, reverse ? from : to);
26 | // Designed for use with the Curve component.
27 | return [
28 | 'M',
29 | [from.lat, from.lng],
30 | 'Q',
31 | [curveMidpoint.lat, curveMidpoint.lng],
32 | [to.lat, to.lng],
33 | ];
34 | }
35 |
--------------------------------------------------------------------------------
/full/src/map/leaflet.curve.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Leaflet.curve v0.6.0 - a plugin for Leaflet mapping library. https://github.com/elfalem/Leaflet.curve
3 | * (c) elfalem 2015-2020
4 | */
5 | /*
6 | * note that SVG (x, y) corresponds to (long, lat)
7 | */
8 |
9 | // This is modified from the original to work better with ES Modules. No other changes were made.
10 | import * as L from 'leaflet';
11 |
12 | export const Curve = L.Path.extend({
13 | options: {
14 | },
15 |
16 | initialize: function(path, options){
17 | L.setOptions(this, options);
18 | this._setPath(path);
19 | },
20 |
21 | // Added to follow the naming convention of L.Polyline and other Leaflet component classes:
22 | // (https://leafletjs.com/reference-1.6.0.html#polyline-setlatlngs)
23 | setLatLngs: function(path) {
24 | return this.setPath(path);
25 | },
26 |
27 | _updateBounds: function() {
28 | // Empty function to satisfy L.Path.setStyle() method
29 | },
30 |
31 | getPath: function(){
32 | return this._coords;
33 | },
34 |
35 | setPath: function(path){
36 | this._setPath(path);
37 | return this.redraw();
38 | },
39 |
40 | getBounds: function() {
41 | return this._bounds;
42 | },
43 |
44 | _setPath: function(path){
45 | this._coords = path;
46 | this._bounds = this._computeBounds();
47 | },
48 |
49 | _computeBounds: function(){
50 | var bound = new L.LatLngBounds();
51 | var lastPoint;
52 | var lastCommand;
53 | var coord;
54 | for(var i = 0; i < this._coords.length; i++){
55 | coord = this._coords[i];
56 | if(typeof coord == 'string' || coord instanceof String){
57 | lastCommand = coord;
58 | }else if(lastCommand == 'H'){
59 | bound.extend([lastPoint.lat,coord[0]]);
60 | lastPoint = new L.latLng(lastPoint.lat,coord[0]);
61 | }else if(lastCommand == 'V'){
62 | bound.extend([coord[0], lastPoint.lng]);
63 | lastPoint = new L.latLng(coord[0], lastPoint.lng);
64 | }else if(lastCommand == 'C'){
65 | var controlPoint1 = new L.latLng(coord[0], coord[1]);
66 | coord = this._coords[++i];
67 | var controlPoint2 = new L.latLng(coord[0], coord[1]);
68 | coord = this._coords[++i];
69 | var endPoint = new L.latLng(coord[0], coord[1]);
70 |
71 | bound.extend(controlPoint1);
72 | bound.extend(controlPoint2);
73 | bound.extend(endPoint);
74 |
75 | endPoint.controlPoint1 = controlPoint1;
76 | endPoint.controlPoint2 = controlPoint2;
77 | lastPoint = endPoint;
78 | }else if(lastCommand == 'S'){
79 | var controlPoint2 = new L.latLng(coord[0], coord[1]);
80 | coord = this._coords[++i];
81 | var endPoint = new L.latLng(coord[0], coord[1]);
82 |
83 | var controlPoint1 = lastPoint;
84 | if(lastPoint.controlPoint2){
85 | var diffLat = lastPoint.lat - lastPoint.controlPoint2.lat;
86 | var diffLng = lastPoint.lng - lastPoint.controlPoint2.lng;
87 | controlPoint1 = new L.latLng(lastPoint.lat + diffLat, lastPoint.lng + diffLng);
88 | }
89 |
90 | bound.extend(controlPoint1);
91 | bound.extend(controlPoint2);
92 | bound.extend(endPoint);
93 |
94 | endPoint.controlPoint1 = controlPoint1;
95 | endPoint.controlPoint2 = controlPoint2;
96 | lastPoint = endPoint;
97 | }else if(lastCommand == 'Q'){
98 | var controlPoint = new L.latLng(coord[0], coord[1]);
99 | coord = this._coords[++i];
100 | var endPoint = new L.latLng(coord[0], coord[1]);
101 |
102 | bound.extend(controlPoint);
103 | bound.extend(endPoint);
104 |
105 | endPoint.controlPoint = controlPoint;
106 | lastPoint = endPoint;
107 | }else if(lastCommand == 'T'){
108 | var endPoint = new L.latLng(coord[0], coord[1]);
109 |
110 | var controlPoint = lastPoint;
111 | if(lastPoint.controlPoint){
112 | var diffLat = lastPoint.lat - lastPoint.controlPoint.lat;
113 | var diffLng = lastPoint.lng - lastPoint.controlPoint.lng;
114 | controlPoint = new L.latLng(lastPoint.lat + diffLat, lastPoint.lng + diffLng);
115 | }
116 |
117 | bound.extend(controlPoint);
118 | bound.extend(endPoint);
119 |
120 | endPoint.controlPoint = controlPoint;
121 | lastPoint = endPoint;
122 | }else{
123 | bound.extend(coord);
124 | lastPoint = new L.latLng(coord[0], coord[1]);
125 | }
126 | }
127 | return bound;
128 | },
129 |
130 | getCenter: function () {
131 | return this._bounds.getCenter();
132 | },
133 |
134 | _update: function(){
135 | if (!this._map) { return; }
136 |
137 | this._updatePath();
138 | },
139 |
140 | _updatePath: function() {
141 | if(this._usingCanvas){
142 | this._updateCurveCanvas();
143 | }else{
144 | this._updateCurveSvg();
145 | }
146 | },
147 |
148 | _project: function() {
149 | var coord, lastCoord, curCommand, curPoint;
150 |
151 | this._points = [];
152 |
153 | for(var i = 0; i < this._coords.length; i++){
154 | coord = this._coords[i];
155 | if(typeof coord == 'string' || coord instanceof String){
156 | this._points.push(coord);
157 | curCommand = coord;
158 | }else {
159 | switch(coord.length){
160 | case 2:
161 | curPoint = this._latLngToPointFn.call(this._map, coord);
162 | lastCoord = coord;
163 | break;
164 | case 1:
165 | if(curCommand == 'H'){
166 | curPoint = this._latLngToPointFn.call(this._map, [lastCoord[0], coord[0]]);
167 | lastCoord = [lastCoord[0], coord[0]];
168 | }else{
169 | curPoint = this._latLngToPointFn.call(this._map, [coord[0], lastCoord[1]]);
170 | lastCoord = [coord[0], lastCoord[1]];
171 | }
172 | break;
173 | }
174 | this._points.push(curPoint);
175 | }
176 | }
177 | },
178 |
179 | _curvePointsToPath: function(points){
180 | var point, curCommand, str = '';
181 | for(var i = 0; i < points.length; i++){
182 | point = points[i];
183 | if(typeof point == 'string' || point instanceof String){
184 | curCommand = point;
185 | str += curCommand;
186 | }else{
187 | switch(curCommand){
188 | case 'H':
189 | str += point.x + ' ';
190 | break;
191 | case 'V':
192 | str += point.y + ' ';
193 | break;
194 | default:
195 | str += point.x + ',' + point.y + ' ';
196 | break;
197 | }
198 | }
199 | }
200 | return str || 'M0 0';
201 | },
202 |
203 | beforeAdd: function(map){
204 | L.Path.prototype.beforeAdd.call(this, map);
205 |
206 | this._usingCanvas = this._renderer instanceof L.Canvas;
207 |
208 | this._latLngToPointFn = this._usingCanvas ? map.latLngToContainerPoint : map.latLngToLayerPoint;
209 | if(this._usingCanvas){
210 | this._pathSvgElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
211 | }
212 | },
213 |
214 | onAdd: function(map){
215 | if(this._usingCanvas){
216 | // determine if dash array is set by user
217 | this._canvasSetDashArray = !this.options.dashArray;
218 | }
219 |
220 | L.Path.prototype.onAdd.call(this, map); // calls _update()
221 |
222 | if(this._usingCanvas){
223 | this._animationCanvasElement = this._insertCustomCanvasElement();
224 |
225 | this._resizeCanvas();
226 |
227 | map.on('resize', this._resizeCanvas, this);
228 |
229 | if(this.options.animate && typeof(TWEEN) === 'object'){
230 | this._pathLength = this._pathSvgElement.getTotalLength();
231 |
232 | this._normalizeCanvasAnimationOptions();
233 |
234 | this._tweenedObject = {offset: this._pathLength};
235 | this._tween = new TWEEN.Tween(this._tweenedObject)
236 | .to({offset: 0}, this.options.animate.duration)
237 | // difference of behavior with SVG, delay occurs on every iteration
238 | .delay(this.options.animate.delay)
239 | .repeat(this.options.animate.iterations - 1)
240 | .onComplete(function(scope){
241 | return function(){
242 | scope._canvasAnimating = false;
243 | }
244 | }(this))
245 | .start();
246 |
247 | this._canvasAnimating = true;
248 | this._animateCanvas();
249 | }else{
250 | this._canvasAnimating = false;
251 | }
252 | }else{
253 | if(this.options.animate && this._path.animate){
254 | var length = this._svgSetDashArray();
255 |
256 | this._path.animate([
257 | {strokeDashoffset: length},
258 | {strokeDashoffset: 0}
259 | ], this.options.animate);
260 | }
261 | }
262 | },
263 |
264 | onRemove: function(map){
265 | L.Path.prototype.onRemove.call(this, map);
266 |
267 | if(this._usingCanvas){
268 | this._clearCanvas();
269 | L.DomUtil.remove(this._animationCanvasElement);
270 | map.off('resize', this._resizeCanvas, this);
271 | }
272 | },
273 |
274 | // SVG specific logic
275 | _updateCurveSvg: function(){
276 | this._renderer._setPath(this, this._curvePointsToPath(this._points));
277 |
278 | if(this.options.animate){
279 | this._svgSetDashArray();
280 | }
281 | },
282 |
283 | _svgSetDashArray: function(){
284 | var path = this._path;
285 | var length = path.getTotalLength();
286 |
287 | if(!this.options.dashArray){
288 | path.style.strokeDasharray = length + ' ' + length;
289 | }
290 | return length;
291 | },
292 |
293 | // Needed by the `Canvas` renderer for interactivity
294 | _containsPoint: function(layerPoint) {
295 | return this._bounds.contains(this._map.layerPointToLatLng(layerPoint));
296 | },
297 |
298 | // Canvas specific logic below here
299 | _insertCustomCanvasElement: function(){
300 | var element = L.DomUtil.create('canvas', 'leaflet-zoom-animated');
301 | var originProp = L.DomUtil.testProp(['transformOrigin', 'WebkitTransformOrigin', 'msTransformOrigin']);
302 | element.style[originProp] = '50% 50%';
303 | var pane = this._map.getPane(this.options.pane);
304 | pane.insertBefore(element, pane.firstChild);
305 |
306 | return element;
307 | },
308 |
309 | _normalizeCanvasAnimationOptions: function(){
310 | var opts = {
311 | delay: 0,
312 | duration: 0,
313 | iterations: 1
314 | };
315 | if(typeof(this.options.animate) == "number"){
316 | opts.duration = this.options.animate;
317 | }else{
318 | if(this.options.animate.duration){
319 | opts.duration = this.options.animate.duration;
320 | }
321 | if(this.options.animate.delay){
322 | opts.delay =this.options.animate.delay;
323 | }
324 | if(this.options.animate.iterations){
325 | opts.iterations = this.options.animate.iterations;
326 | }
327 | }
328 |
329 | this.options.animate = opts;
330 | },
331 |
332 | _updateCurveCanvas: function(){
333 | this._project();
334 |
335 | var pathString = this._curvePointsToPath(this._points);
336 | this._pathSvgElement.setAttribute('d', pathString);
337 |
338 | if(this.options.animate && typeof(TWEEN) === 'object' && this._canvasSetDashArray){
339 | this._pathLength = this._pathSvgElement.getTotalLength();
340 | this.options.dashArray = this._pathLength + '';
341 | this._renderer._updateDashArray(this);
342 | }
343 |
344 | this._path2d = new Path2D(pathString);
345 |
346 | if(this._animationCanvasElement){
347 | this._resetCanvas();
348 | }
349 |
350 |
351 | },
352 |
353 | _animationCanvasElement: null,
354 |
355 | _resizeCanvas: function() {
356 | var size = this._map.getSize();
357 | this._animationCanvasElement.width = size.x;
358 | this._animationCanvasElement.height = size.y;
359 |
360 | this._resetCanvas();
361 | },
362 |
363 | _resetCanvas: function() {
364 | var topLeft = this._map.containerPointToLayerPoint([0, 0]);
365 | L.DomUtil.setPosition(this._animationCanvasElement, topLeft);
366 |
367 | this._redrawCanvas();
368 | },
369 |
370 | _redrawCanvas: function(){
371 | if(!this._canvasAnimating){
372 | this._clearCanvas();
373 | var ctx = this._animationCanvasElement.getContext('2d');
374 | this._curveFillStroke(this._path2d, ctx);
375 | }
376 | },
377 |
378 | _clearCanvas: function() {
379 | this._animationCanvasElement.getContext('2d').clearRect(0, 0, this._animationCanvasElement.width, this._animationCanvasElement.height);
380 | },
381 |
382 | _animateCanvas: function(time){
383 | TWEEN.update(time);
384 |
385 | var ctx = this._animationCanvasElement.getContext('2d');
386 | ctx.clearRect(0, 0, this._animationCanvasElement.width, this._animationCanvasElement.height);
387 | ctx.lineDashOffset = this._tweenedObject.offset;
388 |
389 | this._curveFillStroke(this._path2d, ctx);
390 |
391 | if(this._canvasAnimating){
392 | this._animationFrameId = L.Util.requestAnimFrame(this._animateCanvas, this);
393 | }
394 | },
395 |
396 | // similar to Canvas._fillStroke(ctx, layer)
397 | _curveFillStroke: function (path2d, ctx) {
398 | var options = this.options;
399 |
400 | if (options.fill) {
401 | ctx.globalAlpha = options.fillOpacity;
402 | ctx.fillStyle = options.fillColor || options.color;
403 | ctx.fill(path2d, options.fillRule || 'evenodd');
404 | }
405 |
406 | if (options.stroke && options.weight !== 0) {
407 | if (ctx.setLineDash) {
408 | ctx.setLineDash(this.options && this.options._dashArray || []);
409 | }
410 | ctx.globalAlpha = options.opacity;
411 | ctx.lineWidth = options.weight;
412 | ctx.strokeStyle = options.color;
413 | ctx.lineCap = options.lineCap;
414 | ctx.lineJoin = options.lineJoin;
415 | ctx.stroke(path2d);
416 | }
417 | },
418 |
419 | // path tracing logic below here
420 | trace: function(t){
421 | t = t.filter(function(element){
422 | return element >= 0 && element <= 1;
423 | });
424 |
425 | var point, curCommand, curStartPoint, curEndPoint;
426 | var p1, p2, p3;
427 | var samples = [];
428 | for(var i = 0; i < this._points.length; i++){
429 | point = this._points[i];
430 | if(typeof point == 'string' || point instanceof String){
431 | curCommand = point;
432 |
433 | if(curCommand == 'Z'){
434 | samples = samples.concat(this._linearTrace(t, curEndPoint, curStartPoint));
435 | }
436 | }else{
437 | switch(curCommand){
438 | case 'M':
439 | curStartPoint = point;
440 | curEndPoint = point;
441 | break;
442 | case 'L':
443 | case 'H':
444 | case 'V':
445 | samples = samples.concat(this._linearTrace(t, curEndPoint, point));
446 |
447 | curEndPoint = point;
448 | break;
449 | case 'C':
450 | p1 = point;
451 | p2 = this._points[++i];
452 | p3 = this._points[++i];
453 | samples = samples.concat(this._cubicTrace(t, curEndPoint, p1, p2, p3));
454 |
455 | curEndPoint = p3;
456 | break;
457 | case 'S':
458 | p1 = this._reflectPoint(p2, curEndPoint);
459 | p2 = point;
460 | p3 = this._points[++i];
461 | samples = samples.concat(this._cubicTrace(t, curEndPoint, p1, p2, p3));
462 |
463 | curEndPoint = p3;
464 | break;
465 | case 'Q':
466 | p1 = point;
467 | p2 = this._points[++i];
468 | samples = samples.concat(this._quadraticTrace(t, curEndPoint, p1, p2));
469 |
470 | curEndPoint = p2;
471 | break;
472 | case 'T':
473 | p1 = this._reflectPoint(p1, curEndPoint);
474 | p2 = point;
475 | samples = samples.concat(this._quadraticTrace(t, curEndPoint, p1, p2));
476 |
477 | curEndPoint = p2;
478 | break;
479 | default:
480 | break;
481 | }
482 | }
483 | }
484 | return samples;
485 | },
486 | _linearTrace: function(t, p0, p1){
487 | return t.map(interval => {
488 | var x = this._singleLinearTrace(interval, p0.x, p1.x);
489 | var y = this._singleLinearTrace(interval, p0.y, p1.y);
490 | return this._map.layerPointToLatLng([x, y]);
491 | });
492 | },
493 | _quadraticTrace: function(t, p0, p1, p2){
494 | return t.map(interval => {
495 | var x = this._singleQuadraticTrace(interval, p0.x, p1.x, p2.x);
496 | var y = this._singleQuadraticTrace(interval, p0.y, p1.y, p2.y);
497 | return this._map.layerPointToLatLng([x, y]);
498 | });
499 | },
500 | _cubicTrace: function(t, p0, p1, p2, p3){
501 | return t.map(interval => {
502 | var x = this._singleCubicTrace(interval, p0.x, p1.x, p2.x, p3.x);
503 | var y = this._singleCubicTrace(interval, p0.y, p1.y, p2.y, p3.y);
504 | return this._map.layerPointToLatLng([x, y]);
505 | });
506 | },
507 | _singleLinearTrace: function(t, p0, p1){
508 | return p0 + t * (p1 - p0);
509 | },
510 | _singleQuadraticTrace: function(t, p0, p1, p2){
511 | var oneMinusT = 1 - t;
512 | return Math.pow(oneMinusT, 2) * p0 +
513 | 2 * oneMinusT * t * p1 +
514 | Math.pow(t, 2) * p2;
515 | },
516 | _singleCubicTrace: function(t, p0, p1, p2, p3){
517 | var oneMinusT = 1 - t;
518 | return Math.pow(oneMinusT, 3) * p0 +
519 | 3 * Math.pow(oneMinusT, 2) * t * p1 +
520 | 3 * oneMinusT * Math.pow(t, 2) * p2 +
521 | Math.pow(t, 3) * p3;
522 | },
523 | _reflectPoint: function(point, over){
524 | x = over.x + (over.x - point.x);
525 | y = over.y + (over.y - point.y);
526 | return L.point(x, y);
527 | }
528 | });
529 |
530 | export function curve(path, options){
531 | return new Curve(path, options);
532 | };
--------------------------------------------------------------------------------
/full/src/map/popup.ts:
--------------------------------------------------------------------------------
1 | import { SvelteComponent } from 'svelte';
2 | import * as L from 'leaflet';
3 |
4 | export function bindPopup(
5 | layer: L.Layer,
6 | popup?: string | typeof SvelteComponent,
7 | props?: object
8 | ) {
9 | if (!popup) {
10 | return;
11 | }
12 |
13 | if (typeof popup === 'string') {
14 | layer.bindPopup(popup);
15 | } else {
16 | let popupComponent: SvelteComponent | undefined;
17 | layer.bindPopup(() => {
18 | let container = L.DomUtil.create('div');
19 | popupComponent = new popup({
20 | target: container,
21 | props: { ...(props || {}) },
22 | });
23 | return container;
24 | });
25 |
26 | layer.on('popupclose', () => {
27 | if (popupComponent) {
28 | let old = popupComponent;
29 | popupComponent = undefined;
30 | // Wait for the popup to completely fade out before destroying it.
31 | // Otherwise the fade out looks weird as the contents disappear too early.
32 | setTimeout(() => {
33 | old.$destroy();
34 | }, 500);
35 | }
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/full/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Flow {
2 | id: string;
3 | count: number;
4 | }
5 |
6 | export interface Msa {
7 | id: string;
8 | name: string;
9 | net: number;
10 | centroid: number[];
11 | totalIncoming: number;
12 | totalOutgoing: number;
13 | netAsPercent: number;
14 | population: number;
15 | feature: any;
16 | outgoing: Flow[];
17 | incoming: Flow[];
18 | }
19 |
--------------------------------------------------------------------------------
/full/src/utils.css:
--------------------------------------------------------------------------------
1 | /* Import Tailwind as Global Utils */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
5 |
6 | * {
7 | position: relative;
8 | }
9 |
--------------------------------------------------------------------------------
/full/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dimfeld/svelte-leaflet-demo/897b5aab379cc8926ed9ee65a9df846fbae62df7/full/static/favicon.png
--------------------------------------------------------------------------------
/full/svelte.config.js:
--------------------------------------------------------------------------------
1 | const sveltePreprocess = require('svelte-preprocess');
2 |
3 | const dev = process.env.NODE_ENV === 'development';
4 |
5 | module.exports = {
6 | preprocess: sveltePreprocess({
7 | postcss: require('./postcss.config'),
8 | typescript: true,
9 | aliases: [['ts', 'typescript']],
10 | }),
11 | };
12 |
--------------------------------------------------------------------------------
/full/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: false,
3 | theme: {
4 | extend: {
5 | animation: {
6 | 'dash-offset': 'dash-offset var(--animation-speed, 2s) linear infinite',
7 | },
8 | keyframes: {
9 | 'dash-offset': {
10 | from: {
11 | 'stroke-dashoffset': 'var(--dash-length, 18)',
12 | },
13 | to: {
14 | 'stroke-dashoffset': '0',
15 | },
16 | },
17 | },
18 | },
19 | },
20 | variants: {},
21 | plugins: [require('@tailwindcss/ui')],
22 | experimental: {
23 | applyComplexClasses: true,
24 | defaultLineHeights: true,
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/full/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "module": "ESNext",
5 | "moduleResolution": "node",
6 | "target": "es2020",
7 | "noEmit": true,
8 | "strict": true,
9 | "resolveJsonModule": true,
10 | "allowSyntheticDefaultImports": true,
11 | "lib": ["dom", "es5", "ES2015", "es2016", "es2017", "es2018", "ES2019"]
12 | },
13 | "paths": {
14 | "^/*": ["src/*"]
15 | },
16 | "include": ["src"],
17 | "compileOnSave": false
18 | }
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-leaflet-demo",
3 | "version": "1.0.0",
4 | "description": "Visualize Migrations in the US with Svelte and Leaflet",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/dimfeld/svelte-leaflet-demo.git"
12 | },
13 | "author": "Daniel Imfeld ",
14 | "license": "MIT",
15 | "bugs": {
16 | "url": "https://github.com/dimfeld/svelte-leaflet-demo/issues"
17 | },
18 | "homepage": "https://github.com/dimfeld/svelte-leaflet-demo#readme",
19 | "dependencies": {
20 | "@turf/turf": "^5.1.6",
21 | "d3-dsv": "^2.0.0",
22 | "topojson-client": "^3.1.0",
23 | "topojson-server": "^3.0.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | '@turf/turf': 5.1.6
3 | d3-dsv: 2.0.0
4 | topojson-client: 3.1.0
5 | topojson-server: 3.0.1
6 | lockfileVersion: 5.2
7 | packages:
8 | /@turf/along/5.1.5:
9 | dependencies:
10 | '@turf/bearing': 5.1.5
11 | '@turf/destination': 5.1.5
12 | '@turf/distance': 5.1.5
13 | '@turf/helpers': 5.1.5
14 | dev: false
15 | resolution:
16 | integrity: sha1-YdbmplhKzdq1asVYTge/jL5fi+s=
17 | /@turf/area/5.1.5:
18 | dependencies:
19 | '@turf/helpers': 5.1.5
20 | '@turf/meta': 5.1.6
21 | dev: false
22 | resolution:
23 | integrity: sha1-79iZv9Jgzb0VQbKjwVX4pdLu+h0=
24 | /@turf/bbox-clip/5.1.5:
25 | dependencies:
26 | '@turf/helpers': 5.1.5
27 | '@turf/invariant': 5.1.5
28 | lineclip: 1.1.5
29 | dev: false
30 | resolution:
31 | integrity: sha1-M2S1Mo3/nzz0HZ4C7a/zdNFQzIQ=
32 | /@turf/bbox-polygon/5.1.5:
33 | dependencies:
34 | '@turf/helpers': 5.1.5
35 | dev: false
36 | resolution:
37 | integrity: sha1-auuk7VHYXSluD3w4uIwznwHu4CQ=
38 | /@turf/bbox/5.1.5:
39 | dependencies:
40 | '@turf/helpers': 5.1.5
41 | '@turf/meta': 5.1.6
42 | dev: false
43 | resolution:
44 | integrity: sha1-MFHfUUrUxQ9KT5uKLRX9i2hA7aM=
45 | /@turf/bearing/5.1.5:
46 | dependencies:
47 | '@turf/helpers': 5.1.5
48 | '@turf/invariant': 5.1.5
49 | dev: false
50 | resolution:
51 | integrity: sha1-egt5ATbE70eX8CRjBdRcvi0ns/c=
52 | /@turf/bearing/6.0.1:
53 | dependencies:
54 | '@turf/helpers': 6.1.4
55 | '@turf/invariant': 6.1.2
56 | dev: false
57 | resolution:
58 | integrity: sha512-mXY1NozqV9EFfBTbUItujwfqfQF0G/Xe2fzvnZle90ekPEUfhi4Dgf5JswJTd96J9LiT8kcd6Jonp5khnx0wIg==
59 | /@turf/bezier-spline/5.1.5:
60 | dependencies:
61 | '@turf/helpers': 5.1.5
62 | '@turf/invariant': 5.1.5
63 | dev: false
64 | resolution:
65 | integrity: sha1-WaJ7ul17l+8Vqz/VpA+9I4cEm8o=
66 | /@turf/boolean-clockwise/5.1.5:
67 | dependencies:
68 | '@turf/helpers': 5.1.5
69 | '@turf/invariant': 5.1.5
70 | dev: false
71 | resolution:
72 | integrity: sha1-MwK32sYsXikaB4nimvcoM4f6nes=
73 | /@turf/boolean-contains/5.1.5:
74 | dependencies:
75 | '@turf/bbox': 5.1.5
76 | '@turf/boolean-point-in-polygon': 5.1.5
77 | '@turf/boolean-point-on-line': 5.1.5
78 | '@turf/helpers': 5.1.5
79 | '@turf/invariant': 5.1.5
80 | dev: false
81 | resolution:
82 | integrity: sha1-WW1jruY2961T7pn5/yTJaZSg7xQ=
83 | /@turf/boolean-crosses/5.1.5:
84 | dependencies:
85 | '@turf/boolean-point-in-polygon': 5.1.5
86 | '@turf/helpers': 5.1.5
87 | '@turf/invariant': 5.1.5
88 | '@turf/line-intersect': 5.1.5
89 | '@turf/polygon-to-line': 5.1.5
90 | dev: false
91 | resolution:
92 | integrity: sha1-Ab+uollvFk3kpNMlCU3HwlXHFdY=
93 | /@turf/boolean-disjoint/5.1.6:
94 | dependencies:
95 | '@turf/boolean-point-in-polygon': 5.1.5
96 | '@turf/helpers': 5.1.5
97 | '@turf/line-intersect': 5.1.5
98 | '@turf/meta': 5.1.6
99 | '@turf/polygon-to-line': 5.1.5
100 | dev: false
101 | resolution:
102 | integrity: sha512-KHvUS6SBNYHBCLIJEJrg04pF5Oy+Fqn8V5G9U+9pti5vI9tyX7Ln2g7RSB7iJ1Cxsz8QAi6OukhXjEF2/8ZpGg==
103 | /@turf/boolean-equal/5.1.5:
104 | dependencies:
105 | '@turf/clean-coords': 5.1.5
106 | '@turf/helpers': 5.1.5
107 | '@turf/invariant': 5.1.5
108 | geojson-equality: 0.1.6
109 | dev: false
110 | resolution:
111 | integrity: sha1-Kfj21gu4RQff12WzIlTbjnLJOKQ=
112 | /@turf/boolean-overlap/5.1.5:
113 | dependencies:
114 | '@turf/helpers': 5.1.5
115 | '@turf/invariant': 5.1.5
116 | '@turf/line-intersect': 5.1.5
117 | '@turf/line-overlap': 5.1.5
118 | '@turf/meta': 5.1.6
119 | geojson-equality: 0.1.6
120 | dev: false
121 | resolution:
122 | integrity: sha1-DU5kxSx3CijpPZ7834qLg3OsznU=
123 | /@turf/boolean-parallel/5.1.5:
124 | dependencies:
125 | '@turf/clean-coords': 5.1.5
126 | '@turf/helpers': 5.1.5
127 | '@turf/line-segment': 5.1.5
128 | '@turf/rhumb-bearing': 5.1.5
129 | dev: false
130 | resolution:
131 | integrity: sha1-c5NYR16ltlx+GCejw+DopofTqF0=
132 | /@turf/boolean-point-in-polygon/5.1.5:
133 | dependencies:
134 | '@turf/helpers': 5.1.5
135 | '@turf/invariant': 5.1.5
136 | dev: false
137 | resolution:
138 | integrity: sha1-8BzBlNHgMKVIv9qYHLpDz9YpQbc=
139 | /@turf/boolean-point-on-line/5.1.5:
140 | dependencies:
141 | '@turf/helpers': 5.1.5
142 | '@turf/invariant': 5.1.5
143 | dev: false
144 | resolution:
145 | integrity: sha1-9jPF/4Aq0ku48Vja269v9KAj3Xs=
146 | /@turf/boolean-within/5.1.5:
147 | dependencies:
148 | '@turf/bbox': 5.1.5
149 | '@turf/boolean-point-in-polygon': 5.1.5
150 | '@turf/boolean-point-on-line': 5.1.5
151 | '@turf/helpers': 5.1.5
152 | '@turf/invariant': 5.1.5
153 | dev: false
154 | resolution:
155 | integrity: sha1-RxBdVtB1Kp0Pv81Dw2pfkUnchpc=
156 | /@turf/buffer/5.1.5:
157 | dependencies:
158 | '@turf/bbox': 5.1.5
159 | '@turf/center': 5.1.5
160 | '@turf/helpers': 5.1.5
161 | '@turf/meta': 5.1.6
162 | '@turf/projection': 5.1.5
163 | d3-geo: 1.7.1
164 | turf-jsts: 1.2.3
165 | dev: false
166 | resolution:
167 | integrity: sha1-hByWJ8+5dLEirE4alW8EZrwCMcQ=
168 | /@turf/center-mean/5.1.5:
169 | dependencies:
170 | '@turf/bbox': 5.1.5
171 | '@turf/helpers': 5.1.5
172 | '@turf/meta': 5.1.6
173 | dev: false
174 | resolution:
175 | integrity: sha1-jI6YdTkeXwnw5uePXWYbiLIQigo=
176 | /@turf/center-median/5.1.5:
177 | dependencies:
178 | '@turf/center-mean': 5.1.5
179 | '@turf/centroid': 5.1.5
180 | '@turf/distance': 5.1.5
181 | '@turf/helpers': 5.1.5
182 | '@turf/meta': 5.1.6
183 | dev: false
184 | resolution:
185 | integrity: sha1-u0Yb/noqSGAdikcnaFcYcjoUqHI=
186 | /@turf/center-of-mass/5.1.5:
187 | dependencies:
188 | '@turf/centroid': 5.1.5
189 | '@turf/convex': 5.1.5
190 | '@turf/helpers': 5.1.5
191 | '@turf/invariant': 5.1.5
192 | '@turf/meta': 5.1.6
193 | dev: false
194 | resolution:
195 | integrity: sha1-TTvXnYhJjbq4Mk1PafAyL2Uguco=
196 | /@turf/center/5.1.5:
197 | dependencies:
198 | '@turf/bbox': 5.1.5
199 | '@turf/helpers': 5.1.5
200 | dev: false
201 | resolution:
202 | integrity: sha1-RKss2VT2PA03dX9xWKmcPvURS4A=
203 | /@turf/centroid/5.1.5:
204 | dependencies:
205 | '@turf/helpers': 5.1.5
206 | '@turf/meta': 5.1.6
207 | dev: false
208 | resolution:
209 | integrity: sha1-d4radCFjNQIa2P0OemWoNJ1Tx2k=
210 | /@turf/circle/5.1.5:
211 | dependencies:
212 | '@turf/destination': 5.1.5
213 | '@turf/helpers': 5.1.5
214 | dev: false
215 | resolution:
216 | integrity: sha1-mxV3g1UIq1L7HBCypQZcuiuHtqU=
217 | /@turf/clean-coords/5.1.5:
218 | dependencies:
219 | '@turf/helpers': 5.1.5
220 | '@turf/invariant': 5.1.5
221 | dev: false
222 | resolution:
223 | integrity: sha1-EoAKmKeMmkUqcuxChJPEOs8q2h8=
224 | /@turf/clone/5.1.5:
225 | dependencies:
226 | '@turf/helpers': 5.1.5
227 | dev: false
228 | resolution:
229 | integrity: sha1-JT6NNUdxgZduM636tQoPAqfw42c=
230 | /@turf/clone/6.0.2:
231 | dependencies:
232 | '@turf/helpers': 6.1.4
233 | dev: false
234 | resolution:
235 | integrity: sha512-UVpYPnW3wRj3bPncR6Z2PRbowBk+nEdVWgGewPxrKKLfvswtVtG9n/OIyvbU3E3ZOadBVxTH2uAMEMOz4800FA==
236 | /@turf/clusters-dbscan/5.1.5:
237 | dependencies:
238 | '@turf/clone': 5.1.5
239 | '@turf/distance': 5.1.5
240 | '@turf/helpers': 5.1.5
241 | '@turf/invariant': 5.1.5
242 | '@turf/meta': 5.1.6
243 | density-clustering: 1.3.0
244 | dev: false
245 | resolution:
246 | integrity: sha1-V4H7TmVsdHoLjpk333MYHAMJ4m8=
247 | /@turf/clusters-kmeans/5.1.5:
248 | dependencies:
249 | '@turf/clone': 5.1.5
250 | '@turf/helpers': 5.1.5
251 | '@turf/invariant': 5.1.5
252 | '@turf/meta': 5.1.6
253 | skmeans: 0.9.7
254 | dev: false
255 | resolution:
256 | integrity: sha1-/W3+qLEzuovcI3CsPKzuFYejAvE=
257 | /@turf/clusters/5.1.5:
258 | dependencies:
259 | '@turf/helpers': 5.1.5
260 | '@turf/meta': 5.1.6
261 | dev: false
262 | resolution:
263 | integrity: sha1-ZzpeXxsZycq6vFfJCO6t1oIiTdQ=
264 | /@turf/collect/5.1.5:
265 | dependencies:
266 | '@turf/bbox': 5.1.5
267 | '@turf/boolean-point-in-polygon': 5.1.5
268 | '@turf/helpers': 5.1.5
269 | rbush: 2.0.2
270 | dev: false
271 | resolution:
272 | integrity: sha1-/pjJqMIY7PJP/DPXApUXt8GbKj4=
273 | /@turf/combine/5.1.5:
274 | dependencies:
275 | '@turf/helpers': 5.1.5
276 | '@turf/meta': 5.1.6
277 | dev: false
278 | resolution:
279 | integrity: sha1-uxS976VVBDVxlfwaEkzX1TqMiQU=
280 | /@turf/concave/5.1.5:
281 | dependencies:
282 | '@turf/clone': 5.1.5
283 | '@turf/distance': 5.1.5
284 | '@turf/helpers': 5.1.5
285 | '@turf/invariant': 5.1.5
286 | '@turf/meta': 5.1.6
287 | '@turf/tin': 5.1.5
288 | topojson-client: 3.1.0
289 | topojson-server: 3.0.1
290 | dev: false
291 | resolution:
292 | integrity: sha1-I7uqw4fQNLlldKG9cNBZI3qdIRA=
293 | /@turf/convex/5.1.5:
294 | dependencies:
295 | '@turf/helpers': 5.1.5
296 | '@turf/meta': 5.1.6
297 | concaveman: 1.2.0
298 | dev: false
299 | resolution:
300 | integrity: sha1-Dfk3fdACIWzpghsH9wXgN9rj4B0=
301 | /@turf/destination/5.1.5:
302 | dependencies:
303 | '@turf/helpers': 5.1.5
304 | '@turf/invariant': 5.1.5
305 | dev: false
306 | resolution:
307 | integrity: sha1-7TU4G9zoO73cvQei4rzivd/7zCY=
308 | /@turf/difference/5.1.5:
309 | dependencies:
310 | '@turf/area': 5.1.5
311 | '@turf/helpers': 5.1.5
312 | '@turf/invariant': 5.1.5
313 | '@turf/meta': 5.1.6
314 | turf-jsts: 1.2.3
315 | dev: false
316 | resolution:
317 | integrity: sha1-ok1pCnvKgD8QkKnuO52Qb8Q3H0I=
318 | /@turf/dissolve/5.1.5:
319 | dependencies:
320 | '@turf/boolean-overlap': 5.1.5
321 | '@turf/clone': 5.1.5
322 | '@turf/helpers': 5.1.5
323 | '@turf/invariant': 5.1.5
324 | '@turf/line-intersect': 5.1.5
325 | '@turf/meta': 5.1.6
326 | '@turf/union': 5.1.5
327 | geojson-rbush: 2.1.0
328 | get-closest: 0.0.4
329 | dev: false
330 | resolution:
331 | integrity: sha1-LPEzqQIdIWODHD16lY1lB/nYGTg=
332 | /@turf/distance/5.1.5:
333 | dependencies:
334 | '@turf/helpers': 5.1.5
335 | '@turf/invariant': 5.1.5
336 | dev: false
337 | resolution:
338 | integrity: sha1-Oc8YIEu/h1h9cH5gmmARiQkVZAk=
339 | /@turf/distance/6.0.1:
340 | dependencies:
341 | '@turf/helpers': 6.1.4
342 | '@turf/invariant': 6.1.2
343 | dev: false
344 | resolution:
345 | integrity: sha512-q7t7rWIWfkg7MP1Vt4uLjSEhe5rPfCO2JjpKmk7JC+QZKEQkuvHEqy3ejW1iC7Kw5ZcZNR3qdMGGz+6HnVwqvg==
346 | /@turf/ellipse/5.1.5:
347 | dependencies:
348 | '@turf/helpers': 5.1.5
349 | '@turf/invariant': 5.1.5
350 | '@turf/rhumb-destination': 5.1.5
351 | '@turf/transform-rotate': 5.1.5
352 | dev: false
353 | resolution:
354 | integrity: sha1-1XyrhTmFkgzeYCKKeNgEWAJcVL4=
355 | /@turf/envelope/5.1.5:
356 | dependencies:
357 | '@turf/bbox': 5.1.5
358 | '@turf/bbox-polygon': 5.1.5
359 | '@turf/helpers': 5.1.5
360 | dev: false
361 | resolution:
362 | integrity: sha1-UBMwnFP91D369LWIplw/7X28EIo=
363 | /@turf/explode/5.1.5:
364 | dependencies:
365 | '@turf/helpers': 5.1.5
366 | '@turf/meta': 5.1.6
367 | dev: false
368 | resolution:
369 | integrity: sha1-sSsvd0AEobSPYrqVsgocZVo94Rg=
370 | /@turf/flatten/5.1.5:
371 | dependencies:
372 | '@turf/helpers': 5.1.5
373 | '@turf/meta': 5.1.6
374 | dev: false
375 | resolution:
376 | integrity: sha1-2iknBnEz7WFpsLnWB7khVoiqE1g=
377 | /@turf/flip/5.1.5:
378 | dependencies:
379 | '@turf/clone': 5.1.5
380 | '@turf/helpers': 5.1.5
381 | '@turf/meta': 5.1.6
382 | dev: false
383 | resolution:
384 | integrity: sha1-Q29kOnIvDKU7n85jjkaT2zYIpoo=
385 | /@turf/great-circle/5.1.5:
386 | dependencies:
387 | '@turf/helpers': 5.1.5
388 | '@turf/invariant': 5.1.5
389 | dev: false
390 | resolution:
391 | integrity: sha1-3r+2cc5HVQnLY3MBwV/PzPo1mpM=
392 | /@turf/helpers/5.1.5:
393 | dev: false
394 | resolution:
395 | integrity: sha1-FTQFInq5M9AEpbuWQantmZ/L4M8=
396 | /@turf/helpers/6.1.4:
397 | dev: false
398 | resolution:
399 | integrity: sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==
400 | /@turf/hex-grid/5.1.5:
401 | dependencies:
402 | '@turf/distance': 5.1.5
403 | '@turf/helpers': 5.1.5
404 | '@turf/intersect': 5.1.6
405 | '@turf/invariant': 5.1.5
406 | dev: false
407 | resolution:
408 | integrity: sha1-m3ul/s9QUfHoWJL3E/zlxVBQKmo=
409 | /@turf/interpolate/5.1.5:
410 | dependencies:
411 | '@turf/bbox': 5.1.5
412 | '@turf/centroid': 5.1.5
413 | '@turf/clone': 5.1.5
414 | '@turf/distance': 5.1.5
415 | '@turf/helpers': 5.1.5
416 | '@turf/hex-grid': 5.1.5
417 | '@turf/invariant': 5.1.5
418 | '@turf/meta': 5.1.6
419 | '@turf/point-grid': 5.1.5
420 | '@turf/square-grid': 5.1.5
421 | '@turf/triangle-grid': 5.1.5
422 | dev: false
423 | resolution:
424 | integrity: sha1-DxLwq3VtbdEK+ykMpuh3ve8BPqo=
425 | /@turf/intersect/5.1.6:
426 | dependencies:
427 | '@turf/clean-coords': 5.1.5
428 | '@turf/helpers': 5.1.5
429 | '@turf/invariant': 5.1.5
430 | '@turf/truncate': 5.1.5
431 | turf-jsts: 1.2.3
432 | dev: false
433 | resolution:
434 | integrity: sha512-KXyNv/GXdoGAOy03qZF53rgtXC2tNhF/4jLwTKiVRrBQH6kcEpipGStdJ+QkYIlarQPa8f7I9UlVAB19et4MfQ==
435 | /@turf/invariant/5.1.5:
436 | dependencies:
437 | '@turf/helpers': 5.1.5
438 | dev: false
439 | resolution:
440 | integrity: sha1-9Z9P76CSJLFdzhZR+QPIaNV6JOE=
441 | /@turf/invariant/6.1.2:
442 | dependencies:
443 | '@turf/helpers': 6.1.4
444 | dev: false
445 | resolution:
446 | integrity: sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==
447 | /@turf/isobands/5.1.5:
448 | dependencies:
449 | '@turf/area': 5.1.5
450 | '@turf/bbox': 5.1.5
451 | '@turf/boolean-point-in-polygon': 5.1.5
452 | '@turf/explode': 5.1.5
453 | '@turf/helpers': 5.1.5
454 | '@turf/invariant': 5.1.5
455 | '@turf/meta': 5.1.6
456 | dev: false
457 | resolution:
458 | integrity: sha1-a0TO9YTVUaMTBBh68jtKFYLj8I0=
459 | /@turf/isolines/5.1.5:
460 | dependencies:
461 | '@turf/bbox': 5.1.5
462 | '@turf/helpers': 5.1.5
463 | '@turf/invariant': 5.1.5
464 | '@turf/meta': 5.1.6
465 | dev: false
466 | resolution:
467 | integrity: sha1-irTn9Cuz38VGFOW/FVln9+VdLeE=
468 | /@turf/kinks/5.1.5:
469 | dependencies:
470 | '@turf/helpers': 5.1.5
471 | dev: false
472 | resolution:
473 | integrity: sha1-irtpYdm7AQchO63fLCwmQNAlaYA=
474 | /@turf/length/5.1.5:
475 | dependencies:
476 | '@turf/distance': 5.1.5
477 | '@turf/helpers': 5.1.5
478 | '@turf/meta': 5.1.6
479 | dev: false
480 | resolution:
481 | integrity: sha1-86X4ZMK5lqi7RxeUU1ofrxLuvvs=
482 | /@turf/line-arc/5.1.5:
483 | dependencies:
484 | '@turf/circle': 5.1.5
485 | '@turf/destination': 5.1.5
486 | '@turf/helpers': 5.1.5
487 | dev: false
488 | resolution:
489 | integrity: sha1-AHinRHg1oSrkFKIR+aZNEYYVDhU=
490 | /@turf/line-chunk/5.1.5:
491 | dependencies:
492 | '@turf/helpers': 5.1.5
493 | '@turf/length': 5.1.5
494 | '@turf/line-slice-along': 5.1.5
495 | '@turf/meta': 5.1.6
496 | dev: false
497 | resolution:
498 | integrity: sha1-kQqFwFwG2dD5w4l3oF4IGNUIXEI=
499 | /@turf/line-intersect/5.1.5:
500 | dependencies:
501 | '@turf/helpers': 5.1.5
502 | '@turf/invariant': 5.1.5
503 | '@turf/line-segment': 5.1.5
504 | '@turf/meta': 5.1.6
505 | geojson-rbush: 2.1.0
506 | dev: false
507 | resolution:
508 | integrity: sha1-DikHGuQDKV5JFyO8SfXPrI0R3fM=
509 | /@turf/line-offset/5.1.5:
510 | dependencies:
511 | '@turf/helpers': 5.1.5
512 | '@turf/invariant': 5.1.5
513 | '@turf/meta': 5.1.6
514 | dev: false
515 | resolution:
516 | integrity: sha1-KrWy8In4yRPiMdmUN4553KkLWh4=
517 | /@turf/line-overlap/5.1.5:
518 | dependencies:
519 | '@turf/boolean-point-on-line': 5.1.5
520 | '@turf/helpers': 5.1.5
521 | '@turf/invariant': 5.1.5
522 | '@turf/line-segment': 5.1.5
523 | '@turf/meta': 5.1.6
524 | '@turf/nearest-point-on-line': 5.1.5
525 | geojson-rbush: 2.1.0
526 | dev: false
527 | resolution:
528 | integrity: sha1-lDxvh6A4bcQ9+sEdKz/5wRLNP2A=
529 | /@turf/line-segment/5.1.5:
530 | dependencies:
531 | '@turf/helpers': 5.1.5
532 | '@turf/invariant': 5.1.5
533 | '@turf/meta': 5.1.6
534 | dev: false
535 | resolution:
536 | integrity: sha1-Mgeq7lRqskw9jcPMY/kcdwuAE+U=
537 | /@turf/line-slice-along/5.1.5:
538 | dependencies:
539 | '@turf/bearing': 5.1.5
540 | '@turf/destination': 5.1.5
541 | '@turf/distance': 5.1.5
542 | '@turf/helpers': 5.1.5
543 | dev: false
544 | resolution:
545 | integrity: sha1-7drQoh70efKWihG9LdcomiEy6aU=
546 | /@turf/line-slice/5.1.5:
547 | dependencies:
548 | '@turf/helpers': 5.1.5
549 | '@turf/invariant': 5.1.5
550 | '@turf/nearest-point-on-line': 5.1.5
551 | dev: false
552 | resolution:
553 | integrity: sha1-Hs/OFGKjeFeXVM7fRGTN4mgp8rU=
554 | /@turf/line-split/5.1.5:
555 | dependencies:
556 | '@turf/bbox': 5.1.5
557 | '@turf/helpers': 5.1.5
558 | '@turf/invariant': 5.1.5
559 | '@turf/line-intersect': 5.1.5
560 | '@turf/line-segment': 5.1.5
561 | '@turf/meta': 5.1.6
562 | '@turf/nearest-point-on-line': 5.1.5
563 | '@turf/square': 5.1.5
564 | '@turf/truncate': 5.1.5
565 | geojson-rbush: 2.1.0
566 | dev: false
567 | resolution:
568 | integrity: sha1-Wy30w3YZty73JbUWPPmSbVVArLc=
569 | /@turf/line-to-polygon/5.1.5:
570 | dependencies:
571 | '@turf/bbox': 5.1.5
572 | '@turf/helpers': 5.1.5
573 | '@turf/invariant': 5.1.5
574 | dev: false
575 | resolution:
576 | integrity: sha1-ITz0Gmj4Ikd4ujnTGH3sPouBhlo=
577 | /@turf/mask/5.1.5:
578 | dependencies:
579 | '@turf/bbox': 5.1.5
580 | '@turf/helpers': 5.1.5
581 | '@turf/meta': 5.1.6
582 | '@turf/union': 5.1.5
583 | rbush: 2.0.2
584 | dev: false
585 | resolution:
586 | integrity: sha1-mrD+8aJyyY/j70kvn/thggayQtU=
587 | /@turf/meta/5.1.6:
588 | dependencies:
589 | '@turf/helpers': 5.1.5
590 | dev: false
591 | resolution:
592 | integrity: sha1-wgqGPt7Qhp+yhUje6Ik0G8y0akY=
593 | /@turf/meta/6.0.2:
594 | dependencies:
595 | '@turf/helpers': 6.1.4
596 | dev: false
597 | resolution:
598 | integrity: sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==
599 | /@turf/midpoint/5.1.5:
600 | dependencies:
601 | '@turf/bearing': 5.1.5
602 | '@turf/destination': 5.1.5
603 | '@turf/distance': 5.1.5
604 | '@turf/helpers': 5.1.5
605 | dev: false
606 | resolution:
607 | integrity: sha1-4mH2srDqgSTM7/VSomLdRlydBfA=
608 | /@turf/nearest-point-on-line/5.1.5:
609 | dependencies:
610 | '@turf/bearing': 5.1.5
611 | '@turf/destination': 5.1.5
612 | '@turf/distance': 5.1.5
613 | '@turf/helpers': 5.1.5
614 | '@turf/invariant': 5.1.5
615 | '@turf/line-intersect': 5.1.5
616 | '@turf/meta': 5.1.6
617 | dev: false
618 | resolution:
619 | integrity: sha1-VgauKX8VlHUkvqUaKp71HsG/nDY=
620 | /@turf/nearest-point-to-line/5.1.6:
621 | dependencies:
622 | '@turf/helpers': 6.1.4
623 | '@turf/invariant': 6.1.2
624 | '@turf/meta': 6.0.2
625 | '@turf/point-to-line-distance': 5.1.6
626 | object-assign: 4.1.1
627 | dev: false
628 | resolution:
629 | integrity: sha512-ZSvDIEiHhifn/vNwLXZI/E8xmEz5yBPqfUR7BVHRZrB1cP7jLhKZvkbidjG//uW8Fr1Ulc+PFOXczLspIcx/lw==
630 | /@turf/nearest-point/5.1.5:
631 | dependencies:
632 | '@turf/clone': 5.1.5
633 | '@turf/distance': 5.1.5
634 | '@turf/helpers': 5.1.5
635 | '@turf/meta': 5.1.6
636 | dev: false
637 | resolution:
638 | integrity: sha1-EgUN5Bw5hEMiTHl43g9iE5ANNPs=
639 | /@turf/planepoint/5.1.5:
640 | dependencies:
641 | '@turf/helpers': 5.1.5
642 | '@turf/invariant': 5.1.5
643 | dev: false
644 | resolution:
645 | integrity: sha1-GLvfAG91ne9eQsagBsn53oGyt/8=
646 | /@turf/point-grid/5.1.5:
647 | dependencies:
648 | '@turf/boolean-within': 5.1.5
649 | '@turf/distance': 5.1.5
650 | '@turf/helpers': 5.1.5
651 | '@turf/invariant': 5.1.5
652 | dev: false
653 | resolution:
654 | integrity: sha1-MFFBJI9Quv42zn5mukuX56sjaIc=
655 | /@turf/point-on-feature/5.1.5:
656 | dependencies:
657 | '@turf/boolean-point-in-polygon': 5.1.5
658 | '@turf/center': 5.1.5
659 | '@turf/explode': 5.1.5
660 | '@turf/helpers': 5.1.5
661 | '@turf/nearest-point': 5.1.5
662 | dev: false
663 | resolution:
664 | integrity: sha1-MMfwMkMCd8ZBjZbSieRba/shP+c=
665 | /@turf/point-to-line-distance/5.1.6:
666 | dependencies:
667 | '@turf/bearing': 6.0.1
668 | '@turf/distance': 6.0.1
669 | '@turf/helpers': 6.1.4
670 | '@turf/invariant': 6.1.2
671 | '@turf/meta': 6.0.2
672 | '@turf/projection': 6.0.1
673 | '@turf/rhumb-bearing': 6.0.1
674 | '@turf/rhumb-distance': 6.0.1
675 | dev: false
676 | resolution:
677 | integrity: sha512-PE3hiTeeDEi4ZLPtI8XAzFYW9nHo1EVsZGm/4ZVV8jo39d3X1oLVHxY3e1PkCmWwRapXy4QLqvnTQ7nU4wspNw==
678 | /@turf/points-within-polygon/5.1.5:
679 | dependencies:
680 | '@turf/boolean-point-in-polygon': 5.1.5
681 | '@turf/helpers': 5.1.5
682 | '@turf/meta': 5.1.6
683 | dev: false
684 | resolution:
685 | integrity: sha1-K4VaXfOq2lfC7oIKB1SrlJKKIzc=
686 | /@turf/polygon-tangents/5.1.5:
687 | dependencies:
688 | '@turf/helpers': 5.1.5
689 | '@turf/invariant': 5.1.5
690 | dev: false
691 | resolution:
692 | integrity: sha1-K/AJkUcwJbF44lDcfLmuVAm71lI=
693 | /@turf/polygon-to-line/5.1.5:
694 | dependencies:
695 | '@turf/helpers': 5.1.5
696 | '@turf/invariant': 5.1.5
697 | dev: false
698 | resolution:
699 | integrity: sha1-I7tEjYTcTGUZmaxhGjbZHFklA2o=
700 | /@turf/polygonize/5.1.5:
701 | dependencies:
702 | '@turf/boolean-point-in-polygon': 5.1.5
703 | '@turf/envelope': 5.1.5
704 | '@turf/helpers': 5.1.5
705 | '@turf/invariant': 5.1.5
706 | '@turf/meta': 5.1.6
707 | dev: false
708 | resolution:
709 | integrity: sha1-BJP6EYefOdELmtAs5qI+lC0IqjI=
710 | /@turf/projection/5.1.5:
711 | dependencies:
712 | '@turf/clone': 5.1.5
713 | '@turf/helpers': 5.1.5
714 | '@turf/meta': 5.1.6
715 | dev: false
716 | resolution:
717 | integrity: sha1-JFF+7rLzaBa6n3EueubWo2jt91c=
718 | /@turf/projection/6.0.1:
719 | dependencies:
720 | '@turf/clone': 6.0.2
721 | '@turf/helpers': 6.1.4
722 | '@turf/meta': 6.0.2
723 | dev: false
724 | resolution:
725 | integrity: sha512-Y3RvGT6I53MjYKLG69e9sMk45wJXcLbrEO1t6P3WQQQGqA2gYhhMJyV41vE2Z2llrJpvs2dDx/tIeQzGd0HHMQ==
726 | /@turf/random/5.1.5:
727 | dependencies:
728 | '@turf/helpers': 5.1.5
729 | dev: false
730 | resolution:
731 | integrity: sha1-sy78k0Vgroulfo67UfJBw5+6Lns=
732 | /@turf/rewind/5.1.5:
733 | dependencies:
734 | '@turf/boolean-clockwise': 5.1.5
735 | '@turf/clone': 5.1.5
736 | '@turf/helpers': 5.1.5
737 | '@turf/invariant': 5.1.5
738 | '@turf/meta': 5.1.6
739 | dev: false
740 | resolution:
741 | integrity: sha1-nqPbSmi3PB/R3RH1djGxQ8/vock=
742 | /@turf/rhumb-bearing/5.1.5:
743 | dependencies:
744 | '@turf/helpers': 5.1.5
745 | '@turf/invariant': 5.1.5
746 | dev: false
747 | resolution:
748 | integrity: sha1-rPalAkJ+uMSeGM2mrg7/qwxd3NI=
749 | /@turf/rhumb-bearing/6.0.1:
750 | dependencies:
751 | '@turf/helpers': 6.1.4
752 | '@turf/invariant': 6.1.2
753 | dev: false
754 | resolution:
755 | integrity: sha512-MVBra8OVfjM4+/N0B3o6cBIYg9p/uRKzA9uk05RfrzasEbUL1vdD23LkTooVL74Yw4UxL8BQD9hS5Re2COJFDA==
756 | /@turf/rhumb-destination/5.1.5:
757 | dependencies:
758 | '@turf/helpers': 5.1.5
759 | '@turf/invariant': 5.1.5
760 | dev: false
761 | resolution:
762 | integrity: sha1-sbKuuSFUfyrAwamUtqEw+SRjx0I=
763 | /@turf/rhumb-distance/5.1.5:
764 | dependencies:
765 | '@turf/helpers': 5.1.5
766 | '@turf/invariant': 5.1.5
767 | dev: false
768 | resolution:
769 | integrity: sha1-GAaFdiX0IlOE2tQT5p85U4/192U=
770 | /@turf/rhumb-distance/6.0.1:
771 | dependencies:
772 | '@turf/helpers': 6.1.4
773 | '@turf/invariant': 6.1.2
774 | dev: false
775 | resolution:
776 | integrity: sha512-3G45DQtQByzzfHFPcCyJdUZFwsd45zfZ7sAb1ddF7mhEj4G70+T2G3GKjInymqDNrbyh2gbG6wQiZSToC8Uf9g==
777 | /@turf/sample/5.1.5:
778 | dependencies:
779 | '@turf/helpers': 5.1.5
780 | dev: false
781 | resolution:
782 | integrity: sha1-6ctEikeJzFbuPeLdZ4HiNDQ1tBE=
783 | /@turf/sector/5.1.5:
784 | dependencies:
785 | '@turf/circle': 5.1.5
786 | '@turf/helpers': 5.1.5
787 | '@turf/invariant': 5.1.5
788 | '@turf/line-arc': 5.1.5
789 | '@turf/meta': 5.1.6
790 | dev: false
791 | resolution:
792 | integrity: sha1-rCu5TBPt1gNPb9wrZwCBNdIPXgc=
793 | /@turf/shortest-path/5.1.5:
794 | dependencies:
795 | '@turf/bbox': 5.1.5
796 | '@turf/bbox-polygon': 5.1.5
797 | '@turf/boolean-point-in-polygon': 5.1.5
798 | '@turf/clean-coords': 5.1.5
799 | '@turf/distance': 5.1.5
800 | '@turf/helpers': 5.1.5
801 | '@turf/invariant': 5.1.5
802 | '@turf/meta': 5.1.6
803 | '@turf/transform-scale': 5.1.5
804 | dev: false
805 | resolution:
806 | integrity: sha1-hUroCW9rw+EwD6ynfz6PZ9j5Nas=
807 | /@turf/simplify/5.1.5:
808 | dependencies:
809 | '@turf/clean-coords': 5.1.5
810 | '@turf/clone': 5.1.5
811 | '@turf/helpers': 5.1.5
812 | '@turf/meta': 5.1.6
813 | dev: false
814 | resolution:
815 | integrity: sha1-Csjyei60IYGD7dmZjDJ1q+QIuSY=
816 | /@turf/square-grid/5.1.5:
817 | dependencies:
818 | '@turf/boolean-contains': 5.1.5
819 | '@turf/boolean-overlap': 5.1.5
820 | '@turf/distance': 5.1.5
821 | '@turf/helpers': 5.1.5
822 | '@turf/intersect': 5.1.6
823 | '@turf/invariant': 5.1.5
824 | dev: false
825 | resolution:
826 | integrity: sha1-G9X3uesU8LYLwjH+/nNR0aMvGlE=
827 | /@turf/square/5.1.5:
828 | dependencies:
829 | '@turf/distance': 5.1.5
830 | '@turf/helpers': 5.1.5
831 | dev: false
832 | resolution:
833 | integrity: sha1-qnsh5gM8ySUsOlvW89iNq9b+0YA=
834 | /@turf/standard-deviational-ellipse/5.1.5:
835 | dependencies:
836 | '@turf/center-mean': 5.1.5
837 | '@turf/ellipse': 5.1.5
838 | '@turf/helpers': 5.1.5
839 | '@turf/invariant': 5.1.5
840 | '@turf/meta': 5.1.6
841 | '@turf/points-within-polygon': 5.1.5
842 | dev: false
843 | resolution:
844 | integrity: sha1-hc0oO14ayljyG9ZkEuQUtW2FIyQ=
845 | /@turf/tag/5.1.5:
846 | dependencies:
847 | '@turf/boolean-point-in-polygon': 5.1.5
848 | '@turf/clone': 5.1.5
849 | '@turf/helpers': 5.1.5
850 | '@turf/meta': 5.1.6
851 | dev: false
852 | resolution:
853 | integrity: sha1-0e4aUIjs/UoUEQGcmCOczypJfSA=
854 | /@turf/tesselate/5.1.5:
855 | dependencies:
856 | '@turf/helpers': 5.1.5
857 | earcut: 2.2.2
858 | dev: false
859 | resolution:
860 | integrity: sha1-MqWU6cIaAEIKn5DSxD3z4RZgYc0=
861 | /@turf/tin/5.1.5:
862 | dependencies:
863 | '@turf/helpers': 5.1.5
864 | dev: false
865 | resolution:
866 | integrity: sha1-KCI+r8X76a6azKgc3P6l0UJMkX0=
867 | /@turf/transform-rotate/5.1.5:
868 | dependencies:
869 | '@turf/centroid': 5.1.5
870 | '@turf/clone': 5.1.5
871 | '@turf/helpers': 5.1.5
872 | '@turf/invariant': 5.1.5
873 | '@turf/meta': 5.1.6
874 | '@turf/rhumb-bearing': 5.1.5
875 | '@turf/rhumb-destination': 5.1.5
876 | '@turf/rhumb-distance': 5.1.5
877 | dev: false
878 | resolution:
879 | integrity: sha1-0Jbt2eMA/jFQadVNjkWMQJIh7fs=
880 | /@turf/transform-scale/5.1.5:
881 | dependencies:
882 | '@turf/bbox': 5.1.5
883 | '@turf/center': 5.1.5
884 | '@turf/centroid': 5.1.5
885 | '@turf/clone': 5.1.5
886 | '@turf/helpers': 5.1.5
887 | '@turf/invariant': 5.1.5
888 | '@turf/meta': 5.1.6
889 | '@turf/rhumb-bearing': 5.1.5
890 | '@turf/rhumb-destination': 5.1.5
891 | '@turf/rhumb-distance': 5.1.5
892 | dev: false
893 | resolution:
894 | integrity: sha1-cP064BhWz3uunxWtVhzf6PiQAbk=
895 | /@turf/transform-translate/5.1.5:
896 | dependencies:
897 | '@turf/clone': 5.1.5
898 | '@turf/helpers': 5.1.5
899 | '@turf/invariant': 5.1.5
900 | '@turf/meta': 5.1.6
901 | '@turf/rhumb-destination': 5.1.5
902 | dev: false
903 | resolution:
904 | integrity: sha1-Uwolf7Hccmja3Ks05nkB6yo97GM=
905 | /@turf/triangle-grid/5.1.5:
906 | dependencies:
907 | '@turf/distance': 5.1.5
908 | '@turf/helpers': 5.1.5
909 | '@turf/intersect': 5.1.6
910 | '@turf/invariant': 5.1.5
911 | dev: false
912 | resolution:
913 | integrity: sha1-ezZ2IQhVTBTyjK/zxIsc/ILI3IE=
914 | /@turf/truncate/5.1.5:
915 | dependencies:
916 | '@turf/helpers': 5.1.5
917 | '@turf/meta': 5.1.6
918 | dev: false
919 | resolution:
920 | integrity: sha1-nu37Oxi6gfLJjT6tCUMcyhiErYk=
921 | /@turf/turf/5.1.6:
922 | dependencies:
923 | '@turf/along': 5.1.5
924 | '@turf/area': 5.1.5
925 | '@turf/bbox': 5.1.5
926 | '@turf/bbox-clip': 5.1.5
927 | '@turf/bbox-polygon': 5.1.5
928 | '@turf/bearing': 5.1.5
929 | '@turf/bezier-spline': 5.1.5
930 | '@turf/boolean-clockwise': 5.1.5
931 | '@turf/boolean-contains': 5.1.5
932 | '@turf/boolean-crosses': 5.1.5
933 | '@turf/boolean-disjoint': 5.1.6
934 | '@turf/boolean-equal': 5.1.5
935 | '@turf/boolean-overlap': 5.1.5
936 | '@turf/boolean-parallel': 5.1.5
937 | '@turf/boolean-point-in-polygon': 5.1.5
938 | '@turf/boolean-point-on-line': 5.1.5
939 | '@turf/boolean-within': 5.1.5
940 | '@turf/buffer': 5.1.5
941 | '@turf/center': 5.1.5
942 | '@turf/center-mean': 5.1.5
943 | '@turf/center-median': 5.1.5
944 | '@turf/center-of-mass': 5.1.5
945 | '@turf/centroid': 5.1.5
946 | '@turf/circle': 5.1.5
947 | '@turf/clean-coords': 5.1.5
948 | '@turf/clone': 5.1.5
949 | '@turf/clusters': 5.1.5
950 | '@turf/clusters-dbscan': 5.1.5
951 | '@turf/clusters-kmeans': 5.1.5
952 | '@turf/collect': 5.1.5
953 | '@turf/combine': 5.1.5
954 | '@turf/concave': 5.1.5
955 | '@turf/convex': 5.1.5
956 | '@turf/destination': 5.1.5
957 | '@turf/difference': 5.1.5
958 | '@turf/dissolve': 5.1.5
959 | '@turf/distance': 5.1.5
960 | '@turf/ellipse': 5.1.5
961 | '@turf/envelope': 5.1.5
962 | '@turf/explode': 5.1.5
963 | '@turf/flatten': 5.1.5
964 | '@turf/flip': 5.1.5
965 | '@turf/great-circle': 5.1.5
966 | '@turf/helpers': 5.1.5
967 | '@turf/hex-grid': 5.1.5
968 | '@turf/interpolate': 5.1.5
969 | '@turf/intersect': 5.1.6
970 | '@turf/invariant': 5.1.5
971 | '@turf/isobands': 5.1.5
972 | '@turf/isolines': 5.1.5
973 | '@turf/kinks': 5.1.5
974 | '@turf/length': 5.1.5
975 | '@turf/line-arc': 5.1.5
976 | '@turf/line-chunk': 5.1.5
977 | '@turf/line-intersect': 5.1.5
978 | '@turf/line-offset': 5.1.5
979 | '@turf/line-overlap': 5.1.5
980 | '@turf/line-segment': 5.1.5
981 | '@turf/line-slice': 5.1.5
982 | '@turf/line-slice-along': 5.1.5
983 | '@turf/line-split': 5.1.5
984 | '@turf/line-to-polygon': 5.1.5
985 | '@turf/mask': 5.1.5
986 | '@turf/meta': 5.1.6
987 | '@turf/midpoint': 5.1.5
988 | '@turf/nearest-point': 5.1.5
989 | '@turf/nearest-point-on-line': 5.1.5
990 | '@turf/nearest-point-to-line': 5.1.6
991 | '@turf/planepoint': 5.1.5
992 | '@turf/point-grid': 5.1.5
993 | '@turf/point-on-feature': 5.1.5
994 | '@turf/point-to-line-distance': 5.1.6
995 | '@turf/points-within-polygon': 5.1.5
996 | '@turf/polygon-tangents': 5.1.5
997 | '@turf/polygon-to-line': 5.1.5
998 | '@turf/polygonize': 5.1.5
999 | '@turf/projection': 5.1.5
1000 | '@turf/random': 5.1.5
1001 | '@turf/rewind': 5.1.5
1002 | '@turf/rhumb-bearing': 5.1.5
1003 | '@turf/rhumb-destination': 5.1.5
1004 | '@turf/rhumb-distance': 5.1.5
1005 | '@turf/sample': 5.1.5
1006 | '@turf/sector': 5.1.5
1007 | '@turf/shortest-path': 5.1.5
1008 | '@turf/simplify': 5.1.5
1009 | '@turf/square': 5.1.5
1010 | '@turf/square-grid': 5.1.5
1011 | '@turf/standard-deviational-ellipse': 5.1.5
1012 | '@turf/tag': 5.1.5
1013 | '@turf/tesselate': 5.1.5
1014 | '@turf/tin': 5.1.5
1015 | '@turf/transform-rotate': 5.1.5
1016 | '@turf/transform-scale': 5.1.5
1017 | '@turf/transform-translate': 5.1.5
1018 | '@turf/triangle-grid': 5.1.5
1019 | '@turf/truncate': 5.1.5
1020 | '@turf/union': 5.1.5
1021 | '@turf/unkink-polygon': 5.1.5
1022 | '@turf/voronoi': 5.1.5
1023 | dev: false
1024 | resolution:
1025 | integrity: sha1-wxIlkoh+0jS3VGi4qMRb+Ib7+PY=
1026 | /@turf/union/5.1.5:
1027 | dependencies:
1028 | '@turf/helpers': 5.1.5
1029 | turf-jsts: 1.2.3
1030 | dev: false
1031 | resolution:
1032 | integrity: sha1-UyhbYJQEf8WNlqrA6pCGXsNNRUs=
1033 | /@turf/unkink-polygon/5.1.5:
1034 | dependencies:
1035 | '@turf/area': 5.1.5
1036 | '@turf/boolean-point-in-polygon': 5.1.5
1037 | '@turf/helpers': 5.1.5
1038 | '@turf/meta': 5.1.6
1039 | rbush: 2.0.2
1040 | dev: false
1041 | resolution:
1042 | integrity: sha1-ewGEfFD7V0riV54Z5Ey6hSbSE8M=
1043 | /@turf/voronoi/5.1.5:
1044 | dependencies:
1045 | '@turf/helpers': 5.1.5
1046 | '@turf/invariant': 5.1.5
1047 | d3-voronoi: 1.1.2
1048 | dev: false
1049 | resolution:
1050 | integrity: sha1-6FbpQG3MLyXWbdyJhYTifC6/ymY=
1051 | /call-bind/1.0.0:
1052 | dependencies:
1053 | function-bind: 1.1.1
1054 | get-intrinsic: 1.0.1
1055 | dev: false
1056 | resolution:
1057 | integrity: sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==
1058 | /commander/2.20.3:
1059 | dev: false
1060 | resolution:
1061 | integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
1062 | /concaveman/1.2.0:
1063 | dependencies:
1064 | point-in-polygon: 1.0.1
1065 | rbush: 3.0.1
1066 | robust-predicates: 2.0.4
1067 | tinyqueue: 2.0.3
1068 | dev: false
1069 | resolution:
1070 | integrity: sha512-OcqechF2/kubbffomKqjGEkb0ndlYhEbmyg/fxIGqdfYp5AZjD2Kl5hc97Hh3ngEuHU2314Z4KDbxL7qXGWrQQ==
1071 | /d3-array/1.2.4:
1072 | dev: false
1073 | resolution:
1074 | integrity: sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==
1075 | /d3-dsv/2.0.0:
1076 | dependencies:
1077 | commander: 2.20.3
1078 | iconv-lite: 0.4.24
1079 | rw: 1.3.3
1080 | dev: false
1081 | hasBin: true
1082 | resolution:
1083 | integrity: sha512-E+Pn8UJYx9mViuIUkoc93gJGGYut6mSDKy2+XaPwccwkRGlR+LO97L2VCCRjQivTwLHkSnAJG7yo00BWY6QM+w==
1084 | /d3-geo/1.7.1:
1085 | dependencies:
1086 | d3-array: 1.2.4
1087 | dev: false
1088 | resolution:
1089 | integrity: sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw==
1090 | /d3-voronoi/1.1.2:
1091 | dev: false
1092 | resolution:
1093 | integrity: sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=
1094 | /deep-equal/1.1.1:
1095 | dependencies:
1096 | is-arguments: 1.0.4
1097 | is-date-object: 1.0.2
1098 | is-regex: 1.1.1
1099 | object-is: 1.1.3
1100 | object-keys: 1.1.1
1101 | regexp.prototype.flags: 1.3.0
1102 | dev: false
1103 | resolution:
1104 | integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
1105 | /define-properties/1.1.3:
1106 | dependencies:
1107 | object-keys: 1.1.1
1108 | dev: false
1109 | engines:
1110 | node: '>= 0.4'
1111 | resolution:
1112 | integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
1113 | /density-clustering/1.3.0:
1114 | dev: false
1115 | resolution:
1116 | integrity: sha1-3J9ZyPCrl+FiSsZJMP0xlIF9ysU=
1117 | /earcut/2.2.2:
1118 | dev: false
1119 | resolution:
1120 | integrity: sha512-eZoZPPJcUHnfRZ0PjLvx2qBordSiO8ofC3vt+qACLM95u+4DovnbYNpQtJh0DNsWj8RnxrQytD4WA8gj5cRIaQ==
1121 | /es-abstract/1.17.7:
1122 | dependencies:
1123 | es-to-primitive: 1.2.1
1124 | function-bind: 1.1.1
1125 | has: 1.0.3
1126 | has-symbols: 1.0.1
1127 | is-callable: 1.2.2
1128 | is-regex: 1.1.1
1129 | object-inspect: 1.8.0
1130 | object-keys: 1.1.1
1131 | object.assign: 4.1.2
1132 | string.prototype.trimend: 1.0.2
1133 | string.prototype.trimstart: 1.0.2
1134 | dev: false
1135 | engines:
1136 | node: '>= 0.4'
1137 | resolution:
1138 | integrity: sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==
1139 | /es-abstract/1.18.0-next.1:
1140 | dependencies:
1141 | es-to-primitive: 1.2.1
1142 | function-bind: 1.1.1
1143 | has: 1.0.3
1144 | has-symbols: 1.0.1
1145 | is-callable: 1.2.2
1146 | is-negative-zero: 2.0.0
1147 | is-regex: 1.1.1
1148 | object-inspect: 1.8.0
1149 | object-keys: 1.1.1
1150 | object.assign: 4.1.2
1151 | string.prototype.trimend: 1.0.2
1152 | string.prototype.trimstart: 1.0.2
1153 | dev: false
1154 | engines:
1155 | node: '>= 0.4'
1156 | resolution:
1157 | integrity: sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
1158 | /es-to-primitive/1.2.1:
1159 | dependencies:
1160 | is-callable: 1.2.2
1161 | is-date-object: 1.0.2
1162 | is-symbol: 1.0.3
1163 | dev: false
1164 | engines:
1165 | node: '>= 0.4'
1166 | resolution:
1167 | integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
1168 | /function-bind/1.1.1:
1169 | dev: false
1170 | resolution:
1171 | integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
1172 | /geojson-equality/0.1.6:
1173 | dependencies:
1174 | deep-equal: 1.1.1
1175 | dev: false
1176 | resolution:
1177 | integrity: sha1-oXE3TvBD5dR5eZWEC65GSOB1LXI=
1178 | /geojson-rbush/2.1.0:
1179 | dependencies:
1180 | '@turf/helpers': 6.1.4
1181 | '@turf/meta': 6.0.2
1182 | rbush: 3.0.1
1183 | dev: false
1184 | resolution:
1185 | integrity: sha1-O9c745H8ELCuaT2bis6iquC4Oo0=
1186 | /get-closest/0.0.4:
1187 | dev: false
1188 | resolution:
1189 | integrity: sha1-JprHdtHmAiqg/Vht1wjop9Miaa8=
1190 | /get-intrinsic/1.0.1:
1191 | dependencies:
1192 | function-bind: 1.1.1
1193 | has: 1.0.3
1194 | has-symbols: 1.0.1
1195 | dev: false
1196 | resolution:
1197 | integrity: sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==
1198 | /has-symbols/1.0.1:
1199 | dev: false
1200 | engines:
1201 | node: '>= 0.4'
1202 | resolution:
1203 | integrity: sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
1204 | /has/1.0.3:
1205 | dependencies:
1206 | function-bind: 1.1.1
1207 | dev: false
1208 | engines:
1209 | node: '>= 0.4.0'
1210 | resolution:
1211 | integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
1212 | /iconv-lite/0.4.24:
1213 | dependencies:
1214 | safer-buffer: 2.1.2
1215 | dev: false
1216 | engines:
1217 | node: '>=0.10.0'
1218 | resolution:
1219 | integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
1220 | /is-arguments/1.0.4:
1221 | dev: false
1222 | engines:
1223 | node: '>= 0.4'
1224 | resolution:
1225 | integrity: sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
1226 | /is-callable/1.2.2:
1227 | dev: false
1228 | engines:
1229 | node: '>= 0.4'
1230 | resolution:
1231 | integrity: sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
1232 | /is-date-object/1.0.2:
1233 | dev: false
1234 | engines:
1235 | node: '>= 0.4'
1236 | resolution:
1237 | integrity: sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
1238 | /is-negative-zero/2.0.0:
1239 | dev: false
1240 | engines:
1241 | node: '>= 0.4'
1242 | resolution:
1243 | integrity: sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=
1244 | /is-regex/1.1.1:
1245 | dependencies:
1246 | has-symbols: 1.0.1
1247 | dev: false
1248 | engines:
1249 | node: '>= 0.4'
1250 | resolution:
1251 | integrity: sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
1252 | /is-symbol/1.0.3:
1253 | dependencies:
1254 | has-symbols: 1.0.1
1255 | dev: false
1256 | engines:
1257 | node: '>= 0.4'
1258 | resolution:
1259 | integrity: sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
1260 | /lineclip/1.1.5:
1261 | dev: false
1262 | resolution:
1263 | integrity: sha1-K/JgZ9lDVP6r+R5CdoI221YW/RM=
1264 | /object-assign/4.1.1:
1265 | dev: false
1266 | engines:
1267 | node: '>=0.10.0'
1268 | resolution:
1269 | integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
1270 | /object-inspect/1.8.0:
1271 | dev: false
1272 | resolution:
1273 | integrity: sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
1274 | /object-is/1.1.3:
1275 | dependencies:
1276 | define-properties: 1.1.3
1277 | es-abstract: 1.18.0-next.1
1278 | dev: false
1279 | engines:
1280 | node: '>= 0.4'
1281 | resolution:
1282 | integrity: sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==
1283 | /object-keys/1.1.1:
1284 | dev: false
1285 | engines:
1286 | node: '>= 0.4'
1287 | resolution:
1288 | integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
1289 | /object.assign/4.1.2:
1290 | dependencies:
1291 | call-bind: 1.0.0
1292 | define-properties: 1.1.3
1293 | has-symbols: 1.0.1
1294 | object-keys: 1.1.1
1295 | dev: false
1296 | engines:
1297 | node: '>= 0.4'
1298 | resolution:
1299 | integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
1300 | /point-in-polygon/1.0.1:
1301 | dev: false
1302 | resolution:
1303 | integrity: sha1-1Ztk6P7kHElFiqyCtWcYxZV7Kvc=
1304 | /quickselect/1.1.1:
1305 | dev: false
1306 | resolution:
1307 | integrity: sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==
1308 | /quickselect/2.0.0:
1309 | dev: false
1310 | resolution:
1311 | integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
1312 | /rbush/2.0.2:
1313 | dependencies:
1314 | quickselect: 1.1.1
1315 | dev: false
1316 | resolution:
1317 | integrity: sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==
1318 | /rbush/3.0.1:
1319 | dependencies:
1320 | quickselect: 2.0.0
1321 | dev: false
1322 | resolution:
1323 | integrity: sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==
1324 | /regexp.prototype.flags/1.3.0:
1325 | dependencies:
1326 | define-properties: 1.1.3
1327 | es-abstract: 1.17.7
1328 | dev: false
1329 | engines:
1330 | node: '>= 0.4'
1331 | resolution:
1332 | integrity: sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
1333 | /robust-predicates/2.0.4:
1334 | dev: false
1335 | resolution:
1336 | integrity: sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==
1337 | /rw/1.3.3:
1338 | dev: false
1339 | resolution:
1340 | integrity: sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=
1341 | /safer-buffer/2.1.2:
1342 | dev: false
1343 | resolution:
1344 | integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
1345 | /skmeans/0.9.7:
1346 | dev: false
1347 | resolution:
1348 | integrity: sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg==
1349 | /string.prototype.trimend/1.0.2:
1350 | dependencies:
1351 | define-properties: 1.1.3
1352 | es-abstract: 1.18.0-next.1
1353 | dev: false
1354 | resolution:
1355 | integrity: sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==
1356 | /string.prototype.trimstart/1.0.2:
1357 | dependencies:
1358 | define-properties: 1.1.3
1359 | es-abstract: 1.18.0-next.1
1360 | dev: false
1361 | resolution:
1362 | integrity: sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==
1363 | /tinyqueue/2.0.3:
1364 | dev: false
1365 | resolution:
1366 | integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
1367 | /topojson-client/3.1.0:
1368 | dependencies:
1369 | commander: 2.20.3
1370 | dev: false
1371 | hasBin: true
1372 | resolution:
1373 | integrity: sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==
1374 | /topojson-server/3.0.1:
1375 | dependencies:
1376 | commander: 2.20.3
1377 | dev: false
1378 | hasBin: true
1379 | resolution:
1380 | integrity: sha512-/VS9j/ffKr2XAOjlZ9CgyyeLmgJ9dMwq6Y0YEON8O7p/tGGk+dCWnrE03zEdu7i4L7YsFZLEPZPzCvcB7lEEXw==
1381 | /turf-jsts/1.2.3:
1382 | dev: false
1383 | resolution:
1384 | integrity: sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA==
1385 | specifiers:
1386 | '@turf/turf': ^5.1.6
1387 | d3-dsv: ^2.0.0
1388 | topojson-client: ^3.1.0
1389 | topojson-server: ^3.0.1
1390 |
--------------------------------------------------------------------------------
/skeleton/.eslintrc.js:
--------------------------------------------------------------------------------
1 | const jsRules = {
2 | 'no-unused-vars': ['warn', { args: 'none' }],
3 | 'no-return-await': 'warn',
4 | 'no-use-before-define': 'error',
5 | 'no-mixed-spaces-and-tabs': 'error',
6 | 'no-trailing-spaces': 'warn',
7 | };
8 |
9 | module.exports = {
10 | env: {
11 | browser: true,
12 | es6: true,
13 | node: true,
14 | },
15 | parser: '@typescript-eslint/parser',
16 | parserOptions: {
17 | project: 'tsconfig.json',
18 | ecmaVersion: 2019,
19 | sourceType: 'module',
20 | },
21 | overrides: [
22 | {
23 | files: ['**/*.svelte'],
24 | parser: 'espree',
25 | processor: 'svelte3/svelte3',
26 | extends: ['eslint:recommended'],
27 | rules: jsRules,
28 | },
29 | {
30 | files: ['**/*.js'],
31 | extends: ['eslint:recommended'],
32 | rules: jsRules,
33 | },
34 | ],
35 | plugins: ['@typescript-eslint/eslint-plugin', 'svelte3'],
36 | extends: [
37 | 'plugin:@typescript-eslint/eslint-recommended',
38 | 'prettier/@typescript-eslint',
39 | ],
40 | rules: {},
41 | };
42 |
--------------------------------------------------------------------------------
/skeleton/.gitignore:
--------------------------------------------------------------------------------
1 | public
2 | public/bundle.*
3 | public/utils.*
4 | build
5 | ### Node ###
6 | # Logs
7 | logs
8 | *.log
9 | npm-debug.log*
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 | *.pid.lock
16 |
17 | # node-waf configuration
18 | .lock-wscript
19 |
20 | # Compiled binary addons (http://nodejs.org/api/addons.html)
21 | build/Release
22 |
23 | # Dependency directories
24 | node_modules
25 | jspm_packages
26 |
27 | # Optional npm cache directory
28 | .npm
29 |
30 | # Optional eslint cache
31 | .eslintcache
32 |
33 | # Optional REPL history
34 | .node_repl_history
35 |
36 | # Output of 'npm pack'
37 | *.tgz
38 |
39 | ### Git ###
40 | *.orig
41 |
42 | ### macOS ###
43 | .DS_Store
44 | .AppleDouble
45 | .LSOverride
46 |
47 | # Thumbnails
48 | ._*
49 | # Files that might appear in the root of a volume
50 | .DocumentRevisions-V100
51 | .fseventsd
52 | .Spotlight-V100
53 | .TemporaryItems
54 | .Trashes
55 | .VolumeIcon.icns
56 | .com.apple.timemachine.donotpresent
57 | # Directories potentially created on remote AFP share
58 | .AppleDB
59 | .AppleDesktop
60 | Network Trash Folder
61 | Temporary Items
62 | .apdisk
63 |
--------------------------------------------------------------------------------
/skeleton/.prettierignore:
--------------------------------------------------------------------------------
1 | .git/*
2 | .DS_Store
3 |
4 | license
5 | yarn.lock
6 | .travis.yml
7 |
8 | .yarnclean
9 | .eslintignore
10 | .prettierignore
11 | .npmignore
12 | .gitignore
13 | .dockerignore
14 |
15 | dist
16 | build
17 | packages/*/lib/app
18 | consoles/*/lib/app
19 |
20 | *.ico
21 | *.html
22 | *.log
23 | *.svg
24 | *.map
25 | *.png
26 | *.snap
27 | *.ttf
28 | *.sh
29 | *.txt
--------------------------------------------------------------------------------
/skeleton/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5",
4 | "arrowParens": "always"
5 | }
6 |
--------------------------------------------------------------------------------
/skeleton/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Daniel Imfeld
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/skeleton/README.md:
--------------------------------------------------------------------------------
1 | This is the skeleton version of the Svelte Leaflet demo application. All the map components and data loading are provided, but the application itself needs to be filled in.
2 |
3 | To run:
4 |
5 | 1. Install dependencies with yarn, npm, pnpm, etc.
6 | 2. `npm run dev` to start the Snowpack development server.
7 |
--------------------------------------------------------------------------------
/skeleton/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-leaflet-demo",
3 | "author": "Daniel Imfeld",
4 | "license": "MIT",
5 | "version": "0.0.2",
6 | "scripts": {
7 | "clean": "rimraf public",
8 | "rollup": "rollup -c",
9 | "rollup:watch": "rollup -c -w",
10 | "copy-snowpack-templates": "copyfiles -u 1 snowpack/* public",
11 | "build": "NODE_ENV=production run-s clean rollup",
12 | "dev": "npm-run-all clean copy-snowpack-templates start:snowpack",
13 | "dev:rollup": "NODE_ENV=development npm-run-all clean --parallel start:dev rollup:watch",
14 | "start": "sirv public --single -H 0.0.0.0",
15 | "start:dev": "NODE_ENV=development sirv public --single --dev -H 0.0.0.0",
16 | "start:snowpack": "NODE_ENV=development snowpack dev"
17 | },
18 | "dependencies": {
19 | "@elfalem/leaflet-curve": "^0.6.0",
20 | "d3-scale": "^3.2.3",
21 | "just-flush": "^1.1.0",
22 | "leaflet": "~1.6",
23 | "sirv-cli": "^0.4.4"
24 | },
25 | "devDependencies": {
26 | "@babel/core": "^7.10.0",
27 | "@babel/plugin-proposal-class-properties": "^7.8.3",
28 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
29 | "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
30 | "@babel/plugin-proposal-optional-chaining": "^7.8.3",
31 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
32 | "@babel/plugin-transform-runtime": "^7.9.0",
33 | "@babel/preset-env": "^7.10.0",
34 | "@babel/preset-typescript": "^7.9.0",
35 | "@babel/runtime": "^7.10.0",
36 | "@fullhuman/postcss-purgecss": "^3.0.0",
37 | "@rollup/plugin-babel": "^5.0.3",
38 | "@rollup/plugin-commonjs": "^15.0.0",
39 | "@rollup/plugin-html": "^0.2.0",
40 | "@rollup/plugin-json": "^4.1.0",
41 | "@rollup/plugin-node-resolve": "^8.1.0",
42 | "@rollup/plugin-replace": "^2.3.3",
43 | "@snowpack/app-scripts-svelte": "^1.9.2",
44 | "@snowpack/plugin-postcss": "^1.0.7",
45 | "@tailwindcss/ui": "^0.6.2",
46 | "@types/d3-scale": "^3.2.1",
47 | "@types/leaflet": "^1.5.19",
48 | "@types/topojson-client": "^3.0.0",
49 | "@typescript-eslint/eslint-plugin": "^2.26.0",
50 | "@typescript-eslint/parser": "^2.26.0",
51 | "autoprefixer": "^9",
52 | "babel-eslint": "^10.0.3",
53 | "copyfiles": "^2.4.0",
54 | "cssnano": "^4.1.10",
55 | "eslint": "^6.8.0",
56 | "eslint-config-prettier": "^6.10.1",
57 | "eslint-plugin-svelte3": "^2.7.3",
58 | "lodash.template": "^4.5.0",
59 | "npm-run-all": "^4.1.5",
60 | "postcss": "^7",
61 | "postcss-cli": "^6.1.3",
62 | "postcss-import": "^12.0.1",
63 | "prettier": "^2",
64 | "prettier-plugin-svelte": "^1",
65 | "rimraf": "^3.0.2",
66 | "rollup": "^2.10.0",
67 | "rollup-plugin-copy": "^3.3.0",
68 | "rollup-plugin-livereload": "^2.0.0",
69 | "rollup-plugin-postcss": "^3.0.0",
70 | "rollup-plugin-svelte": "^6",
71 | "rollup-plugin-terser": "^7.0.0",
72 | "snowpack": "^2.16.1",
73 | "svelte": "^3.29.4",
74 | "svelte-preprocess": "^4.5.2",
75 | "tailwindcss": "^1.9.0",
76 | "typescript": "^4.0.5"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/skeleton/postcss.config.js:
--------------------------------------------------------------------------------
1 | const production = process.env.NODE_ENV !== 'development';
2 | const purgecss = require('@fullhuman/postcss-purgecss');
3 | const cssnano = require('cssnano');
4 |
5 | module.exports = {
6 | plugins: [
7 | require('postcss-import')(),
8 | require('tailwindcss'),
9 | require('autoprefixer'),
10 | production &&
11 | purgecss({
12 | content: ['./src/**/*.html', './static/**/*.html', './src/**/*.svelte'],
13 | whitelistPatterns: [/^svelte-/],
14 | defaultExtractor: (content) => {
15 | const regExp = new RegExp(/[A-Za-z0-9-_:/.]+/g);
16 |
17 | const matchedTokens = [];
18 |
19 | let match = regExp.exec(content);
20 | // To make sure that you do not lose any tailwind classes used in class directive.
21 | // https://github.com/tailwindcss/discuss/issues/254#issuecomment-517918397
22 | while (match) {
23 | if (match[0].startsWith('class:')) {
24 | matchedTokens.push(match[0].substring(6));
25 | } else {
26 | matchedTokens.push(match[0]);
27 | }
28 |
29 | match = regExp.exec(content);
30 | }
31 |
32 | return matchedTokens;
33 | },
34 | }),
35 | production && cssnano(),
36 | ].filter(Boolean),
37 | };
38 |
--------------------------------------------------------------------------------
/skeleton/rollup.config.js:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs';
2 | import template from 'lodash.template';
3 | import svelte from 'rollup-plugin-svelte';
4 | import resolve from '@rollup/plugin-node-resolve';
5 | import replace from '@rollup/plugin-replace';
6 | import commonjs from '@rollup/plugin-commonjs';
7 | import livereload from 'rollup-plugin-livereload';
8 | import { terser } from 'rollup-plugin-terser';
9 | import postcss from 'rollup-plugin-postcss';
10 | import babel from '@rollup/plugin-babel';
11 | import json from '@rollup/plugin-json';
12 | import html, { makeHtmlAttributes } from '@rollup/plugin-html';
13 | import copy from 'rollup-plugin-copy';
14 |
15 | const production = process.env.NODE_ENV !== 'development';
16 |
17 | const babelConfig = {
18 | extensions: ['.js', '.mjs', '.html', '.svelte', '.ts'],
19 | babelHelpers: 'bundled',
20 | exclude: ['node_modules/@babel/**', 'static/**', 'build/**', 'public/**'],
21 | presets: [
22 | ['@babel/preset-env', { targets: { esmodules: true } }],
23 | '@babel/preset-typescript',
24 | ],
25 | plugins: [
26 | '@babel/plugin-syntax-dynamic-import',
27 | '@babel/proposal-class-properties',
28 | '@babel/plugin-proposal-object-rest-spread',
29 | '@babel/plugin-proposal-nullish-coalescing-operator',
30 | '@babel/plugin-proposal-optional-chaining',
31 | ],
32 | };
33 |
34 | export default {
35 | input: 'src/index.js',
36 | output: {
37 | dir: 'public',
38 | entryFileNames: '[name].[hash].js',
39 | chunkFileNames: '[name].[hash].js',
40 | assetFileNames: '[name].[hash][extname]',
41 | sourcemap: production ? true : 'inline',
42 | format: 'esm',
43 | manualChunks(id) {
44 | if (id.includes('node_modules')) {
45 | return 'vendor';
46 | } else if (id.endsWith('.json')) {
47 | return 'data';
48 | }
49 | },
50 | },
51 | plugins: [
52 | svelte({
53 | preprocess: require('./svelte.config').preprocess,
54 | // enable run-time checks when not in production
55 | dev: !production,
56 | // extract any component CSS out into
57 | // a separate file — better for performance
58 | // css: css => {
59 | // css.write('public/bundle.css');
60 | // },
61 | // Instead, emit CSS as a file for processing through rollup
62 | emitCss: true,
63 | }),
64 | postcss({
65 | extract: true,
66 | }),
67 |
68 | resolve({
69 | mainFields: ['module', 'browser', 'main'],
70 | extensions: ['.mjs', '.js', '.json', '.ts', '.svelte'],
71 | dedupe: ['svelte'],
72 | }),
73 | copy({
74 | targets: [{ src: 'static/**/*', dest: 'public/' }],
75 | }),
76 | commonjs(),
77 | babel(babelConfig),
78 | json(),
79 |
80 | replace({
81 | 'process.env.NODE_ENV': JSON.stringify(
82 | process.env.NODE_ENV || 'development'
83 | ),
84 | }),
85 |
86 | // Watch the `public` directory and refresh the
87 | // browser on changes when not in production
88 | !production && livereload('public'),
89 |
90 | // If we're building for production (npm run build
91 | // instead of npm run dev), minify
92 | production && terser(),
93 |
94 | html({
95 | title: 'Metro Flow Visualizer',
96 | template: ({ attributes, files, publicPath, title }) => {
97 | let templateFile = fs.readFileSync('src/index.html');
98 |
99 | // This is adapted from the default template function in the HTML plugin.
100 | const scripts = (files.js || [])
101 | .map(({ fileName }) => {
102 | const attrs = makeHtmlAttributes(attributes.script);
103 | return ``;
104 | })
105 | .join('\n');
106 |
107 | const links = (files.css || [])
108 | .map(({ fileName }) => {
109 | const attrs = makeHtmlAttributes(attributes.link);
110 | return ``;
111 | })
112 | .join('\n');
113 |
114 | let exec = template(templateFile.toString());
115 | return exec({
116 | attributes,
117 | title,
118 | scripts,
119 | links,
120 | htmlAttributes: makeHtmlAttributes(attributes.html),
121 | });
122 | },
123 | }),
124 | ],
125 | watch: {
126 | clearScreen: false,
127 | },
128 | };
129 |
--------------------------------------------------------------------------------
/skeleton/snowpack.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@snowpack/app-scripts-svelte",
3 | "scripts": {},
4 | "plugins": [
5 | "@snowpack/plugin-postcss"
6 | ],
7 | "mount": {
8 | "../data": "/data"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/skeleton/snowpack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Metro Flow Visualizer
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/skeleton/src/App.svelte:
--------------------------------------------------------------------------------
1 |
138 |
139 | (loaded = true)} />
140 |
141 |
142 |
Map
143 |
Info
144 |
145 |
--------------------------------------------------------------------------------
/skeleton/src/MapControls.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/skeleton/src/index.html:
--------------------------------------------------------------------------------
1 |
2 | >
3 |
4 |
5 |
6 |
7 | <%= title %>
8 |
9 |
10 | <%= links %>
11 |
12 |
13 |
14 | <%= scripts %>
15 |
16 |
17 |
--------------------------------------------------------------------------------
/skeleton/src/index.js:
--------------------------------------------------------------------------------
1 | import './utils.css';
2 | import App from './App.svelte';
3 |
4 | const app = new App({
5 | target: document.body,
6 | });
7 |
8 | export default app;
9 |
10 | // Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
11 | // Learn more: https://www.snowpack.dev/#hot-module-replacement
12 | if (import.meta.hot) {
13 | import.meta.hot.accept();
14 | import.meta.hot.dispose(() => {
15 | app.$destroy();
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/skeleton/src/map/Control.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
42 |
43 |
44 |
45 | {#if control}
46 |
47 | {/if}
48 |
49 |
50 |
--------------------------------------------------------------------------------
/skeleton/src/map/Curve.svelte:
--------------------------------------------------------------------------------
1 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/skeleton/src/map/GeoJson.svelte:
--------------------------------------------------------------------------------
1 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/skeleton/src/map/Leaflet.svelte:
--------------------------------------------------------------------------------
1 |
55 |
56 |
61 |
62 |
63 | {#if map}
64 |
65 | {/if}
66 |
67 |
--------------------------------------------------------------------------------
/skeleton/src/map/Pane.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/skeleton/src/map/Polyline.svelte:
--------------------------------------------------------------------------------
1 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/skeleton/src/map/Popup.svelte:
--------------------------------------------------------------------------------
1 |
45 |
46 |
47 |
48 | {#if showContents}
49 |
50 | {/if}
51 |
52 |
53 |
--------------------------------------------------------------------------------
/skeleton/src/map/Tooltip.svelte:
--------------------------------------------------------------------------------
1 |
53 |
54 |
55 |
56 | {#if showContents}
57 |
58 | {/if}
59 |
60 |
61 |
--------------------------------------------------------------------------------
/skeleton/src/map/curves.ts:
--------------------------------------------------------------------------------
1 | import * as L from 'leaflet';
2 |
3 | const curveMidpointTheta = Math.PI / 10;
4 | const cosCurveMidpointTheta = Math.cos(curveMidpointTheta);
5 |
6 | function calculateCurve(from: L.LatLng, to: L.LatLng) {
7 | let lineAngle = Math.atan2(to.lat - from.lat, to.lng - from.lng);
8 | let lineMidPointDistance =
9 | Math.sqrt((to.lng - from.lng) ** 2 + (to.lat - from.lat) ** 2) / 2;
10 | let hypotenuse = lineMidPointDistance / cosCurveMidpointTheta;
11 | let totalTheta = lineAngle + curveMidpointTheta;
12 |
13 | return L.latLng(
14 | hypotenuse * Math.sin(totalTheta) + from.lat,
15 | hypotenuse * Math.cos(totalTheta) + from.lng
16 | );
17 | }
18 |
19 | export default function makeLineCoordinates(
20 | map: L.Map,
21 | from: L.LatLng,
22 | to: L.LatLng,
23 | reverse: boolean
24 | ): (string | [number, number])[] {
25 | let curveMidpoint = calculateCurve(reverse ? to : from, reverse ? from : to);
26 | // Designed for use with the Curve component.
27 | return [
28 | 'M',
29 | [from.lat, from.lng],
30 | 'Q',
31 | [curveMidpoint.lat, curveMidpoint.lng],
32 | [to.lat, to.lng],
33 | ];
34 | }
35 |
--------------------------------------------------------------------------------
/skeleton/src/map/leaflet.curve.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Leaflet.curve v0.6.0 - a plugin for Leaflet mapping library. https://github.com/elfalem/Leaflet.curve
3 | * (c) elfalem 2015-2020
4 | */
5 | /*
6 | * note that SVG (x, y) corresponds to (long, lat)
7 | */
8 |
9 | // This is modified from the original to work better with ES Modules. No other changes were made.
10 | import * as L from 'leaflet';
11 |
12 | export const Curve = L.Path.extend({
13 | options: {
14 | },
15 |
16 | initialize: function(path, options){
17 | L.setOptions(this, options);
18 | this._setPath(path);
19 | },
20 |
21 | // Added to follow the naming convention of L.Polyline and other Leaflet component classes:
22 | // (https://leafletjs.com/reference-1.6.0.html#polyline-setlatlngs)
23 | setLatLngs: function(path) {
24 | return this.setPath(path);
25 | },
26 |
27 | _updateBounds: function() {
28 | // Empty function to satisfy L.Path.setStyle() method
29 | },
30 |
31 | getPath: function(){
32 | return this._coords;
33 | },
34 |
35 | setPath: function(path){
36 | this._setPath(path);
37 | return this.redraw();
38 | },
39 |
40 | getBounds: function() {
41 | return this._bounds;
42 | },
43 |
44 | _setPath: function(path){
45 | this._coords = path;
46 | this._bounds = this._computeBounds();
47 | },
48 |
49 | _computeBounds: function(){
50 | var bound = new L.LatLngBounds();
51 | var lastPoint;
52 | var lastCommand;
53 | var coord;
54 | for(var i = 0; i < this._coords.length; i++){
55 | coord = this._coords[i];
56 | if(typeof coord == 'string' || coord instanceof String){
57 | lastCommand = coord;
58 | }else if(lastCommand == 'H'){
59 | bound.extend([lastPoint.lat,coord[0]]);
60 | lastPoint = new L.latLng(lastPoint.lat,coord[0]);
61 | }else if(lastCommand == 'V'){
62 | bound.extend([coord[0], lastPoint.lng]);
63 | lastPoint = new L.latLng(coord[0], lastPoint.lng);
64 | }else if(lastCommand == 'C'){
65 | var controlPoint1 = new L.latLng(coord[0], coord[1]);
66 | coord = this._coords[++i];
67 | var controlPoint2 = new L.latLng(coord[0], coord[1]);
68 | coord = this._coords[++i];
69 | var endPoint = new L.latLng(coord[0], coord[1]);
70 |
71 | bound.extend(controlPoint1);
72 | bound.extend(controlPoint2);
73 | bound.extend(endPoint);
74 |
75 | endPoint.controlPoint1 = controlPoint1;
76 | endPoint.controlPoint2 = controlPoint2;
77 | lastPoint = endPoint;
78 | }else if(lastCommand == 'S'){
79 | var controlPoint2 = new L.latLng(coord[0], coord[1]);
80 | coord = this._coords[++i];
81 | var endPoint = new L.latLng(coord[0], coord[1]);
82 |
83 | var controlPoint1 = lastPoint;
84 | if(lastPoint.controlPoint2){
85 | var diffLat = lastPoint.lat - lastPoint.controlPoint2.lat;
86 | var diffLng = lastPoint.lng - lastPoint.controlPoint2.lng;
87 | controlPoint1 = new L.latLng(lastPoint.lat + diffLat, lastPoint.lng + diffLng);
88 | }
89 |
90 | bound.extend(controlPoint1);
91 | bound.extend(controlPoint2);
92 | bound.extend(endPoint);
93 |
94 | endPoint.controlPoint1 = controlPoint1;
95 | endPoint.controlPoint2 = controlPoint2;
96 | lastPoint = endPoint;
97 | }else if(lastCommand == 'Q'){
98 | var controlPoint = new L.latLng(coord[0], coord[1]);
99 | coord = this._coords[++i];
100 | var endPoint = new L.latLng(coord[0], coord[1]);
101 |
102 | bound.extend(controlPoint);
103 | bound.extend(endPoint);
104 |
105 | endPoint.controlPoint = controlPoint;
106 | lastPoint = endPoint;
107 | }else if(lastCommand == 'T'){
108 | var endPoint = new L.latLng(coord[0], coord[1]);
109 |
110 | var controlPoint = lastPoint;
111 | if(lastPoint.controlPoint){
112 | var diffLat = lastPoint.lat - lastPoint.controlPoint.lat;
113 | var diffLng = lastPoint.lng - lastPoint.controlPoint.lng;
114 | controlPoint = new L.latLng(lastPoint.lat + diffLat, lastPoint.lng + diffLng);
115 | }
116 |
117 | bound.extend(controlPoint);
118 | bound.extend(endPoint);
119 |
120 | endPoint.controlPoint = controlPoint;
121 | lastPoint = endPoint;
122 | }else{
123 | bound.extend(coord);
124 | lastPoint = new L.latLng(coord[0], coord[1]);
125 | }
126 | }
127 | return bound;
128 | },
129 |
130 | getCenter: function () {
131 | return this._bounds.getCenter();
132 | },
133 |
134 | _update: function(){
135 | if (!this._map) { return; }
136 |
137 | this._updatePath();
138 | },
139 |
140 | _updatePath: function() {
141 | if(this._usingCanvas){
142 | this._updateCurveCanvas();
143 | }else{
144 | this._updateCurveSvg();
145 | }
146 | },
147 |
148 | _project: function() {
149 | var coord, lastCoord, curCommand, curPoint;
150 |
151 | this._points = [];
152 |
153 | for(var i = 0; i < this._coords.length; i++){
154 | coord = this._coords[i];
155 | if(typeof coord == 'string' || coord instanceof String){
156 | this._points.push(coord);
157 | curCommand = coord;
158 | }else {
159 | switch(coord.length){
160 | case 2:
161 | curPoint = this._latLngToPointFn.call(this._map, coord);
162 | lastCoord = coord;
163 | break;
164 | case 1:
165 | if(curCommand == 'H'){
166 | curPoint = this._latLngToPointFn.call(this._map, [lastCoord[0], coord[0]]);
167 | lastCoord = [lastCoord[0], coord[0]];
168 | }else{
169 | curPoint = this._latLngToPointFn.call(this._map, [coord[0], lastCoord[1]]);
170 | lastCoord = [coord[0], lastCoord[1]];
171 | }
172 | break;
173 | }
174 | this._points.push(curPoint);
175 | }
176 | }
177 | },
178 |
179 | _curvePointsToPath: function(points){
180 | var point, curCommand, str = '';
181 | for(var i = 0; i < points.length; i++){
182 | point = points[i];
183 | if(typeof point == 'string' || point instanceof String){
184 | curCommand = point;
185 | str += curCommand;
186 | }else{
187 | switch(curCommand){
188 | case 'H':
189 | str += point.x + ' ';
190 | break;
191 | case 'V':
192 | str += point.y + ' ';
193 | break;
194 | default:
195 | str += point.x + ',' + point.y + ' ';
196 | break;
197 | }
198 | }
199 | }
200 | return str || 'M0 0';
201 | },
202 |
203 | beforeAdd: function(map){
204 | L.Path.prototype.beforeAdd.call(this, map);
205 |
206 | this._usingCanvas = this._renderer instanceof L.Canvas;
207 |
208 | this._latLngToPointFn = this._usingCanvas ? map.latLngToContainerPoint : map.latLngToLayerPoint;
209 | if(this._usingCanvas){
210 | this._pathSvgElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
211 | }
212 | },
213 |
214 | onAdd: function(map){
215 | if(this._usingCanvas){
216 | // determine if dash array is set by user
217 | this._canvasSetDashArray = !this.options.dashArray;
218 | }
219 |
220 | L.Path.prototype.onAdd.call(this, map); // calls _update()
221 |
222 | if(this._usingCanvas){
223 | this._animationCanvasElement = this._insertCustomCanvasElement();
224 |
225 | this._resizeCanvas();
226 |
227 | map.on('resize', this._resizeCanvas, this);
228 |
229 | if(this.options.animate && typeof(TWEEN) === 'object'){
230 | this._pathLength = this._pathSvgElement.getTotalLength();
231 |
232 | this._normalizeCanvasAnimationOptions();
233 |
234 | this._tweenedObject = {offset: this._pathLength};
235 | this._tween = new TWEEN.Tween(this._tweenedObject)
236 | .to({offset: 0}, this.options.animate.duration)
237 | // difference of behavior with SVG, delay occurs on every iteration
238 | .delay(this.options.animate.delay)
239 | .repeat(this.options.animate.iterations - 1)
240 | .onComplete(function(scope){
241 | return function(){
242 | scope._canvasAnimating = false;
243 | }
244 | }(this))
245 | .start();
246 |
247 | this._canvasAnimating = true;
248 | this._animateCanvas();
249 | }else{
250 | this._canvasAnimating = false;
251 | }
252 | }else{
253 | if(this.options.animate && this._path.animate){
254 | var length = this._svgSetDashArray();
255 |
256 | this._path.animate([
257 | {strokeDashoffset: length},
258 | {strokeDashoffset: 0}
259 | ], this.options.animate);
260 | }
261 | }
262 | },
263 |
264 | onRemove: function(map){
265 | L.Path.prototype.onRemove.call(this, map);
266 |
267 | if(this._usingCanvas){
268 | this._clearCanvas();
269 | L.DomUtil.remove(this._animationCanvasElement);
270 | map.off('resize', this._resizeCanvas, this);
271 | }
272 | },
273 |
274 | // SVG specific logic
275 | _updateCurveSvg: function(){
276 | this._renderer._setPath(this, this._curvePointsToPath(this._points));
277 |
278 | if(this.options.animate){
279 | this._svgSetDashArray();
280 | }
281 | },
282 |
283 | _svgSetDashArray: function(){
284 | var path = this._path;
285 | var length = path.getTotalLength();
286 |
287 | if(!this.options.dashArray){
288 | path.style.strokeDasharray = length + ' ' + length;
289 | }
290 | return length;
291 | },
292 |
293 | // Needed by the `Canvas` renderer for interactivity
294 | _containsPoint: function(layerPoint) {
295 | return this._bounds.contains(this._map.layerPointToLatLng(layerPoint));
296 | },
297 |
298 | // Canvas specific logic below here
299 | _insertCustomCanvasElement: function(){
300 | var element = L.DomUtil.create('canvas', 'leaflet-zoom-animated');
301 | var originProp = L.DomUtil.testProp(['transformOrigin', 'WebkitTransformOrigin', 'msTransformOrigin']);
302 | element.style[originProp] = '50% 50%';
303 | var pane = this._map.getPane(this.options.pane);
304 | pane.insertBefore(element, pane.firstChild);
305 |
306 | return element;
307 | },
308 |
309 | _normalizeCanvasAnimationOptions: function(){
310 | var opts = {
311 | delay: 0,
312 | duration: 0,
313 | iterations: 1
314 | };
315 | if(typeof(this.options.animate) == "number"){
316 | opts.duration = this.options.animate;
317 | }else{
318 | if(this.options.animate.duration){
319 | opts.duration = this.options.animate.duration;
320 | }
321 | if(this.options.animate.delay){
322 | opts.delay =this.options.animate.delay;
323 | }
324 | if(this.options.animate.iterations){
325 | opts.iterations = this.options.animate.iterations;
326 | }
327 | }
328 |
329 | this.options.animate = opts;
330 | },
331 |
332 | _updateCurveCanvas: function(){
333 | this._project();
334 |
335 | var pathString = this._curvePointsToPath(this._points);
336 | this._pathSvgElement.setAttribute('d', pathString);
337 |
338 | if(this.options.animate && typeof(TWEEN) === 'object' && this._canvasSetDashArray){
339 | this._pathLength = this._pathSvgElement.getTotalLength();
340 | this.options.dashArray = this._pathLength + '';
341 | this._renderer._updateDashArray(this);
342 | }
343 |
344 | this._path2d = new Path2D(pathString);
345 |
346 | if(this._animationCanvasElement){
347 | this._resetCanvas();
348 | }
349 |
350 |
351 | },
352 |
353 | _animationCanvasElement: null,
354 |
355 | _resizeCanvas: function() {
356 | var size = this._map.getSize();
357 | this._animationCanvasElement.width = size.x;
358 | this._animationCanvasElement.height = size.y;
359 |
360 | this._resetCanvas();
361 | },
362 |
363 | _resetCanvas: function() {
364 | var topLeft = this._map.containerPointToLayerPoint([0, 0]);
365 | L.DomUtil.setPosition(this._animationCanvasElement, topLeft);
366 |
367 | this._redrawCanvas();
368 | },
369 |
370 | _redrawCanvas: function(){
371 | if(!this._canvasAnimating){
372 | this._clearCanvas();
373 | var ctx = this._animationCanvasElement.getContext('2d');
374 | this._curveFillStroke(this._path2d, ctx);
375 | }
376 | },
377 |
378 | _clearCanvas: function() {
379 | this._animationCanvasElement.getContext('2d').clearRect(0, 0, this._animationCanvasElement.width, this._animationCanvasElement.height);
380 | },
381 |
382 | _animateCanvas: function(time){
383 | TWEEN.update(time);
384 |
385 | var ctx = this._animationCanvasElement.getContext('2d');
386 | ctx.clearRect(0, 0, this._animationCanvasElement.width, this._animationCanvasElement.height);
387 | ctx.lineDashOffset = this._tweenedObject.offset;
388 |
389 | this._curveFillStroke(this._path2d, ctx);
390 |
391 | if(this._canvasAnimating){
392 | this._animationFrameId = L.Util.requestAnimFrame(this._animateCanvas, this);
393 | }
394 | },
395 |
396 | // similar to Canvas._fillStroke(ctx, layer)
397 | _curveFillStroke: function (path2d, ctx) {
398 | var options = this.options;
399 |
400 | if (options.fill) {
401 | ctx.globalAlpha = options.fillOpacity;
402 | ctx.fillStyle = options.fillColor || options.color;
403 | ctx.fill(path2d, options.fillRule || 'evenodd');
404 | }
405 |
406 | if (options.stroke && options.weight !== 0) {
407 | if (ctx.setLineDash) {
408 | ctx.setLineDash(this.options && this.options._dashArray || []);
409 | }
410 | ctx.globalAlpha = options.opacity;
411 | ctx.lineWidth = options.weight;
412 | ctx.strokeStyle = options.color;
413 | ctx.lineCap = options.lineCap;
414 | ctx.lineJoin = options.lineJoin;
415 | ctx.stroke(path2d);
416 | }
417 | },
418 |
419 | // path tracing logic below here
420 | trace: function(t){
421 | t = t.filter(function(element){
422 | return element >= 0 && element <= 1;
423 | });
424 |
425 | var point, curCommand, curStartPoint, curEndPoint;
426 | var p1, p2, p3;
427 | var samples = [];
428 | for(var i = 0; i < this._points.length; i++){
429 | point = this._points[i];
430 | if(typeof point == 'string' || point instanceof String){
431 | curCommand = point;
432 |
433 | if(curCommand == 'Z'){
434 | samples = samples.concat(this._linearTrace(t, curEndPoint, curStartPoint));
435 | }
436 | }else{
437 | switch(curCommand){
438 | case 'M':
439 | curStartPoint = point;
440 | curEndPoint = point;
441 | break;
442 | case 'L':
443 | case 'H':
444 | case 'V':
445 | samples = samples.concat(this._linearTrace(t, curEndPoint, point));
446 |
447 | curEndPoint = point;
448 | break;
449 | case 'C':
450 | p1 = point;
451 | p2 = this._points[++i];
452 | p3 = this._points[++i];
453 | samples = samples.concat(this._cubicTrace(t, curEndPoint, p1, p2, p3));
454 |
455 | curEndPoint = p3;
456 | break;
457 | case 'S':
458 | p1 = this._reflectPoint(p2, curEndPoint);
459 | p2 = point;
460 | p3 = this._points[++i];
461 | samples = samples.concat(this._cubicTrace(t, curEndPoint, p1, p2, p3));
462 |
463 | curEndPoint = p3;
464 | break;
465 | case 'Q':
466 | p1 = point;
467 | p2 = this._points[++i];
468 | samples = samples.concat(this._quadraticTrace(t, curEndPoint, p1, p2));
469 |
470 | curEndPoint = p2;
471 | break;
472 | case 'T':
473 | p1 = this._reflectPoint(p1, curEndPoint);
474 | p2 = point;
475 | samples = samples.concat(this._quadraticTrace(t, curEndPoint, p1, p2));
476 |
477 | curEndPoint = p2;
478 | break;
479 | default:
480 | break;
481 | }
482 | }
483 | }
484 | return samples;
485 | },
486 | _linearTrace: function(t, p0, p1){
487 | return t.map(interval => {
488 | var x = this._singleLinearTrace(interval, p0.x, p1.x);
489 | var y = this._singleLinearTrace(interval, p0.y, p1.y);
490 | return this._map.layerPointToLatLng([x, y]);
491 | });
492 | },
493 | _quadraticTrace: function(t, p0, p1, p2){
494 | return t.map(interval => {
495 | var x = this._singleQuadraticTrace(interval, p0.x, p1.x, p2.x);
496 | var y = this._singleQuadraticTrace(interval, p0.y, p1.y, p2.y);
497 | return this._map.layerPointToLatLng([x, y]);
498 | });
499 | },
500 | _cubicTrace: function(t, p0, p1, p2, p3){
501 | return t.map(interval => {
502 | var x = this._singleCubicTrace(interval, p0.x, p1.x, p2.x, p3.x);
503 | var y = this._singleCubicTrace(interval, p0.y, p1.y, p2.y, p3.y);
504 | return this._map.layerPointToLatLng([x, y]);
505 | });
506 | },
507 | _singleLinearTrace: function(t, p0, p1){
508 | return p0 + t * (p1 - p0);
509 | },
510 | _singleQuadraticTrace: function(t, p0, p1, p2){
511 | var oneMinusT = 1 - t;
512 | return Math.pow(oneMinusT, 2) * p0 +
513 | 2 * oneMinusT * t * p1 +
514 | Math.pow(t, 2) * p2;
515 | },
516 | _singleCubicTrace: function(t, p0, p1, p2, p3){
517 | var oneMinusT = 1 - t;
518 | return Math.pow(oneMinusT, 3) * p0 +
519 | 3 * Math.pow(oneMinusT, 2) * t * p1 +
520 | 3 * oneMinusT * Math.pow(t, 2) * p2 +
521 | Math.pow(t, 3) * p3;
522 | },
523 | _reflectPoint: function(point, over){
524 | x = over.x + (over.x - point.x);
525 | y = over.y + (over.y - point.y);
526 | return L.point(x, y);
527 | }
528 | });
529 |
530 | export function curve(path, options){
531 | return new Curve(path, options);
532 | };
--------------------------------------------------------------------------------
/skeleton/src/map/popup.ts:
--------------------------------------------------------------------------------
1 | import { SvelteComponent } from 'svelte';
2 | import * as L from 'leaflet';
3 |
4 | export function bindPopup(
5 | layer: L.Layer,
6 | popup?: string | typeof SvelteComponent,
7 | props?: object
8 | ) {
9 | if (!popup) {
10 | return;
11 | }
12 |
13 | if (typeof popup === 'string') {
14 | layer.bindPopup(popup);
15 | } else {
16 | let popupComponent: SvelteComponent | undefined;
17 | layer.bindPopup(() => {
18 | let container = L.DomUtil.create('div');
19 | popupComponent = new popup({
20 | target: container,
21 | props: { ...(props || {}) },
22 | });
23 | return container;
24 | });
25 |
26 | layer.on('popupclose', () => {
27 | if (popupComponent) {
28 | let old = popupComponent;
29 | popupComponent = undefined;
30 | // Wait for the popup to completely fade out before destroying it.
31 | // Otherwise the fade out looks weird as the contents disappear too early.
32 | setTimeout(() => {
33 | old.$destroy();
34 | }, 500);
35 | }
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/skeleton/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Flow {
2 | id: string;
3 | count: number;
4 | }
5 |
6 | export interface Msa {
7 | id: string;
8 | name: string;
9 | net: number;
10 | centroid: number[];
11 | totalIncoming: number;
12 | totalOutgoing: number;
13 | netAsPercent: number;
14 | population: number;
15 | feature: any;
16 | outgoing: Flow[];
17 | incoming: Flow[];
18 | }
19 |
--------------------------------------------------------------------------------
/skeleton/src/utils.css:
--------------------------------------------------------------------------------
1 | /* Import Tailwind as Global Utils */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
5 |
6 | * {
7 | position: relative;
8 | }
9 |
--------------------------------------------------------------------------------
/skeleton/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dimfeld/svelte-leaflet-demo/897b5aab379cc8926ed9ee65a9df846fbae62df7/skeleton/static/favicon.png
--------------------------------------------------------------------------------
/skeleton/svelte.config.js:
--------------------------------------------------------------------------------
1 | const sveltePreprocess = require('svelte-preprocess');
2 |
3 | const dev = process.env.NODE_ENV === 'development';
4 |
5 | module.exports = {
6 | preprocess: sveltePreprocess({
7 | postcss: require('./postcss.config'),
8 | typescript: true,
9 | aliases: [['ts', 'typescript']],
10 | }),
11 | };
12 |
--------------------------------------------------------------------------------
/skeleton/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: false,
3 | theme: {
4 | extend: {
5 | animation: {
6 | 'dash-offset': 'dash-offset var(--animation-speed, 2s) linear infinite',
7 | },
8 | keyframes: {
9 | 'dash-offset': {
10 | from: {
11 | 'stroke-dashoffset': 'var(--dash-length, 18)',
12 | },
13 | to: {
14 | 'stroke-dashoffset': '0',
15 | },
16 | },
17 | },
18 | },
19 | },
20 | variants: {},
21 | plugins: [require('@tailwindcss/ui')],
22 | experimental: {
23 | applyComplexClasses: true,
24 | defaultLineHeights: true,
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/skeleton/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "module": "ESNext",
5 | "moduleResolution": "node",
6 | "target": "es2020",
7 | "noEmit": true,
8 | "strict": true,
9 | "resolveJsonModule": true,
10 | "allowSyntheticDefaultImports": true,
11 | "lib": ["dom", "es5", "ES2015", "es2016", "es2017", "es2018", "ES2019"]
12 | },
13 | "paths": {
14 | "^/*": ["src/*"]
15 | },
16 | "include": ["src"],
17 | "compileOnSave": false
18 | }
19 |
--------------------------------------------------------------------------------