1

I have created an annotation with a label (see jsfiddle).

    <html>
        <head>
            <title>test chart</title>
            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
            <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chartjs-plugin-annotation.min.js"></script>
        </head>
        <body onload="initChart()">
    
            Chart:<br>
            <canvas id=chartCanvas>   
            </canvas>
        </body>
    </html>

and


let data = {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
    datasets: [{
            type: 'line',
            label: 'Dataset 1',
            borderColor: 'rgb(54, 162, 235)',
            borderWidth: 2,
            fill: false,
            data: [10, 5, 40, 15, 30, 30, 48]
        }]
};

let  myAnnotation = {
        type: 'line',
        mode: 'vertical',
        scaleID: 'x',
        value: 3,
        endValue: 3,
        borderColor: 'rgb(75, 192, 192)',
        borderWidth: 2,
        borderDash: [20, 10],
        label: {
            position: 25,
            display: true,
            content: ["Special", "Date"],
            rotation: -90,
            color: 'red'
        },
        enter( { element }, event) {
            element.label.options.content = ["Display the Tip"];
            element.label.rotation = 0;    // or even -90
            return true; // force update
        },
        leave( { element }, event) {
            element.label.options.content = name;
            element.label.rotation = -90;
            return true;
        }
    }


let config = {
    type: 'line',
    data,
    options: {
        plugins: {
            annotation: {
                annotations: {
                    myAnnotation
                }
            }
        }
    }
};

function initChart() {
    var ctx = document.getElementById("chartCanvas").getContext("2d");

    let myChart = new Chart(ctx, config)

    return;
}

What I want to do is be able to hover over the label, and it change to another string, preferably horizontally displayed.

Mostly it works, but when the "enter" event is triggered, the textbox and orientation changes, but the size of the label box doesn't, so the text extends outside the boundary of the box.

How can I get the box to resize appropriately?

1 Answer 1

1

The event handler returning true results in a re-rendering of the chart, not an update, see event-handling in chart.js docs, and events in annotation plugin docs. What you need is an actual update that would recompute the properties of the label.

A canonical solution would be to trigger a chart.update call in the event handler. This requires the actual user options to be changed, not their copies in the chart elements; for instance:

const myAnnotation = {
   // ......... other annotation options
   enter({chart}) {
      myAnnotation.label.content = ["Display the Tip"];
      myAnnotation.label.rotation = 0;    // or even -90
      setTimeout(()=>chart.update('none')); // update after this event handling is complete
   }
   // ........
};   

Full snippet demo:

const data = {
   labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
   datasets: [{
      type: 'line',
      label: 'Dataset 1',
      borderColor: 'rgb(54, 162, 235)',
      borderWidth: 2,
      fill: false,
      data: [10, 5, 40, 15, 30, 30, 48]
   }]
};

const myAnnotation = {
   type: 'line',
   mode: 'vertical',
   scaleID: 'x',
   value: 3,
   endValue: 3,
   borderColor: 'rgb(75, 192, 192)',
   borderWidth: 2,
   borderDash: [20, 10],
   label: {
      position: 25,
      display: true,
      content: ["Special", "Date"],
      rotation: -90,
      color: 'red'
   },
   enter({chart}) {
      myAnnotation.label.content = ["Display the Tip"];
      myAnnotation.label.rotation = 0;    // or even -90
      setTimeout(()=>chart.update('none')); // update after this event handling is complete
   },
   leave({chart}) {
      myAnnotation.label.content = ["Special", "Date"];
      myAnnotation.label.rotation = -90;
      setTimeout(()=>chart.update('none'));
   }
}

const config = {
   type: 'line',
   data,
   options: {
      plugins: {
         annotation: {
            annotations: {
               myAnnotation
            }
         }
      }
   }
};

new Chart('chartCanvas', config);
Chart:<br>
<canvas id=chartCanvas>
</canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/3.1.0/chartjs-plugin-annotation.min.js"></script>

or as jsFiddle.

I called chart.update through a setTimeout, to allow the current thread, that handles the current event, to complete. Still, the full update of the chart is a costly operation, and these updates might be called frequently, since this label rotation feature on mouse move is prone to produce rapid oscillations between the horizontal and vertical states, in certain conditions (for instance, if the mouse is positioned close to the corners of the initial label).

A hacky solution, that is however much lighter, is to use the undocumented function element.resolveElementProperties of the annotation plugin to compute only the properties of the label:

const setupLabel = ({element, chart}, content, rotation) => {
   element.label.options.content = element.options.label.content = content;
   element.options.label.rotation = rotation;
   const properties = element.resolveElementProperties(chart, element.options);
   Object.assign(element.elements[0], properties.elements[0].properties);
};

const myAnnotation = {
   // ......... other annotation options
   enter(context, event) {
      setupLabel(context, ["Display the Tip"], 0);
      return true; // force redraw
   }
   // ........
};

Full snippet demo:

const data = {
   labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
   datasets: [{
      type: 'line',
      label: 'Dataset 1',
      borderColor: 'rgb(54, 162, 235)',
      borderWidth: 2,
      fill: false,
      data: [10, 5, 40, 15, 30, 30, 48]
   }]
};

const setupLabel = ({element, chart}, content, rotation) => {
   element.label.options.content = element.options.label.content = content;
   element.options.label.rotation = rotation;
   const properties = element.resolveElementProperties(chart, element.options);
   Object.assign(element.elements[0], properties.elements[0].properties);
};


const myAnnotation = {
   type: 'line',
   mode: 'vertical',
   scaleID: 'x',
   value: 3,
   endValue: 3,
   borderColor: 'rgb(75, 192, 192)',
   borderWidth: 2,
   borderDash: [20, 10],
   label: {
      position: 25,
      display: true,
      content: ["Special", "Date"],
      rotation: -90,
      color: 'red'
   },
   enter(context, event) {
      setupLabel(context, ["Display the Tip"], 0);
      return true; // force redraw
   },
   leave(context, event) {
      setupLabel(context, ["Special", "Date"], -90);
      return true;
   }
}

const config = {
   type: 'line',
   data,
   options: {
      plugins: {
         annotation: {
            annotations: {
               myAnnotation
            }
         }
      }
   }
};

new Chart('chartCanvas', config);
<canvas id=chartCanvas>
</canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/3.1.0/chartjs-plugin-annotation.min.js"></script>

or as jsFiddle

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.