raintee-maputils 1.0.50 → 1.0.52

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.js CHANGED
@@ -6505,7 +6505,7 @@ class RulerControl {
6505
6505
  this.removeDragEvents = null;
6506
6506
  if (!this.options.invisible) {
6507
6507
  this.button = controlButton({
6508
- title: 'Ruler',
6508
+ title: this.options.title || 'Ruler',
6509
6509
  icon: icons.ruler(),
6510
6510
  onClick: () => this.onControlButtonClick(),
6511
6511
  });
@@ -7340,6 +7340,7 @@ class CustomSearchSelectControl {
7340
7340
  onCancel: () => { },
7341
7341
  placeholder: '搜索...',
7342
7342
  title: '选择',
7343
+ cancelButtonText: '取消',
7343
7344
  showSearch: true,
7344
7345
  compactMode: true, // 新增:紧凑模式
7345
7346
  maxHeight: '100vh', // 新增:最大高度
@@ -7642,7 +7643,7 @@ class CustomSearchSelectControl {
7642
7643
  `;
7643
7644
 
7644
7645
  const cancelBtn = document.createElement('button');
7645
- cancelBtn.textContent = '取消';
7646
+ cancelBtn.textContent = this.options.cancelButtonText;
7646
7647
  cancelBtn.className = 'vector-layer-cancel';
7647
7648
  cancelBtn.style.cssText = `
7648
7649
  padding: ${this._isMobile ? '6px 12px' : '6px 16px'};
@@ -21431,7 +21432,10 @@ class CustomToggleControl {
21431
21432
  class RasterLayerControl {
21432
21433
  constructor() {
21433
21434
  this._panel = null;
21435
+ this._dialog = null;
21436
+ this._layerListContainer = null;
21434
21437
  this._isOpen = false;
21438
+ this._tempLayers = [];
21435
21439
  }
21436
21440
 
21437
21441
  onAdd(map) {
@@ -21444,21 +21448,22 @@ class RasterLayerControl {
21444
21448
  this._button.type = 'button';
21445
21449
  this._button.innerHTML = '底图:初始化中';
21446
21450
  this._button.style.cssText = `
21447
- width: 100%;
21448
- padding: 6px 10px;
21449
- margin: 0;
21450
- font-size: 14px;
21451
- font-family: Arial, sans-serif;
21452
- background: #f8f9fa;
21453
- color: #333;
21454
- border: 1px solid #dee2e6;
21455
- border-radius: 4px;
21456
- cursor: pointer;
21457
- text-align: left;
21458
- white-space: nowrap;
21459
- box-sizing: border-box;
21460
- line-height: 1.4;
21461
- `;
21451
+ width: 100%;
21452
+ padding: 6px 10px;
21453
+ margin: 0;
21454
+ font-size: 14px;
21455
+ font-family: Arial, sans-serif;
21456
+ background: #f8f9fa;
21457
+ color: #333;
21458
+ border: 1px solid #dee2e6;
21459
+ border-radius: 4px;
21460
+ cursor: pointer;
21461
+ text-align: left;
21462
+ white-space: nowrap;
21463
+ box-sizing: border-box;
21464
+ line-height: 1.4;
21465
+ `;
21466
+
21462
21467
  this._button.addEventListener('mouseenter', () => {
21463
21468
  this._button.style.background = '#e9ecef';
21464
21469
  });
@@ -21466,26 +21471,17 @@ class RasterLayerControl {
21466
21471
  this._button.style.background = '#f8f9fa';
21467
21472
  });
21468
21473
 
21469
- this._container.appendChild(this._button);
21470
-
21471
21474
  this._button.addEventListener('click', () => {
21472
21475
  this._togglePanel();
21473
21476
  });
21474
21477
 
21475
- this._map.on('idle', () => {
21476
- this._updateRasterLayers();
21477
-
21478
- });
21479
-
21480
- this._map.on('styledata', () => {
21481
- this._updateRasterLayers();
21482
- });
21478
+ this._container.appendChild(this._button);
21483
21479
 
21484
- this._map.on('sourcedata', () => {
21485
- this._updateRasterLayers();
21486
- });
21480
+ this._map.on('idle', () => this._updateButtonText());
21481
+ this._map.on('styledata', () => this._updateButtonText());
21482
+ this._map.on('sourcedata', () => this._updateButtonText());
21487
21483
 
21488
- this._updateRasterLayers();
21484
+ this._updateButtonText();
21489
21485
 
21490
21486
  return this._container;
21491
21487
  }
@@ -21497,20 +21493,26 @@ class RasterLayerControl {
21497
21493
  if (this._container && this._container.parentNode) {
21498
21494
  this._container.parentNode.removeChild(this._container);
21499
21495
  }
21496
+ this._map = undefined;
21500
21497
  }
21501
21498
 
21502
21499
  _togglePanel() {
21503
- if (this._isOpen) {
21504
- this._closePanel();
21505
- } else {
21506
- this._openPanel();
21507
- }
21500
+ this._isOpen ? this._closePanel() : this._openPanel();
21508
21501
  }
21509
21502
 
21510
21503
  _openPanel() {
21511
21504
  this._createPanelIfNeeded();
21512
- this._updateRasterLayers();
21513
- this._panel.style.display = 'block';
21505
+
21506
+ const layers = this._map.getStyle().layers || [];
21507
+ const rasterLayers = layers.filter(l => l.type === 'raster');
21508
+
21509
+ this._tempLayers = rasterLayers.map(l => ({
21510
+ id: l.id,
21511
+ visible: this._map.getLayoutProperty(l.id, 'visibility') !== 'none'
21512
+ }));
21513
+
21514
+ this._renderLayerList();
21515
+ this._panel.style.display = 'flex';
21514
21516
  this._isOpen = true;
21515
21517
  }
21516
21518
 
@@ -21522,171 +21524,204 @@ class RasterLayerControl {
21522
21524
  }
21523
21525
 
21524
21526
  _createPanelIfNeeded() {
21525
- if (!this._panel) {
21526
- // 创建整体的弹窗容器(包含遮罩 + 弹窗内容)
21527
- this._panel = document.createElement('div');
21528
- this._panel.style.cssText = `
21529
- position: fixed;
21530
- top: 0;
21531
- left: 0;
21532
- width: 100vw;
21533
- height: 100vh;
21534
- background: rgba(0, 0, 0, 0.5);
21535
- display: flex;
21536
- align-items: center;
21537
- justify-content: center;
21538
- z-index: 10000;
21539
- `;
21540
-
21541
- // 创建实际的对话框(白色背景,居中内容区域)
21542
- this._dialog = document.createElement('div');
21543
- this._dialog.style.cssText = `
21544
- position: relative;
21545
- top: 50%;
21546
- left: 50%;
21547
- transform: translate(-50%, -50%);
21548
- display: flex;
21549
- flex-direction: column;
21550
- align-items: center;
21551
- justify-content: center;
21552
- background: white;
21553
- padding: 20px;
21554
- border-radius: 8px;
21555
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
21556
- min-width: 300px;
21557
- max-width: 500px;
21558
- max-height: 80vh;
21559
- overflow-y: auto;
21560
- font-family: Arial, sans-serif;
21561
- `;
21562
-
21563
- // 标题
21564
- const title = document.createElement('div');
21565
- title.textContent = '🗂 点击切换底图(影像栅格瓦片图层)';
21566
- title.style.fontWeight = 'bold';
21567
- title.style.marginBottom = '0.5rem';
21568
- title.style.fontSize = '1rem';
21569
- this._dialog.appendChild(title);
21570
-
21571
- // 图层列表容器(原 _layerListContainer)
21572
- this._layerListContainer = document.createElement('div');
21573
- this._layerListContainer.style.cssText = `
21574
- width: 100%;
21575
- max-height: 60vh;
21576
- display: flex;
21577
- flex-direction: column;
21578
- gap: 4px;
21579
- overflow-y: auto;
21580
- overflow-x: hidden;
21581
- `;
21582
- this._dialog.appendChild(this._layerListContainer);
21583
-
21584
- // // 关闭按钮(可选增强)
21585
- // const closeButton = document.createElement('button');
21586
- // closeButton.textContent = '✅ 关闭';
21587
- // closeButton.style.cssText = `
21588
- // margin-left: auto;
21589
- // margin-right: auto;
21590
- // margin-top: 15px;
21591
- // padding: 6px 12px;
21592
- // background: #6c757d;
21593
- // color: white;
21594
- // border: none;
21595
- // border-radius: 4px;
21596
- // cursor: pointer;
21597
- // `;
21598
- // closeButton.addEventListener('click', () => {
21599
- // this._closePanel();
21600
- // });
21601
- // this._dialog.appendChild(closeButton);
21602
-
21603
- this._panel.appendChild(this._dialog);
21604
- document.body.appendChild(this._panel);
21605
-
21606
- // 点击背景遮罩关闭弹窗(增强用户体验,可选)
21607
- this._panel.addEventListener('click', (e) => {
21608
- // 只有点击背景遮罩部分才关闭,点击对话框内容不关闭
21609
- if (e.target === this._panel) {
21610
- this._closePanel();
21611
- }
21612
- });
21613
- }
21614
- }
21615
-
21616
- _updateRasterLayers() {
21527
+ if (this._panel) return;
21528
+
21529
+ // 遮罩
21530
+ this._panel = document.createElement('div');
21531
+ this._panel.style.cssText = `
21532
+ position: fixed;
21533
+ top: 0; left: 0;
21534
+ width: 100vw; height: 100vh;
21535
+ background: rgba(0,0,0,0.45);
21536
+ display: none;
21537
+ align-items: center;
21538
+ justify-content: center;
21539
+ z-index: 10000;
21540
+ `;
21541
+
21542
+
21543
+ // 对话框
21544
+ this._dialog = document.createElement('div');
21545
+ this._dialog.style.cssText = `
21546
+ position: relative;
21547
+ background: #fff;
21548
+ padding: 16px;
21549
+ border-radius: 10px; /* 稍微更柔和 */
21550
+ min-width: 320px;
21551
+ max-width: 520px;
21552
+ max-height: 75vh; /* 🔥 再低一点,留呼吸感 */
21553
+ overflow: hidden; /* 防止整体溢出 */
21554
+ display: flex;
21555
+ flex-direction: column;
21556
+ box-shadow: 0 6px 18px rgba(0,0,0,.22);
21557
+ font-family: Arial, sans-serif;
21558
+ `;
21559
+
21560
+
21561
+
21562
+
21563
+ // 标题
21564
+ const title = document.createElement('div');
21565
+ title.textContent = '🗂 管理栅格底图';
21566
+ title.style.cssText = `
21567
+ font-weight: bold;
21568
+ margin-bottom: 8px;
21569
+ font-size: 15px;
21570
+ `;
21617
21571
 
21618
- const layers = this._map.getStyle().layers || [];
21619
- const rasterLayers = layers.filter(layer => layer.type === 'raster');
21572
+ // 列表容器
21573
+ this._layerListContainer = document.createElement('div');
21574
+ this._layerListContainer.style.cssText = `
21575
+ width: 100%;
21576
+ max-height: 50vh; /* 🔥 核心:最多占屏幕一半高度 */
21577
+ overflow-y: auto; /* 🔥 超出滚动 */
21578
+ overflow-x: hidden;
21579
+ display: flex;
21580
+ flex-direction: column;
21581
+ gap: 6px;
21582
+ padding: 4px 2px;
21583
+ box-sizing: border-box;
21584
+ border-top: 1px solid #eee;
21585
+ border-bottom: 1px solid #eee;
21586
+ `;
21587
+
21588
+
21589
+
21590
+ this._dialog.appendChild(title);
21591
+ this._dialog.appendChild(this._layerListContainer);
21592
+ this._panel.appendChild(this._dialog);
21593
+ document.body.appendChild(this._panel);
21620
21594
 
21621
- let buttonText = '底图:无';
21622
- let firstVisibleLayerId = null;
21595
+ // 点击遮罩关闭
21596
+ this._panel.addEventListener('click', (e) => {
21597
+ if (e.target === this._panel) this._closePanel();
21598
+ });
21599
+ }
21623
21600
 
21624
- // 查找当前显示的图层(visibility === 'visible')
21625
- for (const layer of rasterLayers) {
21626
- const visibility = this._map.getLayoutProperty(layer.id, 'visibility');
21627
- if (visibility === 'visible') {
21628
- firstVisibleLayerId = layer.id;
21629
- break;
21630
- }
21631
- }
21601
+ _renderLayerList() {
21602
+ if (!this._layerListContainer) return;
21603
+ this._layerListContainer.innerHTML = '';
21632
21604
 
21633
- if (firstVisibleLayerId) {
21634
- buttonText = `底图:${firstVisibleLayerId}`;
21635
- } else if (rasterLayers.length > 0) {
21636
- buttonText = '底图:无';
21605
+ if (!this._tempLayers.length) {
21606
+ this._layerListContainer.textContent = '无可选栅格图层';
21607
+ return;
21637
21608
  }
21638
21609
 
21639
- this._button.innerHTML = buttonText;
21640
-
21641
- // 清空旧的图层列表
21642
- if (this._layerListContainer) { this._layerListContainer.innerHTML = ''; }
21643
- rasterLayers.forEach(layer => {
21644
- const layerId = layer.id;
21610
+ this._tempLayers.forEach((layer, index) => {
21645
21611
  const row = document.createElement('div');
21646
21612
  row.style.cssText = `
21647
- padding: 6px 8px;
21648
- margin-bottom: 2px;
21649
- background: #f8f9fa;
21650
- border-radius: 4px;
21651
- cursor: pointer;
21652
- transition: background 0.2s;
21653
- `;
21613
+ display: flex;
21614
+ align-items: center;
21615
+ gap: 6px;
21616
+ padding: 6px 8px;
21617
+ background: #f8f9fa;
21618
+ border-radius: 4px;
21619
+ `;
21654
21620
 
21655
- row.addEventListener('click', () => {
21656
- // 设置当前图层为 visible,其他为 none
21657
- rasterLayers.forEach(l => {
21658
- const vis = l.id === layerId ? 'visible' : 'none';
21659
- this._map.setLayoutProperty(l.id, 'visibility', vis);
21660
- });
21621
+ const checkbox = document.createElement('input');
21622
+ checkbox.type = 'checkbox';
21623
+ checkbox.checked = layer.visible;
21624
+
21625
+ checkbox.onchange = () => {
21626
+ layer.visible = checkbox.checked;
21627
+
21628
+ // 🔥 立刻在地图中生效
21629
+ this._map.setLayoutProperty(
21630
+ layer.id,
21631
+ 'visibility',
21632
+ layer.visible ? 'visible' : 'none'
21633
+ );
21634
+
21635
+ // 🔄 同步按钮文字
21636
+ this._updateButtonText();
21637
+ };
21661
21638
 
21662
- // 更新按钮文字
21663
- if (this._button) {
21664
- this._button.innerHTML = `底图:${layerId}`;
21665
- }
21666
- this._togglePanel();
21667
- });
21668
21639
 
21669
- // 鼠标 hover 效果
21670
- row.addEventListener('mouseenter', () => {
21671
- row.style.background = '#e9ecef';
21672
- });
21673
- row.addEventListener('mouseleave', () => {
21674
- row.style.background = '#f8f9fa';
21675
- });
21676
21640
 
21677
- // 显示图层 ID(可加样式或 icon)
21678
21641
  const label = document.createElement('span');
21679
- label.textContent = layerId;
21680
- label.style.fontFamily = 'Arial, sans-serif';
21681
- label.style.fontSize = '13px';
21682
- label.style.color = '#333';
21642
+ label.textContent = layer.id;
21643
+ label.style.cssText = `
21644
+ flex: 1;
21645
+ font-size: 13px;
21646
+ color: #333;
21647
+ overflow: hidden;
21648
+ text-overflow: ellipsis;
21649
+ white-space: nowrap;
21650
+ `;
21683
21651
 
21652
+ const upBtn = document.createElement('button');
21653
+ upBtn.textContent = '↑';
21654
+ upBtn.disabled = index === 0;
21655
+ upBtn.onclick = () => this._moveTempLayer(index, index - 1);
21656
+
21657
+ const downBtn = document.createElement('button');
21658
+ downBtn.textContent = '↓';
21659
+ downBtn.disabled = index === this._tempLayers.length - 1;
21660
+ downBtn.onclick = () => this._moveTempLayer(index, index + 1);
21661
+
21662
+ [upBtn, downBtn].forEach(btn => {
21663
+ btn.style.cssText = `
21664
+ padding: 2px 6px;
21665
+ border: 1px solid #ccc;
21666
+ background: #fff;
21667
+ border-radius: 3px;
21668
+ cursor: pointer;
21669
+ `;
21670
+ });
21671
+
21672
+ row.appendChild(checkbox);
21684
21673
  row.appendChild(label);
21685
- this._layerListContainer && this._layerListContainer.appendChild(row);
21674
+ row.appendChild(upBtn);
21675
+ row.appendChild(downBtn);
21676
+ this._layerListContainer.appendChild(row);
21686
21677
  });
21687
- if (rasterLayers.length === 0) {
21688
- this._layerListContainer && this._layerListContainer.appendChild(document.createTextNode('无可选内容'));
21678
+ }
21679
+
21680
+ _moveTempLayer(from, to) {
21681
+ const item = this._tempLayers.splice(from, 1)[0];
21682
+ this._tempLayers.splice(to, 0, item);
21683
+
21684
+ // ✅ 按 Mapbox 官方语义:从“最上层”往下重排
21685
+ for (let i = this._tempLayers.length - 1; i >= 0; i--) {
21686
+ const layerId = this._tempLayers[i].id;
21687
+ const beforeId =
21688
+ i === this._tempLayers.length - 1
21689
+ ? undefined // 最上面的图层:移到最顶
21690
+ : this._tempLayers[i + 1].id;
21691
+
21692
+ // 关键防御:避免 moveLayer 自己到自己前面
21693
+ if (beforeId && beforeId === layerId) continue;
21694
+
21695
+ this._map.moveLayer(layerId, beforeId);
21696
+ }
21697
+
21698
+ this._renderLayerList();
21699
+ }
21700
+
21701
+
21702
+ _applyChanges() {
21703
+ // 现在不再做任何地图操作,只是关闭面板
21704
+ this._closePanel();
21705
+ }
21706
+
21707
+
21708
+ _updateButtonText() {
21709
+ if (!this._map) return;
21710
+
21711
+ const layers = this._map.getStyle().layers || [];
21712
+ const rasterLayers = layers.filter(l => l.type === 'raster');
21713
+
21714
+ let firstVisible = null;
21715
+ for (const layer of rasterLayers) {
21716
+ if (this._map.getLayoutProperty(layer.id, 'visibility') === 'visible') {
21717
+ firstVisible = layer.id;
21718
+ break;
21719
+ }
21689
21720
  }
21721
+
21722
+ this._button.innerHTML = firstVisible
21723
+ ? `底图:${firstVisible}`
21724
+ : rasterLayers.length ? '底图:无' : '底图:无栅格图层';
21690
21725
  }
21691
21726
  }
21692
21727