Chart.js: evenly distributes ticks when using maxTicksLimit

I made a line chart using Chart.js version 2.1.3.

var canvas = $('#gold_chart').get(0); var ctx = canvas.getContext('2d'); var fillPatternGold = ctx.createLinearGradient(0, 0, 0, canvas.height); fillPatternGold.addColorStop(0, '#fdca55'); fillPatternGold.addColorStop(1, '#ffffff'); var goldChart = new Chart(ctx, { type: 'line', animation: false, data: { labels: dates, datasets: [{ label: '', data: prices, pointRadius: 0, borderWidth: 1, borderColor: '#a97f35', backgroundColor: fillPatternGold }] }, title: { position: 'bottom', text: '\u7F8E\u5143 / \u76CE\u53F8' }, options: { legend: { display: false }, tooltips: { callback: function(tooltipItem) { return tooltipItem.yLabel; } }, scales: { xAxes: [{ ticks: { maxTicksLimit: 8 } }] } } }); 

The conclusion is as follows:

Screenshot

As you can see, I limited the maximum number of ticks to 8 through maxTicksLimit . However, the distribution is not even. How can I distribute ticks evenly?

ps there are always 289 records in the data set, and data is recorded every 5 minutes. Sample values ​​for the prices variable are:

 [ {"14:10", 1280.3}, {"14:15", 1280.25}, {"14:20", 1282.85} ] 

I tried different maxTicksLimit values ​​and the results are still not evenly distributed.

+9
javascript
May 16 '16 at 9:18
source share
2 answers

Chart.js uses the skipRatio integral (to find out how many tags to skip). With Chart.js v2.1.x you can write your own plugin for using fractional skipRatio




Preview

enter image description here




Script

 Chart.pluginService.register({ afterUpdate: function (chart) { var xScale = chart.scales['x-axis-0']; if (xScale.options.ticks.maxTicksLimit) { // store the original maxTicksLimit xScale.options.ticks._maxTicksLimit = xScale.options.ticks.maxTicksLimit; // let chart.js draw the first and last label xScale.options.ticks.maxTicksLimit = (xScale.ticks.length % xScale.options.ticks._maxTicksLimit === 0) ? 1 : 2; var originalXScaleDraw = xScale.draw xScale.draw = function () { originalXScaleDraw.apply(this, arguments); var xScale = chart.scales['x-axis-0']; if (xScale.options.ticks.maxTicksLimit) { var helpers = Chart.helpers; var tickFontColor = helpers.getValueOrDefault(xScale.options.ticks.fontColor, Chart.defaults.global.defaultFontColor); var tickFontSize = helpers.getValueOrDefault(xScale.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); var tickFontStyle = helpers.getValueOrDefault(xScale.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle); var tickFontFamily = helpers.getValueOrDefault(xScale.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily); var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); var tl = xScale.options.gridLines.tickMarkLength; var isRotated = xScale.labelRotation !== 0; var yTickStart = xScale.top; var yTickEnd = xScale.top + tl; var chartArea = chart.chartArea; // use the saved ticks var maxTicks = xScale.options.ticks._maxTicksLimit - 1; var ticksPerVisibleTick = xScale.ticks.length / maxTicks; // chart.js uses an integral skipRatio - this causes all the fractional ticks to be accounted for between the last 2 labels // we use a fractional skipRatio var ticksCovered = 0; helpers.each(xScale.ticks, function (label, index) { if (index < ticksCovered) return; ticksCovered += ticksPerVisibleTick; // chart.js has already drawn these 2 if (index === 0 || index === (xScale.ticks.length - 1)) return; // copy of chart.js code var xLineValue = this.getPixelForTick(index); var xLabelValue = this.getPixelForTick(index, this.options.gridLines.offsetGridLines); if (this.options.gridLines.display) { this.ctx.lineWidth = this.options.gridLines.lineWidth; this.ctx.strokeStyle = this.options.gridLines.color; xLineValue += helpers.aliasPixel(this.ctx.lineWidth); // Draw the label area this.ctx.beginPath(); if (this.options.gridLines.drawTicks) { this.ctx.moveTo(xLineValue, yTickStart); this.ctx.lineTo(xLineValue, yTickEnd); } // Draw the chart area if (this.options.gridLines.drawOnChartArea) { this.ctx.moveTo(xLineValue, chartArea.top); this.ctx.lineTo(xLineValue, chartArea.bottom); } // Need to stroke in the loop because we are potentially changing line widths & colours this.ctx.stroke(); } if (this.options.ticks.display) { this.ctx.save(); this.ctx.translate(xLabelValue + this.options.ticks.labelOffset, (isRotated) ? this.top + 12 : this.options.position === "top" ? this.bottom - tl : this.top + tl); this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1); this.ctx.font = tickLabelFont; this.ctx.textAlign = (isRotated) ? "right" : "center"; this.ctx.textBaseline = (isRotated) ? "middle" : this.options.position === "top" ? "bottom" : "top"; this.ctx.fillText(label, 0, 0); this.ctx.restore(); } }, xScale); } }; } }, }); 



Fiddle - http://jsfiddle.net/bh63pe1v/

+17
May 16 '16 at 15:01
source share

A simpler solution until this is fixed by the JS Chart members is to include the decimal in maxTicksLimit .

For example:

 maxTicksLimit: 8, 

produces a huge gap at the end.

 maxTicksLimit: 8.1, 

Does not produce a huge gap at the end.

Depending on what you want to set for maxTicksLimit, you need to play with different decimal places to see which one gives the best result.

0
Feb 07 '19 at 2:38
source share



All Articles