@motionscript/geography 0.1.0-alpha.8 → 0.1.0-alpha.9

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.
package/README.md CHANGED
@@ -1,149 +1,149 @@
1
- # @motionscript/geography
2
-
3
- Geography for [Motion Script](https://motionscript.dev): `GeoBorder`, country and
4
- state outlines by ISO 3166 code. Hand `NODES` to the engine through your
5
- project entry, and a document can name `geoBorder`:
6
-
7
- ```ts
8
- // src/project.ts
9
- import { NODES } from '@motionscript/geography';
10
-
11
- export const nodes = NODES;
12
- ```
13
-
14
- `GeoBorder` draws nothing until a data source is registered; see
15
- [its docs page](https://motionscript.dev/docs/components/geography/geo-border).
16
-
17
- This package is written against [`@motionscript/sdk`](https://github.com/motionscript-dev/motionscript/tree/main/packages/sdk), which it
18
- takes as a peer dependency.
19
-
20
- ## Install
21
-
22
- ```bash
23
- npm install @motionscript/geography @motionscript/sdk
24
- ```
25
-
26
- ## GeoBorder
27
-
28
- - **`start` and `end` trim the fill and the overlay as well as the outline.**
29
- Each path is cut to the part of `[start, end]` that falls inside it, so a
30
- filled border drawn on with `end` from 0 to 1 grows as partial polygons, each
31
- closed by a straight chord, and a stroke-only one grows as a line. There is no
32
- way to trim the stroke alone.
33
- - **Fill and stroke are separate geometry.** The fill is each kept polygon; the
34
- stroke draws each arc once, so a border two selected regions share is stroked
35
- once, and `stroke.align` is forced to the centre. `clipSelf` is the layout box,
36
- not the outline.
37
- - **`detail` never refits.** The files store a simplification bucket per point,
38
- `detail` is a draw-time threshold over it, and the projection is fitted at full
39
- detail and cached apart from it, so tweening `detail` does not move the drawing.
40
- - **`iso` is a list of codes**, as an array or text split on spaces, commas and
41
- semicolons, upper-cased. A code is `AB` or `AB-XYZ`; one that is not, or that no
42
- loaded file has, draws nothing and warns once. A bare country code draws the
43
- country, or at `level: "state"` its first-level subdivisions (minus `remote`
44
- ones when `frame` is `"mainland"`); a subdivision code is always itself.
45
- - **Drawing never throws.** A node declares each file it needs as the asset
46
- `geo:<key>` (gate `render`: layout does not wait for it, but an export loads the
47
- files before the frame that needs them); a missing or failed file draws nothing.
48
-
49
- ### Data sources
50
-
51
- The files are this package's own `data/` (see [The data](#the-data)); the kit
52
- reads them only through their format
53
- (`v1/index`, `v1/countries/<ISO2>`, `v1/states/<ISO2>`, where `v1/states/US`
54
- holds every `US-…` unit). The registry is process-wide, shared by every engine,
55
- session and node:
56
-
57
- ```ts
58
- import { geoRegistry, geoUrlSource } from '@motionscript/geography';
59
-
60
- geoRegistry.use(geoUrlSource('/geo')); // serves the *contents of* @motionscript/geography/data
61
- geoRegistry.define({ 'XX-ATLANTIS': { shape: geojsonPolygon, name: 'Atlantis' } });
62
- ```
63
-
64
- - **Sources are asked in registration order; the first non-null answer wins.**
65
- `null` means "not here" and a throw means "could not tell"; neither is cached
66
- for good, and `loadGeoFile` never rejects. `geoUrlSource` treats HTTP 404 and 400
67
- as absent. `geoLoaderSource(load)` wraps text, bytes or parsed JSON (for example
68
- `fs.readFile`). With no source registered nothing loads and `GeoBorder` draws
69
- nothing.
70
- - **A defined shape wins over every source** and needs none. It is GeoJSON in
71
- lon/lat, wound either way round, and is simplified by `detail` like any other.
72
- - **Decoded files are never freed** while the process lives (`clearGeoFiles`
73
- exists for tests), and `geoLoader(key)` returns one function per key, so any
74
- number of nodes declare the same loader.
75
-
76
- ## The data
77
-
78
- The package also ships the outlines `GeoBorder` draws: country and first-level
79
- subdivision outlines keyed by ISO 3166 code, as small JSON files derived from
80
- [Natural Earth](https://www.naturalearthdata.com/) v5.1.2 (public domain; see
81
- `CREDITS.md`). They are in `data/` and exported as `./data/*`, read by path from
82
- `node_modules` or served from a static host. The kit's code does not import
83
- them.
84
-
85
- ### The data is generated, never edited
86
-
87
- `data/` and `.cache/` are gitignored. `scripts/generate.mjs` removes `data/v1/`
88
- and writes it whole, from three Natural Earth GeoJSON files pinned in
89
- `sources.lock.json` (tag, URL, sha256, size). A downloaded or cached file that
90
- does not match the lock is refused, and a file is cached only after it matches.
91
- The lock changes only through `--update-lock`. To change what a code draws, change
92
- the generator or its tables (`scripts/lib/*.mjs`) and regenerate.
93
-
94
- ```bash
95
- pnpm --filter @motionscript/geography generate # network on first run, ~8 GB heap
96
- pnpm --filter @motionscript/geography verify # checks data/v1/
97
- pnpm --filter @motionscript/geography test # node --test over scripts/tests
98
- node scripts/fixture.mjs <out-dir> # cut the geo kit's test fixture from data/
99
- node --max-old-space-size=8192 scripts/generate.mjs --update-lock # re-pin sources
100
- ```
101
-
102
- `prepack` (before `npm pack` and `publish`) generates `data/` when it is missing,
103
- then runs `verify`; the package has no `build`, `lint` or `typecheck`. The geo kit's
104
- committed fixture is `components/geography/src/border/tests/fixtures/v1/`.
105
-
106
- ### Layout and keys
107
-
108
- ```
109
- data/v1/index.json every listed region: [code, name, nameNl, parent|null, first 0|1]
110
- data/v1/countries/<ISO2>.json one country per file
111
- data/v1/states/<prefix>.json every subdivision whose code starts with <prefix> (US-CA is in states/US)
112
- ```
113
-
114
- - **Countries** are ISO 3166-1 alpha-2 codes from Natural Earth's de facto
115
- worldview, plus `XK` (Kosovo) and two user-assigned codes: `XS` Somaliland and
116
- `XN` Northern Cyprus. Territories the default file folds into a parent (`GF`,
117
- `RE`, `SJ`, ...) are countries of their own while the parent keeps its geometry.
118
- - **Subdivisions** are ISO 3166-2 codes (`US-CA`, `FR-IDF`, `GB-ENG`), filed by the
119
- code's prefix, never by `adm0_a3` (which files Crimea under Russia and Puerto
120
- Rico outside the US). First-level regions of FR, GB, IT, ES and PH are built from
121
- Natural Earth's second-level units.
122
- - **Unlisted features** (placeholders such as `SY-X01`, codeless `-99` units) are in
123
- the files so a state map has no holes, and absent from `index.json`.
124
- - **A feature** has `code`, `name`, `nameNl`, `parent`, `first`, `listed`, optional
125
- `remote`, `area` (steradians), `mainland` (polygon indices, or `null` when all),
126
- `areas` and `polygons` (rings of arc references; `~i` is arc `i` reversed).
127
-
128
- ### Invariants
129
-
130
- - **One topology.** Every country and subdivision is stitched and quantised
131
- together (1e6 steps, one `transform` for every file), so a border two regions
132
- share is one arc with one global id (`arcIds`) in every file that uses it, and
133
- simplifies identically on both sides. The renderer relies on it to stroke the
134
- border once.
135
- - **Simplification is stored, not applied.** Each arc point is a triple
136
- `x, y, bucket` (the first `x`, `y` absolute, the rest deltas). The bucket is
137
- `clamp(round(-2 * log2(weight)), 1, 254)` of the point's spherical triangle area,
138
- 0 for an arc's first and last point (so no detail setting can open a ring), and
139
- 255 for a non-positive weight. `GeoBorder`'s `detail` is a draw-time threshold
140
- over the bucket, so one set of files serves every detail.
141
- - **No file is over 1.5 MiB**, so any one can be fetched alone (`verify`).
142
- - **The format is in the path.** A change in meaning or removal of a field is a new
143
- `data/v<N>/`, with `FORMAT` in `scripts/generate.mjs` and `scripts/verify.mjs` and
144
- `GEO_DATA_FORMAT` in the geo kit's `src/border/format.ts` moving together; adding
145
- a field is compatible with the kit's decoder, which ignores unknown ones.
146
- - **`verify` checks structure and coverage, not provenance**: arc and index
147
- integrity, endpoints, size, and minimum counts (249 countries, the 50 US states
148
- and DC, FR, GB, IT, ES, CA, DE and AU first-level regions). It does not compare
149
- the data with the lock or the generator.
1
+ # @motionscript/geography
2
+
3
+ Geography for [Motion Script](https://motionscript.dev): `GeoBorder`, country and
4
+ state outlines by ISO 3166 code. Hand `NODES` to the engine through your
5
+ project entry, and a document can name `geoBorder`:
6
+
7
+ ```ts
8
+ // src/project.ts
9
+ import { NODES } from '@motionscript/geography';
10
+
11
+ export const nodes = NODES;
12
+ ```
13
+
14
+ `GeoBorder` draws nothing until a data source is registered; see
15
+ [its docs page](https://motionscript.dev/docs/components/geography/geo-border).
16
+
17
+ This package is written against [`@motionscript/sdk`](https://github.com/motionscript-dev/motionscript/tree/main/packages/sdk), which it
18
+ takes as a peer dependency.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ npm install @motionscript/geography @motionscript/sdk
24
+ ```
25
+
26
+ ## GeoBorder
27
+
28
+ - **`start` and `end` trim the fill and the overlay as well as the outline.**
29
+ Each path is cut to the part of `[start, end]` that falls inside it, so a
30
+ filled border drawn on with `end` from 0 to 1 grows as partial polygons, each
31
+ closed by a straight chord, and a stroke-only one grows as a line. There is no
32
+ way to trim the stroke alone.
33
+ - **Fill and stroke are separate geometry.** The fill is each kept polygon; the
34
+ stroke draws each arc once, so a border two selected regions share is stroked
35
+ once, and `stroke.align` is forced to the centre. `clipSelf` is the layout box,
36
+ not the outline.
37
+ - **`detail` never refits.** The files store a simplification bucket per point,
38
+ `detail` is a draw-time threshold over it, and the projection is fitted at full
39
+ detail and cached apart from it, so tweening `detail` does not move the drawing.
40
+ - **`iso` is a list of codes**, as an array or text split on spaces, commas and
41
+ semicolons, upper-cased. A code is `AB` or `AB-XYZ`; one that is not, or that no
42
+ loaded file has, draws nothing and warns once. A bare country code draws the
43
+ country, or at `level: "state"` its first-level subdivisions (minus `remote`
44
+ ones when `frame` is `"mainland"`); a subdivision code is always itself.
45
+ - **Drawing never throws.** A node declares each file it needs as the asset
46
+ `geo:<key>` (gate `render`: layout does not wait for it, but an export loads the
47
+ files before the frame that needs them); a missing or failed file draws nothing.
48
+
49
+ ### Data sources
50
+
51
+ The files are this package's own `data/` (see [The data](#the-data)); the kit
52
+ reads them only through their format
53
+ (`v1/index`, `v1/countries/<ISO2>`, `v1/states/<ISO2>`, where `v1/states/US`
54
+ holds every `US-…` unit). The registry is process-wide, shared by every engine,
55
+ session and node:
56
+
57
+ ```ts
58
+ import { geoRegistry, geoUrlSource } from '@motionscript/geography';
59
+
60
+ geoRegistry.use(geoUrlSource('/geo')); // serves the *contents of* @motionscript/geography/data
61
+ geoRegistry.define({ 'XX-ATLANTIS': { shape: geojsonPolygon, name: 'Atlantis' } });
62
+ ```
63
+
64
+ - **Sources are asked in registration order; the first non-null answer wins.**
65
+ `null` means "not here" and a throw means "could not tell"; neither is cached
66
+ for good, and `loadGeoFile` never rejects. `geoUrlSource` treats HTTP 404 and 400
67
+ as absent. `geoLoaderSource(load)` wraps text, bytes or parsed JSON (for example
68
+ `fs.readFile`). With no source registered nothing loads and `GeoBorder` draws
69
+ nothing.
70
+ - **A defined shape wins over every source** and needs none. It is GeoJSON in
71
+ lon/lat, wound either way round, and is simplified by `detail` like any other.
72
+ - **Decoded files are never freed** while the process lives (`clearGeoFiles`
73
+ exists for tests), and `geoLoader(key)` returns one function per key, so any
74
+ number of nodes declare the same loader.
75
+
76
+ ## The data
77
+
78
+ The package also ships the outlines `GeoBorder` draws: country and first-level
79
+ subdivision outlines keyed by ISO 3166 code, as small JSON files derived from
80
+ [Natural Earth](https://www.naturalearthdata.com/) v5.1.2 (public domain; see
81
+ `CREDITS.md`). They are in `data/` and exported as `./data/*`, read by path from
82
+ `node_modules` or served from a static host. The kit's code does not import
83
+ them.
84
+
85
+ ### The data is generated, never edited
86
+
87
+ `data/` and `.cache/` are gitignored. `scripts/generate.mjs` removes `data/v1/`
88
+ and writes it whole, from three Natural Earth GeoJSON files pinned in
89
+ `sources.lock.json` (tag, URL, sha256, size). A downloaded or cached file that
90
+ does not match the lock is refused, and a file is cached only after it matches.
91
+ The lock changes only through `--update-lock`. To change what a code draws, change
92
+ the generator or its tables (`scripts/lib/*.mjs`) and regenerate.
93
+
94
+ ```bash
95
+ pnpm --filter @motionscript/geography generate # network on first run, ~8 GB heap
96
+ pnpm --filter @motionscript/geography verify # checks data/v1/
97
+ pnpm --filter @motionscript/geography test # node --test over scripts/tests
98
+ node scripts/fixture.mjs <out-dir> # cut the geo kit's test fixture from data/
99
+ node --max-old-space-size=8192 scripts/generate.mjs --update-lock # re-pin sources
100
+ ```
101
+
102
+ `prepack` (before `npm pack` and `publish`) generates `data/` when it is missing,
103
+ then runs `verify`; the package has no `build`, `lint` or `typecheck`. The geo kit's
104
+ committed fixture is `components/geography/src/border/tests/fixtures/v1/`.
105
+
106
+ ### Layout and keys
107
+
108
+ ```
109
+ data/v1/index.json every listed region: [code, name, nameNl, parent|null, first 0|1]
110
+ data/v1/countries/<ISO2>.json one country per file
111
+ data/v1/states/<prefix>.json every subdivision whose code starts with <prefix> (US-CA is in states/US)
112
+ ```
113
+
114
+ - **Countries** are ISO 3166-1 alpha-2 codes from Natural Earth's de facto
115
+ worldview, plus `XK` (Kosovo) and two user-assigned codes: `XS` Somaliland and
116
+ `XN` Northern Cyprus. Territories the default file folds into a parent (`GF`,
117
+ `RE`, `SJ`, ...) are countries of their own while the parent keeps its geometry.
118
+ - **Subdivisions** are ISO 3166-2 codes (`US-CA`, `FR-IDF`, `GB-ENG`), filed by the
119
+ code's prefix, never by `adm0_a3` (which files Crimea under Russia and Puerto
120
+ Rico outside the US). First-level regions of FR, GB, IT, ES and PH are built from
121
+ Natural Earth's second-level units.
122
+ - **Unlisted features** (placeholders such as `SY-X01`, codeless `-99` units) are in
123
+ the files so a state map has no holes, and absent from `index.json`.
124
+ - **A feature** has `code`, `name`, `nameNl`, `parent`, `first`, `listed`, optional
125
+ `remote`, `area` (steradians), `mainland` (polygon indices, or `null` when all),
126
+ `areas` and `polygons` (rings of arc references; `~i` is arc `i` reversed).
127
+
128
+ ### Invariants
129
+
130
+ - **One topology.** Every country and subdivision is stitched and quantised
131
+ together (1e6 steps, one `transform` for every file), so a border two regions
132
+ share is one arc with one global id (`arcIds`) in every file that uses it, and
133
+ simplifies identically on both sides. The renderer relies on it to stroke the
134
+ border once.
135
+ - **Simplification is stored, not applied.** Each arc point is a triple
136
+ `x, y, bucket` (the first `x`, `y` absolute, the rest deltas). The bucket is
137
+ `clamp(round(-2 * log2(weight)), 1, 254)` of the point's spherical triangle area,
138
+ 0 for an arc's first and last point (so no detail setting can open a ring), and
139
+ 255 for a non-positive weight. `GeoBorder`'s `detail` is a draw-time threshold
140
+ over the bucket, so one set of files serves every detail.
141
+ - **No file is over 1.5 MiB**, so any one can be fetched alone (`verify`).
142
+ - **The format is in the path.** A change in meaning or removal of a field is a new
143
+ `data/v<N>/`, with `FORMAT` in `scripts/generate.mjs` and `scripts/verify.mjs` and
144
+ `GEO_DATA_FORMAT` in the geo kit's `src/border/format.ts` moving together; adding
145
+ a field is compatible with the kit's decoder, which ignores unknown ones.
146
+ - **`verify` checks structure and coverage, not provenance**: arc and index
147
+ integrity, endpoints, size, and minimum counts (249 countries, the 50 US states
148
+ and DC, FR, GB, IT, ES, CA, DE and AU first-level regions). It does not compare
149
+ the data with the lock or the generator.
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/border/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAEhC,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAA;AA0EhC,SAAS,SAAS,CAAC,OAAiB,EAAE,GAAW,EAAE,CAAC,EAAE,EAAE,EAAE,CAAmB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAmB;IACrG,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;IAChC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;IAC1C,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IACrC,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,CAAC,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACnB,CAAC,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QACvB,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAA;QAC3B,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAA;QAC/B,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IACnC,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AACnC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAA2B;IACvD,MAAM,GAAG,GAAuB,EAAE,CAAA;IAClC,KAAK,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAA;QAC5B,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAClC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACxD,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAA;AACd,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,QAAQ,CAAC,IAA2B;IAChD,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;IACzC,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAA;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IACrE,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,MAAM,+BAA+B,eAAe,GAAG,CAAC,CAAA;IACpG,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CACtC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CACrF,CAAA;IACD,MAAM,GAAG,GAAG,CAAC,KAAa,EAAc,EAAE,CACtC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IAE7F,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAA;IAC9C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACxD,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;YACjB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI;YAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,MAAM,EAAE,CAAC,CAAC,MAAM,KAAK,IAAI;YACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;gBAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;gBACnD,OAAO;oBACH,KAAK,EAAE,QAAQ;oBACf,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC7E,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;oBAChB,QAAQ,EAAE,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;iBACjD,CAAA;YACL,CAAC,CAAC;SACL,CAAC,CAAA;IACN,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAA;AACvB,CAAC","sourcesContent":["import { geoArea } from \"d3-geo\"\r\n\r\n/** The on-disk shape `@motionscript/geography` writes; see its `generate.mjs`. */\r\nexport const GEO_DATA_FORMAT = 1\r\n\r\nexport interface GeoFileData {\r\n format: number\r\n source?: string\r\n transform: { scale: [number, number]; translate: [number, number] }\r\n /** Global arc id per local arc — identical across files for a shared border. */\r\n arcIds: number[]\r\n /** Per arc, flat `[x0, y0, w0, dx, dy, w, …]`: delta-encoded quantized lon/lat and a weight bucket. */\r\n arcs: number[][]\r\n features: GeoFeatureData[]\r\n}\r\n\r\nexport interface GeoFeatureData {\r\n code: string\r\n name: string\r\n nameNl?: string\r\n parent: string | null\r\n first: boolean\r\n listed: boolean\r\n remote?: boolean\r\n area: number\r\n mainland: number[] | null\r\n areas: number[]\r\n /** Polygons → rings → arc refs (`~i` is arc `i` reversed). */\r\n polygons: number[][][]\r\n}\r\n\r\n/** `[code, name, nameNl, parent, first]` per listed region. */\r\nexport type GeoIndexEntry = [string, string, string, string | null, 0 | 1]\r\n\r\nexport interface GeoIndex {\r\n format: number\r\n source?: string\r\n regions: GeoIndexEntry[]\r\n}\r\n\r\nexport interface GeoArc {\r\n /** Identity for de-duplicating a border drawn by two regions, across files. */\r\n key: number | string\r\n /** Interleaved lon/lat, in degrees. */\r\n points: Float64Array\r\n /** Per point: 0 always survives, higher buckets are less significant; see `thresholdBucket`. */\r\n buckets: Uint8Array\r\n}\r\n\r\nexport interface GeoRingRef {\r\n arc: GeoArc\r\n reversed: boolean\r\n}\r\n\r\nexport interface GeoPolygon {\r\n rings: GeoRingRef[][]\r\n /** Per ring, in steradians — exterior first, then holes. */\r\n ringAreas: number[]\r\n area: number\r\n mainland: boolean\r\n}\r\n\r\nexport interface GeoFeature {\r\n code: string\r\n name: string\r\n nameNl: string\r\n parent: string | null\r\n first: boolean\r\n listed: boolean\r\n remote: boolean\r\n polygons: GeoPolygon[]\r\n}\r\n\r\nexport interface DecodedGeoFile {\r\n features: Map<string, GeoFeature>\r\n}\r\n\r\nfunction decodeArc(encoded: number[], key: number, [kx, ky]: [number, number], [tx, ty]: [number, number]): GeoArc {\r\n const count = encoded.length / 3\r\n const points = new Float64Array(count * 2)\r\n const buckets = new Uint8Array(count)\r\n let x = 0\r\n let y = 0\r\n for (let i = 0; i < count; i++) {\r\n x += encoded[i * 3]\r\n y += encoded[i * 3 + 1]\r\n points[i * 2] = x * kx + tx\r\n points[i * 2 + 1] = y * ky + ty\r\n buckets[i] = encoded[i * 3 + 2]\r\n }\r\n return { key, points, buckets }\r\n}\r\n\r\nexport function ringCoordinates(ring: readonly GeoRingRef[]): [number, number][] {\r\n const out: [number, number][] = []\r\n for (const { arc, reversed } of ring) {\r\n const n = arc.buckets.length\r\n for (let j = out.length === 0 ? 0 : 1; j < n; j++) {\r\n const i = reversed ? n - 1 - j : j\r\n out.push([arc.points[i * 2], arc.points[i * 2 + 1]])\r\n }\r\n }\r\n return out\r\n}\r\n\r\n/** A ring's area in steradians, whichever way it winds. */\r\nexport function ringArea(ring: readonly GeoRingRef[]): number {\r\n const coordinates = ringCoordinates(ring)\r\n if (coordinates.length < 4) return 0\r\n const area = geoArea({ type: \"Polygon\", coordinates: [coordinates] })\r\n return area > 2 * Math.PI ? 4 * Math.PI - area : area\r\n}\r\n\r\nexport function decodeGeoFile(data: GeoFileData): DecodedGeoFile {\r\n if (data.format !== GEO_DATA_FORMAT) {\r\n throw new Error(`geo data format ${data.format} is not supported (expected ${GEO_DATA_FORMAT})`)\r\n }\r\n const arcs = data.arcs.map((encoded, i) =>\r\n decodeArc(encoded, data.arcIds[i], data.transform.scale, data.transform.translate)\r\n )\r\n const ref = (index: number): GeoRingRef =>\r\n index < 0 ? { arc: arcs[~index], reversed: true } : { arc: arcs[index], reversed: false }\r\n\r\n const features = new Map<string, GeoFeature>()\r\n for (const f of data.features) {\r\n const mainland = f.mainland ? new Set(f.mainland) : null\r\n features.set(f.code, {\r\n code: f.code,\r\n name: f.name,\r\n nameNl: f.nameNl ?? f.name,\r\n parent: f.parent,\r\n first: f.first,\r\n listed: f.listed,\r\n remote: f.remote === true,\r\n polygons: f.polygons.map((rings, i) => {\r\n const resolved = rings.map((ring) => ring.map(ref))\r\n return {\r\n rings: resolved,\r\n ringAreas: resolved.map((ring, r) => (r === 0 ? f.areas[i] : ringArea(ring))),\r\n area: f.areas[i],\r\n mainland: mainland === null || mainland.has(i),\r\n }\r\n }),\r\n })\r\n }\r\n return { features }\r\n}\r\n"]}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/border/format.ts"],"names":[],"mappings":"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","sourcesContent":["import { geoArea } from \"d3-geo\"\n\n/** The on-disk shape `@motionscript/geography` writes; see its `generate.mjs`. */\nexport const GEO_DATA_FORMAT = 1\n\nexport interface GeoFileData {\n format: number\n source?: string\n transform: { scale: [number, number]; translate: [number, number] }\n /** Global arc id per local arc — identical across files for a shared border. */\n arcIds: number[]\n /** Per arc, flat `[x0, y0, w0, dx, dy, w, …]`: delta-encoded quantized lon/lat and a weight bucket. */\n arcs: number[][]\n features: GeoFeatureData[]\n}\n\nexport interface GeoFeatureData {\n code: string\n name: string\n nameNl?: string\n parent: string | null\n first: boolean\n listed: boolean\n remote?: boolean\n area: number\n mainland: number[] | null\n areas: number[]\n /** Polygons → rings → arc refs (`~i` is arc `i` reversed). */\n polygons: number[][][]\n}\n\n/** `[code, name, nameNl, parent, first]` per listed region. */\nexport type GeoIndexEntry = [string, string, string, string | null, 0 | 1]\n\nexport interface GeoIndex {\n format: number\n source?: string\n regions: GeoIndexEntry[]\n}\n\nexport interface GeoArc {\n /** Identity for de-duplicating a border drawn by two regions, across files. */\n key: number | string\n /** Interleaved lon/lat, in degrees. */\n points: Float64Array\n /** Per point: 0 always survives, higher buckets are less significant; see `thresholdBucket`. */\n buckets: Uint8Array\n}\n\nexport interface GeoRingRef {\n arc: GeoArc\n reversed: boolean\n}\n\nexport interface GeoPolygon {\n rings: GeoRingRef[][]\n /** Per ring, in steradians — exterior first, then holes. */\n ringAreas: number[]\n area: number\n mainland: boolean\n}\n\nexport interface GeoFeature {\n code: string\n name: string\n nameNl: string\n parent: string | null\n first: boolean\n listed: boolean\n remote: boolean\n polygons: GeoPolygon[]\n}\n\nexport interface DecodedGeoFile {\n features: Map<string, GeoFeature>\n}\n\nfunction decodeArc(encoded: number[], key: number, [kx, ky]: [number, number], [tx, ty]: [number, number]): GeoArc {\n const count = encoded.length / 3\n const points = new Float64Array(count * 2)\n const buckets = new Uint8Array(count)\n let x = 0\n let y = 0\n for (let i = 0; i < count; i++) {\n x += encoded[i * 3]\n y += encoded[i * 3 + 1]\n points[i * 2] = x * kx + tx\n points[i * 2 + 1] = y * ky + ty\n buckets[i] = encoded[i * 3 + 2]\n }\n return { key, points, buckets }\n}\n\nexport function ringCoordinates(ring: readonly GeoRingRef[]): [number, number][] {\n const out: [number, number][] = []\n for (const { arc, reversed } of ring) {\n const n = arc.buckets.length\n for (let j = out.length === 0 ? 0 : 1; j < n; j++) {\n const i = reversed ? n - 1 - j : j\n out.push([arc.points[i * 2], arc.points[i * 2 + 1]])\n }\n }\n return out\n}\n\n/** A ring's area in steradians, whichever way it winds. */\nexport function ringArea(ring: readonly GeoRingRef[]): number {\n const coordinates = ringCoordinates(ring)\n if (coordinates.length < 4) return 0\n const area = geoArea({ type: \"Polygon\", coordinates: [coordinates] })\n return area > 2 * Math.PI ? 4 * Math.PI - area : area\n}\n\nexport function decodeGeoFile(data: GeoFileData): DecodedGeoFile {\n if (data.format !== GEO_DATA_FORMAT) {\n throw new Error(`geo data format ${data.format} is not supported (expected ${GEO_DATA_FORMAT})`)\n }\n const arcs = data.arcs.map((encoded, i) =>\n decodeArc(encoded, data.arcIds[i], data.transform.scale, data.transform.translate)\n )\n const ref = (index: number): GeoRingRef =>\n index < 0 ? { arc: arcs[~index], reversed: true } : { arc: arcs[index], reversed: false }\n\n const features = new Map<string, GeoFeature>()\n for (const f of data.features) {\n const mainland = f.mainland ? new Set(f.mainland) : null\n features.set(f.code, {\n code: f.code,\n name: f.name,\n nameNl: f.nameNl ?? f.name,\n parent: f.parent,\n first: f.first,\n listed: f.listed,\n remote: f.remote === true,\n polygons: f.polygons.map((rings, i) => {\n const resolved = rings.map((ring) => ring.map(ref))\n return {\n rings: resolved,\n ringAreas: resolved.map((ring, r) => (r === 0 ? f.areas[i] : ringArea(ring))),\n area: f.areas[i],\n mainland: mainland === null || mainland.has(i),\n }\n }),\n })\n }\n return { features }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"geo-border.js","sourceRoot":"","sources":["../../src/border/geo-border.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n Flow,\r\n Graphics2D,\r\n Paint,\r\n Shapes,\r\n Types,\r\n component2d,\r\n type EntryOptions,\r\n type FillResolved,\r\n type NodeOf,\r\n // Named so this component's emitted type reaches the shape surface it spreads through the sdk, not core.\r\n type Alignment as _Alignment,\r\n type Fill as _Fill,\r\n type FlowMode as _FlowMode,\r\n type FlowResolved as _FlowResolved,\r\n type GapSize as _GapSize,\r\n type Node2D as _Node2D,\r\n type Node2DProps as _Node2DProps,\r\n type Shadow as _Shadow,\r\n type Stroke as _Stroke,\r\n type Vector2 as _Vector2,\r\n type PathBounds,\r\n type ShadowResolved,\r\n type ShapeProps,\r\n type Size2D,\r\n type StrokeResolved,\r\n type Type,\r\n} from \"@motionscript/sdk\"\r\nimport { snapValue } from \"@motionscript/sdk/component\"\r\n\r\nimport { geoGeometry, type GeoBorders, type GeoContour, type GeoGeometry, type GeoProjectionKind } from \"./geometry\"\r\nimport { geoDataVersion, geoLoader } from \"./loader\"\r\nimport { geoRegistry } from \"./registry\"\r\nimport { geoFilesFor, normalizeIso, selectGeoFeatures, type GeoFrame, type GeoLevel } from \"./selection\"\r\n\r\nexport interface GeoBorderProps extends ShapeProps {\r\n /** ISO 3166-1 alpha-2 (`\"FR\"`) or ISO 3166-2 (`\"US-CA\"`) codes. */\r\n iso: string | readonly string[]\r\n level: GeoLevel\r\n /** 0–1: 1 is full resolution, lower is a more stylised outline. */\r\n detail: number\r\n projection: GeoProjectionKind\r\n frame: GeoFrame\r\n borders: GeoBorders\r\n}\r\n\r\ninterface Chunk {\r\n data: string\r\n /** Where this chunk's contours sit along the whole drawing, as fractions of its length. */\r\n from: number\r\n to: number\r\n}\r\n\r\ninterface Drawn {\r\n geometry: GeoGeometry\r\n width: number\r\n height: number\r\n fills: Chunk[]\r\n lines: Chunk[]\r\n}\r\n\r\n// A renderer's cost for one path grows faster than its contour count, and a shape\r\n// drawn as several paths under one paint is unioned every frame — so a region\r\n// is cut into paths of bounded size, each painted on its own.\r\nconst CONTOURS_PER_PATH = 256\r\nconst POINTS_PER_PATH = 40_000\r\n\r\nconst coordinate = (value: number) => String(Math.round(value * 100) / 100)\r\n\r\nfunction chunk(contours: readonly GeoContour[], total: number, scale: number): Chunk[] {\r\n const chunks: Chunk[] = []\r\n let parts: string[] = []\r\n let count = 0\r\n let points = 0\r\n let from = 0\r\n let length = 0\r\n const flush = () => {\r\n if (count === 0) return\r\n const to = total > 0 ? Math.min(1, length / total) : 1\r\n chunks.push({ data: parts.join(\"\"), from, to })\r\n from = to\r\n parts = []\r\n count = 0\r\n points = 0\r\n }\r\n for (const contour of contours) {\r\n const p = contour.points\r\n // Path data is y-down; the unit geometry is y-up.\r\n for (let i = 0; i < p.length; i += 2) {\r\n parts.push(i === 0 ? \"M\" : \"L\", coordinate(p[i] * scale), \" \", coordinate(-p[i + 1] * scale))\r\n }\r\n if (contour.closed) parts.push(\"Z\")\r\n count++\r\n points += p.length / 2\r\n length += contour.length\r\n if (count >= CONTOURS_PER_PATH || points >= POINTS_PER_PATH) flush()\r\n }\r\n flush()\r\n return chunks\r\n}\r\n\r\n/** One of `values`, switched at the end of a `to`, with its choices listed as its `options`. */\r\nfunction choice<const V extends readonly string[]>(values: V, initial: V[number]): Type<V[number]> {\r\n return Types.custom<V[number], V[number], EntryOptions & { readonly options: V }>(initial, { lerp: snapValue, options: values })\r\n}\r\n\r\n/** A node's own drawing state, kept by its fields' view (one object per node, the same every frame). */\r\ninterface Kept {\r\n drawn: Drawn | null\r\n readonly warned: Set<string>\r\n}\r\n\r\nconst kept = new WeakMap<object, Kept>()\r\n\r\nfunction keptBy(state: object): Kept {\r\n let entry = kept.get(state)\r\n if (!entry) kept.set(state, (entry = { drawn: null, warned: new Set() }))\r\n return entry\r\n}\r\n\r\ninterface Selected {\r\n readonly iso: readonly string[]\r\n readonly level: GeoLevel\r\n readonly frame: GeoFrame\r\n readonly projection: GeoProjectionKind\r\n readonly borders: GeoBorders\r\n readonly detail: number\r\n}\r\n\r\n/** The selection's outlines cut into paths at `size`, or `null` while there is nothing to draw. */\r\nfunction drawnOf(state: Selected, size: Size2D): Drawn | null {\r\n const own = keptBy(state)\r\n const codes = state.iso\r\n const { level, frame } = state\r\n const selection = selectGeoFeatures(codes, level, frame)\r\n for (const code of selection.unknown) {\r\n if (own.warned.has(code)) continue\r\n own.warned.add(code)\r\n console.warn(`[GeoBorder] no region with code ${code}`)\r\n }\r\n if (selection.features.length === 0) return null\r\n\r\n const geometry = geoGeometry({\r\n selectionKey: `${geoRegistry.generation}:${geoDataVersion()}:${level}:${frame}:${codes.join(\",\")}`,\r\n features: selection.features,\r\n frame,\r\n projection: state.projection,\r\n borders: state.borders,\r\n detail: state.detail,\r\n })\r\n if (!geometry) return null\r\n\r\n const { width, height } = size\r\n const cached = own.drawn\r\n if (cached && cached.geometry === geometry && cached.width === width && cached.height === height) return cached\r\n const scale = Math.min(width / geometry.width, height / geometry.height)\r\n const drawn: Drawn = {\r\n geometry,\r\n width,\r\n height,\r\n fills: chunk(geometry.fills, geometry.fillLength, scale),\r\n lines: chunk(geometry.lines, geometry.lineLength, scale),\r\n }\r\n own.drawn = drawn\r\n return drawn\r\n}\r\n\r\n/** Adds `chunk` to `g`, trimmed by `start`/`end` along the whole drawing; `false` when none of it is drawn. */\r\nfunction pathOp(g: Graphics2D, chunk: Chunk, size: Size2D, start: number, end: number): boolean {\r\n const { width, height } = size\r\n const centerBounds: PathBounds = [-width / 2, -height / 2, width / 2, height / 2]\r\n if (start <= 0 && end >= 1) {\r\n g.path({ data: chunk.data, centerBounds })\r\n return true\r\n }\r\n const span = chunk.to - chunk.from\r\n if (span <= 0) return false\r\n const localStart = Math.max(0, (start - chunk.from) / span)\r\n const localEnd = Math.min(1, (end - chunk.from) / span)\r\n if (localEnd <= localStart) return false\r\n g.path({ data: chunk.data, centerBounds, start: localStart, end: localEnd })\r\n return true\r\n}\r\n\r\n/**\r\n * Country and subdivision outlines by ISO 3166 code, fitted into the node's box.\r\n *\r\n * <GeoBorder iso={[\"FR\", \"DE\"]} detail={0.4} stroke={{ weight: 2, fill: \"white\" }} />\r\n *\r\n * Geometry comes from whatever `geoRegistry` has been given — a URL, a loader,\r\n * or shapes defined by hand — and loads as a declared asset, so a frame never\r\n * draws half a country. Fill and stroke are separate geometry: the fill is each\r\n * region's polygons, the stroke is every border once, which is why a border two\r\n * selected regions share is not drawn twice and why `stroke.align` does not\r\n * apply.\r\n */\r\nexport const GeoBorder = component2d({\r\n key: \"geoBorder\",\r\n state: {\r\n ...Paint.state,\r\n ...Flow.state,\r\n iso: Types.custom<string | readonly string[], string[]>([\"FR\"], { resolve: normalizeIso, lerp: snapValue }),\r\n level: choice([\"country\", \"state\"], \"country\"),\r\n detail: Types.number(0.5, { min: 0, max: 1, step: 0.01 }),\r\n projection: choice([\"conic\", \"mercator\", \"equirectangular\", \"orthographic\"], \"conic\"),\r\n frame: choice([\"mainland\", \"all\"], \"mainland\"),\r\n borders: choice([\"all\", \"outline\"], \"all\"),\r\n },\r\n commands: { ...Paint.commands },\r\n // The data gates the draw, not layout: the box never waits on it.\r\n load: (loader, state) => {\r\n for (const file of geoFilesFor(state.iso, state.level)) loader.task(`geo:${file}`, geoLoader(file))\r\n },\r\n measure: (measurer, state, children) => Flow.measure(measurer, state, children, Paint.inset(state)),\r\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\r\n render: (ctx, state) => {\r\n const size = ctx.size\r\n const { start, end } = state\r\n const fill = state.fill as FillResolved[]\r\n const shadow = state.shadow as ShadowResolved[]\r\n const drawn = () => drawnOf(state, size)\r\n\r\n ctx.inFront(() => {\r\n const shape = drawn()\r\n if (!shape || shape.fills.length === 0) return\r\n const g = new Graphics2D()\r\n for (const part of shape.fills) {\r\n if (!pathOp(g, part, size, start, end)) continue\r\n if (shadow.length > 0) g.shadow(shadow)\r\n g.fill(fill)\r\n }\r\n ctx.draw(g)\r\n })\r\n\r\n // The box, not the outline, confines the children and is what picking\r\n // tests: a path clip has no winding test, and a country's bounding box is\r\n // what the selection shows.\r\n Paint.draw(ctx, state, null, { clipShape: Shapes.box(size) })\r\n\r\n ctx.inFront(() => {\r\n const overlay = state.overlay as FillResolved[]\r\n if (overlay.length > 0) {\r\n const shape = drawn()\r\n if (shape) {\r\n const g = new Graphics2D()\r\n for (const part of shape.fills) if (pathOp(g, part, size, start, end)) g.fill(overlay)\r\n ctx.draw(g)\r\n }\r\n }\r\n\r\n const stroke = state.stroke as StrokeResolved[]\r\n if (stroke.length === 0) return\r\n const shape = drawn()\r\n if (!shape || shape.lines.length === 0) return\r\n const centred = stroke.map((layer) => (layer.align === 0 ? layer : { ...layer, align: 0 }))\r\n const castsShadow = shadow.length > 0 && !fill.some((layer) => (layer.opacity ?? 1) > 0)\r\n const g = new Graphics2D()\r\n for (const part of shape.lines) {\r\n if (!pathOp(g, part, size, start, end)) continue\r\n if (castsShadow) g.shadow(shadow)\r\n g.stroke(centred)\r\n }\r\n ctx.draw(g)\r\n })\r\n },\r\n})\r\n\r\nexport type GeoBorder = NodeOf<typeof GeoBorder>\r\n"]}
1
+ {"version":3,"file":"geo-border.js","sourceRoot":"","sources":["../../src/border/geo-border.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Flow,\n Graphics2D,\n Paint,\n Shapes,\n Types,\n component2d,\n type EntryOptions,\n type FillResolved,\n type NodeOf,\n // Named so this component's emitted type reaches the shape surface it spreads through the sdk, not core.\n type Alignment as _Alignment,\n type Fill as _Fill,\n type FlowMode as _FlowMode,\n type FlowResolved as _FlowResolved,\n type GapSize as _GapSize,\n type Node2D as _Node2D,\n type Node2DProps as _Node2DProps,\n type Shadow as _Shadow,\n type Stroke as _Stroke,\n type Vector2 as _Vector2,\n type PathBounds,\n type ShadowResolved,\n type ShapeProps,\n type Size2D,\n type StrokeResolved,\n type Type,\n} from \"@motionscript/sdk\"\nimport { snapValue } from \"@motionscript/sdk/component\"\n\nimport { geoGeometry, type GeoBorders, type GeoContour, type GeoGeometry, type GeoProjectionKind } from \"./geometry\"\nimport { geoDataVersion, geoLoader } from \"./loader\"\nimport { geoRegistry } from \"./registry\"\nimport { geoFilesFor, normalizeIso, selectGeoFeatures, type GeoFrame, type GeoLevel } from \"./selection\"\n\nexport interface GeoBorderProps extends ShapeProps {\n /** ISO 3166-1 alpha-2 (`\"FR\"`) or ISO 3166-2 (`\"US-CA\"`) codes. */\n iso: string | readonly string[]\n level: GeoLevel\n /** 0–1: 1 is full resolution, lower is a more stylised outline. */\n detail: number\n projection: GeoProjectionKind\n frame: GeoFrame\n borders: GeoBorders\n}\n\ninterface Chunk {\n data: string\n /** Where this chunk's contours sit along the whole drawing, as fractions of its length. */\n from: number\n to: number\n}\n\ninterface Drawn {\n geometry: GeoGeometry\n width: number\n height: number\n fills: Chunk[]\n lines: Chunk[]\n}\n\n// A renderer's cost for one path grows faster than its contour count, and a shape\n// drawn as several paths under one paint is unioned every frame — so a region\n// is cut into paths of bounded size, each painted on its own.\nconst CONTOURS_PER_PATH = 256\nconst POINTS_PER_PATH = 40_000\n\nconst coordinate = (value: number) => String(Math.round(value * 100) / 100)\n\nfunction chunk(contours: readonly GeoContour[], total: number, scale: number): Chunk[] {\n const chunks: Chunk[] = []\n let parts: string[] = []\n let count = 0\n let points = 0\n let from = 0\n let length = 0\n const flush = () => {\n if (count === 0) return\n const to = total > 0 ? Math.min(1, length / total) : 1\n chunks.push({ data: parts.join(\"\"), from, to })\n from = to\n parts = []\n count = 0\n points = 0\n }\n for (const contour of contours) {\n const p = contour.points\n // Path data is y-down; the unit geometry is y-up.\n for (let i = 0; i < p.length; i += 2) {\n parts.push(i === 0 ? \"M\" : \"L\", coordinate(p[i] * scale), \" \", coordinate(-p[i + 1] * scale))\n }\n if (contour.closed) parts.push(\"Z\")\n count++\n points += p.length / 2\n length += contour.length\n if (count >= CONTOURS_PER_PATH || points >= POINTS_PER_PATH) flush()\n }\n flush()\n return chunks\n}\n\n/** One of `values`, switched at the end of a `to`, with its choices listed as its `options`. */\nfunction choice<const V extends readonly string[]>(values: V, initial: V[number]): Type<V[number]> {\n return Types.custom<V[number], V[number], EntryOptions & { readonly options: V }>(initial, { lerp: snapValue, options: values })\n}\n\n/** A node's own drawing state, kept by its fields' view (one object per node, the same every frame). */\ninterface Kept {\n drawn: Drawn | null\n readonly warned: Set<string>\n}\n\nconst kept = new WeakMap<object, Kept>()\n\nfunction keptBy(state: object): Kept {\n let entry = kept.get(state)\n if (!entry) kept.set(state, (entry = { drawn: null, warned: new Set() }))\n return entry\n}\n\ninterface Selected {\n readonly iso: readonly string[]\n readonly level: GeoLevel\n readonly frame: GeoFrame\n readonly projection: GeoProjectionKind\n readonly borders: GeoBorders\n readonly detail: number\n}\n\n/** The selection's outlines cut into paths at `size`, or `null` while there is nothing to draw. */\nfunction drawnOf(state: Selected, size: Size2D): Drawn | null {\n const own = keptBy(state)\n const codes = state.iso\n const { level, frame } = state\n const selection = selectGeoFeatures(codes, level, frame)\n for (const code of selection.unknown) {\n if (own.warned.has(code)) continue\n own.warned.add(code)\n console.warn(`[GeoBorder] no region with code ${code}`)\n }\n if (selection.features.length === 0) return null\n\n const geometry = geoGeometry({\n selectionKey: `${geoRegistry.generation}:${geoDataVersion()}:${level}:${frame}:${codes.join(\",\")}`,\n features: selection.features,\n frame,\n projection: state.projection,\n borders: state.borders,\n detail: state.detail,\n })\n if (!geometry) return null\n\n const { width, height } = size\n const cached = own.drawn\n if (cached && cached.geometry === geometry && cached.width === width && cached.height === height) return cached\n const scale = Math.min(width / geometry.width, height / geometry.height)\n const drawn: Drawn = {\n geometry,\n width,\n height,\n fills: chunk(geometry.fills, geometry.fillLength, scale),\n lines: chunk(geometry.lines, geometry.lineLength, scale),\n }\n own.drawn = drawn\n return drawn\n}\n\n/** Adds `chunk` to `g`, trimmed by `start`/`end` along the whole drawing; `false` when none of it is drawn. */\nfunction pathOp(g: Graphics2D, chunk: Chunk, size: Size2D, start: number, end: number): boolean {\n const { width, height } = size\n const centerBounds: PathBounds = [-width / 2, -height / 2, width / 2, height / 2]\n if (start <= 0 && end >= 1) {\n g.path({ data: chunk.data, centerBounds })\n return true\n }\n const span = chunk.to - chunk.from\n if (span <= 0) return false\n const localStart = Math.max(0, (start - chunk.from) / span)\n const localEnd = Math.min(1, (end - chunk.from) / span)\n if (localEnd <= localStart) return false\n g.path({ data: chunk.data, centerBounds, start: localStart, end: localEnd })\n return true\n}\n\n/**\n * Country and subdivision outlines by ISO 3166 code, fitted into the node's box.\n *\n * <GeoBorder iso={[\"FR\", \"DE\"]} detail={0.4} stroke={{ weight: 2, fill: \"white\" }} />\n *\n * Geometry comes from whatever `geoRegistry` has been given — a URL, a loader,\n * or shapes defined by hand — and loads as a declared asset, so a frame never\n * draws half a country. Fill and stroke are separate geometry: the fill is each\n * region's polygons, the stroke is every border once, which is why a border two\n * selected regions share is not drawn twice and why `stroke.align` does not\n * apply.\n */\nexport const GeoBorder = component2d({\n key: \"geoBorder\",\n state: {\n ...Paint.state,\n ...Flow.state,\n iso: Types.custom<string | readonly string[], string[]>([\"FR\"], { resolve: normalizeIso, lerp: snapValue }),\n level: choice([\"country\", \"state\"], \"country\"),\n detail: Types.number(0.5, { min: 0, max: 1, step: 0.01 }),\n projection: choice([\"conic\", \"mercator\", \"equirectangular\", \"orthographic\"], \"conic\"),\n frame: choice([\"mainland\", \"all\"], \"mainland\"),\n borders: choice([\"all\", \"outline\"], \"all\"),\n },\n commands: { ...Paint.commands },\n // The data gates the draw, not layout: the box never waits on it.\n load: (loader, state) => {\n for (const file of geoFilesFor(state.iso, state.level)) loader.task(`geo:${file}`, geoLoader(file))\n },\n measure: (measurer, state, children) => Flow.measure(measurer, state, children, Paint.inset(state)),\n layout: (box, state, children) => Flow.layout(box, state, children, Paint.inset(state)),\n render: (ctx, state) => {\n const size = ctx.size\n const { start, end } = state\n const fill = state.fill as FillResolved[]\n const shadow = state.shadow as ShadowResolved[]\n const drawn = () => drawnOf(state, size)\n\n ctx.inFront(() => {\n const shape = drawn()\n if (!shape || shape.fills.length === 0) return\n const g = new Graphics2D()\n for (const part of shape.fills) {\n if (!pathOp(g, part, size, start, end)) continue\n if (shadow.length > 0) g.shadow(shadow)\n g.fill(fill)\n }\n ctx.draw(g)\n })\n\n // The box, not the outline, confines the children and is what picking\n // tests: a path clip has no winding test, and a country's bounding box is\n // what the selection shows.\n Paint.draw(ctx, state, null, { clipShape: Shapes.box(size) })\n\n ctx.inFront(() => {\n const overlay = state.overlay as FillResolved[]\n if (overlay.length > 0) {\n const shape = drawn()\n if (shape) {\n const g = new Graphics2D()\n for (const part of shape.fills) if (pathOp(g, part, size, start, end)) g.fill(overlay)\n ctx.draw(g)\n }\n }\n\n const stroke = state.stroke as StrokeResolved[]\n if (stroke.length === 0) return\n const shape = drawn()\n if (!shape || shape.lines.length === 0) return\n const centred = stroke.map((layer) => (layer.align === 0 ? layer : { ...layer, align: 0 }))\n const castsShadow = shadow.length > 0 && !fill.some((layer) => (layer.opacity ?? 1) > 0)\n const g = new Graphics2D()\n for (const part of shape.lines) {\n if (!pathOp(g, part, size, start, end)) continue\n if (castsShadow) g.shadow(shadow)\n g.stroke(centred)\n }\n ctx.draw(g)\n })\n },\n})\n\nexport type GeoBorder = NodeOf<typeof GeoBorder>\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../src/border/geometry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n geoArea,\r\n geoBounds,\r\n geoConicEqualArea,\r\n geoEquirectangular,\r\n geoMercator,\r\n geoOrthographic,\r\n geoPath,\r\n geoStream,\r\n type GeoPermissibleObjects,\r\n type GeoProjection,\r\n} from \"d3-geo\"\r\n\r\nimport { ringCoordinates, type GeoArc, type GeoFeature, type GeoPolygon, type GeoRingRef } from \"./format\"\r\nimport type { GeoFrame } from \"./selection\"\r\n\r\nexport type GeoProjectionKind = \"conic\" | \"mercator\" | \"equirectangular\" | \"orthographic\"\r\nexport type GeoBorders = \"all\" | \"outline\"\r\n\r\nexport interface GeoContour {\r\n /** Interleaved x/y in unit space: the longer side spans 1, centred on the origin, y up. */\r\n points: Float32Array\r\n closed: boolean\r\n length: number\r\n}\r\n\r\nexport interface GeoGeometry {\r\n /** The drawing's extent in unit space; the longer of the two is 1. */\r\n width: number\r\n height: number\r\n fills: GeoContour[]\r\n lines: GeoContour[]\r\n fillLength: number\r\n lineLength: number\r\n bytes: number\r\n}\r\n\r\ninterface Part {\r\n polygon: GeoPolygon\r\n largest: boolean\r\n}\r\n\r\ninterface Frame {\r\n projection: GeoProjection\r\n centerX: number\r\n centerY: number\r\n size: number\r\n width: number\r\n height: number\r\n}\r\n\r\nconst FIT = 1024\r\n\r\n// `detail` maps onto a weight threshold that is a fraction of the selection's\r\n// own area, on a log scale — which is what makes a value look equally stylised\r\n// on Monaco and on Russia. 0 keeps points worth 1% of the area; just below 1,\r\n// points worth a billionth of it.\r\nconst POINT_BASE = 2\r\nconst POINT_RANGE = 7\r\nconst POLYGON_BASE = 1.5\r\nconst POLYGON_RANGE = 6\r\n\r\nconst clamp01 = (value: number) => (value > 1 ? 1 : value > 0 ? value : 0)\r\n\r\n/** The highest weight bucket a point may carry and still be drawn. */\r\nexport function pointBucketLimit(detail: number, area: number): number {\r\n if (detail >= 1 || !(area > 0)) return 255\r\n const minWeight = area * 10 ** -(POINT_BASE + POINT_RANGE * clamp01(detail))\r\n return Math.floor(-2 * Math.log2(minWeight))\r\n}\r\n\r\n/** Rings smaller than this (steradians) are dropped, bar each region's largest. */\r\nexport function polygonAreaLimit(detail: number, area: number): number {\r\n if (detail >= 1) return 0\r\n return area * 10 ** -(POLYGON_BASE + POLYGON_RANGE * clamp01(detail))\r\n}\r\n\r\nfunction partsOf(features: readonly GeoFeature[], frame: GeoFrame): Part[] {\r\n const parts: Part[] = []\r\n for (const feature of features) {\r\n const mainland = frame === \"mainland\" ? feature.polygons.filter((p) => p.mainland) : []\r\n const polygons = mainland.length > 0 ? mainland : feature.polygons\r\n let largest: GeoPolygon | null = null\r\n for (const polygon of polygons) if (!largest || polygon.area > largest.area) largest = polygon\r\n for (const polygon of polygons) parts.push({ polygon, largest: polygon === largest })\r\n }\r\n return parts\r\n}\r\n\r\nfunction centerLongitude(west: number, east: number): number {\r\n if (west <= east) return (west + east) / 2\r\n const mid = (west + east + 360) / 2\r\n return mid > 180 ? mid - 360 : mid\r\n}\r\n\r\nfunction makeProjection(kind: GeoProjectionKind, west: number, south: number, east: number, north: number): GeoProjection {\r\n const lon = centerLongitude(west, east)\r\n const lat = (south + north) / 2\r\n switch (kind) {\r\n case \"mercator\":\r\n return geoMercator().rotate([-lon, 0])\r\n case \"equirectangular\":\r\n return geoEquirectangular().rotate([-lon, 0])\r\n case \"orthographic\":\r\n return geoOrthographic().rotate([-lon, -lat])\r\n case \"conic\": {\r\n const span = north - south\r\n return geoConicEqualArea()\r\n .rotate([-lon, 0])\r\n .center([0, lat])\r\n .parallels([south + span / 6, north - span / 6])\r\n }\r\n }\r\n}\r\n\r\nfunction fitFrame(kind: GeoProjectionKind, parts: readonly Part[]): Frame | null {\r\n if (parts.length === 0) return null\r\n const shape = {\r\n type: \"MultiPolygon\",\r\n coordinates: parts.map(({ polygon }) => [ringCoordinates(polygon.rings[0])]),\r\n } as GeoPermissibleObjects\r\n const [[west, south], [east, north]] = geoBounds(shape)\r\n\r\n for (const candidate of [kind, \"equirectangular\"] as const) {\r\n const projection = makeProjection(candidate, west, south, east, north).fitSize([FIT, FIT], shape)\r\n const [[x0, y0], [x1, y1]] = geoPath(projection).bounds(shape)\r\n const size = Math.max(x1 - x0, y1 - y0)\r\n if (!Number.isFinite(size) || size <= 0) continue\r\n return {\r\n projection,\r\n centerX: (x0 + x1) / 2,\r\n centerY: (y0 + y1) / 2,\r\n size,\r\n width: (x1 - x0) / size,\r\n height: (y1 - y0) / size,\r\n }\r\n }\r\n return null\r\n}\r\n\r\nfunction project(frame: Frame, object: GeoPermissibleObjects, closed: boolean): GeoContour[] {\r\n const contours: GeoContour[] = []\r\n let current: number[] | null = null\r\n const { centerX, centerY, size } = frame\r\n const sink = {\r\n point(x: number, y: number) {\r\n current?.push((x - centerX) / size, -(y - centerY) / size)\r\n },\r\n lineStart() {\r\n current = []\r\n },\r\n lineEnd() {\r\n const flat = current\r\n current = null\r\n if (!flat || flat.length < 4) return\r\n let isClosed = closed\r\n if (!closed) {\r\n const n = flat.length\r\n if (flat[0] === flat[n - 2] && flat[1] === flat[n - 1] && n >= 8) {\r\n flat.length = n - 2\r\n isClosed = true\r\n }\r\n }\r\n const points = Float32Array.from(flat)\r\n contours.push({ points, closed: isClosed, length: contourLength(points, isClosed) })\r\n },\r\n polygonStart() {},\r\n polygonEnd() {},\r\n sphere() {},\r\n }\r\n geoStream(object, frame.projection.stream(sink))\r\n return contours\r\n}\r\n\r\nfunction contourLength(points: Float32Array, closed: boolean): number {\r\n let length = 0\r\n const n = points.length / 2\r\n for (let i = 1; i < n; i++) {\r\n length += Math.hypot(points[i * 2] - points[i * 2 - 2], points[i * 2 + 1] - points[i * 2 - 1])\r\n }\r\n if (closed && n > 1) length += Math.hypot(points[0] - points[n * 2 - 2], points[1] - points[n * 2 - 1])\r\n return length\r\n}\r\n\r\n// Longest edge, in degrees, that simplification may leave. d3 takes an edge as\r\n// the short way round the sphere, so an edge across more than half the planet\r\n// (Kaliningrad to Chukotka, once the coast between is dropped) turns inside out.\r\nconst MAX_EDGE_DEGREES = 20\r\n\r\ntype MaskFor = (arc: GeoArc) => Uint8Array\r\n\r\n/** Which of an arc's points survive `limit`, the same whichever way the arc is walked. */\r\nfunction keepMask(arc: GeoArc, limit: number): Uint8Array {\r\n const n = arc.buckets.length\r\n const mask = new Uint8Array(n)\r\n let lastLon = arc.points[0]\r\n let lastLat = arc.points[1]\r\n for (let i = 0; i < n; i++) {\r\n const lon = arc.points[i * 2]\r\n const lat = arc.points[i * 2 + 1]\r\n let far = false\r\n if (arc.buckets[i] > limit) {\r\n let dLon = Math.abs(lon - lastLon)\r\n if (dLon > 180) dLon = 360 - dLon\r\n far = Math.abs(lat - lastLat) > MAX_EDGE_DEGREES || dLon * Math.cos((lat * Math.PI) / 180) > MAX_EDGE_DEGREES\r\n }\r\n if (arc.buckets[i] <= limit || far) {\r\n mask[i] = 1\r\n lastLon = lon\r\n lastLat = lat\r\n }\r\n }\r\n return mask\r\n}\r\n\r\nfunction filteredPoints(refs: readonly GeoRingRef[], maskFor: MaskFor): [number, number][] {\r\n const out: [number, number][] = []\r\n for (const { arc, reversed } of refs) {\r\n const n = arc.buckets.length\r\n const mask = maskFor(arc)\r\n for (let j = out.length === 0 ? 0 : 1; j < n; j++) {\r\n const i = reversed ? n - 1 - j : j\r\n if (mask[i]) out.push([arc.points[i * 2], arc.points[i * 2 + 1]])\r\n }\r\n }\r\n return out\r\n}\r\n\r\n/** A ring keeps at least three vertices, raising its arcs' limits if the global one would collapse it. */\r\nfunction ringLimit(ring: readonly GeoRingRef[], limit: number): number {\r\n let kept = 0\r\n for (const { arc } of ring) {\r\n for (let i = 0; i < arc.buckets.length - 1; i++) if (arc.buckets[i] <= limit) kept++\r\n }\r\n if (kept >= 3) return limit\r\n const buckets: number[] = []\r\n for (const { arc } of ring) for (let i = 0; i < arc.buckets.length - 1; i++) buckets.push(arc.buckets[i])\r\n buckets.sort((a, b) => a - b)\r\n return Math.max(limit, buckets[Math.min(2, buckets.length - 1)] ?? limit)\r\n}\r\n\r\n/**\r\n * Whether a simplified ring still winds the way its original did. Dropping\r\n * points can fold a small ring over itself, and d3 reads an exterior wound the\r\n * wrong way as the rest of the planet — one such island fills the whole frame.\r\n */\r\nfunction windsAsOriginal(ring: [number, number][], exterior: boolean): boolean {\r\n if (ring.length < 4) return true\r\n const inverted = geoArea({ type: \"Polygon\", coordinates: [ring] }) > 2 * Math.PI\r\n return inverted !== exterior\r\n}\r\n\r\ninterface Chain {\r\n refs: GeoRingRef[]\r\n closed: boolean\r\n}\r\n\r\nconst endKey = (arc: GeoArc, last: boolean) => {\r\n const i = last ? arc.buckets.length - 1 : 0\r\n return `${arc.points[i * 2]},${arc.points[i * 2 + 1]}`\r\n}\r\n\r\n/** Joins arcs that meet end to end with nothing else at the joint, so a border draws as one line with real joins. */\r\nfunction chainArcs(arcs: readonly GeoArc[]): Chain[] {\r\n const atNode = new Map<string, GeoArc[]>()\r\n for (const arc of arcs) {\r\n for (const key of [endKey(arc, false), endKey(arc, true)]) {\r\n const list = atNode.get(key)\r\n if (list) list.push(arc)\r\n else atNode.set(key, [arc])\r\n }\r\n }\r\n const visited = new Set<GeoArc>()\r\n const chains: Chain[] = []\r\n const refStart = ({ arc, reversed }: GeoRingRef) => endKey(arc, reversed)\r\n const refEnd = ({ arc, reversed }: GeoRingRef) => endKey(arc, !reversed)\r\n const nextAt = (node: string): GeoArc | null => {\r\n const list = atNode.get(node)!\r\n if (list.length !== 2) return null\r\n return list.find((arc) => !visited.has(arc)) ?? null\r\n }\r\n\r\n for (const arc of arcs) {\r\n if (visited.has(arc)) continue\r\n visited.add(arc)\r\n const refs: GeoRingRef[] = [{ arc, reversed: false }]\r\n for (let next = nextAt(refEnd(refs[refs.length - 1])); next; next = nextAt(refEnd(refs[refs.length - 1]))) {\r\n visited.add(next)\r\n refs.push({ arc: next, reversed: endKey(next, false) !== refEnd(refs[refs.length - 1]) })\r\n }\r\n for (let prev = nextAt(refStart(refs[0])); prev; prev = nextAt(refStart(refs[0]))) {\r\n visited.add(prev)\r\n refs.unshift({ arc: prev, reversed: endKey(prev, true) !== refStart(refs[0]) })\r\n }\r\n chains.push({ refs, closed: refStart(refs[0]) === refEnd(refs[refs.length - 1]) })\r\n }\r\n return chains\r\n}\r\n\r\nfunction buildGeometry(\r\n features: readonly GeoFeature[],\r\n frame: GeoFrame,\r\n fitted: Frame,\r\n borders: GeoBorders,\r\n detail: number\r\n): GeoGeometry {\r\n const parts = partsOf(features, frame)\r\n const area = parts.reduce((sum, { polygon }) => sum + polygon.area, 0)\r\n const pointLimit = pointBucketLimit(detail, area)\r\n const polygonLimit = polygonAreaLimit(detail, area)\r\n\r\n const kept: GeoRingRef[][][] = []\r\n for (const { polygon, largest } of parts) {\r\n if (!largest && polygon.area < polygonLimit) continue\r\n kept.push(polygon.rings.filter((_, i) => i === 0 || polygon.ringAreas[i] >= polygonLimit))\r\n }\r\n\r\n const limits = new Map<GeoArc[\"key\"], number>()\r\n const usage = new Map<GeoArc[\"key\"], { arc: GeoArc; count: number }>()\r\n for (const rings of kept) {\r\n for (const ring of rings) {\r\n const limit = ringLimit(ring, pointLimit)\r\n for (const { arc } of ring) {\r\n limits.set(arc.key, Math.max(limits.get(arc.key) ?? 0, limit))\r\n const use = usage.get(arc.key)\r\n if (use) use.count++\r\n else usage.set(arc.key, { arc, count: 1 })\r\n }\r\n }\r\n }\r\n\r\n const masks = new Map<GeoArc[\"key\"], Uint8Array>()\r\n const maskFor: MaskFor = (arc) => {\r\n let mask = masks.get(arc.key)\r\n if (!mask) {\r\n mask = keepMask(arc, limits.get(arc.key) ?? 255)\r\n masks.set(arc.key, mask)\r\n }\r\n return mask\r\n }\r\n\r\n if (pointLimit < 255) {\r\n for (const rings of kept) {\r\n rings.forEach((ring, index) => {\r\n let limit = Math.min(...ring.map(({ arc }) => limits.get(arc.key) ?? pointLimit))\r\n while (limit < 255 && !windsAsOriginal(filteredPoints(ring, maskFor), index === 0)) {\r\n limit = Math.min(255, limit + 2)\r\n for (const { arc } of ring) {\r\n limits.set(arc.key, Math.max(limits.get(arc.key) ?? 0, limit))\r\n masks.delete(arc.key)\r\n }\r\n }\r\n })\r\n }\r\n }\r\n\r\n const fills = project(\r\n fitted,\r\n {\r\n type: \"MultiPolygon\",\r\n coordinates: kept.flatMap((rings) => {\r\n const [exterior, ...holes] = rings.map((ring) => filteredPoints(ring, maskFor))\r\n return exterior.length < 4 ? [] : [[exterior, ...holes.filter((hole) => hole.length >= 4)]]\r\n }),\r\n } as GeoPermissibleObjects,\r\n true\r\n )\r\n\r\n const lineArcs = [...usage.values()].filter(({ count }) => borders === \"all\" || count === 1).map(({ arc }) => arc)\r\n const lines: GeoContour[] = []\r\n for (const chain of chainArcs(lineArcs)) {\r\n lines.push(\r\n ...project(fitted, { type: \"LineString\", coordinates: filteredPoints(chain.refs, maskFor) } as GeoPermissibleObjects, false)\r\n )\r\n }\r\n\r\n const sum = (contours: GeoContour[]) => contours.reduce((total, c) => total + c.length, 0)\r\n const bytes = [...fills, ...lines].reduce((total, c) => total + c.points.byteLength + 32, 0)\r\n return {\r\n width: fitted.width,\r\n height: fitted.height,\r\n fills,\r\n lines,\r\n fillLength: sum(fills),\r\n lineLength: sum(lines),\r\n bytes,\r\n }\r\n}\r\n\r\nclass ByteCache<V extends { bytes: number }> {\r\n private _entries = new Map<string, V>()\r\n private _bytes = 0\r\n\r\n constructor(private readonly _budget: number) {}\r\n\r\n get(key: string): V | undefined {\r\n const value = this._entries.get(key)\r\n if (value) {\r\n this._entries.delete(key)\r\n this._entries.set(key, value)\r\n }\r\n return value\r\n }\r\n\r\n set(key: string, value: V): void {\r\n const previous = this._entries.get(key)\r\n if (previous) this._bytes -= previous.bytes\r\n this._entries.delete(key)\r\n this._entries.set(key, value)\r\n this._bytes += value.bytes\r\n for (const [oldest, entry] of this._entries) {\r\n if (this._bytes <= this._budget || this._entries.size <= 1) break\r\n this._entries.delete(oldest)\r\n this._bytes -= entry.bytes\r\n }\r\n }\r\n\r\n clear(): void {\r\n this._entries.clear()\r\n this._bytes = 0\r\n }\r\n}\r\n\r\nconst frames = new ByteCache<Frame & { bytes: number }>(64)\r\nconst geometries = new ByteCache<GeoGeometry>(64 * 1024 * 1024)\r\n\r\nexport interface GeoGeometryRequest {\r\n /** Identifies `features` and `frame`: equal keys must mean equal selections. */\r\n selectionKey: string\r\n features: readonly GeoFeature[]\r\n frame: GeoFrame\r\n projection: GeoProjectionKind\r\n borders: GeoBorders\r\n detail: number\r\n}\r\n\r\n/**\r\n * The drawing for a selection, cached. The projection is fitted to the\r\n * selection at full detail, so a `detail` tween never moves or rescales it.\r\n */\r\nexport function geoGeometry(request: GeoGeometryRequest): GeoGeometry | null {\r\n const detail = Math.round(clamp01(request.detail) * 100) / 100\r\n const frameKey = `${request.selectionKey}|${request.projection}`\r\n const key = `${frameKey}|${request.borders}|${detail}`\r\n const cached = geometries.get(key)\r\n if (cached) return cached\r\n\r\n let fitted: Frame | undefined = frames.get(frameKey)\r\n if (!fitted) {\r\n const made = fitFrame(request.projection, partsOf(request.features, request.frame))\r\n if (!made) return null\r\n fitted = made\r\n frames.set(frameKey, { ...made, bytes: 1 })\r\n }\r\n const geometry = buildGeometry(request.features, request.frame, fitted, request.borders, detail)\r\n geometries.set(key, geometry)\r\n return geometry\r\n}\r\n\r\nexport function clearGeoGeometry(): void {\r\n frames.clear()\r\n geometries.clear()\r\n}\r\n"]}
1
+ {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../src/border/geometry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n geoArea,\n geoBounds,\n geoConicEqualArea,\n geoEquirectangular,\n geoMercator,\n geoOrthographic,\n geoPath,\n geoStream,\n type GeoPermissibleObjects,\n type GeoProjection,\n} from \"d3-geo\"\n\nimport { ringCoordinates, type GeoArc, type GeoFeature, type GeoPolygon, type GeoRingRef } from \"./format\"\nimport type { GeoFrame } from \"./selection\"\n\nexport type GeoProjectionKind = \"conic\" | \"mercator\" | \"equirectangular\" | \"orthographic\"\nexport type GeoBorders = \"all\" | \"outline\"\n\nexport interface GeoContour {\n /** Interleaved x/y in unit space: the longer side spans 1, centred on the origin, y up. */\n points: Float32Array\n closed: boolean\n length: number\n}\n\nexport interface GeoGeometry {\n /** The drawing's extent in unit space; the longer of the two is 1. */\n width: number\n height: number\n fills: GeoContour[]\n lines: GeoContour[]\n fillLength: number\n lineLength: number\n bytes: number\n}\n\ninterface Part {\n polygon: GeoPolygon\n largest: boolean\n}\n\ninterface Frame {\n projection: GeoProjection\n centerX: number\n centerY: number\n size: number\n width: number\n height: number\n}\n\nconst FIT = 1024\n\n// `detail` maps onto a weight threshold that is a fraction of the selection's\n// own area, on a log scale — which is what makes a value look equally stylised\n// on Monaco and on Russia. 0 keeps points worth 1% of the area; just below 1,\n// points worth a billionth of it.\nconst POINT_BASE = 2\nconst POINT_RANGE = 7\nconst POLYGON_BASE = 1.5\nconst POLYGON_RANGE = 6\n\nconst clamp01 = (value: number) => (value > 1 ? 1 : value > 0 ? value : 0)\n\n/** The highest weight bucket a point may carry and still be drawn. */\nexport function pointBucketLimit(detail: number, area: number): number {\n if (detail >= 1 || !(area > 0)) return 255\n const minWeight = area * 10 ** -(POINT_BASE + POINT_RANGE * clamp01(detail))\n return Math.floor(-2 * Math.log2(minWeight))\n}\n\n/** Rings smaller than this (steradians) are dropped, bar each region's largest. */\nexport function polygonAreaLimit(detail: number, area: number): number {\n if (detail >= 1) return 0\n return area * 10 ** -(POLYGON_BASE + POLYGON_RANGE * clamp01(detail))\n}\n\nfunction partsOf(features: readonly GeoFeature[], frame: GeoFrame): Part[] {\n const parts: Part[] = []\n for (const feature of features) {\n const mainland = frame === \"mainland\" ? feature.polygons.filter((p) => p.mainland) : []\n const polygons = mainland.length > 0 ? mainland : feature.polygons\n let largest: GeoPolygon | null = null\n for (const polygon of polygons) if (!largest || polygon.area > largest.area) largest = polygon\n for (const polygon of polygons) parts.push({ polygon, largest: polygon === largest })\n }\n return parts\n}\n\nfunction centerLongitude(west: number, east: number): number {\n if (west <= east) return (west + east) / 2\n const mid = (west + east + 360) / 2\n return mid > 180 ? mid - 360 : mid\n}\n\nfunction makeProjection(kind: GeoProjectionKind, west: number, south: number, east: number, north: number): GeoProjection {\n const lon = centerLongitude(west, east)\n const lat = (south + north) / 2\n switch (kind) {\n case \"mercator\":\n return geoMercator().rotate([-lon, 0])\n case \"equirectangular\":\n return geoEquirectangular().rotate([-lon, 0])\n case \"orthographic\":\n return geoOrthographic().rotate([-lon, -lat])\n case \"conic\": {\n const span = north - south\n return geoConicEqualArea()\n .rotate([-lon, 0])\n .center([0, lat])\n .parallels([south + span / 6, north - span / 6])\n }\n }\n}\n\nfunction fitFrame(kind: GeoProjectionKind, parts: readonly Part[]): Frame | null {\n if (parts.length === 0) return null\n const shape = {\n type: \"MultiPolygon\",\n coordinates: parts.map(({ polygon }) => [ringCoordinates(polygon.rings[0])]),\n } as GeoPermissibleObjects\n const [[west, south], [east, north]] = geoBounds(shape)\n\n for (const candidate of [kind, \"equirectangular\"] as const) {\n const projection = makeProjection(candidate, west, south, east, north).fitSize([FIT, FIT], shape)\n const [[x0, y0], [x1, y1]] = geoPath(projection).bounds(shape)\n const size = Math.max(x1 - x0, y1 - y0)\n if (!Number.isFinite(size) || size <= 0) continue\n return {\n projection,\n centerX: (x0 + x1) / 2,\n centerY: (y0 + y1) / 2,\n size,\n width: (x1 - x0) / size,\n height: (y1 - y0) / size,\n }\n }\n return null\n}\n\nfunction project(frame: Frame, object: GeoPermissibleObjects, closed: boolean): GeoContour[] {\n const contours: GeoContour[] = []\n let current: number[] | null = null\n const { centerX, centerY, size } = frame\n const sink = {\n point(x: number, y: number) {\n current?.push((x - centerX) / size, -(y - centerY) / size)\n },\n lineStart() {\n current = []\n },\n lineEnd() {\n const flat = current\n current = null\n if (!flat || flat.length < 4) return\n let isClosed = closed\n if (!closed) {\n const n = flat.length\n if (flat[0] === flat[n - 2] && flat[1] === flat[n - 1] && n >= 8) {\n flat.length = n - 2\n isClosed = true\n }\n }\n const points = Float32Array.from(flat)\n contours.push({ points, closed: isClosed, length: contourLength(points, isClosed) })\n },\n polygonStart() {},\n polygonEnd() {},\n sphere() {},\n }\n geoStream(object, frame.projection.stream(sink))\n return contours\n}\n\nfunction contourLength(points: Float32Array, closed: boolean): number {\n let length = 0\n const n = points.length / 2\n for (let i = 1; i < n; i++) {\n length += Math.hypot(points[i * 2] - points[i * 2 - 2], points[i * 2 + 1] - points[i * 2 - 1])\n }\n if (closed && n > 1) length += Math.hypot(points[0] - points[n * 2 - 2], points[1] - points[n * 2 - 1])\n return length\n}\n\n// Longest edge, in degrees, that simplification may leave. d3 takes an edge as\n// the short way round the sphere, so an edge across more than half the planet\n// (Kaliningrad to Chukotka, once the coast between is dropped) turns inside out.\nconst MAX_EDGE_DEGREES = 20\n\ntype MaskFor = (arc: GeoArc) => Uint8Array\n\n/** Which of an arc's points survive `limit`, the same whichever way the arc is walked. */\nfunction keepMask(arc: GeoArc, limit: number): Uint8Array {\n const n = arc.buckets.length\n const mask = new Uint8Array(n)\n let lastLon = arc.points[0]\n let lastLat = arc.points[1]\n for (let i = 0; i < n; i++) {\n const lon = arc.points[i * 2]\n const lat = arc.points[i * 2 + 1]\n let far = false\n if (arc.buckets[i] > limit) {\n let dLon = Math.abs(lon - lastLon)\n if (dLon > 180) dLon = 360 - dLon\n far = Math.abs(lat - lastLat) > MAX_EDGE_DEGREES || dLon * Math.cos((lat * Math.PI) / 180) > MAX_EDGE_DEGREES\n }\n if (arc.buckets[i] <= limit || far) {\n mask[i] = 1\n lastLon = lon\n lastLat = lat\n }\n }\n return mask\n}\n\nfunction filteredPoints(refs: readonly GeoRingRef[], maskFor: MaskFor): [number, number][] {\n const out: [number, number][] = []\n for (const { arc, reversed } of refs) {\n const n = arc.buckets.length\n const mask = maskFor(arc)\n for (let j = out.length === 0 ? 0 : 1; j < n; j++) {\n const i = reversed ? n - 1 - j : j\n if (mask[i]) out.push([arc.points[i * 2], arc.points[i * 2 + 1]])\n }\n }\n return out\n}\n\n/** A ring keeps at least three vertices, raising its arcs' limits if the global one would collapse it. */\nfunction ringLimit(ring: readonly GeoRingRef[], limit: number): number {\n let kept = 0\n for (const { arc } of ring) {\n for (let i = 0; i < arc.buckets.length - 1; i++) if (arc.buckets[i] <= limit) kept++\n }\n if (kept >= 3) return limit\n const buckets: number[] = []\n for (const { arc } of ring) for (let i = 0; i < arc.buckets.length - 1; i++) buckets.push(arc.buckets[i])\n buckets.sort((a, b) => a - b)\n return Math.max(limit, buckets[Math.min(2, buckets.length - 1)] ?? limit)\n}\n\n/**\n * Whether a simplified ring still winds the way its original did. Dropping\n * points can fold a small ring over itself, and d3 reads an exterior wound the\n * wrong way as the rest of the planet — one such island fills the whole frame.\n */\nfunction windsAsOriginal(ring: [number, number][], exterior: boolean): boolean {\n if (ring.length < 4) return true\n const inverted = geoArea({ type: \"Polygon\", coordinates: [ring] }) > 2 * Math.PI\n return inverted !== exterior\n}\n\ninterface Chain {\n refs: GeoRingRef[]\n closed: boolean\n}\n\nconst endKey = (arc: GeoArc, last: boolean) => {\n const i = last ? arc.buckets.length - 1 : 0\n return `${arc.points[i * 2]},${arc.points[i * 2 + 1]}`\n}\n\n/** Joins arcs that meet end to end with nothing else at the joint, so a border draws as one line with real joins. */\nfunction chainArcs(arcs: readonly GeoArc[]): Chain[] {\n const atNode = new Map<string, GeoArc[]>()\n for (const arc of arcs) {\n for (const key of [endKey(arc, false), endKey(arc, true)]) {\n const list = atNode.get(key)\n if (list) list.push(arc)\n else atNode.set(key, [arc])\n }\n }\n const visited = new Set<GeoArc>()\n const chains: Chain[] = []\n const refStart = ({ arc, reversed }: GeoRingRef) => endKey(arc, reversed)\n const refEnd = ({ arc, reversed }: GeoRingRef) => endKey(arc, !reversed)\n const nextAt = (node: string): GeoArc | null => {\n const list = atNode.get(node)!\n if (list.length !== 2) return null\n return list.find((arc) => !visited.has(arc)) ?? null\n }\n\n for (const arc of arcs) {\n if (visited.has(arc)) continue\n visited.add(arc)\n const refs: GeoRingRef[] = [{ arc, reversed: false }]\n for (let next = nextAt(refEnd(refs[refs.length - 1])); next; next = nextAt(refEnd(refs[refs.length - 1]))) {\n visited.add(next)\n refs.push({ arc: next, reversed: endKey(next, false) !== refEnd(refs[refs.length - 1]) })\n }\n for (let prev = nextAt(refStart(refs[0])); prev; prev = nextAt(refStart(refs[0]))) {\n visited.add(prev)\n refs.unshift({ arc: prev, reversed: endKey(prev, true) !== refStart(refs[0]) })\n }\n chains.push({ refs, closed: refStart(refs[0]) === refEnd(refs[refs.length - 1]) })\n }\n return chains\n}\n\nfunction buildGeometry(\n features: readonly GeoFeature[],\n frame: GeoFrame,\n fitted: Frame,\n borders: GeoBorders,\n detail: number\n): GeoGeometry {\n const parts = partsOf(features, frame)\n const area = parts.reduce((sum, { polygon }) => sum + polygon.area, 0)\n const pointLimit = pointBucketLimit(detail, area)\n const polygonLimit = polygonAreaLimit(detail, area)\n\n const kept: GeoRingRef[][][] = []\n for (const { polygon, largest } of parts) {\n if (!largest && polygon.area < polygonLimit) continue\n kept.push(polygon.rings.filter((_, i) => i === 0 || polygon.ringAreas[i] >= polygonLimit))\n }\n\n const limits = new Map<GeoArc[\"key\"], number>()\n const usage = new Map<GeoArc[\"key\"], { arc: GeoArc; count: number }>()\n for (const rings of kept) {\n for (const ring of rings) {\n const limit = ringLimit(ring, pointLimit)\n for (const { arc } of ring) {\n limits.set(arc.key, Math.max(limits.get(arc.key) ?? 0, limit))\n const use = usage.get(arc.key)\n if (use) use.count++\n else usage.set(arc.key, { arc, count: 1 })\n }\n }\n }\n\n const masks = new Map<GeoArc[\"key\"], Uint8Array>()\n const maskFor: MaskFor = (arc) => {\n let mask = masks.get(arc.key)\n if (!mask) {\n mask = keepMask(arc, limits.get(arc.key) ?? 255)\n masks.set(arc.key, mask)\n }\n return mask\n }\n\n if (pointLimit < 255) {\n for (const rings of kept) {\n rings.forEach((ring, index) => {\n let limit = Math.min(...ring.map(({ arc }) => limits.get(arc.key) ?? pointLimit))\n while (limit < 255 && !windsAsOriginal(filteredPoints(ring, maskFor), index === 0)) {\n limit = Math.min(255, limit + 2)\n for (const { arc } of ring) {\n limits.set(arc.key, Math.max(limits.get(arc.key) ?? 0, limit))\n masks.delete(arc.key)\n }\n }\n })\n }\n }\n\n const fills = project(\n fitted,\n {\n type: \"MultiPolygon\",\n coordinates: kept.flatMap((rings) => {\n const [exterior, ...holes] = rings.map((ring) => filteredPoints(ring, maskFor))\n return exterior.length < 4 ? [] : [[exterior, ...holes.filter((hole) => hole.length >= 4)]]\n }),\n } as GeoPermissibleObjects,\n true\n )\n\n const lineArcs = [...usage.values()].filter(({ count }) => borders === \"all\" || count === 1).map(({ arc }) => arc)\n const lines: GeoContour[] = []\n for (const chain of chainArcs(lineArcs)) {\n lines.push(\n ...project(fitted, { type: \"LineString\", coordinates: filteredPoints(chain.refs, maskFor) } as GeoPermissibleObjects, false)\n )\n }\n\n const sum = (contours: GeoContour[]) => contours.reduce((total, c) => total + c.length, 0)\n const bytes = [...fills, ...lines].reduce((total, c) => total + c.points.byteLength + 32, 0)\n return {\n width: fitted.width,\n height: fitted.height,\n fills,\n lines,\n fillLength: sum(fills),\n lineLength: sum(lines),\n bytes,\n }\n}\n\nclass ByteCache<V extends { bytes: number }> {\n private _entries = new Map<string, V>()\n private _bytes = 0\n\n constructor(private readonly _budget: number) {}\n\n get(key: string): V | undefined {\n const value = this._entries.get(key)\n if (value) {\n this._entries.delete(key)\n this._entries.set(key, value)\n }\n return value\n }\n\n set(key: string, value: V): void {\n const previous = this._entries.get(key)\n if (previous) this._bytes -= previous.bytes\n this._entries.delete(key)\n this._entries.set(key, value)\n this._bytes += value.bytes\n for (const [oldest, entry] of this._entries) {\n if (this._bytes <= this._budget || this._entries.size <= 1) break\n this._entries.delete(oldest)\n this._bytes -= entry.bytes\n }\n }\n\n clear(): void {\n this._entries.clear()\n this._bytes = 0\n }\n}\n\nconst frames = new ByteCache<Frame & { bytes: number }>(64)\nconst geometries = new ByteCache<GeoGeometry>(64 * 1024 * 1024)\n\nexport interface GeoGeometryRequest {\n /** Identifies `features` and `frame`: equal keys must mean equal selections. */\n selectionKey: string\n features: readonly GeoFeature[]\n frame: GeoFrame\n projection: GeoProjectionKind\n borders: GeoBorders\n detail: number\n}\n\n/**\n * The drawing for a selection, cached. The projection is fitted to the\n * selection at full detail, so a `detail` tween never moves or rescales it.\n */\nexport function geoGeometry(request: GeoGeometryRequest): GeoGeometry | null {\n const detail = Math.round(clamp01(request.detail) * 100) / 100\n const frameKey = `${request.selectionKey}|${request.projection}`\n const key = `${frameKey}|${request.borders}|${detail}`\n const cached = geometries.get(key)\n if (cached) return cached\n\n let fitted: Frame | undefined = frames.get(frameKey)\n if (!fitted) {\n const made = fitFrame(request.projection, partsOf(request.features, request.frame))\n if (!made) return null\n fitted = made\n frames.set(frameKey, { ...made, bytes: 1 })\n }\n const geometry = buildGeometry(request.features, request.frame, fitted, request.borders, detail)\n geometries.set(key, geometry)\n return geometry\n}\n\nexport function clearGeoGeometry(): void {\n frames.clear()\n geometries.clear()\n}\n"]}