Commit 31a2a130 authored by Masayuki Tanaka's avatar Masayuki Tanaka

Fix sacatter plot tooltip when same x data exists

parent 0099bf28
...@@ -628,50 +628,72 @@ ...@@ -628,50 +628,72 @@
return y(d.value); return y(d.value);
} }
function findSameXOfValues(values, index) {
var i, targetX = values[index].x, sames = [];
for (i = index - 1; i >= 0; i--) {
if (targetX !== values[i].x) { break; }
sames.push(values[i]);
}
for (i = index; i < values.length; i++) {
if (targetX !== values[i].x) { break; }
sames.push(values[i]);
}
return sames;
}
function findClosestOfValues(values, pos, _min, _max) { // MEMO: values must be sorted by x function findClosestOfValues(values, pos, _min, _max) { // MEMO: values must be sorted by x
var min = _min ? _min : 0, var min = _min ? _min : 0,
max = _max ? _max : values.length - 1, max = _max ? _max : values.length - 1,
med = Math.floor((max - min) / 2) + min, med = Math.floor((max - min) / 2) + min,
value = values[med], value = values[med],
diff = x(value.x) - pos[0], diff = x(value.x) - pos[0],
minDist, maxDist; candidates;
// Update rage for search // Update range for search
diff > 0 ? max = med : min = med; diff > 0 ? max = med : min = med;
// if candidates are two closest min and max, stop recursive call // if candidates are two closest min and max, stop recursive call
if ((max - min) === 1) { if ((max - min) === 1) {
if (! values[min].x) { return values[max]; }
if (! values[max].x) { return values[min]; } // Get candidates that has same min and max index
minDist = Math.pow(pos[0] - x(values[min].x), 2) + Math.pow(pos[1] - y(values[min].value), 2); candidates = [];
maxDist = Math.pow(pos[0] - x(values[max].x), 2) + Math.pow(pos[1] - y(values[max].value), 2); if (values[min].x) {
return minDist < maxDist ? values[min] : values[max]; candidates = candidates.concat(findSameXOfValues(values, min));
}
if (values[max].x) {
candidates = candidates.concat(findSameXOfValues(values, max));
}
// Determine the closest and return
return findClosest(candidates, pos);
} }
return findClosestOfValues(values, pos, min, max); return findClosestOfValues(values, pos, min, max);
} }
function findClosest(targets, mouse) { function findClosestFromTargets(targets, pos) {
var closest, closests, minDist; var candidates;
// map to array of closest points of each target // map to array of closest points of each target
closests = targets.map(function (target) { candidates = targets.map(function (target) {
return findClosestOfValues(target.values, mouse); return findClosestOfValues(target.values, pos);
}); });
// decide closest point // decide closest point and return
closests.forEach(function (c) { return findClosest(candidates, pos);
var dist = Math.pow(x(c.x) - mouse[0], 2) + Math.pow(y(c.value) - mouse[1], 2); }
if (dist < minDist || ! minDist) { function findClosest(values, pos) {
minDist = dist; var minDist, closest;
closest = c; values.forEach(function (v) {
var d = dist(v, pos);
if (d < minDist || ! minDist) {
minDist = d;
closest = v;
} }
}); });
// TODO: multiple closests when each is very close
return closest; return closest;
} }
//-- Tooltip --// //-- Tooltip --//
function showTooltip(selectedData, mouse) { function showTooltip(selectedData, mouse) {
...@@ -894,8 +916,8 @@ ...@@ -894,8 +916,8 @@
return found; return found;
} }
function dist(data, mouse) { function dist(data, pos) {
return Math.pow(x(data.x) - mouse[0], 2) + Math.pow(y(data.value) - mouse[1], 2); return Math.pow(x(data.x) - pos[0], 2) + Math.pow(y(data.value) - pos[1], 2);
} }
//-- Selection --// //-- Selection --//
...@@ -1480,7 +1502,7 @@ ...@@ -1480,7 +1502,7 @@
if (dragging) { return; } // do nothing when dragging if (dragging) { return; } // do nothing when dragging
mouse = d3.mouse(this); mouse = d3.mouse(this);
closest = findClosest(c3.data.targets, mouse); closest = findClosestFromTargets(c3.data.targets, mouse);
// show tooltip when cursor is close to some point // show tooltip when cursor is close to some point
selectedData = [addName(closest)]; selectedData = [addName(closest)];
...@@ -1504,7 +1526,7 @@ ...@@ -1504,7 +1526,7 @@
}) })
.on('click', function () { .on('click', function () {
var mouse = d3.mouse(this), var mouse = d3.mouse(this),
closest = findClosest(c3.data.targets, mouse); closest = findClosestFromTargets(c3.data.targets, mouse);
// select if selection enabled // select if selection enabled
if (dist(closest, mouse) < 100) { if (dist(closest, mouse) < 100) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment