Chart.js icon indicating copy to clipboard operation
Chart.js copied to clipboard

Guidance on adding line shadows in v4

Open JG-QuarkNet opened this issue 2 years ago • 2 comments

Documentation Is:

  • [X] Missing or needed?
  • [ ] Confusing
  • [ ] Not sure?

Please Explain in Detail...

I'm trying to upgrade a graphing app from Flot.js 0.8.3 to use Chart.js 4.4.0. The biggest sticking point is that Flot easily created drop shadows underneath the line of a chart, whereas this is proving to be nearly impossible in Chart.js.

This question has been asked many times over the years, but I can't find any clear, implementable answer for how to do it in Chart.js v4. There is zero documentation on this matter. Probably the best StackOverflow result on the topic is from 2015, which would probably be v1 or v2. In any event, it captures what seems like the three main strategies that people have developed for this:

  1. Make a Plugin
  2. Extend something
  3. Override something

On 1), I've attempted to make a Plugin using the following code:

/* The Chart.js context */
const ctx = document.getElementById('mychart');

/* The Plugin */
const lineShadowPlugin = {
    beforeDraw : function(chartInstance) {
        let _stroke = chartInstance.ctx.stroke;
        chartInstance.ctx.stroke = function () {

            chartInstance.ctx.save();

            chartInstance.ctx.shadowColor = 'gray';
            chartInstance.ctx.shadowBlur = 2;
            chartInstance.ctx.shadowOffsetX = 0.5;
            chartInstance.ctx.shadowOffsetY = 2.5;

            _stroke.apply(this, arguments)
            chartInstance.ctx.restore();
        };

        let _fill = chartInstance.ctx.fill;
        ctx.fill = function () {

            chartInstance.ctx.save();

            chartInstance.ctx.shadowColor = 'gray';
            chartInstance.ctx.shadowBlur = 10;
            chartInstance.ctx.shadowOffsetX = 2;
            chartInstance.ctx.shadowOffsetY = 2;

            _fill.apply(this, arguments)
            chartInstance.ctx.restore();
        };
    }
};

/* The Chart
let chartjs_plot = new Chart(ctx, {
    type: 'scatter',
    data: { ... },
    plugins: [lineShadowPlugin],
    options: { ... }
});

This does work to create a shadow under the line, but it also creates shadows under all of the other chart elements, which I don't want.

On 2), I've tried the code for overriding the Chart.js draw() function from this StackOverflow answer for Chart.js v2, but it results in a this.chart.chart is undefined error, which I suppose is the result of a namespace change between Chart.js v2 and v4.

I've found this issue on the topic, which was moved to a discussion. That discussion centers on overriding the draw function, but it doesn't include enough information for me to get a working chart out of it.

On 3), I've tried the code for extending Chart.types.Line from this StackOverflow answer, but it results in a Chart.types is undefined error, which I also suppose is the result of a namespace change between whatever Chart.js version it was written for and v4.

I've also found this approach for extending LineController with a custom class:

class Custom extends Chart.LineController {
    draw() {
        /* Call the line controller method to draw points */
        super.draw(arguments);

        /* custom drawing */
        const ctx = this.chart.ctx;
        let _stroke = ctx.stroke;

        ctx.stroke = function () {
            ctx.save();
            ctx.shadowColor = 'black';
            ctx.shadowBlur = 10;
            ctx.shadowOffsetX = 0;
            ctx.shadowOffsetY = 4;
            _stroke.apply(this, arguments);
            ctx.restore();
        }
    }
};

Custom.id = 'shadowline'; // chart type name
Custom.defaults = Chart.LineController.defaults;

When I implement this, there is again a drop shadow under everything, and also my data is messed up.

I also found this Chart.js feature request for exactly what I and countless others are struggling with, but which was dismissed by @LeeLenaleee as "externally implementable by plugin hooks" with no further guidance. If it's open for discussion, I strongly support making line shadows a core feature of Chart.js, given that it's an in-demand feature that's preposterously difficult for the average user to accomplish using Plugins.

This is essentially a crosspost of this StackOverflow question, which has been sitting for a month with one comment and no conclusive results.

So, how can I accomplish this? Again, the three requirements are

  1. Create a drop shadow under the line of a line or scatter plot,
  2. Not create a shadow under any other element of the chart, and
  3. Work with Chart.js v4 (specifically 4.4.0)

Thank you to everyone at Chart.js for your work on the library, and thanks in advance to anyone who can help me.

Your Proposal for Changes

Either add shadows as a core feature (feature request, preferable but already rejected) or please explain how to do this somewhere.

Example

No response

JG-QuarkNet avatar Nov 14 '23 21:11 JG-QuarkNet

+1 for documenting how a shadow effect can be added using a plugin. For a newbie to this library it might be easier to just find another library to use rather than jumping into the plugin framework/library internals.

siderakis avatar Feb 22 '24 22:02 siderakis

I finally achieved it, it took me a lot of time, and I hope it helps other people https://stackoverflow.com/a/78905082/11327943

2234839 avatar Aug 23 '24 08:08 2234839