Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Highlight a part of an extjs4 line chart

In the extjs 4.1.1a code below is a working example of a line chart. Now I need to highlight a part of that chart on a given min and max timestamp.

{'xtype' : 'chart',
'store' : 'ChartData',
'height' : '100%',
'width' : '100%',
'legend' : {'position' : top},
'axes': [{
    'title': 'Power',
    'type': 'Numeric',
    'position': 'left',
    'fields': ['power']
},{
    'title': 'Timestamp',
    'type': 'Numeric',
    'position': 'bottom',
    'fields': ['timestamp'],
    'minorTickSteps': 3
}],
'series': [{
    'type': 'line',
    'fill': true,
    'axis' : 'left',
    'xField': 'timestamp',
    'yField': 'power'
}]}

I've searched the sencha forum and found nothing in particular that meets my requirements. For now I managed to change the color of the points on the line chart with a custom renderer.

'renderer': function(sprite, record, attr, index, store) {
var item = store.getAt(index);
if(item != undefined && (item.get('timestamp') < startdate || item.get('timestamp') > enddate)){
    return Ext.apply(attr, {'fill': '#00cc00', 'stroke-width': 3, 'radius': 4});
}else{
    return Ext.apply(attr, {'fill': '#ff0000', 'stroke-width': 3, 'radius': 4});
}}

But I have not found a way to change the color below the line. Any suggestions on that?

UPDATE - Working fine now

I implement a solution based on the answer given by Colombo.

doCustomDrawing: function () {: function (p){
var me = this, chart = me.chart;
if(chart.rendered){
    var series = chart.series.items[0];
    if (me.groupChain != null) {
        me.groupChain.destroy();
        me.groupChain = null;
    }
    me.groupChain = Ext.create('Ext.draw.CompositeSprite', {
        surface: chart.surface
    });
    if(series != null && series.items != null){
        var surface = chart.surface;
        var pathV = 'M';
        var first = true;
        // need first and last x cooridnate
        var mX = 0,hX = 0;
        Ext.each(series.items, function(item){
            var storeItem = item.storeItem,
                    pointX = item.point[0],
                    pointY = item.point[1];
            // based on given startdate and enddate start collection path coordinates
            if(!(storeItem.get('timestamp') < startdate || storeItem.get('timestamp') > enddate)){
                if(hX<pointX){
                    hX = pointX;
                }
                if(first){
                    first = false;
                    mX = pointX;
                    pathV+= + pointX + ' ' + pointY;
                }else{
                    pathV+= ' L' + pointX + ' ' + pointY;
                }
            }
        });
        var sprite = Ext.create('Ext.draw.Sprite', {
            type: 'path',
            fill: '#f00',
            surface: surface,
            // to draw a sprite with the area below the line we need the y coordinate of the x axe which is in my case items[1]
            path : pathV + ' L'+ hX + ' ' + chart.axes.items[1].y + ' L'+ mX + ' ' + chart.axes.items[1].y + 'z'
        });
        me.groupChain.add(sprite);
        me.groupChain.show(true);
    }
}}

This looks really good and has the effect I was hoping for and in case you resize the container the new sprite is cleared from the chart. Thx to Colombo again.

like image 624
everald Avatar asked Nov 13 '22 18:11

everald


1 Answers

This is possible to implement. Here is how I would do it.

1. Add a listener for afterrender event for series.

listeners: {
                afterrender: function (p) {
                    this.doCustomDrawing();
                },
                scope: me
}

2. Create a CompositeSprite

doCustomDrawing: function () {
    var me = this, chart = me.chart;

    if (chart.rendered) {
        var series = chart.series.items[0];
        if (me.groupChain != null) {
            me.groupChain.destroy();
            me.groupChain = null;
        }

        me.groupChain = Ext.create('Ext.draw.CompositeSprite', {
            surface: chart.surface
        });

        // Draw hilight here
        Ext.each(series.items, function (item) {
            var storeItem = item.storeItem,
                pointX = item.point[0], 
                pointY = item.point[1];

            //TODO: Create your new line sprite using pointX and pointY
            // and add it to CompositeSprite me.groupChain  


        });

        me.groupChain.show(true);
    }
},
like image 183
jorel Avatar answered Dec 05 '22 15:12

jorel