web-dev-qa-db-fra.com

Graphique.js axe x

Je me demandais s’il existait un moyen d’incrémenter les étiquettes de l’axe X dans chart.js d’une certaine échelle.

J'ai des étiquettes allant de 50 à 90, et chaque nombre entre les deux est affiché. 

J'aimerais énumérer les étiquettes par 5 ou 10, car elles sont actuellement toutes regroupées.

La partie gauche de l’axe des y est également coupée.

13
roeaxs92

EDIT 2: Ok, donc j’avais besoin d’une telle fonctionnalité dans un projet sur lequel je travaille, j’ai donc créé une version personnalisée de chart.js pour inclure cette fonctionnalité. http://jsfiddle.net/ leighking2/mea767ss/ ou https://github.com/leighquince/Chart.js

C'est une combinaison des deux solutions ci-dessous mais liées au cœur de CHart.js, il n'est donc pas nécessaire de spécifier une échelle et des graphiques personnalisés.

Les graphiques à barres et à barres ont une nouvelle option appelée

labelsFilter:function(label, index){return false;)

par défaut, cela retournera simplement false afin que toutes les étiquettes sur l'axe des abscisses s'afficheront, mais si un filtre est passé en tant qu'option, il filtrera les étiquettes.

alors voici un exemple avec barre et ligne

var ctx = document.getElementById("chart").getContext("2d");
var data = {
    labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
    datasets: [{
        label: "My First dataset",
        fillColor: "rgba(220,220,220,0.5)",
        strokeColor: "rgba(220,220,220,0.8)",
        highlightFill: "rgba(220,220,220,0.75)",
        highlightStroke: "rgba(220,220,220,1)",

        data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
    }]
};


var myLineChart = new Chart(ctx).Line(data, {
    labelsFilter: function (value, index) {
        return (index + 1) % 5 !== 0;
    }
});
<script src="http://quincewebdesign.com/cdn/Chart.js"></script>
<canvas id="chart" width="1200px"></canvas>


REPONSE ORIGINALE

Vous pouvez remplacer la fonction de dessin d'échelle pour y parvenir. La seule chose que je n'aime pas à ce sujet est que cela s'appliquera à tous vos graphiques. L'autre option consiste à avoir un type de graphique personnalisé qui utilise le dessin remplacé.

EDIT 1: on vient de réaliser le même effet en utilisant la valeur d'index plutôt que l'étiquette et cela peut ensuite être appliqué à tous les types d'étiquettes, pas seulement numériques, cela s'applique aux deux exemples et peut être facilement modifié Voici le deuxième exemple utilisant l’index plutôt que le libellé http://jsfiddle.net/leighking2/n9c8jx55/

1st - Remplacement de la fonction de dessin d'échellehttp://jsfiddle.net/leighking2/96grgz0d/

Avant de dessiner l'étiquette de l'axe des abscisses, nous testons si l'étiquette est un nombre et si son reste divisé par 5 n'est pas égal à 0 (donc tout nombre non divisible par 5) S'il correspond à ces deux critères on ne dessine pas l'étiquette

