简体   繁体   中英

Highcharts Multi-Depth 3d pie chart

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 .

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> 

  • The issue with this being that the depth appears to keep the same top reference point, instead of the intended results wherein each 'slice' starts at the same y point.

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 .

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 .

    • also worth noting that i had to define an array for the y translations, which was mostly the results of trial and error

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/

Docs: https://www.highcharts.com/docs/extending-highcharts

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM