当前位置:   article > 正文

Mars3D加载大量Label实体时卡顿的一种解决方法_new mars3d.graphic.billboardentity

new mars3d.graphic.billboardentity

前言

 有部分用户在使用 Mars3D 加载大量label文本时,直到数据量越来越大,地图上的实体越来越多,首屏加载的时候经常会卡顿,客户那边的机器性能太差,有时候卡顿的同时还出现浏览器无响应问题。测试把这个问题归为BUG,要求必须解决~,下面我们来看具体的排查问题过程和解决方法。

加载成百上千实体时出现的问题

让我们先来看下加载Label实体出现了什么问题?

  1. function addBillboardEntity(bsm, name, buildingType, position) {
  2. var graphic = new mars3d.graphic.BillboardEntity({
  3. id: bsm,
  4. name,
  5. position: position,
  6. style: {
  7. image: "img/marker/di3.png",
  8. width: 300,
  9. height: 140,
  10. pixelOffset: new Cesium.Cartesian2(90, -25), // 偏移量
  11. distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
  12. disableDepthTestDistance: 100.0,
  13. scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  14. translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  15. label: {
  16. text: name,
  17. font_size: 40,
  18. scale: 0.5,
  19. color: "#ffffff",
  20. pixelOffsetX: 110,
  21. pixelOffsetY: -70,
  22. outlineColor: "#ffffff", // 边框颜色
  23. outlineWidth: 1, // 边框宽度
  24. background: true,
  25. backgroundColor: "rgba(255,124,125,0.5)",
  26. distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
  27. scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  28. translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  29. },
  30. },
  31. attr: { poiType: "buildingPOI", name, buildingType, bsm, position },
  32. });
  33. graphicLayer.addGraphic(graphic);
  34. }
  35. 复制代码

当我需要创建400多个上面这样的实体时,页面总会卡顿一段时间。于是我上网查找相关资料,可能我表述有问题,一直没找到我想要的答案。所以我进行了浏览器DevTools

pic_b2681676.png

在加载地图的时候,js执行了4.75秒,公司电脑配置如下:

pic_7648b1cf.png

性能不算差吧,继续看Performance分析:

pic_c23aff20.png

这个getImageData怎么执行了2秒多,我当时想难道我传进去的图片Mars3D要做其他的处理?

于是我把BillboardEntity图标点对象改为直接用LabelEntity文本对象:

  1. function addLabelEntity(bsm, name, buildingType, position) {
  2. var graphic = new mars3d.graphic.LabelEntity({
  3. id: bsm,
  4. name,
  5. position: position,
  6. style: {
  7. text: name,
  8. font_size: 40,
  9. scale: 0.5,
  10. color: "#ffffff",
  11. pixelOffsetX: 110,
  12. pixelOffsetY: -70,
  13. outlineColor: "#ffffff", // 边框颜色
  14. outlineWidth: 1, // 边框宽度
  15. background: true,
  16. backgroundColor: "rgba(255,124,125,0.5)",
  17. distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
  18. scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  19. translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  20. },
  21. attr: { poiType: "buildingPOI", name, buildingType, bsm, position },
  22. });
  23. graphicLayer.addGraphic(graphic);
  24. }
  25. 复制代码

pic_3659fbb3.png

少了20%的时间,但Mars3D依然调了getImageData,这就奇怪了?

难道这是Mars3D在生成图片,已经用LabelEntity来渲染了,其他都是纯数据的。难道label不是文本?

带着这个问题,我把LabelEntity实体的style属性也注释掉了。进行了一次Performance

pic_756462ec.png

getImageData方法没有调用:

pic_1a5ccdd5.png

至此,我断定Mars3D在创建含有label的entitie时,会动态生成对应label.name值的图片。

解决方案:自行动态生成图片

找到问题,接下来就好办了,自己尝试构造这个label,不要用到Mars3D的Label。原本项目中实体的BillboardEntity是一张png格式的底图。

pic_588c6b1f.png

