@yangyongtao/gaea 1.1.20 → 1.1.22
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/package.json +1 -1
- package/src/GaeaMethods.js +199 -19
- package/src/components/LayerTree.vue +11 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yangyongtao/gaea",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.22",
|
|
4
4
|
"description": "Gaea 3D visualization component library - Vue 3 components based on Godot WASM engine. Includes WMTS layer loading, camera view control, Vite plugin auto-injection, etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.cjs",
|
package/src/GaeaMethods.js
CHANGED
|
@@ -46,9 +46,17 @@ import Gaea from '../public/index.js';
|
|
|
46
46
|
transition: background 0.2s; backdrop-filter: blur(4px);
|
|
47
47
|
}
|
|
48
48
|
#gaea-reset-btn:hover { background: rgba(0,0,0,0.7); }
|
|
49
|
+
#gaea-layertree-btn {
|
|
50
|
+
position: fixed; top: 16px; right: 60px; z-index: 99990;
|
|
51
|
+
width: 36px; height: 36px; border-radius: 6px; border: none;
|
|
52
|
+
background: rgba(0,0,0,0.5); color: #fff; cursor: pointer;
|
|
53
|
+
font-size: 16px; display: flex; align-items: center; justify-content: center;
|
|
54
|
+
transition: background 0.2s; backdrop-filter: blur(4px);
|
|
55
|
+
}
|
|
56
|
+
#gaea-layertree-btn:hover { background: rgba(0,0,0,0.7); }
|
|
49
57
|
/* 屏幕图标样式(对齐 ht_3dview) */
|
|
50
58
|
.gaea-locationLineStyle {
|
|
51
|
-
position: absolute; overflow: hidden; z-index:
|
|
59
|
+
position: absolute; overflow: hidden; z-index: 99; pointer-events: auto;
|
|
52
60
|
user-select: none; -webkit-user-select: none;
|
|
53
61
|
}
|
|
54
62
|
.gaea-locationLineStyle .text-wrapper {
|
|
@@ -67,7 +75,7 @@ import Gaea from '../public/index.js';
|
|
|
67
75
|
}
|
|
68
76
|
.gaea-iconscreen {
|
|
69
77
|
position: absolute; overflow: hidden; width: 169px; height: 55px;
|
|
70
|
-
user-select: none; -webkit-user-select: none; z-index:
|
|
78
|
+
user-select: none; -webkit-user-select: none; z-index: 99; pointer-events: auto;
|
|
71
79
|
}
|
|
72
80
|
.gaea-iconscreen img {
|
|
73
81
|
position: absolute; width: 100%; height: 100%;
|
|
@@ -146,12 +154,16 @@ const defaultConfig = {
|
|
|
146
154
|
{ name: '苍南县村边界', range: [15, 19], color: [255, 255, 255], index: 60 },
|
|
147
155
|
{ name: '沿浦海塘工程范围线', range: [0, 21], color: [0, 255, 255], index: 120 },
|
|
148
156
|
],
|
|
157
|
+
/** 默认加载的倾斜摄影 3D Tiles(空数组则不加载) */
|
|
158
|
+
default3DTiles: [],
|
|
149
159
|
/** 默认相机视角 */
|
|
150
160
|
defaultCameraPosition: '27.3680928977018,120.414139621887,0,109379.690132486,0,0',
|
|
151
161
|
/** 引擎加载进度回调 */
|
|
152
162
|
onProgress: null,
|
|
153
163
|
/** DataHub API 地址(图层树数据接口),为空则只用默认数据 */
|
|
154
164
|
dataHubApiUrl: '',
|
|
165
|
+
/** 是否显示图层树按钮(右上角重置按钮旁边) */
|
|
166
|
+
showLayerTreeBtn: false,
|
|
155
167
|
/** 图层树分类数据(默认数据,接口数据会合并进来) */
|
|
156
168
|
layerCategories: [
|
|
157
169
|
{ key: 'seawall', text: '海塘', visible: true, children: [
|
|
@@ -265,6 +277,8 @@ export function getConfig() { return _config; }
|
|
|
265
277
|
|
|
266
278
|
// ==================== GaeaApp ====================
|
|
267
279
|
|
|
280
|
+
console.log('[GaeaMethods] 模块已加载 - setCategoryVisible 可用');
|
|
281
|
+
|
|
268
282
|
export class GaeaApp {
|
|
269
283
|
constructor(options = {}) {
|
|
270
284
|
this._options = options;
|
|
@@ -272,6 +286,7 @@ export class GaeaApp {
|
|
|
272
286
|
this.tLayers = [];
|
|
273
287
|
this.layerCategories = this.config.layerCategories || [];
|
|
274
288
|
this._screenIconList = [];
|
|
289
|
+
this._hiddenCategories = new Set();
|
|
275
290
|
this._secIsClickArr = [];
|
|
276
291
|
this._secScreenIconKeyValue = {};
|
|
277
292
|
this._groundPolygonElements = [];
|
|
@@ -339,6 +354,7 @@ export class GaeaApp {
|
|
|
339
354
|
// 影像/地形就绪即可显示地图,隐藏 loading,避免用户等待模型/接口
|
|
340
355
|
hideLoading();
|
|
341
356
|
this._addResetButton();
|
|
357
|
+
this._addLayerTreeButton();
|
|
342
358
|
console.log('[GaeaApp] 地图已就绪,模型与图层树数据后台加载中...');
|
|
343
359
|
|
|
344
360
|
// 剩余重资源(模型位置、GLTF、图层树接口、屏幕图标)后台异步加载,不阻塞地图显示
|
|
@@ -459,7 +475,7 @@ export class GaeaApp {
|
|
|
459
475
|
const cfg = this.config;
|
|
460
476
|
|
|
461
477
|
if (cfg.serviceMode === 'online') {
|
|
462
|
-
//
|
|
478
|
+
// 在线模式:仅加载天地图影像,不加载地形/贴地线/3D Tiles
|
|
463
479
|
this.addTianditu();
|
|
464
480
|
} else {
|
|
465
481
|
// 服务平台模式:WMTS 影像 + 贴地线 + 地形
|
|
@@ -474,6 +490,9 @@ export class GaeaApp {
|
|
|
474
490
|
try { this.addGroundLines(); } catch (e) { console.error('加载贴地线失败:', e); }
|
|
475
491
|
// 地形服务
|
|
476
492
|
try { await this.addInitTerrainServer(); } catch (e) { console.error('加载地形失败:', e); }
|
|
493
|
+
// 倾斜摄影 3D Tiles(isInitLoad 为 true 的自动加载,依赖地形服务)
|
|
494
|
+
const tiles = cfg.default3DTiles || []
|
|
495
|
+
tiles.filter(item => item.isInitLoad).forEach(item => this.add3DTiles(item))
|
|
477
496
|
}
|
|
478
497
|
|
|
479
498
|
const pos = cfg.defaultCameraPosition;
|
|
@@ -486,19 +505,33 @@ export class GaeaApp {
|
|
|
486
505
|
|
|
487
506
|
// ---- 天地图 ----
|
|
488
507
|
|
|
489
|
-
/** 加载天地图影像 */
|
|
508
|
+
/** 加载天地图影像 + 注记 */
|
|
490
509
|
addTianditu() {
|
|
491
510
|
const cfg = this.config;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
511
|
+
|
|
512
|
+
// 影像底图(卫星图)
|
|
513
|
+
const imgStore = new Gaea.TDTWMTSImageStore();
|
|
514
|
+
imgStore.ServerUri = cfg.tiandituServerUri || 'https://t{0}.tianditu.gov.cn/img_c/wmts';
|
|
515
|
+
imgStore.FormatString = cfg.tiandituFormatString || 'SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILECOL={0}&TILEROW={1}&TILEMATRIX={2}&tk={3}';
|
|
516
|
+
imgStore.ImageExtension = cfg.tiandituImageExtension ?? Gaea.ImageExtensionEnum.JPEG;
|
|
517
|
+
imgStore.TK = cfg.tiandituToken;
|
|
518
|
+
imgStore.Name = '影像底图';
|
|
519
|
+
imgStore.LevelRange = new Gaea.Vector2(cfg.tiandituLevelRange[0], cfg.tiandituLevelRange[1]);
|
|
520
|
+
Gaea.World.Instance.DefaultPyramidTileSet.AddImageStore(imgStore);
|
|
500
521
|
console.log('天地图影像加载成功');
|
|
501
|
-
|
|
522
|
+
|
|
523
|
+
// 注记图层(道路/地名标注)
|
|
524
|
+
const labelStore = new Gaea.TDTWMTSImageStore();
|
|
525
|
+
labelStore.ServerUri = 'https://t{0}.tianditu.gov.cn/cia_c/wmts';
|
|
526
|
+
labelStore.FormatString = 'SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=c&FORMAT=image/png&TILECOL={0}&TILEROW={1}&TILEMATRIX={2}&tk={3}';
|
|
527
|
+
labelStore.ImageExtension = Gaea.ImageExtensionEnum.PNG;
|
|
528
|
+
labelStore.TK = cfg.tiandituToken;
|
|
529
|
+
labelStore.Name = '天地图注记';
|
|
530
|
+
labelStore.LevelRange = new Gaea.Vector2(cfg.tiandituLevelRange[0], cfg.tiandituLevelRange[1]);
|
|
531
|
+
Gaea.World.Instance.DefaultPyramidTileSet.AddImageStore(labelStore);
|
|
532
|
+
console.log('天地图注记加载成功');
|
|
533
|
+
|
|
534
|
+
return { imgStore, labelStore };
|
|
502
535
|
}
|
|
503
536
|
|
|
504
537
|
/** 添加右上角重置按钮 */
|
|
@@ -549,6 +582,19 @@ export class GaeaApp {
|
|
|
549
582
|
document.body.appendChild(btn);
|
|
550
583
|
}
|
|
551
584
|
|
|
585
|
+
/** 添加图层树按钮 */
|
|
586
|
+
_addLayerTreeButton() {
|
|
587
|
+
if (document.getElementById('gaea-layertree-btn')) return
|
|
588
|
+
const btn = document.createElement('button')
|
|
589
|
+
btn.id = 'gaea-layertree-btn'
|
|
590
|
+
btn.title = '图层控制'
|
|
591
|
+
btn.innerHTML = '☰'
|
|
592
|
+
btn.onclick = () => {
|
|
593
|
+
document.dispatchEvent(new CustomEvent('gaea-toggle-layertree'))
|
|
594
|
+
}
|
|
595
|
+
document.body.appendChild(btn)
|
|
596
|
+
}
|
|
597
|
+
|
|
552
598
|
// ---- GLTF 模型 ----
|
|
553
599
|
|
|
554
600
|
async _loadGltfModels() {
|
|
@@ -831,8 +877,14 @@ export class GaeaApp {
|
|
|
831
877
|
console.warn(`[GaeaApp] 图标 ${child.text} 创建失败:`, e.message);
|
|
832
878
|
}
|
|
833
879
|
}
|
|
880
|
+
// 根据配置的 visible 决定初始显隐(不影响创建,只控制初始状态)
|
|
881
|
+
if (cat.visible === false) {
|
|
882
|
+
this.setCategoryVisible(cat.key, false);
|
|
883
|
+
}
|
|
834
884
|
}
|
|
835
885
|
console.log('[GaeaApp] 屏幕图标创建完成, 共:', count);
|
|
886
|
+
// 通知外部图标已就绪
|
|
887
|
+
document.dispatchEvent(new CustomEvent('gaea-icons-ready'));
|
|
836
888
|
}
|
|
837
889
|
|
|
838
890
|
// ---- 图层分类显隐控制 ----
|
|
@@ -843,8 +895,17 @@ export class GaeaApp {
|
|
|
843
895
|
* @param {boolean} visible 是否可见
|
|
844
896
|
*/
|
|
845
897
|
setCategoryVisible(categoryKey, visible) {
|
|
898
|
+
// 记录分类显隐状态
|
|
899
|
+
if (visible) {
|
|
900
|
+
this._hiddenCategories.delete(categoryKey)
|
|
901
|
+
} else {
|
|
902
|
+
this._hiddenCategories.add(categoryKey)
|
|
903
|
+
}
|
|
904
|
+
const els = document.querySelectorAll('.gaea-cat-' + categoryKey);
|
|
905
|
+
console.log('[GaeaApp] setCategoryVisible:', categoryKey, visible, '元素数:', els.length);
|
|
906
|
+
els.forEach(el => { el.style.display = visible ? '' : 'none'; });
|
|
907
|
+
// 同步引擎可见性
|
|
846
908
|
const items = this._screenIconList.filter(item => item.category === categoryKey);
|
|
847
|
-
if (!items.length) return;
|
|
848
909
|
items.forEach(item => {
|
|
849
910
|
if (visible) {
|
|
850
911
|
item.element.UseAutoVisible();
|
|
@@ -857,14 +918,13 @@ export class GaeaApp {
|
|
|
857
918
|
}
|
|
858
919
|
|
|
859
920
|
/**
|
|
860
|
-
*
|
|
921
|
+
* 获取某个分类的当前可见性(根据 DOM 元素判断)
|
|
861
922
|
* @param {string} categoryKey
|
|
862
923
|
* @returns {boolean}
|
|
863
924
|
*/
|
|
864
925
|
getCategoryVisible(categoryKey) {
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
return item.element.Visible !== false;
|
|
926
|
+
const el = document.querySelector('.gaea-cat-' + categoryKey);
|
|
927
|
+
return el ? el.style.display !== 'none' : true;
|
|
868
928
|
}
|
|
869
929
|
|
|
870
930
|
// ---- 公开方法 ----
|
|
@@ -1086,6 +1146,68 @@ export class GaeaApp {
|
|
|
1086
1146
|
this.SetPosition(`${x},${y},${z},${h},0,0`);
|
|
1087
1147
|
}
|
|
1088
1148
|
|
|
1149
|
+
/**
|
|
1150
|
+
* 根据名称或 id 定位到海塘
|
|
1151
|
+
* @param {string} name - 海塘名称或 id
|
|
1152
|
+
* @param {string} [tilesetUrl] - 可选,倾斜摄影 3D Tiles 的 tileset.json 地址
|
|
1153
|
+
*/
|
|
1154
|
+
flyToSeawall = (name, tilesetUrl) => {
|
|
1155
|
+
const cats = this.layerCategories || []
|
|
1156
|
+
for (const cat of cats) {
|
|
1157
|
+
if (!cat.children?.length) continue
|
|
1158
|
+
const found = cat.children.find(c => c.text === name || c.id === name)
|
|
1159
|
+
if (found) {
|
|
1160
|
+
this.flyToNode(found)
|
|
1161
|
+
if (tilesetUrl) {
|
|
1162
|
+
this.add3DTiles(tilesetUrl)
|
|
1163
|
+
}
|
|
1164
|
+
return
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
console.warn(`[GaeaApp] 未找到海塘: ${name}`)
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* 加载倾斜摄影 3D Tiles
|
|
1172
|
+
* @param {Object} item - { jsonUrl: tileset.json地址, tilName?: 名称, height?: 高度偏移, isInitLoad?: 是否初始化加载 }
|
|
1173
|
+
*/
|
|
1174
|
+
add3DTiles = (item) => {
|
|
1175
|
+
const tilesetUrl = typeof item === 'string' ? item : item.jsonUrl
|
|
1176
|
+
const name = typeof item === 'string' ? '' : (item.tilName || '')
|
|
1177
|
+
const height = typeof item === 'string' ? 0 : (item.height || 0)
|
|
1178
|
+
const tileset = new Gaea.Gaea3DTileset()
|
|
1179
|
+
tileset.Name = name
|
|
1180
|
+
tileset.TilesetUrl = tilesetUrl
|
|
1181
|
+
tileset.EnablePick = true
|
|
1182
|
+
tileset.UseLight = false
|
|
1183
|
+
tileset.SkipLevelOfDetail = false
|
|
1184
|
+
tileset.IsZUp = true
|
|
1185
|
+
tileset.RecalculateNormals = true
|
|
1186
|
+
tileset.BaseUrl = tilesetUrl.slice(0, tilesetUrl.lastIndexOf('/') + 1)
|
|
1187
|
+
tileset.InitTileSet(name, tilesetUrl)
|
|
1188
|
+
tileset.MaximumMemoryUsage = 512
|
|
1189
|
+
tileset.MaximumScreenSpaceError = 28
|
|
1190
|
+
if (height) {
|
|
1191
|
+
tileset.LocalOffset = new Gaea.Vector3(0, height, 0)
|
|
1192
|
+
}
|
|
1193
|
+
Gaea.World.Instance.RenderableObjectList.AddLast(tileset)
|
|
1194
|
+
console.log('[GaeaApp] 3D Tiles 已加载:', name || tilesetUrl, height ? `高度: ${height}` : '')
|
|
1195
|
+
return tileset
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* 根据经纬度飞到指定位置
|
|
1200
|
+
* @param {number} lat - 纬度
|
|
1201
|
+
* @param {number} lng - 经度
|
|
1202
|
+
* @param {number} [z=0] - 地面高程
|
|
1203
|
+
* @param {number} [alt=500] - 相机高度
|
|
1204
|
+
* @param {number} [pitch=0] - 俯仰角,默认 0(垂直俯视),负值向前倾斜
|
|
1205
|
+
* @param {number} [yaw=0] - 偏航角
|
|
1206
|
+
*/
|
|
1207
|
+
flyToPosition = (lat, lng, z = 0, alt = 500, pitch = 0, yaw = 0) => {
|
|
1208
|
+
this.SetPosition(`${lat},${lng},${z},${alt},${pitch},${yaw}`)
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1089
1211
|
// ---- 沿线飞行 ----
|
|
1090
1212
|
|
|
1091
1213
|
/**
|
|
@@ -1263,12 +1385,17 @@ export class GaeaApp {
|
|
|
1263
1385
|
|
|
1264
1386
|
} // end else (externalDivId)
|
|
1265
1387
|
|
|
1388
|
+
// 打分类标记,用于按类别显隐
|
|
1389
|
+
if (category) {
|
|
1390
|
+
container.classList.add('gaea-cat-' + category);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1266
1393
|
if (!externalDivId) {
|
|
1267
1394
|
document.body.appendChild(container);
|
|
1268
1395
|
}
|
|
1269
1396
|
|
|
1270
1397
|
container.style.position = 'absolute';
|
|
1271
|
-
container.style.zIndex = '
|
|
1398
|
+
container.style.zIndex = '99';
|
|
1272
1399
|
container.style.pointerEvents = 'auto';
|
|
1273
1400
|
container.style.cursor = 'pointer';
|
|
1274
1401
|
|
|
@@ -1338,6 +1465,35 @@ export class GaeaApp {
|
|
|
1338
1465
|
Gaea.World.Instance.DefaultCamera.GotoFavorite(uri);
|
|
1339
1466
|
}
|
|
1340
1467
|
|
|
1468
|
+
/**
|
|
1469
|
+
* 添加点位标记到 3D 地图
|
|
1470
|
+
* @param {Object} opts
|
|
1471
|
+
* @param {string} opts.name - 唯一标识名
|
|
1472
|
+
* @param {string} [opts.text] - 显示文本
|
|
1473
|
+
* @param {number} opts.lat - 纬度
|
|
1474
|
+
* @param {number} opts.lng - 经度
|
|
1475
|
+
* @param {number} [opts.z=0] - 高度
|
|
1476
|
+
* @param {string} [opts.imgUrl] - 图标地址
|
|
1477
|
+
* @param {'textImage'|'styled'|'imageOnly'} [opts.method='textImage'] - 显示样式
|
|
1478
|
+
* @param {Array<number>} [opts.offset=[0,0]] - 屏幕偏移
|
|
1479
|
+
* @param {Function} [opts.onClick] - 点击回调
|
|
1480
|
+
* @param {string} [opts.category] - 分类标识(用于图层树显隐控制)
|
|
1481
|
+
* @returns {Gaea.ScreenGUIElement} screen 元素
|
|
1482
|
+
*/
|
|
1483
|
+
addMarker({ name, text, lat, lng, z = 0, imgUrl, method = 'textImage', offset = [0, 0], onClick, category } = {}) {
|
|
1484
|
+
return this.addScreenIcon({
|
|
1485
|
+
name,
|
|
1486
|
+
text: text || name,
|
|
1487
|
+
imgUrl,
|
|
1488
|
+
position: { x: lat, y: lng, z },
|
|
1489
|
+
method,
|
|
1490
|
+
offset,
|
|
1491
|
+
onClick,
|
|
1492
|
+
category,
|
|
1493
|
+
type: 'marker'
|
|
1494
|
+
})
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1341
1497
|
// ---- 引擎动画方法 ----
|
|
1342
1498
|
|
|
1343
1499
|
hiddenScreenWithClass(className) {
|
|
@@ -1853,6 +2009,30 @@ export class GaeaApp {
|
|
|
1853
2009
|
this._typhoonElement = null;
|
|
1854
2010
|
}
|
|
1855
2011
|
};
|
|
2012
|
+
|
|
2013
|
+
/** 显示所有屏幕标记 */
|
|
2014
|
+
showAllMarkers = () => {
|
|
2015
|
+
this._screenIconList.forEach(item => {
|
|
2016
|
+
// 跳过被隐藏分类的标记
|
|
2017
|
+
if (this._hiddenCategories.has(item.category)) return
|
|
2018
|
+
item.element.UseAutoVisible()
|
|
2019
|
+
item.element.EnablePick = true
|
|
2020
|
+
// 同步显示 DOM 元素
|
|
2021
|
+
const el = document.getElementById(item.element.DivID)
|
|
2022
|
+
if (el) el.style.display = ''
|
|
2023
|
+
})
|
|
2024
|
+
};
|
|
2025
|
+
|
|
2026
|
+
/** 隐藏所有屏幕标记 */
|
|
2027
|
+
hideAllMarkers = () => {
|
|
2028
|
+
this._screenIconList.forEach(item => {
|
|
2029
|
+
item.element.ForceSetVisible(false)
|
|
2030
|
+
item.element.EnablePick = false
|
|
2031
|
+
// 同步隐藏 DOM 元素
|
|
2032
|
+
const el = document.getElementById(item.element.DivID)
|
|
2033
|
+
if (el) el.style.display = 'none'
|
|
2034
|
+
})
|
|
2035
|
+
};
|
|
1856
2036
|
}
|
|
1857
2037
|
|
|
1858
2038
|
export default GaeaApp;
|
|
@@ -18,14 +18,9 @@
|
|
|
18
18
|
<span v-else>▾</span>
|
|
19
19
|
</span>
|
|
20
20
|
<!-- 分类复选框 -->
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
:checked="categoryVisibility[rootNode.key] !== false"
|
|
25
|
-
@change="onCategoryToggle(rootNode.key, $event.target.checked)"
|
|
26
|
-
/>
|
|
27
|
-
<span class="checkmark"></span>
|
|
28
|
-
</label>
|
|
21
|
+
<div class="category-checkbox" @click.stop="onCategoryToggle(rootNode.key, !categoryVisibility[rootNode.key])">
|
|
22
|
+
<span class="checkmark" :class="{ checked: categoryVisibility[rootNode.key] !== false }"></span>
|
|
23
|
+
</div>
|
|
29
24
|
<span class="node-text" :class="{ 'expanded-yellow': rootNode.isExpanded }">{{ rootNode.text }}</span>
|
|
30
25
|
</div>
|
|
31
26
|
|
|
@@ -63,12 +58,10 @@ function handleHideLayerTree() {
|
|
|
63
58
|
|
|
64
59
|
onMounted(() => {
|
|
65
60
|
const raw = props.appInstance?.layerCategories || [];
|
|
66
|
-
categories.value = raw
|
|
67
|
-
|
|
68
|
-
.map(c => ({ ...c, isExpanded: false }));
|
|
69
|
-
// 初始化每个分类的可见性状态
|
|
61
|
+
categories.value = raw.map(c => ({ ...c, isExpanded: false }));
|
|
62
|
+
// 初始化每个分类的可见性状态:按配置的 visible 字段
|
|
70
63
|
for (const cat of categories.value) {
|
|
71
|
-
categoryVisibility[cat.key] =
|
|
64
|
+
categoryVisibility[cat.key] = cat.visible !== false;
|
|
72
65
|
}
|
|
73
66
|
window.addEventListener('gaea-hide-layertree', handleHideLayerTree);
|
|
74
67
|
});
|
|
@@ -78,6 +71,7 @@ onBeforeUnmount(() => {
|
|
|
78
71
|
});
|
|
79
72
|
|
|
80
73
|
function onCategoryToggle(categoryKey, checked) {
|
|
74
|
+
console.log('[LayerTree] onCategoryToggle:', categoryKey, checked, 'appInstance:', !!props.appInstance, 'setCategoryVisible:', !!props.appInstance?.setCategoryVisible);
|
|
81
75
|
categoryVisibility[categoryKey] = checked;
|
|
82
76
|
props.appInstance?.setCategoryVisible?.(categoryKey, checked);
|
|
83
77
|
}
|
|
@@ -129,8 +123,8 @@ const filteredData = computed(() => {
|
|
|
129
123
|
<style scoped>
|
|
130
124
|
.layer-tree-dialog {
|
|
131
125
|
position: fixed;
|
|
132
|
-
top:
|
|
133
|
-
|
|
126
|
+
top: 120px;
|
|
127
|
+
right: 20px;
|
|
134
128
|
width: 300px;
|
|
135
129
|
background: var(--lt-bg);
|
|
136
130
|
border-radius: var(--lt-border-radius);
|
|
@@ -312,7 +306,6 @@ const filteredData = computed(() => {
|
|
|
312
306
|
|
|
313
307
|
/* ===== 分类复选框 ===== */
|
|
314
308
|
.category-checkbox {
|
|
315
|
-
position: relative;
|
|
316
309
|
display: inline-flex;
|
|
317
310
|
align-items: center;
|
|
318
311
|
justify-content: center;
|
|
@@ -323,13 +316,6 @@ const filteredData = computed(() => {
|
|
|
323
316
|
user-select: none;
|
|
324
317
|
}
|
|
325
318
|
|
|
326
|
-
.category-checkbox input[type="checkbox"] {
|
|
327
|
-
position: absolute;
|
|
328
|
-
opacity: 0;
|
|
329
|
-
width: 0;
|
|
330
|
-
height: 0;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
319
|
.checkmark {
|
|
334
320
|
width: 100%;
|
|
335
321
|
height: 100%;
|
|
@@ -342,12 +328,12 @@ const filteredData = computed(() => {
|
|
|
342
328
|
transition: all 0.15s ease;
|
|
343
329
|
}
|
|
344
330
|
|
|
345
|
-
.
|
|
331
|
+
.checkmark.checked {
|
|
346
332
|
background: var(--lt-checkbox-checked-bg);
|
|
347
333
|
border-color: var(--lt-checkbox-checked-bg);
|
|
348
334
|
}
|
|
349
335
|
|
|
350
|
-
.
|
|
336
|
+
.checkmark.checked::after {
|
|
351
337
|
content: '';
|
|
352
338
|
width: 4px;
|
|
353
339
|
height: 8px;
|