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

sushuang pushed a commit to branch PR/plainheart_fix/alignTicks-precision
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit bd19110f247d9221849f43d18f8b49b590095520
Author: 100pah <[email protected]>
AuthorDate: Sun Mar 8 02:51:11 2026 +0800

    fix: (1) Clarify and uniform terminology and add comments to explain 
EC_CYCLE. (2) Fix dataZoom in `appendData`, introduced by recent commits.
---
 src/component/dataZoom/dataZoomProcessor.ts    |   2 +
 src/component/dataZoom/helper.ts               |   3 +-
 src/component/thumbnail/ThumbnailBridgeImpl.ts |   2 +-
 src/component/thumbnail/ThumbnailView.ts       |   2 +-
 src/coord/axisAlignTicks.ts                    |   4 +
 src/coord/axisStatistics.ts                    |  19 ++--
 src/coord/scaleRawExtentInfo.ts                |  12 +-
 src/core/ExtensionAPI.ts                       |   2 +-
 src/core/Scheduler.ts                          |  23 ++--
 src/core/echarts.ts                            | 150 +++++++++++++++++--------
 src/core/task.ts                               |  10 +-
 src/label/LabelManager.ts                      |   2 +-
 src/label/labelLayoutHelper.ts                 |   2 +-
 src/model/OptionManager.ts                     |   6 -
 src/scale/scaleMapper.ts                       |   4 +-
 src/util/cycleCache.ts                         |  73 ++++++++++++
 src/util/model.ts                              |  50 ---------
 src/util/types.ts                              |  57 ++++++++--
 test/bar-polar-multi-series-radial.html        |   2 +-
 19 files changed, 269 insertions(+), 156 deletions(-)

