Cesium加载大量广告牌并实现贴地

项目地址

https://github.com/zhengjie9510/webgis-demo

实现效果

请添加图片描述

实现方法

方式1:heightReference属性

使用 Billboard 自带的 heightReference 属性实现贴地。该方法的好处是实现简单,但如果数据量巨大(50000以上),加载会比较慢。
使用该方法需要在创建 BillboardCollection 时指定 scene 属性。

const collection = new Cesium.BillboardCollection({ scene: viewer.scene })

并在创建 Billboard 时将 heightReference 设置为 CLAMP_TO_GROUND。

collection.add({
	position: position,
	image: pinBuilder.fromColor(Cesium.Color.fromRandom({ alpha: 1.0 }), 20).toDataURL(),
	verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
	horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
	heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
})

方式2:sampleTerrainMostDetailed方法

如果数据量较大,另一种可行的方法是先使用 sampleTerrainMostDetailed 获取点的高程,并存储到数据库中,之后直接从数据库中读取数据。该方式只在高程采样时较慢,后面的加载会非常快,比较适用于大量数据的加载显示。

// 1、生成大量随机点
const points = randomPoint(500, { bbox: [100, 25, 102, 27] })
// 2、Cartographic数组
const positions = []
for (let point of points.features) {
  const coordinates = point.geometry.coordinates
  const position = Cesium.Cartographic.fromDegrees(coordinates[0], coordinates[1])
  positions.push(position)
}
// 3、高程采样
const pinBuilder = new Cesium.PinBuilder();
const collection = new Cesium.BillboardCollection()
const terrainProvider = viewer.terrainProvider
const promise = Cesium.sampleTerrainMostDetailed(terrainProvider, positions);
Promise.resolve(promise).then(function (updatedPositions) {
  for (let position of updatedPositions) {
    collection.add({
      position: Cesium.Cartesian3.fromRadians(position.longitude, position.latitude, position.height),
      image: pinBuilder.fromColor(Cesium.Color.fromRandom({ alpha: 1.0 }), 20).toDataURL(),
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
    })
  }
  viewer.scene.primitives.add(collection)
});
function createPoint(dataSource, geoJson, crsFunction, coordinates, options) { let symbol = options.markerSymbol; let color = options.markerColor; let size = options.markerSize; const properties = geoJson.properties; if (defined(properties)) { const cssColor = properties["marker-color"]; if (defined(cssColor)) { color = Color.fromCssColorString(cssColor); } size = defaultValue(sizes[properties["marker-size"]], size); const markerSymbol = properties["marker-symbol"]; if (defined(markerSymbol)) { symbol = markerSymbol; } } let canvasOrPromise; if (defined(symbol)) { if (symbol.length === 1) { canvasOrPromise = dataSource._pinBuilder.fromText( symbol.toUpperCase(), color, size ); } else { canvasOrPromise = dataSource._pinBuilder.fromMakiIconId( symbol, color, size ); } } else { canvasOrPromise = dataSource._pinBuilder.fromColor(color, size); } const billboard = new BillboardGraphics(); billboard.verticalOrigin = new ConstantProperty(VerticalOrigin.BOTTOM); // Clamp to ground if there isn't a height specified if (coordinates.length === 2 && options.clampToGround) { billboard.heightReference = HeightReference.CLAMP_TO_GROUND; } const entity = createObject( geoJson, dataSource._entityCollection, options.describe ); entity.billboard = billboard; entity.position = new ConstantPositionProperty(crsFunction(coordinates)); const promise = Promise.resolve(canvasOrPromise) .then(function (image) { billboard.image = new ConstantProperty(image); }) .catch(function () { billboard.image = new ConstantProperty( dataSource._pinBuilder.fromColor(color, size) ); }); dataSource._promises.push(promise); }
03-08
<think>好的,我现在需要理解用户提供的这个JavaScript函数createPoint,给他做一个介绍。首先,我要通读代码,看看这个函数是做什么的。看起来这个函数是用来创建地理空间数据中的点要素的,可能是在地图上添加标记之类的。接下来我需要分步骤分析每个部分的功能。 首先,函数的参数是dataSource, geoJson, crsFunction, coordinates, options。可能dataSource是数据源,geoJson是地理JSON数据,crsFunction可能用于坐标参考系统转换,coordinates是坐标点,options是一些配置选项。 接下来,函数内部首先从options中提取markerSymbol、markerColor和markerSize。这些可能是设置图标的符号、颜色和大小。然后检查geoJson的properties属性,如果存在的话,覆盖之前的颜色、大小和符号。比如,如果properties里有"marker-color",就用它来设置颜色,使用Color.fromCssColorString方法转换。大小的话,有一个sizes对象根据"marker-size"属性查找,找不到就用默认的size。符号的话,如果properties里有"marker-symbol",就替换掉options里的symbol。 然后,处理canvasOrPromise变量。如果有symbol存在,判断其长度是否为1。如果是,调用fromText方法生成图标,否则用fromMakiIconId。这可能是因为单个字符可能是文字标记,而较长的符号可能是Maki图标库中的ID。如果没有symbol,就直接根据颜色和大小生成默认的图标。 接下来创建BillboardGraphics对象,设置verticalOrigin为底部对齐,这样图标的位置会以底部为基准。然后检查coordinates的长度是否为2(即二维坐标),且options.clampToGround为真,这样设置高度参考为CLAMP_TO_GROUND,让图标贴地显示。 然后通过createObject创建实体entity,可能将geoJson的属性和其他配置合进去。设置entity的billboard属性和position属性,position使用crsFunction转换坐标后的值。 最后处理promise,当canvasOrPromise解析成功时,设置billboard的image属性为生成的图像;如果失败,则使用默认颜色和大小的图标。将这个promise添加到dataSource的_promises数组中,可能是为了统一管理异步操作。 现在需要确认是否理解正确,比如crsFunction的作用是坐标转换,可能将输入的坐标转换为特定坐标参考系统下的值。dataSource可能是一个管理实体集合的对象,比如Cesium中的DataSource。BillboardGraphics是Cesium中的广告牌图元,用于显示图标。使用Promise来处理异步生成图标的过程,确保图像加载完成后再设置属性。 另外,检查是否有遗漏的部分,比如sizes对象的来源,可能在外部定义,根据不同的"marker-size"属性值(如'small', 'medium'等)对应不同的尺寸。createObject函数可能是用来创建实体属性的辅助函数,具体实现可能在其他地方。 总结一下,这个函数的作用是根据GeoJSON数据和配置选项,创建配置一个点实体的广告牌图标,处理样式覆盖和异步图标加载,最后将实体添加到数据源中。可能用于在Cesium等地图库中动态添加标记点。</think>这是一个用于创建地理空间点要素的JavaScript函数,主要功能是根据GeoJSON数据生成地图标记。以下是对其关键组成部分的分析: $$结构示意图\begin{cases} 参数解析 & \text{接收数据源、坐标等参数} \\ 样式处理 & \text{确定标记颜色/大小/符号} \\ 图标生成 & \text{创建Canvas图标或Maki图标} \\ 实体创建 & \text{构建地图广告牌元素} \\ 异步处理 & \text{管理图标加载过程} \end{cases}\end{cases}$$ **具体执行流程**: 1. **参数解析阶段** - 从`options`提取初始样式: ```javascript let symbol = options.markerSymbol; // 图标符号 let color = options.markerColor; // 基础颜色 let size = options.markerSize; // 默认尺寸 ``` 2. **样式覆盖机制** - 优先使用GeoJSON属性中的样式定义: ```javascript if (defined(properties)) { color = Color.fromCssColorString(properties["marker-color"]); size = sizes[properties["marker-size"]] || size; // 尺寸映射表查询 symbol = properties["marker-symbol"] || symbol; // 符号覆盖 } ``` 3. **图标生成逻辑** - 动态创建图标资源: ```javascript if (symbol?.length === 1) { canvasOrPromise = _pinBuilder.fromText(symbol, color, size); // 文字图标 } else if (symbol) { canvasOrPromise = _pinBuilder.fromMakiIconId(symbol, color, size); // Maki图标 } else { canvasOrPromise = _pinBuilder.fromColor(color, size); // 纯色圆形 } ``` 4. **实体构建过程** - 创建广告牌元素设置空间属性: ```javascript const billboard = new BillboardGraphics(); billboard.verticalOrigin = VerticalOrigin.BOTTOM; // 底部对齐 if (coordinates.length === 2 && options.clampToGround) { billboard.heightReference = HeightReference.CLAMP_TO_GROUND; // 贴地显示 } ``` 5. **异步加载处理** - 使用Promise链管理图标加载: ```javascript Promise.resolve(canvasOrPromise) .then(image => billboard.image = image) .catch(() => 生成备用图标); dataSource._promises.push(promise); // 统一管理异步任务 ``` **典型应用场景**: 该函数适用于地理信息系统(如CesiumJS)中动态加载点要素数据,支持样式自定义和异步资源加载。例如在地图上显示传感器位置时,可通过GeoJSON属性实时控制标记样式,同时确保图标加载失败时自动降级显示默认标记。 **扩展说明**: - 坐标转换函数`crsFunction`负责将原始坐标转换为目标坐标系 - `sizes`应为预定义的尺寸映射表(如:{ small: 24, medium: 36 }) - Maki图标库是Mapbox开源的矢量图标集合,包含常用地图标记 - 通过`clampToGround`参数可实现标记自动贴附地形表面 该实现体现了样式优先级的灵活控制(options < GeoJSON属性)和健壮的异步处理机制,适用于需要动态加载大量地理标记的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值