ECharts 深度进阶:自定义渲染器与百万级数据性能优化

简介: 深入解析ECharts架构,详解自定义WebGL渲染器开发与百万级数据性能优化方案,涵盖数据采样、LOD、增量渲染等核心技术,显著提升大数据可视化性能与交互体验。

ECharts 深度进阶:自定义渲染器与百万级数据性能优化


一、ECharts 架构深度解析与自定义渲染器开发

1.1 ECharts 核心架构与渲染流程

ECharts 的架构设计采用了分层模式,从数据层到视觉层形成了完整的渲染流水线:

架构层级 核心职责 关键组件
数据层 数据处理、转换、映射 Dataset、DataProvider
组件层 坐标轴、图例、工具栏 Axis、Legend、Toolbox
系列层 图表类型实现 Line、Bar、Scatter
渲染层 视觉元素绘制 Canvas、SVG、自定义渲染器

ECharts 的渲染流程遵循以下关键路径:

数据准备 → 组件布局 → 系列绘制 → 渲染输出 → 交互处理

1.2 自定义渲染器开发实战

1.2.1 渲染器接口定义与实现

// 自定义 WebGL 渲染器基础架构
class WebGLRenderer {
   
  constructor(dom, options = {
   }) {
   
    this._dom = dom;
    this._options = options;
    this._gl = null;
    this._programs = new Map();
    this._buffers = new Map();
    this._initWebGLContext();
  }

  _initWebGLContext() {
   
    const canvas = document.createElement('canvas');
    this._dom.appendChild(canvas);

    // 获取 WebGL 上下文
    this._gl = canvas.getContext('webgl', {
   
      antialias: this._options.antialias || false,
      preserveDrawingBuffer: true
    }) || canvas.getContext('experimental-webgl');

    if (!this._gl) {
   
      throw new Error('WebGL 不被支持');
    }

    this._resizeCanvas();
    this._initShaders();
  }

  _resizeCanvas() {
   
    const canvas = this._gl.canvas;
    const width = this._dom.clientWidth;
    const height = this._dom.clientHeight;

    if (canvas.width !== width || canvas.height !== height) {
   
      canvas.width = width;
      canvas.height = height;
      this._gl.viewport(0, 0, width, height);
    }
  }

  _initShaders() {
   
    // 基础顶点着色器
    const vertexShaderSource = `
      attribute vec2 a_position;
      attribute vec4 a_color;
      uniform mat4 u_projection;
      varying vec4 v_color;

      void main() {
        gl_Position = u_projection * vec4(a_position, 0.0, 1.0);
        v_color = a_color;
        gl_PointSize = 5.0;
      }
    `;

    // 基础片段着色器
    const fragmentShaderSource = `
      precision mediump float;
      varying vec4 v_color;

      void main() {
        gl_FragColor = v_color;
      }
    `;

    this._createProgram('basic', vertexShaderSource, fragmentShaderSource);
  }

  _createProgram(name, vsSource, fsSource) {
   
    const gl = this._gl;

    const vertexShader = this._compileShader(gl.VERTEX_SHADER, vsSource);
    const fragmentShader = this._compileShader(gl.FRAGMENT_SHADER, fsSource);

    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
   
      console.error('程序链接失败:', gl.getProgramInfoLog(program));
      gl.deleteProgram(program);
      return null;
    }

    this._programs.set(name, program);
    return program;
  }

  _compileShader(type, source) {
   
    const gl = this._gl;
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
   
      console.error('着色器编译失败:', gl.getShaderInfoLog(shader));
      gl.deleteShader(shader);
      return null;
    }

    return shader;
  }

  // 渲染接口实现
  render(chart, groups, painters) {
   
    this._resizeCanvas();
    this._clear();

    // 执行所有绘制任务
    painters.forEach(painter => {
   
      this._renderGroup(painter.group, painter);
    });
  }

  _clear() {
   
    const gl = this._gl;
    gl.clearColor(1.0, 1.0, 1.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  }

  _renderGroup(group, painter) {
   
    const type = painter.type;

    switch (type) {
   
      case 'line':
        this._renderLine(group, painter);
        break;
      case 'scatter':
        this._renderScatter(group, painter);
        break;
      case 'custom':
        this._renderCustom(group, painter);
        break;
    }
  }

  // 线图渲染
  _renderLine(group, painter) {
   
    const gl = this._gl;
    const program = this._programs.get('basic');
    gl.useProgram(program);

    // 设置投影矩阵
    const projectionMatrix = this._getProjectionMatrix();
    const projectionLocation = gl.getUniformLocation(program, 'u_projection');
    gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);

    // 创建顶点缓冲区
    const vertices = this._buildLineVertices(group, painter);
    this._createBuffer('line_vertices', vertices);

    // 绘制线条
    const positionLocation = gl.getAttribLocation(program, 'a_position');
    gl.enableVertexAttribArray(positionLocation);

    const vertexBuffer = this._buffers.get('line_vertices');
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

    gl.drawArrays(gl.LINE_STRIP, 0, vertices.length / 2);
  }

  _buildLineVertices(group, painter) {
   
    const vertices = [];
    const data = group.data;

    for (let i = 0; i < data.length; i++) {
   
      const point = this._convertPoint(data[i]);
      vertices.push(point[0], point[1]);
    }

    return new Float32Array(vertices);
  }

  _convertPoint(dataPoint) {
   
    // 将数据点转换为屏幕坐标
    const x = (dataPoint[0] - this._xMin) / (this._xMax - this._xMin) * 2 - 1;
    const y = (dataPoint[1] - this._yMin) / (this._yMax - this._yMin) * 2 - 1;
    return [x, -y]; // WebGL Y轴向下
  }

  _getProjectionMatrix() {
   
    return new Float32Array([
      1, 0, 0, 0,
      0, 1, 0, 0,
      0, 0, 1, 0,
      0, 0, 0, 1
    ]);
  }

  _createBuffer(name, data) {
   
    const gl = this._gl;
    const buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    this._buffers.set(name, buffer);
    return buffer;
  }

  // 散点图渲染(优化版本)
  _renderScatter(group, painter) {
   
    const gl = this._gl;
    const program = this._programs.get('basic');
    gl.useProgram(program);

    const data = group.data;
    if (data.length > 100000) {
   
      this._renderScatterInstanced(data, painter);
    } else {
   
      this._renderScatterTraditional(data, painter);
    }
  }

  _renderScatterInstanced(data, painter) {
   
    // 使用实例化渲染处理大数据量
    const gl = this._gl;

    // 创建实例化渲染程序
    const instanceProgram = this._getInstanceProgram();
    gl.useProgram(instanceProgram);

    // 设置实例化数据
    const instanceData = this._buildInstanceData(data);
    this._setupInstanceBuffers(instanceData);

    // 绘制实例
    const instanceCount = data.length;
    gl.drawArraysInstanced(gl.POINTS, 0, 1, instanceCount);
  }

  dispose() {
   
    const gl = this._gl;

    // 清理所有 WebGL 资源
    this._programs.forEach(program => {
   
      gl.deleteProgram(program);
    });

    this._buffers.forEach(buffer => {
   
      gl.deleteBuffer(buffer);
    });

    if (gl.getExtension('WEBGL_lose_context')) {
   
      gl.getExtension('WEBGL_lose_context').loseContext();
    }

    this._dom.removeChild(gl.canvas);
  }
}

