forked from ddrilling/asb_cloud_front
Добавлен механизм автоматического скалирования графиков на группах вертикальных графиков
This commit is contained in:
parent
d5a7d947c6
commit
719180392e
@ -27,16 +27,32 @@ import D3MouseZone from './D3MouseZone'
|
||||
import { getByAccessor, getChartClass, getGroupClass, getTicks } from './functions'
|
||||
import { renderArea, renderLine, renderNeedle, renderPoint } from './renders'
|
||||
|
||||
const roundTo = (v: number, to: number = 50) => {
|
||||
if (to == 0) return v
|
||||
if (v < 0) return Math.round(v / to) * to
|
||||
return Math.ceil(v / to) * to
|
||||
}
|
||||
|
||||
const calculateDomain = (mm: MinMax, round: number = 100): Required<MinMax> => {
|
||||
let min = roundTo(mm.min ?? 0, round)
|
||||
let max = roundTo(mm.max ?? round, round)
|
||||
if (min - max < round) {
|
||||
const mid = (min + max) / 2
|
||||
min = mid - round
|
||||
max = mid + round
|
||||
}
|
||||
return { min, max }
|
||||
}
|
||||
|
||||
type AxisScale = d3.ScaleTime<number, number, never> | d3.ScaleLinear<number, number, never>
|
||||
|
||||
type ExtendedChartDataset<DataType> = ChartDataset<DataType> & {
|
||||
yDomain: MinMax
|
||||
xDomain: MinMax
|
||||
hideXAxis?: boolean
|
||||
}
|
||||
|
||||
type ExtendedChartRegistry<DataType> = ExtendedChartDataset<DataType> & {
|
||||
(): d3.Selection<SVGGElement, DataType, any, any>
|
||||
scale: d3.ScaleLinear<number, number>
|
||||
y: (value: any) => number
|
||||
x: (value: any) => number
|
||||
}
|
||||
@ -110,7 +126,7 @@ export type ChartSizes = ChartOffset & {
|
||||
}
|
||||
|
||||
const axisHeight = 20
|
||||
const space = 20
|
||||
const space = 30
|
||||
|
||||
const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
width: givenWidth = '100%',
|
||||
@ -188,6 +204,32 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
}
|
||||
), [chartArea, axesArea])
|
||||
|
||||
const chartDomains: Record<string, {
|
||||
scale: d3.ScaleLinear<number, number>,
|
||||
domain: Required<MinMax>,
|
||||
}>[] = useMemo(() => {
|
||||
return groups.map((group) => {
|
||||
const out = group.charts.map((chart) => {
|
||||
const mm = { ...chart.xDomain }
|
||||
let domain: Required<MinMax> = { min: 0, max: 100 }
|
||||
if (mm.min && mm.max) {
|
||||
domain = mm as Required<MinMax>
|
||||
} else if (data) {
|
||||
const [min, max] = d3.extent(data, chart.x)
|
||||
domain = calculateDomain({ min, max, ...mm }, 100)
|
||||
}
|
||||
return [chart.key, {
|
||||
scale: d3.scaleLinear().domain([domain.min, domain.max]),
|
||||
domain,
|
||||
}]
|
||||
})
|
||||
|
||||
return Object.fromEntries(out)
|
||||
})
|
||||
}, [groups, data])
|
||||
|
||||
console.log(chartDomains)
|
||||
|
||||
useEffect(() => {
|
||||
if (isDev()) {
|
||||
datasetGroups.forEach((sets, i) => {
|
||||
@ -228,15 +270,6 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
group.charts[chartIdx]().selectAll('*').remove()
|
||||
}
|
||||
|
||||
const yDomain = {
|
||||
min: 0,
|
||||
max: 10,
|
||||
...dataset.yDomain,
|
||||
}
|
||||
|
||||
const scale = d3.scaleLinear()
|
||||
.domain([yDomain.min, yDomain.max])
|
||||
|
||||
// Пересоздаём график
|
||||
const newChart: ExtendedChartRegistry<DataType> = Object.assign(
|
||||
() => group().select('.' + getChartClass(dataset.key)) as d3.Selection<SVGGElement, DataType, any, unknown>,
|
||||
@ -248,8 +281,6 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
animDurationMs,
|
||||
...dataset,
|
||||
yAxis: dataset.yAxis ?? yAxisConfig,
|
||||
yDomain,
|
||||
scale,
|
||||
y: getByAccessor(dataset.yAxis.accessor ?? yAxisConfig.accessor),
|
||||
x: getByAccessor(dataset.xAxis?.accessor),
|
||||
}
|
||||
@ -288,7 +319,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
.attr('class', (g) => `charts-group ${getGroupClass(g.key)}`)
|
||||
.attr('transform', (g) => `translate(${sizes.groupLeft(g.key)}, 0)`)
|
||||
|
||||
actualAxesGroups.each(function(group) {
|
||||
actualAxesGroups.each(function(group, i) {
|
||||
const groupAxes = d3.select(this)
|
||||
const chartsData = group.charts.filter((chart) => !chart.hideXAxis)
|
||||
const charts = groupAxes.selectChildren().data(chartsData)
|
||||
@ -302,17 +333,18 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
.style('color', (d) => d.color ?? null)
|
||||
|
||||
actualCharts.each(function (chart, j) {
|
||||
let axis = d3.axisTop(chart.scale.range([0, sizes.groupWidth]))
|
||||
let axis = d3.axisTop(chartDomains[i][chart.key].scale.range([0, sizes.groupWidth]))
|
||||
const domain = chartDomains[i][chart.key].domain
|
||||
|
||||
if (j === chartsData.length - 1) {
|
||||
axis = axis
|
||||
.ticks(5)
|
||||
.tickSize(-sizes.chartsHeight)
|
||||
.tickFormat((d, i) => i === 0 || i === 5 ? String(d) : '')
|
||||
.tickValues(getTicks(chart.yDomain, 5))
|
||||
.tickValues(getTicks(domain, 5))
|
||||
} else {
|
||||
axis = axis.ticks(1)
|
||||
.tickValues(getTicks(chart.yDomain, 1))
|
||||
.tickValues(getTicks(domain, 1))
|
||||
}
|
||||
|
||||
d3.select(this).call(axis as any)
|
||||
@ -335,7 +367,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
.attr('stroke', j === chartsData.length - 1 ? 'gray' : 'currentColor')
|
||||
})
|
||||
})
|
||||
}, [groups, groupScales, sizes, space])
|
||||
}, [groups, groupScales, sizes, space, chartDomains])
|
||||
|
||||
useEffect(() => { // Рисуем ось Y
|
||||
if (!yAxis) return
|
||||
@ -361,7 +393,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
useEffect(() => {
|
||||
if (!data || !yAxis) return
|
||||
|
||||
groups.forEach((group) => {
|
||||
groups.forEach((group, i) => {
|
||||
group()
|
||||
.attr('transform', `translate(${sizes.groupLeft(group.key)}, 0)`)
|
||||
.attr('clip-path', `url(#chart-clip)`)
|
||||
@ -377,7 +409,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
let chartData = data
|
||||
if (!chartData) return
|
||||
|
||||
const xAxis = chart.scale.range([0, sizes.groupWidth])
|
||||
const xAxis = chartDomains[i][chart.key].scale.range([0, sizes.groupWidth])
|
||||
|
||||
switch (chart.type) {
|
||||
case 'needle':
|
||||
@ -397,12 +429,12 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
||||
}
|
||||
|
||||
if (chart.point)
|
||||
renderPoint<DataType>(chart.scale, yAxis, chart, chartData, true)
|
||||
renderPoint<DataType>(xAxis, yAxis, chart, chartData, true)
|
||||
|
||||
chart.afterDraw?.(chart)
|
||||
})
|
||||
})
|
||||
}, [data, groups, groupScales, height, offset, sizes])
|
||||
}, [data, groups, groupScales, height, offset, sizes, chartDomains])
|
||||
|
||||
return (
|
||||
<LoaderPortal
|
||||
|
Loading…
Reference in New Issue
Block a user