百度地图中。上万级别数据打点渲染图标的方式

1. 本体js文件内容

export const getRandom = () => {
  const crypto = window.crypto || window.msCrypto;
  const array = new Uint32Array(1);
  return crypto.getRandomValues(array)[0];
};

// 缩放级别
const getZoom = function(){
  // 获取当前屏幕的缩放比例
  let zoom = document.body.style.zoom * 1;
  if( isNaN(zoom) || zoom === 0 ){
    zoom = 1;
  }
  return [ zoom, zoom ];
}

export class MapCanvasLayer {
  // 数据集
  datas = [];

  // 地图对象
  _map = null;

  // 显示的canvas
  canvas = null;

  id = parseInt(getRandom() * 1000, 10);

  events = [];

  // 缩放比例
  zoom = [1, 1];

  // 过滤数据
  renderFilter = (data) => data;

  constructor() {
    this.zoom = getZoom();

    // 创建矩阵驱动器
    this.matrixDrive = new MatrixDrive();

    // 创建worker支线
    this.worker = {
      postMessage: () => { },
      terminate: () => { }
    }; 
    
    this.worker = new Worker('/map/mapCanvasLayerWorker.js');
    this.worker.onmessage = (event) => {

      // 对其时间轴
      if( event.data.t !== this.renderTime || window.noRender === false ){
        return;
      }

      this.renderMap(event)

    }
  }

  // 获取当前地图的可视范围
  getBounds() {
    if (!this.centerDiff) return;
    const map = this._map;

    // 右上
    const ys = this.transformXYByYuan(map.getBounds().ne);

    // 这个是左下
    const zx = this.transformXYByYuan(map.getBounds().sw);

    const bounds = [ys, zx];

    return bounds;
  }

  // 坐标转换 转换为原点坐标系的
  transformXYByYuan({ lng, lat }) {
    const map = this._map;

    // 获取原点的位置
    const p = map.pointToPixel();

    // 求目前缩放比
    const rate = this.getLayerRate();

    // 求当前坐标的距离
    const np = map.pointToPixel({ lng: lng, lat: lat });

    // 计算后的x
    const x1 = np.x - p.x;

    // 计算后的y
    const y1 = np.y - p.y;

    return [x1 / rate[0], y1 / rate[1]];
  }

  getLayerRate() {
    const newcenterdiff = [this._map.pointToPixel(this.center), this._map.pointToPixel()];

    const centerdiff = this.centerDiff;

    const xrate = Math.abs(newcenterdiff[0].x - newcenterdiff[1].x) / centerdiff[0];
    const yrate = Math.abs(newcenterdiff[0].y - newcenterdiff[1].y) / centerdiff[1];

    return [xrate, yrate];
  }

  renderMatrixDrive() {
    // 获取当前可视范围
    const bound = this.getBounds();
    console.log(bound);
    const datas = this.matrixDrive.render(bound);

    // const cw = this.canvas.width;
    // const ch = this.canvas.width;

    // 获取当前canvas的像素组
    const canvasData = new ImageData(this.canvas.width, this.canvas.height);

    let it, images, picData, x, y, w, h;

    let pstart, pend, d, dindex;

    // 然后将像素数据解析到的点加载到地图上
    for (var i in datas) {
      it = datas[i];

      images = this.getImages(it.data);

      if (!images) continue;

      // 获取像素数据
      picData = new ImageData(images.imageData.imageData.width, images.imageData.imageData.height); // images.imageData.imageData;
      // picData.data.fill(255);

      // 获取当前数据的像素坐标
      // const x = parseInt(canvasData.width * it.pos[0] / (bound[1][0] + bound[0][0]));
      x = parseInt(canvasData.width * (it.pos[0] - bound[1][0]) / (bound[0][0] - bound[1][0]));

      // const y = parseInt(canvasData.height * it.pos[1] / (bound[1][1] + bound[0][1]));
      y = parseInt(canvasData.height * (bound[1][1] - it.pos[1]) / (bound[1][1] - bound[0][1]));

      // 获取每一行的w
      w = picData.width;

      // console.time("test")

      // for (h = 0; h < picData.height; h++) {

      //     pstart = (0 + h) * w * 4;
      //     pend = w * 4 + pstart;

      //     // canvasData.data.set(
      //     //     picData.data.slice(pstart, pend),
      //     //     (x + (y + h) * canvasData.width) * 4,
      //     // );

      //     d = picData.data.slice(pstart, pend);
      //     dindex = (x + (y + h) * canvasData.width) * 4;
      //     for (var i = 0; i < d.length; i++) {
      //         // canvasData.data[dindex + i] = d[i];
      //     }

      //     // canvasData.data

      // }

      // console.timeEnd("test")

      this.canvas2d.drawImage(images, x, y, it.data.iconConfig?.width || 24, it.data.iconConfig?.height || 30);
    }

    // this.canvas2d.putImageData(canvasData, 0, 0);
  }