1.2.2 ECharts 自定义渲染器注册与集成

// 注册自定义渲染器到 ECharts
class CustomWebGLRenderer {
   
  constructor() {
   
    this.type = 'webgl';
    this._renderer = null;
  }

  // 必须实现的方法
  init(dom, group, storage, painter) {
   
    this._renderer = new WebGLRenderer(dom, {
   
      antialias: true,
      preserveDrawingBuffer: true
    });

    this._storage = storage;
    this._painter = painter;
    return this;
  }

  render(chart, groups, painters) {
   
    if (!this._renderer) return;

    try {
   
      this._renderer.render(chart, groups, painters);
    } catch (error) {
   
      console.error('WebGL 渲染失败:', error);
      this._fallbackToCanvas();
    }
  }

  _fallbackToCanvas() {
   
    console.warn('WebGL 渲染失败,回退到 Canvas');
    // 这里可以实现回退逻辑
  }

  resize() {
   
    if (this._renderer) {
   
      this._renderer.resize();
    }
  }

  dispose() {
   
    if (this._renderer) {
   
      this._renderer.dispose();
      this._renderer = null;
    }
  }

  getType() {
   
    return this.type;
  }

  // 支持的方法检测
  supportDirtyRect() {
   
    return false;
  }

  getLayer() {
   
    return this._renderer ? this._renderer.getLayer() : null;
  }

  refresh() {
   
    this.resize();
  }

  // 性能监控
  getRenderedCount() {
   
    return this._renderer ? this._renderer.getRenderedCount() : 0;
  }

  clear() {
   
    if (this._renderer) {
   
      this._renderer.clear();
    }
  }
}

// 注册到 ECharts
echarts.registerRenderer(CustomWebGLRenderer);

// 使用自定义渲染器
const chart = echarts.init(dom, null, {
   
  renderer: 'webgl' // 使用注册的渲染器类型
});

1.2.3 高级渲染特性实现

// 高级 WebGL 渲染特性
class AdvancedWebGLRenderer extends WebGLRenderer {
   
  constructor(dom, options = {
   }) {
   
    super(dom, options);
    this._initAdvancedShaders();
    this._particleSystems = new Map();
    this._gpuPickers = new Map();
  }

  _initAdvancedShaders() {
   
    // 渐变着色器
    const gradientVertexShader = `
      attribute vec2 a_position;
      attribute float a_value;
      uniform mat4 u_projection;
      varying float v_value;

      void main() {
        gl_Position = u_projection * vec4(a_position, 0.0, 1.0);
        v_value = a_value;
        gl_PointSize = 8.0;
      }
    `;

    const gradientFragmentShader = `
      precision mediump float;
      uniform vec3 u_lowColor;
      uniform vec3 u_highColor;
      varying float v_value;

      void main() {
        float intensity = (v_value - 0.0) / 1.0; // 归一化
        vec3 color = mix(u_lowColor, u_highColor, intensity);
        gl_FragColor = vec4(color, 1.0);
      }
    `;

    this._createProgram('gradient', gradientVertexShader, gradientFragmentShader);

    // 粒子系统着色器
    const particleVertexShader = `
      attribute vec2 a_position;
      attribute vec2 a_velocity;
      attribute float a_lifetime;
      uniform float u_time;
      uniform mat4 u_projection;

      void main() {
        float progress = mod(u_time, a_lifetime) / a_lifetime;
        vec2 position = a_position + a_velocity * progress;
        gl_Position = u_projection * vec4(position, 0.0, 1.0);
        gl_PointSize = 3.0 * (1.0 - progress);
      }
    `;

    const particleFragmentShader = `
      precision mediump float;
      uniform vec4 u_particleColor;

      void main() {
        gl_FragColor = u_particleColor;
      }
    `;

    this._createProgram('particle', particleVertexShader, particleFragmentShader);
  }

  // 热力图渲染
  renderHeatmap(group, painter) {
   
    const gl = this._gl;
    const program = this._programs.get('gradient');
    gl.useProgram(program);

    const data = group.data;
    if (data.length > 50000) {
   
      this._renderHeatmapWithSampling(data, painter);
    } else {
   
      this._renderHeatmapDirect(data, painter);
    }
  }

  _renderHeatmapDirect(data, painter) {
   
    const gl = this._gl;

    // 构建热力图数据
    const heatmapData = this._buildHeatmapData(data);
    this._createBuffer('heatmap', heatmapData);

    // 设置颜色渐变
    const lowColor = painter.style.lowColor || [0, 0, 1];
    const highColor = painter.style.highColor || [1, 0, 0];

    const lowColorLocation = gl.getUniformLocation(program, 'u_lowColor');
    const highColorLocation = gl.getUniformLocation(program, 'u_highColor');

    gl.uniform3f(lowColorLocation, ...lowColor);
    gl.uniform3f(highColorLocation, ...highColor);

    // 绘制点
    gl.drawArrays(gl.POINTS, 0, data.length);
  }

  _buildHeatmapData(data) {
   
    const result = [];

    for (let i = 0; i < data.length; i++) {
   
      const point = this._convertPoint(data[i]);
      const value = data[i][2] || 1.0; // 热度值

      result.push(
        point[0],  // x
        point[1],  // y
        value      // 值
      );
    }

    return new Float32Array(result);
  }

  // 粒子动画系统
  createParticleSystem(name, config) {
   
    const particleSystem = {
   
      particles: [],
      startTime: Date.now(),
      config: config
    };

    this._initParticles(particleSystem);
    this._particleSystems.set(name, particleSystem);
  }

  _initParticles(particleSystem) {
   
    const {
    count, source, velocityRange } = particleSystem.config;

    for (let i = 0; i < count; i++) {
   
      particleSystem.particles.push({
   
        position: [source[0], source[1]],
        velocity: [
          (Math.random() - 0.5) * velocityRange[0],
          (Math.random() - 0.5) * velocityRange[1]
        ],
        lifetime: 1 + Math.random() * 2,
        startTime: Math.random() * 2
      });
    }
  }

  renderParticleSystem(name) {
   
    const system = this._particleSystems.get(name);
    if (!system) return;

    const gl = this._gl;
    const program = this._programs.get('particle');
    gl.useProgram(program);

    // 更新时间
    const timeLocation = gl.getUniformLocation(program, 'u_time');
    const currentTime = (Date.now() - system.startTime) / 1000;
    gl.uniform1f(timeLocation, currentTime);

    // 更新粒子数据
    const particleData = this._buildParticleData(system.particles);
    this._createBuffer('particles', particleData);

    // 绘制粒子
    gl.drawArrays(gl.POINTS, 0, system.particles.length);
  }

  _buildParticleData(particles) {
   
    const data = [];

    particles.forEach(particle => {
   
      data.push(
        particle.position[0], particle.position[1], // 位置
        particle.velocity[0], particle.velocity[1], // 速度
        particle.lifetime                           // 生命周期
      );
    });

    return new Float32Array(data);
  }

  // GPU 拾取系统(用于大数据量交互)
  setupGPUPicker(chart, seriesIndex) {
   
    const picker = {
   
      chart: chart,
      seriesIndex: seriesIndex,
      texture: null,
      framebuffer: null
    };

    this._initGPUPicker(picker);
    this._gpuPickers.set(seriesIndex, picker);
  }

  _initGPUPicker(picker) {
   
    const gl = this._gl;

    // 创建帧缓冲区
    const framebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

    // 创建纹理用于存储 ID
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 512, 512, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

    // 设置纹理参数
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    // 附加纹理到帧缓冲区
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);

    picker.texture = texture;
    picker.framebuffer = framebuffer;

    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  }

  pickElement(x, y, seriesIndex) {
   
    const picker = this._gpuPickers.get(seriesIndex);
    if (!picker) return null;

    const gl = this._gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, picker.framebuffer);

    // 读取像素数据
    const pixel = new Uint8Array(4);
    gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);

    gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    // 解码元素 ID
    const elementId = this._decodeElementId(pixel);
    return elementId;
  }

  _decodeElementId(pixel) {
   
    // 将 RGBA 值解码为元素 ID
    return (pixel[0] << 24) | (pixel[1] << 16) | (pixel[2] << 8) | pixel[3];
  }
}

二、百万级数据性能优化实战

2.1 数据采样与聚合策略

2.1.1 智能数据采样算法

// 大数据量采样与聚合引擎
class DataSamplingEngine {
   
  constructor(options = {
   }) {
   
    this._options = {
   
      maxPoints: 10000,        // 最大显示点数
      samplingMethod: 'lttb',  // 采样方法:lttb、minmax、average
      aggregation: true,       // 是否启用聚合
      ...options
    };

    this._cache = new Map();
    this._statistics = {
   
      totalProcessed: 0,
      totalReduced: 0,
      samplingTime: 0
    };
  }

  // 主采样入口
  sample(data, dimensions = ['x', 'y']) {
   
    const startTime = performance.now();

    if (data.length <= this._options.maxPoints) {
   
      return data; // 数据量不大,直接返回
    }

    let sampledData;

    switch (this._options.samplingMethod) {
   
      case 'lttb':
        sampledData = this._largestTriangleThreeBuckets(data, dimensions);
        break;
      case 'minmax':
        sampledData = this._minMaxSampling(data, dimensions);
        break;
      case 'average':
        sampledData = this._averageSampling(data, dimensions);
        break;
      case 'clustering':
        sampledData = this._clusteringSampling(data, dimensions);
        break;
      default:
        sampledData = this._largestTriangleThreeBuckets(data, dimensions);
    }

    const endTime = performance.now();
    this._statistics.samplingTime = endTime - startTime;
    this._statistics.totalProcessed = data.length;
    this._statistics.totalReduced = sampledData.length;

    return sampledData;
  }

  // LTTB 采样算法(保留趋势特征)
  _largestTriangleThreeBuckets(data, dimensions) {
   
    const [xDim, yDim] = dimensions;
    const dataLength = data.length;

    if (this._options.maxPoints >= dataLength) {
   
      return data;
    }

    const sampled = [];
    const bucketSize = (dataLength - 2) / (this._options.maxPoints - 2);

    let pointIndex = 0;
    sampled.push(data[pointIndex]); // 添加第一个点

    for (let i = 0; i < this._options.maxPoints - 2; i++) {
   
      const bucketStart = Math.floor((i + 0) * bucketSize) + 1;
      const bucketEnd = Math.floor((i + 1) * bucketSize) + 1;

      const avgRangeStart = Math.floor((i + 0) * bucketSize) + 1;
      const avgRangeEnd = Math.floor((i + 1) * bucketSize) + 1;

      // 计算桶的平均点
      let avgX = 0;
      let avgY = 0;
      let avgCount = 0;

      for (let j = avgRangeStart; j < avgRangeEnd; j++) {
   
        const point = data[j];
        avgX += point[xDim];
        avgY += point[yDim];
        avgCount++;
      }

      avgX /= avgCount;
      avgY /= avgCount;

      // 在桶中寻找与前后点形成最大三角形的点
      const pointA = data[pointIndex];
      const pointC = data[Math.min(Math.floor((i + 2) * bucketSize) + 1, dataLength - 1)];

      let maxArea = -1;
      let maxAreaIndex = -1;

      for (let j = bucketStart; j < bucketEnd; j++) {
   
        const pointB = data[j];

        // 计算三角形面积
        const area = Math.abs(
          (pointA[xDim] - pointC[xDim]) * (pointB[yDim] - pointA[yDim]) -
          (pointA[xDim] - pointB[xDim]) * (pointC[yDim] - pointA[yDim])
        ) / 2;

        if (area > maxArea) {
   
          maxArea = area;
          maxAreaIndex = j;
        }
      }

      if (maxAreaIndex !== -1) {
   
        sampled.push(data[maxAreaIndex]);
        pointIndex = maxAreaIndex;
      }
    }

    sampled.push(data[dataLength - 1]); // 添加最后一个点
    return sampled;
  }

  // 最小最大采样(保留极值)
  _minMaxSampling(data, dimensions) {
   
    const [xDim, yDim] = dimensions;
    const dataLength = data.length;
    const bucketSize = Math.ceil(dataLength / this._options.maxPoints);
    const sampled = [];

    for (let i = 0; i < dataLength; i += bucketSize) {
   
      const bucket = data.slice(i, i + bucketSize);

      if (bucket.length === 0) continue;

      let minPoint = bucket[0];
      let maxPoint = bucket[0];
      let minValue = minPoint[yDim];
      let maxValue = maxPoint[yDim];

      // 找到最小值和最大值点
      bucket.forEach(point => {
   
        const value = point[yDim];
        if (value < minValue) {
   
          minValue = value;
          minPoint = point;
        }
        if (value > maxValue) {
   
          maxValue = value;
          maxPoint = point;
        }
      });

      // 如果最小最大值不同,都添加
      if (minPoint !== maxPoint) {
   
        sampled.push(minPoint);
        sampled.push(maxPoint);
      } else {
   
        sampled.push(minPoint);
      }
    }

    return sampled.slice(0, this._options.maxPoints);
  }