Chart.Scale = Chart.Scale.extend({
   draw : function(){
           console.log(this);
           var helpers = Chart.helpers;
           var each = helpers.each;
           var aliasPixel = helpers.aliasPixel;
              var toRadians = helpers.radians;
            var ctx = this.ctx,
                yLabelGap = (this.endPoint - this.startPoint) / this.steps,
                xStart = Math.round(this.xScalePaddingLeft);
            if (this.display){
                ctx.fillStyle = this.textColor;
                ctx.font = this.font;
                each(this.yLabels,function(labelString,index){
                    var yLabelCenter = this.endPoint - (yLabelGap * index),
                        linePositionY = Math.round(yLabelCenter);

                    ctx.textAlign = "right";
                    ctx.textBaseline = "middle";
                    if (this.showLabels){
                        ctx.fillText(labelString,xStart - 10,yLabelCenter);
                    }
                    ctx.beginPath();
                    if (index > 0){
                        // This is a grid line in the centre, so drop that
                        ctx.lineWidth = this.gridLineWidth;
                        ctx.strokeStyle = this.gridLineColor;
                    } else {
                        // This is the first line on the scale
                        ctx.lineWidth = this.lineWidth;
                        ctx.strokeStyle = this.lineColor;
                    }

                    linePositionY += helpers.aliasPixel(ctx.lineWidth);

                    ctx.moveTo(xStart, linePositionY);
                    ctx.lineTo(this.width, linePositionY);
                    ctx.stroke();
                    ctx.closePath();

                    ctx.lineWidth = this.lineWidth;
                    ctx.strokeStyle = this.lineColor;
                    ctx.beginPath();
                    ctx.moveTo(xStart - 5, linePositionY);
                    ctx.lineTo(xStart, linePositionY);
                    ctx.stroke();
                    ctx.closePath();

                },this);

                each(this.xLabels,function(label,index){
                    //================================
                    //test to see if we draw the label
                    //================================
                    if(typeof label === "number" && label%5 != 0){
                     return;   
                    }
                    var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
                        // Check to see if line/bar here and decide where to place the line
                        linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
                        isRotated = (this.xLabelRotation > 0);

                    ctx.beginPath();

                    if (index > 0){
                        // This is a grid line in the centre, so drop that
                        ctx.lineWidth = this.gridLineWidth;
                        ctx.strokeStyle = this.gridLineColor;
                    } else {
                        // This is the first line on the scale
                        ctx.lineWidth = this.lineWidth;
                        ctx.strokeStyle = this.lineColor;
                    }
                    ctx.moveTo(linePos,this.endPoint);
                    ctx.lineTo(linePos,this.startPoint - 3);
                    ctx.stroke();
                    ctx.closePath();


                    ctx.lineWidth = this.lineWidth;
                    ctx.strokeStyle = this.lineColor;


                    // Small lines at the bottom of the base grid line
                    ctx.beginPath();
                    ctx.moveTo(linePos,this.endPoint);
                    ctx.lineTo(linePos,this.endPoint + 5);
                    ctx.stroke();
                    ctx.closePath();

                    ctx.save();
                    ctx.translate(xPos,(isRotated) ? this.endPoint + 12 : this.endPoint + 8);
                    ctx.rotate(toRadians(this.xLabelRotation)*-1);

                    ctx.textAlign = (isRotated) ? "right" : "center";
                    ctx.textBaseline = (isRotated) ? "middle" : "top";
                    ctx.fillText(label, 0, 0);
                    ctx.restore();

                },this);

            }
        } 
});

alors nous pouvons utiliser les graphiques comme d'habitude. Déclarer des données

var ctx = document.getElementById("chart").getContext("2d");
var data = {
    labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
    datasets: [{
        label: "My First dataset",
        fillColor: "rgba(220,220,220,0.2)",
        strokeColor: "rgba(220,220,220,1)",
        pointColor: "rgba(220,220,220,1)",
        pointStrokeColor: "#fff",
        pointHighlightFill: "#fff",
        pointHighlightStroke: "rgba(220,220,220,1)",
        data: [65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45]
    }, ]
};

dessiner un graphique

var myLineChart = new Chart(ctx).Line(data);

2ème graphe personnalisé + échelle personnalisée + fonction de filtragehttp://jsfiddle.net/leighking2/6xej5ek3/

Dans cette méthode, nous devons toujours créer un objet d'échelle personnalisé mais, au lieu de l'appliquer à tous les graphiques que nous créons, nous pouvons choisir de l'appliquer uniquement à ceux que nous avons déclarés. De plus, dans cet exemple, le filtre peut également être une fonction qui est appliquée au moment de l'exécution afin que chaque graphe puisse filtrer les étiquettes différemment.

d'abord l'objet à l'échelle

