赞
踩
有部分用户在使用 Mars3D 加载大量label文本时,直到数据量越来越大,地图上的实体越来越多,首屏加载的时候经常会卡顿,客户那边的机器性能太差,有时候卡顿的同时还出现浏览器无响应问题。测试把这个问题归为BUG,要求必须解决~,下面我们来看具体的排查问题过程和解决方法。
让我们先来看下加载Label实体出现了什么问题?
- function addBillboardEntity(bsm, name, buildingType, position) {
- var graphic = new mars3d.graphic.BillboardEntity({
- id: bsm,
- name,
- position: position,
- style: {
- image: "img/marker/di3.png",
- width: 300,
- height: 140,
- pixelOffset: new Cesium.Cartesian2(90, -25), // 偏移量
- distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
- disableDepthTestDistance: 100.0,
- scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- label: {
- text: name,
- font_size: 40,
- scale: 0.5,
- color: "#ffffff",
- pixelOffsetX: 110,
- pixelOffsetY: -70,
- outlineColor: "#ffffff", // 边框颜色
- outlineWidth: 1, // 边框宽度
- background: true,
- backgroundColor: "rgba(255,124,125,0.5)",
- distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
- scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- },
- },
- attr: { poiType: "buildingPOI", name, buildingType, bsm, position },
- });
- graphicLayer.addGraphic(graphic);
- }
- 复制代码
当我需要创建400多个上面这样的实体时,页面总会卡顿一段时间。于是我上网查找相关资料,可能我表述有问题,一直没找到我想要的答案。所以我进行了浏览器DevTools。
在加载地图的时候,js执行了4.75秒,公司电脑配置如下:
性能不算差吧,继续看Performance分析:
这个getImageData怎么执行了2秒多,我当时想难道我传进去的图片Mars3D要做其他的处理?
于是我把BillboardEntity图标点对象改为直接用LabelEntity文本对象:
- function addLabelEntity(bsm, name, buildingType, position) {
- var graphic = new mars3d.graphic.LabelEntity({
- id: bsm,
- name,
- position: position,
- style: {
- text: name,
- font_size: 40,
- scale: 0.5,
- color: "#ffffff",
- pixelOffsetX: 110,
- pixelOffsetY: -70,
- outlineColor: "#ffffff", // 边框颜色
- outlineWidth: 1, // 边框宽度
- background: true,
- backgroundColor: "rgba(255,124,125,0.5)",
- distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
- scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- },
- attr: { poiType: "buildingPOI", name, buildingType, bsm, position },
- });
- graphicLayer.addGraphic(graphic);
- }
- 复制代码
少了20%的时间,但Mars3D
依然调了getImageData
,这就奇怪了?
难道这是Mars3D
在生成图片,已经用LabelEntity来渲染了,其他都是纯数据的。难道label不是文本?
带着这个问题,我把LabelEntity实体的style
属性也注释掉了。进行了一次Performance
:
getImageData
方法没有调用:
至此,我断定Mars3D
在创建含有label的entitie
时,会动态生成对应label.name值的图片。
找到问题,接下来就好办了,自己尝试构造这个label,不要用到Mars3D的Label
。原本项目中实体的BillboardEntity
是一张png
格式的底图。
思路: 使用Canvas绘制一张带有文本的图片,再将base64码给BillboardEntity
的style.image
参数
- //绘制图片:原来的图片+绘制的name的文字
- function createImage(name) {
- const canvas = document.createElement("canvas");
-
- const image = new Image();
- image.style.width = "400px";
- image.onload = () => {
- canvas.width = image.width;
- canvas.height = image.height;
-
- const ctx = canvas.getContext("2d");
- ctx.drawImage(image, 0, 0, image.width, image.height);
- ctx.font = "bold 20px Arial";
- ctx.textAlign = "center";
- ctx.textBaseline = "bottom";
- ctx.fillStyle = "#FFF";
- ctx.fillText(name, 220, 70);
- this.imageUrl = canvas.toDataURL("image/png");
- };
- image.src = "img/marker/di3.png";
-
- return image;
- }
- //创建图标对象
- function addBillboardEntity(bsm, name, buildingType, position) {
- var graphic = new mars3d.graphic.BillboardEntity({
- id: bsm,
- name,
- position: position,
- style: {
- image: createImage(name), //生成图片
- width: 300,
- height: 140,
- pixelOffset: new Cesium.Cartesian2(90, -25), // 偏移量
- distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 2000.0),
- disableDepthTestDistance: 100.0,
- scaleByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- translucencyByDistance: new Cesium.NearFarScalar(500, 1, 1400, 0.0),
- },
- attr: { poiType: "buildingPOI", name, buildingType, bsm, position },
- });
- graphicLayer.addGraphic(graphic);
- }
- 复制代码
再进行一次Performance
看看, 页面秒开了,没有卡顿:
标注也正常显示:
可以参考Mars3D功能示例的 CanvasBillboard.js 内的代码来理解Canvas的绘制与使用。
考虑到客户的电脑性能不好,每次开启页面都要动态生成几百张图片,也挺浪费性能的。那就做存储吧。
存后端Or前端? 由于这些点位信息是动态配置的,有专门的页面进行管理,所以这些文本和底图会有改变的可能。这种情况把图片存在后端只能手动去控制生成图片。
大量图片,体积是很大的,Storage
存不了这么多,只能放到WebSQL
或IndexedDB
,WebSQL
已经不维护了,那就放在IndexedDB
吧。
- // 项目入口文件中创建并连接IndexedDB
-
- const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
- DBOpenRequest.onupgradeneeded = (e) => {
- console.info('DB upgradeneeded')
- const db = e.target.result;
- if (!db.objectStoreNames.contains('buildingImage')) {
- db.createObjectStore('buildingImage', { keyPath: 'bsm' });
- }
- }
- DBOpenRequest.onsuccess = (e) => {
- console.info('DB链接成功')
- const db = e.target.result;
- Vue.prototype.$DB = db;
-
- new Vue({
- router,
- store,
- beforeDestroy() {
- DBOpenRequest.result.close();
- },
- render: h => h(App)
- }).$mount('#app');
- }
- DBOpenRequest.onerror = (e) => {
- console.ERROR('Can not open indexedDB', e);
-
- new Vue({
- router,
- store,
- beforeDestroy() {
- DBOpenRequest.result.close();
- },
- render: h => h(AppWith404)
- }).$mount('#app');
- };
- 复制代码
最后: 在添加BillboardEntity
的时候先查询库里对应的bsm存不存在,若存在,判断各类信息是否一致,一致的话使用存储的base64图片作为BillboardEntity
的image
;若不存在或者各类信息不一致,重新生成图片并存入库,再作为BillboardEntity
的image
。
至此,Mars3D加载大量Label实体时卡顿的问题基本解决,进入页面也能达到秒开的速度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。