Results 1 to 7 of 7

Thread: Draw a gauge with "stacked" values

Hybrid View

Previous Post Previous Post   Next Post Next Post
    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
      1  

    Default 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
    39,556
    Answers
    3931
    Vote Rating
    1272
      0  

    Default

    Not really a gague chart... more of a pie chart only half of it.
    Mitchell Simoens @LikelyMitch
    Sencha Inc, Senior Software Engineer
    ________________
    Learn BBCode and use it! Checkout the CODE tag!

    Check out my GitHub, lots of nice things for Ext JS and Sencha Touch
    https://github.com/mitchellsimoens

  3. #3
    Sencha User
    Join Date
    Jul 2011
    Posts
    12
    Vote Rating
    1
      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 Attached Images

  4. #4
    Sencha User
    Join Date
    Feb 2012
    Posts
    26
    Vote Rating
    1
      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
      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
    Jan 2015
    Location
    France
    Posts
    6
    Vote Rating
    0
      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.

  7. #7
    Sencha User
    Join Date
    Feb 2012
    Posts
    9
    Vote Rating
    1
      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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •