You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by ov...@apache.org on 2024/01/02 11:10:40 UTC

(echarts) branch feat/break-axis updated: feat(WIP): axis with break

This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a commit to branch feat/break-axis
in repository https://gitbox.apache.org/repos/asf/echarts.git


The following commit(s) were added to refs/heads/feat/break-axis by this push:
     new d1c0f2a5a feat(WIP): axis with break
d1c0f2a5a is described below

commit d1c0f2a5a0385f75369318dff101bb8d4e715776
Author: Ovilia <zw...@gmail.com>
AuthorDate: Tue Jan 2 19:10:15 2024 +0800

    feat(WIP): axis with break
---
 src/coord/axisCommonTypes.ts |  3 ++-
 src/coord/axisHelper.ts      | 10 +++++---
 src/scale/Interval.ts        |  4 ++--
 src/scale/Log.ts             |  4 ++--
 src/scale/Ordinal.ts         |  9 +++++---
 src/scale/Scale.ts           | 12 +++++++++-
 src/scale/Time.ts            |  7 +++---
 src/scale/helper.ts          | 55 ++++++++++++++++++++++++++++++++++++++++----
 src/util/types.ts            |  6 +++++
 9 files changed, 91 insertions(+), 19 deletions(-)

diff --git a/src/coord/axisCommonTypes.ts b/src/coord/axisCommonTypes.ts
index aa92868e3..728c10a7e 100644
--- a/src/coord/axisCommonTypes.ts
+++ b/src/coord/axisCommonTypes.ts
@@ -21,7 +21,7 @@ import { TextAlign, TextVerticalAlign } from 'zrender/src/core/types';
 import {
     TextCommonOption, LineStyleOption, OrdinalRawValue, ZRColor,
     AreaStyleOption, ComponentOption, ColorString,
-    AnimationOptionMixin, Dictionary, ScaleDataValue, CommonAxisPointerOption
+    AnimationOptionMixin, Dictionary, ScaleDataValue, CommonAxisPointerOption, ScaleBreak
 } from '../util/types';
 import { TextStyleProps } from 'zrender/src/graphic/Text';
 
@@ -81,6 +81,7 @@ export interface AxisBaseOptionCommon extends ComponentOption,
      */
     max?: ScaleDataValue | 'dataMax' | ((extent: {min: number, max: number}) => ScaleDataValue);
 
+    breaks?: ScaleBreak[];
 }
 
 export interface NumericAxisBaseOptionCommon extends AxisBaseOptionCommon {
diff --git a/src/coord/axisHelper.ts b/src/coord/axisHelper.ts
index 53485fb31..76c23ad17 100644
--- a/src/coord/axisHelper.ts
+++ b/src/coord/axisHelper.ts
@@ -198,16 +198,20 @@ export function createScaleByModel(model: AxisBaseModel, axisType?: string): Sca
                     ordinalMeta: model.getOrdinalMeta
                         ? model.getOrdinalMeta()
                         : model.getCategories(),
-                    extent: [Infinity, -Infinity]
+                    extent: [Infinity, -Infinity],
+                    breaks: model.get('breaks')
                 });
             case 'time':
                 return new TimeScale({
                     locale: model.ecModel.getLocaleModel(),
-                    useUTC: model.ecModel.get('useUTC')
+                    useUTC: model.ecModel.get('useUTC'),
+                    breaks: model.get('breaks')
                 });
             default:
                 // case 'value'/'interval', 'log', or others.
-                return new (Scale.getClass(axisType) || IntervalScale)();
+                return new (Scale.getClass(axisType) || IntervalScale)({
+                    breaks: model.get('breaks')
+                });
         }
     }
 }
