Thank you for reporting this bug. We will make it our priority to review this report.
  1. #1
    Sencha User
    Join Date
    Jul 2011
    Posts
    12
    Vote Rating
    1
    Cangot is on a distinguished road

      1  

    Default Unanswered: Draw a gauge with "stacked" values

    Hi,

    I want to draw a gauge chart with 5 slices, and a needle.
    Code:
    var myStore =  new Ext.data.Store({     
         fields: ['price'],     
         data : [         {price: 50},         {price : 6},         {price : 20},         {price : 1}     ]
    });
    Code:
    var myChart = {   xtype: 'chart',   store: myStore ,
      axes: [{
          type: 'gauge',
          position: 'gauge',
          minimum: 0,
          maximum: 100
        }],
        series: [{
            type: 'gauge',
            angleField: 'price',
            needle:true
        } 
        ]
    


    What I want is a gauge with 5 slices (my 4 values + empty slice), like the "stacked" attribute with bar chart.
    Is it possible ?

    Thank you


  2. #2
    Sencha - Sr Software Engineer mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    38,605
    Vote Rating
    1143
    Answers
    3711
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      0  

    Default

    Not really a gague chart... more of a pie chart only half of it.
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Software Engineer
    ________________
    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

  3. #3
    Sencha User
    Join Date
    Jul 2011
    Posts
    12
    Vote Rating
    1
    Cangot is on a distinguished road

      0  

    Default

    Hi,

    Of course, you're right ! I was confused because of the needle ...
    I send the "half pie" I made.

    Thank you
    Attached Images

  4. #4
    Sencha User
    Join Date
    Feb 2012
    Posts
    26
    Vote Rating
    1
    Syntona is on a distinguished road

      1  

    Default Stacked gauge chart

    Hey,
    Can I ask you have to accomplish this?
    I am also looking for gauge chart with multiple series.
    I tried to incorporate KPI gauge chart extension available in EXT-JS but not succeeded

    It would be great help if you guide/suggest.

    Thanks in advance.

  5. #5
    Sencha User
    Join Date
    Apr 2013
    Location
    New Delhi
    Posts
    9
    Vote Rating
    1
    rohit.advani is on a distinguished road

      1  

    Default

    @Cangot: Hi, I'm using ExtJS 4.1, can you please help me to understand how did you accomplish this semi pie chart with a needle. I have rendered a pie chart with a donut but not able to find out how to draw a semi pie chart and a needle.

    Can you please assist with some sample code ?

    Regards,
    Rohit

  6. #6
    Sencha User
    Join Date
    Feb 2012
    Posts
    9
    Vote Rating
    1
    Jibbercan is on a distinguished road

      1  

    Default

    Looks like this is a full chart with one data item representing 50% and the color set to the same as the background with a needle image overlayed. I need a chart like this too but I don't want all that wasted white space.

  7. #7
    Sencha User
    Join Date
    Jan 2015
    Location
    France
    Posts
    6
    Vote Rating
    0
    bapt is on a distinguished road

      0  

    Default

    @mitchellsimoens How can we do a half pie chart in ExtJS? I need a Gauge chart without the axes and a label on each field. Already 3 users have asked if there is a way to do this, I hope someone can help.

    Edit: This thread should be moved from Sencha Touch 1.x (unsupported) to Ext JS 4.x forum.

    Edit 2: I've found how to create a Gauge chart without axes and a label on each field, so I will share the solution if it can help other users.
    For the axes, I override the drawAxis function with an empty function and for the series, I override the drawSeries function, based on the Gauge drawSeries function and add me.calcMiddle(item); after rendererAttributes.segment and me.renderLabels(); before delete me.value. Adding onCreateLabel and onPlaceLabel functions from the Pie chart is also necessary.

    Here is a Fiddle with all-in-one file code https://fiddle.sencha.com/#fiddle/ilm and below is my original code in MVC style:

    Code:
    Ext.define('MyChart.view.Gauge', {
        extend: 'Ext.chart.Chart',
        requires: ['MyChart.view.chart.series.StackedGauge', 'MyChart.view.chart.axis.StackedGauge'],
        store: 'Gauge',
        alias: 'widget.gauge',
        width: 400,
        height: 250,
        animate: true,
        insetPadding: 30,
        axes: [{
            type: 'stackedgauge',
            position: 'gauge',
            minimum: 0,
            maximum: 100,
            steps: 10,
            margin: 10
        }],
        series: [{
            type: 'stackedgauge',
            field: 'value',
            donut: 30,
            colorSet: ['#F49D10', '#ddd'],
            label: {
                display: '',
                field: 'value',
                contrast: true,
                font: '18px Arial',
                renderer: function(v) {
                    return v + "%";
                }
            }
        }]
    });
    Code:
    Ext.define('MyChart.view.chart.axis.StackedGauge', {
        extend: 'Ext.chart.axis.Gauge',
        alias: 'axis.stackedgauge',
        drawAxis: function() {}
    });
    Code:
    Ext.define('MyChart.view.chart.series.StackedGauge', {
        extend: 'Ext.chart.series.Gauge',
        alias: 'series.stackedgauge',
    
        drawSeries: function() {
            var me = this,
                chart = me.chart,
                store = chart.getChartStore(),
                group = me.group,
                animate = me.chart.animate,
                axis = me.chart.axes.get(0),
                minimum = axis && axis.minimum || me.minimum || 0,
                maximum = axis && axis.maximum || me.maximum || 0,
                field = me.angleField || me.field || me.xField,
                surface = chart.surface,
                chartBBox = chart.chartBBox,
                rad = me.rad,
                donut = +me.donut,
                values = {},
                items = [],
                seriesStyle = me.seriesStyle,
                seriesLabelStyle = me.seriesLabelStyle,
                colorArrayStyle = me.colorArrayStyle,
                colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
                cos = Math.cos,
                sin = Math.sin,
                rendererAttributes, centerX, centerY, slice, slices, sprite, value,
                item, ln, record, i, j, startAngle, endAngle, middleAngle, sliceLength, path,
                p, spriteOptions, bbox, splitAngle, sliceA, sliceB;
            
            Ext.apply(seriesStyle, me.style || {});
    
            me.setBBox();
            bbox = me.bbox;
    
            //override theme colors
            if (me.colorSet) {
                colorArrayStyle = me.colorSet;
                colorArrayLength = colorArrayStyle.length;
            }
            
            //if not store or store is empty then there's nothing to draw
            if (!store || !store.getCount() || me.seriesIsHidden) {
                me.hide();
                me.items = [];
                return;
            }
            
            centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
            centerY = me.centerY = chartBBox.y + chartBBox.height;
            me.radius = Math.min(centerX - chartBBox.x, centerY - chartBBox.y);
            me.slices = slices = [];
            me.items = items = [];
            
            if (!me.value) {
                record = store.getAt(0);
                me.value = record.get(field);
            }
            
            value = me.value;
            if (me.needle) {
                sliceA = {
                    series: me,
                    value: value,
                    startAngle: -180,
                    endAngle: 0,
                    rho: me.radius
                };
                splitAngle = -180 * (1 - (value - minimum) / (maximum - minimum));
                slices.push(sliceA);
            } else {
                splitAngle = -180 * (1 - (value - minimum) / (maximum - minimum));
                sliceA = {
                    series: me,
                    value: value,
                    startAngle: -180,
                    endAngle: splitAngle,
                    rho: me.radius
                };
                sliceB = {
                    series: me,
                    value: me.maximum - value,
                    startAngle: splitAngle,
                    endAngle: 0,
                    rho: me.radius
                };
                slices.push(sliceA, sliceB);
            }
            
            //do pie slices after.
            for (i = 0, ln = slices.length; i < ln; i++) {
                slice = slices[i];
                sprite = group.getAt(i);
                //set pie slice properties
                rendererAttributes = Ext.apply({
                    segment: {
                        startAngle: slice.startAngle,
                        endAngle: slice.endAngle,
                        margin: 0,
                        rho: slice.rho,
                        startRho: slice.rho * +donut / 100,
                        endRho: slice.rho
                    } 
                }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[i % colorArrayLength] } || {}));
    
                item = Ext.apply({},
                rendererAttributes.segment, {
                    slice: slice,
                    series: me,
                    storeItem: record,
                    index: i
                });
                me.calcMiddle(item);
                items[i] = item;
                // Create a new sprite if needed (no height)
                if (!sprite) {
                    spriteOptions = Ext.apply({
                        type: "path",
                        group: group
                    }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[i % colorArrayLength] } || {}));
                    sprite = surface.add(Ext.apply(spriteOptions, rendererAttributes));
                }
                slice.sprite = slice.sprite || [];
                item.sprite = sprite;
                slice.sprite.push(sprite);
                if (animate) {
                    rendererAttributes = me.renderer(sprite, record, rendererAttributes, i, store);
                    sprite._to = rendererAttributes;
                    me.onAnimate(sprite, {
                        to: rendererAttributes
                    });
                } else {
                    rendererAttributes = me.renderer(sprite, record, Ext.apply(rendererAttributes, {
                        hidden: false
                    }), i, store);
                    sprite.setAttributes(rendererAttributes, true);
                }
            }
            
            if (me.needle) {
                splitAngle = splitAngle * Math.PI / 180;
                
                if (!me.needleSprite) {
                    me.needleSprite = me.chart.surface.add({
                        type: 'path',
                        path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle),
                                    centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)),
                               'L', centerX + me.radius * cos(splitAngle),
                                    centerY + -Math.abs(me.radius * sin(splitAngle))],
                        'stroke-width': 4,
                        'stroke': '#222'
                    });
                } else {
                    if (animate) {
                        me.onAnimate(me.needleSprite, {
                            to: {
                            path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle),
                                        centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)),
                                   'L', centerX + me.radius * cos(splitAngle),
                                        centerY + -Math.abs(me.radius * sin(splitAngle))]
                            }
                        });
                    } else {
                        me.needleSprite.setAttributes({
                            type: 'path',
                            path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle),
                                        centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)),
                                   'L', centerX + me.radius * cos(splitAngle),
                                        centerY + -Math.abs(me.radius * sin(splitAngle))]
                        });
                    }
                }
                me.needleSprite.setAttributes({
                    hidden: false    
                }, true);
            }
            
            me.renderLabels();
            delete me.value;
        },
        onCreateLabel: function(storeItem, item, i, display) {
            var me = this,
                group = me.labelsGroup,
                config = me.label,
                centerX = me.centerX,
                centerY = me.centerY,
                middle = item.middle,
                endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config || {});
    
            return me.chart.surface.add(Ext.apply({
                'type': 'text',
                'text-anchor': 'middle',
                'group': group,
                'x': middle.x,
                'y': middle.y
            }, endLabelStyle));
        },
        onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
            var me = this,
                chart = me.chart,
                resizing = chart.resizing,
                config = me.label,
                format = config.renderer,
                field = config.field,
                centerX = me.centerX,
                centerY = me.centerY,
                middle = item.middle,
                opt = {
                    x: middle.x,
                    y: middle.y
                },
                x = middle.x - centerX,
                y = middle.y - centerY,
                from = {},
                rho = 1,
                theta = Math.atan2(y, x || 1),
                dg = theta * 180 / Math.PI,
                prevDg, labelBox, width, height;
    
            opt.hidden = false;
    
            if (this.__excludes && this.__excludes[i]) {
                opt.hidden = true;
            }
    
            function fixAngle(a) {
                if (a < 0) {
                    a += 360;
                }
                return a % 360;
            }
    
            label.setAttributes({
                text: format(storeItem.get(field), label, storeItem, item, i, display, animate, index)
            }, true);
    
            //ensure the object has zero translation
            opt.translate = {
                x: 0, y: 0
            };
            if (animate && !resizing && (display != 'rotate' || prevDg != null)) {
                me.onAnimate(label, {
                    to: opt
                });
            } else {
                label.setAttributes(opt, true);
            }
            label._from = from;
        }
    });
    A Gauge chart has only 2 stacks by default but if someone wants a real half Pie chart, I think it will be preferable to override the Pie instead of the Gauge.