  setFilter(fn) {
    this.renderFilter = fn;
    this.handleFilterData();
  }

  handleFilterData() {
    this.filterData = this.renderFilter(this.datas);
  }

  getDatas() {
    return this.filterData || [];
  }

  setMap(map) {
    this._map = map;

    // 传入地图宽高
    this.matrixDrive.setOff([map.width, map.height]);

    this.createCanvas();

    // 绑定时间
    this.mapUpdate = (e) => {
      // 移动canvas
      // this.renderCanvasPosition(e);
      // this.clearCanvas();
      this.renderIcon();
    };
    this._map.addEventListener('update', this.mapUpdate);

    this.mapClick = (e) => {
      // const x = e.layerX;
      // const y = e.layerY;
      this.clickMap(e);
    };
    this._map.addEventListener('click', this.mapClick);

    this.mapMousemove = (e) => {
      const x = e.layerX;
      const y = e.layerY;
      this.moveMap(x, y, e);
    };
    // 绑定鼠标浮动事件
    this._map.addEventListener('mousemove', this.mapMousemove);

    this.mapMouseout = (e) => {
      clearTimeout(this.moveMapKey);
      if (this.mouseObject) {
        this.emit('mouseout', this.mouseObject, e);
      }
    };
    // 绑定鼠标浮动事件
    this._map.addEventListener('mouseout', this.mapMouseout);

    this.mapMoving = (event) => {
      let xy = [0, 0];
      if (this.offsetXY) {
        xy = this.offsetXY;
      }
      // 这个需要记录下来 这里的offsetX很奇怪 每一次新的拖拉都会导致叠加 要减去上一次最后的值
      this.xyArray = [event.currentTarget.offsetX, event.currentTarget.offsetY];

      // console.log("mapMoving", this.xyArray, event);



      this.renderCanvasPosition([event.currentTarget.offsetX - xy[0], event.currentTarget.offsetY - xy[1]]);
    };
    this._map.addEventListener('moving', this.mapMoving);

    this.mapDragstart = (event) => {
      this.offRenderMap();

      if (!this.offsetXY) {
        // 这个需要记录下来 这里的offsetX很奇怪 每一次新的拖拉都会导致叠加 要减去上一次最后的值
        this.offsetXY = [event.currentTarget.offsetX, event.currentTarget.offsetY];
      }
      // console.log("movestart");
    };
    this._map.addEventListener('movestart', this.mapDragstart);

    this.mapDragend = (event) => {
      // 这个需要记录下来 这里的offsetX很奇怪 每一次新的拖拉都会导致叠加 要减去上一次最后的值
      // this.offsetXY = null;
      this.onRenderMap();
      // console.log("moveend");
    };
    this._map.addEventListener('moveend', this.mapDragend);

    this.mapZoomstart = (event) => {
      this.offRenderMap();
      this.clearCanvas();
    };
    this._map.addEventListener('zoomstart', this.mapZoomstart);

    this.mapZoomend = (event) => {
      this.onRenderMap()
    };
    this._map.addEventListener('zoomend', this.mapZoomend);
  }

  // 开启渲染
  onRenderMap (){
    this.isRenderMap = true;
  }

  // 关闭渲染
  offRenderMap (){
    this.isRenderMap = false;
  }

  renderMap (event){
    console.log("workerTime:", event.data.t);
    if( this.isRenderMap === true ){
      this.clearCanvasPosition();
      // this.clearCanvas();
      this.canvas2d.putImageData(event.data.d, 0, 0);
    }
  }

  // 清除掉事件
  clearEvent() {
    this._map.removeEventListener('update', this.mapUpdate);
    this._map.removeEventListener('click', this.mapClick);
    this._map.removeEventListener('mousemove', this.mapMousemove);
    this._map.removeEventListener('mouseout', this.mapMouseout);
    this._map.removeEventListener('moving', this.mapMoving);
    this._map.removeEventListener('movestart', this.mapDragstart);
    this._map.removeEventListener('moveend', this.mapDragend);
    this._map.removeEventListener('zoomstart', this.mapZoomstart);
    this._map.removeEventListener('zoomend', this.mapZoomend);
  }

  clearCanvasPosition() {
    this.offsetXY = null;
    this.canvas.style.transform = '';
  }

  renderCanvasPosition(event) {
    // // 赋值canvas位置
    const { canvas } = this;

    const textCss = `translate(${event[0]}px, ${event[1]}px)`;

    canvas.style.transform = `${textCss}`;

    // // 赋值canvas位置
    // const { canvas } = this;

    // let textCss = `translate(${x}px, ${y}px)`;

    // if (this.mapBounds) {
    //     const ws = this._map.pointToPixel(this.mapBounds.sw);
    //     const ne = this._map.pointToPixel(this.mapBounds.ne);

    //     const bounds = this._map.getBounds();
    //     const ws_ = this._map.pointToPixel(bounds.sw);
    //     const ne_ = this._map.pointToPixel(bounds.ne);

    //     const diffx = (ws.x - ne.x) / (ws_.x - ne_.x);
    //     const diffy = (ws.y - ne.y) / (ws_.y - ne_.y);

    //     textCss += `scale(${diffx},${diffy})`;
    // }

    // canvas.style.transform = `${textCss}`;
  }

  setData(datas) {
    // datas = datas.slice(0, 1);



    // 记录原点到中心点的距离
    this.center = map.getCenter();
    const cp = map.pointToPixel(this.center);
    const yp = map.pointToPixel();
    this.centerDiff = [Math.abs(cp.x - yp.x), Math.abs(cp.y - yp.y)];

    this.datas = datas;
    this.handleFilterData();

    const center = this._map.getCenter();
    // 获取原点距离
    const p = this._map.pointToPixel();
    p.y *= -1;
    // 求中心点
    const c = this._map.pointToPixel(center);
    c.y *= -1;
    const cx = c.x - p.x;
    const cy = c.y - p.y;
    this.matrixDrive.setMatrix(
      datas.map((data) => {
        // const points = this._map.pointToPixel(new window.BMapGL.Point(data.x, data.y));
        return {
          // pos: [points.x - p.x, points.y - p.y],
          pos: this.transformXYByYuan(new window.BMapGL.Point(data.x, data.y)),
          data
        };
      }),
      center
    );
    this.renderIcon();
  }

  // 生成一个canvas组件
  createCanvas() {
    this.canvas = document.createElement('canvas');



    this.canvas.style.cssText = 'position: absolute; left: 0px; top: 0px;transform-origin: 50% 50%;z-index: 1;';
    this.canvas.id = `canvas_${this.id}`;
    this.canvas.width = this._map.width;
    this.canvas.height = this._map.height;

    // 创建一个canvasoff对象
    // const canvas = this.canvas.transferControlToOffscreen();
    // this.worker.postMessage({ type: "addCanvas", canvas }, [canvas]);

    this.canvas2d = this.canvas.getContext('2d');
    this._map.container.appendChild(this.canvas);
    return this.canvas;
  }

  setImages(images) {
    this.imagesConfig = {};
    this.imagesConfig.getImages = images.getImages;
    this.imagesConfig.datas = images.datas || [];
  }

  getImages(data) {
    const path = this.imagesConfig.getImages(data);
    return this.imagesConfig.datas[path];
  }

  // 清楚canvas
  clearCanvas() {
    this.canvas2d?.clearRect(0, 0, this.canvas.width, this.canvas.height);
  }

  renderIcon() {
    this.timeRandom = getRandom();
    if (this.renderIconKey) {
      clearTimeout(this.renderIconKey);
    }
    this.renderIconKey = setTimeout(() => {
      this.render(this.timeRandom);
    }, 200);
  }

  // 在worker图片加载
  loadImagesWorker(image, id) {
    this.worker.postMessage({ type: "addImages", data: { 
        imageIndex: image.imageIndex,
        w: image.imageData.width,
        h: image.imageData.height, 
        id 
      } 
    });
  }

  loadImages() {
    return new Promise((resolve) => {

      const datas = this.getDatas();
      // 记录一下需要加载的图片
      const promise = new Set();
      for (var i = 0; i < datas.length; i++) {
        const data = datas[i];
        // 首先检查一下缓存中是否存在这个图片
        const path = this.imagesConfig.getImages(data);
        const image = this.imagesConfig.datas[path];
        if (image === undefined) {
          if (!promise.has(path)) {

            // 添加进入等待加载的列表
            promise.add(path);
            // 如果没有缓存的图片 则加载
            this.loadImage(path).then((img) => {
              img.width = 24;
              img.height = 30;
              this.imagesConfig.datas[path] = img;
              img.imageData = new ImageCanvasData(img);
              this.loadImagesWorker(img.imageData, path);


              // 将图片解析成像素数据
              promise.delete(path);
              if (promise.size === 0) {
                resolve();
              }
            }).catch(() => {
              this.imagesConfig.datas[path] = null;
              promise.delete(path);
              setTimeout(() => {
                if (promise.size === 0 && i === datas.length) {
                  resolve();
                }
              }, 100);
            });
          }
        }
      }
      if (promise.size === 0) {
        resolve();
      }
    });
  }

  loadImage(path) {
    return new Promise((resolve, error) => {
      const img = document.createElement('img');
      img.src = path;
      img.onload = () => {

        resolve(img);
      };
      img.onerror = () => error();
    });
  }

  render(timeRandom) {
    if (timeRandom !== this.timeRandom) {
      return;
    }
    this.renderTime = new Date() * 1;
    // this.clearCanvas();
    // 渲染之前先加载一下需要的图片
    this.loadImages().then(() => {
      // console.time("matrixRender");

      // this.renderMatrixDrive();

      // console.timeEnd("matrixRender");
      
      const map = this._map;
      const datas = this.getDatas();

      if( this.canvas.width !== this._map.width ){
        this.canvas.width = this._map.width;
      }
      if( this.canvas.height !== this._map.height ){
        this.canvas.height = this._map.height;
      }

      // 解析数据的屏幕坐标和id
      const workerData = datas.map((data)=> {
        return {
          iconkey: this.imagesConfig.getImages(data),
          // this.getImages(data),
          p: map.pointToPixel(new window.BMapGL.Point(data.x, data.y))
        }
      })

      // this.renderTime = new Date() * 1;

      this.worker.postMessage({ 
        type: "render", 
        data: workerData, 
        width: this.canvas.width,
        height: this.canvas.height,
        time: this.renderTime
      });

      // console.time('mapRender');
      // let data = null;
      // let config = {};
      // let w = null;
      // let h = null;

      // // 获取当前canvas的像素组
      // const canvasData = new ImageData(this.canvas.width, this.canvas.height);

      // let loadIndex = {};

      // // // 将数据转化屏幕坐标
      // // const indexData = datas.map((e)=> { 
      // //   [map.pointToPixel(new window.BMapGL.Point(e.x, e.y)), this.getImages(e)];
      // // })

      // for (var i = datas.length - 1; i >= 0; i--) {
      //   data = datas[i];
      //   const images = this.getImages(data);
      //   if (!images) continue;
      //   const points = this._map.pointToPixel(new window.BMapGL.Point(data.x, data.y));

      //   const lng = points.x - images.width / 2;
      //   const lat = points.y - images.height / 2;

      //   if (lng > canvasData.width || lng < 0 || lat > canvasData.height || lat < 0) {
      //     continue;
      //   }

      //   // 临时变量由下面的公式分解出来的
      //   const cwc = this.canvas.width * 4;
      //   const pjt = lng * 4 + lat * cwc;

      //   for (var it of images.imageData.imageIndex) {
      //     // 同行中如果并行的

      //     // const index = (points.x + it[0]) * 4 + (points.y + it[1]) * this.canvas.width * 4;
      //     const index = pjt + it[1] * cwc + it[0] * 4;
      //     // if (loadIndex[index]) {
      //     //   continue;
      //     // }
      //     if (it[2].length < canvasData.data.length - index) {
      //       canvasData.data.set(it[2], index);
      //     }
      //     // 记录一下已经加载过的像素点
      //     loadIndex[index] = index;
      //   }
      // }

      // this.canvas2d.putImageData(canvasData, 0, 0);

      // loadIndex = null;

      // this.clearCanvasPosition();
      // console.timeEnd('mapRender');
    });
  }

