chartjs / chartjs-plugin-annotation

Annotation plugin for Chart.js
MIT License
609 stars 329 forks source link

Get other annotations width from an annotation scriptable option. #865

Closed zk118 closed 2 months ago

zk118 commented 1 year ago

Hey, thank's for this usefull plugin !

I would like to get the width of an annotation from within another annotation scriptable option (to place the 2nd annotation next to the first relative to the width of the 1st annotation).

I want to accomplish something like that:

annotation1: {
    type: 'label',
    xValue: () => 0,
    yValue: () => 1,
    content: () => "Annotation 1",
    padding: 5,
    color: 'black',
},

annotation2: {
    type: 'label',
    xValue: () => 0,
    yValue: () => 1,
    xAjust: (cxt) => {
        return ctx.chart.options.plugins.annotation.annotations.annotation1.width
    },
    content: () => "Annotation 2",
    padding: 5,
    color: 'black',
}

But the problem is ctx.chart.options.plugins.annotation.annotations.annotation1.width doesn't exists. Is it possible to achieve ?

Thanks in advance.

stockiNail commented 1 year ago

@evenmind the width of an annotation is a property of the annotation elements which are NOT exported (and then NOT exposed). There is a workaround to access to the elements but not documented and let me call it "private". Let me ask you if the center of the first label must be the point you selected or not. If not, you could use position option to align them. Make sense for you?

zk118 commented 1 year ago

@stockiNail thank you for fast reply. In fact, I need them to be aligned next to each other, the 2nd one starts where the 1st finish, and so on for the 3rd, 4th etc. If I have the center point of 1st annotation, I could calculate the end of 1st annotation: x + (x + center)*2, but how can I access the center point ?

stockiNail commented 1 year ago

If you have to add more than 2 labels, it's not possible, because the position option enable you to decide, depending the point, if you want the label all on the right or on the left (or top or bottom). But with more than 2, it' not possible by position.

I could calculate the end of 1st annotation: x + (x + center)*2, but how can I access the center point ?

As said, the x, y, x2, y2, width, height, centerX and centerY are all properties of the annotation elements which are not officially exposed. :( See https://github.com/chartjs/chartjs-plugin-annotation/discussions/775#discussioncomment-3320658 to see how to access to the "private" state (and then elements). Be aware it could be removed any time.

In the next version, there will be 2 new hooks which can help you on that: https://github.com/chartjs/chartjs-plugin-annotation/pull/744

Setting the z options (to be sure that the labels are draw in the right order), you could take the width (storing it in a variable) and change accordingly all the other labels (accessing to the element).

stockiNail commented 1 year ago

Anyway, even accessing to the loaded elements, you don't know the width of the label you want to change therefore it's quite difficult I guess.

zk118 commented 1 year ago

I will check the private state in the meantime the next version is live, thanks.

stockiNail commented 1 year ago

I think we could add the loaded elements to the element context in order to address this use case (and also others). @kurkle what do you think?

zk118 commented 1 year ago

I get undefined for window['chartjs-plugin-annotation']

stockiNail commented 1 year ago

I get undefined for window['chartjs-plugin-annotation']

Can you provide a sample to reproduce the issue?

zk118 commented 1 year ago

I literally just

annotation2: {
    type: 'label',
    xValue: () => 0,
    yValue: () => 1,
    xAjust: (cxt) => {
        console.log(window['chartjs-plugin-annotation'])
    },
    content: () => "Annotation 2",
    padding: 5,
    color: 'black',
}

and get undefined. Maybe this is because I'm using vue-chartjs wrapper and it does not inject 'chartjs-plugin-annotation' in the window ?

stockiNail commented 1 year ago

Maybe this is because I'm using vue-chartjs wrapper and it does not inject 'chartjs-plugin-annotation' in the window ?

Yes, I think so. I think you are importing the plugin, something like:

import annotationPlugin from 'chartjs-plugin-annotation';

If yes, use annotationPlugin instance instead

zk118 commented 1 year ago

If yes, use annotationPlugin instance instead

Works ! Thank you.

stockiNail commented 1 year ago

@evenmind just FYI, I have submitted a PR https://github.com/chartjs/chartjs-plugin-annotation/pull/869 which is adding the elements to the context. In this way, you will not need to use the undocumented API but you can use the elements in the context. Panned for version 3.0.