详解cesium实现大批量POI点位聚合渲染优化方案

 更新时间:2023年05月05日 15:26:27   作者:不浪brown  
这篇文章主要为大家介绍了cesium实现大批量POI点位聚合渲染优化方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

cesium目前只提供了entityCluster这个聚合类,使打点聚合更方便快捷的实现,但是一般在真正做项目的时候,大家会经常碰到成千上万个甚至几十万个点位需要聚合打点,那这时候你如果还是用entity去实现的话,怕是要被用户按在地上疯狂摩擦,摩擦。。。😅

思考

我们可以通过模拟entityCluster这个类的实现方式,利用源码中的算法,改成primitive的实现方式;

开发

拉下cesium的源码,搜EntityCluster关键字,我们可以找到EntityCluster.js这个文件,那么这个代码就是实现聚合的核心逻辑,接下来我们可以复制一份出来,将EntityCluster全部改为PrimitiveCluster,接着getScreenSpacePositions这个方法里将entity的逻辑删除,否则会因为item.id为entity对象为空导致报错

function getScreenSpacePositions(
  collection,
  points,
  scene,
  occluder,
  entityCluster
) {
  if (!defined(collection)) {
    return;
  }
  const length = collection.length;
  for (let i = 0; i < length; ++i) {
    const item = collection.get(i);
    item.clusterShow = false;
    if (
      !item.show ||
      (entityCluster._scene.mode === SceneMode.SCENE3D &&
        !occluder.isPointVisible(item.position))
    ) {
      continue;
    }
    // const canClusterLabels =
    //   entityCluster._clusterLabels && defined(item._labelCollection);
    // const canClusterBillboards =
    //   entityCluster._clusterBillboards && defined(item.id._billboard);
    // const canClusterPoints =
    //   entityCluster._clusterPoints && defined(item.id._point);
    // if (canClusterLabels && (canClusterPoints || canClusterBillboards)) {
    //   continue;
    // }
    const coord = item.computeScreenSpacePosition(scene);
    if (!defined(coord)) {
      continue;
    }
    points.push({
      index: i,
      collection: collection,
      clustered: false,
      coord: coord,
    });
  }
}

好了,源码大体就是改这么多了,接下来就是怎么用;

使用

import PrimitiveCluster from "@/utils/cesiumCtrl/primitiveCluster";
// 初始化标签实例
const billboardsCollectionCombine = new Cesium.BillboardCollection();
// 初始化实体
const primitives = viewer.scene.primitives.add(
  new Cesium.PrimitiveCollection()
);
getGeojson("/json/schools.geojson").then(({ res }) => {
    // 先获取点位数据
    console.log(res);
    const { features } = res;
    formatClusterPoint(features);
  });
// 整理聚合数据
const formatClusterPoint = (features) => {
  var scene = viewer.scene;
  var primitivecluster = new PrimitiveCluster();
  //与entitycluster相同设置其是否聚合 以及最大最小值
  primitivecluster.enabled = true;
  primitivecluster.pixelRange = 60;
  primitivecluster.minimumClusterSize = 2;
  // primitivecluster._pointCollection = pointCollection;
  // primitivecluster._labelCollection = labelCollection;
  for (let i = 0; i < features.length; i++) {
    const feature = features[i];
    const coordinates = feature.geometry.coordinates;
    const position = Cesium.Cartesian3.fromDegrees(
      coordinates[0],
      coordinates[1]
    );
    // 带图片的点
    billboardsCollectionCombine.add({
      image: "/images/mark-icon.png",
      width: 32,
      height: 32,
      position,
    });
  }
  // 将数据传给primitivecluster的标签属性
  primitivecluster._billboardCollection = billboardsCollectionCombine;
  // 初始化
  primitivecluster._initialize(scene);
  // 将标签数据添加到实体中
  primitives.add(primitivecluster);
  // 监听相机缩放
  primitivecluster.clusterEvent.addEventListener(
    (clusteredEntities, cluster) => {
      // 关闭自带的显示聚合数量的标签
      cluster.label.show = false;
      cluster.billboard.show = true;
      cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
      // 根据聚合数量的多少设置不同层级的图片以及大小
      cluster.billboard.image = combineIconAndLabel(
        "/images/school-icon.png",
        clusteredEntities.length,
        64
      );
      // cluster.billboard.image = "/images/school-icon.png";
      cluster.billboard._imageHeight = 60;
      cluster.billboard._imageWidth = 60;
      cluster.billboard._dirty = false;
      cluster.billboard.width = 40;
      cluster.billboard.height = 40;
    }
  );
  return primitivecluster;
};
/**
 * @description: 将图片和文字合成新图标使用(参考Cesium源码)
 * @param {*} url:图片地址
 * @param {*} label:文字
 * @param {*} size:画布大小
 * @return {*} 返回canvas
 */