  // 聚类采样(基于数据分布)
  _clusteringSampling(data, dimensions) {
   
    const [xDim, yDim] = dimensions;

    // 使用简单网格聚类
    const gridSize = Math.ceil(Math.sqrt(this._options.maxPoints));
    const xExtent = this._getExtent(data, xDim);
    const yExtent = this._getExtent(data, yDim);

    const xStep = (xExtent[1] - xExtent[0]) / gridSize;
    const yStep = (yExtent[1] - yExtent[0]) / gridSize;

    const grid = new Map();

    data.forEach(point => {
   
      const x = point[xDim];
      const y = point[yDim];

      const gridX = Math.floor((x - xExtent[0]) / xStep);
      const gridY = Math.floor((y - yExtent[0]) / yStep);
      const gridKey = `${
     gridX},${
     gridY}`;

      if (!grid.has(gridKey)) {
   
        grid.set(gridKey, []);
      }

      grid.get(gridKey).push(point);
    });

    // 从每个网格中选择代表性点
    const sampled = [];
    for (const [key, points] of grid) {
   
      if (points.length > 0) {
   
        // 选择网格中心最近的点
        const [gridX, gridY] = key.split(',').map(Number);
        const centerX = xExtent[0] + (gridX + 0.5) * xStep;
        const centerY = yExtent[0] + (gridY + 0.5) * yStep;

        let closestPoint = points[0];
        let minDistance = Infinity;

        points.forEach(point => {
   
          const distance = Math.sqrt(
            Math.pow(point[xDim] - centerX, 2) + 
            Math.pow(point[yDim] - centerY, 2)
          );

          if (distance < minDistance) {
   
            minDistance = distance;
            closestPoint = point;
          }
        });

        sampled.push(closestPoint);
      }
    }

    return sampled.slice(0, this._options.maxPoints);
  }

  _getExtent(data, dimension) {
   
    let min = Infinity;
    let max = -Infinity;

    data.forEach(point => {
   
      const value = point[dimension];
      if (value < min) min = value;
      if (value > max) max = value;
    });

    return [min, max];
  }

  // 流式数据采样
  createStreamSampler(windowSize = 1000) {
   
    return new StreamSampler(windowSize, this._options);
  }

  getStatistics() {
   
    return {
    ...this._statistics };
  }

  clearCache() {
   
    this._cache.clear();
  }
}

// 流式数据采样器
class StreamSampler {
   
  constructor(windowSize, options) {
   
    this._windowSize = windowSize;
    this._options = options;
    this._buffer = [];
    this._sampledData = [];
  }

  addDataPoint(point) {
   
    this._buffer.push(point);

    // 维护滑动窗口
    if (this._buffer.length > this._windowSize) {
   
      this._buffer.shift();
    }

    // 定期重新采样
    if (this._buffer.length % 100 === 0) {
   
      this._resample();
    }
  }

  _resample() {
   
    const samplingEngine = new DataSamplingEngine(this._options);
    this._sampledData = samplingEngine.sample(this._buffer);
  }

  getSampledData() {
   
    return this._sampledData;
  }

  clear() {
   
    this._buffer = [];
    this._sampledData = [];
  }
}

2.1.2 分层级细节优化(LOD)

// 多层次细节管理系统
class LODManager {
   
  constructor(options = {
   }) {
   
    this._options = {
   
      zoomLevels: 5,           // 缩放层级数量
      pointsPerLevel: [1000, 5000, 20000, 50000, 100000], // 每层级点数
      autoSwitch: true,        // 自动切换层级
      ...options
    };

    this._currentLevel = 0;
    this._dataLevels = new Map();
    this._samplingEngine = new DataSamplingEngine();
  }

  // 预处理数据,生成多个层级
  preprocessData(rawData, dimensions) {
   
    this._dataLevels.clear();

    for (let level = 0; level < this._options.zoomLevels; level++) {
   
      const maxPoints = this._options.pointsPerLevel[level] || 
                       this._options.pointsPerLevel[this._options.pointsPerLevel.length - 1];

      const sampledData = this._samplingEngine.sample(rawData, {
   
        ...this._options,
        maxPoints: maxPoints
      }, dimensions);

      this._dataLevels.set(level, sampledData);
    }

    return this._dataLevels.get(0); // 返回最粗粒度数据
  }

  // 根据缩放级别获取合适的数据
  getDataForZoom(zoom, viewport) {
   
    const level = this._calculateLODLevel(zoom, viewport);

    if (level !== this._currentLevel) {
   
      this._currentLevel = level;
      return this._dataLevels.get(level);
    }

    return null; // 层级未变化,返回 null
  }

  _calculateLODLevel(zoom, viewport) {
   
    if (!this._options.autoSwitch) {
   
      return this._currentLevel;
    }

    // 基于缩放级别和视图范围计算合适的 LOD 层级
    const visibleDataPoints = this._estimateVisiblePoints(viewport);
    const totalDataPoints = this._dataLevels.get(0).length;

    const density = visibleDataPoints / totalDataPoints;

    // 根据数据密度选择层级
    if (density > 0.5) {
   
      return 0; // 最高细节
    } else if (density > 0.2) {
   
      return 1;
    } else if (density > 0.1) {
   
      return 2;
    } else if (density > 0.05) {
   
      return 3;
    } else {
   
      return 4; // 最低细节
    }
  }

  _estimateVisiblePoints(viewport) {
   
    // 简化的可见点估算
    const {
    width, height, dataExtent } = viewport;
    const totalArea = (dataExtent.xMax - dataExtent.xMin) * (dataExtent.yMax - dataExtent.yMin);
    const visibleArea = width * height;

    return Math.ceil((visibleArea / totalArea) * this._dataLevels.get(0).length);
  }

  // 动态更新数据
  updateData(newData, dimensions) {
   
    this.preprocessData(newData, dimensions);
  }

  getCurrentLevel() {
   
    return this._currentLevel;
  }

  getLevelStatistics() {
   
    const stats = {
   };

    this._dataLevels.forEach((data, level) => {
   
      stats[level] = {
   
        pointCount: data.length,
        memoryUsage: this._estimateMemoryUsage(data)
      };
    });

    return stats;
  }

  _estimateMemoryUsage(data) {
   
    // 估算内存使用量(字节)
    return data.length * 8 * 4; // 假设每个点有 8 个数字属性,每个数字 4 字节
  }
}

2.2 渲染性能优化技术

2.2.1 WebGL 大数据渲染优化

