From 6ec6a929f06c01c053d75378030724749f50bcc9 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 15 Oct 2016 16:49:35 -0500 Subject: [PATCH] Make index mode only work with the horizontal distance to an element (#3471) Make index mode only work with the horizontal distance to an element if intersect is off --- src/core/core.interaction.js | 14 +- test/core.tooltip.tests.js | 307 +++++++++++++++++++++++------------ 2 files changed, 210 insertions(+), 111 deletions(-) diff --git a/src/core/core.interaction.js b/src/core/core.interaction.js index 571f3c3c0..2e680bea5 100644 --- a/src/core/core.interaction.js +++ b/src/core/core.interaction.js @@ -50,19 +50,24 @@ module.exports = function(Chart) { * @param chart {Chart} the chart to look at elements from * @param position {Point} the point to be nearest to * @param intersect {Boolean} if true, only consider items that intersect the position + * @param distanceMetric {Function} Optional function to provide the distance between * @return {ChartElement[]} the nearest items */ - function getNearestItems(chart, position, intersect) { + function getNearestItems(chart, position, intersect, distanceMetric) { var minDistance = Number.POSITIVE_INFINITY; var nearestItems = []; + if (!distanceMetric) { + distanceMetric = helpers.distanceBetweenPoints; + } + parseVisibleItems(chart, function(element) { if (intersect && !element.inRange(position.x, position.y)) { return; } var center = element.getCenterPoint(); - var distance = Math.round(helpers.distanceBetweenPoints(position, center)); + var distance = distanceMetric(position, center); if (distance < minDistance) { nearestItems = [element]; @@ -78,7 +83,10 @@ module.exports = function(Chart) { function indexMode(chart, e, options) { var position = helpers.getRelativePosition(e, chart.chart); - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false); + var distanceMetric = function(pt1, pt2) { + return Math.abs(pt1.x - pt2.x); + }; + var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); var elements = []; if (!items.length) { diff --git a/test/core.tooltip.tests.js b/test/core.tooltip.tests.js index 9927debc0..dd6ee17f5 100755 --- a/test/core.tooltip.tests.js +++ b/test/core.tooltip.tests.js @@ -1,118 +1,209 @@ // Test the rectangle element -describe('tooltip tests', function() { - it('Should display in label mode', function() { - var chartInstance = window.acquireChart({ - type: 'line', - data: { - datasets: [{ - label: 'Dataset 1', - data: [10, 20, 30], - pointHoverBorderColor: 'rgb(255, 0, 0)', - pointHoverBackgroundColor: 'rgb(0, 255, 0)' - }, { - label: 'Dataset 2', - data: [40, 40, 40], - pointHoverBorderColor: 'rgb(0, 0, 255)', - pointHoverBackgroundColor: 'rgb(0, 255, 255)' - }], - labels: ['Point 1', 'Point 2', 'Point 3'] - }, - options: { - tooltips: { - mode: 'label' +describe('Core.Tooltip', function() { + describe('index mode', function() { + it('Should only use x distance when intersect is false', function() { + var chartInstance = window.acquireChart({ + type: 'line', + data: { + datasets: [{ + label: 'Dataset 1', + data: [10, 20, 30], + pointHoverBorderColor: 'rgb(255, 0, 0)', + pointHoverBackgroundColor: 'rgb(0, 255, 0)' + }, { + label: 'Dataset 2', + data: [40, 40, 40], + pointHoverBorderColor: 'rgb(0, 0, 255)', + pointHoverBackgroundColor: 'rgb(0, 255, 255)' + }], + labels: ['Point 1', 'Point 2', 'Point 3'] + }, + options: { + tooltips: { + mode: 'index', + intersect: false + } } - } + }); + + // Trigger an event over top of the + var meta = chartInstance.getDatasetMeta(0); + var point = meta.data[1]; + + var node = chartInstance.chart.canvas; + var rect = node.getBoundingClientRect(); + + var evt = new MouseEvent('mousemove', { + view: window, + bubbles: true, + cancelable: true, + clientX: rect.left + point._model.x, + clientY: 0 + }); + + // Manully trigger rather than having an async test + node.dispatchEvent(evt); + + // Check and see if tooltip was displayed + var tooltip = chartInstance.tooltip; + var globalDefaults = Chart.defaults.global; + + expect(tooltip._view).toEqual(jasmine.objectContaining({ + // Positioning + xPadding: 6, + yPadding: 6, + xAlign: 'left', + yAlign: 'center', + + // Body + bodyFontColor: '#fff', + _bodyFontFamily: globalDefaults.defaultFontFamily, + _bodyFontStyle: globalDefaults.defaultFontStyle, + _bodyAlign: 'left', + bodyFontSize: globalDefaults.defaultFontSize, + bodySpacing: 2, + + // Title + titleFontColor: '#fff', + _titleFontFamily: globalDefaults.defaultFontFamily, + _titleFontStyle: 'bold', + titleFontSize: globalDefaults.defaultFontSize, + _titleAlign: 'left', + titleSpacing: 2, + titleMarginBottom: 6, + + // Footer + footerFontColor: '#fff', + _footerFontFamily: globalDefaults.defaultFontFamily, + _footerFontStyle: 'bold', + footerFontSize: globalDefaults.defaultFontSize, + _footerAlign: 'left', + footerSpacing: 2, + footerMarginTop: 6, + + // Appearance + caretSize: 5, + cornerRadius: 6, + backgroundColor: 'rgba(0,0,0,0.8)', + opacity: 1, + legendColorBackground: '#fff', + displayColors: true, + + // Text + title: ['Point 2'], + beforeBody: [], + body: [{ + before: [], + lines: ['Dataset 1: 20'], + after: [] + }, { + before: [], + lines: ['Dataset 2: 40'], + after: [] + }], + afterBody: [], + footer: [], + caretPadding: 2, + labelColors: [{ + borderColor: 'rgb(255, 0, 0)', + backgroundColor: 'rgb(0, 255, 0)' + }, { + borderColor: 'rgb(0, 0, 255)', + backgroundColor: 'rgb(0, 255, 255)' + }] + })); + + expect(tooltip._view.x).toBeCloseToPixel(269); + expect(tooltip._view.y).toBeCloseToPixel(155); }); - // Trigger an event over top of the - var meta = chartInstance.getDatasetMeta(0); - var point = meta.data[1]; + it('Should only display if intersecting if intersect is set', function() { + var chartInstance = window.acquireChart({ + type: 'line', + data: { + datasets: [{ + label: 'Dataset 1', + data: [10, 20, 30], + pointHoverBorderColor: 'rgb(255, 0, 0)', + pointHoverBackgroundColor: 'rgb(0, 255, 0)' + }, { + label: 'Dataset 2', + data: [40, 40, 40], + pointHoverBorderColor: 'rgb(0, 0, 255)', + pointHoverBackgroundColor: 'rgb(0, 255, 255)' + }], + labels: ['Point 1', 'Point 2', 'Point 3'] + }, + options: { + tooltips: { + mode: 'index', + intersect: true + } + } + }); - var node = chartInstance.chart.canvas; - var rect = node.getBoundingClientRect(); + // Trigger an event over top of the + var meta = chartInstance.getDatasetMeta(0); + var point = meta.data[1]; - var evt = new MouseEvent('mousemove', { - view: window, - bubbles: true, - cancelable: true, - clientX: rect.left + point._model.x, - clientY: rect.top + point._model.y + var node = chartInstance.chart.canvas; + var rect = node.getBoundingClientRect(); + + var evt = new MouseEvent('mousemove', { + view: window, + bubbles: true, + cancelable: true, + clientX: rect.left + point._model.x, + clientY: 0 + }); + + // Manully trigger rather than having an async test + node.dispatchEvent(evt); + + // Check and see if tooltip was displayed + var tooltip = chartInstance.tooltip; + var globalDefaults = Chart.defaults.global; + + expect(tooltip._view).toEqual(jasmine.objectContaining({ + // Positioning + xPadding: 6, + yPadding: 6, + + // Body + bodyFontColor: '#fff', + _bodyFontFamily: globalDefaults.defaultFontFamily, + _bodyFontStyle: globalDefaults.defaultFontStyle, + _bodyAlign: 'left', + bodyFontSize: globalDefaults.defaultFontSize, + bodySpacing: 2, + + // Title + titleFontColor: '#fff', + _titleFontFamily: globalDefaults.defaultFontFamily, + _titleFontStyle: 'bold', + titleFontSize: globalDefaults.defaultFontSize, + _titleAlign: 'left', + titleSpacing: 2, + titleMarginBottom: 6, + + // Footer + footerFontColor: '#fff', + _footerFontFamily: globalDefaults.defaultFontFamily, + _footerFontStyle: 'bold', + footerFontSize: globalDefaults.defaultFontSize, + _footerAlign: 'left', + footerSpacing: 2, + footerMarginTop: 6, + + // Appearance + caretSize: 5, + cornerRadius: 6, + backgroundColor: 'rgba(0,0,0,0.8)', + opacity: 0, + legendColorBackground: '#fff', + displayColors: true, + })); }); - - // Manully trigger rather than having an async test - node.dispatchEvent(evt); - - // Check and see if tooltip was displayed - var tooltip = chartInstance.tooltip; - var globalDefaults = Chart.defaults.global; - - expect(tooltip._view).toEqual(jasmine.objectContaining({ - // Positioning - xPadding: 6, - yPadding: 6, - xAlign: 'left', - yAlign: 'center', - - // Body - bodyFontColor: '#fff', - _bodyFontFamily: globalDefaults.defaultFontFamily, - _bodyFontStyle: globalDefaults.defaultFontStyle, - _bodyAlign: 'left', - bodyFontSize: globalDefaults.defaultFontSize, - bodySpacing: 2, - - // Title - titleFontColor: '#fff', - _titleFontFamily: globalDefaults.defaultFontFamily, - _titleFontStyle: 'bold', - titleFontSize: globalDefaults.defaultFontSize, - _titleAlign: 'left', - titleSpacing: 2, - titleMarginBottom: 6, - - // Footer - footerFontColor: '#fff', - _footerFontFamily: globalDefaults.defaultFontFamily, - _footerFontStyle: 'bold', - footerFontSize: globalDefaults.defaultFontSize, - _footerAlign: 'left', - footerSpacing: 2, - footerMarginTop: 6, - - // Appearance - caretSize: 5, - cornerRadius: 6, - backgroundColor: 'rgba(0,0,0,0.8)', - opacity: 1, - legendColorBackground: '#fff', - displayColors: true, - - // Text - title: ['Point 2'], - beforeBody: [], - body: [{ - before: [], - lines: ['Dataset 1: 20'], - after: [] - }, { - before: [], - lines: ['Dataset 2: 40'], - after: [] - }], - afterBody: [], - footer: [], - caretPadding: 2, - labelColors: [{ - borderColor: 'rgb(255, 0, 0)', - backgroundColor: 'rgb(0, 255, 0)' - }, { - borderColor: 'rgb(0, 0, 255)', - backgroundColor: 'rgb(0, 255, 255)' - }] - })); - - expect(tooltip._view.x).toBeCloseToPixel(269); - expect(tooltip._view.y).toBeCloseToPixel(155); }); it('Should display in single mode', function() {