diff --git a/src/component/dataZoom/dataZoomProcessor.ts 
b/src/component/dataZoom/dataZoomProcessor.ts
index 96033e38d..811b6a264 100644
--- a/src/component/dataZoom/dataZoomProcessor.ts
+++ b/src/component/dataZoom/dataZoomProcessor.ts
@@ -30,6 +30,8 @@ import { AxisBaseModel } from '../../coord/AxisBaseModel';
 
 const dataZoomProcessor: StageHandler = {
 
+    dirtyOnOverallProgress: true,
+
     // `dataZoomProcessor` will only be performed in needed series. Consider if
     // there is a line series and a pie series, it is better not to update the
     // line series if only pie series is needed to be updated.
diff --git a/src/component/dataZoom/helper.ts b/src/component/dataZoom/helper.ts
index d3170ea2b..9fb7c3b58 100644
--- a/src/component/dataZoom/helper.ts
+++ b/src/component/dataZoom/helper.ts
@@ -25,8 +25,9 @@ import SeriesModel from '../../model/Series';
 import { CoordinateSystemHostModel } from '../../coord/CoordinateSystem';
 import { AxisBaseModel } from '../../coord/AxisBaseModel';
 import type AxisProxy from './AxisProxy';
-import { getCachePerECPrepare, GlobalModelCachePerECPrepare, makeInner } from 
'../../util/model';
+import { makeInner } from '../../util/model';
 import type ComponentModel from '../../model/Component';
+import { getCachePerECPrepare, GlobalModelCachePerECPrepare } from 
'../../util/cycleCache';
 
 
 export interface DataZoomPayloadBatchItem {
diff --git a/src/component/thumbnail/ThumbnailBridgeImpl.ts 
b/src/component/thumbnail/ThumbnailBridgeImpl.ts
index 9b33cec8c..f155613dc 100644
--- a/src/component/thumbnail/ThumbnailBridgeImpl.ts
+++ b/src/component/thumbnail/ThumbnailBridgeImpl.ts
@@ -51,7 +51,7 @@ export class ThumbnailBridgeImpl implements ThumbnailBridge {
     }
 
     reset(api: ExtensionAPI) {
-        this._renderVersion = api.getMainProcessVersion();
+        this._renderVersion = api.getECMainCycleVersion();
     }
 
     renderContent(opt: {
diff --git a/src/component/thumbnail/ThumbnailView.ts 
b/src/component/thumbnail/ThumbnailView.ts
index 617f6dfda..a08f1470b 100644
--- a/src/component/thumbnail/ThumbnailView.ts
+++ b/src/component/thumbnail/ThumbnailView.ts
@@ -70,7 +70,7 @@ export class ThumbnailView extends ComponentView {
             return;
         }
 
-        this._renderVersion = api.getMainProcessVersion();
+        this._renderVersion = api.getECMainCycleVersion();
         const group = this.group;
 
         group.removeAll();
diff --git a/src/coord/axisAlignTicks.ts b/src/coord/axisAlignTicks.ts
index 0fb54eedd..61f11ed20 100644
--- a/src/coord/axisAlignTicks.ts
+++ b/src/coord/axisAlignTicks.ts
@@ -56,6 +56,10 @@ export function scaleCalcAlign(
         targetScale, targetAxisModel, targetAxisModel.ecModel, targetAxis, null
     );
 
+    // FIXME:
+    //  (1) Axis inverse is not considered yet.
+    //  (2) `SCALE_EXTENT_KIND_MAPPING` is not considered yet.
+
     const isTargetLogScale = isLogScale(targetScale);
     const alignToScaleLinear = isLogScale(alignToScale) ? 
alignToScale.intervalStub : alignToScale;
     const targetIntervalStub = isTargetLogScale ? targetScale.intervalStub : 
targetScale;
diff --git a/src/coord/axisStatistics.ts b/src/coord/axisStatistics.ts
index f64ae1faa..ca2454619 100644
--- a/src/coord/axisStatistics.ts
+++ b/src/coord/axisStatistics.ts
@@ -21,8 +21,6 @@ import { assert, createHashMap, each, HashMap } from 
'zrender/src/core/util';
 import type GlobalModel from '../model/Global';
 import type SeriesModel from '../model/Series';
 import {
-    getCachePerECFullUpdate, getCachePerECPrepare, 
GlobalModelCachePerECFullUpdate,
-    GlobalModelCachePerECPrepare,
     initExtentForUnion, makeCallOnlyOnce, makeInner,
 } from '../util/model';
 import { DimensionIndex, NullUndefined } from '../util/types';
@@ -34,6 +32,10 @@ import type { AxisBaseModel } from './AxisBaseModel';
 import { tryEnsureTypedArray, Float64ArrayCtor } from '../util/vendor';
 import { EChartsExtensionInstallRegisters } from '../extension';
 import type ComponentModel from '../model/Component';
+import {
+    getCachePerECFullUpdate, getCachePerECPrepare, 
GlobalModelCachePerECFullUpdate,
+    GlobalModelCachePerECPrepare
+} from '../util/cycleCache';
 
 
 const callOnlyOnce = makeCallOnlyOnce();
@@ -237,7 +239,7 @@ export function eachAxisStatKey(
     });
 }
 
-function performAxisStatistics(ecModel: GlobalModel): void {
+function performAxisStatisticsOnOverallReset(ecModel: GlobalModel): void {
     const ecFullUpdateCache = 
ecModelCacheFullUpdateInner(getCachePerECFullUpdate(ecModel));
     const axisStatAll: AxisStatAll = ecFullUpdateCache.all = createHashMap();
 
@@ -350,11 +352,10 @@ function performStatisticsForRecord(
     }
     if (!ecPrepareCacheMiss && ecPrepareLiPosMinGap != null) {
         // Consider the fact in practice:
-        //  - Series data can only be changed in the "ec prepare" stage.
-        //  - The relationship between series and axes can only be changed in 
"ec prepare" stage and
-        //    `SERIES_FILTER`.
-        //  (NOTE: "ec prepare" stage can be typically considered as 
`chart.setOption`, and "ec updated"
-        //  stage can be typically considered as `dispatchAction`.)
+        //  - Series data can only be changed in EC_PREPARE_UPDATE.
+        //  - The relationship between series and axes can only be changed in 
EC_PREPARE_UPDATE and
+        //    SERIES_FILTER.
+        //  (See EC_CYCLE for more info)
         // Therefore, some statistics results can be cached in 
`GlobalModelCachePerECPrepare` to avoid
         // repeated time-consuming calculation for large data (e.g., over 1e5 
data items).
         perKeyPerAxis.liPosMinGap = ecPrepareLiPosMinGap;
@@ -452,7 +453,7 @@ export function requireAxisStatistics(
 
     callOnlyOnce(registers, function () {
         
registers.registerProcessor(registers.PRIORITY.PROCESSOR.AXIS_STATISTICS, {
-            overallReset: performAxisStatistics
+            overallReset: performAxisStatisticsOnOverallReset
         });
     });
 }
diff --git a/src/coord/scaleRawExtentInfo.ts b/src/coord/scaleRawExtentInfo.ts
index d9d7ed6b4..f378b5da5 100644
--- a/src/coord/scaleRawExtentInfo.ts
+++ b/src/coord/scaleRawExtentInfo.ts
@@ -58,7 +58,7 @@ import { AxisStatKey, eachAxisStatKey } from 
'./axisStatistics';
  */
 const scaleInner = makeInner<{
     extent: number[];
-    // series on this axis.
+    // series on this axis to union data extent.
     seriesList: SeriesModel[];
     dimIdxInCoord: number;
 }, Scale>();
@@ -422,9 +422,6 @@ export class ScaleRawExtentInfo {
      *  The outcome `_zoomMM` may have both `NullUndefined` and a finite 
value, like `[undefined, 123]`.
      */
     setZoomMinMax(idxMinMax: 0 | 1, val: number | NullUndefined): void {
-        if (__DEV__) {
-            assert(this._i.zoomMM[idxMinMax] == null);
-        }
         this._i.zoomMM[idxMinMax] = val;
     }
 
@@ -596,8 +593,11 @@ export function scaleRawExtentInfoReallyCreate(
     if (scale.rawExtentInfo) {
         if (__DEV__) {
             // Check for incorrect impl - the duplicated calling of this 
method is only allowed in
-            // one case: first dataZoom then coord sys update.
-            assert(scale.rawExtentInfo.from !== from);
+            // these cases:
+            //  - First in `AxisProxy['reset']` (for dataZoom)
+            //  - Then in `CoordinateSystem['update']`.
+            //  - Then after `chart.appendData()` due to 
`dirtyOnOverallProgress: true`
+            assert(scale.rawExtentInfo.from !== from || from === 
AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM);
         }
         return;
     }
diff --git a/src/core/ExtensionAPI.ts b/src/core/ExtensionAPI.ts
index 047bb704c..cfba0a270 100644
--- a/src/core/ExtensionAPI.ts
+++ b/src/core/ExtensionAPI.ts
@@ -72,7 +72,7 @@ abstract class ExtensionAPI {
     abstract getViewOfComponentModel(componentModel: ComponentModel): 
ComponentView;
     abstract getViewOfSeriesModel(seriesModel: SeriesModel): ChartView;
     abstract getModel(): GlobalModel;
-    abstract getMainProcessVersion(): number;
+    abstract getECMainCycleVersion(): number;
 }
 
 export default ExtensionAPI;
diff --git a/src/core/Scheduler.ts b/src/core/Scheduler.ts
index 745631111..c87690e95 100644
--- a/src/core/Scheduler.ts
+++ b/src/core/Scheduler.ts
@@ -68,6 +68,8 @@ type TaskRecord = {
     overallTask?: OverallTask
 };
 type PerformStageTaskOpt = {
+    // `block` means running from the beginning to the final end within
+    // an individual "progress".
     block?: boolean,
     setDirty?: boolean,
     visualType?: StageHandlerInternal['visualType'],
@@ -96,7 +98,7 @@ interface OverallTaskContext extends TaskContext {
 }
 interface StubTaskContext extends TaskContext {
     model: SeriesModel;
-    overallProgress: boolean;
+    dirtyOnOverallProgress: boolean;
 };
 
 class Scheduler {
@@ -147,7 +149,7 @@ class Scheduler {
         // if a data processor depends on a component (e.g., dataZoomProcessor 
depends
         // on the settings of `dataZoom`), it should be re-performed if the 
component
         // is modified by `setOption`.
-        // (2) If a processor depends on sevral series, speicified by its 
`getTargetSeries`,
+        // (2) If a processor depends on several series, specified by its 
`getTargetSeries`,
         // it should be re-performed when the result array of 
`getTargetSeries` changed.
         // We use `dependencies` to cover these issues.
         // (3) How to update target series when coordinate system related 
components modified.
@@ -488,15 +490,13 @@ class Scheduler {
 
         const seriesType = stageHandler.seriesType;
         const getTargetSeries = stageHandler.getTargetSeries;
-        let overallProgress = true;
+        const dirtyOnOverallProgress = stageHandler.dirtyOnOverallProgress;
         let shouldOverallTaskDirty = false;
         // FIXME:TS never used, so comment it
         // let modifyOutputEnd = stageHandler.modifyOutputEnd;
 
         // An overall task with seriesType detected or has `getTargetSeries`, 
we add
-        // stub in each pipelines, it will set the overall task dirty when the 
pipeline
-        // progress. Moreover, to avoid call the overall task each frame (too 
frequent),
-        // we set the pipeline block.
+        // stub in each pipelines to receive dirty info from upstream.
         let errMsg = '';
         if (__DEV__) {
             errMsg = '"createOnAllSeries" is not supported for "overallReset", 
'
@@ -509,12 +509,7 @@ class Scheduler {
         else if (getTargetSeries) {
             getTargetSeries(ecModel, api).each(createStub);
         }
-        // Otherwise, (usually it is legacy case), the overall task will only 
be
-        // executed when upstream is dirty. Otherwise the progressive 
rendering of all
-        // pipelines will be disabled unexpectedly. But it still needs stubs 
to receive
-        // dirty info from upstream.
         else {
-            overallProgress = false;
             each(ecModel.getSeries(), createStub);
         }
 
@@ -534,12 +529,12 @@ class Scheduler {
             );
             stub.context = {
                 model: seriesModel,
-                overallProgress: overallProgress
+                dirtyOnOverallProgress: dirtyOnOverallProgress
                 // FIXME:TS never used, so comment it
                 // modifyOutputEnd: modifyOutputEnd
             };
             stub.agent = overallTask;
-            stub.__block = overallProgress;
+            stub.__block = dirtyOnOverallProgress;
 
             scheduler._pipe(seriesModel, stub);
         }
@@ -586,7 +581,7 @@ function overallTaskReset(context: OverallTaskContext): 
void {
 }
 
 function stubReset(context: StubTaskContext): 
TaskProgressCallback<StubTaskContext> {
-    return context.overallProgress && stubProgress;
+    return context.dirtyOnOverallProgress && stubProgress;
 }
 
 function stubProgress(this: StubTask): void {
diff --git a/src/core/echarts.ts b/src/core/echarts.ts
index dc350f92c..ad5bb2bdc 100644
--- a/src/core/echarts.ts
+++ b/src/core/echarts.ts
@@ -139,6 +139,7 @@ import type geoSourceManager from 
'../coord/geo/geoSourceManager';
 import {
     registerCustomSeries as registerCustom
 } from '../chart/custom/customSeriesRegister';
+import { resetCachePerECFullUpdate, resetCachePerECPrepare } from 
'../util/cycleCache';
 
 declare let global: any;
 
@@ -203,17 +204,68 @@ export const PRIORITY = {
     }
 };
 
-// Main process have three entries: `setOption`, `dispatchAction` and `resize`,
-// where they must not be invoked nestedly, except the only case: invoke
-// dispatchAction with updateMethod "none" in main process.
-// This flag is used to carry out this rule.
-// All events will be triggered out side main process (i.e. when 
!this[IN_MAIN_PROCESS]).
-const IN_MAIN_PROCESS_KEY = '__flagInMainProcess' as const;
+/**
+ * [ec updating/rendering cycles (EC_CYCLE)]
+ *
+ *  - EC_MAIN_CYCLE:
+ *    - It designates a run of a series of processing/updating/rendering.
+ *    - It is triggered by:
+ *      - `setOption`
+ *      - `dispatchAction`
+ *        (It is typically internally triggered by user inputs; but can also 
an explicit API call.)
+ *      - `resize`
+ *      - The next "animation frame" if in `lazyMode: true`.
+ *    - Nested entry is not allowed. If triggering a new run of EC_MAIN_CYCLE 
during a
+ *      unfinished run, the new run will be delayed until the current run 
finishes
+ *      (if triggered by `dispatchAction`), or throw error (if triggered by 
other API calls).
+ *    - All user-visible ec events are triggered outside EC_MAIN_CYCLE
+ *      (i.e. be triggered after `this[IN_EC_MAIN_CYCLE_KEY]` becoming 
`false`).
+ *    - A run of EC_MAIN_CYCLE comprises:
+ *      - EC_PREPARE_UPDATE (may be absent)
+ *      - EC_FULL_UPDATE or EC_PARTIAL_UPDATE
+ *    - A run of EC_FULL_UPDATE comprises:
+ *      - CoordinateSystem['create']
+ *      - Data processing (may be absent) (see `registerProcessor`)
+ *      - CoordinateSystem['update'] (may be absent)
+ *      - Visual encoding (may be absent) (see `registerVisual`)
+ *      - Layout (may be absent) (see `registerLayout`)
+ *      - Rendering (`ComponentView` or `SeriesView`)
+ *
+ *  - EC_PROGRESSIVE_CYCLE:
+ *    - It also carries out a series of processing/updating/rendering, but out 
of EC_MAIN_CYCLE.
+ *    - It is performed in each "animation frame".
+ *    - It can be triggered internally or `appendData` call.
+ *    - A run of EC_PROGRESSIVE_CYCLE comprises:
+ *      - Data processing (may be absent) (see `registerProcessor`)
+ *      - Visual encoding (may be absent) (see `registerVisual`)
+ *      - Layout (may be absent) (see `registerLayout`)
+ *      - Rendering (`ComponentView` or `SeriesView`)
+ *    - PENDING: currently all data processing tasks (via `registerProcessor`) 
run in "block" mode.
+ *      (see `performDataProcessorTasks`)
+ *
+ *  - Other updating/rendering cycles:
+ *    - Some series have specific update/render cycles. For example, graph 
force layout performs
+ *    layout and rendering in each "animation frame".
+ *
+ *  - Model updating:
+ *    - Model can only be modified at the beginning of ec cycles, including 
only:
+ *      - EC_PREPARE_UPDATE (see method `prepare()`) in `setOption` call.
+ *      - EC action handlers in `dispatchAction` call.
+ *      - `appendData` (a special case, where only data is modified).
+ *
+ *  - The lifetime of CoordinateSystem/Axis/Scale instances:
+ *    - They are only re-created per run of EC_FULL_UPDATE.
+ *
+ *  - Available caches: see `cycleCache.ts`
+ */
+
+// See comments in EC_CYCLE.
+const IN_EC_MAIN_CYCLE_KEY = '__flagInMainProcess' as const;
 // Useful for detecting outdated rendering results in scenarios that these 
issues are involved:
-//  - Use shortcut (such as, updateTransform, or no update) to start a main 
process.
+//  - Use EC_PARTIAL_UPDATE (such as, updateTransform, or no update) to start 
an EC_MAIN_CYCLE.
 //  - Asynchronously update rendered view (e.g., graph force layout).
 //  - Multiple ChartView/ComponentView render to one group cooperatively.
-const MAIN_PROCESS_VERSION_KEY = '__mainProcessVersion' as const;
+const EC_MAIN_CYCLE_VERSION_KEY = '__mainProcessVersion' as const;
 const PENDING_UPDATE = '__pendingUpdate' as const;
 const STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus' as const;
 const ACTION_REG = /^[a-zA-Z0-9_]+$/;
@@ -285,7 +337,7 @@ messageCenterProto.off = 
createRegisterEventWithLowercaseMessageCenter('off');
 // ---------------------------------------
 // Internal method names for class ECharts
 // ---------------------------------------
-let prepare: (ecIns: ECharts) => void;
+let prepare: (ecIns: ECharts) => void; // This is `EC_PREPARE_UPDATE`.
 let prepareView: (ecIns: ECharts, isComponent: boolean) => void;
 let updateDirectly: (
     ecIns: ECharts, method: string, payload: Payload, mainType: 
ComponentMainType, subType?: ComponentSubType
@@ -293,11 +345,11 @@ let updateDirectly: (
 type UpdateMethod = (this: ECharts, payload?: Payload, renderParams?: 
UpdateLifecycleParams) => void;
 let updateMethods: {
     prepareAndUpdate: UpdateMethod,
-    update: UpdateMethod,
-    updateTransform: UpdateMethod,
-    updateView: UpdateMethod,
-    updateVisual: UpdateMethod,
-    updateLayout: UpdateMethod
+    update: UpdateMethod, // This is `EC_FULL_UPDATE`.
+    updateTransform: UpdateMethod, // This is one of `EC_PARTIAL_UPDATE`.
+    updateView: UpdateMethod, // This is one of `EC_PARTIAL_UPDATE`.
+    updateVisual: UpdateMethod, // This is one of `EC_PARTIAL_UPDATE`.
+    updateLayout: UpdateMethod // This is one of `EC_PARTIAL_UPDATE`.
 };
 let doConvertPixel: {
     (
@@ -345,7 +397,7 @@ let enableConnect: (ecIns: ECharts) => void;
 
 let markStatusToUpdate: (ecIns: ECharts) => void;
 let applyChangedStates: (ecIns: ECharts) => void;
-let updateMainProcessVersion: (ecIns: ECharts) => void;
+let updateECMainCycleVersion: (ecIns: ECharts) => void;
 
 type RenderedEventParam = { elapsedTime: number };
 type ECEventDefinition = {
@@ -427,8 +479,8 @@ class ECharts extends Eventful<ECEventDefinition> {
         silent: boolean
         updateParams: UpdateLifecycleParams
     };
-    private [IN_MAIN_PROCESS_KEY]: boolean;
-    private [MAIN_PROCESS_VERSION_KEY]: number;
+    private [IN_EC_MAIN_CYCLE_KEY]: boolean;
+    private [EC_MAIN_CYCLE_VERSION_KEY]: number;
     private [CONNECT_STATUS_KEY]: ConnectStatus;
     private [STATUS_NEEDS_UPDATE_KEY]: boolean;
 
@@ -451,7 +503,7 @@ class ECharts extends Eventful<ECEventDefinition> {
         let defaultCoarsePointer: 'auto' | boolean = 'auto';
         let defaultUseDirtyRect = false;
 
-        this[MAIN_PROCESS_VERSION_KEY] = 1;
+        this[EC_MAIN_CYCLE_VERSION_KEY] = 1;
 
         if (__DEV__) {
             const root = (
@@ -545,15 +597,15 @@ class ECharts extends Eventful<ECEventDefinition> {
         if (this[PENDING_UPDATE]) {
             const silent = (this[PENDING_UPDATE] as any).silent;
 
-            this[IN_MAIN_PROCESS_KEY] = true;
-            updateMainProcessVersion(this);
+            this[IN_EC_MAIN_CYCLE_KEY] = true;
+            updateECMainCycleVersion(this);
 
             try {
                 prepare(this);
                 updateMethods.update.call(this, null, 
this[PENDING_UPDATE].updateParams);
             }
             catch (e) {
-                this[IN_MAIN_PROCESS_KEY] = false;
+                this[IN_EC_MAIN_CYCLE_KEY] = false;
                 this[PENDING_UPDATE] = null;
                 throw e;
             }
@@ -566,7 +618,7 @@ class ECharts extends Eventful<ECEventDefinition> {
             // will render the final state of the elements before the real 
animation started.
             this._zr.flush();
 
-            this[IN_MAIN_PROCESS_KEY] = false;
+            this[IN_EC_MAIN_CYCLE_KEY] = false;
             this[PENDING_UPDATE] = null;
 
             flushPendingActions.call(this, silent);
@@ -649,7 +701,7 @@ class ECharts extends Eventful<ECEventDefinition> {
     setOption<Opt extends ECBasicOption>(option: Opt, opts?: SetOptionOpts): 
void;
     /* eslint-disable-next-line */
     setOption<Opt extends ECBasicOption>(option: Opt, notMerge?: boolean | 
SetOptionOpts, lazyUpdate?: boolean): void {
-        if (this[IN_MAIN_PROCESS_KEY]) {
+        if (this[IN_EC_MAIN_CYCLE_KEY]) {
             if (__DEV__) {
                 error('`setOption` should not be called during main process.');
             }
@@ -672,8 +724,8 @@ class ECharts extends Eventful<ECEventDefinition> {
             notMerge = notMerge.notMerge;
         }
 
-        this[IN_MAIN_PROCESS_KEY] = true;
-        updateMainProcessVersion(this);
+        this[IN_EC_MAIN_CYCLE_KEY] = true;
+        updateECMainCycleVersion(this);
 
         if (!this._model || notMerge) {
             const optionManager = new OptionManager(this._api);
@@ -696,7 +748,7 @@ class ECharts extends Eventful<ECEventDefinition> {
                 silent: silent,
                 updateParams: updateParams
             };
-            this[IN_MAIN_PROCESS_KEY] = false;
+            this[IN_EC_MAIN_CYCLE_KEY] = false;
 
             // `setOption(option, {lazyMode: true})` may be called when 
zrender has been slept.
             // It should wake it up to make sure zrender start to render at 
the next frame.
@@ -709,7 +761,7 @@ class ECharts extends Eventful<ECEventDefinition> {
             }
             catch (e) {
                 this[PENDING_UPDATE] = null;
-                this[IN_MAIN_PROCESS_KEY] = false;
+                this[IN_EC_MAIN_CYCLE_KEY] = false;
 
                 throw e;
             }
@@ -722,7 +774,7 @@ class ECharts extends Eventful<ECEventDefinition> {
             }
 
             this[PENDING_UPDATE] = null;
-            this[IN_MAIN_PROCESS_KEY] = false;
+            this[IN_EC_MAIN_CYCLE_KEY] = false;
 
             flushPendingActions.call(this, silent);
             triggerUpdatedEvent.call(this, silent);
@@ -735,7 +787,7 @@ class ECharts extends Eventful<ECEventDefinition> {
      * @param opts Optional settings
      */
     setTheme(theme: string | ThemeOption, opts?: SetThemeOpts): void {
-        if (this[IN_MAIN_PROCESS_KEY]) {
+        if (this[IN_EC_MAIN_CYCLE_KEY]) {
             if (__DEV__) {
                 error('`setTheme` should not be called during main process.');
             }
@@ -763,8 +815,8 @@ class ECharts extends Eventful<ECEventDefinition> {
             this[PENDING_UPDATE] = null;
         }
 
-        this[IN_MAIN_PROCESS_KEY] = true;
-        updateMainProcessVersion(this);
+        this[IN_EC_MAIN_CYCLE_KEY] = true;
+        updateECMainCycleVersion(this);
 
         try {
             this._updateTheme(theme);
@@ -774,11 +826,11 @@ class ECharts extends Eventful<ECEventDefinition> {
             updateMethods.update.call(this, {type: 'setTheme'}, updateParams);
         }
         catch (e) {
-            this[IN_MAIN_PROCESS_KEY] = false;
+            this[IN_EC_MAIN_CYCLE_KEY] = false;
             throw e;
         }
 
-        this[IN_MAIN_PROCESS_KEY] = false;
+        this[IN_EC_MAIN_CYCLE_KEY] = false;
 
         flushPendingActions.call(this, silent);
         triggerUpdatedEvent.call(this, silent);
@@ -1357,7 +1409,7 @@ class ECharts extends Eventful<ECEventDefinition> {
      * Resize the chart
      */
     resize(opts?: ResizeOpts): void {
-        if (this[IN_MAIN_PROCESS_KEY]) {
+        if (this[IN_EC_MAIN_CYCLE_KEY]) {
             if (__DEV__) {
                 error('`resize` should not be called during main process.');
             }
@@ -1395,8 +1447,8 @@ class ECharts extends Eventful<ECEventDefinition> {
             this[PENDING_UPDATE] = null;
         }
 
-        this[IN_MAIN_PROCESS_KEY] = true;
-        updateMainProcessVersion(this);
+        this[IN_EC_MAIN_CYCLE_KEY] = true;
+        updateECMainCycleVersion(this);
 
         try {
             needPrepare && prepare(this);
@@ -1409,11 +1461,11 @@ class ECharts extends Eventful<ECEventDefinition> {
             });
         }
         catch (e) {
-            this[IN_MAIN_PROCESS_KEY] = false;
+            this[IN_EC_MAIN_CYCLE_KEY] = false;
             throw e;
         }
 
-        this[IN_MAIN_PROCESS_KEY] = false;
+        this[IN_EC_MAIN_CYCLE_KEY] = false;
 
         flushPendingActions.call(this, silent);
 
@@ -1507,7 +1559,7 @@ class ECharts extends Eventful<ECEventDefinition> {
         }
 
         // May dispatchAction in rendering procedure
-        if (this[IN_MAIN_PROCESS_KEY]) {
+        if (this[IN_EC_MAIN_CYCLE_KEY]) {
             this._pendingActions.push(payload);
             return;
         }
@@ -1579,7 +1631,7 @@ class ECharts extends Eventful<ECEventDefinition> {
     private static internalField = (function () {
 
         prepare = function (ecIns: ECharts): void {
-            modelUtil.resetCachePerECPrepare(ecIns._model);
+            resetCachePerECPrepare(ecIns._model);
 
             const scheduler = ecIns._scheduler;
 
@@ -1806,7 +1858,7 @@ class ECharts extends Eventful<ECEventDefinition> {
                     return;
                 }
 
-                modelUtil.resetCachePerECFullUpdate(ecModel);
+                resetCachePerECFullUpdate(ecModel);
                 ecModel.setUpdatePayload(payload);
 
                 scheduler.restoreData(ecModel, payload);
@@ -2050,8 +2102,8 @@ class ECharts extends Eventful<ECEventDefinition> {
             const updateMethod = cptTypeTmp.pop();
             const cptType = cptTypeTmp[0] != null && 
parseClassType(cptTypeTmp[0]);
 
-            this[IN_MAIN_PROCESS_KEY] = true;
-            updateMainProcessVersion(this);
+            this[IN_EC_MAIN_CYCLE_KEY] = true;
+            updateECMainCycleVersion(this);
 
             let payloads: Payload[] = [payload];
             let batched = false;
@@ -2122,7 +2174,7 @@ class ECharts extends Eventful<ECEventDefinition> {
                     }
                 }
                 catch (e) {
-                    this[IN_MAIN_PROCESS_KEY] = false;
+                    this[IN_EC_MAIN_CYCLE_KEY] = false;
                     throw e;
                 }
             }
@@ -2139,7 +2191,7 @@ class ECharts extends Eventful<ECEventDefinition> {
                 eventObj = eventObjBatch[0] as ECActionEvent;
             }
 
-            this[IN_MAIN_PROCESS_KEY] = false;
+            this[IN_EC_MAIN_CYCLE_KEY] = false;
 
             if (!silent) {
                 let refinedEvent: ECActionEvent;
@@ -2434,8 +2486,8 @@ class ECharts extends Eventful<ECEventDefinition> {
             ecIns.getZr().wakeUp();
         };
 
-        updateMainProcessVersion = function (ecIns: ECharts): void {
-            ecIns[MAIN_PROCESS_VERSION_KEY] = (ecIns[MAIN_PROCESS_VERSION_KEY] 
+ 1) % 1000;
+        updateECMainCycleVersion = function (ecIns: ECharts): void {
+            ecIns[EC_MAIN_CYCLE_VERSION_KEY] = 
(ecIns[EC_MAIN_CYCLE_VERSION_KEY] + 1) % 1000;
         };
 
         applyChangedStates = function (ecIns: ECharts): void {
@@ -2666,8 +2718,8 @@ class ECharts extends Eventful<ECEventDefinition> {
                 getViewOfSeriesModel(seriesModel: SeriesModel): ChartView {
                     return ecIns.getViewOfSeriesModel(seriesModel);
                 }
-                getMainProcessVersion(): number {
-                    return ecIns[MAIN_PROCESS_VERSION_KEY];
+                getECMainCycleVersion(): number {
+                    return ecIns[EC_MAIN_CYCLE_VERSION_KEY];
                 }
             })(ecIns);
         };
diff --git a/src/core/task.ts b/src/core/task.ts
index 6a25c1c12..20a59d3fb 100644
--- a/src/core/task.ts
+++ b/src/core/task.ts
@@ -112,7 +112,7 @@ export class Task<Ctx extends TaskContext> {
     // Injected in schedular
     __pipeline: Pipeline;
     __idxInPipeline: number;
-    __block: boolean;
+    __block: boolean; // FIXME: simplify it - merge with 
PerformStageTaskOpt['block']?
 
     // Context must be specified implicitly, to
     // avoid miss update context when model changed.
@@ -242,6 +242,14 @@ export class Task<Ctx extends TaskContext> {
         return this.unfinished();
     }
 
+    /**
+     * Generally, task dirty propagates to downstream tasks.
+     * Task dirty leads to the `reset` call, which discards the previous 
result and starts over
+     * the processing.
+     *
+     * See `StageHandler['reset']` and `StageHandler['overallReset']` for a 
summary of possible
+     * `dirty()` calls.
+     */
     dirty(): void {
         this._dirty = true;
         this._onDirty && this._onDirty(this.context);
diff --git a/src/label/LabelManager.ts b/src/label/LabelManager.ts
index b60a9ac2b..411af3081 100644
--- a/src/label/LabelManager.ts
+++ b/src/label/LabelManager.ts
@@ -86,7 +86,7 @@ interface LabelDesc {
  * Save the original value determined in a pass of echarts main process. That 
refers to the values
  * rendered by `SeriesView`, before `series:layoutlabels` is triggered in 
`renderSeries`.
  *
- * 'series:layoutlabels' may be triggered during some shortcut passes, such as 
zooming in series.graph/geo
+ * 'series:layoutlabels' may be triggered during some EC_PARTIAL_UPDATE 
passes, such as zooming in series.graph/geo
  * (`updateLabelLayout`), where the modified `Element` props should be 
restorable by the original value here.
  *
  * Regarding `Element` state, simply consider the values here as the normal 
state values.
diff --git a/src/label/labelLayoutHelper.ts b/src/label/labelLayoutHelper.ts
index 1136bb63d..856781118 100644
--- a/src/label/labelLayoutHelper.ts
+++ b/src/label/labelLayoutHelper.ts
@@ -509,7 +509,7 @@ export function restoreIgnore(labelList: 
LabelLayoutData[]): void {
 
 /**
  * [NOTICE - restore]:
- *  'series:layoutlabels' may be triggered during some shortcut passes, such 
as zooming in series.graph/geo
+ *  'series:layoutlabels' may be triggered during some EC_PARTIAL_UPDATE 
passes, such as zooming in series.graph/geo
  *  (`updateLabelLayout`), where the modified `Element` props should be 
restorable from `defaultAttr`.
  *  @see `SavedLabelAttr` in `LabelManager.ts`
  *  `restoreIgnore` can be called to perform the restore, if needed.
diff --git a/src/model/OptionManager.ts b/src/model/OptionManager.ts
index ef795ba58..846d3c215 100644
--- a/src/model/OptionManager.ts
+++ b/src/model/OptionManager.ts
@@ -17,12 +17,6 @@
 * under the License.
 */
 
-/**
- * ECharts option manager
- */
-
-
-// import ComponentModel, { ComponentModelConstructor } from './Component';
 import ExtensionAPI from '../core/ExtensionAPI';
 import {
     OptionPreprocessor, MediaQuery, ECUnitOption, MediaUnit, ECBasicOption, 
SeriesOption
diff --git a/src/scale/scaleMapper.ts b/src/scale/scaleMapper.ts
index 76dd2e871..845594430 100644
--- a/src/scale/scaleMapper.ts
+++ b/src/scale/scaleMapper.ts
@@ -205,7 +205,7 @@ export interface ScaleMapperGeneric<This> {
 
     /**
      * [NOTICE]:
-     *  In ec workflow, scale extent is finally determined at 
`coordSys#update` stage.
+     *  In EC_MAIN_CYCLE, scale extent is finally determined at 
`coordSys#update` stage.
      *
      * Get a clone of the scale extent.
      * An extent is always in an increase order.
@@ -230,7 +230,7 @@ export interface ScaleMapperGeneric<This> {
      *
      * `setExtent` is identical to `setExtent2(SCALE_EXTENT_KIND_EFFECTIVE)`.
      *
-     * [The steps of extent construction in ec workflow]:
+     * [The steps of extent construction in EC_MAIN_CYCLE]:
      *  - step#1. At `CoordinateSystem#create` stage, requirements of 
collecting series data extents are
      *            committed to `scaleRawExtentInfoRequireCreate`, and `Scale` 
instances are created.
      *  - step#2. Call `scaleRawExtentInfoReallyCreate` to really collect 
series data extent and create
diff --git a/src/util/cycleCache.ts b/src/util/cycleCache.ts
new file mode 100644
index 000000000..7d653bb72
--- /dev/null
+++ b/src/util/cycleCache.ts
@@ -0,0 +1,73 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import GlobalModel from '../model/Global';
+import { makeInner } from './model';
+
+
+const ecModelCacheInner = makeInner<{
+    fullUpdate: GlobalModelCachePerECFullUpdate;
+    prepare: GlobalModelCachePerECPrepare;
+}, GlobalModel>();
+
+export type GlobalModelCachePerECPrepare = {__: 'prepare'}; // Nominal to 
distinguish.
+export type GlobalModelCachePerECFullUpdate = {__: 'fullUpdate'}; // Nominal 
to distinguish.
+
+/**
+ * CAVEAT: Can only be called by `echarts.ts`
+ */
+export function resetCachePerECPrepare(ecModel: GlobalModel): void {
+    ecModelCacheInner(ecModel).prepare = {} as GlobalModelCachePerECPrepare;
+}
+
+/**
+ * CAVEAT: Can only be called by `echarts.ts`
+ */
+export function resetCachePerECFullUpdate(ecModel: GlobalModel): void {
+    ecModelCacheInner(ecModel).fullUpdate = {} as 
GlobalModelCachePerECFullUpdate;
+}
+
+/**
+ * The cache is auto cleared at the beginning of EC_PREPARE_UPDATE.
+ * See also comments in EC_CYCLE.
+ *
+ * NOTICE:
+ *  - EC_PREPARE_UPDATE is not necessarily executed before each EC_FULL_UPDATE 
performing.
+ *    Typically, `setOption` trigger EC_PREPARE_UPDATE, but `dispatchAction` 
does not.
+ *  - It is not cleared in EC_PARTIAL_UPDATE and EC_PROGRESSIVE_CYCLE.
+ *
+ */
+export function getCachePerECPrepare(ecModel: GlobalModel): 
GlobalModelCachePerECPrepare {
+    return ecModelCacheInner(ecModel).prepare;
+}
+
+/**
+ * The cache is auto cleared at the beginning of EC_FULL_UPDATE.
+ * See also comments in EC_CYCLE.
+ *
+ * NOTICE:
+ *  - It is not cleared in EC_PARTIAL_UPDATE and EC_PROGRESSIVE_CYCLE.
+ *  - The cache should NOT be written before EC_FULL_UPDATE started, such as:
+ *      - should NOT in `getTargetSeries` methods of data processors.
+ *      - should NOT in `init`/`mergeOption`/`optionUpdated`/`getData` methods 
of component/series models.
+ *  - See `getCachePerECPrepare` for details.
+ */
+export function getCachePerECFullUpdate(ecModel: GlobalModel): 
GlobalModelCachePerECFullUpdate {
+    return ecModelCacheInner(ecModel).fullUpdate;
+}
diff --git a/src/util/model.ts b/src/util/model.ts
index 5412ee058..95d7df3d6 100644
--- a/src/util/model.ts
+++ b/src/util/model.ts
@@ -30,7 +30,6 @@ import {
     isStringSafe,
     isNumber,
     hasOwn,
-    isTypedArray,
 } from 'zrender/src/core/util';
 import env from 'zrender/src/core/env';
 import GlobalModel from '../model/Global';
@@ -1274,55 +1273,6 @@ export function makeCallOnlyOnce<Host extends object>() {
 let onceUniqueIndex = getRandomIdBase();
 
 
-const ecModelCacheInner = makeInner<{
-    fullUpdate: GlobalModelCachePerECFullUpdate;
-    prepare: GlobalModelCachePerECPrepare;
-}, GlobalModel>();
-
-export type GlobalModelCachePerECPrepare = {__: 'prepare'}; // Nominal to 
distinguish.
-export type GlobalModelCachePerECFullUpdate = {__: 'fullUpdate'}; // Nominal 
to distinguish.
-
-/**
- * CAVEAT: Can only be called by `echarts.ts`
- */
-export function resetCachePerECPrepare(ecModel: GlobalModel): void {
-    ecModelCacheInner(ecModel).prepare = {} as GlobalModelCachePerECPrepare;
-}
-
-/**
- * CAVEAT: Can only be called by `echarts.ts`
- */
-export function resetCachePerECFullUpdate(ecModel: GlobalModel): void {
-    ecModelCacheInner(ecModel).fullUpdate = {} as 
GlobalModelCachePerECFullUpdate;
-}
-
-/**
- * The cache is auto cleared at the begining of a run of "ec prepare".
- * Typically, `setOption` trigger "ec prepare", but `dispatchAction` does not.
- *
- * NOTICE:
- *  - "ec prepare" is not necessarily performed before each "ec full update" 
performing.
- */
-export function getCachePerECPrepare(ecModel: GlobalModel): 
GlobalModelCachePerECPrepare {
-    return ecModelCacheInner(ecModel).prepare;
-}
-
-/**
- * The cache is auto cleared at the begining of a run of "ec full update".
- * However, all shortcuts (such as `updateView`/`updateLayout`/etc.) do not 
clear it.
- * Typically, all `setOption` and some `dispatchAction` trigger "ec full 
update".
- * This is the same as the lifecycle of coordinate systems instances and axes 
instances.
- *
- * NOTICE:
- *  - The cache should NOT be written in:
- *      - `getTargetSeries` methods of data processors.
- *      - `init`/`mergeOption`/`optionUpdated`/`getData` methods of 
component/series models.
- *    See `getCachePerECPrepare` for details.
- */
-export function getCachePerECFullUpdate(ecModel: GlobalModel): 
GlobalModelCachePerECFullUpdate {
-    return ecModelCacheInner(ecModel).fullUpdate;
-}
-
 /**
  * @usage
  *  - The earlier item takes precedence for duplicate items.
diff --git a/src/util/types.ts b/src/util/types.ts
index ad6e962ad..aebc93ce6 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -336,19 +336,25 @@ export interface StageHandlerOverallReset {
     (ecModel: GlobalModel, api: ExtensionAPI, payload?: Payload): void
 }
 export interface StageHandler {
+
     /**
-     * Indicate that the task will be piped all series
-     * (`performRawSeries` indicate whether includes filtered series).
+     * Indicate that the "series stage task" will be piped for all series
+     * (filtered series is included iff `performRawSeries: true`).
+     *
+     * OVERALL_STAGE_TASK (See `overallReset`) can not set `createOnAllSeries: 
true`.
      */
     createOnAllSeries?: boolean;
+
     /**
-     * Indicate that the task will be only piped in the pipeline of this type 
of series.
-     * (`performRawSeries` indicate whether includes filtered series).
+     * Indicate that the task will only be piped in the pipeline of this type 
of series.
+     * (filtered series is included iff `performRawSeries: true`).
+     * It is available for both `reset` and `overallReset`.
      */
     seriesType?: string;
+
     /**
-     * Indicate that the task will be only piped in the pipeline of the 
returned series.
-     * Called in "prepare" stage, before coord sys creation.
+     * Indicate that the task will only be piped in the pipeline of the 
returned series.
+     * It is called in EC_PREPARE_UPDATE, before `CoordinateSystem['create']`.
      * It is available for both `reset` and `overallReset`.
      */
     getTargetSeries?: (ecModel: GlobalModel, api: ExtensionAPI) => 
HashMap<SeriesModel>;
@@ -362,18 +368,45 @@ export interface StageHandler {
      * Called only when this task in a pipeline.
      */
     plan?: StageHandlerPlan;
+
     /**
-     * If `overallReset` specified, an "overall task" will be created.
-     * "overall task" does not belong to a certain pipeline.
-     * They always be "performed" in certain phase (depends on when they 
declared).
-     * They has "stub"s to connect with pipelines (one stub for one pipeline),
-     * delivering info like "dirty" and "output end".
+     * If `overallReset` is specified, an OVERALL_STAGE_TASK will be created.
+     * An OVERALL_STAGE_TASK resides across multiple pipelines, and is 
associated with
+     * pipelines by "stub"s, which deliver messages like "dirty" and "output 
end".
+     * OVERALL_STAGE_TASK does not support `progess` method.
+     *
+     * The `overallReset` method is called iff this task is "dirty" (See 
`Task['dirty']`).
+     * See `StageHandler['reset']` for a summary of possible `dirty()` calls.
      */
     overallReset?: StageHandlerOverallReset;
+
     /**
-     * Called only when this task in a single pipeline, and "dirty".
+     * If `reset` is specified, a SERIES_STAGE_TASK will be created.
+     * A SERIES_STAGE_TASK is owned by a pipeline and is specific to a single 
series.
+     *
+     * The `reset` method is called iff this task is "dirty" (See 
`Task['dirty']`).
+     * Task `dirty()` call typically originates from:
+     *  - A trigger of EC_MAIN_CYCLE (including EC_FULL_UPDATE and 
EC_PARTIAL_UPDATE)
+     *    (See comments in EC_CYCLE)
+     *  - NOTICE: `dirtyOnOverallProgress: true` cause that the corresponding 
`overallReset`
+     *    and `reset` of downsteams tasks may also be called in 
EC_PROGRESSIVE_CYCLE.
+     *    But in this case, `CoordinateSystem#create` and 
`CoordinateSystem#update` are
+     *    not called.
      */
     reset?: StageHandlerReset;
+
+    /**
+     * This is a temporary mechanism for dataZoom case in `appendData`.
+     *
+     * It will set the OVERALL_STAGE_TASK dirty when the pipeline progress.
+     * Moreover, to avoid call the OVERALL_STAGE_TASK each frame (too 
frequent),
+     * it set the pipeline block (via `task.__block`) in this stage.
+     *
+     * Otherwise, (usually it is legacy case), the OVERALL_STAGE_TASK will 
only be
+     * executed when upstream is dirty. Otherwise the progressive rendering of 
all
+     * pipelines will be disabled unexpectedly.
+     */
+    dirtyOnOverallProgress?: boolean;
 }
 
 export interface StageHandlerInternal extends StageHandler {
diff --git a/test/bar-polar-multi-series-radial.html 
b/test/bar-polar-multi-series-radial.html
index 5185b2551..73374c2a5 100644
--- a/test/bar-polar-multi-series-radial.html
+++ b/test/bar-polar-multi-series-radial.html
@@ -34,7 +34,7 @@ under the License.
         </style>
 
 
-        <!-- <div id="main_multiple_bar_category_angle_axis"></div> -->
+        <div id="main_multiple_bar_category_angle_axis"></div>
         <div id="main_multiple_bar_value_angle_axis"></div>
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to