This is an automated email from the ASF dual-hosted git repository. sushuang pushed a commit to branch pr-21325 in repository https://gitbox.apache.org/repos/asf/echarts.git
commit f94f2214f637fe5a680519c0ee2f606424d27432 Author: 100pah <[email protected]> AuthorDate: Thu Oct 30 15:41:22 2025 +0800 fix: (1) priority of defaults by layout and axis types. (2) init animation. --- src/chart/boxplot/BoxplotView.ts | 2 +- src/chart/boxplot/boxplotLayout.ts | 2 +- src/chart/candlestick/CandlestickSeries.ts | 4 +++ src/chart/candlestick/CandlestickView.ts | 27 +++++++++++++----- src/chart/candlestick/candlestickLayout.ts | 3 +- src/chart/helper/whiskerBoxCommon.ts | 45 +++++++++++++++++++----------- test/candlestick-horizontal.html | 23 ++++++++++++++- 7 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/chart/boxplot/BoxplotView.ts b/src/chart/boxplot/BoxplotView.ts index f48cdf67b..0d8830977 100644 --- a/src/chart/boxplot/BoxplotView.ts +++ b/src/chart/boxplot/BoxplotView.ts @@ -46,7 +46,7 @@ class BoxplotView extends ChartView { group.removeAll(); } - const constDim = seriesModel.get('layout') === 'horizontal' ? 1 : 0; + const constDim = seriesModel.getWhiskerBoxesLayout() === 'horizontal' ? 1 : 0; data.diff(oldData) .add(function (newIdx) { diff --git a/src/chart/boxplot/boxplotLayout.ts b/src/chart/boxplot/boxplotLayout.ts index cf6017b3c..053462d2f 100644 --- a/src/chart/boxplot/boxplotLayout.ts +++ b/src/chart/boxplot/boxplotLayout.ts @@ -144,7 +144,7 @@ function layoutSingleSeries(seriesModel: BoxplotSeriesModel, offset: number, box const coordSys = seriesModel.coordinateSystem; const data = seriesModel.getData(); const halfWidth = boxWidth / 2; - const cDimIdx = seriesModel.get('layout') === 'horizontal' ? 0 : 1; + const cDimIdx = seriesModel.getWhiskerBoxesLayout() === 'horizontal' ? 0 : 1; const vDimIdx = 1 - cDimIdx; const coordDims = ['x', 'y']; const cDim = data.mapDimension(coordDims[cDimIdx]); diff --git a/src/chart/candlestick/CandlestickSeries.ts b/src/chart/candlestick/CandlestickSeries.ts index f152fce2c..55938e3b4 100644 --- a/src/chart/candlestick/CandlestickSeries.ts +++ b/src/chart/candlestick/CandlestickSeries.ts @@ -37,6 +37,7 @@ import SeriesData from '../../data/SeriesData'; import Cartesian2D from '../../coord/cartesian/Cartesian2D'; import { BrushCommonSelectorsForSeries } from '../../component/brush/selector'; import { mixin } from 'zrender/src/core/util'; +import type Axis2D from '../../coord/cartesian/Axis2D'; type CandlestickDataValue = OptionDataValue[]; @@ -158,6 +159,9 @@ class CandlestickSeriesModel extends SeriesModel<CandlestickSeriesOption> { } } +interface CandlestickSeriesModel extends WhiskerBoxCommonMixin<CandlestickSeriesOption> { + getBaseAxis(): Axis2D +} mixin(CandlestickSeriesModel, WhiskerBoxCommonMixin, true); export default CandlestickSeriesModel; diff --git a/src/chart/candlestick/CandlestickView.ts b/src/chart/candlestick/CandlestickView.ts index 728291424..706cae6fc 100644 --- a/src/chart/candlestick/CandlestickView.ts +++ b/src/chart/candlestick/CandlestickView.ts @@ -106,6 +106,8 @@ class CandlestickView extends ChartView { group.removeAll(); } + const transPointDim = getTransPointDimension(seriesModel); + data.diff(oldData) .add(function (newIdx) { if (data.hasValue(newIdx)) { @@ -115,7 +117,7 @@ class CandlestickView extends ChartView { return; } - const el = createNormalBox(itemLayout, newIdx, true); + const el = createNormalBox(itemLayout, newIdx, transPointDim, true); graphic.initProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx); setBoxCommon(el, data, newIdx, isSimpleBox); @@ -141,7 +143,7 @@ class CandlestickView extends ChartView { } if (!el) { - el = createNormalBox(itemLayout, newIdx); + el = createNormalBox(itemLayout, newIdx, transPointDim); } else { graphic.updateProps(el, { @@ -188,10 +190,12 @@ class CandlestickView extends ChartView { const data = seriesModel.getData(); const isSimpleBox = data.getLayout('isSimpleBox'); + const transPointDim = getTransPointDimension(seriesModel); + let dataIndex; while ((dataIndex = params.next()) != null) { const itemLayout = data.getItemLayout(dataIndex) as CandlestickItemLayout; - const el = createNormalBox(itemLayout, dataIndex); + const el = createNormalBox(itemLayout, dataIndex, transPointDim); setBoxCommon(el, data, dataIndex, isSimpleBox); el.incremental = true; @@ -262,12 +266,17 @@ class NormalBoxPath extends Path<NormalBoxPathProps> { } -function createNormalBox(itemLayout: CandlestickItemLayout, dataIndex: number, isInit?: boolean) { +function createNormalBox( + itemLayout: CandlestickItemLayout, + dataIndex: number, + constDim: number, + isInit?: boolean +) { const ends = itemLayout.ends; return new NormalBoxPath({ shape: { points: isInit - ? transInit(ends, itemLayout) + ? transInit(ends, constDim, itemLayout) : ends }, z2: 100 @@ -310,14 +319,18 @@ function setBoxCommon(el: NormalBoxPath, data: SeriesData, dataIndex: number, is toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); } -function transInit(points: number[][], itemLayout: CandlestickItemLayout) { +function transInit(points: number[][], dim: number, itemLayout: CandlestickItemLayout) { return zrUtil.map(points, function (point) { point = point.slice(); - point[1] = itemLayout.initBaseline; + point[dim] = itemLayout.initBaseline; return point; }); } +function getTransPointDimension(seriesModel: CandlestickSeriesModel): number { + return seriesModel.getWhiskerBoxesLayout() === 'horizontal' ? 1 : 0; +} + class LargeBoxPathShape { diff --git a/src/chart/candlestick/candlestickLayout.ts b/src/chart/candlestick/candlestickLayout.ts index 77e5c65d8..6b6fa03a6 100644 --- a/src/chart/candlestick/candlestickLayout.ts +++ b/src/chart/candlestick/candlestickLayout.ts @@ -51,8 +51,7 @@ const candlestickLayout: StageHandler = { const coordSys = seriesModel.coordinateSystem; const data = seriesModel.getData(); const candleWidth = calculateCandleWidth(seriesModel, data); - const layout = seriesModel.get('layout'); - const cDimIdx = layout === 'horizontal' ? 0 : 1; + const cDimIdx = seriesModel.getWhiskerBoxesLayout() === 'horizontal' ? 0 : 1; const vDimIdx = 1 - cDimIdx; const coordDims = ['x', 'y']; const cDimI = data.getDimensionIndex(data.mapDimension(coordDims[cDimIdx])); diff --git a/src/chart/helper/whiskerBoxCommon.ts b/src/chart/helper/whiskerBoxCommon.ts index 891a0dd69..294fd0eae 100644 --- a/src/chart/helper/whiskerBoxCommon.ts +++ b/src/chart/helper/whiskerBoxCommon.ts @@ -30,6 +30,9 @@ import type Axis2D from '../../coord/cartesian/Axis2D'; import { CoordDimensionDefinition } from '../../data/helper/createDimensions'; interface CommonOption extends SeriesOption, SeriesOnCartesianOptionMixin { + // - 'horizontal': Multiple whisker boxes (each drawn vertically) + // are arranged side by side horizontally. + // - 'vertical': The opposite. layout?: LayoutOrient // data?: (DataItemOption | number[])[] @@ -44,14 +47,15 @@ interface DataItemOption { interface WhiskerBoxCommonMixin<Opts extends CommonOption> extends SeriesModel<Opts>{} class WhiskerBoxCommonMixin<Opts extends CommonOption> { - /** - * @private - * @type {string} - */ - _baseAxisDim: string; + private _baseAxisDim: string; defaultValueDimensions: CoordDimensionDefinition['dimsDef']; + /** + * Computed layout. + */ + private _layout: CommonOption['layout']; + /** * @private */ @@ -76,28 +80,33 @@ class WhiskerBoxCommonMixin<Opts extends CommonOption> { const yAxisType = yAxisModel.get('type'); let addOrdinal; + // Theoretically, if `encode` and/or `layout` are not specified, they can be derived from + // the specified one (also according to axis types). However, only the logic for deriving + // `encode` from `layout` is implemented; the reverse direction is not implemented yet, + // due to its complexity and low priority. + let layout = option.layout; + // 'category' axis has historically been enforcing `layout` regardless of its presence. + // This behavior is preserved until it causes problems. if (xAxisType === 'category') { - option.layout = 'horizontal'; + layout = 'horizontal'; ordinalMeta = xAxisModel.getOrdinalMeta(); addOrdinal = !this._hasEncodeRule('x'); } else if (yAxisType === 'category') { - option.layout = 'vertical'; + layout = 'vertical'; ordinalMeta = yAxisModel.getOrdinalMeta(); addOrdinal = !this._hasEncodeRule('y'); } - else if (xAxisType === 'time') { - option.layout = 'horizontal'; - } - else if (yAxisType === 'time') { - option.layout = 'vertical'; - } - else { - option.layout = option.layout || 'horizontal'; + if (!layout) { + layout = yAxisType === 'time' ? 'vertical' : 'horizontal'; + // It is theoretically possible for an axis with type "time" to serve as the "value axis". + // `layout` can be explicitly specified for that case. } + // Do not assign the computed `layout` to `option.layout`, otherwise the idempotent may be broken. + this._layout = layout; const coordDims = ['x', 'y']; - const baseAxisDimIndex = option.layout === 'horizontal' ? 0 : 1; + const baseAxisDimIndex = layout === 'horizontal' ? 0 : 1; const baseAxisDim = this._baseAxisDim = coordDims[baseAxisDimIndex]; const otherAxisDim = coordDims[1 - baseAxisDimIndex]; const axisModels = [xAxisModel, yAxisModel]; @@ -169,6 +178,10 @@ class WhiskerBoxCommonMixin<Opts extends CommonOption> { ) as CartesianAxisModel).axis; } + getWhiskerBoxesLayout() { + return this._layout; + } + }; diff --git a/test/candlestick-horizontal.html b/test/candlestick-horizontal.html index 49bf05f88..bc5fb0db4 100644 --- a/test/candlestick-horizontal.html +++ b/test/candlestick-horizontal.html @@ -41,6 +41,7 @@ under the License. <div id="main6"></div> <div id="main7"></div> <div id="main8"></div> + <div id="main9"></div> <script> require(["echarts"], function (echarts) { @@ -69,7 +70,8 @@ under the License. xAxisType, yAxisType, encode, - data + data, + layout, ) { var itemStyle = chartType === "candlestick" @@ -101,6 +103,7 @@ under the License. type: chartType, encode: encode, data: data, + layout: layout, itemStyle: itemStyle, }, ], @@ -221,6 +224,24 @@ under the License. reversedaray ), }, + { + id: "main9", + title: "boxplot with dual time axes", + option: createChartOption( + "boxplot", + "time", + "time", + { y: [0, 1, 2, 3, 4], x: 5 }, + reversedaray.map(item => { + const newItem = item.slice(); + for (let i = 0; i < 5; i++) { + newItem[i] = new Date(newItem[i] + 1761804046510).toISOString(); + } + return newItem; + }), + 'horizontal' + ), + }, ]; // Create all charts --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
