Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

index-y interaction mode + convert horizontal bar defaults to new mode #4458

Merged
merged 5 commits into from Jul 28, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/general/interactions/README.md
Expand Up @@ -6,4 +6,5 @@ The hover configuration is passed into the `options.hover` namespace. The global
| ---- | ---- | ------- | -----------
| `mode` | `String` | `'nearest'` | Sets which elements appear in the tooltip. See [Interaction Modes](./modes.md#interaction-modes) for details.
| `intersect` | `Boolean` | `true` | if true, the hover mode only applies when the mouse position intersects an item on the chart.
| `axis` | `String` | `'x'` | Can be set to `'x'`, `'y'`, or `'xy'` to define which directions are used in calculating distances. Defaults to `'x'` for `index` mode and `'xy'` in `dataset` and `nearest` modes.
| `animationDuration` | `Number` | `400` | Duration in milliseconds it takes to animate hover style changes.
17 changes: 16 additions & 1 deletion docs/general/interactions/modes.md
Expand Up @@ -41,7 +41,7 @@ Finds the first item that intersects the point and returns it. Behaves like 'nea
See `'index'` mode

## index
Finds item at the same index. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item is used to determine the index.
Finds item at the same index. If the `intersect` setting is true, the first intersecting item is used to determine the index in the data. If `intersect` false the nearest item, in the x direction, is used to determine the index.

```javascript
var chart = new Chart(ctx, {
Expand All @@ -55,6 +55,21 @@ var chart = new Chart(ctx, {
})
```

To use index mode in a chart like the horizontal bar chart, where we search along the y direction, you can use the `axis` setting introduced in v2.7.0. By setting this value to `'y'` on the y direction is used.

```javascript
var chart = new Chart(ctx, {
type: 'horizontalBar',
data: data,
options: {
tooltips: {
mode: 'index',
axis: 'y'
}
}
})
```

## x-axis (deprecated)
Behaves like `'index'` mode with `intersect = false`.

Expand Down
7 changes: 5 additions & 2 deletions src/controllers/controller.bar.js
Expand Up @@ -31,7 +31,8 @@ defaults._set('bar', {

defaults._set('horizontalBar', {
hover: {
mode: 'label'
mode: 'index',
axis: 'y'
},

scales: {
Expand Down Expand Up @@ -82,7 +83,9 @@ defaults._set('horizontalBar', {
var datasetLabel = data.datasets[item.datasetIndex].label || '';
return datasetLabel + ': ' + item.xLabel;
}
}
},
mode: 'index',
axis: 'y'
}
});

Expand Down
38 changes: 27 additions & 11 deletions src/core/core.interaction.js
Expand Up @@ -66,17 +66,13 @@ function getIntersectItems(chart, position) {
* @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
* @param distanceMetric {Function} function to provide the distance between points
* @return {ChartElement[]} the nearest items
*/
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;
Expand All @@ -97,11 +93,27 @@ function getNearestItems(chart, position, intersect, distanceMetric) {
return nearestItems;
}

/**
* Get a distance metric function for two points based on the
* axis mode setting
* @param {String} axis the axis mode. x|y|xy
*/
function getDistanceMetricForAxis(axis) {
var useX = axis.indexOf('x') !== -1;
var useY = axis.indexOf('y') !== -1;

return function(pt1, pt2) {
var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
};
}

function indexMode(chart, e, options) {
var position = getRelativePosition(e, chart);
var distanceMetric = function(pt1, pt2) {
return Math.abs(pt1.x - pt2.x);
};
// Default axis for index mode is 'x' to match old behaviour
options.axis = options.axis || 'x';
var distanceMetric = getDistanceMetricForAxis(options.axis);
var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
var elements = [];

Expand Down Expand Up @@ -185,7 +197,9 @@ module.exports = {
*/
dataset: function(chart, e, options) {
var position = getRelativePosition(e, chart);
var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false);
options.axis = options.axis || 'xy';
var distanceMetric = getDistanceMetricForAxis(options.axis);
var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);

if (items.length > 0) {
items = chart.getDatasetMeta(items[0]._datasetIndex).data;
Expand All @@ -201,7 +215,7 @@ module.exports = {
* @private
*/
'x-axis': function(chart, e) {
return indexMode(chart, e, true);
return indexMode(chart, e, {intersect: true});
},

/**
Expand All @@ -227,7 +241,9 @@ module.exports = {
*/
nearest: function(chart, e, options) {
var position = getRelativePosition(e, chart);
var nearestItems = getNearestItems(chart, position, options.intersect);
options.axis = options.axis || 'xy';
var distanceMetric = getDistanceMetricForAxis(options.axis);
var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric);

// We have multiple items at the same distance from the event. Now sort by smallest
if (nearestItems.length > 1) {
Expand Down