chartjs / chartjs-plugin-annotation

Annotation plugin for Chart.js
MIT License
603 stars 325 forks source link

(x|y)Adjust scriptable context not working properly (cached and overrided) #788

Closed guillaume-ro-fr closed 2 years ago

guillaume-ro-fr commented 2 years ago

Hello 👋

I'm using the yAdjust property on label annotation for a box. The box is larger than the complete chart, which adjusts to the Y axis. Until the previous version of this plugin, I used yAdjust to correct the centering of the title (which when the "center" option is used, is centered with respect to the whole box and not the chart).

For that, I used this code:

yAdjust: (ctx: PartialEventContext) => (ctx.chart.chartArea.height - ctx.element.y) / 2,

With the double execution, I can just return 0 (or any value) when ctx.element.y is not ready, and return the correct value on the second execution:

if (typeof ctx.element.label?.y === 'undefined') {
    return 0; // Any value
}
return (ctx.chart.chartArea.height - ctx.element.label.y) / 2;

But now, this code doesn't work anymore, (I think) because of the merge request #725: yAdjust is evaluated twice but cached by the Proxy object:

The problem is at line 64: resolver.label object contains the cached value of yAdjust (first call) and resolveAnnotationOptions method override element.elements[0].options.yAdjust (correct value with second call) with resolver.label.yAdjust value.

https://github.com/chartjs/chartjs-plugin-annotation/blob/5d9042ce25cae24f5e095b4996d1ca4c0259fd77/src/elements.js#L45-L64

Here is an example of my code (the red zone is the one with title uncentered):

https://codepen.io/guillaume-ro-fr/full/jOzXpMz

Don't hesitate to tell me if you need more information (I tried to return a Proxy instead of a raw number, but I failed...). Maybe related to #726

stockiNail commented 2 years ago

@guillaume-ro-fr I'm still having a look if it's possible to remove the cache from proxy for some options.

When you are mentioning double execution, are you meaning after a chart update? AFA I remember, the behavior should be the same of previous version. But I'll have a look in deep. It happened (and happens) for all options used for element initialization. Can I evaluate another method to positioning the label in the center of the box, without using element options?

stockiNail commented 2 years ago

@guillaume-ro-fr in the meanwhile, I'm sharing with you the following yAdjust scriptable options which is working as you want since the first callback invocation. Let me know if it helps.

yAdjust: (ctx) => {
    const chart = ctx.chart;
    const options = chart.options.plugins.annotation.annotations[ctx.id];
    const maxPx = chart.scales.y.getPixelForValue(options.yMax);
    const base = chart.scales.y.getBasePixel();
    const font = Chart.helpers.toFont(options.label.font);
    return (base - maxPx - font.lineHeight) / 2;
},
guillaume-ro-fr commented 2 years ago

When you are mentioning double execution, are you meaning after a chart update?

In the same update event. I don't know if it is relevant to send you the backtrace (with Webstorm, and I don't know if it is possible 🤷‍♂️).

But THANK YOU very much for your solution, it works perfectly!!! 🎉 It's been 3 hours that I try to find a solution through different means...

stockiNail commented 2 years ago

But THANK YOU very much for your solution, it works perfectly!!! 🎉

Glad to know that it was helpful!