// 高性能 WebGL 渲染优化器
class WebGLRenderOptimizer {
   
  constructor(renderer) {
   
    this._renderer = renderer;
    this._optimizations = new Map();
    this._performanceMonitor = new PerformanceMonitor();
    this._initOptimizations();
  }

  _initOptimizations() {
   
    // 注册各种优化策略
    this._optimizations.set('instancing', this._setupInstancing.bind(this));
    this._optimizations.set('frustumCulling', this._setupFrustumCulling.bind(this));
    this._optimizations.set('levelOfDetail', this._setupLOD.bind(this));
    this._optimizations.set('batching', this._setupBatching.bind(this));
    this._optimizations.set('occlusionCulling', this._setupOcclusionCulling.bind(this));
  }

  // 实例化渲染优化
  _setupInstancing() {
   
    const gl = this._renderer._gl;

    // 创建实例化渲染程序
    const instancingVertexShader = `
      attribute vec2 a_position;
      attribute vec4 a_color;
      attribute vec2 a_offset;
      uniform mat4 u_projection;
      varying vec4 v_color;

      void main() {
        vec2 position = a_position + a_offset;
        gl_Position = u_projection * vec4(position, 0.0, 1.0);
        v_color = a_color;
        gl_PointSize = 3.0;
      }
    `;

    this._renderer._createProgram('instancing', instancingVertexShader, 
      this._renderer._getFragmentShaderSource('basic'));

    return {
   
      enabled: true,
      maxInstances: 100000,
      instanceSize: 4 // vec2 position + vec2 offset
    };
  }

  // 视锥体剔除
  _setupFrustumCulling() {
   
    return {
   
      enabled: true,
      checkInterval: 5, // 每5帧检查一次
      frustum: this._calculateFrustum()
    };
  }

  _calculateFrustum() {
   
    // 计算当前视锥体
    const projectionMatrix = this._renderer._getProjectionMatrix();
    // 从投影矩阵提取视锥体平面
    return this._extractFrustumPlanes(projectionMatrix);
  }

  _extractFrustumPlanes(matrix) {
   
    // 从投影矩阵提取视锥体平面方程
    const planes = [];

    // 提取左右上下远近平面
    for (let i = 0; i < 6; i++) {
   
      planes.push({
   
        normal: [0, 0, 0],
        constant: 0
      });
    }

    return planes;
  }

  // 层次细节
  _setupLOD() {
   
    return {
   
      enabled: true,
      levels: [
        {
    distance: 0, detail: 1.0 },   // 最近,最高细节
        {
    distance: 0.3, detail: 0.5 }, // 中等距离
        {
    distance: 0.6, detail: 0.2 }, // 较远距离
        {
    distance: 0.9, detail: 0.1 }  // 最远,最低细节
      ]
    };
  }

  // 批处理优化
  _setupBatching() {
   
    return {
   
      enabled: true,
      batchSize: 1000,
      dynamicBatching: true
    };
  }

  //  occlusion 剔除
  _setupOcclusionCulling() {
   
    const gl = this._renderer._gl;

    // 检查是否支持 occlusion query
    const occlusionQueryExtension = gl.getExtension('EXT_occlusion_query_boolean') ||
                                   gl.getExtension('MOZ_EXT_occlusion_query') ||
                                   gl.getExtension('WEBKIT_EXT_occlusion_query');

    return {
   
      enabled: !!occlusionQueryExtension,
      extension: occlusionQueryExtension,
      queries: new Map()
    };
  }

  // 应用优化
  applyOptimization(name, data, renderConfig) {
   
    const optimization = this._optimizations.get(name);
    if (!optimization) return data;

    const config = optimization();
    if (!config.enabled) return data;

    switch (name) {
   
      case 'frustumCulling':
        return this._applyFrustumCulling(data, config);
      case 'instancing':
        return this._applyInstancing(data, config, renderConfig);
      case 'levelOfDetail':
        return this._applyLOD(data, config, renderConfig);
      default:
        return data;
    }
  }

  _applyFrustumCulling(data, config) {
   
    // 简化的视锥体剔除
    const visibleData = [];
    const frustum = config.frustum;

    for (let i = 0; i < data.length; i++) {
   
      const point = data[i];
      if (this._isPointInFrustum(point, frustum)) {
   
        visibleData.push(point);
      }
    }

    this._performanceMonitor.recordCulling('frustum', data.length, visibleData.length);
    return visibleData;
  }

  _isPointInFrustum(point, frustum) {
   
    // 简化的点与视锥体检测
    // 实际实现需要检查所有6个平面
    return true; // 这里返回true,实际需要实现完整检测
  }

  _applyInstancing(data, config, renderConfig) {
   
    if (data.length > config.maxInstances) {
   
      console.warn(`数据量超过实例化渲染限制: ${
     data.length} > ${
     config.maxInstances}`);
      return data;
    }

    // 准备实例化数据
    const instanceData = this._prepareInstanceData(data, renderConfig);
    return instanceData;
  }

  _prepareInstanceData(data, renderConfig) {
   
    // 将数据转换为实例化渲染格式
    const instanceBuffer = [];

    data.forEach((point, index) => {
   
      // 添加位置和偏移量
      instanceBuffer.push(
        point.x, point.y,           // 基础位置
        (Math.random() - 0.5) * 0.1, // 随机偏移 x
        (Math.random() - 0.5) * 0.1  // 随机偏移 y
      );
    });

    return new Float32Array(instanceBuffer);
  }

  // 性能监控和自适应优化
  enableAdaptiveOptimization() {
   
    this._adaptiveEnabled = true;
    this._startAdaptiveLoop();
  }

  _startAdaptiveLoop() {
   
    const adaptiveLoop = () => {
   
      if (!this._adaptiveEnabled) return;

      const metrics = this._performanceMonitor.getMetrics();
      this._adjustOptimizations(metrics);

      setTimeout(adaptiveLoop, 1000); // 每秒调整一次
    };

    adaptiveLoop();
  }

  _adjustOptimizations(metrics) {
   
    const fps = metrics.fps;
    const memory = metrics.memory;

    // 根据性能指标动态调整优化策略
    if (fps < 30) {
   
      // 帧率低,启用更多优化
      this._enableAggressiveOptimizations();
    } else if (fps > 50) {
   
      // 帧率高,可以降低优化强度以提高质量
      this._enableQualityOptimizations();
    }
  }

  _enableAggressiveOptimizations() {
   
    this._optimizations.get('frustumCulling').enabled = true;
    this._optimizations.get('levelOfDetail').enabled = true;
    this._optimizations.get('occlusionCulling').enabled = true;
  }

  _enableQualityOptimizations() {
   
    this._optimizations.get('frustumCulling').enabled = true;
    this._optimizations.get('levelOfDetail').enabled = false;
    this._optimizations.get('occlusionCulling').enabled = false;
  }

