From 36fc2be63899fbbe3fa0a2a24f233ff229ed29d1 Mon Sep 17 00:00:00 2001 From: "Mr.Dr.Professor Patrick" Date: Tue, 20 Feb 2024 19:25:09 +0100 Subject: [PATCH] feat(D3 plugin): add opacity and marker setting to shape (#432) feat(D3 plugin): add opacity and marker setting to shape (#425) * feat(D3 plugin): add opacity and marker setting to shape * add jsdoc Co-authored-by: Irina Kuzmina --- .../d3/renderer/hooks/useSeries/prepare-line.ts | 1 + .../d3/renderer/hooks/useSeries/prepare-pie.ts | 1 + src/plugins/d3/renderer/hooks/useSeries/types.ts | 2 ++ .../d3/renderer/hooks/useShapes/bar-x/index.tsx | 3 ++- .../hooks/useShapes/bar-x/prepare-data.ts | 1 + .../d3/renderer/hooks/useShapes/bar-x/types.ts | 1 + .../d3/renderer/hooks/useShapes/bar-y/index.tsx | 3 ++- .../hooks/useShapes/bar-y/prepare-data.ts | 1 + .../d3/renderer/hooks/useShapes/bar-y/types.ts | 1 + .../d3/renderer/hooks/useShapes/line/index.tsx | 3 ++- .../renderer/hooks/useShapes/line/prepare-data.ts | 1 + .../d3/renderer/hooks/useShapes/line/types.ts | 1 + src/plugins/d3/renderer/hooks/useShapes/marker.ts | 10 +++++++++- .../d3/renderer/hooks/useShapes/pie/index.tsx | 5 +++-- .../renderer/hooks/useShapes/pie/prepare-data.ts | 1 + .../d3/renderer/hooks/useShapes/pie/types.ts | 1 + .../d3/renderer/hooks/useShapes/scatter/index.tsx | 3 ++- .../hooks/useShapes/scatter/prepare-data.ts | 3 +++ .../d3/renderer/hooks/useShapes/scatter/types.ts | 1 + src/types/widget-data/area.ts | 15 +++++++++++++++ src/types/widget-data/bar-x.ts | 2 ++ src/types/widget-data/bar-y.ts | 2 ++ src/types/widget-data/line.ts | 9 +++++++++ src/types/widget-data/pie.ts | 2 ++ src/types/widget-data/scatter.ts | 3 +++ 25 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts b/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts index 34cc1fc7..0883378c 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-line.ts @@ -120,6 +120,7 @@ export function prepareLineSeries(args: PrepareLineSeriesArgs) { marker: prepareMarker(series, seriesOptions), dashStyle: dashStyle as DashStyle, linecap: prepareLinecap(dashStyle as DashStyle, series, seriesOptions) as LineCap, + opacity: get(series, 'opacity', 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 212ad692..a2c240bf 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/prepare-pie.ts @@ -61,6 +61,7 @@ export function preparePieSeries(args: PreparePieSeriesArgs) { }, }, renderCustomShape: series.renderCustomShape, + opacity: get(dataItem, 'opacity', null), }; return result; diff --git a/src/plugins/d3/renderer/hooks/useSeries/types.ts b/src/plugins/d3/renderer/hooks/useSeries/types.ts index 8d95983a..0aa2ffdb 100644 --- a/src/plugins/d3/renderer/hooks/useSeries/types.ts +++ b/src/plugins/d3/renderer/hooks/useSeries/types.ts @@ -163,6 +163,7 @@ export type PreparedPieSeries = { }; }; renderCustomShape?: PieSeries['renderCustomShape']; + opacity: number | null; } & BasePreparedSeries; export type PreparedLineSeries = { @@ -195,6 +196,7 @@ export type PreparedLineSeries = { }; dashStyle: DashStyle; linecap: LineCap; + opacity: number | null; } & BasePreparedSeries; export type PreparedAreaSeries = { 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 33fab5f6..0fe5b76b 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-x/index.tsx @@ -44,7 +44,8 @@ export const BarXSeriesShapes = (args: Args) => { .attr('y', (d) => d.y) .attr('height', (d) => d.height) .attr('width', (d) => d.width) - .attr('fill', (d) => d.data.color || d.series.color); + .attr('fill', (d) => d.data.color || d.series.color) + .attr('opacity', (d) => d.opacity); 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-x/prepare-data.ts b/src/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.ts index 507c7b9a..99a1d8f5 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-x/prepare-data.ts @@ -160,6 +160,7 @@ export const prepareBarXData = (args: { y: y - stackHeight, width: rectWidth, height, + opacity: get(yValue.data, 'opacity', null), data: yValue.data, series: yValue.series, }; diff --git a/src/plugins/d3/renderer/hooks/useShapes/bar-x/types.ts b/src/plugins/d3/renderer/hooks/useShapes/bar-x/types.ts index 1d560b06..4c723ce9 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-x/types.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-x/types.ts @@ -7,6 +7,7 @@ export type PreparedBarXData = Omit & { y: number; width: number; height: number; + opacity: number | null; series: PreparedBarXSeries; label?: LabelData; }; 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 8665acc6..d7df9ac1 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-y/index.tsx @@ -38,7 +38,8 @@ export const BarYSeriesShapes = (args: Args) => { .attr('y', (d) => d.y) .attr('height', (d) => d.height) .attr('width', (d) => d.width) - .attr('fill', (d) => d.color); + .attr('fill', (d) => d.color) + .attr('opacity', (d) => d.data.opacity || null); const dataLabels = preparedData.filter((d) => d.series.dataLabels.enabled); const labelSelection = svgElement diff --git a/src/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.ts b/src/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.ts index 2d2d24e4..f41c3412 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-y/prepare-data.ts @@ -142,6 +142,7 @@ export const prepareBarYData = (args: { width, height: barHeight, color: data.color || s.color, + opacity: get(data, 'opacity', null), data, series: s, }); diff --git a/src/plugins/d3/renderer/hooks/useShapes/bar-y/types.ts b/src/plugins/d3/renderer/hooks/useShapes/bar-y/types.ts index e2b0e9b2..49d4ff37 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/bar-y/types.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/bar-y/types.ts @@ -7,5 +7,6 @@ export type PreparedBarYData = Omit & { width: number; height: number; color: string; + opacity: number | null; series: PreparedBarYSeries; }; diff --git a/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx index 5ea81930..a36c1578 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/line/index.tsx @@ -57,7 +57,8 @@ export const LineSeriesShapes = (args: Args) => { .attr('stroke-width', (d) => d.width) .attr('stroke-linejoin', (d) => d.linecap) .attr('stroke-linecap', (d) => d.linecap) - .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width)); + .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.width)) + .attr('opacity', (d) => d.opacity); let dataLabels = preparedData.reduce((acc, d) => { return acc.concat(d.labels); diff --git a/src/plugins/d3/renderer/hooks/useShapes/line/prepare-data.ts b/src/plugins/d3/renderer/hooks/useShapes/line/prepare-data.ts index 6e323ed4..6412baf5 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/line/prepare-data.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/line/prepare-data.ts @@ -82,6 +82,7 @@ export const prepareLineData = (args: { id: s.id, dashStyle: s.dashStyle, linecap: s.linecap, + opacity: s.opacity, }; acc.push(result); diff --git a/src/plugins/d3/renderer/hooks/useShapes/line/types.ts b/src/plugins/d3/renderer/hooks/useShapes/line/types.ts index 9c1ed1e6..82630028 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/line/types.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/line/types.ts @@ -28,4 +28,5 @@ export type PreparedLineData = { labels: LabelData[]; dashStyle: DashStyle; linecap: LineCap; + opacity: number | null; }; diff --git a/src/plugins/d3/renderer/hooks/useShapes/marker.ts b/src/plugins/d3/renderer/hooks/useShapes/marker.ts index b09c06cc..dd947421 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/marker.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/marker.ts @@ -47,7 +47,15 @@ export function renderMarker( export function getMarkerVisibility(d: MarkerData) { const markerStates = d.point.series.marker.states; - const enabled = (markerStates.hover.enabled && d.hovered) || markerStates.normal.enabled; + let enabled: Boolean; + + if (d.hovered) { + enabled = markerStates.hover.enabled && d.hovered; + } else { + enabled = + markerStates.normal.enabled || get(d.point.data, 'marker.states.normal.enabled', false); + } + return enabled ? '' : 'hidden'; } diff --git a/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx index d539774c..b0ae73b4 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/pie/index.tsx @@ -91,7 +91,8 @@ export function PieSeriesShapes(args: PreparePieSeriesArgs) { return arcGenerator(d); }) .attr('class', b('segment')) - .attr('fill', (d) => d.data.color); + .attr('fill', (d) => d.data.color) + .attr('opacity', (d) => d.data.opacity); shapesSelection .selectAll('text') @@ -167,7 +168,7 @@ export function PieSeriesShapes(args: PreparePieSeriesArgs) { type: 'pie', name: currentSegment.series.name, }, - data: currentSegment.series, + data: currentSegment.series.data, }; dispatcher.call('hover-shape', {}, [data], pointer(e, svgContainer)); diff --git a/src/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.ts b/src/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.ts index 38b9ef82..70284c65 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/pie/prepare-data.ts @@ -79,6 +79,7 @@ export function preparePieData(args: Args): PreparedPieData[] { return { value: item.value, color: item.color, + opacity: item.opacity, series: item, hovered: false, active: true, diff --git a/src/plugins/d3/renderer/hooks/useShapes/pie/types.ts b/src/plugins/d3/renderer/hooks/useShapes/pie/types.ts index cdd7d589..7e524f70 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/pie/types.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/pie/types.ts @@ -7,6 +7,7 @@ import {ConnectorCurve} from '../../../../../../types'; export type SegmentData = { value: number; color: string; + opacity: number | null; series: PreparedPieSeries; hovered: boolean; active: boolean; diff --git a/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx b/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx index 86b46759..b186a73b 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx +++ b/src/plugins/d3/renderer/hooks/useShapes/scatter/index.tsx @@ -46,7 +46,8 @@ export function ScatterSeriesShape(props: ScatterSeriesShapeProps) { .data(preparedData, shapeKey) .join('g') .call(renderMarker) - .attr('fill', (d) => d.point.data.color || d.point.series.color || ''); + .attr('fill', (d) => d.point.data.color || d.point.series.color || '') + .attr('opacity', (d) => d.point.opacity); const getSelectedPoint = (element: Element) => { return select(element).datum(); diff --git a/src/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.ts b/src/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.ts index c9a37cbd..48dd9278 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/scatter/prepare-data.ts @@ -1,3 +1,5 @@ +import get from 'lodash/get'; + import type {ScatterSeriesData} from '../../../../../../types'; import type {ChartScale} from '../../useAxisScales'; @@ -32,6 +34,7 @@ export const prepareScatterData = (args: { series: s, x: getXValue({point: d, xAxis, xScale}), y: getYValue({point: d, yAxis, yScale}), + opacity: get(d, 'opacity', null), }, hovered: false, active: true, diff --git a/src/plugins/d3/renderer/hooks/useShapes/scatter/types.ts b/src/plugins/d3/renderer/hooks/useShapes/scatter/types.ts index 18cf7798..b0363fa2 100644 --- a/src/plugins/d3/renderer/hooks/useShapes/scatter/types.ts +++ b/src/plugins/d3/renderer/hooks/useShapes/scatter/types.ts @@ -4,6 +4,7 @@ import {PreparedScatterSeries} from '../../useSeries/types'; type PointData = { x: number; y: number; + opacity: number | null; data: ScatterSeriesData; series: PreparedScatterSeries; }; diff --git a/src/types/widget-data/area.ts b/src/types/widget-data/area.ts index 2509fea5..bff15d3e 100644 --- a/src/types/widget-data/area.ts +++ b/src/types/widget-data/area.ts @@ -20,6 +20,21 @@ export type AreaSeriesData = BaseSeriesData & { y?: string | number; /** Data label value of the point. If not specified, the y value is used. */ label?: string | number; + /** Individual marker options for the point. */ + marker?: { + /** States for a single point marker. */ + states?: { + /** The normal state of a single point marker. */ + normal?: { + /** + * Enable or disable the point marker. + * + * @default false + * */ + enabled: boolean; + }; + }; + }; }; export type AreaMarkerSymbol = 'circle' | 'square'; diff --git a/src/types/widget-data/bar-x.ts b/src/types/widget-data/bar-x.ts index e85cfaec..3df10e7c 100644 --- a/src/types/widget-data/bar-x.ts +++ b/src/types/widget-data/bar-x.ts @@ -26,6 +26,8 @@ export type BarXSeriesData = BaseSeriesData & { category?: string; /** Data label value of the bar-x column. If not specified, the y value is used. */ label?: string | number; + /** Individual opacity for the bar-x column. */ + opacity?: number; }; export type BarXSeries = BaseSeries & { diff --git a/src/types/widget-data/bar-y.ts b/src/types/widget-data/bar-y.ts index d20b92a3..edb9cb20 100644 --- a/src/types/widget-data/bar-y.ts +++ b/src/types/widget-data/bar-y.ts @@ -20,6 +20,8 @@ export type BarYSeriesData = BaseSeriesData & { y?: string | number; /** Data label value of the bar. If not specified, the x value is used. */ label?: string | number; + /** Individual opacity for the bar. */ + opacity?: number; }; export type BarYSeries = BaseSeries & { diff --git a/src/types/widget-data/line.ts b/src/types/widget-data/line.ts index 8c2af3fc..2a5290f2 100644 --- a/src/types/widget-data/line.ts +++ b/src/types/widget-data/line.ts @@ -20,6 +20,13 @@ export type LineSeriesData = BaseSeriesData & { y?: string | number; /** Data label value of the point. If not specified, the y value is used. */ label?: string | number; + marker?: { + states?: { + normal?: { + enabled: boolean; + }; + }; + }; }; export type LineSeries = BaseSeries & { @@ -44,4 +51,6 @@ export type LineSeries = BaseSeries & { dashStyle?: `${DashStyle}`; /** Option for line cap style */ linecap?: `${LineCap}`; + /** Individual opacity for the line. */ + opacity?: number; }; diff --git a/src/types/widget-data/pie.ts b/src/types/widget-data/pie.ts index 8e1c2a37..4875ba22 100644 --- a/src/types/widget-data/pie.ts +++ b/src/types/widget-data/pie.ts @@ -12,6 +12,8 @@ export type PieSeriesData = BaseSeriesData & { visible?: boolean; /** Initial data label of the pie segment. If not specified, the value is used. */ label?: string; + /** Individual opacity for the pie segment. */ + opacity?: number; }; export type ConnectorShape = 'straight-line' | 'polyline'; diff --git a/src/types/widget-data/scatter.ts b/src/types/widget-data/scatter.ts index 5036e365..ff789037 100644 --- a/src/types/widget-data/scatter.ts +++ b/src/types/widget-data/scatter.ts @@ -23,7 +23,10 @@ export type ScatterSeriesData = BaseSeriesData & { * @deprecated use `x` or `y` instead */ category?: string; + /** Individual radius for the point. */ radius?: number; + /** Individual opacity for the point. */ + opacity?: number; }; export type ScatterSeries = BaseSeries & {