Skip to content

Commit fe932a2

Browse files
committed
refactor&feature:
(1) Uniform series data union logic; previous they are implemented in several inconsistent ways and error-prone. And also strict the extent calculation with uniformed utilities. (2) Refactor Scale - uniform the implementation of the numeric transformations (such as axis breaks, logarithm, ordinal related handling) with a decorator pattern and decouple them from Scale class hierarchy. This brings consistent handling for details and enables further extension. (3) Refactor Scale - decouple "axis nice" logic from Scale and make the "axis nice" and "axis align" implemented in the same code style. This removes override (hard to read and maintain), and uniforms the parameters of IntervalScale (previous its parameters can be generated by itself or outside, which is confusing), and reduce scale-type-specified handling (e.g., if (isLogScale) ...) in calculation. (4) Enable "value" axis and "log" axis to render "bar" and "pictorialBar" series without overflowing the axis. Previously only "time" axis enables that on only "bar" series. Introduce "SCALE_EXTENT_KIND_MAPPING" to cover this generalized behavior and use strict "clip" for bar series without extra margin (a previous compromise). And clarify `barGrid` code accordingly, which removes duplicated time-consuming calculation in "bandWidth" calculation. Close #19972. Close #17858. Close #12720. Close #13321. Close #20718. Close #20421. Close #20503.
1 parent 64305a4 commit fe932a2

53 files changed

