Optimice el volumen de datos de la cartelera (cartelera) de la interfaz de cesio es superior a 10w +, el mapa se carga lentamente, se congela y el navegador se congela o incluso falla después de cargar

Optimice el volumen de datos de la cartelera (cartelera) de la interfaz de cesio es superior a 10w +, el mapa se carga lentamente, se congela y el navegador se congela o incluso falla después de cargar

Prefacio:

En el diseño anterior del proyecto, la valla publicitaria estaba vinculada a la colección de colección de entidades. Para obtener más información de datos al obtener una sola entidad (entidad) (la entidad puede inyectar información de atributos distintos de sus propios atributos), se agrega la colección de colección de
entidades Con la función de agregación de clústeres, el punto crítico del volumen de datos es de aproximadamente 3w ~ 4w y la interfaz se congelará. Los fps están por debajo de 20 y fluctúan mucho, la latencia se mantiene en torno a los 100 ms. Cuando la cantidad de datos está por debajo del punto crítico, la forma en que la entidad presenta la página sigue siendo relativamente buena.
Cuando la cantidad de datos es superior a 10w+, los fps son básicamente 0-5 y el retraso es superior a 200 ms. Al cargar datos, el retraso puede aumentar directamente en varios miles. Al mismo tiempo, una gran cantidad de datos (de entidadCollection) hace que el navegador se bloquee directamente y no se cargue.

Solución (colección de primitivas de primitivas)

Nota:

He probado muchos métodos de optimización, dejando de lado la optimización del procesamiento de transferencia de datos de la interfaz en segundo plano, solo para todos los métodos de optimización de la interfaz de cesio frontal, el registro que encontré tiene el mejor efecto y la optimización con la menor sobrecarga al conectar otros. funciones que se han completado en el método siguiente.
Este método también es adecuado para mostrar una gran cantidad de pointPrimitiveCollection (colección de puntos) y labelCollection (colección de etiquetas) en la interfaz
.

dirección de referencia

Vaya al sitio web oficial documentación de primitivas colección de primitivas

Ir al sitio web oficial de ejemplos relacionados.

Vaya al blog de referencia de clústeres primitivos de implementación primitivaCluster

Método de optimización: combine la colección primitiva primitivaCollection y el grupo primitivo primitivoCluster para optimizar la visualización de vallas publicitarias

En ausencia de la necesidad de la función de clústeres de agregación, solo el uso deprimitiveCollection puede resolver perfectamente los problemas de congelaciones y fallas de la interfaz causadas por vallas publicitarias 10w+. La recomendación es no agregar un clúster primitivo primitivoCluster para manejar la optimización cuando no es necesaria la agregación. Porque en el método de agregación, el evento de cambio de la cámara se monitoreará para cambiar el estado de la cantidad de agregación en cualquier momento, pero habrá una situación de congelación. ¡Según las necesidades del proyecto, agregue la función de agregación! Para congelar la agregación, realicé un proceso de optimización agregando un temporizador y lo publicaré a continuación.

colección primitiva colección primitiva

Ejemplo de uso de colección primitiva

Código de adición de colección de vallas publicitarias (como se muestra a continuación), otras colecciones como puntos, etiquetas y documentos oficiales son similares

const billboardCollection = viewer.scene.primitives.add(
  new Cesium.BillboardCollection()
);

billboardCollection.add({
    
    
  position: Cesium.Cartesian3.fromDegrees(114.49, 41.23, 0),
  width: 38,
  height: 38,
  image: "xxxxx"
});

En este momento, la valla publicitaria agregada a billboardCollection se mostrará directamente en la interfaz y puede manejar fácilmente un volumen de datos de más de 100.000. En comparación con el método de suma anterior (como se muestra a continuación), el efecto es obvio

// 之前的添加方式
const entityCollection = new Cesium.EntityCollection();

const billboard = new Cesium.BillboardGraphics({
    
    
  width: 38,
  height: 38,
  image: "xxxxx"
});
const entity = new Cesium.Entity({
    
    
  position: Cesium.Cartesian3.fromDegrees(114.49, 41.23, 0),
  billboard: billboard,
  s1: "xxx",
  s2: "xxx",
  s3: "xxx",
  s4: "xxx",
  s5: "xxx"
});
entityCollection.add(entity);

Si solo necesita optimizar la gran cantidad de datos que hacen que la interfaz se congele y falle, no necesita implementar la función de agregación, y ahora está completamente bien.

grupo primitivo de colección primitiva

La función de agregación de primitiveCollection no la proporciona el funcionario nativo, y solo se proporciona el método EntityCluster en el documento oficial para realizar operaciones de agregación en la colección de entidadCollection. La agregación a través del método EntityCluster debe usarse con el objeto de fuente de datos, porque el objeto de fuente de datos nativo en sí tiene un atributo de agrupación (el blog de agregación de EntityCluster que escribí antes del salto ).
Dado que utilizamos directamente la forma primitiva para agregar vallas publicitarias al mapa, nos saltamos el paso de la fuente de datos. Por lo tanto, necesitamos definir un método PrimitiveCluster para crear un objeto de clúster, agregar la colección primitiva y combinar los métodos proporcionados por otros documentos de blogger. Los métodos de implementación específicos de PrimitiveCluster.js se resumen a continuación

Agregue el método PrimitiveCluster al archivo del paquete de cesio o al archivo de dependencia

1. Ruta agregada:

1: En el paquete npm ----- node_modules\cesium\Source\DataSources\PrimitiveCluster.js
2: Importando archivos externos ---- Source\DataSources\PrimitiveCluster.js

2. Copie el contenido de EntityCluster.js en el mismo directorio a PrimitiveCluster.js

3. Modifique globalmente el nombre en el archivo, EntityCluster -> PrimitiveCluster, entidadCluster -> primitivoCluster

4. Proteja el bloque de código en el método getScreenSpacePositions aproximadamente en la línea 191 (item.id en EntityCluster apunta al objeto de entidad de entidad, y item.id en primitiveCollection no está definido, lo que provocará errores)

/* var canClusterLabels =
  primitiveCluster._clusterLabels && defined(item._labelCollection);
var canClusterBillboards =
  primitiveCluster._clusterBillboards && defined(item.id._billboard);
var canClusterPoints =
  primitiveCluster._clusterPoints && defined(item.id._point);
if (canClusterLabels && (canClusterPoints || canClusterBillboards)) {
  continue;
} */

En el paso 4, si su empresa necesita agregar una identificación de identificación única al cartel al agregar el cartel (como se muestra a continuación), no necesita bloquear el código fuente y la identificación agregada puede evitar informar errores aquí.

billboardCollection.add({
    
    
  id: "xxx",
  position: Cesium.Cartesian3.fromDegrees(114.49, 41.23, 0),
  width: 38,
  height: 38,
  image: "xxxxx"
});

5. Busque el archivo de entrada cesium.js en el directorio principal de PrimitiveCluster.js (node_modules\cesium\Source\Cesium.js) e importe el método PrimitiveCluster.

export {
    
     default as PrimitiveCluster } from "./DataSources/PrimitiveCluster.js";

Hasta ahora, se ha agregado el método PrimitiveCluster y se puede llamar directamente a través del nuevo Cesium.PrimitiveCluster()

Métodos PrimitiveCluster para implementar la agregación

1. Agregue un conjunto de primitivas utilizadas como 'raíz' a scene.primitives

2. Cree una colección de vallas publicitarias BillboardCollection vacía.

3. Cree un objeto de instancia de clústerprimitivoCluster mediante el método PrimitiveCluster

4. Agregue primitivosCluster a las primitivas de la colección de primitivas.

5. Configure los parámetros básicos del objeto primitivoCluster (los parámetros predeterminados se pueden proporcionar sin configuración)

6. (Importante*) Asigne una colección de vallas publicitarias billboardCollection vacía a primitiveCluster._billboardCollection y agregue manualmente contenido de agregación.

Para mencionar: los conjuntos de etiquetas y puntos se agregan de la misma manera

primitiveCluster._labelCollection;
primitiveCluster._pointCollection;

7. (Importante*) Llame al método _initialize para inicializar el detector de eventos de la instancia del clúster.

8. Después de eso, será coherente con el método .then del método de agregación de fuente de datos, solo es necesario reemplazar dataSource.clustering.clusterEvent.addEventListener con primitiveCluster.clusterEvent.addEventListener

como sigue:

const primitives = viewer.scene.primitives.add(
  new Cesium.PrimitiveCollection()
);
const billboardCollection = new Cesium.BillboardCollection();

const primitiveCluster = new Cesium.PrimitiveCluster();
primitives.add(primitiveCluster);
primitiveCluster.enabled = true; //开启聚合功能
primitiveCluster.pixelRange = 15; //范围
primitiveCluster.minimumClusterSize = 2; //最小聚合数量
primitiveCluster._billboardCollection = billboardCollection;
primitiveCluster._initialize(viewer.scene);

primitiveCluster.clusterEvent.addEventListener(function(
  clusteredEntities,
  cluster
) {
    
    
  // ... 处理聚合显示广告牌代码块与dataSource处理方式一致
});

Una vez completada la agregación de la manera anterior, agregar vallas publicitarias a la colección billboardCollection se mostrará en la página y se agregará. Sin embargo, cuando la cantidad de datos es de 10w+, habrá un problema de retraso al procesar el evento de monitoreo del cambio del ángulo de visión de la cámara. Aquí hay un método de optimización simple.

Optimice el problema de retraso de PrimitiveCluster

En el método _initialize de PrimitiveCluster.js, puede ver que el método original usa el método createDeclutterCallback para crear un método de devolución de llamada y agregar este método de devolución de llamada al oyente scene.camera.changed. Por lo tanto, siempre que cambie el ángulo de visión de scene.camera, se ejecutará el método lógico de procesamiento de agregación y se devolverán los dos parámetros clusteredEntities y cluster.

primitiveCluster.clusterEvent.addEventListener(function(
  clusteredEntities,
  cluster
) {
    
    
  // ... 处理聚合显示广告牌代码块与dataSource处理方式一致
});

Por lo tanto, solo necesita agregar un temporizador antivibración en el método _initialize para reducir la frecuencia de procesamiento de eventos y lograr el efecto de optimización. Al mismo tiempo, el parámetro de tiempo de retardo está expuesto y se puede configurar después de la creación de instancias.

//1.PrimitiveCluster构造函数中添加_delay参数
this._delay = defaultValue(options.delay, 800)

//2.在PrimitiveCluster.prototype拦截器Object.defineProperties方法中添加_delay的访问以及设置方法
delay: {
    
    
  get: function () {
    
    
    return this._delay;
  },
  set: function (value) {
    
    
    this._delay = value;
  },
},

// 3._initialize方法改造
PrimitiveCluster.prototype._initialize = function(scene) {
    
    
  this._scene = scene;
  var cluster = createDeclutterCallback(this);
  this._cluster = cluster;
  var _t = null;
  const _self = this;
  this._removeEventListener = scene.camera.changed.addEventListener(function(amount) {
    
    
    if (_t) {
    
    
      clearTimeout(_t);
      _t = null;
    }
    _t = setTimeout(() => {
    
    
      cluster(amount);
    }, _self._delay);
  });
};

Hasta ahora, el contenido anterior trata sobre el método para optimizar el problema de la carga lenta de la cartelera de la interfaz de cesio (cartelera) cuando el volumen de datos es superior a 10w +, el mapa se congela y el navegador se congela severamente después de la carga. se publica a continuación.

registro de código de función

import * as Cesium from "cesium/Cesium";
import defaultValue from "./core/defaultValue";