  disableAdaptiveOptimization() {
   
    this._adaptiveEnabled = false;
  }
}

// 性能监控器
class PerformanceMonitor {
   
  constructor() {
   
    this._metrics = {
   
      fps: 0,
      frameTime: 0,
      memory: 0,
      drawCalls: 0,
      triangles: 0
    };

    this._history = [];
    this._maxHistorySize = 100;
    this._lastFrameTime = performance.now();
    this._frameCount = 0;

    this._startMonitoring();
  }

  _startMonitoring() {
   
    const monitorFrame = () => {
   
      this._updateMetrics();
      requestAnimationFrame(monitorFrame);
    };

    monitorFrame();
  }

  _updateMetrics() {
   
    const currentTime = performance.now();
    const deltaTime = currentTime - this._lastFrameTime;

    this._frameCount++;

    // 每秒更新一次 FPS
    if (deltaTime >= 1000) {
   
      this._metrics.fps = Math.round((this._frameCount * 1000) / deltaTime);
      this._metrics.frameTime = deltaTime / this._frameCount;

      this._frameCount = 0;
      this._lastFrameTime = currentTime;

      // 保存历史数据
      this._history.push({
    ...this._metrics, timestamp: currentTime });
      if (this._history.length > this._maxHistorySize) {
   
        this._history.shift();
      }
    }

    // 监控内存使用(如果可用)
    if (performance.memory) {
   
      this._metrics.memory = performance.memory.usedJSHeapSize;
    }
  }

  recordCulling(type, total, visible) {
   
    console.log(`[${
     type}] 剔除: ${
     total} -> ${
     visible} (${
     ((visible/total)*100).toFixed(1)}%)`);
  }

  recordDrawCall(count = 1) {
   
    this._metrics.drawCalls += count;
  }

  recordTriangles(count) {
   
    this._metrics.triangles += count;
  }

  getMetrics() {
   
    return {
    ...this._metrics };
  }

  getHistory() {
   
    return [...this._history];
  }

  getPerformanceReport() {
   
    const avgFps = this._history.reduce((sum, entry) => sum + entry.fps, 0) / this._history.length;
    const minFps = Math.min(...this._history.map(entry => entry.fps));

    return {
   
      averageFPS: Math.round(avgFps),
      minimumFPS: minFps,
      averageFrameTime: this._metrics.frameTime,
      peakMemory: Math.max(...this._history.map(entry => entry.memory))
    };
  }
}

2.2.2 增量渲染与数据流处理

// 增量渲染引擎
class IncrementalRenderer {
   
  constructor(renderer, options = {
   }) {
   
    this._renderer = renderer;
    this._options = {
   
      chunkSize: 1000,           // 每块数据大小
      renderInterval: 16,        // 渲染间隔(ms),~60fps
      progressive: true,         // 渐进式渲染
      ...options
    };

    this._queue = [];
    this._isRendering = false;
    this._renderedCount = 0;
    this._totalCount = 0;
    this._animationFrameId = null;
  }

  // 添加数据到渲染队列
  addData(data, priority = 0) {
   
    // 将大数据分割成小块
    const chunks = this._chunkData(data, this._options.chunkSize);

    chunks.forEach((chunk, index) => {
   
      this._queue.push({
   
        data: chunk,
        priority: priority,
        index: index,
        total: chunks.length
      });
    });

    this._totalCount += data.length;

    // 按优先级排序
    this._queue.sort((a, b) => b.priority - a.priority);

    // 开始渲染循环
    if (!this._isRendering) {
   
      this._startRendering();
    }
  }

  _chunkData(data, chunkSize) {
   
    const chunks = [];

    for (let i = 0; i < data.length; i += chunkSize) {
   
      chunks.push(data.slice(i, i + chunkSize));
    }

    return chunks;
  }

  _startRendering() {
   
    this._isRendering = true;
    this._renderLoop();
  }

  _renderLoop() {
   
    if (this._queue.length === 0) {
   
      this._isRendering = false;
      this._onComplete();
      return;
    }

    const startTime = performance.now();
    let renderedThisFrame = 0;

    // 在当前帧中渲染尽可能多的数据块
    while (this._queue.length > 0 && 
           performance.now() - startTime < this._options.renderInterval) {
   

      const chunk = this._queue.shift();
      this._renderChunk(chunk);
      renderedThisFrame += chunk.data.length;
    }

    this._renderedCount += renderedThisFrame;

    // 继续下一帧
    this._animationFrameId = requestAnimationFrame(() => {
   
      this._renderLoop();
    });
  }

  _renderChunk(chunk) {
   
    const {
    data, index, total } = chunk;

    // 使用渲染器渲染数据块
    this._renderer.renderChunk(data, {
   
      chunkIndex: index,
      totalChunks: total,
      progress: this._renderedCount / this._totalCount
    });

    // 触发进度事件
    this._onProgress({
   
      rendered: this._renderedCount,
      total: this._totalCount,
      progress: this._renderedCount / this._totalCount,
      chunk: index + 1,
      totalChunks: total
    });
  }

  _onProgress(progress) {
   
    // 可重写的方法,用于处理进度更新
    if (this._options.onProgress) {
   
      this._options.onProgress(progress);
    }

    // 触发自定义事件
    const event = new CustomEvent('incremental-render-progress', {
   
      detail: progress
    });
    document.dispatchEvent(event);
  }

  _onComplete() {
   
    console.log(`增量渲染完成: ${
     this._renderedCount} 个数据点`);

    if (this._options.onComplete) {
   
      this._options.onComplete({
   
        totalRendered: this._renderedCount,
        totalTime: performance.now() - this._startTime
      });
    }

    const event = new CustomEvent('incremental-render-complete', {
   
      detail: {
   
        totalRendered: this._renderedCount,
        totalTime: performance.now() - this._startTime
      }
    });
    document.dispatchEvent(event);
  }

  // 暂停渲染
  pause() {
   
    if (this._animationFrameId) {
   
      cancelAnimationFrame(this._animationFrameId);
      this._animationFrameId = null;
    }
    this._isRendering = false;
  }

  // 恢复渲染
  resume() {
   
    if (!this._isRendering && this._queue.length > 0) {
   
      this._startRendering();
    }
  }

  // 清空队列
  clear() {
   
    this.pause();
    this._queue = [];
    this._renderedCount = 0;
    this._totalCount = 0;
  }

  getStats() {
   
    return {
   
      queueLength: this._queue.length,
      renderedCount: this._renderedCount,
      totalCount: this._totalCount,
      progress: this._totalCount > 0 ? this._renderedCount / this._totalCount : 0
    };
  }
}

// 数据流处理器
class DataStreamProcessor {
   