Chart.CustomScale = Chart.Scale.extend({
    draw: function () {
        console.log(this);
        var helpers = Chart.helpers;
        var each = helpers.each;
        var aliasPixel = helpers.aliasPixel;
        var toRadians = helpers.radians;
        var ctx = this.ctx,
            yLabelGap = (this.endPoint - this.startPoint) / this.steps,
            xStart = Math.round(this.xScalePaddingLeft);
        if (this.display) {
            ctx.fillStyle = this.textColor;
            ctx.font = this.font;
            each(this.yLabels, function (labelString, index) {
                var yLabelCenter = this.endPoint - (yLabelGap * index),
                    linePositionY = Math.round(yLabelCenter);

                ctx.textAlign = "right";
                ctx.textBaseline = "middle";
                if (this.showLabels) {
                    ctx.fillText(labelString, xStart - 10, yLabelCenter);
                }
                ctx.beginPath();
                if (index > 0) {
                    // This is a grid line in the centre, so drop that
                    ctx.lineWidth = this.gridLineWidth;
                    ctx.strokeStyle = this.gridLineColor;
                } else {
                    // This is the first line on the scale
                    ctx.lineWidth = this.lineWidth;
                    ctx.strokeStyle = this.lineColor;
                }

                linePositionY += helpers.aliasPixel(ctx.lineWidth);

                ctx.moveTo(xStart, linePositionY);
                ctx.lineTo(this.width, linePositionY);
                ctx.stroke();
                ctx.closePath();

                ctx.lineWidth = this.lineWidth;
                ctx.strokeStyle = this.lineColor;
                ctx.beginPath();
                ctx.moveTo(xStart - 5, linePositionY);
                ctx.lineTo(xStart, linePositionY);
                ctx.stroke();
                ctx.closePath();

            }, this);

            each(this.xLabels, function (label, index) {
                //======================================================
                //apply the filter the the label if it is a function
                //======================================================
                if (typeof this.labelsFilter === "function" && this.labelsFilter(label)) {
                    return;
                }
                var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
                    // Check to see if line/bar here and decide where to place the line
                    linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
                    isRotated = (this.xLabelRotation > 0);

                ctx.beginPath();

                if (index > 0) {
                    // This is a grid line in the centre, so drop that
                    ctx.lineWidth = this.gridLineWidth;
                    ctx.strokeStyle = this.gridLineColor;
                } else {
                    // This is the first line on the scale
                    ctx.lineWidth = this.lineWidth;
                    ctx.strokeStyle = this.lineColor;
                }
                ctx.moveTo(linePos, this.endPoint);
                ctx.lineTo(linePos, this.startPoint - 3);
                ctx.stroke();
                ctx.closePath();


                ctx.lineWidth = this.lineWidth;
                ctx.strokeStyle = this.lineColor;


                // Small lines at the bottom of the base grid line
                ctx.beginPath();
                ctx.moveTo(linePos, this.endPoint);
                ctx.lineTo(linePos, this.endPoint + 5);
                ctx.stroke();
                ctx.closePath();

                ctx.save();
                ctx.translate(xPos, (isRotated) ? this.endPoint + 12 : this.endPoint + 8);
                ctx.rotate(toRadians(this.xLabelRotation) * -1);

                ctx.textAlign = (isRotated) ? "right" : "center";
                ctx.textBaseline = (isRotated) ? "middle" : "top";
                ctx.fillText(label, 0, 0);
                ctx.restore();

            }, this);

        }
    }
});

maintenant le graphe personnalisé qui utilisera cette échelle, plutôt ennuyeux nous devons écraser toute la fonction buildscale

