Skip to content

性能优化

RayChart 内置多项性能优化,但处理大数据量时,仍需注意以下几点。

数据量控制

建议的数据量

  • 柱状图/折线图: 建议不超过 1000 个数据点
  • 散点图: 建议不超过 5000 个数据点
  • 饼图: 建议不超过 50 个分类
  • 雷达图: 建议不超过 20 个指标

数据采样

大数据量时用采样减少渲染:

javascript
// 原始数据
const rawData = Array.from({ length: 10000 }, (_, i) => i)

// 采样到 1000 个点
const sampledData = rawData.filter((_, i) => i % 10 === 0)

const option = {
  series: [{
    data: sampledData
  }],
  xAxis3D: {
    type: 'value'
  }
}

数据聚合

将数据聚合到更粗的粒度:

javascript
// 按小时聚合分钟数据
const aggregatedData = minuteData.reduce((acc, item, i) => {
  const hourIndex = Math.floor(i / 60)
  if (!acc[hourIndex]) {
    acc[hourIndex] = { sum: 0, count: 0 }
  }
  acc[hourIndex].sum += item.value
  acc[hourIndex].count++
  return acc
}, []).map(item => item.sum / item.count)

渲染优化

避免频繁更新

javascript
// ❌ 不好的做法
setInterval(() => {
  chartOption.value = { ...chartOption.value, series: [newData] }
}, 100)

// ✅ 好的做法
setInterval(() => {
  chartOption.value = { ...chartOption.value, series: [newData] }
}, 1000)

使用 v-if 而非 v-show

vue
<!-- ❌ 不好的做法 -->
<RayBar v-show="visible" :option="option" />

<!-- ✅ 好的做法 -->
<RayBar v-if="visible" :option="option" />

及时销毁

vue
<script setup>
import { ref, onUnmounted } from 'vue'

const chartRef = ref()

onUnmounted(() => {
  // 组件销毁时清理资源
  chartRef.value?.dispose()
})
</script>

资源管理

LRU 缓存

RayChart 用 LRU(最近最少使用)缓存自动管理资源:

  • 材质复用 - 相同配置的材质会被复用
  • 几何体复用 - 相同形状的几何体会被复用
  • 自动清理 - 未使用的资源会被自动清理

缓存配置

javascript
// 默认配置
{
  cacheSize: 100  // 每种资源类型最多缓存 100 个
}

性能数据

场景优化前优化后提升
缓存命中率~70%~85%+21%
内存使用(1h)150MB95MB-37%
内存使用(4h)300MB+110MB-63%

性能监控

使用性能监控

RayChart 内置性能监控:

javascript
import { globalMonitor } from 'raychart'

// 获取性能统计
const stats = globalMonitor.getStats()
console.log('FPS:', stats.fps)
console.log('Memory:', stats.memory)
console.log('Render time:', stats.renderTime)

监控指标

  • FPS - 帧率,建议保持在 30+ FPS
  • Memory - 内存使用,监控是否有内存泄漏
  • Render Time - 渲染时间,单帧渲染时间

性能分析

javascript
// 开始性能分析
const startTime = globalMonitor.start('myOperation')

// 执行操作
// ...

// 结束性能分析
globalMonitor.end('myOperation', startTime)

// 获取统计
const stats = globalMonitor.getOperationStats('myOperation')
console.log('Average time:', stats.averageTime)
console.log('Total calls:', stats.totalCalls)

图表配置优化

降低复杂度

javascript
// ❌ 高复杂度
{
  series: [{
    data: largeDataset,
    itemStyle: {
      metalness: 0.8,
      roughness: 0.2,
      // 复杂的材质配置
    }
  }],
  postprocessing: {
    enable: true,
    bloom: { enable: true },
    SSAO: { enable: true }  // 性能消耗大
  }
}

// ✅ 优化后
{
  series: [{
    data: sampledDataset,  // 采样后的数据
    itemStyle: {
      metalness: 0.3,
      roughness: 0.5
    }
  }],
  postprocessing: {
    enable: true,
    FXAA: { enable: true }  // 仅启用轻量级效果
  }
}

简化光照

