diff --git a/src/component/map/AdministrativeDivision.vue b/src/component/map/AdministrativeDivision.vue index 0596d20..0bd3aba 100644 --- a/src/component/map/AdministrativeDivision.vue +++ b/src/component/map/AdministrativeDivision.vue @@ -39,31 +39,35 @@ const areasColor = [ new Color(190 / 255, 255 / 255, 232 / 255) ] const areaTransparency = 0.3; -const labelTransparency = 0.7; +const labelTransparency = 1; onMounted(() => { - CesiumUtilsSingleton.batchAddGeoJsonLayers( - areasId, - areas, - areas.map((area, index) => { - const areaName = area.features[0].properties.name; - return { - showName: true, - isDefault: true, - labelStyle: { - labelText: areaName, - center: [area.features[0].properties.center[0], area.features[0].properties.center[1], 0], - labelColor: Color.BLACK, - backgroundColor: areasColor[index].withAlpha(labelTransparency) - }, - polygonStyle: { - fill: true, - fillColor: areasColor[index].withAlpha(areaTransparency), - outline: false - } + // 构建批量添加配置数组 + const layerConfigs = areasId.map((id, index) => ({ + layerId: id, + geojsonData: areas[index], + isDefault: true, + options: { + showName: true, + labelStyle: { + labelText: areas[index].features[0].properties.name, + center: [ + areas[index].features[0].properties.center[0], + areas[index].features[0].properties.center[1], + 0 + ] as [number, number, number], + labelColor: Color.BLACK, + backgroundColor: areasColor[index].withAlpha(labelTransparency) + }, + polygonStyle: { + fill: true, + fillColor: areasColor[index].withAlpha(areaTransparency), + outline: false } - }) - ); + } + })); + + CesiumUtilsSingleton.batchAddGeoJsonLayers(layerConfigs); }) diff --git a/src/utils/cesium/CesiumUtils.ts b/src/utils/cesium/CesiumUtils.ts index 6b7c272..c99c3e6 100644 --- a/src/utils/cesium/CesiumUtils.ts +++ b/src/utils/cesium/CesiumUtils.ts @@ -68,6 +68,16 @@ export class CesiumUtils { return this.#entityManager!.addCesiumEntity(entityOptions) } + /** + * 批量添加实体 + * @param entityOptionsList - 实体配置选项数组 + * @returns 创建的 Entity 实例数组 + */ + addCesiumEntitiesBatch(entityOptionsList: EntityOptions[]): Entity[] { + this.#checkManager(this.#entityManager, 'EntityManager') + return this.#entityManager!.addCesiumEntitiesBatch(entityOptionsList) + } + /** * 查询实体 * @param entityId - 实体 ID @@ -119,7 +129,18 @@ export class CesiumUtils { // ===================== Primitive 管理 ===================== /** - * 批量添加 Primitive + * 添加单个 Primitive + * @param primitive - Primitive 配置选项 + */ + addPrimitive(primitive: PrimitiveOptions): void { + this.#checkManager(this.#primitiveManager, 'PrimitiveManager') + this.#primitiveManager!.addPrimitive(primitive) + } + + /** + * 批量添加 Primitive(优化版本) + * - 按类型分组后批量创建,减少 scene.primitives.add 调用次数 + * - 同类型的多个实例合并到一个 Primitive 或 BillboardCollection 中 * @param primitives - Primitive 配置选项数组 */ addPrimitivesBatch(primitives: PrimitiveOptions[]): void { @@ -168,6 +189,16 @@ export class CesiumUtils { // ===================== 图层管理 ===================== + /** + * 批量创建图层 + * @param layerConfigs - 图层配置数组 + * @returns 创建的 ImageryLayer 实例数组(失败的为 null) + */ + createLayersBatch(layerConfigs: LayerConfig[]): (ImageryLayer | null)[] { + this.#checkManager(this.#layerManager, 'LayerManager') + return this.#layerManager!.createLayersBatch(layerConfigs) + } + /** * 创建图层 * @param layerConfig - 图层配置 @@ -268,17 +299,18 @@ export class CesiumUtils { /** * 批量添加GeoJSON图层 - * @param layerIds - 图层 ID 数组 - * @param geojsonDatas - GeoJSON 数据数组 - * @param options - 配置选项数组(包含 isDefault) + * @param layerConfigs - 图层配置数组,每个元素包含 layerId、geojsonData、isDefault 和 options */ async batchAddGeoJsonLayers( - layerIds: string[], - geojsonDatas: CustomizeGeoJsonDataSource[], - options?: GeoJsonOptions[] + layerConfigs: Array<{ + layerId: string + geojsonData: CustomizeGeoJsonDataSource + isDefault?: boolean + options?: GeoJsonOptions + }> ): Promise { this.#checkManager(this.#geoJsonManager, 'GeoJsonManager') - await this.#geoJsonManager!.batchAddGeoJsonLayers(layerIds, geojsonDatas, options) + await this.#geoJsonManager!.batchAddGeoJsonLayers(layerConfigs) } /** diff --git a/src/utils/cesium/EntityManager.ts b/src/utils/cesium/EntityManager.ts index 804b89e..aa26543 100644 --- a/src/utils/cesium/EntityManager.ts +++ b/src/utils/cesium/EntityManager.ts @@ -8,10 +8,8 @@ import { HeightReference, VerticalOrigin, HorizontalOrigin, - ColorMaterialProperty, PolygonHierarchy, PolygonGraphics, - ConstantProperty, GridMaterialProperty, } from 'cesium' import type { EntityOptions } from '@/types/cesium/EntityOptions' @@ -29,6 +27,41 @@ export class EntityManager { this.#viewer = viewer } + /** + * 批量添加实体 + * @param entityOptionsList - 实体配置选项数组 + * @returns 创建的 Entity 实例数组 + */ + addCesiumEntitiesBatch(entityOptionsList: EntityOptions[]): Entity[] { + const entities: Entity[] = [] + + // 预验证所有ID的唯一性 + entityOptionsList.forEach(({ id }) => { + if (!id) throw new Error('实体 id 为必填项') + this.#validateUniqueId(id) + }) + + // 批量创建并添加实体 + entityOptionsList.forEach((entityOptions) => { + const { id, position, attributes = {}, isDefault = false } = entityOptions + + if (!position) throw new Error(`实体 ${id} 的 position 为必填项`) + + const entity = new Entity({ + id, + position: this.#convertPosition(position), + ...attributes, + }) + + this.#configureEntityGraphics(entity, entityOptions) + this.#viewer.entities.add(entity) + this.#storeEntityId(id, isDefault) + entities.push(entity) + }) + + return entities + } + /** * 添加实体 * @param entityOptions - 实体配置选项 @@ -148,7 +181,7 @@ export class EntityManager { entity.polyline = new PolylineGraphics({ positions: this.#convertPositionArray(positions), - material: new ColorMaterialProperty(color), + material: color, width, clampToGround, }) @@ -195,14 +228,13 @@ export class EntityManager { if (!hierarchy) throw new Error('多边形实体必须传入 polygonOptions.hierarchy') entity.polygon = new PolygonGraphics({ - hierarchy: this.#createConstantProperty(this.#processHierarchy(hierarchy)), + hierarchy: this.#processHierarchy(hierarchy), material: material, - outline: this.#createConstantProperty(outline), - outlineColor: this.#createConstantProperty(outlineColor), - outlineWidth: this.#createConstantProperty(outlineWidth), - height: this.#createConstantProperty(height), - extrudedHeight: - extrudedHeight !== undefined ? this.#createConstantProperty(extrudedHeight) : undefined, + outline, + outlineColor, + outlineWidth, + height, + extrudedHeight, heightReference, }) break @@ -233,10 +265,6 @@ export class EntityManager { return new PolygonHierarchy(positions) } - #createConstantProperty(value: unknown): ConstantProperty { - return new ConstantProperty(value) - } - #validateUniqueId(id: string): void { if (this.#defaultEntityIds.has(id) || this.#customEntityIds.has(id)) { throw new Error(`实体 ID ${id} 已存在`) diff --git a/src/utils/cesium/GeoJsonManager.ts b/src/utils/cesium/GeoJsonManager.ts index 62665b1..fee8639 100644 --- a/src/utils/cesium/GeoJsonManager.ts +++ b/src/utils/cesium/GeoJsonManager.ts @@ -13,6 +13,7 @@ import { Cartesian3, Cartographic, JulianDate, + NearFarScalar, } from 'cesium' import type { CustomizeGeoJsonDataSource, GeoJsonOptions } from '@/types/cesium/GeoJsonOptions' import type { LabelConfig } from '@/types/cesium/LabelConfig' @@ -143,18 +144,19 @@ export class GeoJsonManager { /** * 批量添加GeoJSON图层 - * @param layerIds - 图层 ID 数组 - * @param geojsonDatas - GeoJSON 数据数组 - * @param options - 配置选项数组(包含 isDefault) + * @param layerConfigs - 图层配置数组,每个元素包含 layerId、geojsonData、isDefault 和 options */ async batchAddGeoJsonLayers( - layerIds: string[], - geojsonDatas: CustomizeGeoJsonDataSource[], - options?: GeoJsonOptions[], + layerConfigs: Array<{ + layerId: string + geojsonData: CustomizeGeoJsonDataSource + isDefault?: boolean + options?: GeoJsonOptions + }>, ): Promise { await Promise.all( - layerIds.map((id, index) => - this.addGeoJsonLayer(id, geojsonDatas?.[index], false, options?.[index]) + layerConfigs.map(({ layerId, geojsonData, isDefault = false, options }) => + this.addGeoJsonLayer(layerId, geojsonData, isDefault, options) ) ) } @@ -320,6 +322,8 @@ export class GeoJsonManager { /** * 添加标签到数据源 + * - 禁用描边以提升渲染性能 + * - 添加距离衰减以减少远距离渲染负担 */ #addLabelsToDataSource(dataSource: DataSource, label: LabelConfig): void { const entities = dataSource.entities.values @@ -338,9 +342,8 @@ export class GeoJsonManager { text: new ConstantProperty(labelText), font: new ConstantProperty(label?.labelFont || `${label?.labelSize || 16}px "微软雅黑"`), fillColor: new ConstantProperty(label?.labelColor || Color.WHITE), - outlineColor: new ConstantProperty(Color.BLACK), - outlineWidth: new ConstantProperty(1), - style: new ConstantProperty(LabelStyle.FILL_AND_OUTLINE), + // 性能优化:禁用描边 + style: new ConstantProperty(LabelStyle.FILL), pixelOffset: new ConstantProperty( new Cartesian2(label?.labelOffset?.x || 0, label?.labelOffset?.y || -20), ), @@ -352,6 +355,13 @@ export class GeoJsonManager { backgroundColor: new ConstantProperty(label?.backgroundColor || Color.TRANSPARENT), backgroundPadding: new ConstantProperty(new Cartesian2(5, 3)), disableDepthTestDistance: new ConstantProperty(Number.POSITIVE_INFINITY), + // 性能优化:添加距离衰减,减少远距离渲染负担 + scaleByDistance: new ConstantProperty( + new NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5) + ), + translucencyByDistance: new ConstantProperty( + new NearFarScalar(1.5e2, 1.0, 1.5e7, 0.3) + ), }) } }) diff --git a/src/utils/cesium/LayerManager.ts b/src/utils/cesium/LayerManager.ts index 62b734c..50c2b7f 100644 --- a/src/utils/cesium/LayerManager.ts +++ b/src/utils/cesium/LayerManager.ts @@ -20,6 +20,22 @@ export class LayerManager { this.#viewer = viewer } + /** + * 批量创建图层 + * @param layerConfigs - 图层配置数组 + * @returns 创建的 ImageryLayer 实例数组(失败的为 null) + */ + createLayersBatch(layerConfigs: LayerConfig[]): (ImageryLayer | null)[] { + return layerConfigs.map((config) => { + try { + return this.createLayer(config) + } catch (error) { + console.error(`创建图层 ${config.layers} 失败:`, error) + return null + } + }) + } + /** * 创建图层 * @param layerConfig - 图层配置 diff --git a/src/utils/cesium/PrimitiveManager.ts b/src/utils/cesium/PrimitiveManager.ts index 3c0288c..14a7379 100644 --- a/src/utils/cesium/PrimitiveManager.ts +++ b/src/utils/cesium/PrimitiveManager.ts @@ -30,17 +30,40 @@ export class PrimitiveManager { this.#viewer = viewer } + /** + * 添加单个 Primitive + * @param primitive - Primitive 配置选项 + */ + addPrimitive(primitive: PrimitiveOptions): void { + this.addPrimitivesBatch([primitive]) + } + /** * 批量添加 Primitive + * - 按类型分组后批量创建,减少 scene.primitives.add 调用次数 + * - 同类型的多个实例合并到一个 Primitive 或 BillboardCollection 中 * @param primitives - Primitive 配置选项数组 */ addPrimitivesBatch(primitives: PrimitiveOptions[]): void { + if (primitives.length === 0) return + const grouped = this.#groupPrimitivesByType(primitives) - if (grouped.points.length > 0) this.#addPointPrimitives(grouped.points) - if (grouped.polylines.length > 0) this.#addPolylinePrimitives(grouped.polylines) - if (grouped.polygons.length > 0) this.#addPolygonPrimitives(grouped.polygons) - if (grouped.billboards.length > 0) this.#addBillboardPrimitives(grouped.billboards) + // 并行添加不同类型的 Primitive + const promises: Promise[] = [] + + if (grouped.points.length > 0) { + promises.push(Promise.resolve(this.#addPointPrimitives(grouped.points))) + } + if (grouped.polylines.length > 0) { + promises.push(Promise.resolve(this.#addPolylinePrimitives(grouped.polylines))) + } + if (grouped.polygons.length > 0) { + promises.push(Promise.resolve(this.#addPolygonPrimitives(grouped.polygons))) + } + if (grouped.billboards.length > 0) { + promises.push(Promise.resolve(this.#addBillboardPrimitives(grouped.billboards))) + } } /**