Theses days, I’m working on a big Angular application that contains a lot of graph highly customized thanks to Chart.JS.

One of that chart is a bar chart displaying data according to hours on the X-axis:

As you can see, we show labels only on some points so our customer asked us if there is a way to remove the marks corresponding to empty ticks.
Unfortunately, I’ve not found any way to do it out of the box (no properties or callbacks that I could use to implement this feature).

After looking for a long time, I’ve finally managed to do it, thanks to the plugins system that can be used in Chart.JS. The basic idea is pretty simple: we’ll just disable the standard ticks drawing and we’ll draw the ticks:

Chart.plugins.register({
	beforeDraw: function (chart) {
		const chartContext = chart.ctx;
		const hoursAxis = (<any>chart).scales['hours'];
		if (hoursAxis !== undefined) {
			const bottomY = (<any>chart).scales['one'].bottom;

			hoursAxis.options.gridLines.display = false;
			hoursAxis.ticks.forEach(function (label, index) {
				const xPosition = hoursAxis.getPixelForTick(index);

				chartContext.save();
				chartContext.beginPath();

				if (label !== '') {
					chartContext.moveTo(xPosition, bottomY - 5);
					chartContext.lineTo(xPosition, bottomY);
					chartContext.strokeStyle = 'rgba(90, 42, 83, 0.5)';
				}

				chartContext.lineWidth = 1;
				chartContext.stroke();
				chartContext.restore();
			});
		}
	}
});

Here are some details on the previous code:

  • First, we get a reference to the “hours” axis, which is just the X-axis
  • Then, we hide the default tick marks
  • Finally, for each tick, we just compute its position and we draw a small line

So, as you can see, the trick is just to draw the ticks. Yes, it might be a bit overkill (if you have a better idea, feel free to tell me) but in the end, it’s working fine:

The funny thing is, using this technique, you can draw almost everything on the chart. Here, for example, I draw the day names corresponding to the hours to the perfect position (under the “12:00”):

If needed,/for reference here is the code used to do that:

if (daysAxis !== undefined &amp;&amp; majorTickMarks.length > 0) {
	let majorTickMarksIndex = 0;

	const bottomY = (<any>chart).scales['one'].bottom;

	daysAxis.options.gridLines.display = false;
	daysAxis.ticks.forEach(function (label, index) {
		const xPosition = daysAxis.getPixelForTick(index);

		chartContext.save();
		chartContext.font = 'bold 12px Roboto';
		chartContext.fillStyle = '#333333';

		if (label !== '') {
			chartContext.fillText(label, majorTickMarks[majorTickMarksIndex] - chartContext.measureText(label).width / 2, bottomY + 45);
			majorTickMarksIndex++;
		} else {
			chartContext.fillText('', xPosition, bottomY);
		}

		chartContext.restore();
	});
}

Happy coding!


ASP.NET Core and the "No service for type 'Microsoft.AspNetCore.Identity.SignInManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' has been registered" error How to use FontAwesome in an HTML 5 Canvas

Leave a Reply

Your email address will not be published. Required fields are marked *