/**
 * @_v 引入外部创建的Viewer实例(new Cesium.Viewer(...))
 * @myPrimitives 原语集合,可以包含页面显示的pointPrimitiveCollection、billboardCollection、labelCollection、primitiveCollection、primitiveCluster
 * @myPrimitiveCluster 自定义原语集群
 * @myBillboardCollection 广告牌集合(站点显示的内容数据)
 *
 * @desc 使用primitiveCollection原语集合与primitiveCluster原语集群,处理地图界面显示广告牌billboard数量 > 10w 级时,界面卡顿,浏览器崩溃等问题
 */
class CommomSiteTookit {
    
    
  static _v = null;
  myPrimitives = null;
  myPrimitiveCluster = null;
  myBillboardCollection = null;

  constructor() {
    
    }

  /**
   * @desc 使用commomSiteTookit实例前,必须先初始化该实例的_v对象
   */
  init(viewer) {
    
    
    this._v = viewer;
  }

  /**
   * @param [options] 具有以下属性的对象
   * @param [options.delay=800] 防抖处理定时器的time
   * @param [options.enabled=true] 是否启用集群
   * @param [options.pixelRange=15] 用于扩展屏幕空间包围框的像素范围
   * @param [options.minimumClusterSize=2] 可集群的屏幕空间对象的最小数量
   *
   * @desc 处理原语集合,并实现聚合集群功能方法
   * @return billboardCollection集合,可直接往集合里添加广告牌billboard,呈现在页面上
   */
  load(options = {
     
     }) {
    
    
    let billboardCollection = new Cesium.BillboardCollection();

    if (Cesium.defined(this.myPrimitives)) {
    
    
      this._v.scene.primitives.remove(this.myPrimitives);
    }
    this.myPrimitives = this._v.scene.primitives.add(
      new Cesium.PrimitiveCollection()
    );

    const primitiveCluster = new Cesium.PrimitiveCluster();
    this.myPrimitives.add(primitiveCluster);
    primitiveCluster.delay = defaultValue(options.delay, 800);
    primitiveCluster.enabled = defaultValue(options.enabled, true);
    primitiveCluster.pixelRange = defaultValue(options.pixelRange, 15);
    primitiveCluster.minimumClusterSize = defaultValue(
      options.minimumClusterSize,
      2
    );
    primitiveCluster._billboardCollection = billboardCollection;
    primitiveCluster._initialize(this._v.scene);

    let removeListener;
    let pinBuilder = new Cesium.PinBuilder();
    /* 定义广告牌 fromText(显示文字,颜色,大小) */
    let pin50 = pinBuilder.fromText("50+", Cesium.Color.RED, 40).toDataURL();
    let pin40 = pinBuilder.fromText("40+", Cesium.Color.ORANGE, 40).toDataURL();
    let pin30 = pinBuilder.fromText("30+", Cesium.Color.YELLOW, 40).toDataURL();
    let pin20 = pinBuilder.fromText("20+", Cesium.Color.GREEN, 40).toDataURL();
    let pin10 = pinBuilder.fromText("10+", Cesium.Color.BLUE, 40).toDataURL();
    /* 数量小于十个的聚合广告牌 */
    let singleDigitPins = new Array(8);
    for (let i = 0; i < singleDigitPins.length; ++i) {
    
    
      singleDigitPins[i] = pinBuilder
        .fromText("" + (i + 2), Cesium.Color.VIOLET, 40)
        .toDataURL();
    }

    const _ = this;
    function customStyle() {
    
    
      if (Cesium.defined(removeListener)) {
    
    
        removeListener();
        removeListener = undefined;
      } else {
    
    
        removeListener = primitiveCluster.clusterEvent.addEventListener(
          function(clusteredEntities, cluster) {
    
    
            cluster.label.show = false;
            cluster.billboard.show = true;
            cluster.billboard.id = cluster.label.id;
            cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
            /* 根据站点(参数)的数量给予对应的广告牌  */
            if (clusteredEntities.length >= 50) {
    
    
              cluster.billboard.image = pin50;
            } else if (clusteredEntities.length >= 40) {
    
    
              cluster.billboard.image = pin40;
            } else if (clusteredEntities.length >= 30) {
    
    
              cluster.billboard.image = pin30;
            } else if (clusteredEntities.length >= 20) {
    
    
              cluster.billboard.image = pin20;
            } else if (clusteredEntities.length >= 10) {
    
    
              cluster.billboard.image = pin10;
            } else {
    
    
              cluster.billboard.image =
                singleDigitPins[clusteredEntities.length - 2];
            }
          }
        );
      }
      // force a re-cluster with the new styling
      let pixelRange = primitiveCluster.pixelRange;
      primitiveCluster.pixelRange = 0;
      primitiveCluster.pixelRange = pixelRange;
      _.myPrimitiveCluster = primitiveCluster;
    }
    this.myBillboardCollection = billboardCollection;
    // start with custom style
    customStyle();
    return billboardCollection;
  }

