I am trying to create a 3D-scatter plot of some data with Highcharts. To make it easier to understand the 3D position of the data points, specially when using a still picture of the plot instead of the interactive draggable version, I would like to create projections of the data on each of the plot boundary planes.
It is not difficult to assign the corresponding position of these projections (example: http://jsfiddle.net/worg6jLz/1/), but I would like them to appear as real projections, not just as circles (or actually spheres) regardless of the perspective.
Is there a way to transform the plot markers according to their corresponding plane of projection, so that their shape is consistent with such projection regardless of the viewpoint?
Thanks.
$(function () {
// Give the points a 3D feel by adding a radial gradient
Highcharts.getOptions().colors = $.map(Highcharts.getOptions().colors, 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')]
]
};
});
// Set up the chart
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
margin: 100,
type: 'scatter',
options3d: {
enabled: true,
alpha: 10,
beta: 30,
depth: 450,
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: 'Draggable box'
},
subtitle: {
text: 'Click and drag the plot area to rotate in space'
},
plotOptions: {
scatter: {
width: 10,
height: 10,
depth: 10
}
},
yAxis: {
min: 0,
max: 10,
title: null
},
xAxis: {
min: 0,
max: 10,
gridLineWidth: 1
},
zAxis: {
min: 0,
max: 10,
showFirstLabel: false
},
legend: {
enabled: false
},
series: [{
name: 'Data',
marker: {radius: 7,
symbol: 'circle',
fillColor: {
radialGradient: { cx: 0.4, cy: 0.3, r: 0.5 },
stops: [[0, 'rgba(195,195,255,1)'],
[1, 'rgba(0,0,255,1)']]}
},
colorByPoint: false,
color: 'blue',
data: [[9,9,1],[8,8,2],[7,7,3],[6,6,4],[5,5,5],[4,4,6],[3,3,7],[2,2,8],[1,1,9]]
},
{
name: 'Proj.A',
marker: {radius: 7,
symbol: 'circle'},
colorByPoint: false,
color: 'rgba(155,155,155,1)',
data: [[0,9,1],[0,8,2],[0,7,3],[0,6,4],[0,5,5],[0,4,6],[0,3,7],[0,2,8],[0,1,9]]
},
{
name: 'Proj.B',
marker: {radius: 7,
symbol: 'circle'},
colorByPoint: false,
color: 'rgba(155,155,155,1)',
data: [[9,0,1],[8,0,2],[7,0,3],[6,0,4],[5,0,5],[4,0,6],[3,0,7],[2,0,8],[1,0,9]]
},
{
name: 'Proj.C',
marker: {radius: 7,
symbol: 'circle'},
colorByPoint: false,
color: 'rgba(155,155,155,1)',
data: [[9,9,10],[8,8,10],[7,7,10],[6,6,10],[5,5,10],[4,4,10],[3,3,10],[2,2,10],[1,1,10]]
}]
});
// Add mouse events for rotation
$(chart.container).bind('mousedown.hc touchstart.hc', function (eStart) {
eStart = chart.pointer.normalize(eStart);
var posX = eStart.pageX,
posY = eStart.pageY,
alpha = chart.options.chart.options3d.alpha,
beta = chart.options.chart.options3d.beta,
newAlpha,
newBeta,
sensitivity = 5; // lower is more sensitive
$(document).bind({
'mousemove.hc touchdrag.hc': function (e) {
// Run beta
newBeta = beta + (posX - e.pageX) / sensitivity;
chart.options.chart.options3d.beta = newBeta;
// Run alpha
newAlpha = alpha + (e.pageY - posY) / sensitivity;
chart.options.chart.options3d.alpha = newAlpha;
chart.redraw(false);
},
'mouseup touchend': function () {
$(document).unbind('.hc');
}
});
});
});
Bonus: An additional interesting feature, though not the main purpose of this post, would be to draw lines linking the data points with their projections when the mouse pointer is placed over them.