Добавлено опциональное подключение анимации для графиков

This commit is contained in:
goodmice 2022-08-04 01:31:35 +05:00
parent 8f9383654d
commit 53c99a5f42
6 changed files with 39 additions and 29 deletions

View File

@ -3,6 +3,8 @@ import * as d3 from 'd3'
import { ChartRegistry } from '@components/d3/types' import { ChartRegistry } from '@components/d3/types'
import { makePointsOptimizator } from '@utils' import { makePointsOptimizator } from '@utils'
import { appendTransition } from './base'
export const renderArea = <DataType extends Record<string, unknown>>( export const renderArea = <DataType extends Record<string, unknown>>(
xAxis: (value: any) => number, xAxis: (value: any) => number,
yAxis: (value: any) => number, yAxis: (value: any) => number,
@ -47,10 +49,8 @@ export const renderArea = <DataType extends Record<string, unknown>>(
if (chart().selectAll('path').empty()) if (chart().selectAll('path').empty())
chart().append('path') chart().append('path')
chart().selectAll('path') appendTransition(chart().selectAll('path'), chart)
.transition() .attr('d', area(data))
.duration(chart.animDurationMs || 0)
.attr('d', area(data as any))
.attr('stroke-dasharray', chart.dash ? String(chart.dash) : null) .attr('stroke-dasharray', chart.dash ? String(chart.dash) : null)
.attr('fill', chart.areaColor ?? null) .attr('fill', chart.areaColor ?? null)

View File

@ -0,0 +1,12 @@
import * as d3 from 'd3'
import { ChartRegistry } from '../types'
export const appendTransition = <DataType, BaseType extends d3.BaseType, Datum, PElement extends d3.BaseType, PDatum>(
elms: d3.Selection<BaseType, Datum, PElement, PDatum>,
chart: ChartRegistry<DataType>
): d3.Selection<BaseType, Datum, PElement, PDatum> => {
if (chart.animDurationMs && chart.animDurationMs > 0)
return elms.transition().duration(chart.animDurationMs) as any
return elms
}

View File

@ -3,6 +3,8 @@ import * as d3 from 'd3'
import { ChartRegistry } from '@components/d3/types' import { ChartRegistry } from '@components/d3/types'
import { makePointsOptimizator } from '@utils' import { makePointsOptimizator } from '@utils'
import { appendTransition } from './base'
export const renderLine = <DataType extends Record<string, unknown>>( export const renderLine = <DataType extends Record<string, unknown>>(
xAxis: (value: any) => number, xAxis: (value: any) => number,
yAxis: (value: any) => number, yAxis: (value: any) => number,
@ -35,11 +37,9 @@ export const renderLine = <DataType extends Record<string, unknown>>(
if (chart().selectAll('path').empty()) if (chart().selectAll('path').empty())
chart().append('path') chart().append('path')
chart().selectAll('path') appendTransition(chart().selectAll('path'), chart)
.transition()
.duration(chart.animDurationMs ?? 0)
.attr('d', line(data)) .attr('d', line(data))
.attr('stroke-dasharray', String(chart.dash ?? '')) .attr('stroke-dasharray', chart.dash ? String(chart.dash) : null)
return data return data
} }

View File

@ -1,5 +1,7 @@
import { ChartOffset, ChartRegistry } from '@components/d3/types' import { ChartOffset, ChartRegistry } from '@components/d3/types'
import { appendTransition } from './base'
export const renderNeedle = <DataType extends Record<string, unknown>>( export const renderNeedle = <DataType extends Record<string, unknown>>(
xAxis: (value: d3.NumberValue) => number, xAxis: (value: d3.NumberValue) => number,
yAxis: (value: d3.NumberValue) => number, yAxis: (value: d3.NumberValue) => number,
@ -19,10 +21,7 @@ export const renderNeedle = <DataType extends Record<string, unknown>>(
currentNeedles.exit().remove() currentNeedles.exit().remove()
currentNeedles.enter().append('line') currentNeedles.enter().append('line')
chart() appendTransition(chart().selectAll<SVGLineElement, DataType>('line'), chart)
.selectAll<SVGLineElement, DataType>('line')
.transition()
.duration(chart.animDurationMs ?? 0)
.attr('x1', (d) => xAxis(chart.x(d))) .attr('x1', (d) => xAxis(chart.x(d)))
.attr('x2', (d) => xAxis(chart.x(d))) .attr('x2', (d) => xAxis(chart.x(d)))
.attr('y1', height - offset.bottom - offset.top) .attr('y1', height - offset.bottom - offset.top)

View File

@ -1,5 +1,7 @@
import { ChartRegistry, PointChartDataset } from '@components/d3/types' import { ChartRegistry, PointChartDataset } from '@components/d3/types'
import { appendTransition } from './base'
const defaultConfig: Required<Omit<PointChartDataset, 'type'>> = { const defaultConfig: Required<Omit<PointChartDataset, 'type'>> = {
radius: 3, radius: 3,
shape: 'circle', shape: 'circle',
@ -10,6 +12,14 @@ const defaultConfig: Required<Omit<PointChartDataset, 'type'>> = {
fillOpacity: 1, fillOpacity: 1,
} }
const getPointsRoot = <DataType,>(chart: ChartRegistry<DataType>, embeded?: boolean): d3.Selection<SVGGElement, any, any, any> => {
const root = chart()
if (!embeded) return root
if (root.select('.points').empty())
root.append('g').attr('class', 'points')
return root.select('.points')
}
export const renderPoint = <DataType extends Record<string, unknown>>( export const renderPoint = <DataType extends Record<string, unknown>>(
xAxis: (value: any) => number, xAxis: (value: any) => number,
yAxis: (value: any) => number, yAxis: (value: any) => number,
@ -24,19 +34,7 @@ export const renderPoint = <DataType extends Record<string, unknown>>(
config = { ...defaultConfig, ...chart } config = { ...defaultConfig, ...chart }
else return data else return data
const getPointsRoot = (): d3.Selection<any, any, any, any> => { appendTransition(getPointsRoot(chart, embeded), chart)
let root = chart()
if (embeded) {
if (root.select('.points').empty())
root.append('g').attr('class', 'points')
root = root.select('.points')
}
return root
}
getPointsRoot()
.transition()
.duration(chart.animDurationMs ?? 0)
.attr('stroke-width', config.strokeWidth) .attr('stroke-width', config.strokeWidth)
.attr('fill-opacity', config.fillOpacity) .attr('fill-opacity', config.fillOpacity)
.attr('fill', config.fillColor) .attr('fill', config.fillColor)
@ -45,14 +43,14 @@ export const renderPoint = <DataType extends Record<string, unknown>>(
const shape = ['hline', 'vline'].includes(config.shape) ? 'line' : config.shape const shape = ['hline', 'vline'].includes(config.shape) ? 'line' : config.shape
const currentPoints = getPointsRoot() const currentPoints = getPointsRoot(chart, embeded)
.selectAll(shape) .selectAll(shape)
.data(data.filter(chart.y)) .data(data.filter(chart.y))
currentPoints.exit().remove() currentPoints.exit().remove()
currentPoints.enter().append(shape) currentPoints.enter().append(shape)
const newPoints = getPointsRoot() const newPoints = getPointsRoot(chart, embeded)
.selectAll<d3.BaseType, DataType>(shape) .selectAll<d3.BaseType, DataType>(shape)
.transition() .transition()
.duration(chart.animDurationMs ?? 0) .duration(chart.animDurationMs ?? 0)

View File

@ -1,6 +1,8 @@
import { getByAccessor } from '@components/d3/functions' import { getByAccessor } from '@components/d3/functions'
import { ChartRegistry } from '@components/d3/types' import { ChartRegistry } from '@components/d3/types'
import { appendTransition } from './base'
export const renderRectArea = <DataType extends Record<string, any>>( export const renderRectArea = <DataType extends Record<string, any>>(
xAxis: (value: d3.NumberValue) => number, xAxis: (value: d3.NumberValue) => number,
yAxis: (value: d3.NumberValue) => number, yAxis: (value: d3.NumberValue) => number,
@ -28,8 +30,7 @@ export const renderRectArea = <DataType extends Record<string, any>>(
rects.exit().remove() rects.exit().remove()
rects.enter().append('rect') rects.enter().append('rect')
const actualRects = chart() appendTransition(chart().selectAll<SVGRectElement, Record<string, any>>('rect'), chart)
.selectAll<SVGRectElement, Record<string, any>>('rect')
.attr('x1', (d) => xAxis(xMin(d))) .attr('x1', (d) => xAxis(xMin(d)))
.attr('x2', (d) => xAxis(xMax(d))) .attr('x2', (d) => xAxis(xMax(d)))
.attr('y1', (d) => yAxis(yMin(d))) .attr('y1', (d) => yAxis(yMin(d)))