You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2020/06/19 09:36:56 UTC

[incubator-echarts] 02/02: feature: Enable category axis min/max to shrink the other axis extent in cartesian. After this modification, if some data if out of the range of a category axis, the data item will not be filtered, but the extent of the other axis will be calculated based on the filtered data. If dataZoom is used in either of the xAxis or yAxis in that cartesian, the shrink will not be performed.

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

sushuang pushed a commit to branch extent_filtered_by_other_axis
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 4a5f6d66667fde32277c41e09da5379cbac36bc0
Author: 100pah <su...@gmail.com>
AuthorDate: Fri Jun 19 17:36:13 2020 +0800

    feature: Enable category axis min/max to shrink the other axis extent in cartesian.
    After this modification, if some data if out of the range of a category axis,
    the data item will not be filtered, but the extent of the other axis will be calculated
    based on the filtered data.
    If dataZoom is used in either of the xAxis or yAxis in that cartesian, the shrink will not be performed.
---
 src/component/gridSimple.ts                      |   2 +-
 src/coord/cartesian/defaultAxisExtentFromData.ts | 262 ++++++++++++++
 test/axis-filter-extent.html                     | 422 +++++++++++++++++++++++
 3 files changed, 685 insertions(+), 1 deletion(-)

diff --git a/src/component/gridSimple.ts b/src/component/gridSimple.ts
index a73ab83..f1b6c9c 100644
--- a/src/component/gridSimple.ts
+++ b/src/component/gridSimple.ts
@@ -22,7 +22,7 @@ import * as zrUtil from 'zrender/src/core/util';
 import * as graphic from '../util/graphic';
 
 import './axis';
-// import '../coord/cartesian/defaultAxisExtentFromData';
+import '../coord/cartesian/defaultAxisExtentFromData';
 import ComponentView from '../view/Component';
 import GlobalModel from '../model/Global';
 import GridModel from '../coord/cartesian/GridModel';
