From f5c4f97504b6ae96f8f0592bcc15cebb2dfba8a6 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Mon, 19 Oct 2020 14:24:06 +0300 Subject: [PATCH] Add interaction options (#7922) * Add interaction options * Add migration note --- docs/docs/configuration/tooltip.md | 4 +-- docs/docs/general/interactions/index.md | 2 +- docs/docs/general/interactions/modes.md | 16 ++++++----- docs/docs/getting-started/v3-migration.md | 1 + samples/charts/line/multi-axis.html | 4 ++- samples/charts/scatter/multi-axis.html | 6 ++-- src/controllers/controller.bar.js | 4 ++- src/controllers/controller.line.js | 4 ++- src/core/core.controller.js | 19 ++++++++++-- src/core/core.defaults.js | 7 +++-- src/plugins/plugin.tooltip.js | 2 -- test/specs/core.controller.tests.js | 35 +++++++++++++++++++---- types/core/index.d.ts | 9 ++++-- 13 files changed, 85 insertions(+), 28 deletions(-) diff --git a/docs/docs/configuration/tooltip.md b/docs/docs/configuration/tooltip.md index d6287e659..56f1bbe67 100644 --- a/docs/docs/configuration/tooltip.md +++ b/docs/docs/configuration/tooltip.md @@ -10,8 +10,8 @@ The tooltip configuration is passed into the `options.tooltips` namespace. The g | ---- | ---- | ------- | ----------- | `enabled` | `boolean` | `true` | Are on-canvas tooltips enabled? | `custom` | `function` | `null` | See [custom tooltip](#external-custom-tooltips) section. -| `mode` | `string` | `'nearest'` | Sets which elements appear in the tooltip. [more...](../general/interactions/modes.md#interaction-modes). -| `intersect` | `boolean` | `true` | If true, the tooltip mode applies only when the mouse position intersects with an element. If false, the mode will be applied at all times. +| `mode` | `string` | | Sets which elements appear in the tooltip. [more...](../general/interactions/modes.md#interaction-modes). +| `intersect` | `boolean` | | If true, the tooltip mode applies only when the mouse position intersects with an element. If false, the mode will be applied at all times. | `position` | `string` | `'average'` | The mode for positioning the tooltip. [more...](#position-modes) | `callbacks` | `object` | | See the [callbacks section](#tooltip-callbacks). | `itemSort` | `function` | | Sort tooltip items. [more...](#sort-callback) diff --git a/docs/docs/general/interactions/index.md b/docs/docs/general/interactions/index.md index ebed6f2a4..ee23346bb 100644 --- a/docs/docs/general/interactions/index.md +++ b/docs/docs/general/interactions/index.md @@ -2,7 +2,7 @@ title: Interactions --- -The hover configuration is passed into the `options.hover` namespace. The global hover configuration is at `Chart.defaults.hover`. To configure which events trigger chart interactions, see [events](./events.md#events). +The interaction configuration is passed into the `options.interaction` namespace. The global interaction configuration is at `Chart.defaults.interaction`. To configure which events trigger chart interactions, see [events](./events.md#events). | Name | Type | Default | Description | ---- | ---- | ------- | ----------- diff --git a/docs/docs/general/interactions/modes.md b/docs/docs/general/interactions/modes.md index 636dc5001..751f5d502 100644 --- a/docs/docs/general/interactions/modes.md +++ b/docs/docs/general/interactions/modes.md @@ -4,6 +4,8 @@ title: Interaction Modes When configuring interaction with the graph via hover or tooltips, a number of different modes are available. +`options.hover` and `options.tooltips` extend from `options.interaction`. So if `mode`, `intersect` or any other common settings are configured only in `options.interaction`, both hover and tooltips obey that. + The modes are detailed below and how they behave in conjunction with the `intersect` setting. ## point @@ -15,7 +17,7 @@ var chart = new Chart(ctx, { type: 'line', data: data, options: { - tooltips: { + interaction: { mode: 'point' } } @@ -31,7 +33,7 @@ var chart = new Chart(ctx, { type: 'line', data: data, options: { - tooltips: { + interaction: { mode: 'nearest' } } @@ -47,7 +49,7 @@ var chart = new Chart(ctx, { type: 'line', data: data, options: { - tooltips: { + interaction: { mode: 'index' } } @@ -61,7 +63,7 @@ var chart = new Chart(ctx, { type: 'bar', data: data, options: { - tooltips: { + interaction: { mode: 'index', axis: 'y' } @@ -77,7 +79,7 @@ var chart = new Chart(ctx, { type: 'line', data: data, options: { - tooltips: { + interaction: { mode: 'dataset' } } @@ -92,7 +94,7 @@ var chart = new Chart(ctx, { type: 'line', data: data, options: { - tooltips: { + interaction: { mode: 'x' } } @@ -107,7 +109,7 @@ var chart = new Chart(ctx, { type: 'line', data: data, options: { - tooltips: { + interaction: { mode: 'y' } } diff --git a/docs/docs/getting-started/v3-migration.md b/docs/docs/getting-started/v3-migration.md index d2cfb6f19..30105d699 100644 --- a/docs/docs/getting-started/v3-migration.md +++ b/docs/docs/getting-started/v3-migration.md @@ -202,6 +202,7 @@ Animation system was completely rewritten in Chart.js v3. Each property can now #### Interactions +* To allow DRY configuration, a root options scope for common interaction options was added. `options.hover` and `options.tooltips` now both extend from `options.interaction`. Defaults are defined at `defaults.interaction` level, so by default hover and tooltip interactions share the same mode etc. * `interactions` are now limited to the chart area * `{mode: 'label'}` was replaced with `{mode: 'index'}` * `{mode: 'single'}` was replaced with `{mode: 'nearest', intersect: true}` diff --git a/samples/charts/line/multi-axis.html b/samples/charts/line/multi-axis.html index 4a457aac4..be5ebf2fe 100644 --- a/samples/charts/line/multi-axis.html +++ b/samples/charts/line/multi-axis.html @@ -62,7 +62,9 @@ data: lineChartData, options: { responsive: true, - hoverMode: 'index', + interaction: { + mode: 'index' + }, stacked: false, title: { display: true, diff --git a/samples/charts/scatter/multi-axis.html b/samples/charts/scatter/multi-axis.html index 853ab3529..feaafda0d 100644 --- a/samples/charts/scatter/multi-axis.html +++ b/samples/charts/scatter/multi-axis.html @@ -88,8 +88,10 @@ data: scatterChartData, options: { responsive: true, - hoverMode: 'nearest', - intersect: true, + interaction: { + intersect: true, + mode: 'nearest' + }, title: { display: true, text: 'Chart.js Scatter Chart - Multi Axis' diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 173c649cb..cd02a2656 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -528,10 +528,12 @@ BarController.defaults = { 'maxBarThickness', 'minBarLength', ], - hover: { + interaction: { mode: 'index' }, + hover: {}, + datasets: { categoryPercentage: 0.8, barPercentage: 0.9, diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 669b60231..f9ae019e7 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -164,10 +164,12 @@ LineController.defaults = { showLines: true, spanGaps: false, - hover: { + interaction: { mode: 'index' }, + hover: {}, + scales: { _index_: { type: 'category', diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 0621bc884..52c35c03b 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -116,10 +116,25 @@ function initConfig(config) { defaults[config.type], config.options || {}); + options.hover = merge(Object.create(null), [ + defaults.interaction, + defaults.hover, + options.interaction, + options.hover + ]); + options.scales = scaleConfig; - options.title = (options.title !== false) && merge(Object.create(null), [defaults.plugins.title, options.title]); - options.tooltips = (options.tooltips !== false) && merge(Object.create(null), [defaults.plugins.tooltip, options.tooltips]); + options.title = (options.title !== false) && merge(Object.create(null), [ + defaults.plugins.title, + options.title + ]); + options.tooltips = (options.tooltips !== false) && merge(Object.create(null), [ + defaults.interaction, + defaults.plugins.tooltip, + options.interaction, + options.tooltips + ]); return config; } diff --git a/src/core/core.defaults.js b/src/core/core.defaults.js index 6ee9e681e..be9449d62 100644 --- a/src/core/core.defaults.js +++ b/src/core/core.defaults.js @@ -42,12 +42,15 @@ export class Defaults { lineWidth: 0, strokeStyle: undefined }; - this.hover = { - onHover: null, + this.interaction = { mode: 'nearest', intersect: true }; + this.hover = { + onHover: null + }; this.maintainAspectRatio = true; + this.onHover = null; this.onClick = null; this.responsive = true; this.showLines = true; diff --git a/src/plugins/plugin.tooltip.js b/src/plugins/plugin.tooltip.js index 58e5fd932..d9da0d809 100644 --- a/src/plugins/plugin.tooltip.js +++ b/src/plugins/plugin.tooltip.js @@ -1066,9 +1066,7 @@ export default { defaults: { enabled: true, custom: null, - mode: 'nearest', position: 'average', - intersect: true, backgroundColor: 'rgba(0,0,0,0.8)', titleFont: { style: 'bold', diff --git a/test/specs/core.controller.tests.js b/test/specs/core.controller.tests.js index 7467c0830..fe0dd8558 100644 --- a/test/specs/core.controller.tests.js +++ b/test/specs/core.controller.tests.js @@ -89,13 +89,38 @@ describe('Chart', function() { expect(chart.data.datasets[0].data).toEqual([10, 11, 12]); }); - it('should initialize config with default options', function() { + it('should initialize config with default interaction options', function() { var callback = function() {}; var defaults = Chart.defaults; + var defaultMode = defaults.line.interaction.mode; defaults.hover.onHover = callback; defaults.line.spanGaps = true; - defaults.line.hover.mode = 'x-axis'; + defaults.line.interaction.mode = 'test'; + + var chart = acquireChart({ + type: 'line' + }); + + var options = chart.options; + expect(options.font.size).toBe(defaults.font.size); + expect(options.showLines).toBe(defaults.line.showLines); + expect(options.spanGaps).toBe(true); + expect(options.hover.onHover).toBe(callback); + expect(options.hover.mode).toBe('test'); + + defaults.hover.onHover = null; + defaults.line.spanGaps = false; + defaults.line.interaction.mode = defaultMode; + }); + + it('should initialize config with default hover options', function() { + var callback = function() {}; + var defaults = Chart.defaults; + + defaults.hover.onHover = callback; + defaults.line.spanGaps = true; + defaults.line.hover.mode = 'test'; var chart = acquireChart({ type: 'line' @@ -106,11 +131,11 @@ describe('Chart', function() { expect(options.showLines).toBe(defaults.line.showLines); expect(options.spanGaps).toBe(true); expect(options.hover.onHover).toBe(callback); - expect(options.hover.mode).toBe('x-axis'); + expect(options.hover.mode).toBe('test'); defaults.hover.onHover = null; defaults.line.spanGaps = false; - defaults.line.hover.mode = 'index'; + delete defaults.line.hover.mode; }); it('should override default options', function() { @@ -141,7 +166,7 @@ describe('Chart', function() { expect(options.title.position).toBe('bottom'); defaults.hover.onHover = null; - defaults.line.hover.mode = 'index'; + delete defaults.line.hover.mode; defaults.line.spanGaps = false; }); diff --git a/types/core/index.d.ts b/types/core/index.d.ts index 730ae8d4a..05104d478 100644 --- a/types/core/index.d.ts +++ b/types/core/index.d.ts @@ -417,13 +417,18 @@ export interface Defaults { readonly color: string; readonly events: ('mousemove' | 'mouseout' | 'click' | 'touchstart' | 'touchmove')[]; readonly font: IFontSpec; - readonly hover: { - onHover?: () => void; + readonly interaction: { mode: InteractionMode | string; intersect: boolean; }; + readonly hover: { + onHover?: () => void; + mode?: InteractionMode | string; + intersect?: boolean; + }; readonly maintainAspectRatio: boolean; readonly onClick?: () => void; + readonly onHover?: () => void; readonly responsive: boolean; readonly plugins: { [key: string]: any }; -- 2.47.2