function combineIconAndLabel(url, label, size) {
  // 创建画布对象
  let canvas = document.createElement("canvas");
  canvas.width = size;
  canvas.height = size;
  let ctx = canvas.getContext("2d");
  let promise = new Cesium.Resource.fetchImage(url).then((image) => {
    // 异常判断
    try {
      ctx.drawImage(image, 0, 0);
    } catch (e) {
      console.log(e);
    }
    // 渲染字体
    // font属性设置顺序:font-style, font-variant, font-weight, font-size, line-height, font-family
    ctx.fillStyle = Cesium.Color.BLACK.toCssColorString();
    ctx.font = "bold 20px Microsoft YaHei";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillText(label, size / 2, size / 2);
    return canvas;
  });
  return promise;
}

ok,以上就是完整的使用方法,主要是如何使用,不然会造成canvas相关方面的报错等等;

详细源码细节可以查看:github.com/tingyuxuan2… ,此开源项目集合了目前常用的一些三维动画场景,还在不断更新中;

以上就是详解cesium实现大批量POI点位聚合渲染优化方案的详细内容,更多关于cesium大批量POI点位聚合渲染的资料请关注脚本之家其它相关文章!

相关文章

  • RxJS中四种Subject的用法和区别

    RxJS中四种Subject的用法和区别

    RxJS中有四种不同类型的Subject,它们分别是Subject、BehaviorSubject、ReplaySubject和AsyncSubject,本文将介绍这四种Subject的用法、区别以及适用的应用场景,并提供代码示例,需要的朋友可以参考下
    2023-07-07
  • JavaScript常用语句循环,判断,字符串换数字

    JavaScript常用语句循环,判断,字符串换数字

    这篇文章主要介绍了JavaScript常用语句主要包括对循环,判断,字符串换数字相关资料的介绍,具有一定的参考价值,需要的小伙伴可以参考一下具体内容
    2021-12-12
  • JavaScript Array实例方法flat的实现

    JavaScript Array实例方法flat的实现

    flat() 方法用于将一个嵌套多层的数组进行扁平,返回新数组,它不会改变原始数组, flat 方法在处理多维数组时非常有用,它可以让数组操作变得更加灵活和简洁,本文给大家介绍了JavaScript Array实例方法flat的实现,需要的朋友可以参考下
    2024-03-03
  • swiper动态改变滑动内容的实现方法

    swiper动态改变滑动内容的实现方法

    假设当前显示的是1,往左滑动一个递减1,往右滑动一个递增1。下面通过实例代码给大家讲解swiper动态改变滑动内容的实现方法,感兴趣的朋友一起看看吧
    2018-01-01
  • 你必须知道的Javascript知识点之"单线程事件驱动"的使用

    你必须知道的Javascript知识点之"单线程事件驱动"的使用

    本篇文章小编为大家介绍,你必须知道的Javascript知识点之"单线程事件驱动"的使用。需要的朋友参考下
    2013-04-04
  • JS实现的相册图片左右滚动完整实例

    JS实现的相册图片左右滚动完整实例

    这篇文章主要介绍了JS实现的相册图片左右滚动效果,结合完整实例形式分析了javascript事件触发与页面元素属性动态变换的相关操作技巧,需要的朋友可以参考下
    2016-11-11
  • Electron autoUpdater实现Windows安装包自动更新的方法

    Electron autoUpdater实现Windows安装包自动更新的方法

    这篇文章主要介绍了Electron autoUpdater实现Windows安装包自动更新的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • 详解a++和++a的区别

    详解a++和++a的区别

    搞开发已经很久了,一直搞不懂a++和++a到底有所什么不同,后来通过查阅相关资料总结出一点规律,下面小编通过本文给大家介绍
    2017-08-08
  • KnockoutJs快速入门教程

    KnockoutJs快速入门教程

    这篇文章主要为大家分享了KnockoutJs快速入门教程,了解KnockoutJs到底是什么?如何使用KnockoutJS中的data-bind语法来将模型数据绑定到DOM元素中,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • javascript DOM对象的学习实例代码

    javascript DOM对象的学习实例代码

    javascript DOM对象的学习实例代码
    2009-06-06

最新评论