ixmaps-gl 0.1.0
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/LICENSE.txt +28 -0
- package/README.md +291 -0
- package/ixmaps-gl.js +9921 -0
- package/package.json +34 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Guenter Richter
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# ixmaps-gl
|
|
2
|
+
|
|
3
|
+
A from-scratch, config-driven map/theme engine that exposes the **same declarative
|
|
4
|
+
builder API** as the original [ixmaps](https://ixmaps.com) framework —
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
ixmaps.Map(id, options)
|
|
8
|
+
ixmaps.layer(name, layer => layer.data().binding().filter().type().style().meta())
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
— but renders through **MapLibre GL JS + deck.gl** instead of ixmaps' own SVG/Leaflet
|
|
12
|
+
engine. The goal is drop-in compatibility: a real, unmodified ixmaps page should be
|
|
13
|
+
able to run against this engine by swapping only the `<script>` tag that loads it.
|
|
14
|
+
|
|
15
|
+
## Why
|
|
16
|
+
|
|
17
|
+
ixmaps' declarative model (a page describes *what* to show — a data source, a field
|
|
18
|
+
binding, a chart type, a style — not *how* to draw it) is a good fit for a modern
|
|
19
|
+
WebGL rendering stack: MapLibre for basemap/vector-tile rendering and camera control,
|
|
20
|
+
deck.gl for large-scale, GPU-instanced point/polygon layers and clustering. This
|
|
21
|
+
project re-implements the ixmaps theme grammar on top of that stack rather than
|
|
22
|
+
patching the original SVG engine.
|
|
23
|
+
|
|
24
|
+
## Status
|
|
25
|
+
|
|
26
|
+
This engine is under active, compatibility-driven development: every gap found by
|
|
27
|
+
pointing a real ixmaps page at it gets fixed **in the engine**, never by rewriting the
|
|
28
|
+
page. It currently implements:
|
|
29
|
+
|
|
30
|
+
- **FEATURE / FEATURES** — polygon/line rendering from GeoJSON/TopoJSON and the data.js geo
|
|
31
|
+
formats; `featureupper`/`featurelower` hide the layer outside their scales, and, as in flat, a
|
|
32
|
+
FEATURE theme out of scale loads its data only once it comes into scale (for that view);
|
|
33
|
+
flat's drop `shadow` (`shadowblur`/`shadowdx`/`shadowdy`, `maxshadow`, `shadowupper`/`shadowlower`),
|
|
34
|
+
approximated with translucent outlines since deck.gl has no blur
|
|
35
|
+
- **CHOROPLETH** — polygon fill from a bound value: single-field numeric range
|
|
36
|
+
(equal-interval, QUANTILE, NATURAL/Jenks breaks) or multi-field DOMINANT
|
|
37
|
+
(per-polygon argmax, plain/`PERCENTOFMEAN`/`DEVIATION`; with a `value100` the field means are
|
|
38
|
+
flat's pooled Σ field ÷ Σ value100) or COMPOSECOLOR (additive or
|
|
39
|
+
`SUBTRACTIVE` color blend); `HEADTAIL` breaks, `DENSITY` (value per km²), flat's
|
|
40
|
+
`ZEROISNOTVALUE`/`UNDEFINEDISNOTVALUE`; plus DOPACITY/DOPACITYMIN/DOPACITYMAX/DOPACITYMINMAX for
|
|
41
|
+
value- or density-driven fill opacity
|
|
42
|
+
- **CHART\|SYMBOL\|GLOW\|CATEGORICAL\|AGGREGATE\|COUNT\|RELOCATE\|VALUES** — the
|
|
43
|
+
bubble-map pipeline: AGGREGATE on ixmaps-flat's grid (hexagonal, or square with
|
|
44
|
+
`RECT`; cell width from `aggregation`/`gridwidth`/`gridwidthpx`, values summed per
|
|
45
|
+
cell, class breaks and legend from the aggregated cells), dynamic sizing, glow,
|
|
46
|
+
multi-point grouping, on-bubble value labels, `NORMALIZE`, chart boxes (`BOX`, `CIRCULARBOX`)
|
|
47
|
+
with the item title above or below (`TITLE`, `BOTTOMTITLE`), between `boxlower` and `boxupper`
|
|
48
|
+
- **CHART\|USER** — a page's own chart function (`style.userdraw`: `ixmaps.<name>(SVGDocument, opt)`
|
|
49
|
+
and its `_init`, as flat calls them), drawn in flat's chart units and shown as an icon at flat's size
|
|
50
|
+
- **DOT** — the simplest base symbol (fixed-radius, unclustered points)
|
|
51
|
+
- **PLOT** — a small line/area chart per item over its value fields (flat's per-item PLOT
|
|
52
|
+
geometry: first point at the item, `scale`/`rangescale`, FIXSIZE markers), or one per grid
|
|
53
|
+
cell with `GRIDSIZE` (a categorical field's series, e.g. one value per year)
|
|
54
|
+
- A native interactive legend (default bars, `SIMPLELEGEND`, `COMPACTLEGEND`,
|
|
55
|
+
`NOLEGEND`, `TEXTLEGEND`; light/dark color themes; corner or flat `align` option;
|
|
56
|
+
collapsible, collapsed by default on narrow/mobile screens). As flat's `#map-legend` it is one box:
|
|
57
|
+
the themes' legends one after the other in theme order, leaving out a theme hidden or out of scale;
|
|
58
|
+
a range theme of 5 classes or more without `label` gets flat's one-line color bar (with DOPACITY and an
|
|
59
|
+
alpha field, flat's three-row opacity grid); `style.label` names the classes; the opacity slider comes
|
|
60
|
+
with the type word `CHOROPLETH`, the size slider with `CHART`/`BUBBLE`/`DOT`, as in flat
|
|
61
|
+
- A standard facets API (`ixmaps.data.getFacets`/`showFacets`,
|
|
62
|
+
`window.__setFacetFilter`) for building filterable sidebars
|
|
63
|
+
- Globe (orthographic) projection alongside flat Mercator
|
|
64
|
+
|
|
65
|
+
Not yet implemented: `CATEGORICAL` choropleths, and the `QUAD`/`BEZIER`/`VECTOR`/
|
|
66
|
+
`PIE`/`DONUT`/`WAFFLE`/`BAR` base types and SYMBOL shape variants beyond
|
|
67
|
+
circle/square/diamond/triangle. See the top-of-file comment in
|
|
68
|
+
[`ixmaps-gl.js`](./ixmaps-gl.js) for the exact, currently-accurate scope note.
|
|
69
|
+
|
|
70
|
+
### Page scripts, named data and the runtime API
|
|
71
|
+
|
|
72
|
+
A page's `.require(url)` scripts (page code, e.g. a user chart function) load in order before the
|
|
73
|
+
layers are built. `ixmaps.map()` is the map handle as in flat — its calls wait until the map is ready —
|
|
74
|
+
with `add(theme, flags)` / `replace` / `replaceTheme` / `remove`, `changeThemeStyle` for any style key,
|
|
75
|
+
`getZoom()` (flat's zoom), `resize()` and `setBasemapOpacity`; the page's `htmlgui_onNewTheme(id)` and
|
|
76
|
+
`htmlgui_onZoomAndPan()` (also once on load) are called (as in flat, a theme swapped in with `replace` comes last
|
|
77
|
+
in the legend, while FEATURE and CHOROPLETH shapes always draw under the charts), and `map`, `getZoom` and flat's
|
|
78
|
+
`formatValue` exist as globals. `.data({name})` without a URL waits for data of that name: from
|
|
79
|
+
`ixmaps.setExternalData(data, {name})`, or from a broker — `.data({query, name, type: "ext"})`
|
|
80
|
+
registers the query function as `ixmaps[name]` and calls it with flat's options (`ext`, `theme`,
|
|
81
|
+
`setData`); a theme reloads when new data of its name arrives. Charts on a FEATURE layer are placed
|
|
82
|
+
as in flat: joined by `lookup` (`lookupdigits`, `lookuptonumber`, `lookuptoupper`), the first shape of
|
|
83
|
+
an id wins, a polygon's position is flat's shape center (the vertex mean in Mercator), a theme on
|
|
84
|
+
`"a|b"` is placed on each layer (with `DIFFERENCE`, on the last). `aggregationscale` (alias of
|
|
85
|
+
`aggregation`) picks px, meters or a grouping field by scale on flat's grid origin; `chartupper`/
|
|
86
|
+
`chartlower` (else `layerupper`/`layerlower`) hide a theme outside their scales; `.filter()` takes
|
|
87
|
+
flat's grammar (`WHERE a > 5 AND b NOT x`, `LIKE`, `IN`, `BETWEEN`, `$field$`, or a plain regex).
|
|
88
|
+
|
|
89
|
+
### Zoom levels
|
|
90
|
+
|
|
91
|
+
Zoom numbers in the ixmaps API are ixmaps-flat's, i.e. Leaflet's (256px tiles):
|
|
92
|
+
`.view({center, zoom})`, `view([lat, lng], zoom)`, the `zoom` of a project map
|
|
93
|
+
(`loadProject`/`setProjectJSON`) and the `zoom` `getProjectString()` returns. MapLibre
|
|
94
|
+
works on 512px tiles, so ixmaps-gl shows ixmaps zoom *z* at MapLibre zoom *z* − 1 — the
|
|
95
|
+
same area a flat page shows. Map scales (`aggregation`, `valueupper`, `featureupper`/`featurelower`
|
|
96
|
+
and `boxupper`/`boxlower` thresholds, `normalSizeScale`) are computed from the zoom that is
|
|
97
|
+
actually displayed. Code that talks
|
|
98
|
+
to the MapLibre map directly (`api.map.getZoom()`, `jumpTo`) sees MapLibre zooms.
|
|
99
|
+
|
|
100
|
+
### Theme normalization
|
|
101
|
+
|
|
102
|
+
Every layer definition passes through one pure function, `normalizeTheme()`, before any
|
|
103
|
+
renderer sees it. Its input has real ixmaps-flat's theme-definition shape (`{layer, data,
|
|
104
|
+
binding, style: {type, filter, title, …}, meta}` — the same shape as a theme in a flat
|
|
105
|
+
project JSON), and every alias rule lives there: `BUBBLE` implies `SYMBOL`, `geo` is read
|
|
106
|
+
as `position`, `.title()` is the legend-title fallback, and all of real ixmaps-flat's
|
|
107
|
+
binding aliases resolve to their targets (`values`/`fields`/`field` → `value`,
|
|
108
|
+
`sizefield` → `size`, `itemfield` → `id`, `text`/`valuefield` → the value-label field, …),
|
|
109
|
+
also when given as a style key (`.style({sizefield})` ≡ `.binding({size})`, as in flat).
|
|
110
|
+
flat's single lookup field (`geo`, `position`, `lookup`, `georef`, `lookupfield`, …) is read
|
|
111
|
+
by flat's own rule: `"lat|lon"` → points; `"geometry"` or GeoJSON/TopoJSON data → the
|
|
112
|
+
features' own geometry; any other single field on tabular data → a join key against the
|
|
113
|
+
same-named FEATURE layer — so a flat-style choropleth `.binding({geo: "code"})` works.
|
|
114
|
+
And as in flat, `.meta()` is merged into style first (meta wins): a style property given in
|
|
115
|
+
`.meta()` applies, and the meta keys (`title`, `tooltip`, `name`, `snippet`, `description`)
|
|
116
|
+
work when given in `.style()` too. The layer builder has all of flat's methods, including
|
|
117
|
+
`.field()`, `.field100()`, `.geo()`, `.lookup()`, `.encoding()`, `.query()`, `.process()` and
|
|
118
|
+
`.json()`; each writes the slot flat writes. Repeated `.binding()`, `.style()` and `.meta()` calls merge, as in flat
|
|
119
|
+
(a later value for the same key wins). The style keys read as numbers (`fillopacity`, `linewidth`, `scale`, `classes`,
|
|
120
|
+
…) are typed here once: `"0.8"` becomes `0.8`, also in runtime style changes (`setThemeStyle`, the legend sliders),
|
|
121
|
+
while anything that isn't a plain number (`"auto"`, `"12px"`) stays as given.
|
|
122
|
+
A page's own data processing function (`.data({process})` or `.process()`, as a function or
|
|
123
|
+
its `toString()`) runs like in flat: after loading, it gets the data as a data.js Table
|
|
124
|
+
(`column()`, `addColumn()`, …) and returns it, or nothing to keep the changed table.
|
|
125
|
+
The alias table is generated from the shared grammar (`test/sync-grammar.mjs`); targets
|
|
126
|
+
this engine doesn't implement yet (`colorfield`, `timefield`, `titlefield`, …) are resolved
|
|
127
|
+
but unused. It never mutates the page's own objects. Unit tests: `cd test && npm run unit`.
|
|
128
|
+
|
|
129
|
+
### World copies
|
|
130
|
+
|
|
131
|
+
At an extreme zoom-out MapLibre repeats the world side by side, and the themes are repeated on
|
|
132
|
+
every copy (flat repeats only its basemap tiles). `.options({worldcopies: false})` draws the
|
|
133
|
+
world once, but MapLibre then also stops the zoom-out where the world gets narrower than the
|
|
134
|
+
window.
|
|
135
|
+
|
|
136
|
+
### Data formats and data.js
|
|
137
|
+
|
|
138
|
+
Like flat, ixmaps-gl loads the real [data.js](https://github.com/gjrichter/data.js) by default
|
|
139
|
+
(from flat's CDN URL, alongside MapLibre and deck.gl), unless the page has it already;
|
|
140
|
+
`.options({datajs: url})` loads another build, `.options({datajs: false})` none. It reads every
|
|
141
|
+
`.data({url, type})` format data.js knows — `csv`, `json`, `jsondb`, `jsonstat`, `ndjson`/`jsonl`,
|
|
142
|
+
`rss`, `kml`, `gml`, `geobuf`, `pbf`, `flatgeobuf`/`fgb`, `geopackage`/`gpkg`, `parquet` — and hands
|
|
143
|
+
the table to `.data({process})`, `.data({query})` and project scripts, as flat does. A data.js geo
|
|
144
|
+
format comes as a table with a `geometry` column; `.binding({geo: "geometry"})` turns it into
|
|
145
|
+
points, lines or polygons. GeoJSON and TopoJSON are read by ixmaps-gl itself (features directly),
|
|
146
|
+
and without data.js CSV falls back to ixmaps-gl's own parser (same rows, ~10 % faster on 1.2M rows).
|
|
147
|
+
|
|
148
|
+
### Loading ixmaps-flat project files
|
|
149
|
+
|
|
150
|
+
`map.loadProject(src, flags)` (and the global `ixmaps.loadProject` / `ixmaps.setProjectJSON`)
|
|
151
|
+
loads a real ixmaps-flat project — an object, a JSON string or a URL — the way flat's own
|
|
152
|
+
`setProjectJSON` does: the map part (projection from flat's map file, `center`/`zoom`,
|
|
153
|
+
`options`) and then the themes, in order; without `add` the first theme clears the existing
|
|
154
|
+
ones, `replace` swaps themes by `style.name`/`meta.name`, `themeonly`/`maponly`/`keepview`
|
|
155
|
+
work as in flat. Themes in flat's older shape (data source in `style.dbtable*`, value field at
|
|
156
|
+
the top level) are translated first. It resolves to `{ themes, skipped, notes }`: a theme
|
|
157
|
+
that can't load is skipped with a warning, the rest still load. **Code a project names is not
|
|
158
|
+
run by default** — `required` scripts, `ext` data scripts and a project's `process` functions are
|
|
159
|
+
reported, not executed (only a page's own `.data({process})` runs) — and the basemap isn't switched.
|
|
160
|
+
|
|
161
|
+
A page can opt in to a project's **scripts** (`data.ext`) for script URLs under prefixes it lists —
|
|
162
|
+
no built-in prefixes, and a project file's own `options.trustedscripts` is ignored. Both of flat's
|
|
163
|
+
script contracts work: a **processing script** on a loaded file (`ixmaps.<data.name>.after` /
|
|
164
|
+
`.process(table, options)`), and a **broker** (`data.type: "ext"`), which loads the data itself in
|
|
165
|
+
`ixmaps.<data.name>(theme, options)` and hands it over with `ixmaps.setExternalData(data, {type, name})`:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
ixmaps.Map("map_div", {...}).options({
|
|
169
|
+
trustedscripts: ["https://gjrichter.github.io/viz/", "https://raw.githubusercontent.com/gjrichter/"]
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Prefixes match whole path segments; relative script paths resolve against the page. Data is parsed
|
|
174
|
+
by data.js, and a script runs right before its own theme loads. The
|
|
175
|
+
theme properties a broker sets from its data (flat's `szFields`, `szField100`, `szSnippet`,
|
|
176
|
+
`szTitle`, `szLabelA`, `setProperties()`, …) are applied to the theme, where flat's own style keys
|
|
177
|
+
would put them. As in flat, a broker whose function the page itself already defines
|
|
178
|
+
(`ixmaps.<name>`, page code — no opt-in needed) is called directly, and gets `data.ext` (or the
|
|
179
|
+
`data.url`) as `options.ext`, its data URL; only otherwise is `data.ext` loaded as the broker's
|
|
180
|
+
script. For brokers that query by view, like flat's bbox data providers, ixmaps-gl has flat's
|
|
181
|
+
`ixmaps.getBoundingBox()`, `ixmaps.refreshTheme(id)` (loads the theme's data again, in place),
|
|
182
|
+
`ixmaps.setTitle(html)`/`setTitleBox(text, color)`, `ixmaps.getThemeObj(id).fVisible` (false for a
|
|
183
|
+
FEATURE theme out of scale) and calls a page's `ixmaps.htmlgui_onZoomAndPan(zoom)` after each zoom
|
|
184
|
+
or pan. Scripts that reach further into flat's internals (`ixmaps.parentApi`, other `htmlgui_*`
|
|
185
|
+
hooks) aren't supported. `test/project-report.mjs` shows which themes
|
|
186
|
+
of your own project files gl can render.
|
|
187
|
+
|
|
188
|
+
## Quick start
|
|
189
|
+
|
|
190
|
+
Load the engine from jsDelivr, pinned to a release tag (or `@main` for the latest commit):
|
|
191
|
+
|
|
192
|
+
```html
|
|
193
|
+
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.1.0/ixmaps-gl.js"></script>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
or use a local copy (`<script src="ixmaps-gl.js"></script>`). A minimal page:
|
|
197
|
+
|
|
198
|
+
```html
|
|
199
|
+
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.1.0/ixmaps-gl.js"></script>
|
|
200
|
+
<div id="map_div" style="position:absolute;inset:0;"></div>
|
|
201
|
+
|
|
202
|
+
<script>
|
|
203
|
+
var __theme = ixmaps.layer("my_theme", layer => layer
|
|
204
|
+
.data({ url: "data.topojson.gz", type: "topojson" })
|
|
205
|
+
.binding({ position: "geometry", value: "CATEGORY_FIELD", size: "SIZE_FIELD" })
|
|
206
|
+
.type("CHART|SYMBOL|GLOW|CATEGORICAL|AGGREGATE|COUNT|RELOCATE|VALUES")
|
|
207
|
+
.style({ colorscheme: ["#ddbb22", "#0066cc", "#ff0088"] })
|
|
208
|
+
.meta({ title: "My theme", tooltip: "<b>{{theme.title}}</b><br>{{theme.item.chart}}" })
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
ixmaps.Map("map_div", { mapType: "VT_BRIGHT_LIGHT", mode: "pan", legend: "open" })
|
|
212
|
+
.view({ center: { lat: 45.47, lng: 9.19 }, zoom: 10 })
|
|
213
|
+
.layer(__theme);
|
|
214
|
+
</script>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
See [`demo_accidents.html`](./stage/demo_accidents.html) for a minimal working page copied
|
|
218
|
+
verbatim (config included) from a real ixmaps page — the only change is which script
|
|
219
|
+
provides `ixmaps.layer`/`ixmaps.Map`.
|
|
220
|
+
|
|
221
|
+
## Grammar validation (opt-in)
|
|
222
|
+
|
|
223
|
+
ixmaps-gl can check every theme definition against the shared ixmaps grammar
|
|
224
|
+
([ixmaps-grammar](https://github.com/gjrichter/ixmaps-grammar), extracted from the real
|
|
225
|
+
ixmaps-flat sources) and report — once per keyword, in the browser console — typos and
|
|
226
|
+
features this engine doesn't implement:
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
[ixmaps-gl validate] error unknown-style-key — layer "points": unknown style key "fillOpacity" — did you mean "fillopacity"?
|
|
230
|
+
[ixmaps-gl validate] warning gl-unsupported — layer "pie": type flag "PIE" is not implemented by ixmaps-gl
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
It is **off by default** — nothing is fetched and nothing changes. Turn it on with any of:
|
|
234
|
+
|
|
235
|
+
```js
|
|
236
|
+
ixmaps.Map("map_div", {...}).options({ validate: true }) // or a validator module URL
|
|
237
|
+
ixmaps.validate = true // before or after loading ixmaps-gl.js
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
or by adding `?ixmaps-validate` to the page URL (this only switches validation on; the
|
|
241
|
+
validator URL can only be set from page code).
|
|
242
|
+
|
|
243
|
+
Checked: Map() options, `.options()`, each layer's `.type()` flags, `.style()`, `.meta()`,
|
|
244
|
+
`.binding()`, `.data()`; layers added later (`defineLayer`); runtime `setThemeStyle` /
|
|
245
|
+
`changeThemeStyle` patches; and reads of `ixmaps.*` functions this engine lacks (the
|
|
246
|
+
`ixmaps` global becomes a Proxy in validation mode only; missing properties still read as
|
|
247
|
+
`undefined`). `map.getValidationReport()` returns the findings as data (`null` when off).
|
|
248
|
+
If the validator can't be loaded, the map loads normally without it. See
|
|
249
|
+
[`examples/validate_demo.html`](./examples/validate_demo.html).
|
|
250
|
+
|
|
251
|
+
For checking page files before they run, use the static checker in ixmaps-grammar
|
|
252
|
+
(`ixmaps-check --engine gl page.html`).
|
|
253
|
+
|
|
254
|
+
## Example / demo pages
|
|
255
|
+
|
|
256
|
+
| Page | What it shows |
|
|
257
|
+
|---|---|
|
|
258
|
+
| [`demo_accidents.html`](./stage/demo_accidents.html) | Minimal quick-start example |
|
|
259
|
+
| [`accidents_app.html`](./stage/accidents_app.html) / [`germany_accidents_app.html`](./stage/germany_accidents_app.html) | Full app with a facets sidebar (standard facets API) |
|
|
260
|
+
| [`global_power_plants_world_map.html`](./stage/global_power_plants_world_map.html) | Native legend, globe projection toggle |
|
|
261
|
+
| [`global_power_plants_sidebar.html`](./stage/global_power_plants_sidebar.html) | Same dataset with a facets sidebar instead of the native legend |
|
|
262
|
+
| [`mappa_stranieri_30.html`](./stage/mappa_stranieri_30.html) | Symbol shapes, city picker, runtime `changeThemeStyle` filtering, light legend theme |
|
|
263
|
+
| [`roma_incidenti_pericolosita_sidebar_gl.html`](./stage/roma_incidenti_pericolosita_sidebar_gl.html) | AGGREGATE on a gridwidth grid, facets sidebar |
|
|
264
|
+
| [`roma_incidenti_pericolosita_sidebar.html`](./stage/roma_incidenti_pericolosita_sidebar.html) | The same page on the **real** ixmaps-flat engine, kept for side-by-side reference |
|
|
265
|
+
| [`uk_collisions_2023.html`](./stage/uk_collisions_2023.html), [`ixmaps-loader_70.html`](./stage/ixmaps-loader_70.html) | Additional real-page compatibility tests |
|
|
266
|
+
| [`examples/`](./examples) | Smaller feature-by-feature test pages (choropleth classing modes, bubble ranges, etc.) |
|
|
267
|
+
|
|
268
|
+
Serve any of these with a static file server (they fetch remote data over HTTPS, so
|
|
269
|
+
`file://` won't work for most):
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
python3 -m http.server 8000
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Testing
|
|
276
|
+
|
|
277
|
+
[`test/`](./test) holds an output-regression harness: it loads every example and real-page
|
|
278
|
+
test in headless Chromium, records what the engine produces (every deck.gl layer's
|
|
279
|
+
per-item accessor output, each theme's class breaks and colors, legend and tooltips) and
|
|
280
|
+
compares it against committed baselines, so a refactor that changes any output is caught
|
|
281
|
+
with the exact layer and field.
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
cd test && npm install && npm test
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
See [`test/README.md`](./test/README.md).
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
BSD 3-Clause — see [`LICENSE.txt`](./LICENSE.txt).
|