Reputation: 1898
In highcharts I'm trying to add a drag-effect to point's datalabel. I've found a couple of ways to target a given label. In this fiddle you can see some of my attempts. (I've combined to different attempts in one fiddle here to show off what I've tried)
Now both using chart.series[0].data[0].dataLabel and using the points click event makes me able to change the attributes of a dataLabel. However I'm not able to attach a jquery ui .draggable() to the label. Is is somehow possible to make an element inside a chart draggable?
Please let me know if any more information is needed
Upvotes: 4
Views: 1557
Reputation: 262969
You can actually attach draggable
widgets to the data labels just fine. However, since the data labels are SVG elements, they completely ignore changes made to their position
, left
and top
CSS properties.
Instead, the <g>
elements that wrap the labels expose a transform
attribute:
<g zIndex="1" transform="translate(9, 152)">
<!-- data label content -->
</g>
We can still use the draggable
widget (which is quite handy because it abstracts the lower-level drag events) and update the transform
attribute of the data label wrappers in a drag event handler. Since drag coordinates are relative, we'll have to parse the original transform
attribute and use the resulting coordinates as the origin.
Now, all the label wrappers are themselves children of groups decorated with the highcharts-data-labels
class. This provides us with a good starting point, so we can write something like:
$(".highcharts-data-labels").children().filter(function() {
var $this = $(this);
// Parse original translation.
var coords = $this.attr("transform")
.match(/translate\((-?\d+),\s*(-?\d+)\)/);
if (coords) {
// Associate origin with element.
return $this.data("origin", {
x: +coords[1],
y: +coords[2]
});
} else {
// Parsing failed, reject element.
return false;
}
}).draggable({
drag: function(event, ui) {
var $this = $(this);
// Fetch back origin.
var origin = $this.data("origin");
// Update current transform.
$this.attr("transform", "translate("
+ (origin.x + ui.position.left) + ", "
+ (origin.y + ui.position.top) + ")");
}
});
You will find an updated fiddle here.
A few remarks about the code above:
filter() is used instead of each() because it allows us to filter out elements whose transform
attributes could not be parsed (you never know), instead of outright failing or feeding garbage to the computations in the drag
handler,
attr() is used instead of prop() to emphasize the fact we're modifying attributes in an SVG fragment. prop()
would probably work in the exact same way, so it's only a matter of style and personal preference.
Finally, a caveat: I can only test this on Firefox for now, but it seems to be very difficult to trigger mousedown
events on some of the labels, especially in "crowded" areas with portions of the curve and the data tip competing for space. Tweaking the zIndex
attributes of the data label wrappers did not achieve much. Multiple clicks sometimes help. If this is consistent on all browsers, additional solutions will probably have to be devised (transparent overlays maybe, or simply relaying mousedown
events from the data points themselves to the data labels).
Upvotes: 1
Reputation: 25090
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'line'
},
title: {
text: 'Monthly Average Temperature'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
yAxis: {
title: {
text: 'Temperature'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
plotOptions: {
series: {
dataLabels: {
enabled: true
},
events: {
//Here I'm able to move the labels by using the click and shift-click.
//I wish to do this by dragging
click: function(event) {
var current_y = event.point.dataLabel.attr('y');
if(event.shiftKey) {
var new_y = current_y + 2;
event.point.dataLabel.attr({y: new_y});
} else {
var new_y = current_y - 2;
event.point.dataLabel.attr({y: new_y});
}
}
}
}
},
series: [{
name: 'Tokyo',
data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
}, {
name: 'New York',
data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
}, {
name: 'Berlin',
data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
}]
});
//Second attempt to grab a point. Works for chaning attributes
var point = chart.series[0].data[0].dataLabel;
} , function(chart){
});
$(function() {
console.log(chart) ;
$( "#draggable" ).draggable()
.text(chart.series[0].data[0].y + 'drag and drop me ');
});
Upvotes: 0