ixmaps-gl 0.2.4 → 0.2.5
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 +3 -3
- package/ixmaps-gl.js +75 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,7 +193,7 @@ of your own project files gl can render.
|
|
|
193
193
|
Load the engine from jsDelivr, pinned to a release tag (or `@main` for the latest commit):
|
|
194
194
|
|
|
195
195
|
```html
|
|
196
|
-
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.2.
|
|
196
|
+
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.2.5/ixmaps-gl.js"></script>
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
or from unpkg, the npm package [`ixmaps-gl`](https://www.npmjs.com/package/ixmaps-gl)
|
|
@@ -201,13 +201,13 @@ or from unpkg, the npm package [`ixmaps-gl`](https://www.npmjs.com/package/ixmap
|
|
|
201
201
|
browser script, which defines the global `ixmaps`):
|
|
202
202
|
|
|
203
203
|
```html
|
|
204
|
-
<script src="https://unpkg.com/ixmaps-gl@0.2.
|
|
204
|
+
<script src="https://unpkg.com/ixmaps-gl@0.2.5/ixmaps-gl.js"></script>
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
or use a local copy (`<script src="ixmaps-gl.js"></script>`). A minimal page:
|
|
208
208
|
|
|
209
209
|
```html
|
|
210
|
-
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.2.
|
|
210
|
+
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.2.5/ixmaps-gl.js"></script>
|
|
211
211
|
<div id="map_div" style="position:absolute;inset:0;"></div>
|
|
212
212
|
|
|
213
213
|
<script>
|
package/ixmaps-gl.js
CHANGED
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
// ---------------------------------------------------------------
|
|
81
81
|
// this engine's release (= package.json "version", checked by
|
|
82
82
|
// test/unit/version.test.mjs); ixmaps.glVersion, and logged once at start
|
|
83
|
-
const IXMAPS_GL_VERSION = '0.2.
|
|
83
|
+
const IXMAPS_GL_VERSION = '0.2.5';
|
|
84
84
|
|
|
85
85
|
const LIB_URLS = {
|
|
86
86
|
// Bumped 3.6.2 -> 5.x (2026-09-21, globe-projection compat fix): native
|
|
@@ -306,7 +306,7 @@
|
|
|
306
306
|
// crafted link must not be able to load arbitrary code into the page.
|
|
307
307
|
// ---------------------------------------------------------------
|
|
308
308
|
// v0.1.6: knows this engine's aliases, lookupfield rule, meta↔style, builder methods, project loading
|
|
309
|
-
const VALIDATOR_URL_DEFAULT = 'https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-grammar@v0.1.
|
|
309
|
+
const VALIDATOR_URL_DEFAULT = 'https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-grammar@v0.1.22/dist/validate.mjs';
|
|
310
310
|
// a page may set ixmaps.validate BEFORE loading this script — the
|
|
311
311
|
// `global.ixmaps = {...}` export below would otherwise overwrite it
|
|
312
312
|
const _preloadValidate = global.ixmaps && global.ixmaps.validate;
|
|
@@ -2066,7 +2066,7 @@
|
|
|
2066
2066
|
// edit it by hand; `npm run unit` fails when it drifts.
|
|
2067
2067
|
// ---------------------------------------------------------------
|
|
2068
2068
|
// <grammar:binding-aliases>
|
|
2069
|
-
// generated from ixmaps-grammar 0.1.
|
|
2069
|
+
// generated from ixmaps-grammar 0.1.22 (ixmaps-flat 1.0.42, 2b978d5 2026-10-02) — 52 aliases
|
|
2070
2070
|
const FLAT_BINDING_ALIASES = {
|
|
2071
2071
|
"aggregation": "style.aggregationfield",
|
|
2072
2072
|
"aggregationfield": "style.aggregationfield",
|
|
@@ -2128,7 +2128,7 @@
|
|
|
2128
2128
|
// both — so .style({tooltip}) is a tooltip and .meta({fillopacity}) a style
|
|
2129
2129
|
// property. GENERATED by test/sync-grammar.mjs — do not edit.
|
|
2130
2130
|
// <grammar:meta-keys>
|
|
2131
|
-
// generated from ixmaps-grammar 0.1.
|
|
2131
|
+
// generated from ixmaps-grammar 0.1.22 — 5 meta keys
|
|
2132
2132
|
const FLAT_META_KEYS = ["description","name","snippet","title","tooltip"];
|
|
2133
2133
|
// </grammar:meta-keys>
|
|
2134
2134
|
|
|
@@ -7707,6 +7707,35 @@
|
|
|
7707
7707
|
return this._glowIconCache.get(key);
|
|
7708
7708
|
}
|
|
7709
7709
|
|
|
7710
|
+
// SHADOW on chart symbols — flat's chart drop shadow (maptheme.js 17097-17160, 18709-18749):
|
|
7711
|
+
// an SVG filter that blurs the symbol by nShadowBlur (3) REAL screen pixels, offsets it by
|
|
7712
|
+
// nShadowDx/Dy (1.5/2.5 px) and darkens it to 0.1 × its color at the source alpha. Here: a
|
|
7713
|
+
// blurred disc as a MASK icon (tinted per item via getColor), one per size step, so the blur
|
|
7714
|
+
// stays ~blurPx on screen whatever the symbol radius (a single scaled icon would blur big
|
|
7715
|
+
// bubbles more). The disc spans 2/3 of the canvas: the rest is room for the blur.
|
|
7716
|
+
// `shape`: the symbol's own (drawSymbolPath, as _buildSingleIcon) — flat's filter shadows
|
|
7717
|
+
// whatever the symbol is, e.g. a RECT square
|
|
7718
|
+
_getShadowIcon(radiusPx, blurPx, shape) {
|
|
7719
|
+
shape = shape || 'circle';
|
|
7720
|
+
const step = Math.max(0, Math.min(7, Math.round(Math.log2(Math.max(1, radiusPx)))));
|
|
7721
|
+
const key = `shadow-${shape}-${step}-${blurPx}`;
|
|
7722
|
+
if (!this._glowIconCache.has(key)) {
|
|
7723
|
+
const size = 96, disc = 32, c = size / 2;
|
|
7724
|
+
const sigma = Math.max(0.5, Math.min(12, blurPx * disc / Math.pow(2, step)));
|
|
7725
|
+
const canvas = document.createElement('canvas');
|
|
7726
|
+
canvas.width = size; canvas.height = size;
|
|
7727
|
+
const ctx = canvas.getContext('2d');
|
|
7728
|
+
// the disc itself is drawn off-canvas; only its blurred shadow lands at the center
|
|
7729
|
+
ctx.shadowColor = 'rgba(255,255,255,1)';
|
|
7730
|
+
ctx.shadowBlur = sigma * 2;
|
|
7731
|
+
ctx.shadowOffsetX = size * 4;
|
|
7732
|
+
ctx.fillStyle = '#fff';
|
|
7733
|
+
ctx.beginPath(); drawSymbolPath(ctx, shape, c - size * 4, c, disc); ctx.closePath(); ctx.fill();
|
|
7734
|
+
this._glowIconCache.set(key, { url: canvas.toDataURL(), width: size, height: size, anchorX: c, anchorY: c, mask: true, id: key });
|
|
7735
|
+
}
|
|
7736
|
+
return this._glowIconCache.get(key);
|
|
7737
|
+
}
|
|
7738
|
+
|
|
7710
7739
|
_buildBubbleIcon(counts, colors) {
|
|
7711
7740
|
// The cache key quantizes each count's RATIO to the group's total,
|
|
7712
7741
|
// not the raw count — computeBubblePackLayout's radii are purely
|
|
@@ -9506,6 +9535,34 @@
|
|
|
9506
9535
|
const singleBorderColorRgb = this.style.linecolor && styleLineColor(this.style.linecolor) !== 'none' ? hexOrNamedToRgb(styleLineColor(this.style.linecolor)) : null;
|
|
9507
9536
|
const singleBorderWidthPx = styleNum(this.style.linewidth) || 0;
|
|
9508
9537
|
|
|
9538
|
+
const itemRgb = d => this.categoryColorsRgb[d.properties.counts ? dominant(d.properties.counts) : d.properties.cat] || [128, 128, 128];
|
|
9539
|
+
const radiusOf = d => valueRadius(sizeValueOf(d), liveZoom, this.style, this.mapOptions, this.flags, this._maxSizeValue);
|
|
9540
|
+
|
|
9541
|
+
// SHADOW (style.shadow, flat's gate: maxshadow, shadowupper/lower — flatShadowOn): a soft
|
|
9542
|
+
// drop shadow under each symbol, see _getShadowIcon
|
|
9543
|
+
if (flatShadowOn(this.style, combined.length, liveZoom)) {
|
|
9544
|
+
const blurPx = styleNum(this.style.shadowblur) || 3;
|
|
9545
|
+
const num = (v, d) => (isNaN(styleNum(v)) ? d : styleNum(v));
|
|
9546
|
+
const dx = num(this.style.shadowdx, 1.5), dy = num(this.style.shadowdy, 2.5);
|
|
9547
|
+
layers.push(new IconLayer({
|
|
9548
|
+
id: `ix-symbolshadow-${this.name}-g${this._iconGeneration}`,
|
|
9549
|
+
data: combined, pickable: false,
|
|
9550
|
+
getPosition: d => d.geometry.coordinates,
|
|
9551
|
+
getIcon: d => this._getShadowIcon(radiusOf(d), blurPx, d.properties.counts ? 'circle' : this._resolveSymbolShape(d.properties)),
|
|
9552
|
+
getSize: d => radiusOf(d) * 3, // disc = 2/3 of the icon → its diameter is 2r
|
|
9553
|
+
getPixelOffset: [dx, dy],
|
|
9554
|
+
getColor: d => {
|
|
9555
|
+
const rgb = itemRgb(d);
|
|
9556
|
+
const gray = Math.round(Math.min(255, 0.1 * (rgb[0] + rgb[1] + rgb[2])));
|
|
9557
|
+
return [gray, gray, gray, Math.round(this._iconAlpha(d) * fillOpacity)];
|
|
9558
|
+
},
|
|
9559
|
+
sizeUnits: 'pixels',
|
|
9560
|
+
billboard: true,
|
|
9561
|
+
parameters: ICON_LAYER_GLOBE_PARAMETERS,
|
|
9562
|
+
updateTriggers: { getIcon: [liveZoom, blurPx], getSize: liveZoom }
|
|
9563
|
+
}));
|
|
9564
|
+
}
|
|
9565
|
+
|
|
9509
9566
|
// GLOW: gradient-texture halo (see _getGlowIcon for why this diverges
|
|
9510
9567
|
// from the real engine's literal flat-circle formula). Individual
|
|
9511
9568
|
// and cluster glows keep their own size multiplier (11 vs 9 — a lone
|
|
@@ -9523,6 +9580,20 @@
|
|
|
9523
9580
|
billboard: true,
|
|
9524
9581
|
parameters: ICON_LAYER_GLOBE_PARAMETERS
|
|
9525
9582
|
}));
|
|
9583
|
+
} else if (this.flags.has('AURA') && !this.flags.has('ZOOM')) {
|
|
9584
|
+
// AURA (flat maptheme.js 20924-20930, the GLOW branch's `else`): a circle at 1.3 × the
|
|
9585
|
+
// radius behind the symbol, in the line color (else the symbol's), at 0.3 opacity
|
|
9586
|
+
layers.push(new IconLayer({
|
|
9587
|
+
id: `ix-aura-${this.name}-g${this._iconGeneration}`,
|
|
9588
|
+
data: combined, pickable: false,
|
|
9589
|
+
getPosition: d => d.geometry.coordinates,
|
|
9590
|
+
getIcon: d => this._buildSingleIcon(singleBorderColorRgb || itemRgb(d), 0.3, 'circle', null, 0),
|
|
9591
|
+
getSize: d => radiusOf(d) * 2 * 1.3,
|
|
9592
|
+
getColor: d => [255, 255, 255, this._iconAlpha(d)],
|
|
9593
|
+
sizeUnits: 'pixels',
|
|
9594
|
+
billboard: true,
|
|
9595
|
+
parameters: ICON_LAYER_GLOBE_PARAMETERS
|
|
9596
|
+
}));
|
|
9526
9597
|
}
|
|
9527
9598
|
|
|
9528
9599
|
// BOX / CIRCULARBOX with TITLE / BOTTOMTITLE — flat's BOX block
|