diff --git a/core/core-frontend/src/views/chart/components/js/formatter.ts b/core/core-frontend/src/views/chart/components/js/formatter.ts index 1fef635612..81ea49521f 100644 --- a/core/core-frontend/src/views/chart/components/js/formatter.ts +++ b/core/core-frontend/src/views/chart/components/js/formatter.ts @@ -158,3 +158,26 @@ function transSeparatorAndSuffix(value, formatter) { } return str + formatter.suffix.replace(/(^\s*)|(\s*$)/g, '') } + +/** + * 根据最小值、最大值max和刻度数量tickCount + * 计算一个nice最小刻度值 + * @param min + * @param max + * @param tickCount + */ +export const niceMin = (min, max, tickCount = 5) => { + // 数据的总跨度 + const range = max - min + // 将范围均分为 tickCount-1 份, 得到每份的粗略步长 + const roughStep = range / (tickCount - 1) + // 确定步长的数量级 + // 取步长的 10 为底的对数,向下取整,得到步长的数量级 + const exponent = Math.floor(Math.log10(roughStep)) + // 将步长取整到nice的倍数(如 1, 2, 5, 10, 20, 50...) + const power = Math.pow(10, exponent) + // 从中找出第一个大于等于粗略步长的nice步长 + const niceStep = [1, 2, 5, 10].map(mult => mult * power).find(step => step >= roughStep) + // 将 min 向下取整到 niceStep 的整数倍,得到一个更整齐的起始值 + return Math.floor(min / niceStep) * niceStep +} diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts index b6bd598f5d..673766731f 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts @@ -19,7 +19,7 @@ import { parseJson, setUpStackSeriesColor } from '@/views/chart/components/js/util' -import { valueFormatter } from '@/views/chart/components/js/formatter' +import { niceMin, valueFormatter } from '@/views/chart/components/js/formatter' import { LINE_AXIS_TYPE, LINE_EDITOR_PROPERTY, @@ -126,6 +126,30 @@ export class Area extends G2PlotChartView { newChart.on('point:click', action) extremumEvt(newChart, chart, options, container) configPlotTooltipEvent(chart, newChart) + const yAxis = parseJson(chart.customStyle).yAxis + if (yAxis.axisValue?.auto) { + newChart.on('legend-item-group:click', e => { + if (e.view?.options?.scales) { + const values = e.view.filteredData + .map(d => d.value) + ?.filter(v => v !== null && v !== undefined) + const min = Math.min(...values) + const max = Math.max(...values) + e.view.options.scales.value.min = niceMin(min, max) + e.view.render(true) + } + }) + newChart.on('slider:valuechanged', ev => { + const values = ev.view.filteredData + .map(d => d.value) + ?.filter(v => v !== null && v !== undefined) + const min = Math.min(...values) + const max = Math.max(...values) + if (max !== min) { + ev.view.options.scales.value.min = niceMin(min, max) + } + }) + } return newChart } @@ -270,6 +294,20 @@ export class Area extends G2PlotChartView { } return { ...tmpOptions, ...axis } } + if (axisValue?.auto) { + const data = options.data || [] + const values = data.map(d => d.value)?.filter(v => v !== null && v !== undefined) + const min = Math.min(...values) + const max = Math.max(...values) + const niceMinValue = niceMin(min, max) + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: niceMinValue + } + } + return { ...tmpOptions, ...axis } + } return tmpOptions } diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts index ae8b45d9a0..e7282f957f 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/line/line.ts @@ -20,7 +20,7 @@ import { setUpGroupSeriesColor } from '@/views/chart/components/js/util' import { cloneDeep, defaults, isEmpty } from 'lodash-es' -import { valueFormatter } from '@/views/chart/components/js/formatter' +import { niceMin, valueFormatter } from '@/views/chart/components/js/formatter' import { LINE_AXIS_TYPE, LINE_EDITOR_PROPERTY, @@ -34,6 +34,7 @@ import { Group } from '@antv/g-canvas' const { t } = useI18n() const DEFAULT_DATA = [] + /** * 折线图 */ @@ -68,6 +69,7 @@ export class Line extends G2PlotChartView { type: 'q' } } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, action, container } = drawOptions chart.container = container @@ -128,6 +130,30 @@ export class Line extends G2PlotChartView { newChart.on('point:click', action) extremumEvt(newChart, chart, options, container) configPlotTooltipEvent(chart, newChart) + const yAxis = parseJson(chart.customStyle).yAxis + if (yAxis.axisValue?.auto) { + newChart.on('legend-item-group:click', e => { + if (e.view?.options?.scales) { + const values = e.view.filteredData + .map(d => d.value) + ?.filter(v => v !== null && v !== undefined) + const min = Math.min(...values) + const max = Math.max(...values) + e.view.options.scales.value.min = niceMin(min, max) + e.view.render(true) + } + }) + newChart.on('slider:valuechanged', ev => { + const values = ev.view.filteredData + .map(d => d.value) + ?.filter(v => v !== null && v !== undefined) + const min = Math.min(...values) + const max = Math.max(...values) + if (max !== min) { + ev.view.options.scales.value.min = niceMin(min, max) + } + }) + } return newChart } @@ -249,6 +275,20 @@ export class Line extends G2PlotChartView { } return { ...tmpOptions, ...axis } } + if (axisValue?.auto) { + const data = options.data || [] + const values = data.map(d => d.value)?.filter(v => v !== null && v !== undefined) + const min = Math.min(...values) + const max = Math.max(...values) + const niceMinValue = niceMin(min, max) + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: niceMinValue + } + } + return { ...tmpOptions, ...axis } + } return tmpOptions } @@ -310,9 +350,11 @@ export class Line extends G2PlotChartView { tooltip } } + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { return setUpGroupSeriesColor(chart, data) } + protected configLegend(chart: Chart, options: LineOptions): LineOptions { const optionTmp = super.configLegend(chart, options) if (!optionTmp.legend) { @@ -420,6 +462,7 @@ export class Line extends G2PlotChartView { } return optionTmp } + protected setupOptions(chart: Chart, options: LineOptions): LineOptions { return flow( this.configTheme,