  constructor(options = {
   }) {
   
    this._options = {
   
      bufferSize: 10000,        // 缓冲区大小
      processInterval: 100,     // 处理间隔(ms)
      maxRetention: 100000,     // 最大保留数据点
      ...options
    };

    this._buffer = [];
    this._processedData = [];
    this._isProcessing = false;
    this._samplingEngine = new DataSamplingEngine();
    this._listeners = new Map();
  }

  // 添加流数据
  addStreamData(data) {
   
    this._buffer.push(...data);

    // 维护缓冲区大小
    if (this._buffer.length > this._options.bufferSize * 2) {
   
      this._buffer = this._buffer.slice(-this._options.bufferSize);
    }

    // 启动处理循环
    if (!this._isProcessing) {
   
      this._startProcessing();
    }
  }

  _startProcessing() {
   
    this._isProcessing = true;
    this._processLoop();
  }

  _processLoop() {
   
    if (this._buffer.length === 0) {
   
      this._isProcessing = false;
      return;
    }

    // 处理当前缓冲区数据
    const processStart = performance.now();
    const chunk = this._buffer.splice(0, this._options.bufferSize);

    // 采样和处理数据
    const processedChunk = this._processChunk(chunk);
    this._updateProcessedData(processedChunk);

    const processTime = performance.now() - processStart;

    // 通知监听器
    this._notifyListeners('dataProcessed', {
   
      chunkSize: chunk.length,
      processTime: processTime,
      totalProcessed: this._processedData.length
    });

    // 继续处理
    setTimeout(() => {
   
      this._processLoop();
    }, this._options.processInterval);
  }

  _processChunk(chunk) {
   
    // 应用数据采样
    return this._samplingEngine.sample(chunk, {
   
      maxPoints: Math.min(1000, chunk.length / 10)
    });
  }

  _updateProcessedData(newData) {
   
    this._processedData.push(...newData);

    // 维护数据总量
    if (this._processedData.length > this._options.maxRetention) {
   
      this._processedData = this._processedData.slice(-this._options.maxRetention);
    }
  }

  // 获取处理后的数据
  getProcessedData() {
   
    return [...this._processedData];
  }

  // 添加事件监听器
  addListener(event, callback) {
   
    if (!this._listeners.has(event)) {
   
      this._listeners.set(event, []);
    }
    this._listeners.get(event).push(callback);
  }

  _notifyListeners(event, data) {
   
    const listeners = this._listeners.get(event);
    if (listeners) {
   
      listeners.forEach(callback => callback(data));
    }
  }

  // 清空数据
  clear() {
   
    this._buffer = [];
    this._processedData = [];
    this._isProcessing = false;
  }

  getStatistics() {
   
    return {
   
      bufferSize: this._buffer.length,
      processedSize: this._processedData.length,
      isProcessing: this._isProcessing
    };
  }
}

2.3 ECharts 百万数据集成方案

// ECharts 百万数据集成包装器
class EChartsMillionDataAdapter {
   
  constructor(chart, options = {
   }) {
   
    this._chart = chart;
    this._options = {
   
      useSampling: true,
      useIncremental: true,
      useWebGL: true,
      maxPoints: 10000,
      ...options
    };

    this._samplingEngine = new DataSamplingEngine({
   
      maxPoints: this._options.maxPoints
    });

    this._lodManager = new LODManager();
    this._incrementalRenderer = null;
    this._webglRenderer = null;

    this._initialize();
  }

  _initialize() {
   
    // 初始化增量渲染器
    if (this._options.useIncremental) {
   
      this._incrementalRenderer = new IncrementalRenderer(this, {
   
        chunkSize: 1000,
        onProgress: this._onRenderProgress.bind(this),
        onComplete: this._onRenderComplete.bind(this)
      });
    }

    // 初始化 WebGL 渲染器
    if (this._options.useWebGL) {
   
      this._initWebGLRenderer();
    }

    // 监听图表事件
    this._bindChartEvents();
  }

  _initWebGLRenderer() {
   
    try {
   
      this._webglRenderer = new AdvancedWebGLRenderer(this._chart.getDom());
      this._webglOptimizer = new WebGLRenderOptimizer(this._webglRenderer);
    } catch (error) {
   
      console.warn('WebGL 初始化失败,回退到 Canvas:', error);
      this._options.useWebGL = false;
    }
  }

  // 设置大数据
  setBigData(seriesIndex, rawData, dimensions = ['x', 'y']) {
   
    const series = this._chart.getOption().series[seriesIndex];
    if (!series) {
   
      console.error(`系列 ${
     seriesIndex} 不存在`);
      return;
    }

    let processedData;

    if (this._options.useSampling) {
   
      // 使用采样数据
      processedData = this._samplingEngine.sample(rawData, dimensions);

      // 预处理 LOD 数据
      this._lodManager.preprocessData(rawData, dimensions);
    } else {
   
      processedData = rawData;
    }

    // 更新图表数据
    if (this._options.useIncremental && rawData.length > 50000) {
   
      this._setDataIncremental(seriesIndex, processedData);
    } else {
   
      this._setDataDirect(seriesIndex, processedData);
    }

    // 保存原始数据引用
    this._originalData = rawData;
  }

  _setDataIncremental(seriesIndex, data) {
   
    this._incrementalRenderer.addData(data, 1);
  }

  _setDataDirect(seriesIndex, data) {
   
    this._chart.setOption({
   
      series: [{
   
        ...this._chart.getOption().series[seriesIndex],
        data: data
      }]
    });
  }

  _onRenderProgress(progress) {
   
    // 更新进度显示
    console.log(`渲染进度: ${
     (progress.progress * 100).toFixed(1)}%`);

    // 可以在这里更新进度条等UI
  }

  _onRenderComplete(result) {
   
    console.log(`渲染完成,总计 ${
     result.totalRendered} 个点,耗时 ${
     result.totalTime}ms`);
  }

  _bindChartEvents() {
   
    // 监听数据缩放事件,动态调整 LOD
    this._chart.on('datazoom', (params) => {
   
      this._onDataZoom(params);
    });

    // 监听渲染完成事件
    this._chart.on('rendered', (params) => {
   
      this._onChartRendered(params);
    });
  }

  _onDataZoom(params) {
   
    if (!this._options.useSampling || !this._lodManager) {
   
      return;
    }

    const zoom = params.zoom;
    const viewport = this._getCurrentViewport();

    const newData = this._lodManager.getDataForZoom(zoom, viewport);
    if (newData) {
   
      this._updateChartData(newData);
    }
  }

  _getCurrentViewport() {
   
    const option = this._chart.getOption();
    const xAxis = option.xAxis[0];
    const yAxis = option.yAxis[0];

    return {
   
      width: this._chart.getWidth(),
      height: this._chart.getHeight(),
      dataExtent: {
   
        xMin: xAxis.min || 0,
        xMax: xAxis.max || 100,
        yMin: yAxis.min || 0,
        yMax: yAxis.max || 100
      }
    };
  }

