Saltar al contenido

Haga que las etiquetas del eje X en chart.js se incrementen en una escala determinada

Luego de de nuestra extensa búsqueda de datos resolvimos esta incógnita que pueden tener algunos de nuestros usuarios. Te compartimos la solución y nuestro deseo es servirte de gran ayuda.

Solución:

EDITAR 2: Ok, en realidad necesitaba una funcionalidad como esta en un proyecto en el que estoy trabajando, así que hice una compilación personalizada de chart.js para incluir esta funcionalidad. o https://github.com/leighquince/Chart.js

Es una combinación de las dos soluciones a continuación, pero vinculada al núcleo de CHart.js, por lo que no es necesario especificar escalas y gráficos personalizados.

Tanto los gráficos de líneas como los de barras tienen una nueva opción llamada

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

por defecto, esto simplemente volverá false por lo que se mostrarán todas las etiquetas en el eje x, pero si se pasa un filtro como una opción, se filtrarán las etiquetas

así que aquí hay un ejemplo con barra y línea

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


RESPUESTA ORIGINAL

Puede anular la función de dibujo de escala para lograr esto. Lo único que no me gusta de esto es que se aplicará a todos sus gráficos, por lo que la otra opción es tener un tipo de gráfico personalizado que haga uso del dibujo anulado.

EDICIÓN 1: me acabo de dar cuenta de que se puede lograr el mismo efecto utilizando el valor del índice en lugar de la etiqueta y esto se puede aplicar a todos los tipos de etiquetas, no solo a los numéricos, esto se aplica a ambos ejemplos y podría cambiarse fácilmente. Aquí está el segundo ejemplo que usa el índice en lugar de la etiqueta http://jsfiddle.net/leighking2/n9c8jx55/

1o – Anulación de la función de dibujo de escala http://jsfiddle.net/leighking2/96grgz0d/

El único cambio aquí es antes de dibujar la etiqueta del eje x, probamos si la etiqueta es un número y si su resto cuando se divide por 5 no es igual a 0 (por lo que cualquier número no es divisible por 5) si coincide con ambos criterios, no lo hacemos. dibuja la etiqueta

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

            
         
);

entonces podemos usar los gráficos como de costumbre. Declarar datos

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]
    , ]
;

dibujar gráfico

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

2do gráfico personalizado + escala personalizada + función de filtro http://jsfiddle.net/leighking2/6xej5ek3/

En este método, todavía necesitamos crear un objeto de escala personalizado, pero en lugar de aplicarlo a todos los gráficos que creamos, podemos optar por aplicarlo solo a los que hemos declarado. Además, en este ejemplo también podemos hacer que el filtro sea una función que se aplique en el tiempo de ejecución para que podamos hacer que cada gráfico filtre las etiquetas de manera diferente

primero el objeto de escala

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

        
    
);

ahora el gráfico personalizado que hará uso de esta escala, es bastante molesto tener que anular toda la función buildscale

Chart.types.Line.extend(
    name: "LineAlt",
    initialize: function (data) ,
    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);
    
);

entonces podemos usarlo como de costumbre. Declare los datos pero esta vez pase una nueva opción para labelsFilter que es una función para aplicar el filtrado de las etiquetas x

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]
    , ]
;

luego dibuje el gráfico usando nuestro nuevo nombre de gráfico personalizado

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

En general, aunque es un poco más complicado, prefiero el segundo método, ya que significa que se puede aplicar un filtro personalizado a cada gráfico que declaro.

Eres capaz de añadir valor a nuestro contenido informacional colaborando tu experiencia en las referencias.

¡Haz clic para puntuar esta entrada!
(Votos: 2 Promedio: 4.5)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *