Drag and drop overlapping points - javascript

I have a graph plotted with a multitude of lines, a rather big figure overlapping the lines and ontop of that is a point that is capable of being drag and dropped all over the plot by the user.
The problem I'm facing currently is that as soon as the user drags and drops the point straight ontop of a line or a point of the figure, the user is unable to drag and drop the point away. I have set up a fiddle with my current setup.
JavaScript/jQuery code:
$(function() {
var startPoint = [[7.00, 0]];
var line10 = HHIsoPleth(7.00, 7.80, 10);
var line120 = HHIsoPleth(7.00, 7.80, 120);
var options = {
series: {
points: {
editMode: "none",
show: true,
radius: 0,
symbol: "circle",
fill: true,
hoverable: false,
},
lines: {
editMode: "none",
editable: false,
hoverable: false,
clickable: false
}
},
yaxes: [ {
position: "left",
min: 0, max: 60,
tickSize: 4,
} ],
xaxes: [ {
position: "bottom",
min: 7.00, max: 7.80,
} ],
grid: {
backgroundColor: "transparent",
editable: true,
hoverable: true,
clickable: false,
},
legend: {
position: "nw"
},
};
var data = [
{ data: line10, label: "PCO2", lines: { show: true, lineWidth: 1 }, points: { show: false }, editable: false, clickable: false, hoverable: false, color: "#FF0000" },
{ data: line120, lines: { show: true, lineWidth: 1 }, points: { show: false }, editable: false, clickable: false, hoverable: false, color: "#FF0000" },
{ data: startPoint, label: "Bloedzuur gehalte", lines: { show: true }, points: { show: true, radius: 3 }, editable: true, editMode: 'xy', color: '#00FF00' },
];
var plot = $.plot($("#flot-placeholder"), data, options);
// Drag and drop
$("#flot-placeholder").bind("datadrop", function(event, pos, item) {
var PCO2 = getPCO2(pos.x1.toFixed(2), pos.y1.toFixed(2));
var pH = getPH(pos.y1.toFixed(2), PCO2);
var HCOmm = getHCO3(pH, PCO2);
updatePoint(pH, HCOmm);
});
// Generate red lines / isopleths
function HHIsoPleth(minPH, maxPH, PCO2){
var isoPleth = [];
for (var i = minPH; i < maxPH; i+=0.01){
HCOmm = (0.03 * PCO2 * Math.pow(10,i-6.1));
isoPleth.push([i,HCOmm]);
}
return isoPleth;
}
function getHCO3(ph, pco2) {
return 0.03 * pco2 * Math.pow(10, ph - 6.1);
}
function getPH(hco3, pco2) {
return 6.1 + Math.log10(hco3 / (0.03 * pco2));
}
function getPCO2(ph, hco3) {
return (hco3 / 0.03) * Math.pow(10, 6.1 - ph);
}
//Reset point
$("#davenportReset").click(function() {
updatePoint(7.00, 0);
});
function updatePoint(x, y) {
data[16].data[0] = [x, y];
$.plot($("#flot-placeholder"), data, options);
}
// Debug purpose, get the index of the point that is clicked
$("#placeholder").bind("plotdown", function(event,pos,item){
$("#log").append("\nplotdown(" + item.seriesIndex + ")");
});
});
Additional libraries: Flot.js, JUMFlot
HTML:
<input class="davenportInput" id="davenportReset" type="button" value="Reset Point" />
<div id="flot-placeholder" style="width:558px;height:511px"></div>
eventlog<textarea id="log" rows="15" cols="28"></textarea>
In the provided fiddle you'll see that you can drag and drop the green point all around the plot. But once you drop it ontop any of the red lines it is no longer possible to drag and drop the green point somewhere else. In the textarea you'll see that when you click the green point, plotdown(16) will be shown in the textarea. But will show plotdown(0-15) when it is clicked when the point is over any of the red/yellow lines.
Would it be possible to get the 16th data serie(the drag and drop point) when it's overlapping any of the red lines?
Using (once again) Mark's answer I solved it. One condition I had though was that I had to keep the green point above all other lines.
This is what I did:
var startPoint = [[7.00, 0]];
var invisPoint = [[7.00, 0]];
var line10 = HHIsoPleth(7.00, 7.80, 10);
var line120 = HHIsoPleth(7.00, 7.80, 120);
To create a invisible placeholder point.
I than added it to the data object
var data = [
{ data: invisPoint , lines: { show: false }, points: { show: false, radius: 3 }, editable: true, editMode: 'xy', color: '#00FF00' },
{ data: line10, label: "PCO2", lines: { show: true, lineWidth: 1 }, points: { show: false }, editable: false, clickable: false, hoverable: false, color: "#FF0000" },
{ data: line120, lines: { show: true, lineWidth: 1 }, points: { show: false }, editable: false, clickable: false, hoverable: false, color: "#FF0000" },
{ data: startPoint, label: "Bloedzuur gehalte", lines: { show: true }, points: { show: true, radius: 3 }, editable: true, editMode: 'xy', color: '#00FF00' },
];
And updated the updatePoint function
function updatePoint(x, y) {
var data = plot.getData();
data[0].data[0] = [x, y]; // Invisible point
data[17].data[0] = [x, y]; // Green point
plot.setData(data);
plot.draw();
}
This way, the invisible point gets selected and dragged and dropped. I simply use those coordinates to position the green point aswell.

Internally, flot or jumflot in this case, when you mousedown is searching the points to see if one is near enough to your mouse cursor. It searches the points in order and finds your line segment before the point. So, simple fix, place your move-able point first:
var data = [
{ data: startPoint, label: "Bloedzuur gehalte", lines: { show: true }, points: { show: true, radius: 3 }, editable: true, editMode: 'xy', color: '#00FF00' },
{ data: line10, label: "PCO2", lines: { show: true, lineWidth: 1 }, points: { show: false }, editable: false, clickable: false, hoverable: false, color: "#FF0000" },
....
In addition, update your plot like this:
function updatePoint(x, y) {
var data = plot.getData();
data[0].data[0] = [x, y];
plot.setData(data);
plot.draw();
}
Calling $.plot over and over again is expensive and will probably leak memory (it used to at least - not sure if it was every fixed).
Updated fiddle.

Related

Apex Charts JS fill to size

So I've got a pretty small div, in which I gotta get a small timeline chart shoved in. The current problem is, that due to the chart being perfectly centered, I have a lot of whitespace I could really use, to make the actual data and chart much larger.:
I think showing the parent div shouldn't matter(because changing around these sizes doesn't really affect the chart itself). It feels like there's some option in the configuration that I'm missing. I've tried setting offsetY and even offsetX to negative values, because I was desperate, but to no avail.
<html>
<div id="chartTarget" style="height: 100; width: 100%;">
<canvas id="chartCanvas" height="100"></canvas>
<div style="opacity:0;" class="chartTooltip center">
</div>
</div>
</html>
Relevant code is pretty much straight up copied from the example, but since I'm bound to get questions about it, here goes:
var options = {
series: [
{
name: 'Pending',
data: [
{
x: 'Trip',
y: [
new Date('2021-04-21T03:24:00').getTime(),
new Date('2021-04-21T04:24:00').getTime()
]
}
]
},
{
name: 'Active',
data: [
{
x: 'Trip',
y: [
new Date('2021-04-21T05:24:00').getTime(),
new Date('2021-04-21T08:24:00').getTime()
]
}
]
},
{
name: 'Deleted',
data: [
{
x: 'Trip',
y: [
new Date('2021-04-21T11:24:00').getTime(),
new Date('2021-04-21T12:24:00').getTime()
]
}
]
}
],
chart: {
height: 75,
width: 250,
type: 'rangeBar',
offsetY: -25,
toolbar: {
show: false,
tools: {
download: false,
selection: false,
zoom: false,
zoomin: false,
zoomout: false,
pan: true,
reset: true
}
},
events: {
dataPointMouseEnter: function (event, chartContext, config) {
config.w.config.chart.toolbar.show = false;
},
dataPointMouseLeave: function (event, chartContext, config) {
config.w.config.chart.toolbar.show = false;
}
}
},
plotOptions: {
bar: {
horizontal: true,
barHeight: '50%',
rangeBarGroupRows: true
}
},
colors: [
"#008FFB", "#00E396", "#FEB019", "#FF4560", "#775DD0",
"#3F51B5", "#546E7A", "#D4526E", "#8D5B4C", "#F86624",
"#D7263D", "#1B998B", "#2E294E", "#F46036", "#E2C044"
],
fill: {
type: 'solid'
},
xaxis: {
type: 'datetime',
labels: {
maxHeight: 25,
style: {
fontSize: '9px'
},
offsetY: -8
},
tooltip: {
enabled: false
}
},
yaxis: {
show: false,
lines: {
show: true
}
},
legend: {
show: false,
position: 'top'
}
};
var chart = new ApexCharts(document.querySelector("#chartTarget"), options);
chart.render();
I need the label, so things like sparkline aren't useful.
A negative offset at the chart level seems to have fixed for my needs.
chart.offsetY: -25
I assume everyone else can play with negative offset values, where available for more fine tuning.

How to contain category data in tooltip

I've seen tutorials and posts about getting data from the x axis into the tooltip but I am overriding it with categories and cannot figure out how to get the x axis to show up in the tooltip.
This is what im working with:
function showTooltip(x, y, contents) {
$('<div id="tooltip" class="flot-tooltip tooltip"><div class="tooltip-arrow"></div>' + contents + '</div>').css({
top: y - 43,
left: x - 15,
}).appendTo("body").fadeIn(200);
}
var data = [[1492854610, -1240],[1492939020, -1273],[1493025073, -1279],[1493117066, -1186],[1493198484, -1269],[1493289175, -1198],[1493370646, -1280],[1493458518, -1255],[1493543731, -1275],[1493630250, -1273],[1493716306, -1279],[1493803609, -1264],[1493889258, -1276],[1493975557, -1278],[1494064529, -1235],[1494155440, -1160],[1494237980, -1224],[1494321047, -1280],[1494407990, -1271],[1494494125, -1275],[1494581609, -1257],[1494668321, -1252],[1494753220, -1277],[1494847855, -1140],[1494925963, -1278],[1495012537, -1275],[1495099289, -1269],[1495188205, -1227],[1495273568, -1244],[1495358329, -1272]];
$.plot($("#placeholder"), [{
label: "Delay: ",
data: data,
color: "#3a8ce5"
}], {
xaxis: {
mode: "categories",
tickLength: 0,
ticks: [[0, "1:50 AM"],[1, "1:17 AM"],[2, "1:11 AM"],[3, "2:44 AM"],[4, "1:21 AM"],[5, "2:32 AM"],[6, "1:10 AM"],[7, "1:35 AM"],[8, "1:15 AM"],[9, "1:17 AM"],[10, "1:11 AM"],[11, "1:26 AM"],[12, "1:14 AM"],[13, "1:12 AM"],[14, "1:55 AM"],[15, "3:10 AM"],[16, "2:06 AM"],[17, "1:10 AM"],[18, "1:19 AM"],[19, "1:15 AM"],[20, "1:33 AM"],[21, "1:38 AM"],[22, "1:13 AM"],[23, "3:30 AM"],[24, "1:12 AM"],[25, "1:15 AM"],[26, "1:21 AM"],[27, "2:03 AM"],[28, "1:46 AM"],[29, "1:18 AM"]]
},
yaxis: {
min: -2000,
max: 1000,
},
series: {
lines: {
show: true,
fill: true
},
points: {
show: true,
}
},
grid: {
hoverable: true,
clickable: true,
markings: [
{ color: '#000', lineWidth: 1, yaxis: { from: 0, to: 0 } },
]
},
legend: {
show: false
}
});
$("#placeholder").bind("plothover", function(event, pos, item) {
if (item) {
if (previousPoint != item.dataIndex) {
previousPoint = item.dataIndex;
$("#tooltip").remove();
var y = item.datapoint[1].toFixed();
showTooltip(item.pageX, item.pageY,
item.series.label + " = " + y);
}
} else {
$("#tooltip").remove();
previousPoint = null;
}
});
I am trying to get the times part of the categories. The item array has 3 pieces of data, none of which are the times
jFiddle:
http://jsfiddle.net/zw14y8c3/2/
The item.datapoint[0] data has the index of the x-axis tick. With that you can get the actual tick label from the ticks array:
var x = $("#placeholder").data('plot').getAxes().xaxis.ticks[item.datapoint[0]].label;
See the updated fiddle for the full example.

Jquery Flot Bar Chart doesn't fit to the board

I have two bar charts, one of them shows top ten categories, the other one shows min ten categories.
There is no problem with top ten bar chart, but I use the very same code to draw min ten bar chart that I used in top ten bar chart, but here is the result.
This is top ten:
And this is min ten:
As you can see above image, min ten chart's bars look like damaged and labels below the bars can't be seen.
And here is the codes that produce these results:
MinTen produced html which feeds the bar chart:
var initCatMinTenBarChart = function ()
{
var dataMin = new Array();
var ticks = [[0, 'Kozmetik'],[1, 'Ev&Yaşam'],[2, 'Cep Telefonu'],[3, 'Ayakkabı'],[4, 'Bilgisayar'],[5, 'Beyaz Eşya']];var labels = ['Kozmetik','Ev&Yaşam','Cep Telefonu','Ayakkabı','Bilgisayar','Beyaz Eşya'];var minTenCat_d1 = 18;var minTenCat_d2 = 12;var minTenCat_d3 = 8;var minTenCat_d4 = 7;var minTenCat_d5 = 6;var minTenCat_d6 = 4;
var isempty = false;
var d_min_ten_cat_bar = [[0,18],[1,12],[2,8],[3,7],[4,6],[5,4]];
dataMin.push({
label: labels,
data: d_min_ten_cat_bar,
bars: {
show: true,
barWidth: 0.2,
order: 1
}
});
if (!isempty) {
$.plot("#MinTenCatBarChart", dataMin, $.extend(true, {}, Plugins.getFlotDefaults(), {
legend: {
show: false
},
series: {
lines: { show: false },
points: { show: false }
},
grid: {
hoverable: true,
clickable: true
},
tooltip: true,
tooltipOpts: {
content: function (label, x, y) { return 'İçerik Sayısı: ' + y; }
},
bars: {
align: "center",
barWidth: 0.1
},
xaxis: {
align: "center",
ticks: ticks
},
yaxis: {
tickLength: 0
}
}));
}
}
TopTen produced html data which feeds the bar chart:
var initCatTopTenBarChart = function ()
{
var dataTop = new Array();
var ticks = [[0, 'Kozmetik'],[1, 'Ev&Yaşam'],[2, 'Cep Telefonu'],[3, 'Ayakkabı'],[4, 'Bilgisayar'],[5, 'Beyaz Eşya']];var labels = ['Kozmetik','Ev&Yaşam','Cep Telefonu','Ayakkabı','Bilgisayar','Beyaz Eşya'];var topTenCat_d1 = 18;var topTenCat_d2 = 12;var topTenCat_d3 = 8;var topTenCat_d4 = 7;var topTenCat_d5 = 6;var topTenCat_d6 = 4;
var isempty = false;
var d_top_ten_cat_bar = [[0,18],[1,12],[2,8],[3,7],[4,6],[5,4]];
dataTop.push({
label: labels,
data: d_top_ten_cat_bar,
bars: {
show: true,
barWidth: 0.2,
order: 1
}
});
if (!isempty) {
$.plot("#TopTenCatBarChart", dataTop, $.extend(true, {}, Plugins.getFlotDefaults(), {
legend: {
show: false
},
series: {
lines: { show: false },
points: { show: false }
},
grid: {
hoverable: true,
clickable: true
},
tooltip: true,
tooltipOpts: {
content: function (label, x, y) { return 'İçerik Sayısı: ' + y; }
},
bars: {
align: "center",
barWidth: 0.1
},
xaxis: {
align: "center",
ticks: ticks
},
yaxis: {
tickLength: 0
}
// tick olasyına bak 0,10 arası işlemez burda max-min şeyapmak lazım
}));
}
}
Maybe the positioning is off because of when the chart is being rendered? Try drawing the charts only once their corresponding tab is selected and visible.