思路: 使用Canvas绘制一张带有文本的图片,再将base64码给BillboardEntitystyle.image参数

  1. //绘制图片:原来的图片+绘制的name的文字
  2. function createImage(name) {
  3. const canvas = document.createElement("canvas");
  4. const image = new Image();
  5. image.style.width = "400px";
  6. image.onload = () => {
  7. canvas.width = image.width;
  8. canvas.height = image.height;
  9. const ctx = canvas.getContext("2d");
  10. ctx.drawImage(image, 0, 0, image.width, image.height);
  11. ctx.font = "bold 20px Arial";
  12. ctx.textAlign = "center";
  13. ctx.textBaseline = "bottom";
  14. ctx.fillStyle = "#FFF";
  15. ctx.fillText(name, 220, 70);
  16. this.imageUrl = canvas.toDataURL("image/png");
  17. };
  18. image.src = "img/marker/di3.png";
  19. return image;
  20. }
  21. //创建图标对象
  22. function addBillboardEntity(bsm, name, buildingType, position) {
  23. var graphic = new mars3d.graphic.BillboardEntity({
  24. id: bsm,
  25. name,
  26. position: position,
  27. style: {
  28. image: createImage(name), //生成图片
  29. width: 300,
  30. height: 140,
  31. pixelOffset: new Cesium.Cartesian2(90, -25), // 偏移量
  32. distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
  33. disableDepthTestDistance: 100.0,
  34. scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  35. translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
  36. },
  37. attr: { poiType: "buildingPOI", name, buildingType, bsm, position },
  38. });
  39. graphicLayer.addGraphic(graphic);
  40. }
  41. 复制代码

再进行一次Performance看看, 页面秒开了,没有卡顿:

pic_0f69adf6.png

标注也正常显示:

pic_06a0fd2e.png

可以参考Mars3D功能示例的 CanvasBillboard.js 内的代码来理解Canvas的绘制与使用。

新的问题: 加入客户端缓存处理

考虑到客户的电脑性能不好,每次开启页面都要动态生成几百张图片,也挺浪费性能的。那就做存储吧。

存后端Or前端? 由于这些点位信息是动态配置的,有专门的页面进行管理,所以这些文本和底图会有改变的可能。这种情况把图片存在后端只能手动去控制生成图片。

IndexedDB存储

大量图片,体积是很大的,Storage存不了这么多,只能放到WebSQLIndexedDB,WebSQL已经不维护了,那就放在IndexedDB吧。

  1. // 项目入口文件中创建并连接IndexedDB
  2. const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
  3. DBOpenRequest.onupgradeneeded = (e) => {
  4. console.info('DB upgradeneeded')
  5. const db = e.target.result;
  6. if (!db.objectStoreNames.contains('buildingImage')) {
  7. db.createObjectStore('buildingImage', { keyPath: 'bsm' });
  8. }
  9. }
  10. DBOpenRequest.onsuccess = (e) => {
  11. console.info('DB链接成功')
  12. const db = e.target.result;
  13. Vue.prototype.$DB = db;
  14. new Vue({
  15. router,
  16. store,
  17. beforeDestroy() {
  18. DBOpenRequest.result.close();
  19. },
  20. render: h => h(App)
  21. }).$mount('#app');
  22. }
  23. DBOpenRequest.onerror = (e) => {
  24. console.ERROR('Can not open indexedDB', e);
  25. new Vue({
  26. router,
  27. store,
  28. beforeDestroy() {
  29. DBOpenRequest.result.close();
  30. },
  31. render: h => h(AppWith404)
  32. }).$mount('#app');
  33. };
  34. 复制代码

最后: 在添加BillboardEntity的时候先查询库里对应的bsm存不存在,若存在,判断各类信息是否一致,一致的话使用存储的base64图片作为BillboardEntityimage;若不存在或者各类信息不一致,重新生成图片并存入库,再作为BillboardEntityimage

结语

至此,Mars3D加载大量Label实体时卡顿的问题基本解决,进入页面也能达到秒开的速度。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/687542
推荐阅读
  

闽ICP备14008679号