So I'm looking to create a 3d pie chart (in Highcharts), where the depth of each slice is determined by the point's value. The question here should give you a good idea of what I'm going for.
Currently Highcharts only supports depth arguments at the series level, so my first idea was to make multiple series, as is shown here: #1 .
Highcharts.chart('container', { chart: { type: 'pie', options3d: { enabled: true, alpha: 60 } }, title: { text: 'Contents of Highsoft\\'s weekly fruit delivery' }, subtitle: { text: '3D donut in Highcharts' }, plotOptions: { pie: { innerSize: 125, depth: 60 } }, series: [{ name: 'Delivered amount', data: [ { name: 'a', y: 1, val: 0.59, color: '#25683d' }, { name: 'b', y: 1, val: 1.25, color: '#222f58' }, { name: 'c', y: 2, val: 0.73, color: '#bebe89' }, ], depth: 45, startAngle: 0, endAngle: 180 }, { data: [ { name: 'd', y: 2, val: -0.69, color: '#900' }, { name: 'e', y: 2, val: 0.57, color: '#a0a0a0' } ], depth: 60, startAngle: 180, endAngle: 360 }] });
<script src="https://code.highcharts.com/highcharts.js"> </script> <script src="https://code.highcharts.com/highcharts-3d.js"></script> <script src="https://code.highcharts.com/modules/exporting.js"></script> <script src="https://code.highcharts.com/modules/export-data.js"></script> <div id="container" style="height: 400px"></div>
When that didnt work, I went back to storing all data in one series, and trying to update the SVG elements depth after render (as can be seen here: #2 .
Highcharts.chart('container', { chart: { type: 'pie', options3d: { enabled: true, alpha: 60 }, events: { load: function() { this.series[0].data.forEach((val, i) => { var depth = val.graphic.attribs.depth; val.graphic.attribs.depth = depth + (i * 10); }); this.redraw(); } } }, title: { text: 'Contents of Highsoft\\'s weekly fruit delivery' }, subtitle: { text: '3D donut in Highcharts' }, plotOptions: { pie: { innerSize: 125, depth: 60 } }, series: [{ name: 'Delivered amount', data: [{ name: 'a', y: 1, val: 0.59, color: '#25683d' }, { name: 'b', y: 1, val: 1.25, color: '#222f58' }, { name: 'c', y: 2, val: 0.73, color: '#bebe89' }, { name: 'd', y: 2, val: -0.69, color: '#900' }, { name: 'e', y: 2, val: 0.57, color: '#a0a0a0' } ], }] });
Once again, the depth appears to just add content down, and my attempts at translation ( https://api.highcharts.com/class-reference/Highcharts.SVGElement#translate ) to shift each slice up have been less than successful in maintaining an aesthetically pleasing chart.. for instance: #3 .
Highcharts.chart('container', { chart: { type: 'pie', options3d: { enabled: true, alpha: 60 }, events: { load: function() { this.series[0].data.forEach((val, i) => { var depth = val.graphic.attribs.depth; val.graphic.attribs.depth = depth + (i * 10); }); this.redraw(); }, redraw: function() { var y_trans = [0, -8, -16, -25, -34]; this.series[0].data.forEach((val, i) => { val.graphic.translate(0, y_trans[i]); }); } } }, title: { text: 'Contents of Highsoft\\'s weekly fruit delivery' }, subtitle: { text: '3D donut in Highcharts' }, plotOptions: { pie: { innerSize: 125, depth: 60 } }, series: [{ name: 'Delivered amount', data: [{ name: 'a', y: 1, val: 0.59, color: '#25683d' }, { name: 'b', y: 1, val: 1.25, color: '#222f58' }, { name: 'c', y: 2, val: 0.73, color: '#bebe89' }, { name: 'd', y: 2, val: -0.69, color: '#900' }, { name: 'e', y: 2, val: 0.57, color: '#a0a0a0' } ], }] });
Any references or ideas would be greatly appreciated as I'm starting to hit a wall.
You can use Highcharts wrap
and extend translate
method:
var each = Highcharts.each,
round = Math.round,
cos = Math.cos,
sin = Math.sin,
deg2rad = Math.deg2rad;
Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'translate', function(proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
if (!this.chart.is3d()) {
return;
}
var series = this,
chart = series.chart,
options = chart.options,
seriesOptions = series.options,
depth = seriesOptions.depth || 0,
options3d = options.chart.options3d,
alpha = options3d.alpha,
beta = options3d.beta,
z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : series._i * depth;
z += depth / 2;
if (seriesOptions.grouping !== false) {
z = 0;
}
each(series.data, function(point) {
var shapeArgs = point.shapeArgs,
angle;
point.shapeType = 'arc3d';
var ran = point.options.h;
shapeArgs.z = z;
shapeArgs.depth = depth * 0.75 + ran;
shapeArgs.alpha = alpha;
shapeArgs.beta = beta;
shapeArgs.center = series.center;
shapeArgs.ran = ran;
angle = (shapeArgs.end + shapeArgs.start) / 2;
point.slicedTranslation = {
translateX: round(cos(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)),
translateY: round(sin(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad))
};
});
});
(function(H) {
H.wrap(Highcharts.SVGRenderer.prototype, 'arc3dPath', function(proceed) {
// Run original proceed method
var ret = proceed.apply(this, [].slice.call(arguments, 1));
ret.zTop = (ret.zOut + 0.5) / 100;
return ret;
});
}(Highcharts));
Also, in load
event you need to reverse the chart:
events: {
load: function() {
var each = Highcharts.each,
points = this.series[0].points;
each(points, function(p, i) {
p.graphic.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side1.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side2.attr({
translateY: -p.shapeArgs.ran
});
});
}
}
Live demo: http://jsfiddle.net/BlackLabel/c4wk5z9L/
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.