  /**
   * @params enable bool值控制开启或关闭集群
   * @desc 控制集群生效与否
   */
  enableCluster(enable) {
    
    
    if (Cesium.defined(this.myPrimitiveCluster)) {
    
    
      this.myPrimitiveCluster.enabled = enable;
    }
  }

  /**
   * @params id 站点ID
   * @return 返回可操作的广告牌[siteBillboard.image = 'xxxx']
   * @desc 根据id在集合中获取指定站点广告牌
   */
  getSiteBillboardById(id) {
    
    
    if (!Cesium.defined(this.myBillboardCollection)) return undefined;
    const _b = this.myBillboardCollection;
    const l = _b.length;
    let siteBillboard = undefined;
    for (let i = 0; i < l; i++) {
    
    
      if (id == _b.get(i).id) {
    
    
        siteBillboard = _b.get(i);
        break;
      }
    }
    return siteBillboard;
  }

  /**
   * @desc 删除所有站点广告牌
   */
  removeAll() {
    
    
    if (Cesium.defined(this.myPrimitives)) {
    
    
      this._v.scene.primitives.remove(this.myPrimitives);
    }
  }

  /**
   * @params show bool值 控制显示或隐藏
   * @desc 隐藏或显示所有站点广告牌
   */
  showStatus(show = true) {
    
    
    this.myPrimitives.show = show;
  }

  /**
   * @desc 根据id删除指定站点广告牌
   */
  remove(id) {
    
    
    const billboard = this.getSiteBillboardById(id);
    billboard && this.myBillboardCollection.remove(billboard);
  }

  /**
   * @desc 销毁(目前退出页面时直接viewer销毁)
   */
  destroy() {
    
    
    this.myPrimitives = null;
    this.myPrimitiveCluster = null;
    this.myBillboardCollection = null;
    // this._v.scene.primitives.destroy()
  }
}

export default new CommomSiteTookit();

Después de ejecutar commomSiteTookit.init (visor), la operación principal de carga de datos está en el método de carga. La billboardCollection devuelta por la carga puede agregar dinámicamente datos de vallas publicitarias y presentarlos directamente en la interfaz. El código es el siguiente.

const list = ['10w+数据']
const l = list.length
const data = commomSiteTookit.load({
    
    
  enabled: true,
  delay: 1200,
  pixelRange: 20
});
for (let i = 0; i < l; i++) {
    
    
  data.add({
    
    
    image: `xxxx`,
    scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1, 1.5e7, 0.2),
    width: 38, // default: undefined
    height: 38, // default: undefined
    position: Cesium.Cartesian3.fromDegrees(
      list[i].longitude,
      list[i].latitude,
      0
    ),
    id: list[i].id + ""
  });
}

Supongo que te gusta

Origin blog.csdn.net/weixin_42508580/article/details/126927483
Recomendado
Clasificación