Hybrid View

    Thank you for reporting this bug. We will make it our priority to review this report.
  1. #1
    Ext JS Premium Member
    Join Date
    Feb 2009
    Location
    London, UK
    Posts
    31
    Vote Rating
    0
    awebb is on a distinguished road

      0  

    Question Unanswered: Reducing number of labels on X axis of Stock example

    Unanswered: Reducing number of labels on X axis of Stock example


    Take your Stock line chart example: how would you greatly reduce the number of labels on the X (time) axis?

    You have approx seven months worth of data, and the number of labels is excessive. I have a stock line chart based on your example, but with >2 years worth of data, with a data point available on virtually every weekday. The number of labels that gets rendered is massive, and the X axis is unreadable.

    How to reduce the number of labels to have a label + dash every (say) three months?

    Looking at the source, it would seem that the real problem is one of reducing the number of "inflections" on the X axis, since both the rendering of labels and grid lines is keyed off the number of inflections. (A per-label inflection is only hidden if it would intersect with the previous label; i.e. you're trying to render as many as you possibly can, which I don't think is a good idea - unless the behaviour is overridable.)

    Any help / guidance would be welcome.

  2. #2
    Sencha User
    Join Date
    Nov 2010
    Posts
    168
    Vote Rating
    0
    philogb is on a distinguished road

      0  

    Default


    Hi - Thanks for your report. Unfortunately this is a feature we currently do not have. I just implemented the use of the filter function for the labels, that gets called just like a renderer but returns true or false to set the labels as displayed or hidden.

    I had to change the source code for this, and you probably won't be able to use the filter function until the next release, but if you want to change the source code of the framework to add this, then you would have to change the drawVerticalLabels and drawHorizontalLabels methods with this code:

    Code:
        drawHorizontalLabels: function() {
            var me = this,
                labelConf = me.labelStyle.style,
                renderer = labelConf.renderer || function(v) {
                    return v;
                },
                filter = labelConf.filter || function() {
                    return true;
                },
                math = Math,
                floor = math.floor,
                max = math.max,
                axes = me.chart.axes,
                position = me.position,
                inflections = me.inflections,
                ln = inflections.length,
                labels = me.labels,
                skipTicks = me.skipTicks,
                maxHeight = 0,
                ratio,
                bbox, point, prevLabel,
                textLabel, text,
                last, x, y, i, firstLabel;
    
    
            if (!me.calcLabels && skipTicks) {
                labels = labels.slice(skipTicks);
                ln -= skipTicks;
            }
    
    
            last = ln - 1;
            //get a reference to the first text label dimensions
            point = inflections[0];
            firstLabel = me.getOrCreateLabel(0, renderer(labels[0]));
            ratio = math.abs(math.sin(labelConf.rotate && (labelConf.rotate.degrees * math.PI / 180) || 0)) >> 0;
    
    
            for (i = 0; i < ln; i++) {
                point = inflections[i];
                text = renderer(labels[i]);
                textLabel = me.getOrCreateLabel(i, text);
                bbox = textLabel._bbox;
                maxHeight = max(maxHeight, bbox.height + me.dashSize + (labelConf.padding || 0));
                x = floor(point[0] - (ratio? bbox.height : bbox.width) / 2);
                if (me.chart.maxGutter[0] == 0) {
                    if (i == 0 && axes.findIndex('position', 'left') == -1) {
                        x = point[0];
                    }
                    else if (i == last && axes.findIndex('position', 'right') == -1) {
                        x = point[0] - bbox.width;
                    }
                }
                if (position == 'top') {
                    y = point[1] - (me.dashSize * 2) - labelConf.padding - (bbox.height / 2);
                }
                else {
                    y = point[1] + (me.dashSize * 2) + labelConf.padding + (bbox.height / 2);
                }
                if (!me.isPannable()) {
                    x += me.x;
                    y += me.y;
                }
                textLabel.setAttributes({
                    hidden: false,
                    x: x,
                    y: y
                }, true);
                if (labelConf.rotate) {
                    textLabel.setAttributes(labelConf, true);
                }
                // Skip label if there isn't available minimum space
                if (i != 0 && (((me.intersect(textLabel, prevLabel)
                    || me.intersect(textLabel, firstLabel))) || !filter(textLabel, text, i))) {
                    textLabel.hide(true);
                    continue;
                }
                prevLabel = textLabel;
            }
    
    
            return maxHeight;
        },
    
    
        drawVerticalLabels: function() {
            var me = this,
                labelConf = me.labelStyle.style,
                renderer = labelConf.renderer || function(v) {
                    return v;
                },
                filter = labelConf.filter || function() {
                    return true;
                },
                inflections = me.inflections,
                position = me.position,
                ln = inflections.length,
                labels = me.labels,
                skipTicks = me.skipTicks,
                maxWidth = 0,
                math = Math,
                max = math.max,
                floor = math.floor,
                ceil = math.ceil,
                axes = me.chart.axes,
                gutterY = me.chart.maxGutter[1],
                bbox, point, prevLabel,
                textLabel, text,
                last, x, y, i;
    
    
            if (!me.calcLabels && skipTicks) {
                labels = labels.slice(skipTicks);
                ln -= skipTicks;
            }
    
    
            last = ln;
            for (i = 0; i < last; i++) {
                point = inflections[i];
                text = renderer(labels[i]);
                textLabel = me.getOrCreateLabel(i, text);
                bbox = textLabel._bbox;
                maxWidth = max(maxWidth, bbox.width + me.dashSize + (labelConf.padding || 0));
                y = point[1];
                if (gutterY < bbox.height / 2) {
                    if (i == last - 1 && axes.findIndex('position', 'top') == -1) {
                        y += ceil(bbox.height / 2);
                    }
                    else if (i == 0 && axes.findIndex('position', 'bottom') == -1) {
                        y -= floor(bbox.height / 2);
                    }
                }
                if (position == 'left') {
                    x = point[0] - bbox.width - me.dashSize - (labelConf.padding || 0) - 2;
                }
                else {
                    x = point[0] + me.dashSize + (labelConf.padding || 0) + 2;
                }
                if (!me.isPannable()) {
                    x += me.x;
                    y += me.y + me.panY;
                }
                textLabel.setAttributes(Ext.apply({
                    hidden: false,
                    x: x,
                    y: y
                }, labelConf), true);
                // Skip label if there isn't available minimum space
                if (i != 0 && (me.intersect(textLabel, prevLabel) || !filter(textLabel, text, i))) {
                    textLabel.hide(true);
                    continue;
                }
                prevLabel = textLabel;
            }
    
    
            return maxWidth;
        },
    Then for the Stocks example, I only render labels that are modulo 5:

    Code:
                axes: [{
                    type: 'Numeric',
                    position: 'left',
                    fields: ['djia'],
                    title: 'Dow Jones Average'
                }, {
                    type: 'Numeric',
                    position: 'right',
                    fields: ['sp500'],
                    title: 'S&P 500'
                }, {
                    type: 'Time',
                    position: 'bottom',
                    fields: ['date'],
                    dateFormat: ' M d ',
                    label: {
                        filter: function(textLabel, text, i) {
                            return (+text.split(' ')[2] % 5) === 0;
                        },
                        rotate: {
                            degrees: 45
                        }
                    }
                }],
    I hope this helps,

  3. #3
    Ext JS Premium Member
    Join Date
    Feb 2009
    Location
    London, UK
    Posts
    31
    Vote Rating
    0
    awebb is on a distinguished road

      0  

    Default Filtering of inflections: great results

    Filtering of inflections: great results


    Thanks philogb.

    That's useful up to a point, and I would argue that you should include a boolean include-label filter function in future releases. However, you can and should go so much further. What we really want to do is to filter the X axis inflections and their associated paths (for the little dashes). Then we can draw a small number of vertical grid lines that divide up the line chart into (say) six sections, and just have a few, useful labels and dashes instead of information overload.

    I've done this, and it looks great. Take a look at these two screenshots, showing the same line chart at different time periods...
    screen1.jpg

    screen2.jpg


    Ok, how we do this? Well, we introduce a user-supplied filterInflection(index) function into 'drawAxis' (search for "AJW" to see all my modifications):-

    Code:
        /**
         * Renders the axis into the screen and updates it's position.
         */
        drawAxis: function (init) {
            var me = this,
                filterFnScope = me.filterFnScope || this,  // AJW: scope for the filterInflection() function
                filterInflection = me.filterInflection || function() { return true; },  // AJW: filter inflection function
                zoomX = me.zoomX,
                zoomY = me.zoomY,
                x = me.startX * zoomX,
                y = me.startY * zoomY,
                gutterX = me.chart.maxGutter[0] * zoomX,
                gutterY = me.chart.maxGutter[1] * zoomY,
                dashSize = me.dashSize,
                subDashesX = me.minorTickSteps || 0,
                subDashesY = me.minorTickSteps || 0,
                isSide = me.isSide(),
                viewLength = me.length,
                bufferLength = viewLength * me.overflowBuffer,
                totalLength = viewLength * (isSide ? zoomY : zoomX),
                position = me.position,
                inflections = [],
                calcLabels = me.calcLabels,
                stepCalcs = me.applyData(),
                step = stepCalcs.step,
                from = stepCalcs.from,
                to = stepCalcs.to,
                math = Math,
                mfloor = math.floor,
                mmax = math.max,
                mmin = math.min,
                mround = math.round,
                trueLength, currentX, currentY, startX, startY, path, dashesX, dashesY, delta, skipTicks, i,
                index;  // AJW: added index var
    
            me.updateSurfaceBox();
    
            //If no steps are specified
            //then don't draw the axis. This generally happens
            //when an empty store.
            if (me.hidden || me.chart.store.getCount() < 1 || stepCalcs.steps <= 0) {
                me.getSurface().items.hide(true);
                if (me.displaySprite) {
                    me.displaySprite.hide(true);
                }
                return;
            }
    
            me.from = stepCalcs.from;
            me.to = stepCalcs.to;
            if (isSide) {
                currentX = mfloor(x) + 0.5;
                path = ["M", currentX, y, "l", 0, -totalLength];
                trueLength = totalLength - (gutterY * 2);
            }
            else {
                currentY = mfloor(y) + 0.5;
                path = ["M", x, currentY, "l", totalLength, 0];
                trueLength = totalLength - (gutterX * 2);
            }
    
            delta = trueLength * step / (to - from);
            skipTicks = me.skipTicks = mfloor(mmax(0, (isSide ? totalLength + me.panY - viewLength - bufferLength : -me.panX - bufferLength)) / delta);
            dashesX = mmax(subDashesX +1, 0);
            dashesY = mmax(subDashesY +1, 0);
            if (calcLabels) {
                me.labels = [stepCalcs.from + skipTicks * step];
            }
            if (isSide) {
                currentY = startY = y - gutterY - delta * skipTicks;
                currentX = x - ((position == 'left') * dashSize * 2);
                while (currentY >= startY - mmin(trueLength, viewLength + bufferLength * 2)) {
                    path.push("M", currentX, mfloor(currentY) + 0.5, "l", dashSize * 2 + 1, 0);
                    if (currentY != startY) {
                        for (i = 1; i < dashesY; i++) {
                            path.push("M", currentX + dashSize, mfloor(currentY + delta * i / dashesY) + 0.5, "l", dashSize + 1, 0);
                        }
                    }
                    inflections.push([ mfloor(x), mfloor(currentY) ]);
                    currentY -= delta;
                    if (calcLabels) {
                        // Cut everything that is after tenth digit after floating point. This is to get rid of
                        // rounding errors, i.e. 12.00000000000121212.
                        me.labels.push(+(me.labels[me.labels.length - 1] + step).toFixed(10));
                    }
                    if (delta === 0) {
                        break;
                    }
                }
                if (mround(currentY + delta - (y - gutterY - trueLength))) {
                    path.push("M", currentX, mfloor(y - totalLength + gutterY) + 0.5, "l", dashSize * 2 + 1, 0);
                    for (i = 1; i < dashesY; i++) {
                        path.push("M", currentX + dashSize, mfloor(y - totalLength + gutterY + delta * i / dashesY) + 0.5, "l", dashSize + 1, 0);
                    }
                    inflections.push([ mfloor(x), mfloor(currentY) ]);
                    if (calcLabels) {
                        // Cut everything that is after tenth digit after floating point. This is to get rid of
                        // rounding errors, i.e. 12.00000000000121212.
                        me.labels.push(+(me.labels[me.labels.length - 1] + step).toFixed(10));
                    }
                }
            } else {
                // AJW: initialize the index for the filterInflection function
                index = -1;
    
                currentX = startX = x + gutterX + delta * skipTicks;
                currentY = y - ((position == 'top') * dashSize * 2);
                while (currentX <= startX + mmin(trueLength, viewLength + bufferLength * 2)) {
                    // AJW: increment the index for the filterInflection function
                    index++;
    
                    // AJW: if the filterInflection function returns false, then we don't want an inflection, label
                    // and dash(es) for this data point.  In this case we just push null onto the inflections array
                    // to a) maintain a one-to-one correspondence between data points, inflections and labels and
                    // b) indicate to the code that we don't want to render a grid line and label for this inflection.
                    if (!filterInflection.call(filterFnScope, index)) {
                        inflections.push(null);
                    } else {
                        path.push("M", mfloor(currentX) + 0.5, currentY, "l", 0, dashSize * 2 + 1);
                        if (currentX != startX) {
                            for (i = 1; i < dashesX; i++) {
                                path.push("M", mfloor(currentX - delta * i / dashesX) + 0.5, currentY, "l", 0, dashSize + 1);
                            }
                        }
                        inflections.push([ mfloor(currentX), mfloor(y) ]);
                    }
    
                    currentX += delta;
                    if (calcLabels) {
                        // Cut everything that is after tenth digit after floating point. This is to get rid of
                        // rounding errors, i.e. 12.00000000000121212.
                        me.labels.push(+(me.labels[me.labels.length - 1] + step).toFixed(10));
                    }
                    if (delta === 0) {
                        break;
                    }
                }
                if (mround(currentX - delta - (x + gutterX + trueLength))) {
                    path.push("M", mfloor(x + totalLength - gutterX) + 0.5, currentY, "l", 0, dashSize * 2 + 1);
                    for (i = 1; i < dashesX; i++) {
                        path.push("M", mfloor(x + totalLength - gutterX - delta * i / dashesX) + 0.5, currentY, "l", 0, dashSize + 1);
                    }
                    inflections.push([mfloor(currentX), mfloor(y) ]);
                    if (calcLabels) {
                        // Cut everything that is after tenth digit after floating point. This is to get rid of
                        // rounding errors, i.e. 12.00000000000121212.
                        me.labels.push(+(me.labels[me.labels.length - 1] + step).toFixed(10));
                    }
                }
            }
            if (!me.axis) {
                me.axis = me.getSurface().add(Ext.apply({
                    type: 'path',
                    path: path
                }, me.style));
            }
            me.axis.setAttributes({
                path: path,
                hidden: false
            }, true);
            me.inflections = inflections;
            if (!init) {
                //if grids have been styled in some way
                if ( me.grid ||
                     me.gridStyle.style ||
                     me.gridStyle.oddStyle.style ||
                     me.gridStyle.evenStyle.style ) {
                  me.drawGrid();
                }
            }
            me.axisBBox = me.axis.getBBox();
            me.drawLabel();
        },
    The comments tell the story. Note that I've only made the mods for non-side axes. We end up with no unnecessary paths to render, and a sparse me.inflections array. Now we need to modify drawGrid() to ignore points (aka inflections) that are null:-

    Code:
        /**
         * Renders an horizontal and/or vertical grid into the Surface.
         */
        drawGrid: function() {
            var me = this,
                surface = me.getSurface(),
                grid = me.gridStyle.style || me.grid,
                odd = me.gridStyle.oddStyle.style || grid.odd,
                even = me.gridStyle.evenStyle.style || grid.even,
                inflections = me.inflections,
                ln = inflections.length - ((odd || even)? 0 : 1),
                position = me.position,
                gutter = me.chart.maxGutter,
                width = me.width - 2,
                point, prevPoint,
                i = 1,
                isSide = me.isSide(),
                path = [], styles, lineWidth, dlineWidth,
                oddPath = [], evenPath = [];
    
            if ((gutter[1] !== 0 && isSide) ||
                (gutter[0] !== 0 && !isSide)) {
                i = 0;
                ln++;
            }
            for (; i < ln; i++) {
                point = inflections[i];
    
                // AJW: if point is null, this means that a grid line is not wanted for this inflection.
                if (point === null) {
                    continue;
                }
    
                prevPoint = inflections[i - 1];
                if (odd || even) {
                    path = (i % 2)? oddPath : evenPath;
                    styles = ((i % 2)? odd : even) || {};
                    lineWidth = (styles.lineWidth || styles['stroke-width'] || 0) / 2;
                    dlineWidth = 2 * lineWidth;
                    if (position == 'left') {
                        path.push("M", prevPoint[0] + 1 + lineWidth, prevPoint[1] + 0.5 - lineWidth,
                                  "L", prevPoint[0] + 1 + width - lineWidth, prevPoint[1] + 0.5 - lineWidth,
                                  "L", point[0] + 1 + width - lineWidth, point[1] + 0.5 + lineWidth,
                                  "L", point[0] + 1 + lineWidth, point[1] + 0.5 + lineWidth, "Z");
                    }
                    else if (position == 'right') {
                        path.push("M", prevPoint[0] - lineWidth, prevPoint[1] + 0.5 - lineWidth,
                                  "L", prevPoint[0] - width + lineWidth, prevPoint[1] + 0.5 - lineWidth,
                                  "L", point[0] - width + lineWidth, point[1] + 0.5 + lineWidth,
                                  "L", point[0] - lineWidth, point[1] + 0.5 + lineWidth, "Z");
                    }
                    else if (position == 'top') {
                        path.push("M", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] + 1 + lineWidth,
                                  "L", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] + 1 + width - lineWidth,
                                  "L", point[0] + 0.5 - lineWidth, point[1] + 1 + width - lineWidth,
                                  "L", point[0] + 0.5 - lineWidth, point[1] + 1 + lineWidth, "Z");
                    }
                    else {
                        path.push("M", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] - lineWidth,
                                "L", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] - width + lineWidth,
                                "L", point[0] + 0.5 - lineWidth, point[1] - width + lineWidth,
                                "L", point[0] + 0.5 - lineWidth, point[1] - lineWidth, "Z");
                    }
                } else {
                    if (position == 'left') {
                        path = path.concat(["M", point[0] + 0.5, point[1] + 0.5, "l", width, 0]);
                    }
                    else if (position == 'right') {
                        path = path.concat(["M", point[0] - 0.5, point[1] + 0.5, "l", -width, 0]);
                    }
                    else if (position == 'top') {
                        path = path.concat(["M", point[0] + 0.5, point[1] + 0.5, "l", 0, width]);
                    }
                    else {
                        path = path.concat(["M", point[0] + 0.5, point[1] - 0.5, "l", 0, -width]);
                    }
                }
            }
            if (odd || even) {
                if (oddPath.length) {
                    if (!me.gridOdd && oddPath.length) {
                        me.gridOdd = surface.add({
                            type: 'path',
                            path: oddPath
                        });
                    }
                    me.gridOdd.setAttributes(Ext.apply({
                        path: oddPath,
                        hidden: false
                    }, odd || {}), true);
                }
                if (evenPath.length) {
                    if (!me.gridEven) {
                        me.gridEven = surface.add({
                            type: 'path',
                            path: evenPath
                        });
                    }
                    me.gridEven.setAttributes(Ext.apply({
                        path: evenPath,
                        hidden: false
                    }, even || {}), true);
                }
            }
            else {
                if (path.length) {
                    if (!me.gridLines) {
                        me.gridLines = me.getSurface().add({
                            type: 'path',
                            path: path,
                            "stroke-width": me.lineWidth || 1,
                            stroke: me.gridColor || '#ccc'
                        });
                    }
                    me.gridLines.setAttributes({
                        hidden: false,
                        path: path
                    }, true);
                }
                else if (me.gridLines) {
                    me.gridLines.hide(true);
                }
            }
        },

    And we need to modify drawHorizontalLabels() similarly to ignore null points/inflections. Note the extra work I have to do to hide previously rendered labels:-

    Code:
        drawHorizontalLabels: function() {
            var me = this,
                labelConf = me.labelStyle.style,
                renderer = labelConf.renderer || function(v) {
                    return v;
                },
                math = Math,
                floor = math.floor,
                max = math.max,
                axes = me.chart.axes,
                position = me.position,
                inflections = me.inflections,
                ln = inflections.length,
                labels = me.labels,
                skipTicks = me.skipTicks,
                maxHeight = 0,
                ratio,
                bbox, point, prevLabel,
                textLabel, text,
                last, x, y, i, firstLabel;
    
            if (!me.calcLabels && skipTicks) {
                labels = labels.slice(skipTicks);
                ln -= skipTicks;
            }
    
            last = ln - 1;
            //get a reference to the first text label dimensions
            point = inflections[0];
            firstLabel = me.getOrCreateLabel(0, renderer(labels[0]));
            ratio = math.abs(math.sin(labelConf.rotate && (labelConf.rotate.degrees * math.PI / 180) || 0)) >> 0;
    
            for (i = 0; i < ln; i++) {
                point = inflections[i];
    
                // AJW: if point is null, this means that a label is not wanted for this inflection.
                if (point === null) {
                    // AJW: not optimal, and I don't particularly like it, but I had to explicitly put in this
                    // call to hide labels because otherwise changing the store data (e.g. changing time period
                    // selection) won't clear the previously-rendered labels, and labels would overwrite each
                    // other and look very messy.
                    me.getOrCreateLabel(i, text).hide(true);
    
                    continue;
                }
    
                text = renderer(labels[i]);
                textLabel = me.getOrCreateLabel(i, text);
                bbox = textLabel._bbox;
                maxHeight = max(maxHeight, bbox.height + me.dashSize + (labelConf.padding || 0));
                x = floor(point[0] - (ratio? bbox.height : bbox.width) / 2);
                if (me.chart.maxGutter[0] == 0) {
                    if (i == 0 && axes.findIndex('position', 'left') == -1) {
                        x = point[0];
                    }
                    else if (i == last && axes.findIndex('position', 'right') == -1) {
                        x = point[0] - bbox.width;
                    }
                }
                if (position == 'top') {
                    y = point[1] - (me.dashSize * 2) - labelConf.padding - (bbox.height / 2);
                }
                else {
                    y = point[1] + (me.dashSize * 2) + labelConf.padding + (bbox.height / 2);
                }
                if (!me.isPannable()) {
                    x += me.x;
                    y += me.y;
                }
                textLabel.setAttributes({
                    hidden: false,
                    x: x,
                    y: y
                }, true);
                if (labelConf.rotate) {
                    textLabel.setAttributes(labelConf, true);
                }
                // Skip label if there isn't available minimum space
                if (i != 0 && (me.intersect(textLabel, prevLabel)
                    || me.intersect(textLabel, firstLabel))) {
                    textLabel.hide(true);
                    continue;
                }
                prevLabel = textLabel;
            }
    
            return maxHeight;
        },
    Now I specify the filterInflection function in my config:-

    Code:
                        }, {
                            type: 'Time',
                            position: 'bottom',
                            fields: ['date'],
                            dateFormat: 'd M Y',
                            grid: true,
                            filterFnScope: this,
                            filterInflection: function(index) {
                                return ((index % this.keepEvery) === 0);
                            }
                        }],
    Note that this.keepEvery is a number that I set up before loading new data into the store. It's the numer of data points (= number of records in the store) divided by six (the number of sections I want) and rounded down to the nearest integer.

    This is pretty good! I cheated, of course, by only considering the X axis. But now I've got a stock line chart to be proud of.

    It would be great to see something like this officially supported in the next version.

  4. #4
    Touch Premium Member
    Join Date
    Apr 2011
    Location
    Cary, NC
    Posts
    135
    Vote Rating
    0
    Answers
    5
    ChrisWalker is on a distinguished road

      0  

    Default


    @awebb
    I second your request to have the ability to customize the axis labels. Your example does indeed look much better.
    I would go even further for a time scaled axis- have the ability to label at certain time points even if I don't have a point for that particular time. For example, if I am plotting over a range of say, 1 hour, I would like the ability to have the labels every x minutes ie. 1:00, 1:10, 1:20, 1:30 etc. even if I do not have a point at those particular times (example- data comes in at 1:03, 1:06, 1:11, 1:18, 1:25.....).

  5. #5
    Sencha User
    Join Date
    Nov 2010
    Posts
    168
    Vote Rating
    0
    philogb is on a distinguished road

      0  

    Default


    Hi - Thanks for your feedback. I just logged this and we will work on it for the next release.

  6. #6
    Sencha User
    Join Date
    Oct 2011
    Posts
    5
    Vote Rating
    0
    lucastp is on a distinguished road

      0  

    Default


    Hi,

    My problem is approximately the same. I have to reduce the number of labels + dash on the x axis...

    I tried to modify the drawHorizontalLabels and [FONT=Menlo, 'Courier New', Courier, monospace][/FONT] drawVerticalLabels as philogb did but get the errors like me.labelStyle is not defined and me.issPannable() is not defined.

    Am I missing something ?

    Please if there's anyone that solved this problem I would really appreciate any help.

    Thank you,

    Luca