diff --git a/src/coord/cartesian/defaultAxisExtentFromData.ts b/src/coord/cartesian/defaultAxisExtentFromData.ts
new file mode 100644
index 0000000..2b0e58e
--- /dev/null
+++ b/src/coord/cartesian/defaultAxisExtentFromData.ts
@@ -0,0 +1,262 @@
+/*
+* 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 * as echarts from '../../echarts';
+import { createHashMap, each, HashMap, hasOwn, keys, map } from 'zrender/src/core/util';
+import SeriesModel from '../../model/Series';
+import { isCartesian2DSeries, findAxisModels } from './cartesianAxisHelper';
+import { getDataDimensionsOnAxis, unionAxisExtentFromData } from '../axisHelper';
+import { AxisBaseModel } from '../AxisBaseModel';
+import Axis from '../Axis';
+import GlobalModel from '../../model/Global';
+import { Dictionary } from '../../util/types';
+import { ScaleRawExtentInfo, ScaleRawExtentResult, ensureScaleRawExtentInfo } from '../scaleRawExtentInfo';
+
+
+type AxisRecord = {
+    condExtent: number[];
+    rawExtentInfo?: ScaleRawExtentInfo;
+    rawExtentResult?: ScaleRawExtentResult
+    tarExtent?: number[];
+};
+
+type SeriesRecord = {
+    seriesModel: SeriesModel;
+    xAxisModel: AxisBaseModel;
+    yAxisModel: AxisBaseModel;
+};
+
+// A tricky: the priority is just after dataZoom processor.
+// If dataZoom has fixed the min/max, this processor do not need to work.
+echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER + 10, {
+
+    getTargetSeries: function (ecModel) {
+        const seriesModelMap = createHashMap<SeriesModel>();
+        ecModel.eachSeries(function (seriesModel: SeriesModel) {
+            isCartesian2DSeries(seriesModel) && seriesModelMap.set(seriesModel.uid, seriesModel);
+        });
+        return seriesModelMap;
+    },
+
+    overallReset: function (ecModel, api) {
+        const seriesRecords = [] as SeriesRecord[];
+        const axisRecordMap = createHashMap<AxisRecord>();
+
+        prepareDataExtentOnAxis(ecModel, axisRecordMap, seriesRecords);
+        calculateFilteredExtent(axisRecordMap, seriesRecords);
+        shrinkAxisExtent(axisRecordMap);
+    }
+});
+
+function prepareDataExtentOnAxis(
+    ecModel: GlobalModel,
+    axisRecordMap: HashMap<AxisRecord>,
+    seriesRecords: SeriesRecord[]
+): void {
+    ecModel.eachSeries(function (seriesModel: SeriesModel) {
+        if (!isCartesian2DSeries(seriesModel)) {
+            return;
+        }
+
+        const axesModelMap = findAxisModels(seriesModel);
+        const xAxisModel = axesModelMap.xAxisModel;
+        const yAxisModel = axesModelMap.yAxisModel;
+        const xAxis = xAxisModel.axis;
+        const yAxis = yAxisModel.axis;
+        const xRawExtentInfo = xAxis.scale.rawExtentInfo;
+        const yRawExtentInfo = yAxis.scale.rawExtentInfo;
+        const data = seriesModel.getData();
+
+        // If either axis controlled by other filter like "dataZoom",
+        // use the rule of dataZoom rather than adopting the rules here.
+        if (
+            (xRawExtentInfo && xRawExtentInfo.frozen)
+            || (yRawExtentInfo && yRawExtentInfo.frozen)
+        ) {
+            return;
+        }
+
+        seriesRecords.push({
+            seriesModel: seriesModel,
+            xAxisModel: xAxisModel,
+            yAxisModel: yAxisModel
+        });
+
+        // FIXME: this logic needs to be consistent with
+        // `coord/cartesian/Grid.ts#_updateScale`.
+        // It's not good to implement one logic in multiple places.
+        unionAxisExtentFromData(prepareAxisRecord(axisRecordMap, xAxisModel).condExtent, data, xAxis.dim);
+        unionAxisExtentFromData(prepareAxisRecord(axisRecordMap, yAxisModel).condExtent, data, yAxis.dim);
+    });
+}
+
+function calculateFilteredExtent(
+    axisRecordMap: HashMap<AxisRecord>,
+    seriesRecords: SeriesRecord[]
+) {
+    each(seriesRecords, function (seriesRecord) {
+        const xAxisModel = seriesRecord.xAxisModel;
+        const yAxisModel = seriesRecord.yAxisModel;
+        const xAxis = xAxisModel.axis;
+        const yAxis = yAxisModel.axis;
+        const xAxisRecord = prepareAxisRecord(axisRecordMap, xAxisModel);
+        const yAxisRecord = prepareAxisRecord(axisRecordMap, yAxisModel);
+        xAxisRecord.rawExtentInfo = ensureScaleRawExtentInfo(
+            xAxis.scale, xAxisModel, xAxisRecord.condExtent
+        );
+        yAxisRecord.rawExtentInfo = ensureScaleRawExtentInfo(
+            yAxis.scale, yAxisModel, yAxisRecord.condExtent
+        );
+        xAxisRecord.rawExtentResult = xAxisRecord.rawExtentInfo.calculate();
+        yAxisRecord.rawExtentResult = yAxisRecord.rawExtentInfo.calculate();
+
+        // If the "xAxis" is set `min`/`max`, some data items might be out of the cartesian.
+        // then the "yAxis" may needs to calculate extent only based on the data items inside
+        // the cartesian (similar to what "dataZoom" did).
+        // A typical case is bar-racing, where bars ara sort dynamically and may only need to
+        // displayed part of the whole bars.
+
+        const data = seriesRecord.seriesModel.getData();
+        // For duplication removal.
+        const condDimMap: Dictionary<boolean> = {};
+        const tarDimMap: Dictionary<boolean> = {};
+        let condAxisExtent: number[];
+        let tarAxisRecord: AxisRecord;
+
+        function addCondition(axis: Axis, axisRecord: AxisRecord) {
+            // But for simplicity and safty and performance, we only adopt this
+            // feature on category axis at present.
+            const condExtent = axisRecord.condExtent;
+            const rawExtentResult = axisRecord.rawExtentResult;
+            if (axis.type === 'category'
+                && (condExtent[0] < rawExtentResult.min || rawExtentResult.max < condExtent[1])
+            ) {
+                each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) {
+                    if (!hasOwn(condDimMap, dataDim)) {
+                        condDimMap[dataDim] = true;
+                        condAxisExtent = [rawExtentResult.min, rawExtentResult.max];
+                    }
+                });
+            }
+        }
+        function addTarget(axis: Axis, axisRecord: AxisRecord) {
+            const rawExtentResult = axisRecord.rawExtentResult;
+            if (axis.type !== 'category'
+                && (!rawExtentResult.minFixed || !rawExtentResult.maxFixed)
+            ) {
+                each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) {
+                    if (!hasOwn(condDimMap, dataDim) && !hasOwn(tarDimMap, dataDim)) {
+                        tarDimMap[dataDim] = true;
+                        tarAxisRecord = axisRecord;
+                    }
+                });
+            }
+        }
+
+        addCondition(xAxis, xAxisRecord);
+        addCondition(yAxis, yAxisRecord);
+        addTarget(xAxis, xAxisRecord);
+        addTarget(yAxis, yAxisRecord);
+
+        const condDims = keys(condDimMap);
+        const tarDims = keys(tarDimMap);
+        const tarDimExtents = map(tarDims, function () {
+            return initExtent();
+        });
+
+        const condDimsLen = condDims.length;
+        const tarDimsLen = tarDims.length;
+
+        if (!condDimsLen || !tarDimsLen) {
+            return;
+        }
+
+        const singleCondDim = condDimsLen === 1 ? condDims[0] : null;
+        const singleTarDim = tarDimsLen === 1 ? tarDims[0] : null;
+        const dataLen = data.count();
+
+        // Time consuming, because this is a "block task".
+        // Simple optimization for the vast majority of cases.
+        if (singleCondDim && singleTarDim) {
+            for (let dataIdx = 0; dataIdx < dataLen; dataIdx++) {
+                const condVal = data.get(singleCondDim, dataIdx) as number;
+                if (condVal >= condAxisExtent[0] && condVal <= condAxisExtent[1]) {
+                    unionExtent(tarDimExtents[0], data.get(singleTarDim, dataIdx) as number);
+                }
+            }
+        }
+        else {
+            for (let dataIdx = 0; dataIdx < dataLen; dataIdx++) {
+                for (let j = 0; j < condDimsLen; j++) {
+                    const condVal = data.get(condDims[j], dataIdx) as number;
+                    if (condVal >= condAxisExtent[0] && condVal <= condAxisExtent[1]) {
+                        for (let k = 0; k < tarDimsLen; k++) {
+                            unionExtent(tarDimExtents[k], data.get(tarDims[k], dataIdx) as number);
+                        }
+                        // Any one dim is in range means satisfied.
+                        break;
+                    }
+                }
+            }
+        }
+
+        each(tarDimExtents, function (tarDimExtent, i) {
+            const dim = tarDims[i];
+            // FIXME: if there has been approximateExtent set?
+            data.setApproximateExtent(tarDimExtent as [number, number], dim);
+            const tarAxisExtent = tarAxisRecord.tarExtent = tarAxisRecord.tarExtent || initExtent();
+            unionExtent(tarAxisExtent, tarDimExtent[0]);
+            unionExtent(tarAxisExtent, tarDimExtent[1]);
+        });
+    });
+}
+
+function shrinkAxisExtent(axisRecordMap: HashMap<AxisRecord>) {
+    axisRecordMap.each(function (axisRecord) {
+        const tarAxisExtent = axisRecord.tarExtent;
+        if (tarAxisExtent) {
+            const rawExtentResult = axisRecord.rawExtentResult;
+            const rawExtentInfo = axisRecord.rawExtentInfo;
+            // Shink the original extent.
+            if (!rawExtentResult.minFixed && tarAxisExtent[0] > rawExtentResult.min) {
+                rawExtentInfo.modifyDataMinMax('min', tarAxisExtent[0]);
+            }
+            if (!rawExtentResult.maxFixed && tarAxisExtent[1] < rawExtentResult.max) {
+                rawExtentInfo.modifyDataMinMax('max', tarAxisExtent[1]);
+            }
+        }
+    });
+}
+
+function prepareAxisRecord(
+    axisRecordMap: HashMap<AxisRecord>,
+    axisModel: AxisBaseModel
+): AxisRecord {
+    return axisRecordMap.get(axisModel.uid)
+        || axisRecordMap.set(axisModel.uid, { condExtent: initExtent() });
+}
+
+function initExtent() {
+    return [Infinity, -Infinity];
+}
+
+function unionExtent(extent: number[], val: number) {
+    val < extent[0] && (extent[0] = val);
+    val > extent[1] && (extent[1] = val);
+}
diff --git a/test/axis-filter-extent.html b/test/axis-filter-extent.html
new file mode 100644
index 0000000..a6ef027
--- /dev/null
+++ b/test/axis-filter-extent.html
@@ -0,0 +1,422 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/esl.js"></script>
+        <script src="lib/config.js"></script>
+        <script src="lib/jquery.min.js"></script>
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+
+        <div id="main-no-dataZoom"></div>
+        <div id="main-has-dataZoom-x"></div>
+        <div id="main-has-dataZoom-y"></div>
+        <div id="main-has-stack"></div>
+        <div id="main-has-dataZoom-y-stack"></div>
+
+
+        <script>
+            var TOTAL_HEIGHT = 1200;
+
+            /**
+             * @param opt: {
+             *     dataZoomX: boolean;
+             *     dataZoomY: boolean;
+             *     stack: boolean;
+             * }
+             */
+            function makeMultiCartesian(echarts, opt) {
+                var gridHeight = 100;
+                var currTop = 40;
+                var gap = 80;
+
+                var option = {
+                    grid: [],
+                    xAxis: [],
+                    yAxis: [],
+                    series: [],
+                    dataZoom: []
+                };
+
+                function makeCartesian(option, partialOption, label) {
+                    option.grid.push({
+                        top: currTop,
+                        height: gridHeight
+                    });
+
+                    option.xAxis.push(echarts.util.defaults({
+                        gridIndex: option.grid.length - 1
+                    }, partialOption.xAxis));
+
+                    option.yAxis.push(echarts.util.defaults({
+                        name: label[
+                            opt.dataZoomX ? 'dataZoomX' :
+                            opt.dataZoomY ? 'dataZoomY' :
+                            'noDataZoom'
+                        ],
+                        nameTextStyle: {
+                            align: 'left'
+                        },
+                        gridIndex: option.grid.length - 1
+                    }, partialOption.yAxis));
+
+                    var xAxisIndex = option.xAxis.length - 1;
+                    var yAxisIndex = option.yAxis.length - 1;
+
+                    var seriesList = partialOption.seriesList[opt.stack ? 'stackHas' : 'stackNon'];
+                    echarts.util.each(seriesList, function (series) {
+                        // FIXME:
+                        // currently (20200619) if series.stack is the same but series
+                        // on different grid, that would get wrong result.
+                        if (opt.stack) {
+                            series.stack = series.stack + '__' + xAxisIndex + '_' + yAxisIndex;
+                        }
+                        option.series.push(echarts.util.defaults({
+                            label: { show: true },
+                            itemStyle: {
+                                opacity: 0.8
+                            },
+                            xAxisIndex: xAxisIndex,
+                            yAxisIndex: yAxisIndex
+                        }, series));
+                    });
+
+                    if (opt.dataZoomX) {
+                        option.dataZoom.push({
+                            type: 'slider',
+                            filterMode: 'none',
+                            height: 15,
+                            top: currTop + gridHeight + 20,
+                            xAxisIndex: xAxisIndex
+                        }, {
+                            type: 'inside',
+                            filterMode: 'none',
+                            xAxisIndex: xAxisIndex
+                        });
+                    }
+                    if (opt.dataZoomY) {
+                        option.dataZoom.push({
+                            type: 'slider',
+                            filterMode: 'none',
+                            yAxisIndex: yAxisIndex
+                        }, {
+                            type: 'inside',
+                            filterMode: 'none',
+                            yAxisIndex: yAxisIndex
+                        });
+                    }
+
+                    currTop += gridHeight + gap;
+                }
+
+                // ---------------------------------------
+                // Cases in a single chart instance BEGIN
+                // ---------------------------------------
+
+                makeCartesian(option, {
+                    xAxis: {
+                        type: 'category'
+                    },
+                    yAxis: {
+                    },
+                    seriesList: {
+                        stackNon: [{
+                            type: 'bar',
+                            data: [['a', 22], ['b', 52], ['c', 659]]
+                        }],
+                        stackHas: [{
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 12], ['b', 32], ['c', 200]]
+                        }, {
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 10], ['b', 20], ['c', 459]]
+                        }]
+                    }
+                }, {
+                    noDataZoom: 'y-min: 0, y-max: niced from 659, x-min: "a", x-max: "c"',
+                    dataZoomX: 'y-min: 0, y-max: niced from 659, x-min: "a", x-max: "c"',
+                    dataZoomY: 'y-min: 0, y-max: niced from 659, x-min: "a", x-max: "c"',
+                });
+
+                makeCartesian(option, {
+                    xAxis: {
+                        type: 'category',
+                        max: 1
+                    },
+                    yAxis: {
+                    },
+                    seriesList: {
+                        stackNon: [{
+                            type: 'bar',
+                            data: [['a', 22], ['b', 52], ['c', 959]]
+                        }],
+                        stackHas: [{
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 12], ['b', 32], ['c', 359]]
+                        }, {
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 10], ['b', 20], ['c', 600]]
+                        }]
+                    }
+                }, {
+                    noDataZoom: 'y-min: 0, y-max: niced from 52, x-min: "a", x-max: "b"',
+                    dataZoomX: 'y-min: 0, y-max: niced from 959, x-min: "a", x-max: "b"',
+                    dataZoomY: 'y-min: 0, y-max: niced from 959, x-min: "a", x-max: "b"'
+                });
+
+                makeCartesian(option, {
+                    xAxis: {
+                        type: 'category',
+                        max: 2,
+                        min: 1
+                    },
+                    yAxis: {
+                    },
+                    seriesList: {
+                        stackNon: [{
+                            type: 'bar',
+                            data: [['a', 959], ['b', 22], ['c', 52], ['d', -959]]
+                        }],
+                        stackHas: [{
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 300], ['b', 12], ['c', 32], ['d', -259]]
+                        }, {
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 659], ['b', 10], ['c', 20], ['d', -700]]
+                        }],
+                    }
+                }, {
+                    noDataZoom: 'y-min: 0, y-max: niced from 52, x-min: "b", x-max: "c"',
+                    dataZoomX: 'y-min: niced from -959, y-max: niced from 959, x-min: "b", x-max: "c"',
+                    dataZoomY: 'y-min: niced from -959, y-max: niced from 959, x-min: "b", x-max: "c"'
+                });
+
+                makeCartesian(option, {
+                    xAxis: {
+                        type: 'category',
+                        max: 2,
+                        min: 1
+                    },
+                    yAxis: {
+                        max: 500
+                    },
+                    seriesList: {
+                        stackNon: [{
+                            type: 'bar',
+                            data: [['a', 959], ['b', 22], ['c', 52], ['d', -959]]
+                        }],
+                        stackHas: [{
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 159], ['b', 2], ['c', 7], ['d', -59]]
+                        }, {
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 800], ['b', 20], ['c', 45], ['d', -900]]
+                        }]
+                    }
+                }, {
+                    noDataZoom: 'y-min: 0, y-max: 500, x-min: "b", x-max: "c"',
+                    dataZoomX: 'y-min: niced from -959, y-max: 500, x-min: "b", x-max: "c"',
+                    dataZoomY: 'y-min: niced from -959, y-max: 500, x-min: "b", x-max: "c"'
+                });
+
+                makeCartesian(option, {
+                    xAxis: {
+                        type: 'category',
+                        min: 1
+                    },
+                    yAxis: {
+                        scale: true
+                    },
+                    seriesList: {
+                        stackNon: [{
+                            type: 'line',
+                            areaStyle: {},
+                            data: [['a', 359], ['b', 122], ['c', 152]]
+                        }],
+                        stackHas: [{
+                            type: 'line',
+                            stack: 's',
+                            data: [['a', 159], ['b', 62], ['c', 100]]
+                        }, {
+                            type: 'line',
+                            stack: 's',
+                            areaStyle: {},
+                            data: [['a', 200], ['b', 60], ['c', 52]]
+                        }]
+                    }
+                }, {
+                    noDataZoom: '(yAxis.scale: true) y-min: niced from (noStack ? 122 : 62), y-max: niced from 152, x-min: "b", x-max: "c"',
+                    dataZoomX: '(yAxis.scale: true) y-min: niced from (noStack ? 122 : 62), y-max: niced from 359, x-min: "b", x-max: "c"',
+                    dataZoomY: '(yAxis.scale: true) y-min: niced from (noStack ? 122 : 62), y-max: niced from 359, x-min: "b", x-max: "c"'
+                });
+
+                makeCartesian(option, {
+                    xAxis: {
+                        type: 'category',
+                        min: 1,
+                        max: 2
+                    },
+                    yAxis: {
+                        boundaryGap: ['50%', '50%']
+                    },
+                    seriesList: {
+                        stackNon: [{
+                            type: 'bar',
+                            data: [['a', 559], ['b', 82], ['c', 152], ['d', -559]]
+                        }],
+                        stackHas: [{
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 159], ['b', 22], ['c', 52], ['d', -159]]
+                        }, {
+                            type: 'bar',
+                            stack: 's',
+                            data: [['a', 400], ['b', 60], ['c', 100], ['d', -459]]
+                        }]
+                    }
+                }, {
+                    // 187 = 152 + .5 * (152 - 82)
+                    // 217 = 152 + .5 * (152 - 22)
+                    // -43 = 22-.5 * (152 - 22)
+                    noDataZoom: '(boundaryGap: [.5, .5]) y-min: (noStack ? 0 : -43), y-max: niced from (noStack ? 187 : 217), x-min: "b", x-max: "c"',
+                    dataZoomX: '(boundaryGap: [.5, .5]) y-min: -1118, y-max: niced from 1118, x-min: "b", x-max: "c"',
+                    dataZoomY: '(boundaryGap: [.5, .5]) y-min: -1118, y-max: niced from 1118, x-min: "b", x-max: "c"'
+                });
+
+                // -------------------------------------
+                // Cases in a single chart instance END
+                // -------------------------------------
+
+                return option;
+            }
+        </script>
+
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option = makeMultiCartesian(echarts, {});
+
+            var chart = testHelper.create(echarts, 'main-no-dataZoom', {
+                title: [
+                    'Check xAxis, yAxis min/max'
+                ],
+                option: option,
+                height: TOTAL_HEIGHT
+            });
+        });
+        </script>
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option = makeMultiCartesian(echarts, {
+                dataZoomX: true
+            });
+
+            var chart = testHelper.create(echarts, 'main-has-dataZoom-x', {
+                title: [
+                    '[has **dataZoom on X** filterMode: "none"] Check xAxis, yAxis min/max'
+                ],
+                option: option,
+                height: TOTAL_HEIGHT
+            });
+        });
+        </script>
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option = makeMultiCartesian(echarts, {
+                dataZoomY: true
+            });
+
+            var chart = testHelper.create(echarts, 'main-has-dataZoom-y', {
+                title: [
+                    '[has **dataZoom on Y** filterMode: "none"] Check xAxis, yAxis min/max'
+                ],
+                option: option,
+                height: TOTAL_HEIGHT
+            });
+        });
+        </script>
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option = makeMultiCartesian(echarts, {
+                stack: true
+            });
+
+            var chart = testHelper.create(echarts, 'main-has-stack', {
+                title: [
+                    '[has **stack**] Check xAxis, yAxis min/max'
+                ],
+                option: option,
+                height: TOTAL_HEIGHT
+            });
+        });
+        </script>
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option = makeMultiCartesian(echarts, {
+                stack: true,
+                dataZoomY: true
+            });
+
+            var chart = testHelper.create(echarts, 'main-has-dataZoom-y-stack', {
+                title: [
+                    '[has **dataZoom on Y** has **stack**] Check xAxis, yAxis min/max'
+                ],
+                option: option,
+                height: TOTAL_HEIGHT
+            });
+        });
+        </script>
+
+
+    </body>
+</html>
+


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