Flot Strange Line Chart

I have a chart with ordering by date.
My problem is the chart lines joining false from start to end.
My options:
var options =
{
grid:
{
color: "#dedede",
borderWidth: 1,
borderColor: "transparent",
clickable: true,
hoverable: true
},
series: {
grow: {active:false},
lines: {
show: true,
fill: false,
lineWidth: 2,
steps: false
},
points: {
show:true,
radius: 5,
lineWidth: 3,
fill: true,
fillColor: "#000"
}
},
legend: { position: "nw", backgroundColor: null, backgroundOpacity: 0, noColumns: 2 },
yaxis: { tickSize:50 },
xaxis: {
mode: "time",
tickFormatter: function(val, axis) {
var d = new Date(val);
return d.getUTCDate() + "/" + (d.getUTCMonth() + 1);
}
},
colors: [],
shadowSize:1,
tooltip: true,
tooltipOpts: {
content: "%s : %y.0",
shifts: {
x: -30,
y: -50
},
defaultTheme: false
}
};
Note: I'm not re-ordering any data. Just giving the timestamp with this function:
function gd(year, month, day) {
return new Date(year, month - 1, day).getTime();
}
Setting the data like this:
$.each(e.data, function(i, e){
data.push([gd(parseInt(e['year']), parseInt(e['month']), parseInt(e['day'])), parseInt(e['value'])]);
});
var entity = {
label: e.campaign,
data: data,
lines: {fillColor: randomColor},
points: {fillColor: randomColor}
};
entities.push(entity);
Console log:
When creating line charts, flot will connect the data points using the order from the data series, ignoring the actual x-coordinates. That's why data series should be in ascending order.
A minimal example (using your data in ascending order):
var d1 = [
[1401310800000, 275],
[1401397200000, 270],
[1401483600000, 313],
[1401570000000, 279],
[1401656400000, 216],
[1401742800000, 255],
[1401829200000, 244],
[1401915600000, 70]
];
$.plot("#chart", [ d1 ]);
Here is a jsfiddle showing the chart.

Set/remove onClick event of separate points in jQuery Plot

I'm plotting a graph with jQuery Plot. The graph contents 2 lines with points. I set the the option 'clickable' in grid on true. It makes all points clickable.
The question is how can I set only separate points clickable?
Here is my code:
d1 = [[889.0, y_max], [905.0, y_max], [915.0, y_max], [935, y_max]];
d2 = [[885.0, 0.4], [905.0, 0.6], [915.0, 0.34], [935, 0.39]];
options = {
yaxis: { min: y_min, max: y_max },
grid: { hoverable: true,
clickable: true,
borderWidth: 0 },
legend: {
show: true,
noColumns: 4,
container: $("#labeler"),
labelFormatter: function (label, series) {
var cb = label;
return cb;
}
}
};
ed_data = [
{ data: d1,
points: { show: true, symbol: "diamond" },
lines: { show: false },
color: "#FF0000"
},
{ label: "Serie 1",
data: d2,
points: { show: true,
symbol: "triangle" },
lines: { show: true,
lineWidth: 1 }
}];
pl = $.plot($("#placeholder_top"), ed_data, options);
OK, this is a bit of a hack, but it works. The idea is to expand the array that defines a data point from two elements (x and y) to three (x, y, and clickable). So you'd define your data something like this:
d2 = [[885.0, 0.4], [905.0, 0.6, true], [915.0, 0.34, false], [935, 0.39, true]];
The first point won't be clickable (its third element is undefined), the second and fourth will be (the third element for both is set to true), the third point won't be clickable (its third element is false).
Now, when you bind a plotclick event, you can easily filter out the items you won't respond to:
$("#chart").bind("plotclick", function (event, pos, item) {
if (item) {
var dataPoint = item.series.data[item.dataIndex];
if (dataPoint[2]) {
// respond to the click
}
}
});

Categories