tg-map-core 4.1.8 → 4.2.1

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.
@@ -1,5 +1,5 @@
1
1
  import * as maptalks from 'maptalks';
2
- import { noop, throwError, assert, lateinit, Arrays as Arrays$1, identical, throwUnsupported, delay, assertNever, Strings as Strings$1, StringEnums } from 'tg-commons';
2
+ import { noop, throwError, assert, lateinit, Arrays as Arrays$1, identical, throwUnsupported, delay, assertNever, Strings as Strings$1, isTruthy } from 'tg-commons';
3
3
  import coordtransform from 'coordtransform';
4
4
  import deepmerge from 'deepmerge';
5
5
  import { ClusterLayer } from 'maptalks.markercluster';
@@ -1528,7 +1528,17 @@ class TalksEventTargetDelegate extends AbstractEventTargetDelegate {
1528
1528
  static EVENT_TYPE_MAP = typedRecord({
1529
1529
  'center-changed': 'movestart moving moveend zoomend',
1530
1530
  'zoom-changed': 'zoomend',
1531
+ // https://maptalks.org/maptalks.js/api/1.x/Map.html#event:setbaselayer
1532
+ 'map-type-changed': 'setbaselayer',
1531
1533
  });
1534
+ eventTypeMap;
1535
+ /**
1536
+ * @param eventTypeMap 额外的事件类型映射
1537
+ */
1538
+ constructor(inner, coordTypeSupplier, eventTypeMap) {
1539
+ super(inner, coordTypeSupplier);
1540
+ this.eventTypeMap = { ...TalksEventTargetDelegate.EVENT_TYPE_MAP, ...eventTypeMap };
1541
+ }
1532
1542
  addEventListener(type, listener) {
1533
1543
  const key = generateEventKey(type, listener);
1534
1544
  if (this.eventMap.has(key)) {
@@ -1546,14 +1556,14 @@ class TalksEventTargetDelegate extends AbstractEventTargetDelegate {
1546
1556
  }
1547
1557
  listener.call(this.target, ev);
1548
1558
  };
1549
- this.inner.on(TalksEventTargetDelegate.EVENT_TYPE_MAP[type] ?? type, actualListener);
1559
+ this.inner.on(this.eventTypeMap[type] ?? type, actualListener);
1550
1560
  this.eventMap.set(key, actualListener);
1551
1561
  }
1552
1562
  removeEventListener(type, listener) {
1553
1563
  const key = generateEventKey(type, listener);
1554
1564
  const actualListener = this.eventMap.get(key);
1555
1565
  if (actualListener) {
1556
- this.inner.off(TalksEventTargetDelegate.EVENT_TYPE_MAP[type] ?? type, actualListener);
1566
+ this.inner.off(this.eventTypeMap[type] ?? type, actualListener);
1557
1567
  this.eventMap.delete(key);
1558
1568
  }
1559
1569
  else {
@@ -1724,6 +1734,19 @@ function hideBaiduMapUnauthWarn() {
1724
1734
  }
1725
1735
  return false;
1726
1736
  };
1737
+ if (!isBaiduGL()) {
1738
+ // 新的V3版也会直接从签名的`B_BUSINESS_INFO`中检测是否弹窗警告, 强制清空它可以规避检测(
1739
+ Object.defineProperty(window, 'B_BUSINESS_INFO', {
1740
+ configurable: true,
1741
+ enumerable: true,
1742
+ get: () => {
1743
+ return undefined;
1744
+ },
1745
+ set: (v) => {
1746
+ console.debug('B_BUSINESS_INFO', 'set', v);
1747
+ },
1748
+ });
1749
+ }
1727
1750
  let originalBMap;
1728
1751
  let originalBMapVerifyCbk;
1729
1752
  Object.defineProperty(window, 'BMap', {
@@ -2160,13 +2183,17 @@ var BuildInMapTypeId;
2160
2183
  })(BuildInMapTypeId || (BuildInMapTypeId = {}));
2161
2184
  class BuildInMapType {
2162
2185
  id;
2186
+ index;
2163
2187
  baidu;
2164
2188
  google;
2165
2189
  googleCoordType;
2166
- constructor(id, baidu, // 需要延迟初始化, 故写成方法
2190
+ constructor(id,
2191
+ /** 在{@link MapType.BUILD_IN_MAP_TYPES.values}中的index */
2192
+ index, baidu, // 需要延迟初始化, 故写成方法
2167
2193
  google, // 同上
2168
2194
  googleCoordType) {
2169
2195
  this.id = id;
2196
+ this.index = index;
2170
2197
  this.baidu = baidu;
2171
2198
  this.google = google;
2172
2199
  this.googleCoordType = googleCoordType;
@@ -2276,10 +2303,10 @@ class TrafficLayer {
2276
2303
  }
2277
2304
  var MapType;
2278
2305
  (function (MapType) {
2279
- MapType.NORMAL = new BuildInMapType(BuildInMapTypeId.normal, () => BMAP_NORMAL_MAP, () => google.maps.MapTypeId.ROADMAP, CoordType.gcj02);
2280
- MapType.SATELLITE = new BuildInMapType(BuildInMapTypeId.satellite, () => BMAP_SATELLITE_MAP, () => google.maps.MapTypeId.SATELLITE, CoordType.wgs84);
2281
- MapType.HYBRID = new BuildInMapType(BuildInMapTypeId.hybrid, () => BMAP_HYBRID_MAP, () => google.maps.MapTypeId.HYBRID, CoordType.gcj02);
2282
- MapType.TERRAIN = new BuildInMapType('terrain', () => /* 三维 */ BMAP_PERSPECTIVE_MAP, () => /* 地形 */ google.maps.MapTypeId.TERRAIN, CoordType.wgs84);
2306
+ MapType.NORMAL = new BuildInMapType(BuildInMapTypeId.normal, 0, () => BMAP_NORMAL_MAP, () => google.maps.MapTypeId.ROADMAP, CoordType.gcj02);
2307
+ MapType.SATELLITE = new BuildInMapType(BuildInMapTypeId.satellite, 1, () => BMAP_SATELLITE_MAP, () => google.maps.MapTypeId.SATELLITE, CoordType.wgs84);
2308
+ MapType.HYBRID = new BuildInMapType(BuildInMapTypeId.hybrid, 2, () => BMAP_HYBRID_MAP, () => google.maps.MapTypeId.HYBRID, CoordType.gcj02);
2309
+ MapType.TERRAIN = new BuildInMapType('terrain', 3, () => /* 三维 */ BMAP_PERSPECTIVE_MAP, () => /* 地形 */ google.maps.MapTypeId.TERRAIN, CoordType.wgs84);
2283
2310
  MapType.BUILD_IN_MAP_TYPES = new FastFindValues([MapType.NORMAL, MapType.SATELLITE, MapType.HYBRID, MapType.TERRAIN]);
2284
2311
  })(MapType || (MapType = {}));
2285
2312
 
@@ -2292,6 +2319,10 @@ var MapTypeControlType;
2292
2319
  const MAP_TYPES_DEFAULT = [MapType.NORMAL, MapType.SATELLITE, MapType.HYBRID];
2293
2320
  class BaiduMapTypeControl extends BaiduControl {
2294
2321
  static create(options) {
2322
+ if (isBaiduGL()) {
2323
+ // GL版, 不存在MapTypeControl...故返回空
2324
+ return new EmptyControl(true, options.position ?? ControlPosition.TOP_LEFT);
2325
+ }
2295
2326
  const mapTypes = options.mapTypes ?? MAP_TYPES_DEFAULT;
2296
2327
  const type2baidu = {
2297
2328
  [MapTypeControlType.DEFAULT]: BMAP_MAPTYPE_CONTROL_HORIZONTAL,
@@ -2343,9 +2374,13 @@ class GoogleMapTypeControl extends GoogleControl {
2343
2374
  });
2344
2375
  }
2345
2376
  }
2346
- class TalksMapTypeControl extends EmptyControl {
2377
+ class TalksMapTypeControl extends TalksControl {
2347
2378
  static create(options) {
2348
- return new TalksMapTypeControl(true, options.position ?? ControlPosition.TOP_LEFT);
2379
+ const position = options.position ?? ControlPosition.TOP_LEFT;
2380
+ const inner = new maptalks.control.LayerSwitcher({
2381
+ position: ControlPositionConverter.getTalks().toValue(position),
2382
+ });
2383
+ return new TalksMapTypeControl(inner, position);
2349
2384
  }
2350
2385
  }
2351
2386
 
@@ -7293,7 +7328,7 @@ class TalksMarkerClusterer {
7293
7328
  this.inner = new ClusterLayer('cluster', options.markers?.map(it => it.innerOverlay), Objects.deleteUndefinedPropertyOnPlainObjectDeeply({
7294
7329
  ...ClusterIconStyle.toTalks(options.styles),
7295
7330
  // {@macro marker_clusterer_grid_size}
7296
- maxClusterRadius: options.gridSize ?? (map.currentBaseLayerId === 'baidu' || map.currentBaseLayerId === 'baidu-detail' ? 60 : 100),
7331
+ maxClusterRadius: options.gridSize ?? (map.cachedBaseLayerId === 'baidu' || map.cachedBaseLayerId === 'baidu-detail' ? 60 : 100),
7297
7332
  maxClusterZoom: options.maxZoom,
7298
7333
  zIndex: options.zIndex,
7299
7334
  }));
@@ -7629,6 +7664,12 @@ class BaseMap {
7629
7664
  removeOverlayMapType(mapType) {
7630
7665
  this.removeLayer(mapType);
7631
7666
  }
7667
+ addOverlay(overlay) {
7668
+ overlay.addTo(this);
7669
+ }
7670
+ removeOverlay(overlay) {
7671
+ overlay.remove();
7672
+ }
7632
7673
  addControl(control) {
7633
7674
  control.addTo(this);
7634
7675
  }
@@ -7665,9 +7706,6 @@ class Overlay {
7665
7706
  removeEventListener(type, listener) {
7666
7707
  this.delegate.removeEventListener(type, listener);
7667
7708
  }
7668
- remove() {
7669
- this.map.removeOverlay(this);
7670
- }
7671
7709
  }
7672
7710
  class GoogleOverlay extends Overlay {
7673
7711
  map;
@@ -7678,6 +7716,13 @@ class GoogleOverlay extends Overlay {
7678
7716
  createDelegate() {
7679
7717
  return new GoogleEventTargetDelegate(this.innerOverlay, this.map);
7680
7718
  }
7719
+ addTo(map) {
7720
+ this.map = map;
7721
+ this.innerOverlay.setMap(map.innerMap);
7722
+ }
7723
+ remove() {
7724
+ this.innerOverlay.setMap(null);
7725
+ }
7681
7726
  isVisible() {
7682
7727
  return this.innerOverlay.getVisible();
7683
7728
  }
@@ -7694,6 +7739,13 @@ class BaiduOverlay extends Overlay {
7694
7739
  createDelegate() {
7695
7740
  return new BaiduEventTargetDelegate(this.innerOverlay, this.map);
7696
7741
  }
7742
+ addTo(map) {
7743
+ this.map = map;
7744
+ this.map.innerMap.addOverlay(this.innerOverlay);
7745
+ }
7746
+ remove() {
7747
+ this.map.innerMap.removeOverlay(this.innerOverlay);
7748
+ }
7697
7749
  /** 仅限内部使用; 设为private时, 生成的d.ts文件中, 方法返回值会变成any, 故改成了public */
7698
7750
  get overlay() {
7699
7751
  // 这几个属性被声明成可选的, 这里将其强转成必选
@@ -7803,11 +7855,43 @@ class GoogleShape extends GoogleOverlay {
7803
7855
  }
7804
7856
  }
7805
7857
  class TalksShape extends TalksOverlay {
7858
+ addTo(map) {
7859
+ this.map = map;
7860
+ this.map.overlayLayer.addGeometry(this.innerOverlay);
7861
+ // 添加到地图中之后, startEdit()才有效
7862
+ if (this.isEditable() && !this.innerOverlay.isEditing()) {
7863
+ this.innerOverlay.startEdit();
7864
+ }
7865
+ }
7866
+ remove() {
7867
+ this.map.overlayLayer.removeGeometry(this.innerOverlay);
7868
+ }
7869
+ /**
7870
+ * ## 编辑状态的映射
7871
+ * tg-map的editable, 直接表示是否处于编辑状态
7872
+ * talks的editable, 只是标记overlay是否可以编辑(默认为true), 要进入编辑状态(isEditing), 还需要执行startEdit()
7873
+ * 也就是说我们需要想办法把talks的四个状态, 映射为tg-map的两个状态
7874
+ *
7875
+ * 我们的做法是, 用editable保存isEditing期望的值, 保证editable为true时isEditing也会为true, 为false时isEditing也会为false
7876
+ * 这样就可以和tg-map的editable的语义简单对应上了
7877
+ *
7878
+ * @see addTo
7879
+ * @see setEditable
7880
+ */
7806
7881
  isEditable() {
7807
- return this.innerOverlay.config().editable ?? true;
7882
+ return this.innerOverlay.options.editable ?? false;
7808
7883
  }
7809
7884
  setEditable(editable) {
7885
+ // 同步设置editable和isEditing
7886
+ // TODO: 2026/01/23 ipcjs 切换编辑状态时, 控制台会报重复注册事件警告, 已提PR: https://github.com/maptalks/maptalks.js/pull/2796
7810
7887
  this.innerOverlay.config({ editable: editable });
7888
+ const isEditing = this.innerOverlay.isEditing();
7889
+ if (editable) {
7890
+ !isEditing && this.innerOverlay.startEdit();
7891
+ }
7892
+ else {
7893
+ isEditing && this.innerOverlay.endEdit();
7894
+ }
7811
7895
  }
7812
7896
  setStrokeColor(color) {
7813
7897
  this.innerOverlay.updateSymbol({ lineColor: color });
@@ -7977,6 +8061,41 @@ class TalksCircle extends TalksShape {
7977
8061
  });
7978
8062
  return new TalksCircle(inner, coord, this);
7979
8063
  }
8064
+ prevCenter;
8065
+ prevRadius;
8066
+ eventHubDelegate;
8067
+ createDelegate() {
8068
+ return (this.eventHubDelegate = new EventHubEventTargetDelegate(super.createDelegate(), {
8069
+ types: ['radius-changed', 'center-changed'],
8070
+ onListen: (type) => {
8071
+ if (type === 'radius-changed') {
8072
+ this.prevRadius = this.innerOverlay.getRadius();
8073
+ this.innerOverlay.on('editrecord', this.onRadiusChanged);
8074
+ }
8075
+ else {
8076
+ this.prevCenter = this.innerOverlay.getCoordinates();
8077
+ this.innerOverlay.on('editrecord', this.onCenterChanged);
8078
+ }
8079
+ },
8080
+ onCancel: (type) => {
8081
+ this.innerOverlay.off('editrecord', type === 'radius-changed' ? this.onRadiusChanged : this.onCenterChanged);
8082
+ },
8083
+ }));
8084
+ }
8085
+ onRadiusChanged = () => {
8086
+ const radius = this.innerOverlay.getRadius();
8087
+ if (this.prevRadius !== radius) {
8088
+ this.eventHubDelegate?.notify({ type: 'radius-changed', target: this });
8089
+ this.prevRadius = radius;
8090
+ }
8091
+ };
8092
+ onCenterChanged = () => {
8093
+ const center = this.innerOverlay.getCoordinates();
8094
+ if (this.prevCenter !== center && !this.prevCenter?.equals(center)) {
8095
+ this.eventHubDelegate?.notify({ type: 'center-changed', target: this });
8096
+ this.prevCenter = center;
8097
+ }
8098
+ };
7980
8099
  setCenter(center) {
7981
8100
  this.coordType = this.map.coordType;
7982
8101
  this.innerOverlay.setCoordinates(center.toTalks(this.coordType));
@@ -9121,6 +9240,13 @@ class TalksLabelOverlay extends TalksOverlay {
9121
9240
  });
9122
9241
  return new TalksLabelOverlay(label, coord, this);
9123
9242
  }
9243
+ addTo(map) {
9244
+ this.map = map;
9245
+ this.innerOverlay.addTo(map.innerMap);
9246
+ }
9247
+ remove() {
9248
+ this.innerOverlay.remove();
9249
+ }
9124
9250
  setContent(content) {
9125
9251
  this.innerOverlay.setContent(content);
9126
9252
  }
@@ -9132,7 +9258,7 @@ class TalksLabelOverlay extends TalksOverlay {
9132
9258
  this.innerOverlay.setCoordinates(position.toTalks(this.coordType));
9133
9259
  }
9134
9260
  getOffset() {
9135
- const options = this.innerOverlay.config();
9261
+ const options = this.innerOverlay.options;
9136
9262
  return { x: options.dx ?? 0, y: options.dy ?? 0 };
9137
9263
  }
9138
9264
  setOffset(offset) {
@@ -9639,6 +9765,13 @@ class TalksMarker extends TalksOverlay {
9639
9765
  super(innerOverlay, coordType, map);
9640
9766
  this.state = state;
9641
9767
  }
9768
+ addTo(map) {
9769
+ this.map = map;
9770
+ this.map.markerLayer.addGeometry(this.innerOverlay);
9771
+ }
9772
+ remove() {
9773
+ this.map.markerLayer.removeGeometry(this.innerOverlay);
9774
+ }
9642
9775
  getPosition() {
9643
9776
  return LatLng.fromTalks(this.innerOverlay.getCoordinates(), this.coordType);
9644
9777
  }
@@ -9673,13 +9806,13 @@ class TalksMarker extends TalksOverlay {
9673
9806
  this.innerOverlay.config('interactive', enable);
9674
9807
  }
9675
9808
  isClickable() {
9676
- return this.innerOverlay.config().interactive ?? true;
9809
+ return this.innerOverlay.options.interactive ?? true;
9677
9810
  }
9678
9811
  setDraggable(enable) {
9679
9812
  this.innerOverlay.config('draggable', enable);
9680
9813
  }
9681
9814
  isDraggable() {
9682
- return this.innerOverlay.config().draggable ?? false;
9815
+ return this.innerOverlay.options.draggable ?? false;
9683
9816
  }
9684
9817
  setZIndex(zIndex) {
9685
9818
  this.innerOverlay.setZIndex(zIndex ?? 0);
@@ -9907,6 +10040,12 @@ class TalksPolyline extends TalksShape {
9907
10040
  });
9908
10041
  return new TalksPolyline(inner, coordType, this);
9909
10042
  }
10043
+ createDelegate() {
10044
+ return new TalksEventTargetDelegate(this.innerOverlay, this.map, {
10045
+ // https://maptalks.org/maptalks.js/api/1.x/Geometry.html#event:editrecord
10046
+ 'path-edited': 'editrecord',
10047
+ });
10048
+ }
9910
10049
  getPath() {
9911
10050
  return this.innerOverlay.getCoordinates().map(it => LatLng.fromTalks(it, this.coordType));
9912
10051
  }
@@ -10025,6 +10164,12 @@ class TalksPolygon extends TalksShape {
10025
10164
  });
10026
10165
  return new TalksPolygon(inner, coord, this);
10027
10166
  }
10167
+ createDelegate() {
10168
+ return new TalksEventTargetDelegate(this.innerOverlay, this.map, {
10169
+ // https://maptalks.org/maptalks.js/api/1.x/Geometry.html#event:editrecord
10170
+ 'paths-edited': 'editrecord',
10171
+ });
10172
+ }
10028
10173
  getPaths() {
10029
10174
  return this.innerOverlay.getCoordinates()
10030
10175
  .map(path => path.map(it => LatLng.fromTalks(it, this.coordType)));
@@ -10190,6 +10335,12 @@ class TalksRectangle extends TalksShape {
10190
10335
  height: computeDistanceBetween(nw, bounds.sw),
10191
10336
  };
10192
10337
  }
10338
+ createDelegate() {
10339
+ return new TalksEventTargetDelegate(this.innerOverlay, this.map, {
10340
+ // https://maptalks.org/maptalks.js/api/1.x/Geometry.html#event:editrecord
10341
+ 'bounds-changed': 'editrecord',
10342
+ });
10343
+ }
10193
10344
  getBounds() {
10194
10345
  return LatLngBounds.fromTalks(this.innerOverlay.getExtent(), this.coordType);
10195
10346
  }
@@ -10392,12 +10543,6 @@ class BaiduMap extends BaseMap {
10392
10543
  removeElementOverlay(overlay) {
10393
10544
  this.map.removeOverlay(overlay.asBaidu());
10394
10545
  }
10395
- addOverlay(overlay) {
10396
- this.map.addOverlay(overlay.innerOverlay);
10397
- }
10398
- removeOverlay(overlay) {
10399
- this.map.removeOverlay(overlay.innerOverlay);
10400
- }
10401
10546
  addCustomControl(control) {
10402
10547
  if (!control.inner) {
10403
10548
  const BaiduControl = class extends BMap.Control {
@@ -10618,12 +10763,6 @@ class GoogleMap extends BaseMap {
10618
10763
  removeElementOverlay(overlay) {
10619
10764
  overlay.asGoogle().setMap(null);
10620
10765
  }
10621
- addOverlay(overlay) {
10622
- overlay.innerOverlay.setMap(this.map);
10623
- }
10624
- removeOverlay(overlay) {
10625
- overlay.innerOverlay.setMap(null);
10626
- }
10627
10766
  addCustomControl(control) {
10628
10767
  if (!control.inner) {
10629
10768
  control.inner = control.onCreateElement();
@@ -10772,12 +10911,6 @@ class HereMap extends BaseMap {
10772
10911
  removeElementOverlay(overlay) {
10773
10912
  throw new Error('Method not implemented.');
10774
10913
  }
10775
- addOverlay(overlay) {
10776
- throw new Error('Method not implemented.');
10777
- }
10778
- removeOverlay(overlay) {
10779
- throw new Error('Method not implemented.');
10780
- }
10781
10914
  createMarker(options) {
10782
10915
  throw new Error('Method not implemented.');
10783
10916
  }
@@ -10859,11 +10992,14 @@ const quadKey = (z, x, y) => {
10859
10992
  };
10860
10993
  const talksBaseLayerIds = [
10861
10994
  'osm',
10862
- 'osm-simple',
10995
+ 'osm-light',
10996
+ 'osm-dark',
10997
+ 'osm-terrain',
10863
10998
  'google',
10864
10999
  'baidu',
10865
11000
  'baidu-detail',
10866
11001
  'amap',
11002
+ 'amap-terrain',
10867
11003
  'tencent',
10868
11004
  'geoq',
10869
11005
  'tianditu',
@@ -10875,7 +11011,8 @@ function talksBaseLayerIdToCoordType(layerId) {
10875
11011
  case 'baidu':
10876
11012
  case 'baidu-detail':
10877
11013
  return CoordType.bd09;
10878
- case 'osm-simple':
11014
+ case 'osm-light':
11015
+ case 'osm-dark':
10879
11016
  case 'osm':
10880
11017
  case 'yandex':
10881
11018
  return CoordType.wgs84;
@@ -10896,15 +11033,29 @@ function talksBaseLayerIdToCoordType(layerId) {
10896
11033
  * @see https://maptalks.org/examples/cn/tilelayer-projection/baidu/#tilelayer-projection_baidu
10897
11034
  */
10898
11035
  const TILE_LAYER_BAIDU_SCALER = 1;
10899
- function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
11036
+ function createTalksBaseLayerImpl(layerId, { id = layerId, visible = true, } = {}) {
10900
11037
  switch (layerId) {
10901
11038
  case 'amap':
10902
11039
  return new maptalks.TileLayer(id, {
10903
11040
  visible,
10904
- urlTemplate: 'http://webrd03.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}&lang=zh_cn',
11041
+ urlTemplate: 'http://webrd{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}&lang=zh_cn',
11042
+ subdomains: ['01', '02', '03', '04'],
10905
11043
  minZoom: 3,
10906
11044
  maxZoom: 18,
10907
11045
  attribution: '&copy; <a target="_blank" href="https://amap.com/">AMap</a>',
11046
+ spatialReference: { projection: 'EPSG:3857' },
11047
+ });
11048
+ case 'amap-terrain':
11049
+ // http://examples.maptalks.com/examples/cn/3d/terrain/load
11050
+ return new maptalks.TileLayer(id, {
11051
+ visible,
11052
+ minZoom: 1,
11053
+ // 深圳最大可以到18级, 一些偏远地带, 18级可能没有数据
11054
+ maxZoom: 18,
11055
+ urlTemplate: 'http://webst{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
11056
+ subdomains: ['01', '02', '03', '04'],
11057
+ attribution: '&copy; <a target="_blank" href="https://amap.com/">AMap</a>',
11058
+ spatialReference: { projection: 'EPSG:3857' },
10908
11059
  });
10909
11060
  case 'baidu':
10910
11061
  return new maptalks.TileLayer(id, {
@@ -10912,20 +11063,20 @@ function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
10912
11063
  urlTemplate: `http://online{s}.map.bdimg.com/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=pl&type=sate&scaler=${TILE_LAYER_BAIDU_SCALER}`,
10913
11064
  subdomains: ['0', '1', '2', '3'],
10914
11065
  spatialReference: {
10915
- projection: 'baidu',
11066
+ projection: 'BAIDU',
10916
11067
  },
10917
11068
  minZoom: 3,
10918
11069
  maxZoom: 20,
10919
11070
  attribution: '&copy; <a target="_blank" href="http://map.baidu.com">Baidu</a>',
10920
11071
  });
10921
11072
  case 'baidu-detail':
10922
- // 参考: https://maptalks.org/examples/cn/tilelayer-projection/baidu/#tilelayer-projection_baidu
11073
+ // https://maptalks.org/examples/cn/tilelayer-projection/baidu/#tilelayer-projection_baidu
10923
11074
  return new maptalks.TileLayer(id, {
10924
11075
  visible,
10925
11076
  urlTemplate: `https://gss{s}.bdstatic.com/8bo_dTSlRsgBo1vgoIiO_jowehsv/tile/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=${TILE_LAYER_BAIDU_SCALER}&udt=20170927`,
10926
11077
  subdomains: ['0', '1', '2', '3'],
10927
11078
  spatialReference: {
10928
- projection: 'baidu',
11079
+ projection: 'BAIDU',
10929
11080
  },
10930
11081
  minZoom: 3,
10931
11082
  maxZoom: 19,
@@ -10940,6 +11091,7 @@ function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
10940
11091
  subdomains: ['0', '1', '2', '3'],
10941
11092
  minZoom: 3,
10942
11093
  maxZoom: 18,
11094
+ spatialReference: { projection: 'EPSG:3857' },
10943
11095
  });
10944
11096
  case 'google':
10945
11097
  return new maptalks.TileLayer(id, {
@@ -10947,6 +11099,7 @@ function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
10947
11099
  urlTemplate: 'https://api.xiox.top/proxy/https://maps.google.com/maps/vt?lyrs=m&x={x}&y={y}&z={z}&hl=zh-CN',
10948
11100
  subdomains: ['0', '1', '2', '3'],
10949
11101
  attribution: '&copy; <a target="_blank" href="https://www.google.com/maps">Google</a>',
11102
+ spatialReference: { projection: 'EPSG:3857' },
10950
11103
  });
10951
11104
  case 'geoq':
10952
11105
  // 不知道是哪家的, 无法显示
@@ -10954,6 +11107,7 @@ function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
10954
11107
  visible,
10955
11108
  urlTemplate: 'https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}',
10956
11109
  subdomains: ['0', '1', '2', '3'],
11110
+ spatialReference: { projection: 'EPSG:3857' },
10957
11111
  });
10958
11112
  case 'tianditu':
10959
11113
  // key已失效, 无法显示
@@ -10976,6 +11130,7 @@ function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
10976
11130
  subdomains: ['1', '2', '3', '4'],
10977
11131
  maxZoom: 21,
10978
11132
  attribution: '&copy; <a target="_blank" href="https://yandex.com/maps/">Yandex</a>',
11133
+ spatialReference: { projection: 'EPSG:3857' },
10979
11134
  });
10980
11135
  case 'bing':
10981
11136
  return new maptalks.TileLayer(id, {
@@ -10984,49 +11139,97 @@ function createTalksBaseLayer(layerId, { id = layerId, visible = true, } = {}) {
10984
11139
  subdomains: ['1', '2', '3'],
10985
11140
  minZoom: 3,
10986
11141
  maxZoom: 18,
11142
+ spatialReference: { projection: 'EPSG:3857' },
10987
11143
  });
10988
11144
  case 'osm':
11145
+ // https://operations.osmfoundation.org/policies/tiles/
10989
11146
  return new maptalks.TileLayer(id, {
10990
11147
  visible,
10991
11148
  urlTemplate: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
10992
11149
  subdomains: ['a', 'b', 'c'],
10993
11150
  attribution: '&copy; <a target="_blank" href="http://www.osm.org/copyright">OSM</a>',
11151
+ spatialReference: { projection: 'EPSG:3857' },
10994
11152
  });
10995
- case 'osm-simple':
11153
+ case 'osm-light':
11154
+ // https://github.com/CartoDB/basemap-styles
10996
11155
  return new maptalks.TileLayer(id, {
10997
11156
  visible,
10998
11157
  urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
10999
11158
  subdomains: ['a', 'b', 'c', 'd'],
11000
11159
  attribution: '&copy; <a target="_blank" href="http://www.osm.org/copyright">OSM</a> contributors, &copy; <a target="_blank" href="https://carto.com/attributions">CARTO</a>',
11160
+ spatialReference: { projection: 'EPSG:3857' },
11161
+ });
11162
+ case 'osm-dark':
11163
+ // https://github.com/CartoDB/basemap-styles
11164
+ return new maptalks.TileLayer(id, {
11165
+ visible,
11166
+ urlTemplate: 'http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
11167
+ subdomains: ['a', 'b', 'c', 'd'],
11168
+ attribution: '&copy; <a target="_blank" href="http://www.osm.org/copyright">OSM</a> contributors, &copy; <a target="_blank" href="https://carto.com/attributions">CARTO</a>',
11169
+ spatialReference: { projection: 'EPSG:3857' },
11170
+ });
11171
+ case 'osm-terrain':
11172
+ // https://wiki.openstreetmap.org/wiki/OpenTopoMap#Usage
11173
+ return new maptalks.TileLayer(id, {
11174
+ visible,
11175
+ urlTemplate: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
11176
+ subdomains: ['a', 'b', 'c'],
11177
+ attribution: '&copy; <a target="_blank" href="http://www.osm.org/copyright">OSM</a>',
11178
+ spatialReference: { projection: 'EPSG:3857' },
11001
11179
  });
11002
11180
  }
11003
11181
  }
11182
+ const createTalksBaseLayer = process.env.NODE_ENV !== 'production'
11183
+ ? (layerId, options) => {
11184
+ const layer = createTalksBaseLayerImpl(layerId, options);
11185
+ if (layer.options.visible == null || layer.options.spatialReference == null) {
11186
+ console.warn('创建的baseLayer必须设置visible和spatialReference', layer.options);
11187
+ }
11188
+ return layer;
11189
+ }
11190
+ : createTalksBaseLayerImpl;
11004
11191
 
11005
11192
  const MAP_ATTRIBUTION_TG = { content: 'TG' };
11006
11193
  class TalksMap extends BaseMap {
11007
11194
  mapOptions;
11195
+ baseLayoutIds;
11008
11196
  map;
11197
+ attributionControl;
11198
+ baseLayerGroup;
11199
+ mapStyleTheme;
11200
+ /**
11201
+ * 由于通过{@link MapTypeControl}, maptalks可以在内部切换可见的baseLayer, 所以要获取实际当前的显示的baseLayer, 应该使用{@link getCurrentBaseLayer}
11202
+ * 但为了方便快速的执行{@link coordType}, 因而增加了这个缓存的值
11203
+ * @internal
11204
+ * */
11205
+ cachedBaseLayerId;
11009
11206
  /** @internal */
11010
- currentBaseLayerId;
11011
11207
  markerLayer;
11208
+ /** @internal */
11012
11209
  overlayLayer;
11013
- constructor(element, mapOptions, baseLayoutIds) {
11210
+ constructor(element, mapOptions,
11211
+ /**
11212
+ * 最多8项, 前四项对应{@link MapType.BUILD_IN_MAP_TYPES}的四个值(普通、卫星、混合、地形)的亮色版, 后四项对应暗色版
11213
+ * @see computeBaseLayerId
11214
+ */
11215
+ baseLayoutIds) {
11014
11216
  super(element);
11015
11217
  this.mapOptions = mapOptions;
11016
- // TODO: 2025/11/05 ipcjs 实现MapType机制
11017
- const buildInMapTypeIdIndex = StringEnums.values(BuildInMapTypeId).indexOf(mapOptions.buildInMapTypeId ?? BuildInMapTypeId.normal);
11018
- this.currentBaseLayerId = baseLayoutIds[buildInMapTypeIdIndex] ?? baseLayoutIds[0];
11019
- const baseLayers = baseLayoutIds.map(id => createTalksBaseLayer(id, { visible: id === this.currentBaseLayerId }));
11020
- const baseLayer = baseLayers.find(it => it.isVisible());
11218
+ this.baseLayoutIds = baseLayoutIds;
11219
+ this.mapStyleTheme = mapOptions.mapStyle?.talks?.theme ?? 'light';
11220
+ this.cachedBaseLayerId = this.computeBaseLayerId(mapOptions.buildInMapTypeId, this.mapStyleTheme);
11221
+ this.baseLayerGroup = new maptalks.GroupTileLayer('base', baseLayoutIds
11222
+ .filter(isTruthy)
11223
+ .map(id => createTalksBaseLayer(id, { visible: id === this.cachedBaseLayerId })));
11021
11224
  this.markerLayer = new maptalks.VectorLayer('markers');
11022
11225
  this.overlayLayer = new maptalks.VectorLayer('overlays');
11226
+ const baseLayer = this.getCurrentBaseLayer();
11023
11227
  this.map = new maptalks.Map(element, {
11024
- attribution: mapOptions.hideLogo ? false : MAP_ATTRIBUTION_TG,
11025
- // TODO: 使用GroupTileLayer, Map无法正确读取到当前显示的Layer的attribution, 故暂时不使用它
11026
- // baseLayer: new maptalks.GroupTileLayer('base', baseLayers),
11027
- baseLayer: baseLayer,
11228
+ // 默认的attribution不会显示GroupTileLayer的子layer的attribution, 故不显示, 使用自己的this.attributionControl来处理
11229
+ attribution: false,
11230
+ baseLayer: this.baseLayerGroup,
11028
11231
  // {@macro layer_baidu_spatial_reference}
11029
- spatialReference: baseLayer?.config().spatialReference,
11232
+ spatialReference: baseLayer?.options.spatialReference,
11030
11233
  // 参考google, marker和其他overlay分属不同layer, 并且marker位于overlay上方
11031
11234
  layers: [
11032
11235
  this.overlayLayer, this.markerLayer,
@@ -11035,11 +11238,60 @@ class TalksMap extends BaseMap {
11035
11238
  seamlessZoom: mapOptions.fractionalZoom ?? false,
11036
11239
  zoom: mapOptions.zoom,
11037
11240
  // 默认使用baseLayer的Zoom范围
11038
- minZoom: mapOptions.minZoom ?? baseLayer?.config().minZoom,
11039
- maxZoom: mapOptions.maxZoom ?? baseLayer?.config().maxZoom,
11241
+ minZoom: mapOptions.minZoom ?? baseLayer?.options.minZoom,
11242
+ maxZoom: mapOptions.maxZoom ?? baseLayer?.options.maxZoom,
11040
11243
  });
11041
11244
  this.setGestureHandling(mapOptions.gestureHandling);
11042
11245
  this.setEventTargetDelegate(new TalksEventTargetDelegate(this.map, this));
11246
+ this.attributionControl = new maptalks.control.Attribution(MAP_ATTRIBUTION_TG);
11247
+ this.map.addControl(this.attributionControl);
11248
+ this.setHideLogo(mapOptions.hideLogo ?? false);
11249
+ this.map.on('setbaselayer', this.onBaseLayerChanged);
11250
+ this.onBaseLayerChanged();
11251
+ }
11252
+ getCurrentBaseLayer() {
11253
+ return this.baseLayerGroup.layers.find(it => it.isVisible());
11254
+ }
11255
+ onBaseLayerChanged = () => {
11256
+ const baseLayer = this.getCurrentBaseLayer();
11257
+ if (!baseLayer)
11258
+ return;
11259
+ // 更新cacheBaseLayerId, attribution, spatialReference, 但并没有更新minZoom/maxZoom, 因为感觉必要性不大
11260
+ this.cachedBaseLayerId = baseLayer.getId();
11261
+ const layerAttribution = baseLayer.options.attribution;
11262
+ this.attributionControl.setContent(MAP_ATTRIBUTION_TG.content + (layerAttribution ? ` - ${layerAttribution}` : ''));
11263
+ if (this.map.getSpatialReference().options.projection !== baseLayer.getSpatialReference().options.projection) {
11264
+ console.debug('setSpatialReference', this.map.getSpatialReference().options, '==>', baseLayer.getSpatialReference().options);
11265
+ this.map.setSpatialReference(baseLayer.getSpatialReference().options);
11266
+ }
11267
+ };
11268
+ computeBaseLayerId(buildInMapTypeId = BuildInMapTypeId.normal, theme = 'light') {
11269
+ const mapType = MapType.BUILD_IN_MAP_TYPES.get(BuildInMapType.prototype.getId, buildInMapTypeId);
11270
+ if (theme === 'dark') {
11271
+ const darkOffset = MapType.BUILD_IN_MAP_TYPES.values.length;
11272
+ // 遍历: 7, 6, 5, 4, 查找设置了值的暗色layerId
11273
+ for (let i = Math.min((mapType.index + darkOffset), this.baseLayoutIds.length - 1); i >= darkOffset; i--) {
11274
+ if (this.baseLayoutIds[i]) {
11275
+ return this.baseLayoutIds[i];
11276
+ }
11277
+ }
11278
+ }
11279
+ // 遍历: 3, 2, 1, 0, 查找设置了值的亮色layerId
11280
+ for (let i = Math.min(mapType.index, this.baseLayoutIds.length - 1); i >= 0; i--) {
11281
+ if (this.baseLayoutIds[i]) {
11282
+ return this.baseLayoutIds[i];
11283
+ }
11284
+ }
11285
+ return this.baseLayoutIds[0];
11286
+ }
11287
+ setBaseLayer(id, theme) {
11288
+ this.mapStyleTheme = theme;
11289
+ const baseLayerId = this.computeBaseLayerId(id, theme);
11290
+ const currentBaseLayerId = this.getCurrentBaseLayer()?.getId();
11291
+ if (currentBaseLayerId !== baseLayerId) {
11292
+ this.baseLayerGroup.layers.forEach((layer) => Talks.setVisible(layer, layer.getId() === baseLayerId));
11293
+ this.onBaseLayerChanged();
11294
+ }
11043
11295
  }
11044
11296
  setGestureHandling(gestureHandling = GestureHandlingOptions.auto) {
11045
11297
  if (gestureHandling === GestureHandlingOptions.auto) {
@@ -11075,7 +11327,7 @@ class TalksMap extends BaseMap {
11075
11327
  return this.map;
11076
11328
  }
11077
11329
  get coordType() {
11078
- return talksBaseLayerIdToCoordType(this.currentBaseLayerId);
11330
+ return talksBaseLayerIdToCoordType(this.cachedBaseLayerId);
11079
11331
  }
11080
11332
  fromContainerPointToLatLng(point) {
11081
11333
  const coordinate = this.map.containerPointToCoordinate(new maptalks.Point(point.x, point.y));
@@ -11086,7 +11338,7 @@ class TalksMap extends BaseMap {
11086
11338
  return point; // maptalks.Point符合Point接口, 可以直接返回
11087
11339
  }
11088
11340
  setHideLogo(hideLogo) {
11089
- this.map.config('attribution', hideLogo ? false : MAP_ATTRIBUTION_TG);
11341
+ Talks.setVisible(this.attributionControl, !hideLogo);
11090
11342
  }
11091
11343
  setFractionalZoom(enabled) {
11092
11344
  this.map.config('seamlessZoom', enabled);
@@ -11113,16 +11365,31 @@ class TalksMap extends BaseMap {
11113
11365
  this.map.setMaxZoom(zoom);
11114
11366
  }
11115
11367
  setMapStyle(mapStyle) {
11116
- // TODO: 2026/01/05 ipcjs 下一版再实现该功能
11368
+ if (mapStyle?.talks?.theme) {
11369
+ const mapType = this.getMapType();
11370
+ if (mapType instanceof BuildInMapType) {
11371
+ this.setBaseLayer(mapType.id, mapStyle.talks.theme);
11372
+ }
11373
+ else {
11374
+ console.log('自定义MapType不支持设置地图样式', mapType);
11375
+ }
11376
+ }
11117
11377
  }
11118
11378
  setBuildInMapTypeId(id) {
11119
- // TODO: 2026/01/05 ipcjs 下一版再实现该功能
11379
+ this.setBaseLayer(id, this.mapStyleTheme);
11120
11380
  }
11121
11381
  setMapType(mapType) {
11122
- // TODO: 2026/01/05 ipcjs 下一版再实现该功能
11382
+ if (mapType instanceof BuildInMapType) {
11383
+ this.setBaseLayer(mapType.getId(), this.mapStyleTheme);
11384
+ }
11123
11385
  }
11124
11386
  getMapType() {
11125
- // TODO: 2026/01/05 ipcjs 下一版再实现该功能
11387
+ const currentBaseLayerId = this.getCurrentBaseLayer()?.getId();
11388
+ const index = this.baseLayoutIds.findIndex(it => it === currentBaseLayerId);
11389
+ if (index !== -1) {
11390
+ return MapType.BUILD_IN_MAP_TYPES.values[index % MapType.BUILD_IN_MAP_TYPES.values.length];
11391
+ }
11392
+ // TODO: 2026/01/05 ipcjs 自定义MapType, 下一版再实现该功能
11126
11393
  return MapType.NORMAL;
11127
11394
  }
11128
11395
  addLayer(layer) {
@@ -11154,22 +11421,6 @@ class TalksMap extends BaseMap {
11154
11421
  removeElementOverlay(overlay) {
11155
11422
  // TODO: 2026/01/05 ipcjs 下一版再实现该功能
11156
11423
  }
11157
- addOverlay(overlay) {
11158
- if (overlay.innerOverlay instanceof maptalks.ui.UIComponent) {
11159
- overlay.innerOverlay.addTo(this.map);
11160
- return;
11161
- }
11162
- const layer = overlay instanceof TalksMarker ? this.markerLayer : this.overlayLayer;
11163
- layer.addGeometry(overlay.innerOverlay);
11164
- }
11165
- removeOverlay(overlay) {
11166
- if (overlay.innerOverlay instanceof maptalks.ui.UIComponent) {
11167
- overlay.innerOverlay.remove();
11168
- return;
11169
- }
11170
- const layer = overlay instanceof TalksMarker ? this.markerLayer : this.overlayLayer;
11171
- layer.removeGeometry(overlay.innerOverlay);
11172
- }
11173
11424
  createMarker = TalksMarker.create;
11174
11425
  createMarkerClusterer(options) {
11175
11426
  return new TalksMarkerClusterer(this, options);
@@ -11253,17 +11504,20 @@ var TgMapFactory;
11253
11504
  case TgMapType.here:
11254
11505
  return new HereMap($map, options);
11255
11506
  case TgMapType.baiduFree:
11256
- return new TalksMap($map, options, ['baidu', 'osm']);
11507
+ return new TalksMap($map, options, ['baidu', 'amap-terrain', undefined, undefined, 'osm-dark']);
11257
11508
  case TgMapType.googleFree:
11258
- return new TalksMap($map, options, ['google', 'osm']);
11509
+ return new TalksMap($map, options, ['google', 'osm-terrain', undefined, undefined, 'osm-dark']);
11259
11510
  case TgMapType.amap:
11260
- return new TalksMap($map, options, ['amap']);
11511
+ return new TalksMap($map, options, ['amap', 'amap-terrain', undefined, undefined, 'osm-dark']);
11261
11512
  case TgMapType.osm:
11262
- return new TalksMap($map, options, ['osm']);
11513
+ return new TalksMap($map, options, ['osm-light', 'osm-terrain', undefined, undefined, 'osm-dark']);
11263
11514
  case TgMapType.yandex:
11264
- return new TalksMap($map, options, ['yandex']);
11265
- case TgMapType.talks:
11266
- return new TalksMap($map, options, [getTgMapConfig().talks.layerId || 'bing']);
11515
+ return new TalksMap($map, options, ['yandex', undefined, undefined, undefined, 'osm-dark']);
11516
+ case TgMapType.talks: {
11517
+ const hasDefinedFirstElement = (array) => !!(array && array.length && array[0]);
11518
+ const talks = getTgMapConfig().talks;
11519
+ return new TalksMap($map, options, hasDefinedFirstElement(talks.layerIds) ? talks.layerIds : [talks.layerId || 'bing']);
11520
+ }
11267
11521
  default:
11268
11522
  assertNever(type);
11269
11523
  }