From 752407eba19befcfb4923c492ad900b251658837 Mon Sep 17 00:00:00 2001 From: Dan Onoshko Date: Mon, 5 Dec 2022 23:48:36 +0400 Subject: [PATCH] feat: events utils (#963) utils to handle chart clicks were added --- .size-limit.json | 2 +- sandboxes/events/index.html | 11 +++ sandboxes/events/index.ts | 4 ++ sandboxes/events/package.json | 16 +++++ sandboxes/events/src/App.vue | 89 ++++++++++++++++++++++++ sandboxes/events/src/chartConfig.ts | 28 ++++++++ sandboxes/events/vite.config.js | 6 ++ src/index.ts | 5 ++ src/utils.ts | 45 +++++++++++++ stories/chart.stories.ts | 101 ++++++++++++++++++++++++++++ 10 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 sandboxes/events/index.html create mode 100644 sandboxes/events/index.ts create mode 100644 sandboxes/events/package.json create mode 100644 sandboxes/events/src/App.vue create mode 100644 sandboxes/events/src/chartConfig.ts create mode 100644 sandboxes/events/vite.config.js create mode 100644 stories/chart.stories.ts diff --git a/.size-limit.json b/.size-limit.json index 5261dc91..b9e90c47 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -1,7 +1,7 @@ [ { "path": "dist/index.js", - "limit": "1.7 KB", + "limit": "1.9 KB", "webpack": false, "running": false }, diff --git a/sandboxes/events/index.html b/sandboxes/events/index.html new file mode 100644 index 00000000..087b841f --- /dev/null +++ b/sandboxes/events/index.html @@ -0,0 +1,11 @@ + + + + + + + + +
+ + diff --git a/sandboxes/events/index.ts b/sandboxes/events/index.ts new file mode 100644 index 00000000..52c7b68b --- /dev/null +++ b/sandboxes/events/index.ts @@ -0,0 +1,4 @@ +import { createApp } from 'vue' +import App from './src/App.vue' + +createApp(App).mount('#app') diff --git a/sandboxes/events/package.json b/sandboxes/events/package.json new file mode 100644 index 00000000..df369262 --- /dev/null +++ b/sandboxes/events/package.json @@ -0,0 +1,16 @@ +{ + "type": "module", + "scripts": { + "start": "vite" + }, + "dependencies": { + "chart.js": "^4.0.0", + "vue": "^3.2.31", + "vue-chartjs": "^5.0.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^3.0.1", + "typescript": "^4.9.3", + "vite": "^3.2.4" + } +} diff --git a/sandboxes/events/src/App.vue b/sandboxes/events/src/App.vue new file mode 100644 index 00000000..11e991ce --- /dev/null +++ b/sandboxes/events/src/App.vue @@ -0,0 +1,89 @@ + + + diff --git a/sandboxes/events/src/chartConfig.ts b/sandboxes/events/src/chartConfig.ts new file mode 100644 index 00000000..514c046d --- /dev/null +++ b/sandboxes/events/src/chartConfig.ts @@ -0,0 +1,28 @@ +export const data = { + labels: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ], + datasets: [ + { + label: 'Data One', + backgroundColor: '#f87979', + data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11] + } + ] +} + +export const options = { + responsive: true, + maintainAspectRatio: false +} diff --git a/sandboxes/events/vite.config.js b/sandboxes/events/vite.config.js new file mode 100644 index 00000000..2e3d2576 --- /dev/null +++ b/sandboxes/events/vite.config.js @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue()] +}) diff --git a/src/index.ts b/src/index.ts index 26f802d1..7d85bfff 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,11 @@ import { } from './typedCharts.js' export type { ChartProps, ChartComponentRef } from './types.js' +export { + getDatasetAtEvent, + getElementAtEvent, + getElementsAtEvent +} from './utils.js' export { Chart, createTypedChart, diff --git a/src/utils.ts b/src/utils.ts index 49f1c7fb..50728a5c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -91,3 +91,48 @@ export function cloneData< return nextData } + +/** + * Get dataset from mouse click event + * @param chart - Chart.js instance + * @param event - Mouse click event + * @returns Dataset + */ +export function getDatasetAtEvent(chart: Chart, event: MouseEvent) { + return chart.getElementsAtEventForMode( + event, + 'dataset', + { intersect: true }, + false + ) +} + +/** + * Get single dataset element from mouse click event + * @param chart - Chart.js instance + * @param event - Mouse click event + * @returns Dataset + */ +export function getElementAtEvent(chart: Chart, event: MouseEvent) { + return chart.getElementsAtEventForMode( + event, + 'nearest', + { intersect: true }, + false + ) +} + +/** + * Get all dataset elements from mouse click event + * @param chart - Chart.js instance + * @param event - Mouse click event + * @returns Dataset + */ +export function getElementsAtEvent(chart: Chart, event: MouseEvent) { + return chart.getElementsAtEventForMode( + event, + 'index', + { intersect: true }, + false + ) +} diff --git a/stories/chart.stories.ts b/stories/chart.stories.ts new file mode 100644 index 00000000..df91040a --- /dev/null +++ b/stories/chart.stories.ts @@ -0,0 +1,101 @@ +import 'chart.js/auto' +import type { InteractionItem } from 'chart.js' +import { ref } from 'vue' +import { + ChartComponentRef, + Chart, + getDatasetAtEvent, + getElementAtEvent, + getElementsAtEvent +} from '../src/index.js' +import * as barChartConfig from '../sandboxes/bar/src/chartConfig.js' + +export default { + title: 'Chart', + component: Chart, + parameters: { + layout: 'centered' + } +} + +export function Default(args) { + return { + components: { Chart }, + template: '', + setup() { + return { args } + } + } +} + +Default.args = { + id: 'bar-chart', + type: 'bar', + width: 400, + height: 400, + ...barChartConfig +} + +export function Events(args) { + return { + components: { Chart }, + template: '', + setup() { + const datasetAtEvent = (dataset: InteractionItem[]) => { + if (!dataset.length) return + + const datasetIndex = dataset[0].datasetIndex + + console.log('dataset', barChartConfig.data.datasets[datasetIndex].label) + } + + const elementAtEvent = (element: InteractionItem[]) => { + if (!element.length) return + + const { datasetIndex, index } = element[0] + + console.log( + 'element', + barChartConfig.data.labels[index], + barChartConfig.data.datasets[datasetIndex].data[index] + ) + } + + const elementsAtEvent = (elements: InteractionItem[]) => { + if (!elements.length) return + + console.log('elements', elements) + } + + const chartRef = ref(null) + + const onClick = (event: MouseEvent) => { + const { + value: { chart } + } = chartRef + + if (!chart) { + return + } + + datasetAtEvent(getDatasetAtEvent(chart, event)) + elementAtEvent(getElementAtEvent(chart, event)) + elementsAtEvent(getElementsAtEvent(chart, event)) + } + + return { + chartRef, + args, + onClick + } + } + } +} + +Events.args = { + id: 'bar-chart', + type: 'bar', + width: 400, + height: 400, + ...barChartConfig +}