@caoguo/maplibre 0.0.3 → 0.0.6
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/dist/{chunk-EZOV5O2M.js → chunk-QGVXYR2I.js} +3 -3
- package/dist/{chunk-EZOV5O2M.js.map → chunk-QGVXYR2I.js.map} +1 -1
- package/dist/index.cjs +361 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +269 -27
- package/dist/index.d.ts +269 -27
- package/dist/index.js +353 -42
- package/dist/index.js.map +1 -1
- package/dist/sources/index.cjs +1 -1
- package/dist/sources/index.cjs.map +1 -1
- package/dist/sources/index.js +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { caoguoStyle, WUHAN_ZOOM, WUHAN_CENTER
|
|
1
|
+
import { caoguoStyle, osmRasterStyle, WUHAN_ZOOM, WUHAN_CENTER } from './chunk-DNEF4DHG.js';
|
|
2
2
|
export { WUHAN_CENTER, WUHAN_ZOOM, osmRasterStyle } from './chunk-DNEF4DHG.js';
|
|
3
|
-
import { tiandituStyle, addTiandituBaseMap } from './chunk-
|
|
4
|
-
export { MissingTokenError, addTiandituBaseMap, buildTiandituSources, tiandituStyle, tiandituTileUrls } from './chunk-
|
|
3
|
+
import { MissingTokenError, tiandituStyle, addTiandituBaseMap } from './chunk-QGVXYR2I.js';
|
|
4
|
+
export { MissingTokenError, addTiandituBaseMap, buildTiandituSources, tiandituStyle, tiandituTileUrls } from './chunk-QGVXYR2I.js';
|
|
5
5
|
import { createDefaultStore, registerOfflineProtocol, offlineSourceTiles, packGeoJSONToStore } from './chunk-MNUQZUQA.js';
|
|
6
6
|
export { CACHEABLE_HOSTS, CACHE_NAME, IdbTileStore, MSG_AIRGAP, MemoryTileStore, OFFLINE_PROTOCOL, SW_TEMPLATE_HINT, createDefaultStore, createFetchHandler, createOfflineLoader, installServiceWorker, offlineGeoJSONSource, offlineSourceTiles, offlineTileUrl, packGeoJSONToStore, parseOfflineUrl, registerOfflineProtocol, registerOfflineServiceWorker, resolveCacheKey, resolveFromStore, resolveResponse, setAirgap, shouldCache, tileKey } from './chunk-MNUQZUQA.js';
|
|
7
7
|
import maplibregl from 'maplibre-gl';
|
|
@@ -258,15 +258,96 @@ var ThemeSwitcher = class {
|
|
|
258
258
|
}
|
|
259
259
|
};
|
|
260
260
|
|
|
261
|
+
// src/controls/LegendControl.ts
|
|
262
|
+
function escapeHtml(s) {
|
|
263
|
+
return s.replace(
|
|
264
|
+
/[&<>"']/g,
|
|
265
|
+
(c) => c === "&" ? "&" : c === "<" ? "<" : c === ">" ? ">" : c === '"' ? """ : "'"
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
function renderLegendHtml(items, title) {
|
|
269
|
+
const titleHtml = title ? `<div class="cg-legend-title">${escapeHtml(title)}</div>` : "";
|
|
270
|
+
const itemsHtml = items.map((it) => {
|
|
271
|
+
const swatch = it.shape === "line" ? `<span class="cg-legend-swatch cg-legend-swatch--line" style="background:${it.color}"></span>` : `<span class="cg-legend-swatch" style="background:${it.color}"></span>`;
|
|
272
|
+
return `<div class="cg-legend-item">${swatch}<span>${escapeHtml(it.label)}</span></div>`;
|
|
273
|
+
}).join("");
|
|
274
|
+
return `<div class="cg-legend-body">${titleHtml}${itemsHtml}</div>`;
|
|
275
|
+
}
|
|
276
|
+
var LegendControl = class {
|
|
277
|
+
constructor(options) {
|
|
278
|
+
this.opts = { title: options.title ?? "", items: options.items };
|
|
279
|
+
this.el = options.container ?? document.createElement("div");
|
|
280
|
+
this.el.className = "caoguo-legend-control";
|
|
281
|
+
this.el.style.cssText = "position:absolute;right:10px;top:10px;padding:8px 10px;background:rgba(10,15,30,.72);color:#cfe;border-radius:6px;font:12px/1.5 system-ui,sans-serif;z-index:2;max-width:220px;";
|
|
282
|
+
this.bodyEl = document.createElement("div");
|
|
283
|
+
this.el.appendChild(this.bodyEl);
|
|
284
|
+
this.render();
|
|
285
|
+
}
|
|
286
|
+
render() {
|
|
287
|
+
this.bodyEl.innerHTML = renderLegendHtml(this.opts.items, this.opts.title || void 0);
|
|
288
|
+
}
|
|
289
|
+
/** 运行时更新图例项(随图层切换重新渲染) */
|
|
290
|
+
setItems(items, title) {
|
|
291
|
+
if (title !== void 0) this.opts.title = title;
|
|
292
|
+
this.opts.items = items;
|
|
293
|
+
this.render();
|
|
294
|
+
}
|
|
295
|
+
/** 挂载到容器 */
|
|
296
|
+
addTo(container) {
|
|
297
|
+
if (!this.el.parentElement) container.appendChild(this.el);
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
300
|
+
remove() {
|
|
301
|
+
this.el.remove();
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/controls/ExportControl.ts
|
|
306
|
+
function triggerDownload(dataUrl, filename) {
|
|
307
|
+
const a = document.createElement("a");
|
|
308
|
+
a.href = dataUrl;
|
|
309
|
+
a.download = filename.endsWith(".png") ? filename : `${filename}.png`;
|
|
310
|
+
document.body.appendChild(a);
|
|
311
|
+
a.click();
|
|
312
|
+
a.remove();
|
|
313
|
+
}
|
|
314
|
+
var ExportControl = class {
|
|
315
|
+
constructor(map, options = {}) {
|
|
316
|
+
this.onClick = () => this.export();
|
|
317
|
+
this.map = map;
|
|
318
|
+
this.filename = options.filename ?? "caoguo-map";
|
|
319
|
+
this.el = options.container ?? document.createElement("button");
|
|
320
|
+
this.el.className = "caoguo-export-control";
|
|
321
|
+
this.el.textContent = options.buttonText ?? "\u5BFC\u51FA PNG";
|
|
322
|
+
this.el.style.cssText = "position:absolute;right:10px;top:10px;padding:5px 10px;background:rgba(10,15,30,.72);color:#cfe;border:1px solid #2a3550;border-radius:4px;font:12px system-ui,sans-serif;cursor:pointer;z-index:3;";
|
|
323
|
+
this.el.addEventListener("click", this.onClick);
|
|
324
|
+
}
|
|
325
|
+
/** 导出当前地图视图为 PNG 并下载 */
|
|
326
|
+
export() {
|
|
327
|
+
const canvas = this.map.getCanvas();
|
|
328
|
+
const url = canvas.toDataURL("image/png");
|
|
329
|
+
triggerDownload(url, this.filename);
|
|
330
|
+
}
|
|
331
|
+
/** 挂载到容器 */
|
|
332
|
+
addTo(container) {
|
|
333
|
+
if (!this.el.parentElement) container.appendChild(this.el);
|
|
334
|
+
return this;
|
|
335
|
+
}
|
|
336
|
+
remove() {
|
|
337
|
+
this.el.removeEventListener("click", this.onClick);
|
|
338
|
+
this.el.remove();
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
261
342
|
// src/shaders/glowGeometry.ts
|
|
262
|
-
function glowPasses(passes = 4,
|
|
343
|
+
function glowPasses(passes = 4, baseWidth = 3) {
|
|
263
344
|
if (passes < 1) passes = 1;
|
|
264
345
|
const out = [];
|
|
265
346
|
for (let i = 0; i < passes; i++) {
|
|
266
347
|
const t = passes === 1 ? 1 : 1 - i / (passes - 1);
|
|
267
348
|
out.push({
|
|
268
|
-
|
|
269
|
-
opacity:
|
|
349
|
+
width: baseWidth * (1 + (1 - t) * (passes - 1) * 1.8),
|
|
350
|
+
opacity: 0.1 + 0.9 * t * t
|
|
270
351
|
});
|
|
271
352
|
}
|
|
272
353
|
return out;
|
|
@@ -274,20 +355,58 @@ function glowPasses(passes = 4, coreOpacity = 1) {
|
|
|
274
355
|
function projectSimple(lng, lat) {
|
|
275
356
|
const x = lng / 180;
|
|
276
357
|
const y = Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)) / Math.PI;
|
|
277
|
-
return [x, Math.max(-1, Math.min(1, y))];
|
|
358
|
+
return [x, Math.max(-1, Math.min(1, y / Math.PI))];
|
|
278
359
|
}
|
|
279
360
|
function buildGlowGeometry(lines, opts = {}) {
|
|
280
|
-
const passes = glowPasses(opts.passes ?? 4, opts.
|
|
281
|
-
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
361
|
+
const passes = glowPasses(opts.passes ?? 4, opts.baseWidth ?? 3);
|
|
362
|
+
const stride = 6;
|
|
363
|
+
const verts = [];
|
|
364
|
+
const passRanges = [];
|
|
365
|
+
const renderGroups = [];
|
|
366
|
+
const groups = [];
|
|
367
|
+
for (const line of lines) {
|
|
368
|
+
const g = line.group ?? "default";
|
|
369
|
+
if (!groups.includes(g)) groups.push(g);
|
|
370
|
+
}
|
|
371
|
+
for (let p = 0; p < passes.length; p++) {
|
|
372
|
+
passes[p];
|
|
373
|
+
const start = verts.length / stride;
|
|
374
|
+
for (const group of groups) {
|
|
375
|
+
const groupStart = verts.length / stride;
|
|
376
|
+
const groupIndex = groups.indexOf(group);
|
|
377
|
+
for (const line of lines) {
|
|
378
|
+
if ((line.group ?? "default") !== group) continue;
|
|
379
|
+
const pts = line.coordinates.map(([lng, lat]) => projectSimple(lng, lat));
|
|
380
|
+
if (pts.length < 2) continue;
|
|
381
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
382
|
+
const a = pts[i];
|
|
383
|
+
const b = pts[i + 1];
|
|
384
|
+
const dx = b[0] - a[0];
|
|
385
|
+
const dy = b[1] - a[1];
|
|
386
|
+
const quad = [
|
|
387
|
+
[a[0], a[1], dx, dy, 1, groupIndex],
|
|
388
|
+
[a[0], a[1], dx, dy, -1, groupIndex],
|
|
389
|
+
[b[0], b[1], dx, dy, 1, groupIndex],
|
|
390
|
+
[b[0], b[1], dx, dy, -1, groupIndex]
|
|
391
|
+
];
|
|
392
|
+
const idx = [0, 1, 2, 2, 1, 3];
|
|
393
|
+
for (const k of idx) {
|
|
394
|
+
const v = quad[k];
|
|
395
|
+
verts.push(v[0], v[1], v[2], v[3], v[4], v[5]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const count2 = verts.length / stride - groupStart;
|
|
400
|
+
if (count2 > 0) renderGroups.push({ passIndex: p, group, start: groupStart, count: count2 });
|
|
401
|
+
}
|
|
402
|
+
const count = verts.length / stride - start;
|
|
403
|
+
passRanges.push({ start, count });
|
|
404
|
+
}
|
|
405
|
+
return { vertices: new Float32Array(verts), passRanges, passes, stride, groups, renderGroups };
|
|
288
406
|
}
|
|
289
407
|
|
|
290
408
|
// src/shaders/CustomLineLayer.ts
|
|
409
|
+
var FALLBACK_COLOR = [0.6, 0.7, 0.9];
|
|
291
410
|
var DEFAULT_COLORS = {
|
|
292
411
|
pipe: [0.2, 0.85, 1],
|
|
293
412
|
// 青蓝:管线
|
|
@@ -298,17 +417,21 @@ var DEFAULT_COLORS = {
|
|
|
298
417
|
};
|
|
299
418
|
var VERT = `
|
|
300
419
|
attribute vec2 aPos;
|
|
301
|
-
attribute
|
|
420
|
+
attribute vec2 aDir;
|
|
421
|
+
attribute float aSide;
|
|
302
422
|
uniform mat4 uMatrix;
|
|
303
423
|
uniform float uWidth;
|
|
304
424
|
uniform vec2 uResolution;
|
|
305
425
|
void main() {
|
|
306
|
-
// \u7B80\u5316\uFF1A\u6CBF\u6CD5\u7EBF\u65B9\u5411\u504F\u79FB width\uFF08\u5C4F\u5E55\u7A7A\u95F4\uFF09\uFF0C\u8FD9\u91CC\u4EC5\u6F14\u793A\u6838\u5FC3\u6295\u5F71
|
|
307
426
|
vec4 clip = uMatrix * vec4(aPos, 0.0, 1.0);
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
vec2
|
|
311
|
-
|
|
427
|
+
// \u6BB5\u65B9\u5411\u4E5F\u6295\u5F71\uFF0C\u6C42\u5C4F\u5E55\u7A7A\u95F4\u65B9\u5411
|
|
428
|
+
vec4 clipDir = uMatrix * vec4(aPos + aDir, 0.0, 1.0);
|
|
429
|
+
vec2 s0 = clip.xy / clip.w;
|
|
430
|
+
vec2 s1 = clipDir.xy / clipDir.w;
|
|
431
|
+
vec2 dir = normalize(s1 - s0 + vec2(1e-6));
|
|
432
|
+
vec2 normal = vec2(-dir.y, dir.x);
|
|
433
|
+
vec2 offset = normal * aSide * (uWidth / uResolution * 2.0);
|
|
434
|
+
gl_Position = vec4(s0 + offset * clip.w, clip.z, clip.w);
|
|
312
435
|
}
|
|
313
436
|
`;
|
|
314
437
|
var FRAG = `
|
|
@@ -323,6 +446,9 @@ function compile(gl, type, src) {
|
|
|
323
446
|
const sh = gl.createShader(type);
|
|
324
447
|
gl.shaderSource(sh, src);
|
|
325
448
|
gl.compileShader(sh);
|
|
449
|
+
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
|
|
450
|
+
console.error("[CustomLineLayer] shader \u7F16\u8BD1\u5931\u8D25:", gl.getShaderInfoLog(sh));
|
|
451
|
+
}
|
|
326
452
|
return sh;
|
|
327
453
|
}
|
|
328
454
|
var CustomLineLayer = class {
|
|
@@ -333,40 +459,48 @@ var CustomLineLayer = class {
|
|
|
333
459
|
this.lines = opts.lines;
|
|
334
460
|
this.colors = { ...DEFAULT_COLORS, ...opts.colors };
|
|
335
461
|
this.baseWidth = opts.baseWidth ?? 3;
|
|
336
|
-
this.
|
|
337
|
-
|
|
462
|
+
this.geometry = buildGlowGeometry(this.lines, { passes: opts.passes ?? 4, baseWidth: this.baseWidth });
|
|
463
|
+
for (const g of this.geometry.groups) {
|
|
464
|
+
if (!(g in this.colors)) this.colors[g] = FALLBACK_COLOR;
|
|
465
|
+
}
|
|
338
466
|
}
|
|
339
467
|
onAdd(map, gl) {
|
|
340
468
|
this.map = map;
|
|
469
|
+
this.gl = gl;
|
|
341
470
|
const vs = compile(gl, gl.VERTEX_SHADER, VERT);
|
|
342
471
|
const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);
|
|
343
472
|
const prog = gl.createProgram();
|
|
344
473
|
gl.attachShader(prog, vs);
|
|
345
474
|
gl.attachShader(prog, fs);
|
|
346
475
|
gl.linkProgram(prog);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
for (const line of this.geometry.lines) {
|
|
350
|
-
const pts = line.points;
|
|
351
|
-
for (let i = 0; i < pts.length - 1; i++) {
|
|
352
|
-
verts.push(pts[i][0], pts[i][1], 0, pts[i + 1][0], pts[i + 1][1], 0);
|
|
353
|
-
}
|
|
476
|
+
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
|
|
477
|
+
console.error("[CustomLineLayer] program \u94FE\u63A5\u5931\u8D25:", gl.getProgramInfoLog(prog));
|
|
354
478
|
}
|
|
479
|
+
this.program = prog;
|
|
355
480
|
const buf = gl.createBuffer();
|
|
356
481
|
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
357
|
-
gl.bufferData(gl.ARRAY_BUFFER,
|
|
482
|
+
gl.bufferData(gl.ARRAY_BUFFER, this.geometry.vertices, gl.STATIC_DRAW);
|
|
358
483
|
this.buffer = buf;
|
|
359
484
|
}
|
|
360
485
|
render(gl, matrix) {
|
|
361
486
|
if (!this.program || !this.buffer) return;
|
|
362
487
|
gl.useProgram(this.program);
|
|
363
488
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
|
489
|
+
const stride = this.geometry.stride * 4;
|
|
364
490
|
const aPos = gl.getAttribLocation(this.program, "aPos");
|
|
365
|
-
const
|
|
491
|
+
const aDir = gl.getAttribLocation(this.program, "aDir");
|
|
492
|
+
const aSide = gl.getAttribLocation(this.program, "aSide");
|
|
493
|
+
const aGroup = gl.getAttribLocation(this.program, "aGroup");
|
|
366
494
|
gl.enableVertexAttribArray(aPos);
|
|
367
|
-
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false,
|
|
368
|
-
gl.enableVertexAttribArray(
|
|
369
|
-
gl.vertexAttribPointer(
|
|
495
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, stride, 0);
|
|
496
|
+
gl.enableVertexAttribArray(aDir);
|
|
497
|
+
gl.vertexAttribPointer(aDir, 2, gl.FLOAT, false, stride, 8);
|
|
498
|
+
gl.enableVertexAttribArray(aSide);
|
|
499
|
+
gl.vertexAttribPointer(aSide, 1, gl.FLOAT, false, stride, 16);
|
|
500
|
+
if (aGroup >= 0) {
|
|
501
|
+
gl.enableVertexAttribArray(aGroup);
|
|
502
|
+
gl.vertexAttribPointer(aGroup, 1, gl.FLOAT, false, stride, 20);
|
|
503
|
+
}
|
|
370
504
|
const uMatrix = gl.getUniformLocation(this.program, "uMatrix");
|
|
371
505
|
gl.uniformMatrix4fv(uMatrix, false, new Float32Array(matrix));
|
|
372
506
|
const uWidth = gl.getUniformLocation(this.program, "uWidth");
|
|
@@ -377,12 +511,31 @@ var CustomLineLayer = class {
|
|
|
377
511
|
gl.uniform2f(uRes, canvas?.width ?? 1024, canvas?.height ?? 768);
|
|
378
512
|
gl.enable(gl.BLEND);
|
|
379
513
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
514
|
+
for (const rg of this.geometry.renderGroups) {
|
|
515
|
+
const pass = this.geometry.passes[rg.passIndex];
|
|
516
|
+
const color = this.colors[rg.group] ?? FALLBACK_COLOR;
|
|
517
|
+
gl.uniform1f(uWidth, pass.width);
|
|
383
518
|
gl.uniform3f(uColor, color[0], color[1], color[2]);
|
|
384
519
|
gl.uniform1f(uOpacity, pass.opacity);
|
|
385
|
-
gl.drawArrays(gl.
|
|
520
|
+
gl.drawArrays(gl.TRIANGLES, rg.start, rg.count);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* 动态更新线集合(高亮选中、切换数据等无需重建图层)。
|
|
525
|
+
* 浏览器环境会刷新 GPU 缓冲;纯逻辑/测试环境仅更新几何与数据。
|
|
526
|
+
*/
|
|
527
|
+
setLines(lines) {
|
|
528
|
+
this.lines = lines;
|
|
529
|
+
this.geometry = buildGlowGeometry(this.lines, {
|
|
530
|
+
passes: this.geometry.passes.length,
|
|
531
|
+
baseWidth: this.baseWidth
|
|
532
|
+
});
|
|
533
|
+
for (const g of this.geometry.groups) {
|
|
534
|
+
if (!(g in this.colors)) this.colors[g] = FALLBACK_COLOR;
|
|
535
|
+
}
|
|
536
|
+
if (this.buffer && this.gl) {
|
|
537
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);
|
|
538
|
+
this.gl.bufferData(this.gl.ARRAY_BUFFER, this.geometry.vertices, this.gl.STATIC_DRAW);
|
|
386
539
|
}
|
|
387
540
|
}
|
|
388
541
|
onRemove(_map, gl) {
|
|
@@ -446,17 +599,119 @@ var LodController = class {
|
|
|
446
599
|
}
|
|
447
600
|
};
|
|
448
601
|
|
|
602
|
+
// src/terrain.ts
|
|
603
|
+
var DEFAULT_TERRAIN_TILES = [
|
|
604
|
+
"https://elevation-tiles-prod.s3.amazonaws.com/terrarium/{z}/{x}/{y}.png"
|
|
605
|
+
];
|
|
606
|
+
function applyTerrain(mlMap, opts = {}) {
|
|
607
|
+
const sourceId = opts.sourceId ?? "cg-dem";
|
|
608
|
+
if (!mlMap.getSource(sourceId)) {
|
|
609
|
+
mlMap.addSource(sourceId, {
|
|
610
|
+
type: "raster-dem",
|
|
611
|
+
tiles: opts.tiles ?? DEFAULT_TERRAIN_TILES,
|
|
612
|
+
encoding: opts.encoding ?? "terrarium",
|
|
613
|
+
tileSize: 256,
|
|
614
|
+
maxzoom: opts.maxzoom ?? 15
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
mlMap.setTerrain({ source: sourceId, exaggeration: opts.exaggeration ?? 1.5 });
|
|
618
|
+
}
|
|
619
|
+
function removeTerrain(mlMap, sourceId = "cg-dem") {
|
|
620
|
+
mlMap.setTerrain(null);
|
|
621
|
+
if (mlMap.getSource(sourceId)) {
|
|
622
|
+
mlMap.removeSource(sourceId);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/sourceUtils.ts
|
|
627
|
+
function upsertSource(mlMap, id, data) {
|
|
628
|
+
if (mlMap.getSource(id)) {
|
|
629
|
+
if (mlMap.setData) {
|
|
630
|
+
mlMap.setData(id, data);
|
|
631
|
+
} else if (mlMap.addSource) {
|
|
632
|
+
mlMap.addSource(id, data);
|
|
633
|
+
}
|
|
634
|
+
} else if (mlMap.addSource) {
|
|
635
|
+
mlMap.addSource(id, data);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
function removeSourceSafe(mlMap, id) {
|
|
639
|
+
if (mlMap.getSource(id) && mlMap.removeSource) {
|
|
640
|
+
mlMap.removeSource(id);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function removeSourcesSafe(mlMap, ids) {
|
|
644
|
+
for (const id of ids) {
|
|
645
|
+
removeSourceSafe(mlMap, id);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
449
649
|
// src/index.ts
|
|
650
|
+
var WebGLUnavailableError = class extends Error {
|
|
651
|
+
constructor(message = "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 WebGL\uFF0C\u65E0\u6CD5\u6E32\u67D3\u5730\u56FE") {
|
|
652
|
+
super(message);
|
|
653
|
+
this.name = "WebGLUnavailableError";
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
function isWebGLAvailable() {
|
|
657
|
+
try {
|
|
658
|
+
const canvas = document.createElement("canvas");
|
|
659
|
+
let failed = false;
|
|
660
|
+
const onErr = () => {
|
|
661
|
+
failed = true;
|
|
662
|
+
};
|
|
663
|
+
canvas.addEventListener("webglcontextcreationerror", onErr, { once: true });
|
|
664
|
+
const gl = canvas.getContext("webgl2") || canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
665
|
+
canvas.removeEventListener("webglcontextcreationerror", onErr);
|
|
666
|
+
if (failed || !gl) return false;
|
|
667
|
+
const vendor = gl.getParameter(gl.VERSION);
|
|
668
|
+
if (!vendor) return false;
|
|
669
|
+
const vs = gl.createShader(gl.VERTEX_SHADER);
|
|
670
|
+
if (!vs) return false;
|
|
671
|
+
gl.shaderSource(vs, "attribute vec2 p; void main(){ gl_Position = vec4(p,0.0,1.0); }");
|
|
672
|
+
gl.compileShader(vs);
|
|
673
|
+
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) return false;
|
|
674
|
+
return true;
|
|
675
|
+
} catch {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
var GLOBAL_KEY = "__caoguoMapConfig__";
|
|
680
|
+
function setGlobalConfig(cfg) {
|
|
681
|
+
const prev = getGlobalConfig();
|
|
682
|
+
globalThis[GLOBAL_KEY] = { ...prev, ...cfg };
|
|
683
|
+
}
|
|
684
|
+
function getGlobalConfig() {
|
|
685
|
+
return globalThis[GLOBAL_KEY] ?? {};
|
|
686
|
+
}
|
|
450
687
|
var Map = class {
|
|
451
688
|
constructor(options) {
|
|
452
689
|
/** 离线瓦片后端(默认浏览器 IndexedDB / Node 内存) */
|
|
453
690
|
this._store = createDefaultStore();
|
|
454
691
|
this._dataCRS = options.dataCRS ?? "WGS84";
|
|
692
|
+
if (!isWebGLAvailable()) {
|
|
693
|
+
throw new WebGLUnavailableError();
|
|
694
|
+
}
|
|
695
|
+
let style = osmRasterStyle();
|
|
696
|
+
if (options.style) {
|
|
697
|
+
style = options.style;
|
|
698
|
+
} else if (options.tianditu) {
|
|
699
|
+
if (!options.tianditu.token) throw new MissingTokenError();
|
|
700
|
+
style = tiandituStyle(
|
|
701
|
+
options.tianditu.type ?? "vector",
|
|
702
|
+
options.tianditu
|
|
703
|
+
);
|
|
704
|
+
} else {
|
|
705
|
+
const g = getGlobalConfig();
|
|
706
|
+
if (g.tiandituToken) {
|
|
707
|
+
style = tiandituStyle("vector", { token: g.tiandituToken });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
455
710
|
this._map = new maplibregl.Map({
|
|
456
711
|
container: options.container,
|
|
457
712
|
center: options.center ?? WUHAN_CENTER,
|
|
458
713
|
zoom: options.zoom ?? WUHAN_ZOOM,
|
|
459
|
-
style
|
|
714
|
+
style,
|
|
460
715
|
pitch: options.pitch ?? 0,
|
|
461
716
|
bearing: options.bearing ?? 0,
|
|
462
717
|
attributionControl: { compact: true }
|
|
@@ -525,8 +780,23 @@ var Map = class {
|
|
|
525
780
|
else this._map.on(event, cb);
|
|
526
781
|
}
|
|
527
782
|
addSource(id, source) {
|
|
783
|
+
if (this._map.getSource(id)) {
|
|
784
|
+
try {
|
|
785
|
+
this._map.removeSource(id);
|
|
786
|
+
} catch {
|
|
787
|
+
}
|
|
788
|
+
}
|
|
528
789
|
this._map.addSource(id, source);
|
|
529
790
|
}
|
|
791
|
+
/** 安全移除 source(不存在时静默忽略) */
|
|
792
|
+
removeSource(id) {
|
|
793
|
+
if (this._map.getSource(id)) {
|
|
794
|
+
try {
|
|
795
|
+
this._map.removeSource(id);
|
|
796
|
+
} catch {
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
530
800
|
getSource(id) {
|
|
531
801
|
return this._map.getSource(id);
|
|
532
802
|
}
|
|
@@ -556,6 +826,26 @@ var Map = class {
|
|
|
556
826
|
ctrl.addTo(container);
|
|
557
827
|
return ctrl;
|
|
558
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* 挂载图例控件(通用):渲染数据驱动的色块/线段图例,说明专题图层语义。
|
|
831
|
+
* 返回控件实例,可调用 .setItems() 随图层切换更新、.remove() 卸载。
|
|
832
|
+
*/
|
|
833
|
+
addLegendControl(options) {
|
|
834
|
+
const ctrl = new LegendControl(options);
|
|
835
|
+
const container = this._map.getContainer();
|
|
836
|
+
ctrl.addTo(container);
|
|
837
|
+
return ctrl;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* 挂载地图导出控件(通用):点击按钮将当前视图导出为 PNG 下载。
|
|
841
|
+
* 返回控件实例,可调用 .remove() 卸载。
|
|
842
|
+
*/
|
|
843
|
+
addExportControl(options = {}) {
|
|
844
|
+
const ctrl = new ExportControl(this._map, options);
|
|
845
|
+
const container = this._map.getContainer();
|
|
846
|
+
ctrl.addTo(container);
|
|
847
|
+
return ctrl;
|
|
848
|
+
}
|
|
559
849
|
/**
|
|
560
850
|
* 挂载辉光管线 Custom Layer(T6 / F-1.3)。
|
|
561
851
|
* 传入 GeoJSON 线集合,叠加渲染管线/路网/水系辉光效果。
|
|
@@ -564,7 +854,10 @@ var Map = class {
|
|
|
564
854
|
addGlowLayer(opts) {
|
|
565
855
|
const layer = new CustomLineLayer(opts);
|
|
566
856
|
this._map.addLayer(layer);
|
|
567
|
-
return
|
|
857
|
+
return {
|
|
858
|
+
id: layer.id,
|
|
859
|
+
setLines: (lines) => layer.setLines(lines)
|
|
860
|
+
};
|
|
568
861
|
}
|
|
569
862
|
/**
|
|
570
863
|
* 挂载 LOD 控制器(T7 / F-1.7)。
|
|
@@ -576,12 +869,30 @@ var Map = class {
|
|
|
576
869
|
ctrl.evaluate(true);
|
|
577
870
|
return ctrl;
|
|
578
871
|
}
|
|
872
|
+
/**
|
|
873
|
+
* 启用 3D 地形渲染(F-1.5)。
|
|
874
|
+
*
|
|
875
|
+
* 注入 raster-dem 高程源并调用 maplibre-gl 原生 `setTerrain`,使地图呈现地形起伏。
|
|
876
|
+
* DEM 瓦片默认使用公共 Terrarium 源(elevation-tiles-prod,Terrain-RGB 编码,支持 CORS),
|
|
877
|
+
* 可在 opts.tiles 覆盖为私有瓦片服务(如 MinIO / 本地 MBTiles 服务)。
|
|
878
|
+
*
|
|
879
|
+
* @param opts.exaggeration 地形夸张系数(默认 1.5)
|
|
880
|
+
* @param opts.tiles DEM 瓦片模板,{z}/{x}/{y} 占位
|
|
881
|
+
* @param opts.encoding 'terrarium'(默认,Mapzen)| 'mapbox'
|
|
882
|
+
*/
|
|
883
|
+
enableTerrain(opts = {}) {
|
|
884
|
+
applyTerrain(this._map, opts);
|
|
885
|
+
}
|
|
886
|
+
/** 关闭 3D 地形渲染(F-1.5),并移除 DEM 源 */
|
|
887
|
+
disableTerrain(sourceId = "cg-dem") {
|
|
888
|
+
removeTerrain(this._map, sourceId);
|
|
889
|
+
}
|
|
579
890
|
get instance() {
|
|
580
891
|
return this._map;
|
|
581
892
|
}
|
|
582
893
|
};
|
|
583
894
|
var src_default = Map;
|
|
584
895
|
|
|
585
|
-
export { CustomLineLayer, LodController, Map, ScaleControl, ThemeSwitcher, buildGlowGeometry, cgcs2000ToWgs84, computeScaleBar, createTransformer, src_default as default, fromWgs84, gcj02ToWgs84, glowPasses, isInChina, oppositeTheme, projectSimple, resolveLod, setCgcs2000GridShift, suggestDensity, themeFromStyle, toWgs84, transformBounds, transformPoint, wgs84ToCgcs2000, wgs84ToGcj02 };
|
|
896
|
+
export { CustomLineLayer, ExportControl, LegendControl, LodController, Map, ScaleControl, ThemeSwitcher, WebGLUnavailableError, buildGlowGeometry, cgcs2000ToWgs84, computeScaleBar, createTransformer, src_default as default, fromWgs84, gcj02ToWgs84, getGlobalConfig, glowPasses, isInChina, isWebGLAvailable, oppositeTheme, projectSimple, removeSourceSafe, removeSourcesSafe, renderLegendHtml, resolveLod, setCgcs2000GridShift, setGlobalConfig, suggestDensity, themeFromStyle, toWgs84, transformBounds, transformPoint, triggerDownload, upsertSource, wgs84ToCgcs2000, wgs84ToGcj02 };
|
|
586
897
|
//# sourceMappingURL=index.js.map
|
|
587
898
|
//# sourceMappingURL=index.js.map
|