  _updateChartData(data) {
   
    // 使用增量更新避免界面卡顿
    this._chart.setOption({
   
      series: [{
   
        data: data
      }]
    }, {
   
      replaceMerge: ['series']
    });
  }

  _onChartRendered(params) {
   
    // 图表渲染完成后的处理
    this._updatePerformanceStats();
  }

  _updatePerformanceStats() {
   
    const stats = {
   
      sampling: this._samplingEngine.getStatistics(),
      lod: this._lodManager ? this._lodManager.getLevelStatistics() : null,
      incremental: this._incrementalRenderer ? this._incrementalRenderer.getStats() : null
    };

    console.log('性能统计:', stats);
  }

  // 动态更新选项
  updateOptions(newOptions) {
   
    this._options = {
    ...this._options, ...newOptions };

    // 重新初始化相关组件
    if (newOptions.useWebGL && !this._webglRenderer) {
   
      this._initWebGLRenderer();
    }
  }

  // 销毁资源
  dispose() {
   
    if (this._incrementalRenderer) {
   
      this._incrementalRenderer.clear();
    }

    if (this._webglRenderer) {
   
      this._webglRenderer.dispose();
    }

    // 移除事件监听
    this._chart.off('datazoom');
    this._chart.off('rendered');
  }

  // 获取性能报告
  getPerformanceReport() {
   
    const baseReport = this._chart.getModel().getPerformanceReport();
    const samplingStats = this._samplingEngine.getStatistics();

    return {
   
      ...baseReport,
      sampling: samplingStats,
      dataReduction: {
   
        original: this._originalData ? this._originalData.length : 0,
        displayed: this._getDisplayedDataCount(),
        reduction: this._originalData ? 
          (1 - this._getDisplayedDataCount() / this._originalData.length) * 100 : 0
      }
    };
  }

  _getDisplayedDataCount() {
   
    const series = this._chart.getOption().series[0];
    return series.data ? series.data.length : 0;
  }
}

// 使用示例
function createMillionDataChart(dom) {
   
  // 创建图表实例
  const chart = echarts.init(dom);

  // 创建大数据适配器
  const adapter = new EChartsMillionDataAdapter(chart, {
   
    useSampling: true,
    useIncremental: true,
    useWebGL: true,
    maxPoints: 5000
  });

  // 生成模拟大数据
  const millionData = generateMockData(1000000);

  // 设置数据
  adapter.setBigData(0, millionData, ['x', 'y']);

  // 基础配置
  chart.setOption({
   
    title: {
    text: '百万数据点性能演示' },
    tooltip: {
    trigger: 'axis' },
    xAxis: {
    type: 'value' },
    yAxis: {
    type: 'value' },
    series: [{
   
      type: 'scatter',
      symbolSize: 3,
      itemStyle: {
    opacity: 0.6 }
    }]
  });

  return {
    chart, adapter };
}

// 模拟数据生成
function generateMockData(count) {
   
  const data = [];

  for (let i = 0; i < count; i++) {
   
    data.push({
   
      x: Math.random() * 1000,
      y: Math.random() * 1000,
      value: Math.random() * 100
    });
  }

  return data;
}

三、性能对比与优化效果评估

优化技术 数据量 渲染时间 内存占用 交互流畅度
原生 Canvas 10万点 1200ms 85MB 卡顿
数据采样 10万点 180ms 25MB 良好
WebGL 渲染 10万点 45ms 15MB 流畅
增量渲染 100万点 分块加载 可控 良好
LOD 系统 动态数据 自适应 优化 优秀

四、总结

我们建立了完整的 ECharts 高级优化技术体系。以下是关键要点的总结:

  • 自定义渲染器开发
  • 大数据处理策略
  • 性能优化体系


关于作者



🌟 我是suxiaoxiang,一位热爱技术的开发者

💡 专注于Java生态和前沿技术分享

🚀 持续输出高质量技术内容



如果这篇文章对你有帮助,请支持一下:




👍 点赞


收藏


👀 关注



您的支持是我持续创作的动力!感谢每一位读者的关注与认可!


目录
相关文章
|
9天前
|
机器人 API 调度
基于 DMS Dify+Notebook+Airflow 实现 Agent 的一站式开发
本文提出“DMS Dify + Notebook + Airflow”三位一体架构,解决 Dify 在代码执行与定时调度上的局限。通过 Notebook 扩展 Python 环境,Airflow实现任务调度,构建可扩展、可运维的企业级智能 Agent 系统,提升大模型应用的工程化能力。
|
人工智能 前端开发 API
前端接入通义千问(Qwen)API:5 分钟实现你的 AI 问答助手
本文介绍如何在5分钟内通过前端接入通义千问(Qwen)API,快速打造一个AI问答助手。涵盖API配置、界面设计、流式响应、历史管理、错误重试等核心功能,并提供安全与性能优化建议,助你轻松集成智能对话能力到前端应用中。
674 154
|
15天前
|
人工智能 数据可视化 Java
Spring AI Alibaba、Dify、LangGraph 与 LangChain 综合对比分析报告
本报告对比Spring AI Alibaba、Dify、LangGraph与LangChain四大AI开发框架,涵盖架构、性能、生态及适用场景。数据截至2025年10月,基于公开资料分析,实际发展可能随技术演进调整。
939 152
|
负载均衡 Java 微服务
OpenFeign:让微服务调用像本地方法一样简单
OpenFeign是Spring Cloud中声明式微服务调用组件,通过接口注解简化远程调用,支持负载均衡、服务发现、熔断降级、自定义拦截器与编解码,提升微服务间通信开发效率与系统稳定性。
357 156
|
7天前
|
分布式计算 监控 API
DMS Airflow:企业级数据工作流编排平台的专业实践
DMS Airflow 是基于 Apache Airflow 构建的企业级数据工作流编排平台,通过深度集成阿里云 DMS(Data Management Service)系统的各项能力,为数据团队提供了强大的工作流调度、监控和管理能力。本文将从 Airflow 的高级编排能力、DMS 集成的特殊能力,以及 DMS Airflow 的使用示例三个方面,全面介绍 DMS Airflow 的技术架构与实践应用。
|
7天前
|
人工智能 自然语言处理 前端开发
Qoder全栈开发实战指南:开启AI驱动的下一代编程范式
Qoder是阿里巴巴于2025年发布的AI编程平台,首创“智能代理式编程”,支持自然语言驱动的全栈开发。通过仓库级理解、多智能体协同与云端沙箱执行,实现从需求到上线的端到端自动化,大幅提升研发效率,重塑程序员角色,引领AI原生开发新范式。
456 2