@bitalltech-maplibre/core 1.0.4 → 1.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/index.esm.js CHANGED
@@ -293,6 +293,273 @@ const createBeamGeometry = (options) => {
293
293
  }
294
294
  };
295
295
  };
296
+ const EMPTY_FEATURE_COLLECTION = {
297
+ type: "FeatureCollection",
298
+ features: []
299
+ };
300
+ const createFeature$1 = (geometry, properties) => ({
301
+ type: "Feature",
302
+ geometry,
303
+ properties
304
+ });
305
+ const asOpacity = (value, fallback) => Math.max(0, Math.min(1, value ?? fallback));
306
+ const createRadarPowerFeatures = (radar) => {
307
+ var _a;
308
+ if (radar.visible === false) {
309
+ return [];
310
+ }
311
+ const color = radar.color ?? "#38ff4a";
312
+ const ringColor = radar.ringColor ?? color;
313
+ const ringCount = Math.max(0, Math.floor(radar.ringCount ?? 4));
314
+ const coreRadius = Math.max(20, radar.coreRadius ?? Math.min(160, radar.radius * 0.035));
315
+ const features = [];
316
+ if (radar.fillOpacity && radar.fillOpacity > 0) {
317
+ features.push(
318
+ createFeature$1(createCirclePolygon(radar.center, radar.radius), {
319
+ radarId: radar.id,
320
+ kind: "fill",
321
+ color: radar.fillColor ?? color,
322
+ opacity: asOpacity(radar.fillOpacity, 0)
323
+ })
324
+ );
325
+ }
326
+ for (let index = ringCount; index >= 1; index -= 1) {
327
+ const distance = radar.radius * index / ringCount;
328
+ features.push(
329
+ createFeature$1(createCircleLine(radar.center, distance), {
330
+ radarId: radar.id,
331
+ kind: "ring",
332
+ color: ringColor,
333
+ opacity: asOpacity(radar.ringOpacity, 0.95),
334
+ width: Math.max(0, radar.ringWidth ?? 2)
335
+ })
336
+ );
337
+ if (radar.showDistanceLabels !== false) {
338
+ const text = ((_a = radar.distanceLabelFormatter) == null ? void 0 : _a.call(radar, distance, index)) ?? `${Math.round(distance)}`;
339
+ [
340
+ { bearing: 0, textAnchor: "bottom" },
341
+ { bearing: 90, textAnchor: "left" },
342
+ { bearing: 180, textAnchor: "top" },
343
+ { bearing: 270, textAnchor: "right" }
344
+ ].forEach((label) => {
345
+ features.push(
346
+ createFeature$1(
347
+ {
348
+ type: "Point",
349
+ coordinates: getDestination(radar.center, distance, label.bearing)
350
+ },
351
+ {
352
+ radarId: radar.id,
353
+ kind: "distance-label",
354
+ text,
355
+ textAnchor: label.textAnchor,
356
+ color: radar.distanceLabelColor ?? ringColor,
357
+ opacity: asOpacity(radar.distanceLabelOpacity, 0.92),
358
+ haloColor: radar.distanceLabelHaloColor ?? "rgba(15, 23, 42, 0.42)",
359
+ size: radar.distanceLabelSize ?? 12
360
+ }
361
+ )
362
+ );
363
+ });
364
+ }
365
+ }
366
+ if (radar.showCrosshair !== false) {
367
+ features.push(
368
+ createFeature$1(
369
+ {
370
+ type: "LineString",
371
+ coordinates: [
372
+ getDestination(radar.center, radar.radius, 180),
373
+ getDestination(radar.center, radar.radius, 0)
374
+ ]
375
+ },
376
+ {
377
+ radarId: radar.id,
378
+ kind: "crosshair",
379
+ color: radar.crosshairColor ?? ringColor,
380
+ opacity: asOpacity(radar.crosshairOpacity, 0.5),
381
+ width: Math.max(0, radar.crosshairWidth ?? 1.4)
382
+ }
383
+ ),
384
+ createFeature$1(
385
+ {
386
+ type: "LineString",
387
+ coordinates: [
388
+ getDestination(radar.center, radar.radius, 270),
389
+ getDestination(radar.center, radar.radius, 90)
390
+ ]
391
+ },
392
+ {
393
+ radarId: radar.id,
394
+ kind: "crosshair",
395
+ color: radar.crosshairColor ?? ringColor,
396
+ opacity: asOpacity(radar.crosshairOpacity, 0.5),
397
+ width: Math.max(0, radar.crosshairWidth ?? 1.4)
398
+ }
399
+ )
400
+ );
401
+ }
402
+ features.push(
403
+ createFeature$1(createCirclePolygon(radar.center, coreRadius), {
404
+ radarId: radar.id,
405
+ kind: "core",
406
+ color: radar.coreColor ?? color,
407
+ opacity: asOpacity(radar.fillOpacity, 0)
408
+ })
409
+ );
410
+ return features;
411
+ };
412
+ const createRadarPowerData = (radars) => ({
413
+ type: "FeatureCollection",
414
+ features: radars.flatMap(createRadarPowerFeatures)
415
+ });
416
+ const createLayerDefinitions = (id) => {
417
+ const source = `${id}-source`;
418
+ const layers = [
419
+ {
420
+ id: `${id}-fill`,
421
+ type: "fill",
422
+ source,
423
+ filter: ["==", ["get", "kind"], "fill"],
424
+ paint: {
425
+ "fill-color": ["coalesce", ["get", "color"], "#38ff4a"],
426
+ "fill-opacity": ["coalesce", ["get", "opacity"], 0]
427
+ }
428
+ },
429
+ {
430
+ id: `${id}-core`,
431
+ type: "fill",
432
+ source,
433
+ filter: ["==", ["get", "kind"], "core"],
434
+ paint: {
435
+ "fill-color": ["coalesce", ["get", "color"], "#38ff4a"],
436
+ "fill-opacity": ["coalesce", ["get", "opacity"], 0]
437
+ }
438
+ },
439
+ {
440
+ id: `${id}-ring`,
441
+ type: "line",
442
+ source,
443
+ filter: ["==", ["get", "kind"], "ring"],
444
+ paint: {
445
+ "line-color": ["coalesce", ["get", "color"], "#38ff4a"],
446
+ "line-opacity": ["coalesce", ["get", "opacity"], 0.95],
447
+ "line-width": ["coalesce", ["get", "width"], 2]
448
+ }
449
+ },
450
+ {
451
+ id: `${id}-crosshair`,
452
+ type: "line",
453
+ source,
454
+ filter: ["==", ["get", "kind"], "crosshair"],
455
+ paint: {
456
+ "line-color": ["coalesce", ["get", "color"], "#38ff4a"],
457
+ "line-opacity": ["coalesce", ["get", "opacity"], 0.5],
458
+ "line-width": ["coalesce", ["get", "width"], 1.4]
459
+ }
460
+ },
461
+ {
462
+ id: `${id}-labels`,
463
+ type: "symbol",
464
+ source,
465
+ filter: ["==", ["get", "kind"], "distance-label"],
466
+ layout: {
467
+ "text-field": ["get", "text"],
468
+ "text-size": ["coalesce", ["get", "size"], 12],
469
+ "text-anchor": ["get", "textAnchor"],
470
+ "text-allow-overlap": true,
471
+ "text-ignore-placement": true
472
+ },
473
+ paint: {
474
+ "text-color": ["coalesce", ["get", "color"], "#38ff4a"],
475
+ "text-opacity": ["coalesce", ["get", "opacity"], 0.92],
476
+ "text-halo-color": ["coalesce", ["get", "haloColor"], "rgba(15, 23, 42, 0.42)"],
477
+ "text-halo-width": 1
478
+ }
479
+ }
480
+ ];
481
+ return {
482
+ source,
483
+ layers
484
+ };
485
+ };
486
+ const removeLayerIfExists$1 = (map, id) => {
487
+ if (map.getLayer(id)) {
488
+ map.removeLayer(id);
489
+ }
490
+ };
491
+ const removeSourceIfExists$1 = (map, id) => {
492
+ if (map.getSource(id)) {
493
+ map.removeSource(id);
494
+ }
495
+ };
496
+ const addRadarPowerGroup = (map, options) => {
497
+ const { source, layers } = createLayerDefinitions(options.id);
498
+ let radars = [...options.radars ?? []];
499
+ let removed = false;
500
+ map.addSource(source, {
501
+ type: "geojson",
502
+ data: EMPTY_FEATURE_COLLECTION
503
+ });
504
+ layers.forEach((layer) => {
505
+ map.addLayer(layer, options.beforeId);
506
+ });
507
+ const sourceRef = map.getSource(source);
508
+ const layerIds = layers.map((layer) => layer.id);
509
+ const setGroupVisibility = (visible) => {
510
+ layerIds.forEach((layerId) => {
511
+ if (map.getLayer(layerId)) {
512
+ map.setLayoutProperty(layerId, "visibility", visible ? "visible" : "none");
513
+ }
514
+ });
515
+ };
516
+ const setData = (nextRadars) => {
517
+ if (removed) return;
518
+ radars = nextRadars.map((radar) => ({ ...radar }));
519
+ sourceRef.setData(createRadarPowerData(radars));
520
+ };
521
+ if (radars.length > 0) {
522
+ setData(radars);
523
+ }
524
+ if (options.visible === false) {
525
+ setGroupVisibility(false);
526
+ }
527
+ return {
528
+ id: options.id,
529
+ sourceId: source,
530
+ layerIds,
531
+ setData,
532
+ updateRadar(id, nextOptions) {
533
+ const index = radars.findIndex((radar) => radar.id === id);
534
+ if (index < 0 || removed) return;
535
+ radars[index] = { ...radars[index], ...nextOptions, id };
536
+ sourceRef.setData(createRadarPowerData(radars));
537
+ },
538
+ setRadarVisible(id, visible) {
539
+ const radar = radars.find((item) => item.id === id);
540
+ if (!radar || removed) return;
541
+ radar.visible = visible;
542
+ sourceRef.setData(createRadarPowerData(radars));
543
+ },
544
+ removeRadar(id) {
545
+ if (removed) return;
546
+ radars = radars.filter((radar) => radar.id !== id);
547
+ sourceRef.setData(createRadarPowerData(radars));
548
+ },
549
+ show() {
550
+ if (!removed) setGroupVisibility(true);
551
+ },
552
+ hide() {
553
+ if (!removed) setGroupVisibility(false);
554
+ },
555
+ remove() {
556
+ if (removed) return;
557
+ removed = true;
558
+ [...layerIds].reverse().forEach((layerId) => removeLayerIfExists$1(map, layerId));
559
+ removeSourceIfExists$1(map, source);
560
+ }
561
+ };
562
+ };
296
563
  const createFeature = (geometry, properties) => ({
297
564
  type: "Feature",
298
565
  geometry,
@@ -398,7 +665,8 @@ const createManagedEffect = (map, initialOptions, renderEffect) => {
398
665
  if (nextRender.startAnimation) {
399
666
  disposeAnimation = nextRender.startAnimation({
400
667
  getOptions: () => options,
401
- setData
668
+ setData,
669
+ requestRender: () => map.triggerRepaint()
402
670
  }) || void 0;
403
671
  }
404
672
  };
@@ -909,7 +1177,8 @@ const createSectorScanRender = (options) => {
909
1177
  options.center,
910
1178
  options.radius
911
1179
  ),
912
- animate: Boolean(options.rotationSpeed && options.rotationSpeed !== 0)
1180
+ // 动画由插件主动 triggerRepaint,避免 CanvasSource 自己持续刷新一整张地图。
1181
+ animate: false
913
1182
  }
914
1183
  }
