I am using ChartJS to display a chart and would like to interact with the annotations via the annotationsplugin.
In addition the annotations are draggable, so the user can drag them around freely. I am using the drag documentation for that.
This works fine, however, I need to make sure that the mouse is moved/dragged very slowly. If I move it slightly too fast, it will stop.
I thought I remove the mouseout
event handler of the example. However, this does not work and once I move the mouse too fast and the mouse is slightly off the edges of that annotation, it stops.
It is also noticable on the example of the annotation plugin in the link above.
Unfortunately, I have very thin lines I would like to drag, so I need to move the mouse in slow motion in order to make this work. In order to test the problem, you can simply try to move the example at the very edge of the annotations.
Using the code from the example
you linked to (and that is just an example with minimal features, not a
production-ready dragging api), one can overcome the issue with dragging being stopped when
the pointer enters another annotation by preventing the default functionality
of enter
and leave
while dragging:
enter(ctx) {
if(lastEvent){
return;
}
element = ctx.element;
},
leave() {
if(lastEvent){
return
}
element = undefined;
// lastEvent = undefined;
}
lastEvent
is defined (truthy) while dragging is on. That seems to also
take care of the fast moving mouse, since dragging is not canceled if the
pointer temporarily gets outside the element before its position was updated.
Demo snippet
//code mostly from https://www.chartjs.org/chartjs-plugin-annotation/3.1.0/samples/interaction/dragging.html
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: Array.from({length: 100}, ()=>Math.round(Math.random() * 100))
}]
};
const annotation1 = {
type: 'box',
backgroundColor: 'rgba(165, 214, 167, 0.2)',
borderColor: 'rgb(165, 214, 167)',
borderWidth: 2,
label: {
display: true,
content: ['Box annotation', 'to drag'],
textAlign: 'center'
},
xMax: 'May',
xMin: 'April',
xScaleID: 'x',
yMax: 75,
yMin: 25,
yScaleID: 'y'
};
const annotation2 = {
type: 'label',
backgroundColor: 'rgba(255, 99, 132, 0.25)',
borderWidth: 3,
borderColor: 'black',
content: ['Label annotation', 'to drag'],
callout: {
display: true,
borderColor: 'black',
},
position: {
x: "25%",
y: "start"
},
xValue: 1,
yValue: 40
};
const annotation3 = {
type: 'point',
backgroundColor: 'rgba(0, 255, 255, 0.4)',
borderWidth: 2,
borderColor: 'black',
radius: 20,
xValue: 'March', // oe 2
yValue: 50
};
const annotation4 = {
type: 'polygon',
backgroundColor: 'rgba(150, 0, 0, 0.25)',
borderWidth: 2,
borderColor: 'black',
radius: 50,
sides: 6,
xValue: 5,// or 'June',
yValue: 20
};
let element;
let lastEvent;
const drag = function(moveX, moveY) {
element.x += moveX;
element.y += moveY;
element.x2 += moveX;
element.y2 += moveY;
element.centerX += moveX;
element.centerY += moveY;
if (element.elements && element.elements.length) {
for (const subEl of element.elements) {
subEl.x += moveX;
subEl.y += moveY;
subEl.x2 += moveX;
subEl.y2 += moveY;
subEl.centerX += moveX;
subEl.centerY += moveY;
subEl.bX += moveX;
subEl.bY += moveY;
}
}
};
const handleElementDragging = function(event) {
if (!lastEvent || !element) {
return;
}
const moveX = event.x - lastEvent.x;
const moveY = event.y - lastEvent.y;
drag(moveX, moveY);
lastEvent = event;
return true;
};
const handleDrag = function(event) {
if (element) {
switch (event.type) {
case 'mousemove':
return handleElementDragging(event);
case 'mouseout':
case 'mouseup':
lastEvent = undefined;
break;
case 'mousedown':
lastEvent = event;
break;
default:
}
}
};
const config = {
type: 'line',
plugins: [{
beforeEvent(chart, args) {
if (handleDrag(args.event)) {
args.changed = true;
return;
}
}
}],
data,
options: {
events: ['mousedown', 'mouseup', 'mousemove', 'mouseout'],
scales: {
y: {
beginAtZero: true,
min: 0,
max: 100
}
},
plugins: {
annotation: {
enter(ctx) {
if(lastEvent){
return;
}
element = ctx.element;
},
leave() {
if(lastEvent){
return
}
element = undefined;
// lastEvent = undefined;
},
annotations: {
annotation1,
annotation2,
annotation3,
annotation4
}
}
}
}
};
new Chart('myChart', config);
<div style="height: 300px">
<canvas id="myChart">
</canvas>
</div>
<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>
Please let me know if this doesn't cover all the issues of this category.