From 9aedc59de0fa628cc04037740c350b3dc69e1c59 Mon Sep 17 00:00:00 2001 From: Irina Kuzmina Date: Fri, 1 Mar 2024 12:57:52 +0300 Subject: [PATCH] feat(D3 plugin): add cursor option for series (#441) feat(D3): add cursor option for series --- src/plugins/d3/renderer/hooks/useSeries/prepare-area.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/prepare-scatter.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/prepare-treemap.ts | 5 ++++- src/plugins/d3/renderer/hooks/useSeries/types.ts | 3 ++- src/plugins/d3/renderer/hooks/useShapes/area/index.tsx | 3 ++- src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx | 3 ++- src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx | 3 ++- src/plugins/d3/renderer/hooks/useShapes/line/index.tsx | 3 ++- src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx | 3 ++- src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx | 3 ++- src/plugins/d3/renderer/hooks/useShapes/treemap/index.tsx | 3 ++- src/types/widget-data/base.ts | 2 ++ 16 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-area.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-area.ts index 6db51cf9..508cea2a 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-area.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-area.ts @@ -85,6 +85,7 @@ export function prepareArea(args: PrepareAreaSeriesArgs) { allowOverlap: get(series, 'dataLabels.allowOverlap', false), }, marker: prepareMarker(series, seriesOptions), + cursor: get(series, 'cursor', null), }; return prepared; diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.ts index 643d1712..e13cc396 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-x.ts @@ -42,6 +42,7 @@ export function prepareBarXSeries(args: PrepareBarXSeriesArgs): PreparedSeries[] allowOverlap: series.dataLabels?.allowOverlap || false, padding: get(series, 'dataLabels.padding', DEFAULT_DATALABELS_PADDING), }, + cursor: get(series, 'cursor', null), }; }, []); } diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.ts index 495c1a7d..71323dc4 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-bar-y.ts @@ -53,6 +53,7 @@ export function prepareBarYSeries(args: PrepareBarYSeriesArgs): PreparedSeries[] stacking: series.stacking, stackId: getSeriesStackId(series), dataLabels: prepareDataLabels(series), + cursor: get(series, 'cursor', null), }; }, []); } diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts index 0883378c..1df017cb 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts @@ -121,6 +121,7 @@ export function prepareLineSeries(args: PrepareLineSeriesArgs) { dashStyle: dashStyle as DashStyle, linecap: prepareLinecap(dashStyle as DashStyle, series, seriesOptions) as LineCap, opacity: get(series, 'opacity', null), + cursor: get(series, 'cursor', null), }; return prepared; diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts index a2c240bf..d8597e01 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts @@ -62,6 +62,7 @@ export function preparePieSeries(args: PreparePieSeriesArgs) { }, renderCustomShape: series.renderCustomShape, opacity: get(dataItem, 'opacity', null), + cursor: get(series, 'cursor', null), }; return result; diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-scatter.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-scatter.ts index ee809a85..ec8c85b1 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-scatter.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-scatter.ts @@ -66,6 +66,7 @@ export function prepareScatterSeries(args: PrepareScatterSeriesArgs): PreparedSc }, data: s.data, marker: prepareMarker(s, seriesOptions, index), + cursor: get(s, 'cursor', null), }; return prepared; diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-treemap.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-treemap.ts index 1716b0c8..717c85df 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-treemap.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-treemap.ts @@ -24,7 +24,7 @@ export function prepareTreemap(args: PrepareTreemapSeriesArgs) { const name = s.name || ''; const color = s.color || colorScale(name); - return { + const preparedSeries: PreparedTreemapSeries = { color, data: s.data, dataLabels: { @@ -43,6 +43,9 @@ export function prepareTreemap(args: PrepareTreemapSeriesArgs) { }, levels: s.levels, layoutAlgorithm: get(s, 'layoutAlgorithm', LayoutAlgorithm.Binary), + cursor: get(s, 'cursor', null), }; + + return preparedSeries; }); } diff --git a/src/plugins/d3/renderer/hooks/useSeries/types.ts b/src/plugins/d3/renderer/hooks/useSeries/types.ts index 0aa2ffdb..7650fba1 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/types.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/types.ts @@ -82,6 +82,7 @@ type BasePreparedSeries = { enabled: boolean; symbol: PreparedLegendSymbol; }; + cursor: string | null; }; export type PreparedScatterSeries = { @@ -243,7 +244,7 @@ export type PreparedTreemapSeries = { }; layoutAlgorithm: `${LayoutAlgorithm}`; } & BasePreparedSeries & - TreemapSeries; + Omit; export type PreparedSeries = | PreparedScatterSeries diff --git a/src/plugins/d3/renderer/hooks/useShapes/area/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/area/index.tsx index c52b745e..ac0cd72e 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/area/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/area/index.tsx @@ -51,7 +51,8 @@ export const AreaSeriesShapes = (args: Args) => { .selectAll('shape') .data(preparedData) .join('g') - .attr('class', b('series')); + .attr('class', b('series')) + .attr('cursor', (d) => d.series.cursor); shapeSelection .append('path') diff --git a/src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx index 0fe5b76b..a9335892 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx @@ -45,7 +45,8 @@ export const BarXSeriesShapes = (args: Args) => { .attr('height', (d) => d.height) .attr('width', (d) => d.width) .attr('fill', (d) => d.data.color || d.series.color) - .attr('opacity', (d) => d.opacity); + .attr('opacity', (d) => d.opacity) + .attr('cursor', (d) => d.series.cursor); let dataLabels = preparedData.map((d) => d.label).filter(Boolean) as LabelData[]; if (!preparedData[0]?.series.dataLabels.allowOverlap) { diff --git a/src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx index d7df9ac1..cd635518 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx @@ -39,7 +39,8 @@ export const BarYSeriesShapes = (args: Args) => { .attr('height', (d) => d.height) .attr('width', (d) => d.width) .attr('fill', (d) => d.color) - .attr('opacity', (d) => d.data.opacity || null); + .attr('opacity', (d) => d.data.opacity || null) + .attr('cursor', (d) => d.series.cursor); const dataLabels = preparedData.filter((d) => d.series.dataLabels.enabled); const labelSelection = svgElement diff --git a/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx index a36c1578..a9ae4526 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx @@ -58,7 +58,8 @@ export const LineSeriesShapes = (args: Args) => { .attr('stroke-linejoin', (d) => d.linecap) .attr('stroke-linecap', (d) => d.linecap) .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width)) - .attr('opacity', (d) => d.opacity); + .attr('opacity', (d) => d.opacity) + .attr('cursor', (d) => d.series.cursor); let dataLabels = preparedData.reduce((acc, d) => { return acc.concat(d.labels); diff --git a/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx index b0ae73b4..52ab228c 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx @@ -53,7 +53,8 @@ export function PieSeriesShapes(args: PreparePieSeriesArgs) { return `translate(${x}, ${y})`; }) .style('stroke', (pieData) => pieData.borderColor) - .style('stroke-width', (pieData) => pieData.borderWidth); + .style('stroke-width', (pieData) => pieData.borderWidth) + .attr('cursor', (pieData) => pieData.series.cursor); // Render halo appearing outside the hovered slice shapesSelection diff --git a/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx index b186a73b..26fcacfd 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx @@ -47,7 +47,8 @@ export function ScatterSeriesShape(props: ScatterSeriesShapeProps) { .join('g') .call(renderMarker) .attr('fill', (d) => d.point.data.color || d.point.series.color || '') - .attr('opacity', (d) => d.point.opacity); + .attr('opacity', (d) => d.point.opacity) + .attr('cursor', (d) => d.point.series.cursor); const getSelectedPoint = (element: Element) => { return select(element).datum(); diff --git a/src/plugins/d3/renderer/hooks/useShapes/treemap/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/treemap/index.tsx index bf0478e4..21c78c1e 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/treemap/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/treemap/index.tsx @@ -35,7 +35,8 @@ export const TreemapSeriesShape = (props: ShapeProps) => { .selectAll('g') .data(leaves) .join('g') - .attr('transform', (d) => `translate(${d.x0},${d.y0})`); + .attr('transform', (d) => `translate(${d.x0},${d.y0})`) + .attr('cursor', series.cursor); const rectSelection = leaf .append('rect') .attr('id', (d) => d.id || d.name) diff --git a/src/types/widget-data/base.ts b/src/types/widget-data/base.ts index 5593bb6a..af1658b8 100644 --- a/src/types/widget-data/base.ts +++ b/src/types/widget-data/base.ts @@ -22,6 +22,8 @@ export type BaseSeries = { * */ allowOverlap?: boolean; }; + /** You can set the cursor to "pointer" if you have click events attached to the series, to signal to the user that the points and lines can be clicked. */ + cursor?: string; }; export type BaseSeriesData = {