Skip to content

3D 曲面图

3D 曲面图用于展示二维网格数据的高度分布,通过连续曲面表现数据趋势,适用于地形数据、数学函数可视化、科学计算等场景。

快速开始

最简单的 3D 曲面图只需提供二维数组数据:

vue
<template>
  <RaySurface3D :option="chartOption" />
</template>

<script setup>
import { ref } from 'vue';
import { RaySurface3D } from 'raychart';

// 生成简单的波浪曲面数据
function generateWaveSurface() {
  const data = [];
  for (let z = 0; z < 40; z++) {
    const row = [];
    for (let x = 0; x < 40; x++) {
      const xVal = (x / 39) * Math.PI * 2;
      const zVal = (z / 39) * Math.PI * 2;
      row.push(Math.sin(xVal) * Math.cos(zVal) * 4 + 5);
    }
    data.push(row);
  }
  return data;
}

const chartOption = ref({
  grid3D: { show: true },
  xAxis3D: { show: true },
  yAxis3D: { show: true },
  zAxis3D: { show: true },
  series: [
    {
      type: 'surface3D',
      name: '波浪曲面',
      data: generateWaveSurface(),
    },
  ],
});
</script>

数据格式说明

data 支持三种格式:

  • 二维数组 number[][]:第一维(行)对应 Z 轴方向,第二维(列)对应 X 轴方向,数值对应 Y 轴(高度)
  • 函数 (x, z) => y:按需采样生成曲面
  • 对象数组 [{x, z, value}, ...]

核心配置

数据配置

属性类型默认值说明
series.typestring-必须为 'surface3D'
series.datanumber[][]-二维网格数据(必填)
series.namestring-系列名称(用于图例和提示)

样式配置

属性类型默认值说明
series.itemStyleobject-曲面材质配置
series.itemStyle.opacitynumber0.9透明度(0-1)
series.itemStyle.roughnessnumber0.4粗糙度(0-1,影响反光)
series.itemStyle.metalnessnumber0.1金属度(0-1)
series.itemStyle.clearcoatnumber0.3清漆层强度(0-1)
series.colorGradientArray<{stop, color}>内置 9 色渐变(蓝→红)曲面颜色映射
线框配置(可选)

通过 series.wireframe 配置线框网格:

javascript
wireframe: {
  show: true,          // 显示线框(默认 true)
  color: '#ffffff',    // 线框颜色(默认 '#ffffff')
  opacity: 0.15        // 线框透明度(默认 0.15)
}

线框可以帮助用户更好地理解曲面的网格结构和曲率变化。

曲面细分配置(进阶)

通过调整数据网格密度控制曲面细分:

javascript
// 更密集的网格(50x50)可以提供更平滑的曲面
const data = generateSurface(mathFunction, 50, 50);

// 稀疏网格(20x20)适用于简单曲面或性能优化
const data = generateSurface(mathFunction, 20, 20);

网格密度越高,曲面越平滑,但渲染性能会降低。建议在 20-60 之间选择合适的值。

坐标系配置

通过 grid3DxAxis3DyAxis3DzAxis3D 配置坐标系:

javascript
grid3D: {
  show: true,          // 显示网格盒子
  boxWidth: 20,        // 盒子宽度(X 轴)
  boxHeight: 10        // 盒子高度(Y 轴)
}

盒子高度建议根据数据范围调整,以获得最佳视觉效果。

常见场景

数学函数曲面

展示数学函数 y = sin(x) * cos(z) 的三维形态:

vue
<template>
  <RaySurface3D :option="chartOption" />
</template>

<script setup>
import { ref } from 'vue';
import { RaySurface3D } from 'raychart';

// 生成数学函数曲面
function generateMathSurface(fn, xSteps, zSteps) {
  const data = [];
  for (let z = 0; z < zSteps; z++) {
    const row = [];
    for (let x = 0; x < xSteps; x++) {
      const xVal = (x / (xSteps - 1)) * Math.PI * 2;
      const zVal = (z / (zSteps - 1)) * Math.PI * 2;
      row.push(fn(xVal, zVal));
    }
    data.push(row);
  }
  return data;
}

const chartOption = ref({
  lights: [
    { id: '1', type: 'Ambient', color: '#ffffff', intensity: 0.5 },
    {
      id: '2',
      type: 'Directional',
      color: '#fffdf4',
      intensity: 1.0,
      position: { x: 10, y: 15, z: 10 },
      castShadow: true,
    },
  ],
  grid3D: { show: true, boxWidth: 20, boxHeight: 10 },
  xAxis3D: { show: true },
  yAxis3D: { show: true },
  zAxis3D: { show: true },
  series: [
    {
      type: 'surface3D',
      name: '波浪曲面',
      data: generateMathSurface((x, z) => Math.sin(x) * Math.cos(z) * 4 + 5, 40, 40),
      wireframe: { show: true, opacity: 0.15 },
      itemStyle: { opacity: 0.9, roughness: 0.4, metalness: 0.1 },
    },
  ],
});
</script>