Chart.types.Line.extend({
    name: "LineAlt",
    initialize: function (data) {
        //======================================================
        //ensure the new option is part of the options
        //======================================================
        this.options.labelsFilter = data.labelsFilter || null;
        Chart.types.Line.prototype.initialize.apply(this, arguments);


    },
    buildScale: function (labels) {
        var helpers = Chart.helpers;
        var self = this;

        var dataTotal = function () {
            var values = [];
            self.eachPoints(function (point) {
                values.Push(point.value);
            });

            return values;
        };
        var scaleOptions = {
            templateString: this.options.scaleLabel,
            height: this.chart.height,
            width: this.chart.width,
            ctx: this.chart.ctx,
            textColor: this.options.scaleFontColor,
            fontSize: this.options.scaleFontSize,
            //======================================================
            //pass this new options to the scale object
            //======================================================
            labelsFilter: this.options.labelsFilter,
            fontStyle: this.options.scaleFontStyle,
            fontFamily: this.options.scaleFontFamily,
            valuesCount: labels.length,
            beginAtZero: this.options.scaleBeginAtZero,
            integersOnly: this.options.scaleIntegersOnly,
            calculateYRange: function (currentHeight) {
                var updatedRanges = helpers.calculateScaleRange(
                dataTotal(),
                currentHeight,
                this.fontSize,
                this.beginAtZero,
                this.integersOnly);
                helpers.extend(this, updatedRanges);
            },
            xLabels: labels,
            font: helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
            lineWidth: this.options.scaleLineWidth,
            lineColor: this.options.scaleLineColor,
            gridLineWidth: (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
            gridLineColor: (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
            padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
            showLabels: this.options.scaleShowLabels,
            display: this.options.showScale
        };

        if (this.options.scaleOverride) {
            helpers.extend(scaleOptions, {
                calculateYRange: helpers.noop,
                steps: this.options.scaleSteps,
                stepValue: this.options.scaleStepWidth,
                min: this.options.scaleStartValue,
                max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
            });
        }

        //======================================================
        //Use the new Custom Scal that will make use of a labelsFilter function
        //======================================================
        this.scale = new Chart.CustomScale(scaleOptions);
    }
});

alors nous pouvons l'utiliser comme d'habitude. Déclarer les données mais passer cette fois une nouvelle option pour labelsFilter, une fonction permettant d'appliquer le filtrage des x labels

var ctx = document.getElementById("chart").getContext("2d");
var data = {
    labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
    labelsFilter: function (label) {
        //return true if this label should be filtered out
        return label % 5 !== 0;
    },
    datasets: [{
        label: "My First dataset",
        fillColor: "rgba(220,220,220,0.2)",
        strokeColor: "rgba(220,220,220,1)",
        pointColor: "rgba(220,220,220,1)",
        pointStrokeColor: "#fff",
        pointHighlightFill: "#fff",
        pointHighlightStroke: "rgba(220,220,220,1)",
        data: [65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45]
    }, ]
};

puis dessinez le graphique en utilisant notre nouveau nom de graphique personnalisé

var myLineChart = new Chart(ctx).LineAlt(data);

Globalement, même si cela est un peu plus complexe, je préfère la deuxième méthode car cela signifie qu’un filtre personnalisé peut être appliqué à chaque graphe que je déclare.

29
Quince

J'ai mis à jour l'extrait de code fourni pour empêcher la rotation des étiquettes de l'axe des abscisses. De plus, certains paramètres n'étaient pas transmis dans le constructeur. Vérifiez les commentaires // Mike Walder.

 //Code to manually set the interval of X-Axis Labels: From http://jsfiddle.net/leighking2/n9c8jx55/
        Chart.CustomScale = Chart.Scale.extend({
            draw: function () {
                var helpers = Chart.helpers;
                var each = helpers.each;
                var aliasPixel = helpers.aliasPixel;
                var toRadians = helpers.radians;
                var ctx = this.ctx,
                    yLabelGap = (this.endPoint - this.startPoint) / this.steps,
                    xStart = Math.round(this.xScalePaddingLeft);
                if (this.display) {
                    ctx.fillStyle = this.textColor;
                    ctx.font = this.font;
                    each(this.yLabels, function (labelString, index) {
                        var yLabelCenter = this.endPoint - (yLabelGap * index),
                            linePositionY = Math.round(yLabelCenter);

                        ctx.textAlign = "right";
                        ctx.textBaseline = "middle";
                        if (this.showLabels) {
                            ctx.fillText(labelString, xStart - 10, yLabelCenter);
                        }
                        ctx.beginPath();
                        if (index > 0) {
                            // This is a grid line in the centre, so drop that
                            ctx.lineWidth = this.gridLineWidth;
                            ctx.strokeStyle = this.gridLineColor;
                        } else {
                            // This is the first line on the scale
                            ctx.lineWidth = this.lineWidth;
                            ctx.strokeStyle = this.lineColor;
                        }

                        linePositionY += helpers.aliasPixel(ctx.lineWidth);

                        ctx.moveTo(xStart, linePositionY);
                        ctx.lineTo(this.width, linePositionY);
                        ctx.stroke();
                        ctx.closePath();

                        ctx.lineWidth = this.lineWidth;
                        ctx.strokeStyle = this.lineColor;
                        ctx.beginPath();
                        ctx.moveTo(xStart - 5, linePositionY);
                        ctx.lineTo(xStart, linePositionY);
                        ctx.stroke();
                        ctx.closePath();

                    }, this);

                    each(this.xLabels, function (label, index) {
                        //======================================================
                        //apply the filter to the index if it is a function
                        //======================================================
                        if (typeof this.labelsFilter === "function" && this.labelsFilter(index)) {
                            return;
                        }
                        //Hack by Mike Walder to enforce X-Labels are Written horizontally
                        var xLabelRot = this.xLabelRotation;
                        this.xLabelRotation = 0;
                        //End of Hack
                        var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
                            // Check to see if line/bar here and decide where to place the line
                            linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
                            //Mike Walder: isRotated nees original Roation Value to display the X-Label in the RollOver Area of a Datapoint
                            isRotated = true;(xLabelRot > 0);

                        ctx.beginPath();
                    if(this.scaleShowVerticalLines){
                            if (index > 0) {
                                // This is a grid line in the centre, so drop that
                                ctx.lineWidth = this.gridLineWidth;
                                ctx.strokeStyle = this.gridLineColor;
                            } else {
                                // This is the first line on the scale
                                ctx.lineWidth = this.lineWidth;
                                ctx.strokeStyle = this.lineColor;
                            }
                            ctx.moveTo(linePos, this.endPoint);
                            ctx.lineTo(linePos, this.startPoint - 3);
                            ctx.stroke();
                            ctx.closePath();


                            ctx.lineWidth = this.lineWidth;
                            ctx.strokeStyle = this.lineColor;
                        }
                        // Small lines at the bottom of the base grid line
                        ctx.beginPath();
                        ctx.moveTo(linePos, this.endPoint);
                        ctx.lineTo(linePos, this.endPoint + 5);
                        ctx.stroke();
                        ctx.closePath();

                        ctx.save();
                        ctx.translate(xPos, (isRotated) ? this.endPoint + 12 : this.endPoint + 8);
                        ctx.rotate(toRadians(this.xLabelRotation) * -1);

                        //Mike Walder added center here, because it looks better if the label designator is in the center of the smal line
                        ctx.textAlign = "center";
                        ctx.textBaseline = (isRotated) ? "middle" : "top";
                        ctx.fillText(label, 0, 0);
                        ctx.restore();

                    }, this);

                }
            }
        });

Chart.types.Line.extend({
            name: "LineAlt",
            initialize: function (data) {
                //======================================================
                //ensure the new option is part of the options
                //======================================================
                this.options.labelsFilter = data.labelsFilter || null;
                Chart.types.Line.prototype.initialize.apply(this, arguments);

            },
            buildScale: function (labels) {
                var helpers = Chart.helpers;
                var self = this;

                var dataTotal = function () {
                    var values = [];
                    self.eachPoints(function (point) {
                        values.Push(point.value);
                    });

                    return values;
                };
                var scaleOptions = {
                    // Mike Walder: added this configuration option since it is overridden in the new code
                    scaleShowVerticalLines: this.options.scaleShowVerticalLines,
                    templateString: this.options.scaleLabel,
                    height: this.chart.height,
                    width: this.chart.width,
                    ctx: this.chart.ctx,
                    textColor: this.options.scaleFontColor,
                    fontSize: this.options.scaleFontSize,
                    //======================================================
                    //pass this new options to the scale object
                    //======================================================
                    labelsFilter: this.options.labelsFilter,
                    fontStyle: this.options.scaleFontStyle,
                    fontFamily: this.options.scaleFontFamily,
                    valuesCount: labels.length,
                    beginAtZero: this.options.scaleBeginAtZero,
                    integersOnly: this.options.scaleIntegersOnly,
                    calculateYRange: function (currentHeight) {
                        var updatedRanges = helpers.calculateScaleRange(
                        dataTotal(),
                        currentHeight,
                        this.fontSize,
                        this.beginAtZero,
                        this.integersOnly);
                        helpers.extend(this, updatedRanges);
                    },
                    xLabels: labels,
                    font: helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
                    lineWidth: this.options.scaleLineWidth,
                    lineColor: this.options.scaleLineColor,
                    gridLineWidth: (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
                    gridLineColor: (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
                    padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
                    showLabels: this.options.scaleShowLabels,
                    display: this.options.showScale
                };

                if (this.options.scaleOverride) {
                    helpers.extend(scaleOptions, {
                        calculateYRange: helpers.noop,
                        steps: this.options.scaleSteps,
                        stepValue: this.options.scaleStepWidth,
                        min: this.options.scaleStartValue,
                        max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
                    });
                }

                //======================================================
                //Use the new Custom Scal that will make use of a labelsFilter function
                //======================================================
                this.scale = new Chart.CustomScale(scaleOptions);
            }
        });
0
Mike Walder