diff --git a/src/plugins/d3/__stories__/line/Line.stories.tsx b/src/plugins/d3/__stories__/line/Line.stories.tsx new file mode 100644 index 00000000..12ddf2ee --- /dev/null +++ b/src/plugins/d3/__stories__/line/Line.stories.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +import {StoryObj} from '@storybook/react'; + +import {D3Plugin} from '../..'; +import {Loader} from '../../../../components/Loader/Loader'; +import {settings} from '../../../../libs'; +import {LineWithLogarithmicAxis} from '../../examples/line/LogarithmicAxis'; + +const ChartStory = ({Chart}: {Chart: React.FC}) => { + const [loading, setLoading] = React.useState(true); + + React.useEffect(() => { + settings.set({plugins: [D3Plugin]}); + setLoading(false); + }, []); + + if (loading) { + return ; + } + + return ( +
+ +
+ ); +}; + +export const LogarithmicAxis: StoryObj = { + name: 'Logarithmic axis', + args: { + Chart: LineWithLogarithmicAxis, + }, +}; + +export default { + title: 'Plugins/D3/Line', + component: ChartStory, +}; diff --git a/src/plugins/d3/examples/line/LogarithmicAxis.tsx b/src/plugins/d3/examples/line/LogarithmicAxis.tsx new file mode 100644 index 00000000..93e3303b --- /dev/null +++ b/src/plugins/d3/examples/line/LogarithmicAxis.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +import {Col, Container, Row, Text} from '@gravity-ui/uikit'; +import {randomNormal} from 'd3'; + +import {ChartKit} from '../../../../components/ChartKit'; +import {ChartKitWidgetData} from '../../../../types'; +import {ExampleWrapper} from '../ExampleWrapper'; + +export const LineWithLogarithmicAxis = () => { + const randomY = randomNormal(0, 100); + const widgetData: ChartKitWidgetData = { + series: { + data: [ + { + type: 'line', + name: 'Line series', + data: new Array(25).fill(null).map((_, index) => ({ + x: index, + y: Math.abs(randomY()), + })), + }, + ], + }, + }; + const lineWidgetData: ChartKitWidgetData = {...widgetData, title: {text: 'line'}}; + const logarithmicWidgetData: ChartKitWidgetData = { + ...widgetData, + title: {text: 'logarithmic'}, + yAxis: [ + { + type: 'logarithmic', + }, + ], + }; + + return ( + + + logarithmic VS line + + + + + + + + + + + + + + + ); +}; diff --git a/src/plugins/d3/renderer/hooks/useAxisScales/index.ts b/src/plugins/d3/renderer/hooks/useAxisScales/index.ts index c55822ea..2fcab444 100644 --- a/src/plugins/d3/renderer/hooks/useAxisScales/index.ts +++ b/src/plugins/d3/renderer/hooks/useAxisScales/index.ts @@ -1,10 +1,14 @@ import React from 'react'; -import {extent, scaleBand, scaleLinear, scaleUtc} from 'd3'; +import {extent, scaleBand, scaleLinear, scaleLog, scaleUtc} from 'd3'; import type {ScaleBand, ScaleLinear, ScaleTime} from 'd3'; import get from 'lodash/get'; -import {ChartKitWidgetAxis, ChartKitWidgetSeries} from '../../../../../types'; +import { + ChartKitWidgetAxis, + ChartKitWidgetAxisType, + ChartKitWidgetSeries, +} from '../../../../../types'; import {DEFAULT_AXIS_TYPE} from '../../constants'; import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, @@ -65,13 +69,14 @@ const filterCategoriesByVisibleSeries = (args: { }; export function createYScale(axis: PreparedAxis, series: PreparedSeries[], boundsHeight: number) { - const yType = get(axis, 'type', DEFAULT_AXIS_TYPE); + const yType: ChartKitWidgetAxisType = get(axis, 'type', DEFAULT_AXIS_TYPE); const yMin = get(axis, 'min'); const yCategories = get(axis, 'categories'); const yTimestamps = get(axis, 'timestamps'); switch (yType) { - case 'linear': { + case 'linear': + case 'logarithmic': { const domain = getDomainDataYBySeries(series); const range = [boundsHeight, boundsHeight * axis.maxPadding]; @@ -83,7 +88,8 @@ export function createYScale(axis: PreparedAxis, series: PreparedSeries[], bound yMaxValue = Math.max(yMaxValue, 0); } - return scaleLinear().domain([yMinValue, yMaxValue]).range(range).nice(); + const scaleFn = yType === 'logarithmic' ? scaleLog : scaleLinear; + return scaleFn().domain([yMinValue, yMaxValue]).range(range).nice(); } break; @@ -150,7 +156,7 @@ export function createXScale( ) { const xMin = get(axis, 'min'); const xMax = getDefaultMaxXAxisValue(series); - const xType = get(axis, 'type', DEFAULT_AXIS_TYPE); + const xType: ChartKitWidgetAxisType = get(axis, 'type', DEFAULT_AXIS_TYPE); const xCategories = get(axis, 'categories'); const xTimestamps = get(axis, 'timestamps'); const maxPadding = get(axis, 'maxPadding', 0); @@ -159,7 +165,8 @@ export function createXScale( const xRange = [0, boundsWidth - xAxisMinPadding]; switch (xType) { - case 'linear': { + case 'linear': + case 'logarithmic': { const domain = getDomainDataXBySeries(series); if (isNumericalArrayData(domain)) { @@ -167,7 +174,9 @@ export function createXScale( const xMinValue = typeof xMin === 'number' ? xMin : domainXMin; const xMaxValue = typeof xMax === 'number' ? Math.max(xMax, domainXMax) : domainXMax; - return scaleLinear().domain([xMinValue, xMaxValue]).range(xRange).nice(); + + const scaleFn = xType === 'logarithmic' ? scaleLog : scaleLinear; + return scaleFn().domain([xMinValue, xMaxValue]).range(xRange).nice(); } break; diff --git a/src/plugins/d3/renderer/hooks/useChartOptions/y-axis.ts b/src/plugins/d3/renderer/hooks/useChartOptions/y-axis.ts index bdbcbe47..fb08c685 100644 --- a/src/plugins/d3/renderer/hooks/useChartOptions/y-axis.ts +++ b/src/plugins/d3/renderer/hooks/useChartOptions/y-axis.ts @@ -4,6 +4,7 @@ import get from 'lodash/get'; import type {BaseTextStyle, ChartKitWidgetSeries, ChartKitWidgetYAxis} from '../../../../../types'; import { DEFAULT_AXIS_LABEL_FONT_SIZE, + DEFAULT_AXIS_TYPE, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants'; @@ -107,7 +108,7 @@ export const getPreparedYAxis = ({ const titleStyle: BaseTextStyle = { fontSize: get(axisItem, 'title.style.fontSize', yAxisTitleDefaults.fontSize), }; - const axisType = get(axisItem, 'type', 'linear'); + const axisType = get(axisItem, 'type', DEFAULT_AXIS_TYPE); const preparedAxis: PreparedAxis = { type: axisType, labels: { diff --git a/src/types/widget-data/axis.ts b/src/types/widget-data/axis.ts index 78317dc5..32ca24e0 100644 --- a/src/types/widget-data/axis.ts +++ b/src/types/widget-data/axis.ts @@ -2,7 +2,7 @@ import type {FormatNumberOptions} from '../../plugins/shared'; import type {BaseTextStyle} from './base'; -export type ChartKitWidgetAxisType = 'category' | 'datetime' | 'linear'; +export type ChartKitWidgetAxisType = 'category' | 'datetime' | 'linear' | 'logarithmic'; export type ChartKitWidgetAxisLabels = { /** Enable or disable the axis labels. */