
该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:
依赖前置
scatter3d 三维图表依赖扩展包:highcharts-3d.js,必须引入才能渲染三维坐标轴、拖拽旋转逻辑。
代码分模块深度解析
模块 1:全局渐变统一配置 Highcharts.setOptions
Highcharts.setOptions({
colors: Highcharts.getOptions().colors.map(function (color) {
return {
radialGradient: { cx: 0.4, cy: 0.3, r: 0.5 },
stops: [
[0, color],
[1, Highcharts.color(color).brighten(-0.2).get('rgb')]
]
};
})
});
模块 2:Chart 画布与 3D 核心配置
chart: {
renderTo: 'container',
margin: 100,
type: 'scatter3d',
animation: false,
options3d: {
enabled: true,
alpha: 10, // 垂直俯仰角度
beta: 30, // 水平旋转角度
depth: 250, // 三维纵深深度
viewDistance: 5,
fitToPlot: false,
frame: { // 立方体三维边框
bottom: { size: 1, color: 'rgba(0,0,0,0.02)' },
back: { size: 1, color: 'rgba(0,0,0,0.04)' },
side: { size: 1, color: 'rgba(0,0,0,0.06)' }
}
}
}
关键 3D 参数说明:
- alpha:上下俯仰角度,数值越大俯视越明显;
- beta:左右水平旋转角度;
- depth:控制 3D 透视拉伸程度;
- frame:绘制立方体底面、背面、侧面边框,打造封闭空间盒子;
- animation: false:关闭渲染动画,拖拽旋转更流畅。
模块 3:散点样式 plotOptions
plotOptions: {
scatter: {
width: 10,
height: 10,
depth: 10
}
}
三维散点长宽高统一为 10 单位,形成标准正立方体小球,长宽深一致保证球体不变形。
模块 4:三轴坐标轴配置
xAxis/yAxis/zAxis: { min:0, max:10 }
三轴统一值域 0~10,构成规整立方体空间;隐藏 Z 轴首刻度、Y 轴标题,简化画布视觉。
模块 5:数据系列 Series
series: [{
name: 'Data',
colorByPoint: true, // 每个点自动分配不同渐变颜色
data: [ [x,y,z], [x,y,z], … ]
}]
模块 6:自定义拖拽旋转事件(核心交互扩展)
原生 3D 图表无内置拖拽旋转逻辑,代码手动封装鼠标 / 触屏拖拽:
可运行代码
html 预览
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>3D可拖拽立方体散点图</title>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-3d.js"></script>
<style>
#container {
width: 100%;
height: 650px;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
// 全局配置:散点径向渐变,实现3D圆球质感
Highcharts.setOptions({
colors: Highcharts.getOptions().colors.map(function (color) {
return {
radialGradient: {
cx: 0.4,
cy: 0.3,
r: 0.5
},
stops: [
[0, color],
[1, Highcharts.color(color).brighten(-0.2).get('rgb')]
]
};
})
});
// 初始化3D图表
const chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
margin: 100,
type: 'scatter3d',
animation: false,
options3d: {
enabled: true,
alpha: 10,
beta: 30,
depth: 250,
viewDistance: 5,
fitToPlot: false,
frame: {
bottom: { size: 1, color: 'rgba(0,0,0,0.02)' },
back: { size: 1, color: 'rgba(0,0,0,0.04)' },
side: { size: 1, color: 'rgba(0,0,0,0.06)' }
}
}
},
title: {
text: '可拖拽三维立方体散点图'
},
subtitle: {
text: '按住鼠标拖动画布,可360°旋转三维空间'
},
plotOptions: {
scatter: {
width: 10,
height: 10,
depth: 10
}
},
yAxis: {
min: 0,
max: 10,
title: { text: 'Y轴' }
},
xAxis: {
min: 0,
max: 10,
title: { text: 'X轴' },
gridLineWidth: 1
},
zAxis: {
min: 0,
max: 10,
title: { text: 'Z轴' },
showFirstLabel: false
},
legend: {
enabled: false
},
series: [{
name: '空间采样点',
colorByPoint: true,
accessibility: {
exposeAsGroupOnly: true
},
data: [
[1, 6, 5], [8, 7, 9], [1, 3, 4], [4, 6, 8], [5, 7, 7], [6, 9, 6],
[7, 0, 5], [2, 3, 3], [3, 9, 8], [3, 6, 5], [4, 9, 4], [2, 3, 3],
[6, 9, 9], [0, 7, 0], [7, 7, 9], [7, 2, 9], [0, 6, 2], [4, 6, 7],
[3, 7, 7], [0, 1, 7], [2, 8, 6], [2, 3, 7], [6, 4, 8], [3, 5, 9],
[7, 9, 5], [3, 1, 7], [4, 4, 2], [3, 6, 2], [3, 1, 6], [6, 8, 5],
[6, 6, 7], [4, 1, 1], [7, 2, 7], [7, 7, 0], [8, 8, 9], [9, 4, 1],
[8, 3, 4], [9, 8, 9], [3, 5, 3], [0, 2, 4], [6, 0, 2], [2, 1, 3],
[5, 8, 9], [2, 1, 1], [9, 7, 6], [3, 0, 2], [9, 9, 0], [3, 4, 8],
[2, 6, 1], [8, 9, 2], [7, 6, 5], [6, 3, 1], [9, 3, 1], [8, 9, 3],
[9, 1, 0], [3, 8, 7], [8, 0, 0], [4, 9, 7], [8, 6, 2], [4, 3, 0],
[2, 3, 5], [9, 1, 4], [1, 1, 4], [6, 0, 2], [6, 1, 6], [3, 8, 8],
[8, 8, 7], [5, 5, 0], [3, 9, 6], [5, 4, 3], [6, 8, 3], [0, 1, 5],
[6, 7, 3], [8, 3, 2], [3, 8, 3], [2, 1, 6], [4, 6, 7], [8, 9, 9],
[5, 4, 2], [6, 1, 3], [6, 9, 5], [4, 8, 2], [9, 7, 4], [5, 4, 2],
[9, 6, 1], [2, 7, 3], [4, 5, 4], [6, 8, 1], [3, 4, 0], [2, 2, 6],
[5, 1, 2], [9, 9, 7], [6, 9, 9], [8, 4, 3], [4, 1, 7], [6, 2, 5],
[0, 4, 9], [3, 5, 9], [6, 9, 1], [1, 9, 2]
]
}]
});
// 自定义鼠标、触屏拖拽旋转逻辑
(function (H) {
function dragStart(eStart) {
eStart = chart.pointer.normalize(eStart);
const posX = eStart.chartX,
posY = eStart.chartY,
alpha = chart.options.chart.options3d.alpha,
beta = chart.options.chart.options3d.beta,
sensitivity = 5,
handlers = [];
function drag(e) {
e = chart.pointer.normalize(e);
chart.update({
chart: {
options3d: {
alpha: alpha + (e.chartY – posY) / sensitivity,
beta: beta + (posX – e.chartX) / sensitivity
}
}
}, undefined, undefined, false);
}
function unbindAll() {
handlers.forEach(function (unbind) {
if (unbind) unbind();
});
handlers.length = 0;
}
handlers.push(H.addEvent(document, 'mousemove', drag));
handlers.push(H.addEvent(document, 'touchmove', drag));
handlers.push(H.addEvent(document, 'mouseup', unbindAll));
handlers.push(H.addEvent(document, 'touchend', unbindAll));
}
H.addEvent(chart.container, 'mousedown', dragStart);
H.addEvent(chart.container, 'touchstart', dragStart);
}(Highcharts));
</script>
</body>
</html>
业务数据解读
所有散点均匀分布在 X:0~10、Y:0~10、Z:0~10 的标准立方体三维空间,无集中聚集区域,属于均匀随机三维采样点; 拖拽旋转可从正面、侧面、俯视、仰视多角度观察点位空间分布,解决二维图表无法表达三维空间关系的痛点。

