raintee-maputils 1.0.51 → 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
@@ -21432,7 +21432,10 @@ class CustomToggleControl {
21432
21432
  class RasterLayerControl {
21433
21433
  constructor() {
21434
21434
  this._panel = null;
21435
+ this._dialog = null;
21436
+ this._layerListContainer = null;
21435
21437
  this._isOpen = false;
21438
+ this._tempLayers = [];
21436
21439
  }
21437
21440
 
21438
21441
  onAdd(map) {
@@ -21445,21 +21448,22 @@ class RasterLayerControl {
21445
21448
  this._button.type = 'button';
21446
21449
  this._button.innerHTML = '底图:初始化中';
21447
21450
  this._button.style.cssText = `
21448
- width: 100%;
21449
- padding: 6px 10px;
21450
- margin: 0;
21451
- font-size: 14px;
21452
- font-family: Arial, sans-serif;
21453
- background: #f8f9fa;
21454
- color: #333;
21455
- border: 1px solid #dee2e6;
21456
- border-radius: 4px;
21457
- cursor: pointer;
21458
- text-align: left;
21459
- white-space: nowrap;
21460
- box-sizing: border-box;
21461
- line-height: 1.4;
21462
- `;
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
+
21463
21467
  this._button.addEventListener('mouseenter', () => {
21464
21468
  this._button.style.background = '#e9ecef';
21465
21469
  });
@@ -21467,26 +21471,17 @@ class RasterLayerControl {
21467
21471
  this._button.style.background = '#f8f9fa';
21468
21472
  });
21469
21473
 
21470
- this._container.appendChild(this._button);
21471
-
21472
21474
  this._button.addEventListener('click', () => {
21473
21475
  this._togglePanel();
21474
21476
  });
21475
21477
 
21476
- this._map.on('idle', () => {
21477
- this._updateRasterLayers();
21478
-
21479
- });
21480
-
21481
- this._map.on('styledata', () => {
21482
- this._updateRasterLayers();
21483
- });
21478
+ this._container.appendChild(this._button);
21484
21479
 
21485
- this._map.on('sourcedata', () => {
21486
- this._updateRasterLayers();
21487
- });
21480
+ this._map.on('idle', () => this._updateButtonText());
21481
+ this._map.on('styledata', () => this._updateButtonText());
21482
+ this._map.on('sourcedata', () => this._updateButtonText());
21488
21483
 
21489
- this._updateRasterLayers();
21484
+ this._updateButtonText();
21490
21485
 
21491
21486
  return this._container;
21492
21487
  }
@@ -21498,20 +21493,26 @@ class RasterLayerControl {
21498
21493
  if (this._container && this._container.parentNode) {
21499
21494
  this._container.parentNode.removeChild(this._container);
21500
21495
  }
21496
+ this._map = undefined;
21501
21497
  }
21502
21498
 
21503
21499
  _togglePanel() {
21504
- if (this._isOpen) {
21505
- this._closePanel();
21506
- } else {
21507
- this._openPanel();
21508
- }
21500
+ this._isOpen ? this._closePanel() : this._openPanel();
21509
21501
  }
21510
21502
 
21511
21503
  _openPanel() {
21512
21504
  this._createPanelIfNeeded();
21513
- this._updateRasterLayers();
21514
- 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';
21515
21516
  this._isOpen = true;
21516
21517
  }
21517
21518
 
@@ -21523,171 +21524,204 @@ class RasterLayerControl {
21523
21524
  }
21524
21525
 
21525
21526
  _createPanelIfNeeded() {
21526
- if (!this._panel) {
21527
- // 创建整体的弹窗容器(包含遮罩 + 弹窗内容)
21528
- this._panel = document.createElement('div');
21529
- this._panel.style.cssText = `
21530
- position: fixed;
21531
- top: 0;
21532
- left: 0;
21533
- width: 100vw;
21534
- height: 100vh;
21535
- background: rgba(0, 0, 0, 0.5);
21536
- display: flex;
21537
- align-items: center;
21538
- justify-content: center;
21539
- z-index: 10000;
21540
- `;
21541
-
21542
- // 创建实际的对话框(白色背景,居中内容区域)
21543
- this._dialog = document.createElement('div');
21544
- this._dialog.style.cssText = `
21545
- position: relative;
21546
- top: 50%;
21547
- left: 50%;
21548
- transform: translate(-50%, -50%);
21549
- display: flex;
21550
- flex-direction: column;
21551
- align-items: center;
21552
- justify-content: center;
21553
- background: white;
21554
- padding: 20px;
21555
- border-radius: 8px;
21556
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
21557
- min-width: 300px;
21558
- max-width: 500px;
21559
- max-height: 80vh;
21560
- overflow-y: auto;
21561
- font-family: Arial, sans-serif;
21562
- `;
21563
-
21564
- // 标题
21565
- const title = document.createElement('div');
21566
- title.textContent = '🗂 点击切换底图(影像栅格瓦片图层)';
21567
- title.style.fontWeight = 'bold';
21568
- title.style.marginBottom = '0.5rem';
21569
- title.style.fontSize = '1rem';
21570
- this._dialog.appendChild(title);
21571
-
21572
- // 图层列表容器(原 _layerListContainer)
21573
- this._layerListContainer = document.createElement('div');
21574
- this._layerListContainer.style.cssText = `
21575
- width: 100%;
21576
- max-height: 60vh;
21577
- display: flex;
21578
- flex-direction: column;
21579
- gap: 4px;
21580
- overflow-y: auto;
21581
- overflow-x: hidden;
21582
- `;
21583
- this._dialog.appendChild(this._layerListContainer);
21584
-
21585
- // // 关闭按钮(可选增强)
21586
- // const closeButton = document.createElement('button');
21587
- // closeButton.textContent = '✅ 关闭';
21588
- // closeButton.style.cssText = `
21589
- // margin-left: auto;
21590
- // margin-right: auto;
21591
- // margin-top: 15px;
21592
- // padding: 6px 12px;
21593
- // background: #6c757d;
21594
- // color: white;
21595
- // border: none;
21596
- // border-radius: 4px;
21597
- // cursor: pointer;
21598
- // `;
21599
- // closeButton.addEventListener('click', () => {
21600
- // this._closePanel();
21601
- // });
21602
- // this._dialog.appendChild(closeButton);
21603
-
21604
- this._panel.appendChild(this._dialog);
21605
- document.body.appendChild(this._panel);
21606
-
21607
- // 点击背景遮罩关闭弹窗(增强用户体验,可选)
21608
- this._panel.addEventListener('click', (e) => {
21609
- // 只有点击背景遮罩部分才关闭,点击对话框内容不关闭
21610
- if (e.target === this._panel) {
21611
- this._closePanel();
21612
- }
21613
- });
21614
- }
21615
- }
21616
-
21617
- _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
+ `;
21618
21571
 
21619
- const layers = this._map.getStyle().layers || [];
21620
- 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);
21621
21594
 
21622
- let buttonText = '底图:无';
21623
- let firstVisibleLayerId = null;
21595
+ // 点击遮罩关闭
21596
+ this._panel.addEventListener('click', (e) => {
21597
+ if (e.target === this._panel) this._closePanel();
21598
+ });
21599
+ }
21624
21600
 
21625
- // 查找当前显示的图层(visibility === 'visible')
21626
- for (const layer of rasterLayers) {
21627
- const visibility = this._map.getLayoutProperty(layer.id, 'visibility');
21628
- if (visibility === 'visible') {
21629
- firstVisibleLayerId = layer.id;
21630
- break;
21631
- }
21632
- }
21601
+ _renderLayerList() {
21602
+ if (!this._layerListContainer) return;
21603
+ this._layerListContainer.innerHTML = '';
21633
21604
 
21634
- if (firstVisibleLayerId) {
21635
- buttonText = `底图:${firstVisibleLayerId}`;
21636
- } else if (rasterLayers.length > 0) {
21637
- buttonText = '底图:无';
21605
+ if (!this._tempLayers.length) {
21606
+ this._layerListContainer.textContent = '无可选栅格图层';
21607
+ return;
21638
21608
  }
21639
21609
 
21640
- this._button.innerHTML = buttonText;
21641
-
21642
- // 清空旧的图层列表
21643
- if (this._layerListContainer) { this._layerListContainer.innerHTML = ''; }
21644
- rasterLayers.forEach(layer => {
21645
- const layerId = layer.id;
21610
+ this._tempLayers.forEach((layer, index) => {
21646
21611
  const row = document.createElement('div');
21647
21612
  row.style.cssText = `
21648
- padding: 6px 8px;
21649
- margin-bottom: 2px;
21650
- background: #f8f9fa;
21651
- border-radius: 4px;
21652
- cursor: pointer;
21653
- transition: background 0.2s;
21654
- `;
21613
+ display: flex;
21614
+ align-items: center;
21615
+ gap: 6px;
21616
+ padding: 6px 8px;
21617
+ background: #f8f9fa;
21618
+ border-radius: 4px;
21619
+ `;
21655
21620
 
21656
- row.addEventListener('click', () => {
21657
- // 设置当前图层为 visible,其他为 none
21658
- rasterLayers.forEach(l => {
21659
- const vis = l.id === layerId ? 'visible' : 'none';
21660
- this._map.setLayoutProperty(l.id, 'visibility', vis);
21661
- });
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
+ };
21662
21638
 
21663
- // 更新按钮文字
21664
- if (this._button) {
21665
- this._button.innerHTML = `底图:${layerId}`;
21666
- }
21667
- this._togglePanel();
21668
- });
21669
21639
 
21670
- // 鼠标 hover 效果
21671
- row.addEventListener('mouseenter', () => {
21672
- row.style.background = '#e9ecef';
21673
- });
21674
- row.addEventListener('mouseleave', () => {
21675
- row.style.background = '#f8f9fa';
21676
- });
21677
21640
 
21678
- // 显示图层 ID(可加样式或 icon)
21679
21641
  const label = document.createElement('span');
21680
- label.textContent = layerId;
21681
- label.style.fontFamily = 'Arial, sans-serif';
21682
- label.style.fontSize = '13px';
21683
- 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
+ `;
21684
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);
21685
21673
  row.appendChild(label);
21686
- this._layerListContainer && this._layerListContainer.appendChild(row);
21674
+ row.appendChild(upBtn);
21675
+ row.appendChild(downBtn);
21676
+ this._layerListContainer.appendChild(row);
21687
21677
  });
21688
- if (rasterLayers.length === 0) {
21689
- 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
+ }
21690
21720
  }
21721
+
21722
+ this._button.innerHTML = firstVisible
21723
+ ? `底图:${firstVisible}`
21724
+ : rasterLayers.length ? '底图:无' : '底图:无栅格图层';
21691
21725
  }
21692
21726
  }
21693
21727