马鞍面(双曲抛物面)

展示经典的马鞍面数学模型 y = x² - z²

vue
<script setup>
const chartOption = ref({
  lights: [
    { id: '1', type: 'Ambient', color: '#ffffff', intensity: 0.6 },
    {
      id: '2',
      type: 'Directional',
      color: '#fffdf4',
      intensity: 1.0,
      position: { x: 10, y: 15, z: 10 },
      castShadow: true,
    },
  ],
  grid3D: { show: true, boxWidth: 20, boxHeight: 10 },
  xAxis3D: { show: true },
  yAxis3D: { show: true },
  zAxis3D: { show: true },
  series: [
    {
      type: 'surface3D',
      name: '马鞍面',
      data: generateMathSurface((x, z) => {
        const nx = x / Math.PI - 1; // 归一化到 [-1, 1]
        const nz = z / Math.PI - 1;
        return (nx * nx - nz * nz) * 4 + 5;
      }, 40, 40),
      wireframe: { show: true, opacity: 0.15 },
      itemStyle: {
        opacity: 0.9,
        roughness: 0.4,
        metalness: 0.1,
      },
    },
  ],
});
</script>

涟漪曲面(径向波)

模拟水面涟漪效果 y = sin(r) / r

vue
<script setup>
const chartOption = ref({
  lights: [
    { id: '1', type: 'Ambient', color: '#ffffff', intensity: 0.5 },
    { id: '2', type: 'Directional', color: '#4facfe', intensity: 0.8, position: { x: -10, y: 15, z: 10 } },
    { id: '3', type: 'Point', color: '#f093fb', intensity: 0.5, position: { x: 0, y: 20, z: 0 } },
  ],
  grid3D: { show: true, boxWidth: 20, boxHeight: 10 },
  xAxis3D: { show: true },
  yAxis3D: { show: true },
  zAxis3D: { show: true },
  series: [
    {
      type: 'surface3D',
      name: '涟漪',
      data: generateMathSurface((x, z) => {
        const nx = x - Math.PI; // 中心化
        const nz = z - Math.PI;
        const r = Math.sqrt(nx * nx + nz * nz); // 到中心的距离
        return (Math.sin(r) / (r + 0.001)) * 5 + 5; // 避免除零
      }, 50, 50),
      wireframe: { show: true, opacity: 0.1 },
      itemStyle: {
        opacity: 0.88,
        roughness: 0.3,
        metalness: 0.15,
      },
    },
  ],
});
</script>

地形高度图

使用真实的地形数据展示海拔分布:

vue
<script setup>
// 模拟地形数据(实际项目中可从后端或 GeoTIFF 加载)
function generateTerrainData() {
  const data = [];
  for (let z = 0; z < 30; z++) {
    const row = [];
    for (let x = 0; x < 30; x++) {
      // 模拟山峰:使用多个高斯分布叠加
      const peak1 = Math.exp(-((x - 10) ** 2 + (z - 10) ** 2) / 20) * 8;
      const peak2 = Math.exp(-((x - 20) ** 2 + (z - 15) ** 2) / 30) * 6;
      const noise = Math.sin(x * 0.3) * Math.cos(z * 0.3) * 0.5;
      row.push(peak1 + peak2 + noise + 2); // 基础海拔 2
    }
    data.push(row);
  }
  return data;
}

const chartOption = ref({
  lights: [
    { id: '1', type: 'Ambient', color: '#ffffff', intensity: 0.7 },
    {
      id: '2',
      type: 'Directional',
      color: '#fffdf4',
      intensity: 1.2,
      position: { x: 15, y: 20, z: 15 },
      castShadow: true,
    },
  ],
  grid3D: { show: true, boxWidth: 20, boxHeight: 12 },
  xAxis3D: { name: '经度' },
  yAxis3D: { name: '海拔(m)' },
  zAxis3D: { name: '纬度' },
  series: [
    {
      type: 'surface3D',
      name: '地形',
      data: generateTerrainData(),
      wireframe: { show: false }, // 地形图通常不显示线框
      itemStyle: {
        opacity: 1.0,
        roughness: 0.8, // 粗糙表面模拟土壤质感
        metalness: 0.0,
      },
    },
  ],
});
</script>

组件属性

属性类型默认值说明
optionRayChartOption-图表配置对象(必填)
widthstring | number'100%'图表宽度
heightstring | number'600px'图表高度

相关文档

基础学习

进阶主题

API 参考

其他图表类型

在线示例