diff --git a/src/scale/Interval.ts b/src/scale/Interval.ts
index 3fc00cf14..f250b9801 100644
--- a/src/scale/Interval.ts
+++ b/src/scale/Interval.ts
@@ -46,11 +46,11 @@ class IntervalScale<SETTING extends Dictionary<unknown> = Dictionary<unknown>> e
     }
 
     normalize(val: number): number {
-        return helper.normalize(val, this._extent);
+        return helper.normalize(val, this._extent, this._breaks);
     }
 
     scale(val: number): number {
-        return helper.scale(val, this._extent);
+        return helper.scale(val, this._extent, this._breaks);
     }
 
     setExtent(start: number | string, end: number | string): void {
diff --git a/src/scale/Log.ts b/src/scale/Log.ts
index b1f4d08b1..536e114fc 100644
--- a/src/scale/Log.ts
+++ b/src/scale/Log.ts
@@ -183,11 +183,11 @@ class LogScale extends Scale {
 
     normalize(val: number): number {
         val = mathLog(val) / mathLog(this.base);
-        return scaleHelper.normalize(val, this._extent);
+        return scaleHelper.normalize(val, this._extent, this._breaks);
     }
 
     scale(val: number): number {
-        val = scaleHelper.scale(val, this._extent);
+        val = scaleHelper.scale(val, this._extent, this._breaks);
         return mathPow(this.base, val);
     }
 
diff --git a/src/scale/Ordinal.ts b/src/scale/Ordinal.ts
index dd7d255c8..29f557c20 100644
--- a/src/scale/Ordinal.ts
+++ b/src/scale/Ordinal.ts
@@ -34,7 +34,8 @@ import {
     DimensionLoose,
     OrdinalSortInfo,
     OrdinalScaleTick,
-    ScaleTick
+    ScaleTick,
+    ScaleBreak
 } from '../util/types';
 import { CategoryAxisBaseOption } from '../coord/axisCommonTypes';
 import { isArray, map, isObject, isString } from 'zrender/src/core/util';
@@ -42,6 +43,7 @@ import { isArray, map, isObject, isString } from 'zrender/src/core/util';
 type OrdinalScaleSetting = {
     ordinalMeta?: OrdinalMeta | CategoryAxisBaseOption['data'];
     extent?: [number, number];
+    breaks?: ScaleBreak[];
 };
 
 class OrdinalScale extends Scale<OrdinalScaleSetting> {
@@ -127,6 +129,7 @@ class OrdinalScale extends Scale<OrdinalScaleSetting> {
         }
         this._ordinalMeta = ordinalMeta as OrdinalMeta;
         this._extent = this.getSetting('extent') || [0, ordinalMeta.categories.length - 1];
+        this._breaks = this.getSetting('breaks') || [];
     }
 
     parse(val: OrdinalRawValue | OrdinalNumber): OrdinalNumber {
@@ -153,7 +156,7 @@ class OrdinalScale extends Scale<OrdinalScaleSetting> {
      */
     normalize(val: OrdinalRawValue | OrdinalNumber): number {
         val = this._getTickNumber(this.parse(val));
-        return scaleHelper.normalize(val, this._extent);
+        return scaleHelper.normalize(val, this._extent, this._breaks);
     }
 
     /**
@@ -161,7 +164,7 @@ class OrdinalScale extends Scale<OrdinalScaleSetting> {
      * @return raw ordinal number.
      */
     scale(val: number): OrdinalNumber {
-        val = Math.round(scaleHelper.scale(val, this._extent));
+        val = Math.round(scaleHelper.scale(val, this._extent, this._breaks));
         return this.getRawOrdinalNumber(val);
     }
 
diff --git a/src/scale/Scale.ts b/src/scale/Scale.ts
index 143f4c9b7..bb0e2ff0c 100644
--- a/src/scale/Scale.ts
+++ b/src/scale/Scale.ts
@@ -26,8 +26,10 @@ import {
     ScaleDataValue,
     OptionDataValue,
     DimensionLoose,
-    ScaleTick
+    ScaleTick,
+    ScaleBreak
 } from '../util/types';
+import { getExtentSpanWithoutBreaks } from './helper';
 import { ScaleRawExtentInfo } from '../coord/scaleRawExtentInfo';
 
 
@@ -38,6 +40,7 @@ abstract class Scale<SETTING extends Dictionary<unknown> = Dictionary<unknown>>
     private _setting: SETTING;
 
     protected _extent: [number, number];
+    protected _breaks: ScaleBreak[];
 
     private _isBlank: boolean;
 
@@ -47,6 +50,7 @@ abstract class Scale<SETTING extends Dictionary<unknown> = Dictionary<unknown>>
     constructor(setting?: SETTING) {
         this._setting = setting || {} as SETTING;
         this._extent = [Infinity, -Infinity];
+        this._breaks = this._setting.breaks as ScaleBreak[] || [];
     }
 
     getSetting<KEY extends keyof SETTING>(name: KEY): SETTING[KEY] {
@@ -117,6 +121,12 @@ abstract class Scale<SETTING extends Dictionary<unknown> = Dictionary<unknown>>
         }
     }
 
+    getBrokenExtentRatio(): number {
+        const realSpan = getExtentSpanWithoutBreaks(this._extent, this._breaks);
+        const totalSpan = this._extent[1] - this._extent[0];
+        return totalSpan === 0 ? 1 : realSpan / totalSpan;
+    }
+
     /**
      * If value is in extent range
      */
diff --git a/src/scale/Time.ts b/src/scale/Time.ts
index 2458490b2..b575fd0e8 100644
--- a/src/scale/Time.ts
+++ b/src/scale/Time.ts
@@ -73,7 +73,7 @@ import {
 import * as scaleHelper from './helper';
 import IntervalScale from './Interval';
 import Scale from './Scale';
-import {TimeScaleTick, ScaleTick} from '../util/types';
+import {TimeScaleTick, ScaleTick, ScaleBreak} from '../util/types';
 import {TimeAxisLabelFormatterOption} from '../coord/axisCommonTypes';
 import { warn } from '../util/log';
 import { LocaleOption } from '../core/locale';
@@ -102,6 +102,7 @@ const bisect = function (
 type TimeScaleSetting = {
     locale: Model<LocaleOption>;
     useUTC: boolean;
+    breaks?: ScaleBreak[];
 };
 
 class TimeScale extends IntervalScale<TimeScaleSetting> {
@@ -242,11 +243,11 @@ class TimeScale extends IntervalScale<TimeScaleSetting> {
     }
 
     normalize(val: number): number {
-        return scaleHelper.normalize(this.parse(val), this._extent);
+        return scaleHelper.normalize(this.parse(val), this._extent, this._breaks);
     }
 
     scale(val: number): number {
-        return scaleHelper.scale(val, this._extent);
+        return scaleHelper.scale(val, this._extent, this._breaks);
     }
 
 }
diff --git a/src/scale/helper.ts b/src/scale/helper.ts
index 3302b165e..89b8b1c43 100644
--- a/src/scale/helper.ts
+++ b/src/scale/helper.ts
@@ -18,6 +18,7 @@
 */
 
 import {getPrecision, round, nice, quantityExponent} from '../util/number';
+import { ScaleBreak } from '../util/types';
 import IntervalScale from './Interval';
 import LogScale from './Log';
 import Scale from './Scale';
@@ -126,13 +127,59 @@ export function contain(val: number, extent: [number, number]): boolean {
     return val >= extent[0] && val <= extent[1];
 }
 
-export function normalize(val: number, extent: [number, number]): number {
+export function normalize(
+    val: number,
+    extent: [number, number],
+    breaks?: ScaleBreak[]
+): number {
     if (extent[1] === extent[0]) {
         return 0.5;
     }
-    return (val - extent[0]) / (extent[1] - extent[0]);
+    if (!breaks) {
+        breaks = [];
+    }
+    if (breaks.length === 0) {
+        return (val - extent[0]) / (extent[1] - extent[0]);
+    }
+
+    // If the value is in the break, return the normalized value in the break
+    let accVal = extent[0];
+    let lastBreakEnd = extent[0];
+    let largerThanLastBreakEnd = true;
+    for (let i = 0; i < breaks.length; i++) {
+        const brk = breaks[i];
+        if (val <= brk.start) {
+            accVal += val - lastBreakEnd;
+            largerThanLastBreakEnd = false;
+            break;
+        }
+        else if (val <= brk.end) {
+            accVal += brk.start - lastBreakEnd;
+            largerThanLastBreakEnd = false;
+            break;
+        }
+        else {
+            accVal += brk.start - lastBreakEnd + brk.gap;
+            lastBreakEnd = brk.end;
+        }
+    }
+    const value = accVal + (largerThanLastBreakEnd ? (val - lastBreakEnd) : 0);
+    return (value - extent[0]) / getExtentSpanWithoutBreaks(extent, breaks);
 }
 
-export function scale(val: number, extent: [number, number]): number {
-    return val * (extent[1] - extent[0]) + extent[0];
+export function scale(
+    val: number,
+    extent: [number, number],
+    breaks?: ScaleBreak[]
+): number {
+    return val * getExtentSpanWithoutBreaks(extent, breaks) + extent[0];
+}
+
+export function getExtentSpanWithoutBreaks(extent: [number, number], breaks: ScaleBreak[]): number {
+    // When breaks is defined, calculate the sum of break gaps
+    let span = extent[1] - extent[0];
+    for (let i = 0; i < breaks.length; i++) {
+        span -= breaks[i].end - breaks[i].start - breaks[i].gap;
+    }
+    return span;
 }
diff --git a/src/util/types.ts b/src/util/types.ts
index c7b0c4ef3..14c1c214b 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -387,6 +387,12 @@ export type ParsedValueNumeric = number | OrdinalNumber;
  */
 export type ScaleDataValue = ParsedValueNumeric | OrdinalRawValue | Date;
 
+export type ScaleBreak = {
+    start: number,
+    end: number,
+    gap: number
+};
+
 export interface ScaleTick {
     level?: number,
     value: number


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org