ixmaps-gl 0.1.0 → 0.2.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/README.md +10 -2
- package/ixmaps-gl.js +67 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -190,13 +190,21 @@ of your own project files gl can render.
|
|
|
190
190
|
Load the engine from jsDelivr, pinned to a release tag (or `@main` for the latest commit):
|
|
191
191
|
|
|
192
192
|
```html
|
|
193
|
-
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.
|
|
193
|
+
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.2.0/ixmaps-gl.js"></script>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
or from unpkg, the npm package [`ixmaps-gl`](https://www.npmjs.com/package/ixmaps-gl)
|
|
197
|
+
(`https://unpkg.com/ixmaps-gl` for the latest version; `npm install ixmaps-gl` installs the same
|
|
198
|
+
browser script, which defines the global `ixmaps`):
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<script src="https://unpkg.com/ixmaps-gl@0.2.0/ixmaps-gl.js"></script>
|
|
194
202
|
```
|
|
195
203
|
|
|
196
204
|
or use a local copy (`<script src="ixmaps-gl.js"></script>`). A minimal page:
|
|
197
205
|
|
|
198
206
|
```html
|
|
199
|
-
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.
|
|
207
|
+
<script src="https://cdn.jsdelivr.net/gh/gjrichter/ixmaps-gl@v0.2.0/ixmaps-gl.js"></script>
|
|
200
208
|
<div id="map_div" style="position:absolute;inset:0;"></div>
|
|
201
209
|
|
|
202
210
|
<script>
|
package/ixmaps-gl.js
CHANGED
|
@@ -78,14 +78,27 @@
|
|
|
78
78
|
// Same CDN builds every example page already pinned; centralized here
|
|
79
79
|
// so bumping a version is a one-file edit, not a 13-file one.
|
|
80
80
|
// ---------------------------------------------------------------
|
|
81
|
+
// this engine's release (= package.json "version", checked by
|
|
82
|
+
// test/unit/version.test.mjs); ixmaps.glVersion, and logged once at start
|
|
83
|
+
const IXMAPS_GL_VERSION = '0.2.0';
|
|
84
|
+
|
|
81
85
|
const LIB_URLS = {
|
|
82
86
|
// Bumped 3.6.2 -> 5.x (2026-09-21, globe-projection compat fix): native
|
|
83
87
|
// globe projection (map.setProjection({type:'globe'})) needs >=5.0.1
|
|
84
88
|
// (5.0.0 shipped a style-spec regression, reverted in 5.0.1). Requires
|
|
85
89
|
// MapLibre GL JS v4.5.1, v5, or v6 on the deck.gl side (see `deck`
|
|
86
90
|
// below) — v5 satisfies that.
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
// 5.x -> 6.x (2026-09-29): MapLibre 6 is published only as an ES
|
|
92
|
+
// module (dist/maplibre-gl.mjs, named exports, no UMD bundle and no
|
|
93
|
+
// window.maplibregl) — loadMaplibre imports it and provides the global.
|
|
94
|
+
// Its worker (maplibre-gl-worker.mjs, resolved next to the module) is
|
|
95
|
+
// cross-origin from the CDN; MapLibre wraps it in a same-origin blob URL
|
|
96
|
+
// itself. Pinned to an exact version: unpkg answers a version range
|
|
97
|
+
// (@6) with a redirect, and a browser refuses a worker script that
|
|
98
|
+
// redirects ("Refused to cross-origin redirects of the top-level worker
|
|
99
|
+
// script" — the map never loaded on a file:// page).
|
|
100
|
+
maplibreCss: 'https://unpkg.com/maplibre-gl@6.11.2/dist/maplibre-gl.css',
|
|
101
|
+
maplibreJs: 'https://unpkg.com/maplibre-gl@6.11.2/dist/maplibre-gl.mjs',
|
|
89
102
|
// Bumped 8.9.35 -> 9.4.0 (2026-09-21, globe-reprojection fix): v8's
|
|
90
103
|
// interleaving (MapboxOverlay) always computed flat Web-Mercator
|
|
91
104
|
// screen positions regardless of the map's actual projection —
|
|
@@ -117,6 +130,49 @@
|
|
|
117
130
|
document.head.appendChild(el);
|
|
118
131
|
});
|
|
119
132
|
}
|
|
133
|
+
// MapLibre 6's ES module → the window.maplibregl the engine and pages use
|
|
134
|
+
// (a copy of its named exports: a module namespace is read-only)
|
|
135
|
+
function loadMaplibre(src) {
|
|
136
|
+
installFileWorkerShim();
|
|
137
|
+
return import(src).then(mod => {
|
|
138
|
+
global.maplibregl = Object.assign({}, mod.default || {}, mod);
|
|
139
|
+
}, err => { throw new Error(`[ixmaps-gl] failed to load ${src}: ${err && err.message}`); });
|
|
140
|
+
}
|
|
141
|
+
// MapLibre 6 starts its worker as a module worker; for a worker on the
|
|
142
|
+
// CDN it wraps it in a blob URL (`import "…maplibre-gl-worker.mjs"`).
|
|
143
|
+
// On a file:// page Chrome refuses every module worker from a blob URL
|
|
144
|
+
// ("Refused to cross-origin redirects of the top-level worker script" —
|
|
145
|
+
// the map never loaded), while a module worker from a data: URL works.
|
|
146
|
+
// Only there, and only for MapLibre's own wrapper, the Worker is started
|
|
147
|
+
// from the same import as a data: URL. Other workers are untouched.
|
|
148
|
+
function installFileWorkerShim() {
|
|
149
|
+
if (!global.location || global.location.protocol !== 'file:' || !global.Worker || global.Worker.__ixmapsGlFileShim) return;
|
|
150
|
+
const NativeBlob = global.Blob, NativeWorker = global.Worker;
|
|
151
|
+
const maplibreWorkerImport = new WeakMap(); // Blob → its import statement
|
|
152
|
+
const blobUrls = new Map(); // blob: URL → import statement
|
|
153
|
+
const isMaplibreImport = t => typeof t === 'string' && /^import "https?:[^"]*\/maplibre-gl-worker(-dev)?\.mjs"$/.test(t);
|
|
154
|
+
function Blob(parts, opts) {
|
|
155
|
+
const b = new NativeBlob(parts, opts);
|
|
156
|
+
if (Array.isArray(parts) && parts.length === 1 && isMaplibreImport(parts[0])) maplibreWorkerImport.set(b, parts[0]);
|
|
157
|
+
return b;
|
|
158
|
+
}
|
|
159
|
+
Blob.prototype = NativeBlob.prototype;
|
|
160
|
+
global.Blob = Blob;
|
|
161
|
+
const nativeCreate = global.URL.createObjectURL;
|
|
162
|
+
global.URL.createObjectURL = function (obj) {
|
|
163
|
+
const u = nativeCreate.call(this, obj);
|
|
164
|
+
if (maplibreWorkerImport.has(obj)) blobUrls.set(u, maplibreWorkerImport.get(obj));
|
|
165
|
+
return u;
|
|
166
|
+
};
|
|
167
|
+
function Worker(url, opts) {
|
|
168
|
+
const imp = blobUrls.get(String(url));
|
|
169
|
+
if (imp && opts && opts.type === 'module') return new NativeWorker('data:text/javascript,' + encodeURIComponent(imp), opts);
|
|
170
|
+
return new NativeWorker(url, opts);
|
|
171
|
+
}
|
|
172
|
+
Worker.prototype = NativeWorker.prototype;
|
|
173
|
+
Worker.__ixmapsGlFileShim = true;
|
|
174
|
+
global.Worker = Worker;
|
|
175
|
+
}
|
|
120
176
|
function loadStylesheet(href) {
|
|
121
177
|
return new Promise((resolve, reject) => {
|
|
122
178
|
const el = document.createElement('link');
|
|
@@ -188,7 +244,7 @@
|
|
|
188
244
|
}
|
|
189
245
|
if (i === 2) return true;
|
|
190
246
|
}
|
|
191
|
-
console.warn(`[ixmaps-gl] this page loads maplibre-gl ${v || '(unknown version)'}; deck.gl needs >= ${MAPLIBRE_MIN_VERSION.join('.')} — loading ${LIB_URLS.maplibreJs.match(/maplibre-gl@([\d.]+)/)[1]}
|
|
247
|
+
console.warn(`[ixmaps-gl] this page loads maplibre-gl ${v || '(unknown version)'}; deck.gl needs >= ${MAPLIBRE_MIN_VERSION.join('.')} — loading ${LIB_URLS.maplibreJs.match(/maplibre-gl@([\d.]+)/)[1]} instead (it replaces window.maplibregl); remove the page's own maplibre-gl <script> tag`);
|
|
192
248
|
return false;
|
|
193
249
|
}
|
|
194
250
|
// data.js, unless the page has it already: .options({datajs: url}) loads
|
|
@@ -213,12 +269,16 @@
|
|
|
213
269
|
function ensureLibrariesLoaded() {
|
|
214
270
|
if (!_librariesPromise) {
|
|
215
271
|
_librariesPromise = Promise.all([
|
|
216
|
-
pageMaplibreUsable() ? Promise.resolve() :
|
|
272
|
+
pageMaplibreUsable() ? Promise.resolve() : loadMaplibre(LIB_URLS.maplibreJs),
|
|
217
273
|
pageDeckUsable() ? Promise.resolve() : loadScript(LIB_URLS.deck),
|
|
218
274
|
global.Mustache ? Promise.resolve() : loadScript(LIB_URLS.mustache),
|
|
219
275
|
[...document.styleSheets].some(s => s.href === LIB_URLS.maplibreCss) ? Promise.resolve() : loadStylesheet(LIB_URLS.maplibreCss)
|
|
220
276
|
]).then(() => {
|
|
221
277
|
({ IconLayer, ScatterplotLayer, GeoJsonLayer, MapLibreOverlay, TextLayer } = global.deck);
|
|
278
|
+
// which engine and libraries this page really runs (a page may
|
|
279
|
+
// bring its own MapLibre/deck.gl — the loaded ones are named)
|
|
280
|
+
const ml = global.maplibregl && typeof global.maplibregl.getVersion === 'function' ? global.maplibregl.getVersion() : '?';
|
|
281
|
+
console.info(`[ixmaps-gl] ${IXMAPS_GL_VERSION} · MapLibre ${ml} · deck.gl ${global.deck.VERSION || '?'}`);
|
|
222
282
|
// Matches the real engine's own ui/js/tools/tooltip_mustache.js,
|
|
223
283
|
// which overrides Mustache.escape to identity: tooltip HTML (the
|
|
224
284
|
// template itself, and this engine's own chart/data-table
|
|
@@ -9887,6 +9947,8 @@
|
|
|
9887
9947
|
szResourceBase: ixmapsSzResourceBase, getProjectString, setProjectJSON, loadProject,
|
|
9888
9948
|
markThemeClass, unmarkThemeClass, getBoundingBox, setTitle, setTitleBox, refreshTheme, formatValue: flatFormatValue,
|
|
9889
9949
|
map: mapHandle, getZoom,
|
|
9950
|
+
// this engine's version (flat's own ixmaps.version numbers flat)
|
|
9951
|
+
glVersion: IXMAPS_GL_VERSION,
|
|
9890
9952
|
// flat always has this page hook (its layer legend tool defines it,
|
|
9891
9953
|
// ui/js/tools/layer_legend.js 702-712): pages wrap it and call the one
|
|
9892
9954
|
// they replaced — the chain ends here
|
|
@@ -9905,6 +9967,7 @@
|
|
|
9905
9967
|
// test-only: lets test/unit/*.test.mjs call pure internals directly (the
|
|
9906
9968
|
// engine runs in a Node vm there); deliberately NOT on the ixmaps object
|
|
9907
9969
|
global.__ixmapsGlInternals = {
|
|
9970
|
+
IXMAPS_GL_VERSION,
|
|
9908
9971
|
normalizeTheme, projectThemeToDefinition, LayerBuilder, LayerRuntime, typeStyleNumbers, styleNum,
|
|
9909
9972
|
resolveScriptUrl, isTrustedScriptUrl, loadProcessingScript, loadBrokerData, applyBrokerThemePatch, makeBrokerTheme,
|
|
9910
9973
|
equalIntervalBreaks, quantileBreaks, naturalBreaks, evenStrideSample, jenksBreakValues, partsFromBreakValues, resolvePartsClass,
|