extjssencha-touchsencha-touch-2sencha-touch-2.1

Rendering of data points in Sencha charts


I have a Sencha chart where I render some of the data points in a specific color depending on the values in in my data store. This works fine also long as I'm not zooming the chart, but as sone as I zoom the x-axis of the chart the highlighted data point moves because the index of the renderer function does no longer correspond to the index of the record in the store. See this fiddle: https://fiddle.sencha.com/#fiddle/ls3 -> Zoom the x-axis

The original chart: The original chart The chart after zooming in and out again (the second red dot shouldn't be there): The chart after zooming in and out again

Is there a way to avoid this behaviour?

Thanks in advance!


Solution

  • This is some documented behaviour, even if the doc is apparently taunting you:

    It is usually the index of the store record associated with the sprite

    There doesn't seem to be an information in the arguments passed to the renderer that could be used to retrieve the record in a infallible way... However, the method that calls the renderer has the information, so a simple override can save the day (fixed fiddle):

    // I like to name overrides after the overridden class, but do as per your tastes
    Ext.define('MyApp.overrides.Ext.chart.series.sprite.Line.RendererIndex', {
        override: 'Ext.chart.series.sprite.Line',
    
        // The parent method will call the renderer, and knows the start index...
        // but it won't give it to you, so let's help ourselve and store it now.
        renderAggregates: function (aggregates, start, end, surface, ctx, clip, region) {
            this.renderingRangeStart = start;
            return this.callParent(arguments);
        },
    
        // Utility method to convert the index into some useful piece of information,
        // that is a store record. The name is a bit circumvoluted in order to avoid
        // collision with some future code from Sencha
        getRecordAtRenderIndex: function(index) {
            var store = this.getStore();
            if (store) {
                return store.getAt(this.renderingRangeStart + index);
            }
        }
    });
    

    In the parent method, this is the line that calls the renderer:

    markerCfg = attr.renderer.call(this, this, markerCfg, {store:this.getStore()}, i/3) || {};
    

    One could be tempted to change this line to "fix" the arguments passed to the renderer, but (1) that may break other existing renderers, and (2) that would require to copy-paste the whole code of the method, which is always a lit bit worrying for the future. I think it's best to work "around" the code; which is made possible easily here since the missing information is sitting in the arguments of the overridden method.