@yangyongtao/gaea 1.1.19 → 1.1.21
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 +211 -32
- 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.21",
|
|
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,10 +286,10 @@ 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 = [];
|
|
278
|
-
this._categoryIcons = {};
|
|
279
293
|
this.tweenGroup = new TWEEN.Group();
|
|
280
294
|
this._tourConfig = {
|
|
281
295
|
'沿浦水闸': { direction: [-0.5, 0.3, 0.3], positionList: [
|
|
@@ -340,6 +354,7 @@ export class GaeaApp {
|
|
|
340
354
|
// 影像/地形就绪即可显示地图,隐藏 loading,避免用户等待模型/接口
|
|
341
355
|
hideLoading();
|
|
342
356
|
this._addResetButton();
|
|
357
|
+
this._addLayerTreeButton();
|
|
343
358
|
console.log('[GaeaApp] 地图已就绪,模型与图层树数据后台加载中...');
|
|
344
359
|
|
|
345
360
|
// 剩余重资源(模型位置、GLTF、图层树接口、屏幕图标)后台异步加载,不阻塞地图显示
|
|
@@ -460,7 +475,7 @@ export class GaeaApp {
|
|
|
460
475
|
const cfg = this.config;
|
|
461
476
|
|
|
462
477
|
if (cfg.serviceMode === 'online') {
|
|
463
|
-
//
|
|
478
|
+
// 在线模式:仅加载天地图影像,不加载地形/贴地线/3D Tiles
|
|
464
479
|
this.addTianditu();
|
|
465
480
|
} else {
|
|
466
481
|
// 服务平台模式:WMTS 影像 + 贴地线 + 地形
|
|
@@ -475,6 +490,9 @@ export class GaeaApp {
|
|
|
475
490
|
try { this.addGroundLines(); } catch (e) { console.error('加载贴地线失败:', e); }
|
|
476
491
|
// 地形服务
|
|
477
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))
|
|
478
496
|
}
|
|
479
497
|
|
|
480
498
|
const pos = cfg.defaultCameraPosition;
|
|
@@ -487,19 +505,33 @@ export class GaeaApp {
|
|
|
487
505
|
|
|
488
506
|
// ---- 天地图 ----
|
|
489
507
|
|
|
490
|
-
/** 加载天地图影像 */
|
|
508
|
+
/** 加载天地图影像 + 注记 */
|
|
491
509
|
addTianditu() {
|
|
492
510
|
const cfg = this.config;
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
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);
|
|
501
521
|
console.log('天地图影像加载成功');
|
|
502
|
-
|
|
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(9, 15);
|
|
531
|
+
Gaea.World.Instance.DefaultPyramidTileSet.AddImageStore(labelStore);
|
|
532
|
+
console.log('天地图注记加载成功');
|
|
533
|
+
|
|
534
|
+
return { imgStore, labelStore };
|
|
503
535
|
}
|
|
504
536
|
|
|
505
537
|
/** 添加右上角重置按钮 */
|
|
@@ -550,6 +582,19 @@ export class GaeaApp {
|
|
|
550
582
|
document.body.appendChild(btn);
|
|
551
583
|
}
|
|
552
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
|
+
|
|
553
598
|
// ---- GLTF 模型 ----
|
|
554
599
|
|
|
555
600
|
async _loadGltfModels() {
|
|
@@ -806,18 +851,13 @@ export class GaeaApp {
|
|
|
806
851
|
};
|
|
807
852
|
console.log('[GaeaApp] 开始创建屏幕图标... categories:', cats.length);
|
|
808
853
|
let count = 0;
|
|
809
|
-
this._categoryIcons = {};
|
|
810
854
|
for (const cat of cats) {
|
|
811
855
|
if (!cat.children?.length) continue;
|
|
812
|
-
this._categoryIcons[cat.key] = [];
|
|
813
856
|
const cfg = catConfig[cat.key] || { img: '', method: 'textImage', visibleRange: [10, 50000], offset: [-40, -35], drawLine: false };
|
|
814
857
|
for (const child of cat.children) {
|
|
815
858
|
if (!child.position) continue;
|
|
816
859
|
count++;
|
|
817
860
|
try {
|
|
818
|
-
const safeId = child.text.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_');
|
|
819
|
-
const divId = 'gaea-icon-' + safeId;
|
|
820
|
-
this._categoryIcons[cat.key].push(divId);
|
|
821
861
|
this.addScreenIcon({
|
|
822
862
|
name: child.text,
|
|
823
863
|
text: child.text,
|
|
@@ -828,6 +868,7 @@ export class GaeaApp {
|
|
|
828
868
|
visibleRange: cfg.visibleRange,
|
|
829
869
|
anchorType: cfg.anchorType,
|
|
830
870
|
drawLine: cfg.drawLine,
|
|
871
|
+
category: cat.key,
|
|
831
872
|
onClick: (name, data) => {
|
|
832
873
|
if (cfg.onClick) cfg.onClick(name, { ...child, ...data });
|
|
833
874
|
},
|
|
@@ -836,8 +877,14 @@ export class GaeaApp {
|
|
|
836
877
|
console.warn(`[GaeaApp] 图标 ${child.text} 创建失败:`, e.message);
|
|
837
878
|
}
|
|
838
879
|
}
|
|
880
|
+
// 根据配置的 visible 决定初始显隐(不影响创建,只控制初始状态)
|
|
881
|
+
if (cat.visible === false) {
|
|
882
|
+
this.setCategoryVisible(cat.key, false);
|
|
883
|
+
}
|
|
839
884
|
}
|
|
840
885
|
console.log('[GaeaApp] 屏幕图标创建完成, 共:', count);
|
|
886
|
+
// 通知外部图标已就绪
|
|
887
|
+
document.dispatchEvent(new CustomEvent('gaea-icons-ready'));
|
|
841
888
|
}
|
|
842
889
|
|
|
843
890
|
// ---- 图层分类显隐控制 ----
|
|
@@ -848,23 +895,35 @@ export class GaeaApp {
|
|
|
848
895
|
* @param {boolean} visible 是否可见
|
|
849
896
|
*/
|
|
850
897
|
setCategoryVisible(categoryKey, visible) {
|
|
851
|
-
|
|
852
|
-
if (
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
+
// 同步引擎可见性
|
|
908
|
+
const items = this._screenIconList.filter(item => item.category === categoryKey);
|
|
909
|
+
items.forEach(item => {
|
|
910
|
+
if (visible) {
|
|
911
|
+
item.element.UseAutoVisible();
|
|
912
|
+
item.element.EnablePick = true;
|
|
913
|
+
} else {
|
|
914
|
+
item.element.ForceSetVisible(false);
|
|
915
|
+
item.element.EnablePick = false;
|
|
916
|
+
}
|
|
856
917
|
});
|
|
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
|
-
if (!divIds?.length) return true;
|
|
867
|
-
const el = document.getElementById(divIds[0]);
|
|
926
|
+
const el = document.querySelector('.gaea-cat-' + categoryKey);
|
|
868
927
|
return el ? el.style.display !== 'none' : true;
|
|
869
928
|
}
|
|
870
929
|
|
|
@@ -1087,6 +1146,68 @@ export class GaeaApp {
|
|
|
1087
1146
|
this.SetPosition(`${x},${y},${z},${h},0,0`);
|
|
1088
1147
|
}
|
|
1089
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
|
+
|
|
1090
1211
|
// ---- 沿线飞行 ----
|
|
1091
1212
|
|
|
1092
1213
|
/**
|
|
@@ -1210,7 +1331,7 @@ export class GaeaApp {
|
|
|
1210
1331
|
* 添加屏幕图标(参考 ht_3dview 三种创建方式)
|
|
1211
1332
|
* @param {string} opts.method - 'textImage' | 'styled' | 'imageOnly'
|
|
1212
1333
|
*/
|
|
1213
|
-
addScreenIcon({ name, text, imgUrl, position, method = 'textImage', offset = [0, 0], visibleRange = [10, 50000], anchorType = 6, drawLine = false, onClick, type = null, divId: externalDivId, elementName, elementChildrenIndex } = {}) {
|
|
1334
|
+
addScreenIcon({ name, text, imgUrl, position, method = 'textImage', offset = [0, 0], visibleRange = [10, 50000], anchorType = 6, drawLine = false, onClick, type = null, category = null, divId: externalDivId, elementName, elementChildrenIndex } = {}) {
|
|
1214
1335
|
const safeId = name.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_');
|
|
1215
1336
|
const divId = externalDivId || 'gaea-icon-' + safeId;
|
|
1216
1337
|
|
|
@@ -1264,12 +1385,17 @@ export class GaeaApp {
|
|
|
1264
1385
|
|
|
1265
1386
|
} // end else (externalDivId)
|
|
1266
1387
|
|
|
1388
|
+
// 打分类标记,用于按类别显隐
|
|
1389
|
+
if (category) {
|
|
1390
|
+
container.classList.add('gaea-cat-' + category);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1267
1393
|
if (!externalDivId) {
|
|
1268
1394
|
document.body.appendChild(container);
|
|
1269
1395
|
}
|
|
1270
1396
|
|
|
1271
1397
|
container.style.position = 'absolute';
|
|
1272
|
-
container.style.zIndex = '
|
|
1398
|
+
container.style.zIndex = '99';
|
|
1273
1399
|
container.style.pointerEvents = 'auto';
|
|
1274
1400
|
container.style.cursor = 'pointer';
|
|
1275
1401
|
|
|
@@ -1313,7 +1439,7 @@ export class GaeaApp {
|
|
|
1313
1439
|
console.log('[GaeaApp] child:', !!child);
|
|
1314
1440
|
if (child) {
|
|
1315
1441
|
child.AddChild(screen, false);
|
|
1316
|
-
const screenItem = { element: screen, type: type || null };
|
|
1442
|
+
const screenItem = { element: screen, type: type || null, category };
|
|
1317
1443
|
this._screenIconList.push(screenItem);
|
|
1318
1444
|
return screen;
|
|
1319
1445
|
}
|
|
@@ -1324,7 +1450,7 @@ export class GaeaApp {
|
|
|
1324
1450
|
|
|
1325
1451
|
screen.GeographyPosition = new Gaea.Vector3(position.x, position.y, position.z || 0);
|
|
1326
1452
|
Gaea.World.Instance.RenderableObjectList.AddLast(screen);
|
|
1327
|
-
const screenItem = { element: screen, type: type || null };
|
|
1453
|
+
const screenItem = { element: screen, type: type || null, category };
|
|
1328
1454
|
this._screenIconList.push(screenItem);
|
|
1329
1455
|
return screen;
|
|
1330
1456
|
}
|
|
@@ -1339,6 +1465,35 @@ export class GaeaApp {
|
|
|
1339
1465
|
Gaea.World.Instance.DefaultCamera.GotoFavorite(uri);
|
|
1340
1466
|
}
|
|
1341
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
|
+
|
|
1342
1497
|
// ---- 引擎动画方法 ----
|
|
1343
1498
|
|
|
1344
1499
|
hiddenScreenWithClass(className) {
|
|
@@ -1854,6 +2009,30 @@ export class GaeaApp {
|
|
|
1854
2009
|
this._typhoonElement = null;
|
|
1855
2010
|
}
|
|
1856
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
|
+
};
|
|
1857
2036
|
}
|
|
1858
2037
|
|
|
1859
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;
|