everald
everald

Reputation: 128

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.

Upvotes: 5

Views: 4278

Answers (2)

jorel
jorel

Reputation: 808

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);
    }
},

Upvotes: 1

egerardus
egerardus

Reputation: 11486

There is no "built-in" way to go about this. You are probably running into some difficulties looking for it because "highlighting" a line chart currently means something totally different in the ExtJS API. It normally refers to making the line and markers bold when you hover the mouse over a data series.

However your idea sounds interesting, I might need use this in a project I have coming up.

I don't have the time to work out the exact code right now but this could be done by creating a rectangular sprite and adding it to the chart's surface property.

You can do that even after the chart has been all rendered using the Ext.draw.Surface.add method as described here in the docs.

You will have to come up with logic for determining width and positioning, if I remember the chart API properly, you should be able to extract x coordinates (horizontal location) of individual records by fishing around in the items property of the Ext.chart.series.Line object inside the chart.

The height of the highlight should be easy though - just read the height of the chart.

Upvotes: 0

Related Questions