@versatiles/svelte 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,52 @@
1
+ {"label":"USA, Alabama","population":5177563.231041876,"bbox":[-88.471115,30.247195,-84.889196,35.00118]}
2
+ {"label":"USA, Alaska","population":759804.0423448097,"bbox":[-188.90491,51.61274,-129.986323,71.351633]}
3
+ {"label":"USA, Arizona","population":8097866.395435425,"bbox":[-114.815198,31.331629,-109.042503,37.00574]}
4
+ {"label":"USA, Arkansas","population":3230323.8574354965,"bbox":[-94.616242,33.002096,-89.730812,36.501861]}
5
+ {"label":"USA, California","population":40722586.88907707,"bbox":[-124.410798,32.536556,-114.136058,42.011663]}
6
+ {"label":"USA, Colorado","population":5968443.743926897,"bbox":[-109.058934,36.994786,-102.042974,41.003906]}
7
+ {"label":"USA, Connecticut","population":3655185.0041402103,"bbox":[-73.727192,40.987475,-71.799309,42.050002]}
8
+ {"label":"USA, Delaware","population":988837.953840262,"bbox":[-75.786521,38.451652,-75.047134,39.831841]}
9
+ {"label":"USA, District of Columbia","population":730449.1869271634,"bbox":[-77.117418,38.791222,-76.909294,38.993869]}
10
+ {"label":"USA, Florida","population":21757142.98770998,"bbox":[-87.633143,25.120779,-80.03115,31.003013]}
11
+ {"label":"USA, Georgia","population":11719867.446026482,"bbox":[-85.606675,30.356734,-80.885553,35.00118]}
12
+ {"label":"USA, Hawaii","population":881429.9347368085,"bbox":[-159.764448,18.948267,-154.807817,22.228955]}
13
+ {"label":"USA, Idaho","population":1933382.548647272,"bbox":[-117.241483,41.995232,-111.047063,49.000239]}
14
+ {"label":"USA, Illinois","population":13379410.50339758,"bbox":[-91.50534,36.983832,-87.49622,42.510065]}
15
+ {"label":"USA, Indiana","population":6932660.678495618,"bbox":[-88.060345,37.788942,-84.801565,41.759724]}
16
+ {"label":"USA, Iowa","population":3223588.6728098514,"bbox":[-96.631756,40.379535,-90.141582,43.501391]}
17
+ {"label":"USA, Kansas","population":3043167.317689491,"bbox":[-102.053927,36.994786,-94.610765,40.001626]}
18
+ {"label":"USA, Kentucky","population":4769510.0898046745,"bbox":[-89.418626,36.496384,-81.969987,39.103408]}
19
+ {"label":"USA, Louisiana","population":4716545.393436735,"bbox":[-94.041164,29.009407,-89.002379,33.018527]}
20
+ {"label":"USA, Maine","population":1338467.0092898812,"bbox":[-71.08183,43.057759,-66.979601,47.461219]}
21
+ {"label":"USA, Maryland","population":6300244.10830445,"bbox":[-79.488933,37.909435,-75.047134,39.722302]}
22
+ {"label":"USA, Massachusetts","population":6567830.886439975,"bbox":[-73.508114,41.496831,-69.937149,42.887974]}
23
+ {"label":"USA, Michigan","population":9836600.438030683,"bbox":[-90.415429,41.694001,-82.413619,48.173221]}
24
+ {"label":"USA, Minnesota","population":5791488.56556222,"bbox":[-97.228743,43.501391,-89.615796,49.383625]}
25
+ {"label":"USA, Mississippi","population":3123243.1444979305,"bbox":[-91.636787,30.181472,-88.098683,34.995703]}
26
+ {"label":"USA, Missouri","population":6453137.449391876,"bbox":[-95.7664,35.997983,-89.133825,40.615043]}
27
+ {"label":"USA, Montana","population":1105757.5461610334,"bbox":[-116.04751,44.394132,-104.042057,49.000239]}
28
+ {"label":"USA, Nebraska","population":1927199.5751335358,"bbox":[-104.053011,40.001626,-95.306337,43.002989]}
29
+ {"label":"USA, Nevada","population":3724231.0557103534,"bbox":[-120.001861,35.00118,-114.04295,42.000709]}
30
+ {"label":"USA, New Hampshire","population":1385364.059273818,"bbox":[-72.544173,42.696281,-70.703921,45.303304]}
31
+ {"label":"USA, New Jersey","population":9184491.767511679,"bbox":[-75.561967,38.993869,-73.902454,41.359907]}
32
+ {"label":"USA, New Mexico","population":2385077.1582568623,"bbox":[-109.04798,31.331629,-103.001438,37.000263]}
33
+ {"label":"USA, New York","population":18375122.60360537,"bbox":[-79.76278,40.543843,-72.100541,45.018503]}
34
+ {"label":"USA, North Carolina","population":11414773.704236036,"bbox":[-84.319594,33.845545,-75.715321,36.589492]}
35
+ {"label":"USA, North Dakota","population":683303.1426835521,"bbox":[-104.047534,45.933153,-96.560556,49.000239]}
36
+ {"label":"USA, Ohio","population":11639778.570655461,"bbox":[-84.817996,38.424267,-80.518598,41.978802]}
37
+ {"label":"USA, Oklahoma","population":4117763.3142439188,"bbox":[-103.001438,33.637421,-94.430026,37.000263]}
38
+ {"label":"USA, Oregon","population":4349027.331137432,"bbox":[-124.553198,41.989755,-116.463758,46.261769]}
39
+ {"label":"USA, Pennsylvania","population":13088961.863057058,"bbox":[-80.518598,39.722302,-74.69661,42.269079]}
40
+ {"label":"USA, Rhode Island","population":924899.033123764,"bbox":[-71.859555,41.321569,-71.120168,42.01714]}
41
+ {"label":"USA, South Carolina","population":5373609.9850199865,"bbox":[-83.339222,32.032678,-78.541422,35.198349]}
42
+ {"label":"USA, South Dakota","population":897722.3989744552,"bbox":[-104.058488,42.488157,-96.434587,45.944106]}
43
+ {"label":"USA, Tennessee","population":7129013.832038804,"bbox":[-90.311367,34.984749,-81.679709,36.677123]}
44
+ {"label":"USA, Texas","population":30746134.131327786,"bbox":[-106.643603,25.887551,-93.526331,36.501861]}
45
+ {"label":"USA, Utah","population":3469677.9621637366,"bbox":[-114.048427,37.000263,-109.042503,42.000709]}
46
+ {"label":"USA, Vermont","population":645833.1056439477,"bbox":[-73.436914,42.729142,-71.4926,45.013027]}
47
+ {"label":"USA, Virginia","population":9001125.446413808,"bbox":[-83.673316,36.5402,-75.244304,39.464886]}
48
+ {"label":"USA, Washington","population":7397111.944808818,"bbox":[-124.706553,45.549767,-116.918344,49.000239]}
49
+ {"label":"USA, West Virginia","population":1913671.4932506953,"bbox":[-82.621743,37.20291,-77.719881,40.636951]}
50
+ {"label":"USA, Wisconsin","population":5953802.719794881,"bbox":[-92.885529,42.493634,-87.03068,46.95734]}
51
+ {"label":"USA, Wyoming","population":656776.5127059702,"bbox":[-111.05254,40.998429,-104.053011,45.002073]}
52
+ {"label":"USA, Puerto Rico","population":3450971.537693411,"bbox":[-67.269879,17.929556,-65.626797,18.515589]}
@@ -0,0 +1,7 @@
1
+ {"label":"World", "population":8100000000, "bbox":[-180,-90,180,90]}
2
+ {"label":"Asia", "population":4561000000, "bbox":[31.6,-13.1,180,84.53]}
3
+ {"label":"North America", "population":579000000, "bbox":[-180,5.5,-18,90]}
4
+ {"label":"Europe", "population":746000000, "bbox":[-31.3,34.9,69,81.9]}
5
+ {"label":"Africa", "population":1216000000, "bbox":[-25.4,-34.9,63.5,37.4]}
6
+ {"label":"South America", "population":422000000, "bbox":[-91.7,-56,-34.8,12.5]}
7
+ {"label":"Oceania", "population":46000000, "bbox":[91,-57,180,28]}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env npx tsx
2
+ import { createReadStream, readFileSync, writeFileSync } from 'node:fs';
3
+ import { brotliDecompressSync, createBrotliDecompress, createGunzip } from 'node:zlib';
4
+ import { basename, resolve } from 'node:path';
5
+ import * as turf from '@turf/turf';
6
+ import split from 'split2';
7
+ // Buffer to hold decompressed population data
8
+ let popBuffer;
9
+ // Parse command-line arguments
10
+ let input = process.argv[2];
11
+ const labelTemplate = process.argv[3];
12
+ const populationKey = process.argv[4];
13
+ // Validate command-line arguments
14
+ if (!input || !labelTemplate) {
15
+ [
16
+ 'Expected: ./geojson2bboxes.ts <FILENAME> <LABEL_TEMPLATE> [POPULATION_KEY]',
17
+ 'where:',
18
+ '<FILENAME>: The name of the input GeoJSON or GeoJSONL file. The file can be optionally compressed with .br (Brotli) or .gz (Gzip).',
19
+ '<LABEL_TEMPLATE>: A template string used to generate labels for each feature. The template can include placeholders in the form {propertyName} which will be replaced by the corresponding property value from each feature.',
20
+ "[POPULATION_KEY]: (Optional) The key in the feature's properties that contains the population value. If not provided, the script will attempt to estimate the population using a predefined algorithm."
21
+ ].forEach((m) => console.error(m));
22
+ process.exit(1);
23
+ }
24
+ // Determine the input stream, handling compressed files
25
+ let stream = createReadStream(input);
26
+ input = basename(input);
27
+ if (input.endsWith('.br')) {
28
+ stream = stream.pipe(createBrotliDecompress());
29
+ input = basename(input, '.br');
30
+ }
31
+ else if (input.endsWith('.gz')) {
32
+ stream = stream.pipe(createGunzip());
33
+ input = basename(input, '.gz');
34
+ }
35
+ // Initialize the result array
36
+ let result = [];
37
+ if (input.endsWith('.geojson')) {
38
+ // If the input is a GeoJSON file, process it directly
39
+ result = JSON.parse(await streamToString(stream)).features.map(processFeature);
40
+ }
41
+ else if (input.endsWith('.geojsonl')) {
42
+ // If the input is a GeoJSONL file, process it line by line
43
+ result = await mapJSONStream(stream.pipe(split()), processFeature);
44
+ }
45
+ // Write the results to a JSONL file
46
+ writeFileSync(input + '.jsonl', result
47
+ .map((f) => JSON.stringify(f))
48
+ .sort() // Sort the results before writing
49
+ .join('\n'));
50
+ /**
51
+ * Processes a GeoJSON feature to extract the label, population, and bounding box (BBox).
52
+ * @param feature - The GeoJSON feature to process.
53
+ * @returns An object containing the label, population, and bounding box.
54
+ */
55
+ function processFeature(feature) {
56
+ if (feature.geometry.type !== 'Polygon' && feature.geometry.type !== 'MultiPolygon') {
57
+ throw new Error('Feature must be Polygon or MultiPolygon');
58
+ }
59
+ const polygon = feature;
60
+ const { properties } = polygon;
61
+ if (!properties)
62
+ throw new Error('Feature has no properties');
63
+ // Compute the bounding box using Turf.js
64
+ const bbox = turf.bbox(polygon);
65
+ // Generate the label using the provided template
66
+ const label = labelTemplate.replace(/{(.*?)}/g, (text, key) => {
67
+ const value = properties[key];
68
+ if (value === undefined)
69
+ console.error(`key "${key}" not found in feature properties`);
70
+ return value;
71
+ });
72
+ // Determine the population
73
+ let population;
74
+ if (populationKey) {
75
+ population = properties[populationKey];
76
+ }
77
+ else {
78
+ console.log(`Guessing population for "${label}"`);
79
+ population = guessPopulation(polygon);
80
+ }
81
+ return { label, population, bbox };
82
+ }
83
+ /**
84
+ * Converts a stream to a string by accumulating its chunks.
85
+ * @param stream - The stream to convert.
86
+ * @returns A promise that resolves to the string representation of the stream's content.
87
+ */
88
+ function streamToString(stream) {
89
+ const chunks = [];
90
+ return new Promise((resolve, reject) => {
91
+ stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
92
+ stream.on('error', (err) => reject(err));
93
+ stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
94
+ });
95
+ }
96
+ /**
97
+ * Maps each feature in a JSONL stream to an entry using a provided callback function.
98
+ * @param stream - The stream of JSONL data.
99
+ * @param cb - The callback function to process each feature.
100
+ * @returns A promise that resolves to an array of entries.
101
+ */
102
+ function mapJSONStream(stream, cb) {
103
+ const result = [];
104
+ return new Promise((resolve, reject) => {
105
+ stream.on('data', (chunk) => result.push(cb(JSON.parse(chunk))));
106
+ stream.on('error', (err) => reject(err));
107
+ stream.on('end', () => resolve(result));
108
+ });
109
+ }
110
+ /**
111
+ * Estimates the population for a given feature by recursively subdividing its bounding box.
112
+ * @param feature - The GeoJSON feature for which to estimate population.
113
+ * @returns The estimated population.
114
+ */
115
+ function guessPopulation(feature) {
116
+ if (!popBuffer) {
117
+ // Load and decompress the population density data if not already loaded
118
+ popBuffer = brotliDecompressSync(readFileSync(resolve(import.meta.dirname, 'population.raw.br')));
119
+ }
120
+ let sum = 0;
121
+ // Flatten the geometry and estimate population for each part
122
+ turf.flattenEach(feature, (f) => {
123
+ const bbox = turf.bbox(f);
124
+ sum += rec(f, bbox, 0, 0, 4320, 4320);
125
+ sum += rec(f, bbox, 4320, 0, 8640, 4320);
126
+ });
127
+ return sum;
128
+ /**
129
+ * Recursively estimates the population for a bounding box.
130
+ * @param feature - The feature to process.
131
+ * @param bboxF - The bounding box of the feature.
132
+ * @param x0 - The starting x-coordinate.
133
+ * @param y0 - The starting y-coordinate.
134
+ * @param x1 - The ending x-coordinate.
135
+ * @param y1 - The ending y-coordinate.
136
+ * @returns The estimated population within the given bounding box.
137
+ */
138
+ function rec(feature, bboxF, x0, y0, x1, y1) {
139
+ if (!feature)
140
+ return 0;
141
+ if (x0 === x1 || y0 === y1)
142
+ return 0;
143
+ // Calculate the bounding box for this subdivision
144
+ const bbox = [x0 / 24 - 180, y0 / 24 - 90, x1 / 24 - 180, y1 / 24 - 90];
145
+ // Check if the subdivision overlaps with the feature's bounding box
146
+ if (!bboxOverlap(bbox, bboxF))
147
+ return 0;
148
+ // Create a polygon from the bounding box and calculate the intersection
149
+ const bboxPolygon = turf.bboxPolygon(bbox);
150
+ const intersection = turf.intersect(turf.featureCollection([feature, bboxPolygon]));
151
+ if (!intersection)
152
+ return 0;
153
+ // If the subdivision is minimal, calculate the population directly
154
+ if (x1 - x0 === 1 && y1 - y0 === 1) {
155
+ const areaFull = turf.area(bboxPolygon);
156
+ const areaIntersected = turf.area(intersection);
157
+ const populationDensity = Math.pow(2, popBuffer[y0 * 8640 + x0] / 10);
158
+ return (populationDensity * areaIntersected) / areaFull;
159
+ }
160
+ // Recursively subdivide the bounding box and sum the population estimates
161
+ bboxF = turf.bbox(intersection);
162
+ const xn = Math.round((x0 + x1) / 2);
163
+ const yn = Math.round((y0 + y1) / 2);
164
+ let sum = 0;
165
+ sum += rec(intersection, bboxF, x0, y0, xn, yn);
166
+ sum += rec(intersection, bboxF, xn, y0, x1, yn);
167
+ sum += rec(intersection, bboxF, x0, yn, xn, y1);
168
+ sum += rec(intersection, bboxF, xn, yn, x1, y1);
169
+ return sum;
170
+ }
171
+ }
172
+ /**
173
+ * Checks if two bounding boxes overlap.
174
+ * @param bbox1 - The first bounding box.
175
+ * @param bbox2 - The second bounding box.
176
+ * @returns True if the bounding boxes overlap, false otherwise.
177
+ */
178
+ function bboxOverlap(bbox1, bbox2) {
179
+ return !(bbox1[0] > bbox2[2] ||
180
+ bbox1[1] > bbox2[3] ||
181
+ bbox1[2] < bbox2[0] ||
182
+ bbox1[3] < bbox2[1]);
183
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env npx tsx
2
+ export {};
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env npx tsx
2
+ import { readdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ // Change the current working directory to the script's directory
4
+ process.chdir(import.meta.dirname);
5
+ console.log('Loading data...');
6
+ // Initialize an array to hold the processed data
7
+ const data = [];
8
+ // Set to keep track of known labels to prevent duplicates
9
+ const knownLabels = new Set();
10
+ // Read all files in the "sources" directory
11
+ readdirSync('../data/sources').forEach((filename) => {
12
+ // Skip files that do not end with .jsonl
13
+ if (!filename.endsWith('.jsonl'))
14
+ return;
15
+ // Read the contents of the file and split it into lines
16
+ const lines = readFileSync(`../data/sources/${filename}`, 'utf8').split('\n');
17
+ for (const line of lines) {
18
+ // Skip empty lines
19
+ if (!line)
20
+ continue;
21
+ // Parse each line into an Entry object
22
+ const entry = JSON.parse(line);
23
+ // Check for missing population values
24
+ if (!entry.population) {
25
+ console.error(`Error: Population is missing in line: ${line}`);
26
+ continue;
27
+ }
28
+ // Check for duplicate labels
29
+ if (knownLabels.has(entry.label)) {
30
+ throw new Error(`Error: Label "${entry.label}" is duplicated`);
31
+ }
32
+ // Add the label to the knownLabels set
33
+ knownLabels.add(entry.label);
34
+ // Round the bounding box values
35
+ const bbox = roundBBox(entry.bbox);
36
+ // Add the entry to the data array
37
+ data.push({ ...entry, bbox });
38
+ }
39
+ });
40
+ // Sort the data array by population in descending order
41
+ data.sort((a, b) => b.population - a.population);
42
+ console.log('Writing data to output file...');
43
+ // Write the processed data to a JSON file
44
+ writeFileSync('../bboxes.json', '[\n' +
45
+ data
46
+ .map((e) => {
47
+ const r = [e.label, ...e.bbox];
48
+ // Ensure the array has exactly 5 elements (label + 4 bbox values)
49
+ if (r.length !== 5)
50
+ throw new Error('Error: Incorrect entry length');
51
+ return JSON.stringify(r);
52
+ })
53
+ .join(',\n') +
54
+ '\n]');
55
+ console.log('Data processing complete.');
56
+ /**
57
+ * Rounds the values in a bounding box to a precision determined by its size.
58
+ * @param bbox - The bounding box to round.
59
+ * @returns A new bounding box with rounded values.
60
+ */
61
+ function roundBBox(bbox) {
62
+ // Determine precision based on the size of the bounding box
63
+ const fx = length2precision(Math.abs(bbox[2] - bbox[0]));
64
+ const fy = length2precision(Math.abs(bbox[3] - bbox[1]));
65
+ // Round the bounding box values
66
+ const x = Math.floor(bbox[0] * fx) / fx;
67
+ const y = Math.floor(bbox[1] * fy) / fy;
68
+ const b = [x, y, Math.ceil((bbox[2] - x) * fx) / fx, Math.ceil((bbox[3] - y) * fy) / fy];
69
+ return b;
70
+ /**
71
+ * Determines the precision for rounding based on the length of a side of the bounding box.
72
+ * @param n - The length of a side of the bounding box.
73
+ * @returns The precision factor to use for rounding.
74
+ */
75
+ function length2precision(n) {
76
+ if (n > 300)
77
+ return 1; // No rounding for large values
78
+ if (n > 30)
79
+ return 10; // Round to the nearest 0.1
80
+ if (n > 3)
81
+ return 100; // Round to the nearest 0.01
82
+ return 1000; // Round to the nearest 0.001 for small values
83
+ }
84
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import BBoxMap from './BBoxMap/BBoxMap.svelte';
1
+ import BBoxMap from './components/BBoxMap/BBoxMap.svelte';
2
2
  export { BBoxMap };
package/dist/index.js CHANGED
@@ -1,3 +1,2 @@
1
- // Reexport your entry components here
2
- import BBoxMap from './BBoxMap/BBoxMap.svelte';
1
+ import BBoxMap from './components/BBoxMap/BBoxMap.svelte';
3
2
  export { BBoxMap };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versatiles/svelte",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "scripts": {
5
5
  "build": "vite build && npm run package",
6
6
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
@@ -36,14 +36,14 @@
36
36
  "svelte": "^4.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@playwright/test": "^1.46.0",
39
+ "@playwright/test": "^1.46.1",
40
40
  "@sveltejs/adapter-auto": "^3.2.4",
41
41
  "@sveltejs/kit": "^2.5.22",
42
42
  "@sveltejs/package": "^2.3.4",
43
43
  "@sveltejs/vite-plugin-svelte": "^3.1.1",
44
44
  "@turf/turf": "^7.1.0",
45
45
  "@types/eslint": "^9.6.0",
46
- "@types/node": "^22.3.0",
46
+ "@types/node": "^22.4.0",
47
47
  "@types/split2": "^4.2.3",
48
48
  "@versatiles/release-tool": "^1.2.5",
49
49
  "eslint": "^9.9.0",
@@ -53,14 +53,14 @@
53
53
  "globals": "^15.9.0",
54
54
  "prettier": "^3.3.3",
55
55
  "prettier-plugin-svelte": "^3.2.6",
56
- "publint": "^0.2.9",
56
+ "publint": "^0.2.10",
57
57
  "split2": "^4.2.0",
58
58
  "svelte": "^4.2.18",
59
59
  "svelte-check": "^3.8.5",
60
60
  "tsx": "^4.17.0",
61
61
  "typescript": "^5.5.4",
62
62
  "typescript-eslint": "^8.1.0",
63
- "vite": "^5.4.0",
63
+ "vite": "^5.4.1",
64
64
  "vitest": "^2.0.5"
65
65
  },
66
66
  "svelte": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import 'maplibre-gl/dist/maplibre-gl.css';
3
2
  import type { BBox } from './BBoxMap.js';
3
+ import 'maplibre-gl/dist/maplibre-gl.css';
4
4
  declare const __propDef: {
5
5
  props: {
6
6
  selectedBBox?: BBox;
File without changes