javascript
// ❌ 过多光源 - 手动配置过多光源
{
  series: [{ data: [120, 200, 150] }],
  lights: [
    { type: 'Ambient', intensity: 0.3 },
    { type: 'Directional', intensity: 1.0, position: { x: 5, y: 10, z: 5 } },
    { type: 'Point', intensity: 0.8, position: { x: -5, y: 5, z: 5 } },
    { type: 'Point', intensity: 0.6, position: { x: 5, y: 5, z: -5 } },
    { type: 'Spot', intensity: 1.0, position: { x: 0, y: 10, z: 0 } }
  ]
}

// ✅ 使用默认光照 - 框架自动配置
{
  series: [{ data: [120, 200, 150] }],
  xAxis3D: { data: ['A', 'B', 'C'] }
  // 光照会自动配置,无需手动指定
}

移动端优化

检测设备

javascript
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)

const option = {
  series: [{
    data: isMobile ? sampledData : fullData
  }],
  xAxis3D: {
    data: categories
  },
  postprocessing: {
    enable: !isMobile  // 移动端禁用后处理
  },
  controlSettings: {
    rotateSpeed: isMobile ? 0.5 : 1.0  // 移动端降低速度
  }
}

降低分辨率

vue
<template>
  <RayBar 
    :option="option" 
    :width="isMobile ? '100%' : '800px'"
    :height="isMobile ? '400px' : '600px'"
  />
</template>

性能检查清单

开发阶段

  • [ ] 数据量是否在建议范围内
  • [ ] 是否使用了数据采样或聚合
  • [ ] 是否避免了频繁更新
  • [ ] 是否正确使用 v-if
  • [ ] 是否在组件销毁时清理资源

优化阶段

  • [ ] 是否启用了性能监控
  • [ ] FPS 是否稳定在 30+
  • [ ] 内存使用是否稳定
  • [ ] 是否简化了光照配置
  • [ ] 是否按需启用后处理效果

移动端

  • [ ] 是否检测了移动设备
  • [ ] 是否降低了数据量
  • [ ] 是否禁用了后处理
  • [ ] 是否降低了交互速度
  • [ ] 是否测试了实际设备

性能基准

桌面端(推荐配置)

  • CPU: Intel i5 或同等性能
  • GPU: 独立显卡或集成显卡
  • 内存: 8GB+
  • 浏览器: Chrome/Firefox/Edge 最新版

性能表现:

  • 1000 数据点: 60 FPS
  • 5000 数据点: 30-60 FPS
  • 10000 数据点: 需要优化

移动端(推荐配置)

  • 设备: iPhone 8+ / Android 中高端设备
  • 浏览器: Safari/Chrome 最新版

性能表现:

  • 500 数据点: 30-60 FPS
  • 1000 数据点: 需要优化
  • 建议禁用后处理效果

常见问题

Q: 图表卡顿怎么办?

A:

  1. 减少数据量
  2. 禁用后处理效果
  3. 简化光照配置
  4. 降低更新频率

Q: 内存持续增长?

A:

  1. 检查是否有内存泄漏
  2. 确保组件销毁时调用 dispose()
  3. 避免创建过多图表实例

Q: 移动端性能差?

A:

  1. 大幅减少数据量
  2. 禁用所有后处理效果
  3. 使用简单的材质配置
  4. 降低分辨率

性能优化案例

案例 1: 大数据量折线图

问题: 10000 个数据点导致卡顿

解决方案:

javascript
// 使用道格拉斯-普克算法简化曲线
const simplifiedData = simplifyPolyline(rawData, tolerance)

const option = {
  series: [{
    data: simplifiedData  // 简化后约 500 个点
  }],
  xAxis3D: {
    type: 'value'
  }
}

结果: FPS 从 15 提升到 60

案例 2: 多图表页面

问题: 页面有 10 个图表,内存占用高

解决方案:

vue
<template>
  <div v-for="chart in visibleCharts" :key="chart.id">
    <component :is="chart.component" v-if="chart.visible" :option="chart.option" />
  </div>
</template>

<script setup>
import { RayBar, RayLine, RayPie } from 'raychart'

// 使用虚拟滚动,只渲染可见的图表
const visibleCharts = computed(() => {
  return charts.value.filter(chart => isInViewport(chart))
})
</script>

结果: 内存占用从 800MB 降到 200MB