  // 判断点击事件
  clickMap(e) {
    const _x = e.clientPos.x;
    const _y = e.clientPos.y;
    const map = this._map;
    const innerWidth = window.innerWidth;
    const innerHeight = window.innerHeight;
    const zoom = getZoom();
    const x = e.pixel.x / zoom[0]; // _x / innerWidth * map.width;
    const y = e.pixel.y / zoom[1]; //  _y / innerHeight * map.height;
    const datas = this.getDatas();

    // 选中的对象
    const filterData = [];

    for (var i = 0; i < datas.length; i++) {
      const points = this._map.pointToPixel(new window.BMapGL.Point(datas[i].x, datas[i].y));
      if (Math.abs(points.x - x) < 8 && Math.abs(points.y - y) < 8) {
        filterData.push(datas[i]);
        // return;
      };
    }
    
    if( filterData.length > 0 ){
      this.emit('click', filterData[0], filterData, e);
    }
  }

  // 触摸点判断
  moveMap(_x, _y, event) {
    if (this.moveMapKey) {
      clearTimeout(this.moveMapKey);
    }
    this.moveMapKey = setTimeout(() => {
      const map = this._map;
      const innerWidth = window.innerWidth;
      const innerHeight = window.innerHeight;
      const zoom = getZoom();
      const x = event.clientPos.x / zoom[0]; // _x / innerWidth * map.width;
      const y = event.clientPos.y / zoom[1]; //  _y / innerHeight * map.height;
      const datas = this.getDatas();
      for (var i = 0; i < datas.length; i++) {
        const points = this._map.pointToPixel(new window.BMapGL.Point(datas[i].x, datas[i].y));
        if (Math.abs(points.x - x) < 8 && Math.abs(points.y - y) < 8) {
          // 如果当前选中得对象不是自己则触发移除事件
          if (this.mouseObject !== datas[i]) {
            this.emit('mouseout', this.mouseObject, event);
          }
          this.mouseObject = datas[i];
          this.emit('mouse', datas[i], { ...event, layerX: x, layerY: y });
          return;
        };
      }
      // 如果当前选中得对象不是自己则触发移除事件
      if (this.mouseObject) {
        this.emit('mouseout', this.mouseObject, { ...event, layerX: x, layerY: y });
      }
      // this.mouseObject = datas[i];
    }, 300);
  }

  emit(type, ...arg) {
    this.events.forEach((eve) => {
      if (eve.type === type) {
        eve.resovle(...arg);
      };
    });
  }

  on(type, fn) {
    this.events.push({
      type,
      resovle: fn
    });
  }

  close() {
    this.clearEvent();
    this.canvas.remove();
    this.worker.terminate();
  }
}

/**
 * 矩阵数据计算对象
 */
class MatrixDrive {
  constructor(bounds = [1920, 960]) {
    // 可视框
    this.bounds = bounds;
    // 计算中心点
    this.center = null;
  }

  // 传入矩阵数据
  /**
     * { pos: [x, y] , data: {} }
     */
  setMatrix(Arrays) {
    this.matrix = Arrays;
  }

  setOff(b) {
    this.bounds = b;
  }

  /**
     * @param {Object} bounds
     * [ [ 右上角x距离, y距离 ], [左下角 x距离, y距离] ];
     */
  render(bounds) {
    const ysx = bounds[0][0];
    const ysy = bounds[0][1];
    const zxx = bounds[1][0];
    const zxy = bounds[1][1];
    // 初始化zoom

    // 要处理的矩阵数据
    const datas = this.matrix;

    const boundPoint = [];

    const [offw, offh] = this.bounds;
    const width = Math.abs(zxx) + Math.abs(ysx);
    const height = Math.abs(zxy) + Math.abs(ysy);

    for (var i in datas) {
      const data = datas[i];
      const pos = data.pos;
      if (zxx < pos[0] && pos[0] < ysx && zxy > pos[1] && pos[1] > ysy) {
        // 判断范围内的数据
        // 计算范围内数据
        data.position = [Math.abs(pos[0] - zxx) / width * offw, Math.abs(pos[1] - ysy) / height * offh];
        boundPoint.push(data);
      }
    }

    // 将处理好的数据进行排列
    this.renderAfter(boundPoint);

    return boundPoint;
  }