915
1184
  ] : void 0,
@@ -926,16 +1195,26 @@ const createSectorScanRender = (options) => {
926
1195
  }
927
1196
  }
928
1197
  ],
929
- startAnimation: options.rotationSpeed && options.rotationSpeed !== 0 ? ({ getOptions, setData }) => {
1198
+ startAnimation: options.rotationSpeed && options.rotationSpeed !== 0 ? ({ getOptions, setData, requestRender }) => {
930
1199
  const startTime = performance.now();
931
1200
  let frameId = 0;
1201
+ let lastFrameTime = -Infinity;
932
1202
  const tick = (timestamp) => {
933
1203
  const currentOptions = getOptions();
934
- const angleOffset = (timestamp - startTime) / 1e3 * (currentOptions.rotationSpeed || 0);
935
- if (canvas) {
936
- drawSectorGradientCanvas(canvas, currentOptions, angleOffset);
1204
+ const frameRate = currentOptions.frameRate ?? 30;
1205
+ const minFrameInterval = frameRate > 0 ? 1e3 / frameRate : 0;
1206
+ if (timestamp - lastFrameTime >= minFrameInterval) {
1207
+ const angleOffset = (timestamp - startTime) / 1e3 * (currentOptions.rotationSpeed || 0);
1208
+ const outlineVisible = (currentOptions.outlineOpacity ?? 0.95) > 0 && (currentOptions.outlineWidth ?? 2) > 0;
1209
+ if (canvas) {
1210
+ drawSectorGradientCanvas(canvas, currentOptions, angleOffset);
1211
+ requestRender();
1212
+ }
1213
+ if (!canvas || outlineVisible) {
1214
+ setData(createSectorScanData(currentOptions, angleOffset));
1215
+ }
1216
+ lastFrameTime = timestamp;
937
1217
  }
938
- setData(createSectorScanData(currentOptions, angleOffset));
939
1218
  frameId = requestAnimationFrame(tick);
940
1219
  };
941
1220
  frameId = requestAnimationFrame(tick);
@@ -3906,6 +4185,7 @@ export {
3906
4185
  addDirectionalPulse,
3907
4186
  addNavigationSpoofing,
3908
4187
  addPulseMarker,
4188
+ addRadarPowerGroup,
3909
4189
  addRadarSweep,
3910
4190
  addRingPulseMarker,
3911
4191
  addSectorScan,