Lines changed: 3987 additions & 1973 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/chart/bar/BarView.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ function getClipArea(coord: CoordSysOfBar, data: SeriesData) {
9696
const coordSysClipArea = coord.getArea && coord.getArea();
9797
if (isCoordinateSystemType<Cartesian2D>(coord, 'cartesian2d')) {
9898
const baseAxis = coord.getBaseAxis();
99-
// When boundaryGap is false or using time axis. bar may exceed the grid.
99+
// When boundaryGap is false in category axis, bar may exceed the grid.
100100
// We should not clip this part.
101101
// See test/bar2.html
102-
if (baseAxis.type !== 'category' || !baseAxis.onBand) {
102+
if (baseAxis.type === 'category' && !baseAxis.onBand) {
103103
const expandWidth = data.getLayout('bandWidth');
104104
if (baseAxis.isHorizontal()) {
105105
(coordSysClipArea as CartesianCoordArea).x -= expandWidth;
@@ -225,6 +225,7 @@ class BarView extends ChartView {
225225
group.removeClipPath();
226226
// We don't use clipPath in normal mode because we needs a perfect animation
227227
// And don't want the label are clipped.
228+
// Instead, `Clipper` is used in normal mode.
228229

229230
const roundCap = seriesModel.get('roundCap', true);
230231

src/chart/bar/install.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import { EChartsExtensionInstallRegisters } from '../../extension';
2121
import * as zrUtil from 'zrender/src/core/util';
22-
import {layout, createProgressiveLayout} from '../../layout/barGrid';
22+
import {layout, createProgressiveLayout, registerBarGridAxisContainShapeHandler} from '../../layout/barGrid';
2323
import dataSample from '../../processor/dataSample';
2424

2525
import BarSeries from './BarSeries';
@@ -67,4 +67,5 @@ export function install(registers: EChartsExtensionInstallRegisters) {
6767
);
6868
});
6969

70+
registerBarGridAxisContainShapeHandler(registers);
7071
}

src/chart/bar/installPictorialBar.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import { EChartsExtensionInstallRegisters } from '../../extension';
2121
import PictorialBarView from './PictorialBarView';
2222
import PictorialBarSeriesModel from './PictorialBarSeries';
23-
import { createProgressiveLayout, layout } from '../../layout/barGrid';
23+
import { createProgressiveLayout, layout, registerBarGridAxisContainShapeHandler } from '../../layout/barGrid';
2424
import { curry } from 'zrender/src/core/util';
2525

2626
export function install(registers: EChartsExtensionInstallRegisters) {
@@ -30,4 +30,6 @@ export function install(registers: EChartsExtensionInstallRegisters) {
3030
registers.registerLayout(registers.PRIORITY.VISUAL.LAYOUT, curry(layout, 'pictorialBar'));
3131
// Do layout after other overall layout, which can prepare some information.
3232
registers.registerLayout(registers.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, createProgressiveLayout('pictorialBar'));
33+
34+
registerBarGridAxisContainShapeHandler(registers);
3335
}

src/chart/custom/CustomSeries.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import Displayable from 'zrender/src/graphic/Displayable';
2121
import { ImageProps, ImageStyleProps } from 'zrender/src/graphic/Image';
2222
import { PathProps, PathStyleProps } from 'zrender/src/graphic/Path';
2323
import { ZRenderType } from 'zrender/src/zrender';
24-
import { BarGridLayoutOptionForCustomSeries, BarGridLayoutResult } from '../../layout/barGrid';
24+
import {
25+
BarGridLayoutOptionForCustomSeries,
26+
BarGridLayoutResultForCustomSeries
27+
} from '../../layout/barGrid';
2528
import {
2629
AnimationOption,
2730
BlurScope,
@@ -296,7 +299,7 @@ export interface CustomSeriesRenderItemAPI extends
296299
): VT extends NonStyleVisualProps ? DefaultDataVisual[VT]
297300
: VT extends StyleVisualProps ? PathStyleProps[typeof STYLE_VISUAL_TYPE[VT]]
298301
: void;
299-
barLayout(opt: BarGridLayoutOptionForCustomSeries): BarGridLayoutResult;
302+
barLayout(opt: BarGridLayoutOptionForCustomSeries): BarGridLayoutResultForCustomSeries;
300303
currentSeriesIndices(): number[];
301304
font(opt: Pick<TextCommonOption, 'fontStyle' | 'fontWeight' | 'fontSize' | 'fontFamily'>): string;
302305
}

src/chart/custom/CustomView.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import * as graphicUtil from '../../util/graphic';
2525
import { setDefaultStateProxy, toggleHoverEmphasis } from '../../util/states';
2626
import * as labelStyleHelper from '../../label/labelStyle';
2727
import {getDefaultLabel} from '../helper/labelHelper';
28-
import {getLayoutOnAxis} from '../../layout/barGrid';
28+
import {
29+
BarGridLayoutOptionForCustomSeries, BarGridLayoutResultForCustomSeries,
30+
getLayoutOnAxis
31+
} from '../../layout/barGrid';
2932
import DataDiffer from '../../data/DataDiffer';
3033
import Model from '../../model/Model';
3134
import ChartView from '../../view/Chart';
@@ -43,7 +46,7 @@ import {
4346
ECElement,
4447
DisplayStateNonNormal,
4548
OrdinalRawValue,
46-
InnerDecalObject
49+
InnerDecalObject,
4750
} from '../../util/types';
4851
import Element, { ElementTextConfig } from 'zrender/src/Element';
4952
import prepareCartesian2d from '../../coord/cartesian/prepareCustom';
@@ -90,7 +93,8 @@ import CustomSeriesModel, {
9093
CustomPathOption,
9194
CustomRootElementOption,
9295
CustomSeriesOption,
93-
CustomCompoundPathOption
96+
CustomCompoundPathOption,
97+
CustomSeriesRenderItemCoordinateSystemAPI
9498
} from './CustomSeries';
9599
import { PatternObject } from 'zrender/src/graphic/Pattern';
96100
import {
@@ -916,8 +920,8 @@ function makeRenderItem(
916920
* @return If not support, return undefined.
917921
*/
918922
function barLayout(
919-
opt: Omit<Parameters<typeof getLayoutOnAxis>[0], 'axis'>
920-
): ReturnType<typeof getLayoutOnAxis> {
923+
opt: BarGridLayoutOptionForCustomSeries
924+
): BarGridLayoutResultForCustomSeries {
921925
if (coordSys.type === 'cartesian2d') {
922926
const baseAxis = coordSys.getBaseAxis() as Axis2D;
923927
return getLayoutOnAxis(defaults({axis: baseAxis}, opt));

src/chart/heatmap/HeatmapView.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,10 @@ class HeatmapView extends ChartView {
241241
if (isNaN(data.get(dataDims[2], idx) as number)
242242
|| isNaN(dataDimX as number)
243243
|| isNaN(dataDimY as number)
244-
|| dataDimX < xAxisExtent[0]
245-
|| dataDimX > xAxisExtent[1]
246-
|| dataDimY < yAxisExtent[0]
247-
|| dataDimY > yAxisExtent[1]
244+
|| (dataDimX as number) < xAxisExtent[0]
245+
|| (dataDimX as number) > xAxisExtent[1]
246+
|| (dataDimY as number) < yAxisExtent[0]
247+
|| (dataDimY as number) > yAxisExtent[1]
248248
) {
249249
continue;
250250
}

src/chart/line/LineView.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ function xyExtentFromPoints(points: ArrayLike<number>) {
9292
const x = points[i++];
9393
const y = points[i++];
9494
if (!isPointIllegal(x, y)) {
95-
modelUtil.unionExtent(xExtent, x);
96-
modelUtil.unionExtent(yExtent, y);
95+
modelUtil.unionExtentFromNumber(xExtent, x);
96+
modelUtil.unionExtentFromNumber(yExtent, y);
9797
}
9898
}
9999
return [xExtent, yExtent];

src/component/axis/AxisBuilder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import ExtensionAPI from '../../core/ExtensionAPI';
6565
import { makeInner } from '../../util/model';
6666
import { getAxisBreakHelper } from './axisBreakHelper';
6767
import { AXIS_BREAK_EXPAND_ACTION_TYPE, BaseAxisBreakPayload } from './axisAction';
68-
import { getScaleBreakHelper } from '../../scale/break';
68+
import { getScaleBreakHelper, hasBreaks } from '../../scale/break';
6969
import BoundingRect from 'zrender/src/core/BoundingRect';
7070
import Point from 'zrender/src/core/Point';
7171
import { copyTransform } from 'zrender/src/core/Transformable';
@@ -709,7 +709,7 @@ const builders: Record<AxisBuilderAxisPartName, AxisElementsBuilder> = {
709709
style: lineStyle,
710710
};
711711

712-
if (axisModel.get(['axisLine', 'breakLine']) && axisModel.axis.scale.hasBreaks()) {
712+
if (axisModel.get(['axisLine', 'breakLine']) && hasBreaks(axisModel.axis.scale)) {
713713
getAxisBreakHelper()!.buildAxisBreakLine(axisModel, group, transformGroup, pathBaseProp);
714714
}
715715
else {

src/component/axisPointer/modelHelper.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,7 @@ export function fixValue(axisModel: AxisBaseModel) {
373373
option.status = useHandle ? 'show' : 'hide';
374374
}
375375

376-
const extent = scale.getExtent().slice();
377-
extent[0] > extent[1] && extent.reverse();
376+
const extent = scale.getExtent();
378377

379378
if (// Pick a value on axis when initializing.
380379
value == null

src/component/dataZoom/AxisProxy.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ import { Dictionary, NullUndefined } from '../../util/types';
3030
import DataZoomModel from './DataZoomModel';
3131
import { AxisBaseModel } from '../../coord/AxisBaseModel';
3232
import { getAxisMainType, isCoordSupported, DataZoomAxisDimension } from './helper';
33-
import { initExtentForUnion, SINGLE_REFERRING } from '../../util/model';
33+
import { SINGLE_REFERRING } from '../../util/model';
3434
import { isOrdinalScale, isTimeScale } from '../../scale/helper';
35-
import { AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM, axisExtentInfoFinalBuild, ensureScaleRawExtentInfo } from '../../coord/scaleRawExtentInfo';
35+
import {
36+
AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM, scaleRawExtentInfoReallyCreate,
37+
} from '../../coord/scaleRawExtentInfo';
3638

3739

3840
interface MinMaxSpan {
@@ -69,7 +71,7 @@ class AxisProxy {
6971

7072
private _window: AxisProxyWindow;
7173

72-
private _dataExtent: [number, number];
74+
private _dataExtent: number[];
7375

7476
private _minMaxSpan: MinMaxSpan;
7577

@@ -260,7 +262,7 @@ class AxisProxy {
260262
const pxSpan = mathAbs(pxExtent[1] - pxExtent[0]);
261263
const precision = isScaleOrdinalOrTime
262264
? 0
263-
: getAcceptableTickPrecision(valueWindow[1] - valueWindow[0], pxSpan, 0.5);
265+
: getAcceptableTickPrecision(valueWindow, pxSpan, 0.5);
264266
each([[0, mathCeil], [1, mathFloor]] as const, function ([idx, ceilOrFloor]) {
265267
if (!needRound[idx] || !isFinite(precision)) {
266268
return;
@@ -320,10 +322,10 @@ class AxisProxy {
320322
// Nevertheless, user can set min/max/scale on axes to make extent of axes
321323
// consistent.
322324
const axis = this.getAxisModel().axis;
323-
axisExtentInfoFinalBuild(this.ecModel, axis, AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM);
324-
const rawExtentInfo = ensureScaleRawExtentInfo(axis)
325-
const rawExtentResult = rawExtentInfo.calculate();
326-
this._dataExtent = [rawExtentResult.min, rawExtentResult.max];
325+
scaleRawExtentInfoReallyCreate(this.ecModel, axis, AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM);
326+
327+
const rawExtentInfo = axis.scale.rawExtentInfo;
328+
this._dataExtent = rawExtentInfo.makeForZoom();
327329

328330
// `calculateDataWindow` uses min/maxSpan.
329331
this._updateMinMaxSpan();
@@ -342,10 +344,10 @@ class AxisProxy {
342344
// `axisHelper.getScaleExtent`. But the different just affects the experience a
343345
// little when zooming. So it will not be fixed until some users require it strongly.
344346
if (percent[0] !== 0) {
345-
rawExtentInfo.setDeterminedMinMax('min', value[0]);
347+
rawExtentInfo.setZoomMinMax(0, value[0]);
346348
}
347349
if (percent[1] !== 100) {
348-
rawExtentInfo.setDeterminedMinMax('max', value[1]);
350+
rawExtentInfo.setZoomMinMax(1, value[1]);
349351
}
350352
}
351353

0 commit comments

Comments
 (0)