Skip to content

Commit

Permalink
Changed tooltip behaviour in line charts and derivatives.
Browse files Browse the repository at this point in the history
Previously, the tooltip would display the nearest point in the X dimension on the hovered series. Changed this to display the nearest point on any series. This makes it easier to inspect points on other series that are behind the tooltip. Also, polar charts with non-shared tooltips were fixed.
  • Loading branch information
TorsteinHonsi committed Mar 16, 2015
1 parent 3b9c377 commit d228fa0
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 90 deletions.
69 changes: 44 additions & 25 deletions js/highcharts-more.src.js
Expand Up @@ -2146,32 +2146,39 @@ Axis.prototype.beforePadding = function () {
pointerProto = Pointer.prototype,
colProto;

seriesProto.searchPolarPoint = function (e) {
/**
* Search a k-d tree by the point angle, used for shared tooltips in polar charts
*/
seriesProto.searchPointByAngle = function (e) {
var series = this,
chart = series.chart,
xAxis = series.xAxis,
center = xAxis.pane.center,
plotX = e.chartX - center[0] - chart.plotLeft,
plotY = e.chartY - center[1] - chart.plotTop;

e = {
return this.searchKDTree({
clientX: 180 + (Math.atan2(plotX, plotY) * (-180 / Math.PI))
};
return this.searchKDTree(e);
});

};

/**
* Wrap the buildKDTree function so that it searches by angle (clientX) in case of shared tooltip,
* and by two dimensional distance in case of non-shared.
*/
wrap(seriesProto, 'buildKDTree', function (proceed) {
proceed.apply(this);
});

wrap(seriesProto, 'searchPoint', function (proceed, e) {
if (this.chart.polar) {
return this.searchPolarPoint(e);
} else {
return proceed.call(this, e);
if (this.kdByAngle) {
this.searchPoint = this.searchPointByAngle;
} else {
this.kdDimensions = 2;
this.kdComparer = 'distR';
}
}
proceed.apply(this);
});

/**
* Translate a point's plotX and plotY from the internal angle and radius measures to
* true plotX, plotY coordinates
Expand All @@ -2187,18 +2194,22 @@ Axis.prototype.beforePadding = function () {
point.rectPlotX = plotX;
point.rectPlotY = plotY;

// Record the angle in degrees for use in tooltip
clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
if (clientX < 0) { // #2665
clientX += 360;
}
point.clientX = clientX;


// Find the polar plotX and plotY
xy = this.xAxis.postTranslate(point.plotX, this.yAxis.len - plotY);
point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
point.plotY = point.polarPlotY = xy.y - chart.plotTop;

// If shared tooltip, record the angle in degrees in order to align X points. Otherwise,
// use a standard k-d tree to get the nearest point in two dimensions.
if (this.kdByAngle) {
clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
if (clientX < 0) { // #2665
clientX += 360;
}
point.clientX = clientX;
} else {
point.clientX = point.plotX;
}
};

/**
Expand Down Expand Up @@ -2346,17 +2357,25 @@ Axis.prototype.beforePadding = function () {
* center.
*/
wrap(seriesProto, 'translate', function (proceed) {

var chart = this.chart,
points,
i;

// Run uber method
proceed.call(this);

// Postprocess plot coordinates
if (this.chart.polar && !this.preventPostTranslate) {
var points = this.points,
if (chart.polar) {
this.kdByAngle = chart.tooltip.shared;

if (!this.preventPostTranslate) {
points = this.points;
i = points.length;
while (i--) {
// Translate plotX, plotY from angle and radius to true plot coordinates
this.toXY(points[i]);

while (i--) {
// Translate plotX, plotY from angle and radius to true plot coordinates
this.toXY(points[i]);
}
}
}
});
Expand Down
20 changes: 10 additions & 10 deletions js/highcharts.src.js
Expand Up @@ -9549,8 +9549,13 @@ Pointer.prototype = {
}
}

// If it has a hoverPoint and that series requires direct touch (like columns),
// use the hoverPoint (#3899). Otherwise, search the k-d tree.
if (!shared && hoverSeries && hoverSeries.directTouch && hoverPoint) {
kdpoint = hoverPoint;

// Handle shared tooltip or cases where a series is not yet hovered
if (!(hoverSeries && hoverSeries.noSharedTooltip) && (shared || !hoverSeries)) { // #3821
} else {
// Find nearest points on all series
each(series, function (s) {
// Skip hidden series
Expand All @@ -9565,19 +9570,14 @@ Pointer.prototype = {
// Find absolute nearest point
each(kdpoints, function (p) {
if (p && defined(p.plotX) && defined(p.plotY)) {
if ((p.dist.distX < distance) || ((p.dist.distX === distance || p.series.kdDimensions > 1) && p.dist.distR < rdistance)) {
if ((p.dist.distX < distance) || ((p.dist.distX === distance || p.series.kdDimensions > 1) &&
p.dist.distR < rdistance)) {
distance = p.dist.distX;
rdistance = p.dist.distR;
kdpoint = p;
}
}
});

// Handle non-shared tooltips
} else {
// If it has a hoverPoint and that series requires direct touch (like columns), use the hoverPoint (#3899).
// Otherwise, search the k-d tree (like scatter).
kdpoint = (hoverSeries.directTouch && hoverPoint) || (hoverSeries && hoverSeries.searchPoint(e));
});
}

// Refresh tooltip for kdpoint if new hover point or tooltip was hidden // #3926
Expand All @@ -9586,7 +9586,7 @@ Pointer.prototype = {
if (shared && !kdpoint.series.noSharedTooltip) {
i = kdpoints.length;
while (i--) {
if (kdpoints[i].clientX !== kdpoint.clientX || (kdpoints[i].series.noSharedTooltip || false)) {
if (kdpoints[i].clientX !== kdpoint.clientX || kdpoints[i].series.noSharedTooltip) {
kdpoints.splice(i, 1);
}
}
Expand Down
20 changes: 10 additions & 10 deletions js/highmaps.src.js
Expand Up @@ -9086,8 +9086,13 @@ Pointer.prototype = {
}
}

// If it has a hoverPoint and that series requires direct touch (like columns),
// use the hoverPoint (#3899). Otherwise, search the k-d tree.
if (!shared && hoverSeries && hoverSeries.directTouch && hoverPoint) {
kdpoint = hoverPoint;

// Handle shared tooltip or cases where a series is not yet hovered
if (!(hoverSeries && hoverSeries.noSharedTooltip) && (shared || !hoverSeries)) { // #3821
} else {
// Find nearest points on all series
each(series, function (s) {
// Skip hidden series
Expand All @@ -9102,19 +9107,14 @@ Pointer.prototype = {
// Find absolute nearest point
each(kdpoints, function (p) {
if (p && defined(p.plotX) && defined(p.plotY)) {
if ((p.dist.distX < distance) || ((p.dist.distX === distance || p.series.kdDimensions > 1) && p.dist.distR < rdistance)) {
if ((p.dist.distX < distance) || ((p.dist.distX === distance || p.series.kdDimensions > 1) &&
p.dist.distR < rdistance)) {
distance = p.dist.distX;
rdistance = p.dist.distR;
kdpoint = p;
}
}
});

// Handle non-shared tooltips
} else {
// If it has a hoverPoint and that series requires direct touch (like columns), use the hoverPoint (#3899).
// Otherwise, search the k-d tree (like scatter).
kdpoint = (hoverSeries.directTouch && hoverPoint) || (hoverSeries && hoverSeries.searchPoint(e));
});
}

// Refresh tooltip for kdpoint if new hover point or tooltip was hidden // #3926
Expand All @@ -9123,7 +9123,7 @@ Pointer.prototype = {
if (shared && !kdpoint.series.noSharedTooltip) {
i = kdpoints.length;
while (i--) {
if (kdpoints[i].clientX !== kdpoint.clientX || (kdpoints[i].series.noSharedTooltip || false)) {
if (kdpoints[i].clientX !== kdpoint.clientX || kdpoints[i].series.noSharedTooltip) {
kdpoints.splice(i, 1);
}
}
Expand Down
20 changes: 10 additions & 10 deletions js/highstock.src.js
Expand Up @@ -9549,8 +9549,13 @@ Pointer.prototype = {
}
}

// If it has a hoverPoint and that series requires direct touch (like columns),
// use the hoverPoint (#3899). Otherwise, search the k-d tree.
if (!shared && hoverSeries && hoverSeries.directTouch && hoverPoint) {
kdpoint = hoverPoint;

// Handle shared tooltip or cases where a series is not yet hovered
if (!(hoverSeries && hoverSeries.noSharedTooltip) && (shared || !hoverSeries)) { // #3821
} else {
// Find nearest points on all series
each(series, function (s) {
// Skip hidden series
Expand All @@ -9565,19 +9570,14 @@ Pointer.prototype = {
// Find absolute nearest point
each(kdpoints, function (p) {
if (p && defined(p.plotX) && defined(p.plotY)) {
if ((p.dist.distX < distance) || ((p.dist.distX === distance || p.series.kdDimensions > 1) && p.dist.distR < rdistance)) {
if ((p.dist.distX < distance) || ((p.dist.distX === distance || p.series.kdDimensions > 1) &&
p.dist.distR < rdistance)) {
distance = p.dist.distX;
rdistance = p.dist.distR;
kdpoint = p;
}
}
});

// Handle non-shared tooltips
} else {
// If it has a hoverPoint and that series requires direct touch (like columns), use the hoverPoint (#3899).
// Otherwise, search the k-d tree (like scatter).
kdpoint = (hoverSeries.directTouch && hoverPoint) || (hoverSeries && hoverSeries.searchPoint(e));
});
}

// Refresh tooltip for kdpoint if new hover point or tooltip was hidden // #3926
Expand All @@ -9586,7 +9586,7 @@ Pointer.prototype = {
if (shared && !kdpoint.series.noSharedTooltip) {
i = kdpoints.length;
while (i--) {
if (kdpoints[i].clientX !== kdpoint.clientX || (kdpoints[i].series.noSharedTooltip || false)) {
if (kdpoints[i].clientX !== kdpoint.clientX || kdpoints[i].series.noSharedTooltip) {
kdpoints.splice(i, 1);
}
}
Expand Down
69 changes: 44 additions & 25 deletions js/parts-more/Polar.js
Expand Up @@ -11,32 +11,39 @@
pointerProto = Pointer.prototype,
colProto;

seriesProto.searchPolarPoint = function (e) {
/**
* Search a k-d tree by the point angle, used for shared tooltips in polar charts
*/
seriesProto.searchPointByAngle = function (e) {
var series = this,
chart = series.chart,
xAxis = series.xAxis,
center = xAxis.pane.center,
plotX = e.chartX - center[0] - chart.plotLeft,
plotY = e.chartY - center[1] - chart.plotTop;

e = {
return this.searchKDTree({
clientX: 180 + (Math.atan2(plotX, plotY) * (-180 / Math.PI))
};
return this.searchKDTree(e);
});

};

/**
* Wrap the buildKDTree function so that it searches by angle (clientX) in case of shared tooltip,
* and by two dimensional distance in case of non-shared.
*/
wrap(seriesProto, 'buildKDTree', function (proceed) {
proceed.apply(this);
});

wrap(seriesProto, 'searchPoint', function (proceed, e) {
if (this.chart.polar) {
return this.searchPolarPoint(e);
} else {
return proceed.call(this, e);
if (this.kdByAngle) {
this.searchPoint = this.searchPointByAngle;
} else {
this.kdDimensions = 2;
this.kdComparer = 'distR';
}
}
proceed.apply(this);
});

/**
* Translate a point's plotX and plotY from the internal angle and radius measures to
* true plotX, plotY coordinates
Expand All @@ -52,18 +59,22 @@
point.rectPlotX = plotX;
point.rectPlotY = plotY;

// Record the angle in degrees for use in tooltip
clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
if (clientX < 0) { // #2665
clientX += 360;
}
point.clientX = clientX;


// Find the polar plotX and plotY
xy = this.xAxis.postTranslate(point.plotX, this.yAxis.len - plotY);
point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
point.plotY = point.polarPlotY = xy.y - chart.plotTop;

// If shared tooltip, record the angle in degrees in order to align X points. Otherwise,
// use a standard k-d tree to get the nearest point in two dimensions.
if (this.kdByAngle) {
clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
if (clientX < 0) { // #2665
clientX += 360;
}
point.clientX = clientX;
} else {
point.clientX = point.plotX;
}
};

/**
Expand Down Expand Up @@ -211,17 +222,25 @@
* center.
*/
wrap(seriesProto, 'translate', function (proceed) {

var chart = this.chart,
points,
i;

// Run uber method
proceed.call(this);

// Postprocess plot coordinates
if (this.chart.polar && !this.preventPostTranslate) {
var points = this.points,
if (chart.polar) {
this.kdByAngle = chart.tooltip.shared;

if (!this.preventPostTranslate) {
points = this.points;
i = points.length;
while (i--) {
// Translate plotX, plotY from angle and radius to true plot coordinates
this.toXY(points[i]);

while (i--) {
// Translate plotX, plotY from angle and radius to true plot coordinates
this.toXY(points[i]);
}
}
}
});
Expand Down

0 comments on commit d228fa0

Please sign in to comment.