  // 进行渲染完毕
  renderAfter(datas) {
    // render(this.matrix);
    console.log(datas.length);
  }
}

class ImageCanvasData {
  constructor(images) {
    // 像素数据
    this.imageData = null;

    this.set(images);
  }

  set(img) {
    // 创建
    const { canvas, context } = ImageCanvasData.getCanvas();

    canvas.width = img.width;
    canvas.height = img.height;

    context.drawImage(img, 0, 0);

    // 获取图片的像素数据
    var imageData = context.getImageData(0, 0, img.width, img.height);

    // 现在imageData包含了图片的所有像素数据,您可以对其进行操作
    this.imageData = imageData;

    // 计算初始化坐标位置
    this.bound = [parseInt(img.width), parseInt(img.height)];

    // 获取数据的下标数组
    const imageIndex = [];
    let tongzu = null;
    for (var i = 0; i * 4 < imageData.data.length; i++) {
      // 判断是否是透明的
      if (imageData.data[i * 4 + 3] !== 0) {

        // 如果没有 那就初始化
        if (!tongzu) {
          tongzu = [i % img.width, parseInt(i / img.width), null, i * 4, (i * 4) % (img.width * 4), parseInt((i * 4) / (img.width * 4))];
          tongzu[2] = imageData.data.slice(tongzu[3], i * 4);
          imageIndex.push(tongzu);
        }else {
          // 这里需要判断是否换行了 如果已经换行了 就要结束这边并且新起一个
          if( parseInt((i * 4) / (img.width * 4)) === tongzu[5] ){
            tongzu[2] = imageData.data.slice(tongzu[3], i * 4);
          }else {
            tongzu = [i % img.width, parseInt(i / img.width), null, i * 4, (i * 4) % (img.width * 4), parseInt((i * 4) / (img.width * 4))];
            imageIndex.push(tongzu);
          }
        }
      }
      // imageIndex.push([parseInt(i / img.width), i % img.width, imageData.data.slice(i, i + 4)]);
    }
    this.imageIndex = imageIndex;
  }

  toDatas() {
    // 假设您已经有一个canvas元素,并且图片已经通过drawImage方法绘制进去
    var canvas = document.getElementById('myCanvas');
    var context = canvas.getContext('2d');

    // 绘制图片到canvas上
    var image = new Image();
    image.src = 'path/to/your/image.jpg';
    image.onload = function () {
      context.drawImage(image, 0, 0);

      // 获取图片的像素数据
      var imageData = context.getImageData(0, 0, canvas.width, canvas.height);

      // 现在imageData包含了图片的所有像素数据,您可以对其进行操作
      console.log(imageData);
    };
  }

  static getCanvas() {
    if (this.canvasObj) return this.canvasObj;
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    this.canvasObj = { canvas, context };
    return this.canvasObj;
  }
}

 

 

2. 计算用的worker内容

// 保存的图片数据
const images = {};

// 数据
const points = [];

// canvas
let canvas = null;

// 绘画
let ctx = null;

// 最新的一次timekey
let timekey = null;

// 监听消息事件
onmessage = function (e) {


    // 获取方式类型
    const type = e.data.type;

    // 传入数据
    if (type === "addDatas") {
        addDatas(e.data);
    }

    // 传入图片数据
    if (type === "addImages") {
        addImages(e.data);
    }

    // 传入canvas
    if (type === "addCanvas") {
        addCanvas(e.data);
    }

    // 进行渲染
    if (type === "render") {
        renderCanvas(e.data);
    }

};

//新增数据
const addDatas = function (data) {
    points = data.points;
};

// 渲染
const renderCanvas = function (data) {
    timekey = data.time;
    render(data);
};

// 新增canvas
const addCanvas = function (data) {
    canvas = data.canvas;
    ctx = canvas.getContext("2d");
};

// 新增图片
const addImages = function (data) {
    images[data.data.id] = data.data;
};


const getImagesById = function(key){
    return images[key];
}

