|
|
@@ -1,11 +1,10 @@
|
|
|
import { actions, storeDate } from '../store/store.js' //局部状态管理
|
|
|
|
|
|
// 添加s3m
|
|
|
-function addS3mLayers(scps, callback) { //scps:[{ url, options:{name}]} 无返回值
|
|
|
+function addS3mLayers(scps, callback) {
|
|
|
let promiseArray = [];
|
|
|
try {
|
|
|
if (scps) {
|
|
|
- //加载scps
|
|
|
scps.forEach(scp => {
|
|
|
promiseArray.push(
|
|
|
viewer.scene.addS3MTilesLayerByScp(scp.url, scp.options)
|
|
|
@@ -22,9 +21,8 @@ function addS3mLayers(scps, callback) { //scps:[{ url, options:{name}]} 无返
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-
|
|
|
// 添加场景
|
|
|
-function addScene(url, options, callback) { //无返回值options:{SceneToken,autoSetView}
|
|
|
+function addScene(url, options, callback) {
|
|
|
if (options && options.SceneToken) {
|
|
|
Cesium.Credential.CREDENTIAL = new Cesium.Credential(options.SceneToken);
|
|
|
}
|
|
|
@@ -51,7 +49,7 @@ function addTerrainLayer(LayerURL, isSct) {
|
|
|
try {
|
|
|
const terrainProvider = new Cesium.CesiumTerrainProvider({
|
|
|
url: LayerURL,
|
|
|
- isSct: isSct, //地形服务源自SuperMap iServer发布时需设置isSct为true
|
|
|
+ isSct: isSct,
|
|
|
});
|
|
|
viewer.terrainProvider = terrainProvider;
|
|
|
return terrainProvider;
|
|
|
@@ -65,27 +63,110 @@ function addTerrainLayer(LayerURL, isSct) {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 添加影像
|
|
|
-function addImageLayer(LayerURL) { // 返回img图层layer
|
|
|
+// ======================= ✅ 已修复:万能自动坐标系转换 =======================
|
|
|
+function addImageLayer(LayerURL, layerName) {
|
|
|
try {
|
|
|
+ let url = LayerURL;
|
|
|
+ let mapName = '';
|
|
|
+
|
|
|
+ // 清理URL参数,不手动解析投影
|
|
|
+ if (LayerURL.includes('prjCoordSys')) {
|
|
|
+ try {
|
|
|
+ const urlObj = new URL(LayerURL);
|
|
|
+ url = urlObj.origin + urlObj.pathname;
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('解析URL失败:', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取地图名称
|
|
|
+ if (url.includes('/maps/')) {
|
|
|
+ const mapsIndex = url.lastIndexOf('/maps/');
|
|
|
+ mapName = url.substring(mapsIndex + 6);
|
|
|
+ }
|
|
|
+
|
|
|
+ let options = {
|
|
|
+ url: url,
|
|
|
+ };
|
|
|
+
|
|
|
+ if (mapName) {
|
|
|
+ options.name = mapName;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ✅ 核心:自动将任意坐标系 → 输出 WGS84
|
|
|
+ options.outputPrjCoordSys = {
|
|
|
+ epsgCode: 4326,
|
|
|
+ name: "WGS 84",
|
|
|
+ type: "EPSG",
|
|
|
+ coordinateSystemType: "GEODETIC"
|
|
|
+ };
|
|
|
+
|
|
|
+ // ✅ 不手动指定原投影,不硬编码范围,交给超图自动处理
|
|
|
let layer = viewer.imageryLayers.addImageryProvider(
|
|
|
- new Cesium.SuperMapImageryProvider({
|
|
|
- url: LayerURL,
|
|
|
- })
|
|
|
+ new Cesium.SuperMapImageryProvider(options)
|
|
|
);
|
|
|
- return layer
|
|
|
+
|
|
|
+ viewer.imageryLayers.raiseToTop(layer);
|
|
|
+ layer.show = true;
|
|
|
+ layer._loadedUrl = LayerURL;
|
|
|
+ layer._loadedLayerName = layerName || '';
|
|
|
+
|
|
|
+ // 自动定位到图层范围
|
|
|
+ checkLayerExtentAndAdjust(layer);
|
|
|
+
|
|
|
+ return layer;
|
|
|
} catch (e) {
|
|
|
+ console.error('加载影像图层失败:', e);
|
|
|
let widget = viewer.cesiumWidget;
|
|
|
if (widget._showRenderLoopErrors) {
|
|
|
let title = "渲染时发生错误,已停止渲染。";
|
|
|
widget.showErrorPanel(title, undefined, e);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
};
|
|
|
|
|
|
+// 检查图层范围并自动定位
|
|
|
+function checkLayerExtentAndAdjust(layer) {
|
|
|
+ try {
|
|
|
+ const provider = layer.imageryProvider;
|
|
|
+ Cesium.when(provider.readyPromise, function () {
|
|
|
+ const rectangle = provider.rectangle;
|
|
|
+ if (rectangle) {
|
|
|
+ const west = Cesium.Math.toDegrees(rectangle.west);
|
|
|
+ const south = Cesium.Math.toDegrees(rectangle.south);
|
|
|
+ const east = Cesium.Math.toDegrees(rectangle.east);
|
|
|
+ const north = Cesium.Math.toDegrees(rectangle.north);
|
|
|
+ console.log('图层真实范围:', { west, south, east, north });
|
|
|
+
|
|
|
+ // 范围无效时飞到中国区域
|
|
|
+ const isInvalidExtent = (south < -90 || north > 90) ||
|
|
|
+ (south > north) || (west > east);
|
|
|
+
|
|
|
+ if (isInvalidExtent) {
|
|
|
+ console.warn('范围无效,自动定位到中国区域');
|
|
|
+ flyToChinaRegion();
|
|
|
+ } else {
|
|
|
+ // 有效范围 → 自动定位到图层
|
|
|
+ viewer.flyTo(layer, { duration: 1.5 });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.error('检查图层范围失败:', e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 定位到中国
|
|
|
+function flyToChinaRegion() {
|
|
|
+ viewer.scene.camera.flyTo({
|
|
|
+ destination: Cesium.Cartesian3.fromDegrees(104.0, 35.0, 4000000),
|
|
|
+ duration: 2,
|
|
|
+ orientation: { heading: 0, pitch: -60, roll: 0 }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
// 添加mvt
|
|
|
-function addMvtLayer(LayerURL, name, callback) { // 返回img图层layer
|
|
|
+function addMvtLayer(LayerURL, name, callback) {
|
|
|
try {
|
|
|
let mvtMap = viewer.scene.addVectorTilesMap({
|
|
|
url: LayerURL,
|
|
|
@@ -101,11 +182,8 @@ function addMvtLayer(LayerURL, name, callback) { // 返回img图层layer
|
|
|
(bounds.north + bounds.south) * 0.5,
|
|
|
10000
|
|
|
),
|
|
|
- duration:0,
|
|
|
- orientation: {
|
|
|
- heading: 0,
|
|
|
- roll: 0
|
|
|
- }
|
|
|
+ duration: 0,
|
|
|
+ orientation: { heading: 0, roll: 0 }
|
|
|
});
|
|
|
actions.setChangeLayers();
|
|
|
callback(mvtMap)
|
|
|
@@ -118,31 +196,418 @@ function addMvtLayer(LayerURL, name, callback) { // 返回img图层layer
|
|
|
widget.showErrorPanel(title, undefined, e);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
};
|
|
|
|
|
|
-// 加载GeoJson图层 已修复:面填充不被地形遮挡
|
|
|
+// 加载GeoJson图层
|
|
|
function addGeoJsonLayer(url, name, callback) {
|
|
|
try {
|
|
|
+ // 判断是否为超图REST数据服务
|
|
|
+ if (url.includes('/iserver/services/') && url.includes('/rest/data/datasources')) {
|
|
|
+ loadSuperMapRestDataService(url, name, callback);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
const loadPromise = Cesium.GeoJsonDataSource.load(url, {
|
|
|
stroke: Cesium.Color.fromCssColorString('#0055FF').withAlpha(1),
|
|
|
fill: Cesium.Color.fromCssColorString('#00FF00').withAlpha(0.4),
|
|
|
strokeWidth: 3,
|
|
|
clampToGround: true
|
|
|
});
|
|
|
-
|
|
|
- Cesium.when(loadPromise, function(dataSource) {
|
|
|
+
|
|
|
+ Cesium.when(loadPromise, function (dataSource) {
|
|
|
viewer.dataSources.add(dataSource);
|
|
|
- let entities = dataSource.entities.values;
|
|
|
+ processGeoJsonEntities(dataSource, name);
|
|
|
+ viewer.flyTo(dataSource, { duration: 2 });
|
|
|
+ actions.setChangeLayers();
|
|
|
+ if (callback) callback(dataSource);
|
|
|
+ }, function (error) {
|
|
|
+ console.error("加载GeoJSON失败:", error);
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.error("加载GeoJSON异常:", e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 从超图REST服务获取要素并转换为标准GeoJSON
|
|
|
+function fetchFeaturesFromSuperMap(url, timeout) {
|
|
|
+ const timeoutPromise = new Promise((_, reject) => {
|
|
|
+ setTimeout(() => reject(new Error('请求超时')), timeout);
|
|
|
+ });
|
|
|
+
|
|
|
+ return Promise.race([
|
|
|
+ fetch(url, { timeout: timeout }),
|
|
|
+ timeoutPromise
|
|
|
+ ])
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP错误: ${response.status}`);
|
|
|
+ }
|
|
|
+ return response.text();
|
|
|
+ })
|
|
|
+ .then(text => {
|
|
|
+ try {
|
|
|
+ return JSON.parse(text);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('JSON解析失败:', text.substring(0, 200));
|
|
|
+ throw new Error('服务返回的不是有效的JSON数据');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(superMapData => {
|
|
|
+ // 超图返回的格式是: { features: [...], totalCount: N, ... }
|
|
|
+ // 需要转换为标准GeoJSON格式: { type: 'FeatureCollection', features: [...] }
|
|
|
+
|
|
|
+ // 调试:查看完整返回数据结构
|
|
|
+ console.log('超图服务返回的数据:', JSON.stringify(superMapData, null, 2).substring(0, 2000));
|
|
|
+ console.log('数据类型:', typeof superMapData);
|
|
|
+ console.log('数据键:', Object.keys(superMapData || {}));
|
|
|
+
|
|
|
+ let features = [];
|
|
|
+
|
|
|
+ // 尝试多种可能的数据结构
|
|
|
+ if (superMapData.features && Array.isArray(superMapData.features)) {
|
|
|
+ features = superMapData.features;
|
|
|
+ console.log('从 features 属性获取要素');
|
|
|
+ } else if (superMapData.recordset && Array.isArray(superMapData.recordset)) {
|
|
|
+ features = superMapData.recordset;
|
|
|
+ console.log('从 recordset 属性获取要素');
|
|
|
+ } else if (superMapData.result && superMapData.result.features && Array.isArray(superMapData.result.features)) {
|
|
|
+ features = superMapData.result.features;
|
|
|
+ console.log('从 result.features 属性获取要素');
|
|
|
+ } else if (Array.isArray(superMapData)) {
|
|
|
+ features = superMapData;
|
|
|
+ console.log('数据本身是数组');
|
|
|
+ } else {
|
|
|
+ console.warn('未找到要素数据,尝试查找其他属性');
|
|
|
+ // 遍历所有属性查找数组
|
|
|
+ for (const key of Object.keys(superMapData || {})) {
|
|
|
+ if (Array.isArray(superMapData[key])) {
|
|
|
+ console.log(`发现数组属性 ${key},长度:`, superMapData[key].length);
|
|
|
+ if (superMapData[key].length > 0 && superMapData[key][0].geometry) {
|
|
|
+ features = superMapData[key];
|
|
|
+ console.log(`使用 ${key} 作为要素数组`);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换每个要素的坐标格式(超图可能返回平面坐标,需要转换为经纬度)
|
|
|
+ console.log('原始要素数量:', features.length);
|
|
|
+ if (features.length > 0) {
|
|
|
+ console.log('第一个要素示例:', JSON.stringify(features[0], null, 2).substring(0, 1000));
|
|
|
+ }
|
|
|
+
|
|
|
+ features = features.map((feature, index) => {
|
|
|
+ if (!feature) {
|
|
|
+ console.warn(`要素 ${index} 为空`);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (!feature.geometry) {
|
|
|
+ console.warn(`要素 ${index} 没有geometry`);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (!feature.geometry.coordinates) {
|
|
|
+ console.warn(`要素 ${index} 没有coordinates`);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 尝试转换坐标
|
|
|
+ try {
|
|
|
+ feature.geometry.coordinates = convertCoordinates(feature.geometry.coordinates);
|
|
|
+ return feature;
|
|
|
+ } catch (e) {
|
|
|
+ console.error(`要素 ${index} 坐标转换失败:`, e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }).filter(Boolean);
|
|
|
+
|
|
|
+ console.log('转换后的要素数量:', features.length);
|
|
|
+
|
|
|
+ // 返回标准GeoJSON FeatureCollection
|
|
|
+ return {
|
|
|
+ type: 'FeatureCollection',
|
|
|
+ features: features
|
|
|
+ };
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+// 坐标转换:尝试将平面坐标转换为经纬度
|
|
|
+function convertCoordinates(coordinates) {
|
|
|
+ if (!Array.isArray(coordinates)) {
|
|
|
+ return coordinates;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否是经纬度范围(-180到180,-90到90)
|
|
|
+ const isLatLng = (coord) => {
|
|
|
+ return Math.abs(coord[0]) <= 180 && Math.abs(coord[1]) <= 90;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 检查是否是Web Mercator或其他大坐标值
|
|
|
+ const isLargeCoord = (coord) => {
|
|
|
+ return Math.abs(coord[0]) > 10000 || Math.abs(coord[1]) > 10000;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理点坐标
|
|
|
+ if (coordinates.length >= 2 && typeof coordinates[0] === 'number') {
|
|
|
+ if (isLargeCoord(coordinates)) {
|
|
|
+ console.log('检测到大坐标值,尝试Web Mercator转WGS84:', coordinates);
|
|
|
+ try {
|
|
|
+ const cartesian3 = Cesium.Cartesian3.fromArray(coordinates);
|
|
|
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
|
|
|
+ return [
|
|
|
+ Cesium.Math.toDegrees(cartographic.longitude),
|
|
|
+ Cesium.Math.toDegrees(cartographic.latitude),
|
|
|
+ cartographic.height || 0
|
|
|
+ ];
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('坐标转换失败:', e);
|
|
|
+ return coordinates;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return coordinates;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理线坐标(二维数组)
|
|
|
+ if (coordinates.length > 0 && Array.isArray(coordinates[0])) {
|
|
|
+ return coordinates.map(coord => convertCoordinates(coord));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理多边形坐标(三维数组)
|
|
|
+ if (coordinates.length > 0 && Array.isArray(coordinates[0][0])) {
|
|
|
+ return coordinates.map(ring => ring.map(coord => convertCoordinates(coord)));
|
|
|
+ }
|
|
|
+
|
|
|
+ return coordinates;
|
|
|
+}
|
|
|
+
|
|
|
+// 加载超图REST数据服务
|
|
|
+function loadSuperMapRestDataService(baseUrl, name, callback) {
|
|
|
+ console.log('开始加载超图REST数据服务:', baseUrl);
|
|
|
+
|
|
|
+ // 设置超时时间
|
|
|
+ const timeout = 30000; // 30秒
|
|
|
+
|
|
|
+ // 创建超时Promise
|
|
|
+ const timeoutPromise = new Promise((_, reject) => {
|
|
|
+ setTimeout(() => reject(new Error('请求超时')), timeout);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 修正URL:添加.json后缀(如果缺少的话)
|
|
|
+ let datasourcesUrl = baseUrl;
|
|
|
+ if (!datasourcesUrl.endsWith('.json')) {
|
|
|
+ datasourcesUrl = `${baseUrl}.json`;
|
|
|
+ }
|
|
|
+ console.log('修正后的数据源URL:', datasourcesUrl);
|
|
|
+
|
|
|
+ // 获取数据源列表
|
|
|
+ Promise.race([
|
|
|
+ fetch(datasourcesUrl, { timeout: timeout }),
|
|
|
+ timeoutPromise
|
|
|
+ ])
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ // 如果.json后缀失败,尝试不加后缀
|
|
|
+ if (datasourcesUrl !== baseUrl) {
|
|
|
+ console.log(`HTTP错误: ${response.status},尝试不加.json后缀`);
|
|
|
+ return fetch(baseUrl, { timeout: timeout });
|
|
|
+ }
|
|
|
+ throw new Error(`HTTP错误: ${response.status}`);
|
|
|
+ }
|
|
|
+ return response;
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP错误: ${response.status}`);
|
|
|
+ }
|
|
|
+ return response.text();
|
|
|
+ })
|
|
|
+ .then(text => {
|
|
|
+ // 尝试解析JSON
|
|
|
+ try {
|
|
|
+ return JSON.parse(text);
|
|
|
+ } catch (e) {
|
|
|
+ // 如果JSON解析失败,检查是否是HTML错误页面
|
|
|
+ console.error('JSON解析失败,响应内容:', text.substring(0, 200));
|
|
|
+ throw new Error('服务返回的不是有效的JSON数据');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(dataSources => {
|
|
|
+ console.log('获取到数据源列表:', dataSources);
|
|
|
+
|
|
|
+ // 处理超图REST数据服务返回的格式
|
|
|
+ // 超图返回的格式是: { datasourceNames: [...], childUriList: [...], datasourceCount: N }
|
|
|
+ let dataSourceNames = [];
|
|
|
+ if (Array.isArray(dataSources)) {
|
|
|
+ // 如果返回的是数组,直接使用
|
|
|
+ dataSourceNames = dataSources.map(ds => ds.name || ds);
|
|
|
+ } else if (dataSources && dataSources.datasourceNames && Array.isArray(dataSources.datasourceNames)) {
|
|
|
+ // 超图REST数据服务格式
|
|
|
+ dataSourceNames = dataSources.datasourceNames;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!dataSourceNames || dataSourceNames.length === 0) {
|
|
|
+ console.warn('未找到数据源');
|
|
|
+ if (callback) callback(null);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历所有数据源
|
|
|
+ const loadPromises = [];
|
|
|
+
|
|
|
+ dataSourceNames.forEach(dataSourceName => {
|
|
|
+ // 确保数据源名称是字符串
|
|
|
+ const name = typeof dataSourceName === 'object' ? (dataSourceName.name || dataSourceName) : dataSourceName;
|
|
|
+ let datasetsUrl = `${baseUrl}/${encodeURIComponent(name)}/datasets`;
|
|
|
+ if (!datasetsUrl.endsWith('.json')) {
|
|
|
+ datasetsUrl += '.json';
|
|
|
+ }
|
|
|
|
|
|
- let boundingSphere = new Cesium.BoundingSphere();
|
|
|
- let entitiesLength = entities.length;
|
|
|
+ // 获取数据集列表
|
|
|
+ const datasetPromise = Promise.race([
|
|
|
+ fetch(datasetsUrl, { timeout: timeout }),
|
|
|
+ timeoutPromise
|
|
|
+ ])
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ if (datasetsUrl !== `${baseUrl}/${encodeURIComponent(name)}/datasets`) {
|
|
|
+ return fetch(`${baseUrl}/${encodeURIComponent(name)}/datasets`, { timeout: timeout });
|
|
|
+ }
|
|
|
+ throw new Error(`HTTP错误: ${response.status}`);
|
|
|
+ }
|
|
|
+ return response;
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP错误: ${response.status}`);
|
|
|
+ }
|
|
|
+ return response.text();
|
|
|
+ })
|
|
|
+ .then(text => {
|
|
|
+ try {
|
|
|
+ return JSON.parse(text);
|
|
|
+ } catch (e) {
|
|
|
+ console.error(`数据集列表JSON解析失败 (${name}):`, text.substring(0, 200));
|
|
|
+ throw new Error('数据集列表不是有效的JSON');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(datasets => {
|
|
|
+ console.log(`数据源 ${name} 的数据集列表:`, datasets);
|
|
|
+
|
|
|
+ // 处理数据集格式
|
|
|
+ let datasetNames = [];
|
|
|
+ if (Array.isArray(datasets)) {
|
|
|
+ datasetNames = datasets.map(ds => ds.name || ds);
|
|
|
+ } else if (datasets && datasets.datasetNames && Array.isArray(datasets.datasetNames)) {
|
|
|
+ datasetNames = datasets.datasetNames;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!datasetNames || datasetNames.length === 0) {
|
|
|
+ return Promise.resolve([]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载每个数据集的要素(限制同时加载的数量)
|
|
|
+ const featurePromises = [];
|
|
|
+ const maxConcurrent = 3; // 最大并发数
|
|
|
+
|
|
|
+ for (let i = 0; i < datasetNames.length; i += maxConcurrent) {
|
|
|
+ const batch = datasetNames.slice(i, i + maxConcurrent);
|
|
|
+ const batchPromises = batch.map(dsName => {
|
|
|
+ // 确保数据集名称是字符串
|
|
|
+ const datasetName = typeof dsName === 'object' ? (dsName.name || dsName) : dsName;
|
|
|
+ let featuresUrl = `${baseUrl}/${encodeURIComponent(name)}/datasets/${encodeURIComponent(datasetName)}/features.json?returnContent=true`;
|
|
|
+ console.log('加载要素URL:', featuresUrl);
|
|
|
+
|
|
|
+ // 先获取超图格式的要素数据,转换为标准GeoJSON后再加载
|
|
|
+ return fetchFeaturesFromSuperMap(featuresUrl, timeout)
|
|
|
+ .then(geoJsonData => {
|
|
|
+ if (!geoJsonData) {
|
|
|
+ throw new Error('未获取到有效要素数据');
|
|
|
+ }
|
|
|
+ // 使用Cesium加载GeoJSON
|
|
|
+ return Cesium.GeoJsonDataSource.load(geoJsonData, {
|
|
|
+ stroke: Cesium.Color.fromCssColorString('#0055FF').withAlpha(1),
|
|
|
+ fill: Cesium.Color.fromCssColorString('#00FF00').withAlpha(0.4),
|
|
|
+ strokeWidth: 3,
|
|
|
+ clampToGround: true
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .then(geoJsonDataSource => {
|
|
|
+ viewer.dataSources.add(geoJsonDataSource);
|
|
|
+ processGeoJsonEntities(geoJsonDataSource, `${name}-${datasetName}`);
|
|
|
+ return geoJsonDataSource;
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error(`加载数据集 ${datasetName} 失败:`, error);
|
|
|
+ return null;
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ featurePromises.push(Promise.all(batchPromises));
|
|
|
+ }
|
|
|
+
|
|
|
+ return Promise.all(featurePromises).then(results => results.flat());
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error(`获取数据集列表失败 (${name}):`, error);
|
|
|
+ return [];
|
|
|
+ });
|
|
|
|
|
|
- for (let i = 0; i < entitiesLength; i++) {
|
|
|
+ loadPromises.push(datasetPromise);
|
|
|
+ });
|
|
|
+
|
|
|
+ Promise.all(loadPromises)
|
|
|
+ .then(results => {
|
|
|
+ const allDataSources = results.flat().filter(Boolean);
|
|
|
+ console.log('所有加载的GeoJSON数据源:', allDataSources);
|
|
|
+
|
|
|
+ if (allDataSources.length > 0) {
|
|
|
+ viewer.flyTo(allDataSources[0], { duration: 2 });
|
|
|
+ }
|
|
|
+
|
|
|
+ actions.setChangeLayers();
|
|
|
+ if (callback) callback(allDataSources.length > 0 ? allDataSources : null);
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error('加载超图REST数据服务失败:', error);
|
|
|
+ if (callback) callback(null);
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error('获取数据源列表失败:', error);
|
|
|
+ if (callback) callback(null);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+// 处理GeoJSON实体(异步方式,避免阻塞主线程)
|
|
|
+function processGeoJsonEntities(dataSource, name) {
|
|
|
+ try {
|
|
|
+ let entities = dataSource.entities.values;
|
|
|
+ let entitiesLength = entities.length;
|
|
|
+
|
|
|
+ // 限制处理的实体数量,防止大量数据导致卡死
|
|
|
+ const maxEntities = 5000;
|
|
|
+ if (entitiesLength > maxEntities) {
|
|
|
+ console.warn(`实体数量过多(${entitiesLength}),仅处理前${maxEntities}个`);
|
|
|
+ entitiesLength = maxEntities;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用异步批量处理
|
|
|
+ const batchSize = 50; // 每批处理50个实体
|
|
|
+ let currentIndex = 0;
|
|
|
+
|
|
|
+ const processBatch = () => {
|
|
|
+ if (currentIndex >= entitiesLength) {
|
|
|
+ return; // 处理完成
|
|
|
+ }
|
|
|
+
|
|
|
+ const endIndex = Math.min(currentIndex + batchSize, entitiesLength);
|
|
|
+
|
|
|
+ for (let i = currentIndex; i < endIndex; i++) {
|
|
|
let entity = entities[i];
|
|
|
- entity.name = name || 'GeoJSON';
|
|
|
+ if (!entity) continue;
|
|
|
|
|
|
- // 面配置 完全贴地 不被遮挡
|
|
|
+ entity.name = name || 'GeoJSON';
|
|
|
+
|
|
|
if (entity.polygon) {
|
|
|
entity.polygon.fill = true;
|
|
|
entity.polygon.outline = true;
|
|
|
@@ -155,16 +620,14 @@ function addGeoJsonLayer(url, name, callback) {
|
|
|
entity.polygon.outlineColor = Cesium.Color.fromCssColorString('#0055FF');
|
|
|
entity.polygon.outlineWidth = 4;
|
|
|
}
|
|
|
-
|
|
|
- // 线配置
|
|
|
+
|
|
|
if (entity.polyline) {
|
|
|
entity.polyline.clampToGround = true;
|
|
|
entity.polyline.classificationType = Cesium.ClassificationType.TERRAIN;
|
|
|
entity.polyline.material = Cesium.Color.fromCssColorString('#0055FF');
|
|
|
entity.polyline.width = 4;
|
|
|
}
|
|
|
-
|
|
|
- // 点配置
|
|
|
+
|
|
|
if (entity.point) {
|
|
|
entity.point.clampToGround = true;
|
|
|
entity.point.color = Cesium.Color.fromCssColorString('#FF0000');
|
|
|
@@ -174,8 +637,7 @@ function addGeoJsonLayer(url, name, callback) {
|
|
|
entity.point.disableDepthTestDistance = Number.POSITIVE_INFINITY;
|
|
|
entity.isGeoJsonPoint = true;
|
|
|
}
|
|
|
-
|
|
|
- // 图标转点
|
|
|
+
|
|
|
if (entity.billboard) {
|
|
|
entity.billboard.show = false;
|
|
|
entity.point = {
|
|
|
@@ -188,41 +650,31 @@ function addGeoJsonLayer(url, name, callback) {
|
|
|
};
|
|
|
entity.isGeoJsonPoint = true;
|
|
|
}
|
|
|
-
|
|
|
- // 计算视图范围
|
|
|
- if (entity.boundingSphere) {
|
|
|
- if (i === 0) {
|
|
|
- boundingSphere = entity.boundingSphere;
|
|
|
- } else {
|
|
|
- boundingSphere = Cesium.BoundingSphere.union(boundingSphere, entity.boundingSphere);
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
-
|
|
|
- viewer.flyTo(dataSource, { duration: 2 });
|
|
|
-
|
|
|
- actions.setChangeLayers();
|
|
|
- if (callback) callback(dataSource);
|
|
|
- }, function(error) {
|
|
|
- console.error("加载GeoJSON失败:", error);
|
|
|
- });
|
|
|
- } catch (e) {
|
|
|
- console.error("加载GeoJSON异常:", e);
|
|
|
+
|
|
|
+ currentIndex = endIndex;
|
|
|
+ // 使用 requestAnimationFrame 让出主线程给渲染
|
|
|
+ requestAnimationFrame(processBatch);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 开始处理
|
|
|
+ processBatch();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理GeoJSON实体失败:', error);
|
|
|
}
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
-// 加载s3m和场景函数
|
|
|
+// 加载s3m和场景
|
|
|
function promiseWhen(promiseArray, callback, type) {
|
|
|
Cesium.when.all(
|
|
|
promiseArray,
|
|
|
function (layers) {
|
|
|
- console.log("layers:",layers)
|
|
|
storeDate.layers = viewer.scene.layers.layerQueue;
|
|
|
actions.setChangeLayers();
|
|
|
callback(layers, type);
|
|
|
storeDate.layers.forEach((s3mlayer) => {
|
|
|
if (!s3mlayer.visibleDistanceMax || s3mlayer.visibleDistanceMax > 12000) {
|
|
|
- s3mlayer.visibleDistanceMax = 12000 //设置模型最可见距离
|
|
|
+ s3mlayer.visibleDistanceMax = 12000
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
@@ -236,7 +688,7 @@ function promiseWhen(promiseArray, callback, type) {
|
|
|
);
|
|
|
};
|
|
|
|
|
|
-// 检验url地址
|
|
|
+// 检验url
|
|
|
function checkURL(url) {
|
|
|
if (url === null || url === "") {
|
|
|
return false;
|
|
|
@@ -248,18 +700,14 @@ function checkURL(url) {
|
|
|
return true
|
|
|
};
|
|
|
|
|
|
-// 删除图层
|
|
|
+// 删除图层
|
|
|
function layersDelete(type, id_name, callback) {
|
|
|
switch (type) {
|
|
|
case "SCENE":
|
|
|
- console.log('开始删除SCENE图层, id_name:', id_name);
|
|
|
if (viewer.scene.layers && viewer.scene.layers.layerQueue) {
|
|
|
const layers = viewer.scene.layers.layerQueue;
|
|
|
- console.log('场景中的图层数量:', layers.length);
|
|
|
for (let i = layers.length - 1; i >= 0; i--) {
|
|
|
- const layer = layers[i];
|
|
|
- console.log('删除图层:', i, layer.name);
|
|
|
- viewer.scene.layers.remove(layer);
|
|
|
+ viewer.scene.layers.remove(layers[i]);
|
|
|
}
|
|
|
}
|
|
|
actions.setChangeLayers();
|
|
|
@@ -271,16 +719,29 @@ function layersDelete(type, id_name, callback) {
|
|
|
if (callback) callback();
|
|
|
break;
|
|
|
case "IMG":
|
|
|
+ case "IMAGE":
|
|
|
let img_layer;
|
|
|
- if (typeof (id_name) === 'nunber') {
|
|
|
+ if (typeof (id_name) === 'number') {
|
|
|
img_layer = viewer.imageryLayers.get(id_name);
|
|
|
} else {
|
|
|
- let img_layers = viewer.imageryLayers._layers
|
|
|
+ let img_layers = viewer.imageryLayers._layers;
|
|
|
for (let i = 0; i < img_layers.length; i++) {
|
|
|
- if (img_layers[i].imageryProvider.tablename && img_layers[i].imageryProvider.tablename === id_name) {
|
|
|
- img_layer = img_layers[i];
|
|
|
+ const layer = img_layers[i];
|
|
|
+ const provider = layer.imageryProvider;
|
|
|
+ let matched = false;
|
|
|
+ if (provider.tablename && provider.tablename === id_name) matched = true;
|
|
|
+ if (!matched && layer._loadedLayerName && (layer._loadedLayerName === id_name || layer._loadedLayerName.includes(id_name) || id_name.includes(layer._loadedLayerName))) matched = true;
|
|
|
+ if (!matched && layer._loadedUrl && (layer._loadedUrl === id_name || layer._loadedUrl.includes(id_name) || id_name.includes(layer._loadedUrl))) matched = true;
|
|
|
+ if (!matched && provider.url) {
|
|
|
+ const urlStr = typeof provider.url === 'string' ? provider.url : JSON.stringify(provider.url);
|
|
|
+ if (urlStr.includes(id_name) || id_name.includes(urlStr)) matched = true;
|
|
|
}
|
|
|
- };
|
|
|
+ if (!matched && provider.name && (provider.name === id_name || provider.name.includes(id_name))) matched = true;
|
|
|
+ if (matched) {
|
|
|
+ img_layer = layer;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
if (img_layer) {
|
|
|
viewer.imageryLayers.remove(img_layer);
|
|
|
@@ -300,18 +761,14 @@ function layersDelete(type, id_name, callback) {
|
|
|
break;
|
|
|
case "GEOJSON":
|
|
|
case "SHP":
|
|
|
- console.log('开始删除GEOJSON/SHP图层, id_name:', id_name);
|
|
|
if (viewer.dataSources) {
|
|
|
const dataSources = viewer.dataSources._dataSources;
|
|
|
- console.log('当前数据源数量:', dataSources.length);
|
|
|
let removed = false;
|
|
|
for (let i = dataSources.length - 1; i >= 0; i--) {
|
|
|
const ds = dataSources[i];
|
|
|
- console.log('检查数据源:', i, 'name:', ds.name, '_name:', ds._name);
|
|
|
- if (ds.name === id_name || ds._name === id_name ||
|
|
|
- (ds.name && ds.name.includes(id_name)) ||
|
|
|
+ if (ds.name === id_name || ds._name === id_name ||
|
|
|
+ (ds.name && ds.name.includes(id_name)) ||
|
|
|
(ds._name && ds._name.includes(id_name))) {
|
|
|
- console.log('匹配到数据源,删除:', ds.name);
|
|
|
viewer.dataSources.remove(ds);
|
|
|
removed = true;
|
|
|
break;
|
|
|
@@ -320,7 +777,6 @@ function layersDelete(type, id_name, callback) {
|
|
|
for (let j = 0; j < entities.length; j++) {
|
|
|
const entity = entities[j];
|
|
|
if (entity.name === id_name || (entity.name && entity.name.includes(id_name))) {
|
|
|
- console.log('通过entity匹配到数据源,删除:', ds.name);
|
|
|
viewer.dataSources.remove(ds);
|
|
|
removed = true;
|
|
|
break;
|
|
|
@@ -328,9 +784,6 @@ function layersDelete(type, id_name, callback) {
|
|
|
}
|
|
|
if (removed) break;
|
|
|
}
|
|
|
- if (!removed) {
|
|
|
- console.warn('未找到匹配的数据源:', id_name);
|
|
|
- }
|
|
|
}
|
|
|
actions.setChangeLayers();
|
|
|
if (callback) callback();
|