// 开始进行渲染计算
const render = function (data) {
    
    const datas = data.data;
    if( !datas || datas.length === 0 ){
        return;
    }

    console.time('mapRender');

    const width = data.width;
    const height = data.height;
    const time = data.time;

    // 获取当前canvas的像素组
    const canvasData = new ImageData(width, height);

    let loadIndex = {};

    for (var i = datas.length - 1; i >= 0; i--) {
        data = datas[i];
        const images = getImagesById(data.iconkey);
        if (!images) continue;
        const points = data.p;
        // config = data.iconConfig || {};
        // w = config.width || 24;
        // h = config.height || 35;
        // this.canvas2d.drawImage(images, points.x - w / 2, points.y - h / 2, w, h);

        const lng = points.x - images.w / 2;
        const lat = points.y - images.h / 2;

        if (lng > canvasData.width || lng < 0 || lat > canvasData.height || lat < 0) {
            continue;
        }

        // 临时变量由下面的公式分解出来的
        const cwc = width * 4;
        const pjt = lng * 4 + lat * cwc;

        for (var it of images.imageIndex) {
            // 同行中如果并行的

            // const index = (points.x + it[0]) * 4 + (points.y + it[1]) * this.canvas.width * 4;
            const index = pjt + it[1] * cwc + it[0] * 4;
            // if (loadIndex[index]) {
            //     continue;
            // }
            if (it[2].length < canvasData.data.length - index) {
                canvasData.data.set(it[2], index);
            }
            // 记录一下已经加载过的像素点
            loadIndex[index] = index;
        }
    }

    // this.canvas2d.putImageData(canvasData, 0, 0);

    loadIndex = null;

    renderMap({t: "render", d: canvasData, t: time});
    // postMessage({t: "render", d: canvasData, t: time});

    // this.clearCanvasPosition();
    console.timeEnd('mapRender');
};


const renderMap = function(params){
    setTimeout(()=>{
        if( params.t === timekey ){
            postMessage(params);
        }
    }, 10)
}

 

 

3. 业务代码中使用的内容

// 创建告警信息数据分布
    layerGJ () {
      const layerIcon = new MapCanvasLayer();
      layerIcon.setMap(map);
      // 每次渲染前对数据进行过滤
      layerIcon.setFilter((datas) => {
        // 获取选中的类型
        const types = this.legend.filter((e) => e.check).map((e) => e.type);

        // 从数据中进行过滤
        const d = datas.filter(
          (e) => types.indexOf(e.unitType || e.ssxtBm) > -1
        );
        return d;
      });
      layerIcon.setImages({
        getImages: (data) => {
          if (data.unitType === 'XKS') {
            return `/images/deviceIcon/xks_${data.lwzt || '1'}.svg`;
          }

          // 如果没有类型则选择电气
          const name = reversedMapPath[data.ssxtBm];
          const bjzt = data.bjzt;

          // 暂时返回两种状态颜色, 因为只有正常和异常两种颜色
          if (bjzt === '01') {
            return `/images/deviceIcon/${name}_01.svg`;
          } else {
            return `/images/deviceIcon/${name}_10.svg`;
          }
          // return `/images/deviceIcon/${name}_${bjzt}.svg`;
        }
      });
      layerIcon.on('click', (data) => {
        if (data.unitType === 'XKS') {
          //
          this.xksId = data.dwbm;
          this.showXksDialog = true;
          return; // open();
        }
        this.$emit('deviceClick', data);
      });
      layerIcon.on('mouse', (data, event) => {
        // 显示标题
        this.deviceTitleConfig = {
          ...data,
          left: event.layerX + 'px',
          top: event.layerY - 30 + 'px',
          show: true
        };
      });
      layerIcon.on('mouseout', (data) => {
        // 显示标题
        this.deviceTitleConfig = {
          show: false
        };
      });
      this.getLayerIconGJ = function () {
        return layerIcon;
      };
    },



    this.getLayerIconGJ().setData(data);
    // data中需要包含x, y

 

据目前使用来看。1W数据的渲染速度在20ms左右。10W的速度在200ms  这个速度。还是可以满足一般的业务需求的。  有疑问可以联系我。137550763

 

posted @ 2024-08-23 15:02  blurs  阅读(30)  评论(0)    收藏  举报