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 2018/04/17 20:04:34 UTC

[incubator-echarts] branch master updated (c05418c -> 364720b)

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

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


    from c05418c  typo
     new e22c5e9  Limit min shadow width for axisPointer.
     new df46e28  Enhance dataZoom: do not trigger if range not changed, otherwise cause bad effect when progressive rendering.
     new 364720b  Support large bar for some cases (to the data amount of 2e5).

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/chart/bar.js                                  |  16 +--
 src/chart/bar/BarSeries.js                        |  26 +++-
 src/chart/bar/BarView.js                          |  99 ++++++++++++++-
 src/chart/bar/BaseBarSeries.js                    |   5 +
 src/chart/bar/helper.js                           |   2 +-
 src/chart/candlestick/CandlestickView.js          |  15 +--
 src/component/axisPointer/CartesianAxisPointer.js |   2 +-
 src/component/axisPointer/PolarAxisPointer.js     |   2 +-
 src/component/dataZoom/InsideZoomView.js          |  28 +++--
 src/component/dataZoom/SliderZoomView.js          |  16 ++-
 src/component/dataZoom/roams.js                   |  16 +--
 src/coord/axisHelper.js                           |  30 ++---
 src/echarts.js                                    |  11 +-
 src/layout/barGrid.js                             | 140 ++++++++++++++++++----
 src/util/throttle.js                              |   8 ++
 test/bar-large1.html                              | 132 ++++++++++++++++++++
 test/candlestick-large2.html                      | 123 ++++++++++---------
 17 files changed, 511 insertions(+), 160 deletions(-)
 create mode 100644 test/bar-large1.html

-- 
To stop receiving notification emails like this one, please contact
sushuang@apache.org.

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


[incubator-echarts] 01/03: Limit min shadow width for axisPointer.

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e22c5e91a60a100da97de8f03f9ab28e30002a92
Author: sushuang <su...@gmail.com>
AuthorDate: Wed Apr 18 00:23:04 2018 +0800

    Limit min shadow width for axisPointer.
---
 src/component/axisPointer/CartesianAxisPointer.js | 2 +-
 src/component/axisPointer/PolarAxisPointer.js     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/component/axisPointer/CartesianAxisPointer.js b/src/component/axisPointer/CartesianAxisPointer.js
index 9963885..98686bd 100644
--- a/src/component/axisPointer/CartesianAxisPointer.js
+++ b/src/component/axisPointer/CartesianAxisPointer.js
@@ -103,7 +103,7 @@ var pointerShapeBuilder = {
     },
 
     shadow: function (axis, pixelValue, otherExtent, elStyle) {
-        var bandWidth = axis.getBandWidth();
+        var bandWidth = Math.max(1, axis.getBandWidth());
         var span = otherExtent[1] - otherExtent[0];
         return {
             type: 'Rect',
diff --git a/src/component/axisPointer/PolarAxisPointer.js b/src/component/axisPointer/PolarAxisPointer.js
index 02e09ab..50c3afe 100644
--- a/src/component/axisPointer/PolarAxisPointer.js
+++ b/src/component/axisPointer/PolarAxisPointer.js
@@ -110,7 +110,7 @@ var pointerShapeBuilder = {
     },
 
     shadow: function (axis, polar, coordValue, otherExtent, elStyle) {
-        var bandWidth = axis.getBandWidth();
+        var bandWidth = Math.max(1, axis.getBandWidth());
         var radian = Math.PI / 180;
 
         return axis.dim === 'angle'

-- 
To stop receiving notification emails like this one, please contact
sushuang@apache.org.

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


[incubator-echarts] 03/03: Support large bar for some cases (to the data amount of 2e5).

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 364720ba254540679f15d4b16d3f92bb03507579
Author: sushuang <su...@gmail.com>
AuthorDate: Wed Apr 18 04:03:48 2018 +0800

    Support large bar for some cases (to the data amount of 2e5).
---
 src/chart/bar.js                         |  16 ++--
 src/chart/bar/BarSeries.js               |  26 +++++-
 src/chart/bar/BarView.js                 |  99 ++++++++++++++++++++--
 src/chart/bar/BaseBarSeries.js           |   5 ++
 src/chart/bar/helper.js                  |   2 +-
 src/chart/candlestick/CandlestickView.js |  15 ++--
 src/coord/axisHelper.js                  |  30 +++----
 src/echarts.js                           |  11 ++-
 src/layout/barGrid.js                    | 140 +++++++++++++++++++++++++------
 test/bar-large1.html                     | 132 +++++++++++++++++++++++++++++
 test/candlestick-large2.html             | 123 ++++++++++++++-------------
 11 files changed, 471 insertions(+), 128 deletions(-)

diff --git a/src/chart/bar.js b/src/chart/bar.js
index 7879572..21e7eee 100644
--- a/src/chart/bar.js
+++ b/src/chart/bar.js
@@ -1,6 +1,6 @@
 import * as echarts from '../echarts';
 import * as zrUtil from 'zrender/src/core/util';
-import { layout } from '../layout/barGrid';
+import {layout, largeLayout} from '../layout/barGrid';
 
 import '../coord/cartesian/Grid';
 import './bar/BarSeries';
@@ -10,11 +10,13 @@ import '../component/gridSimple';
 
 
 echarts.registerLayout(zrUtil.curry(layout, 'bar'));
+// Should after normal bar layout, otherwise it is blocked by normal bar layout.
+echarts.registerLayout(largeLayout);
 
-// Visual coding for legend
-echarts.registerVisual(function (ecModel) {
-    ecModel.eachSeriesByType('bar', function (seriesModel) {
-        var data = seriesModel.getData();
-        data.setVisual('legendSymbol', 'roundRect');
-    });
+echarts.registerVisual({
+    seriesType: 'bar',
+    reset: function (seriesModel) {
+        // Visual coding for legend
+        seriesModel.getData().setVisual('legendSymbol', 'roundRect');
+    }
 });
diff --git a/src/chart/bar/BarSeries.js b/src/chart/bar/BarSeries.js
index 6f5d2f8..2c46956 100644
--- a/src/chart/bar/BarSeries.js
+++ b/src/chart/bar/BarSeries.js
@@ -6,5 +6,29 @@ export default BaseBarSeries.extend({
 
     dependencies: ['grid', 'polar'],
 
-    brushSelector: 'rect'
+    brushSelector: 'rect',
+
+    /**
+     * @override
+     */
+    getProgressive: function () {
+        // Do not support progressive in normal mode.
+        return this.get('large')
+            ? this.get('progressive')
+            : false;
+    },
+
+    /**
+     * @override
+     */
+    getProgressiveThreshold: function () {
+        // Do not support progressive in normal mode.
+        var progressiveThreshold = this.get('progressiveThreshold');
+        var largeThreshold = this.get('largeThreshold');
+        if (largeThreshold > progressiveThreshold) {
+            progressiveThreshold = largeThreshold;
+        }
+        return progressiveThreshold;
+    }
+
 });
diff --git a/src/chart/bar/BarView.js b/src/chart/bar/BarView.js
index 7fd05b8..01ad899 100644
--- a/src/chart/bar/BarView.js
+++ b/src/chart/bar/BarView.js
@@ -5,7 +5,7 @@ import * as graphic from '../../util/graphic';
 import {setLabel} from './helper';
 import Model from '../../model/Model';
 import barItemStyle from './barItemStyle';
-
+import Path from 'zrender/src/graphic/Path';
 
 var BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];
 
@@ -18,12 +18,16 @@ export default echarts.extendChartView({
     type: 'bar',
 
     render: function (seriesModel, ecModel, api) {
+        this._updateDrawMode(seriesModel);
+
         var coordinateSystemType = seriesModel.get('coordinateSystem');
 
         if (coordinateSystemType === 'cartesian2d'
             || coordinateSystemType === 'polar'
         ) {
-            this._render(seriesModel, ecModel, api);
+            this._isLargeDraw
+                ? this._renderLarge(seriesModel, ecModel, api)
+                : this._renderNormal(seriesModel, ecModel, api);
         }
         else if (__DEV__) {
             console.warn('Only cartesian2d and polar supported for bar.');
@@ -32,9 +36,25 @@ export default echarts.extendChartView({
         return this.group;
     },
 
-    dispose: zrUtil.noop,
+    incrementalPrepareRender: function (seriesModel, ecModel, api) {
+        this._clear();
+        this._updateDrawMode(seriesModel);
+    },
+
+    incrementalRender: function (params, seriesModel, ecModel, api) {
+        // Do not support progressive in normal mode.
+        this._incrementalRenderLarge(params, seriesModel);
+    },
+
+    _updateDrawMode: function (seriesModel) {
+        var isLargeDraw = seriesModel.pipelineContext.large;
+        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {
+            this._isLargeDraw = isLargeDraw;
+            this._clear();
+        }
+    },
 
-    _render: function (seriesModel, ecModel, api) {
+    _renderNormal: function (seriesModel, ecModel, api) {
         var group = this.group;
         var data = seriesModel.getData();
         var oldData = this._data;
@@ -114,10 +134,25 @@ export default echarts.extendChartView({
         this._data = data;
     },
 
-    remove: function (ecModel, api) {
+    _renderLarge: function (seriesModel, ecModel, api) {
+        this._clear();
+        createLarge(seriesModel, this.group);
+    },
+
+    _incrementalRenderLarge: function (params, seriesModel) {
+        createLarge(seriesModel, this.group, true);
+    },
+
+    dispose: zrUtil.noop,
+
+    remove: function (ecModel) {
+        this._clear(ecModel);
+    },
+
+    _clear: function (ecModel) {
         var group = this.group;
         var data = this._data;
-        if (ecModel.get('animation')) {
+        if (ecModel && ecModel.get('animation')) {
             if (data) {
                 data.eachItemGraphicEl(function (el) {
                     if (el.type === 'sector') {
@@ -132,7 +167,9 @@ export default echarts.extendChartView({
         else {
             group.removeAll();
         }
+        this._data = null;
     }
+
 });
 
 var elementCreator = {
@@ -282,3 +319,53 @@ function getLineWidth(itemModel, rawLayout) {
     var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;
     return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));
 }
+
+
+var LargePath = Path.extend({
+
+    type: 'largeBar',
+
+    shape: {points: []},
+
+    buildPath: function (ctx, shape) {
+        // Drawing lines is more efficient than drawing
+        // a whole line or drawing rects.
+        var points = shape.points;
+        var startPoint = this.__startPoint;
+        var valueIdx = this.__valueIdx;
+
+        for (var i = 0; i < points.length; i += 2) {
+            startPoint[this.__valueIdx] = points[i + valueIdx];
+            ctx.moveTo(startPoint[0], startPoint[1]);
+            ctx.lineTo(points[i], points[i + 1]);
+        }
+    }
+});
+
+function createLarge(seriesModel, group, incremental) {
+    // TODO support polar
+    var data = seriesModel.getData();
+    var startPoint = [];
+    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;
+    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');
+
+    var el = new LargePath({
+        shape: {points: data.getLayout('largePoints')},
+        incremental: !!incremental,
+        __startPoint: startPoint,
+        __valueIdx: valueIdx
+    });
+    group.add(el);
+    setLargeStyle(el, seriesModel, data);
+}
+
+function setLargeStyle(el, seriesModel, data) {
+    var borderColor = data.getVisual('borderColor') || data.getVisual('color');
+    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);
+
+    el.useStyle(itemStyle);
+    el.style.fill = null;
+    el.style.stroke = borderColor;
+    el.style.lineWidth = data.getLayout('barWidth');
+}
+
diff --git a/src/chart/bar/BaseBarSeries.js b/src/chart/bar/BaseBarSeries.js
index 269deeb..46d18f5 100644
--- a/src/chart/bar/BaseBarSeries.js
+++ b/src/chart/bar/BaseBarSeries.js
@@ -41,6 +41,11 @@ export default SeriesModel.extend({
         barMinAngle: 0,
         // cursor: null,
 
+        large: false,
+        largeThreshold: 400,
+        progressive: 5e3,
+        progressiveChunkMode: 'mod',
+
         // barMaxWidth: null,
         // 默认自适应
         // barWidth: null,
diff --git a/src/chart/bar/helper.js b/src/chart/bar/helper.js
index e4ebed5..60530ac 100644
--- a/src/chart/bar/helper.js
+++ b/src/chart/bar/helper.js
@@ -26,4 +26,4 @@ function fixPosition(style, labelPositionOutside) {
     if (style.textPosition === 'outside') {
         style.textPosition = labelPositionOutside;
     }
-}
\ No newline at end of file
+}
diff --git a/src/chart/candlestick/CandlestickView.js b/src/chart/candlestick/CandlestickView.js
index 4200c1c..511dcca 100644
--- a/src/chart/candlestick/CandlestickView.js
+++ b/src/chart/candlestick/CandlestickView.js
@@ -103,11 +103,8 @@ var CandlestickView = ChartView.extend({
     },
 
     _renderLarge: function (seriesModel) {
-        var group = this.group;
-
-        group.removeAll();
-
-        createLarge(seriesModel, group);
+        this._clear();
+        createLarge(seriesModel, this.group);
     },
 
     _incrementalRenderNormal: function (params, seriesModel) {
@@ -264,15 +261,13 @@ function createLarge(seriesModel, group, incremental) {
 }
 
 function setLargeStyle(sign, el, seriesModel, data) {
-    var normalItemStyleModel = seriesModel.getModel(NORMAL_ITEM_STYLE_PATH);
     var suffix = sign > 0 ? 'P' : 'N';
-
-    var color = data.getVisual('color' + suffix);
-    var borderColor = data.getVisual('borderColor' + suffix) || color;
+    var borderColor = data.getVisual('borderColor' + suffix)
+        || data.getVisual('color' + suffix);
 
     // Color must be excluded.
     // Because symbol provide setColor individually to set fill and stroke
-    var itemStyle = normalItemStyleModel.getItemStyle(SKIP_PROPS);
+    var itemStyle = seriesModel.getModel(NORMAL_ITEM_STYLE_PATH).getItemStyle(SKIP_PROPS);
 
     el.useStyle(itemStyle);
     el.style.fill = null;
diff --git a/src/coord/axisHelper.js b/src/coord/axisHelper.js
index d7c14e0..a424ca6 100644
--- a/src/coord/axisHelper.js
+++ b/src/coord/axisHelper.js
@@ -4,7 +4,11 @@ import OrdinalScale from '../scale/Ordinal';
 import IntervalScale from '../scale/Interval';
 import Scale from '../scale/Scale';
 import * as numberUtil from '../util/number';
-import {calBarWidthAndOffset} from '../layout/barGrid';
+import {
+    prepareLayoutBarSeries,
+    makeColumnLayout,
+    retrieveColumnLayout
+} from '../layout/barGrid';
 import BoundingRect from 'zrender/src/core/BoundingRect';
 
 import '../scale/Time';
@@ -120,26 +124,26 @@ export function getScaleExtent(scale, model) {
     // is base axis
     // FIXME
     // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.
-    // (2) Refactor the logic with `barGrid`. Is it not need to `calBarWidthAndOffset` twice with different extent?
+    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?
     //     Should not depend on series type `bar`?
     // (3) Fix that might overlap when using dataZoom.
     // (4) Consider other chart types using `barGrid`?
     // See #6728, #4862, `test/bar-overflow-time-plot.html`
     var ecModel = model.ecModel;
     if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {
-        var barSeriesModels = [];
+        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);
         var isBaseAxisAndHasBarSeries;
 
-        ecModel.eachSeriesByType('bar', function (seriesModel) {
-            if (seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d') {
-                barSeriesModels.push(seriesModel);
-                isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;
-            }
+        zrUtil.each(barSeriesModels, function (seriesModel) {
+            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;
         });
 
         if (isBaseAxisAndHasBarSeries) {
+            // Calculate placement of bars on axis
+            var barWidthAndOffset = makeColumnLayout(barSeriesModels);
+
             // Adjust axis min and max to account for overflow
-            var adjustedScale = adjustScaleForOverflow(min, max, model, barSeriesModels);
+            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);
             min = adjustedScale.min;
             max = adjustedScale.max;
         }
@@ -148,18 +152,14 @@ export function getScaleExtent(scale, model) {
     return [min, max];
 }
 
-function adjustScaleForOverflow(min, max, model, barSeriesModels) {
+function adjustScaleForOverflow(min, max, model, barWidthAndOffset) {
 
     // Get Axis Length
     var axisExtent = model.axis.getExtent();
     var axisLength = axisExtent[1] - axisExtent[0];
 
-    // Calculate placement of bars on axis
-    var barWidthAndOffset = calBarWidthAndOffset(barSeriesModels);
-
     // Get bars on current base axis and calculate min and max overflow
-    var baseAxisKey = model.axis.dim + model.axis.index;
-    var barsOnCurrentAxis = barWidthAndOffset[baseAxisKey];
+    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);
     if (barsOnCurrentAxis === undefined) {
         return {min: min, max: max};
     }
diff --git a/src/echarts.js b/src/echarts.js
index eec6060..784216d 100644
--- a/src/echarts.js
+++ b/src/echarts.js
@@ -791,14 +791,17 @@ var updateMethods = {
 
         scheduler.performDataProcessorTasks(ecModel, payload);
 
-        coordSysMgr.update(ecModel, api);
-
         // Current stream render is not supported in data process. So we can update
         // stream modes after data processing, where the filtered data is used to
-        // deteming whether use progressive rendering. And we update stream modes
-        // after coordinate system updated, then full coord info can be fetched.
+        // deteming whether use progressive rendering.
         updateStreamModes(this, ecModel);
 
+        // We update stream modes before coordinate system updated, then the modes info
+        // can be fetched when coord sys updating (consider the barGrid extent fix). But
+        // the drawback is the full coord info can not be fetched. Fortunately this full
+        // coord is not requied in stream mode updater currently.
+        coordSysMgr.update(ecModel, api);
+
         clearColorPalette(ecModel);
         scheduler.performVisualTasks(ecModel, payload);
 
diff --git a/src/layout/barGrid.js b/src/layout/barGrid.js
index ba07b6d..f23c3fb 100644
--- a/src/layout/barGrid.js
+++ b/src/layout/barGrid.js
@@ -1,8 +1,12 @@
 import * as zrUtil from 'zrender/src/core/util';
 import {parsePercent} from '../util/number';
 import {isDimensionStacked} from '../data/helper/dataStackHelper';
+import createRenderPlanner from '../chart/helper/createRenderPlanner';
 
 var STACK_PREFIX = '__ec_stack_';
+var LARGE_BAR_MIN_WIDTH = 0.5;
+
+var LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;
 
 function getSeriesStackId(seriesModel) {
     return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;
@@ -22,7 +26,7 @@ function getAxisKey(axis) {
  * @param {number} [opt.barCategoryGap]
  * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.
  */
-export function getLayoutOnAxis(opt, api) {
+export function getLayoutOnAxis(opt) {
     var params = [];
     var baseAxis = opt.axis;
     var axisKey = 'axis0';
@@ -39,7 +43,7 @@ export function getLayoutOnAxis(opt, api) {
             stackId: STACK_PREFIX + i
         }, opt));
     }
-    var widthAndOffsets = doCalBarWidthAndOffset(params, api);
+    var widthAndOffsets = doCalBarWidthAndOffset(params);
 
     var result = [];
     for (var i = 0; i < opt.count; i++) {
@@ -51,8 +55,20 @@ export function getLayoutOnAxis(opt, api) {
     return result;
 }
 
-export function calBarWidthAndOffset(barSeries, api) {
-    var seriesInfoList = zrUtil.map(barSeries, function (seriesModel) {
+export function prepareLayoutBarSeries(seriesType, ecModel) {
+    var seriesModels = [];
+    ecModel.eachSeriesByType(seriesType, function (seriesModel) {
+        // Check series coordinate, do layout for cartesian2d only
+        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {
+            seriesModels.push(seriesModel);
+        }
+    });
+    return seriesModels;
+}
+
+export function makeColumnLayout(barSeries) {
+    var seriesInfoList = [];
+    zrUtil.each(barSeries, function (seriesModel) {
         var data = seriesModel.getData();
         var cartesian = seriesModel.coordinateSystem;
         var baseAxis = cartesian.getBaseAxis();
@@ -70,7 +86,7 @@ export function calBarWidthAndOffset(barSeries, api) {
         var barGap = seriesModel.get('barGap');
         var barCategoryGap = seriesModel.get('barCategoryGap');
 
-        return {
+        seriesInfoList.push({
             bandWidth: bandWidth,
             barWidth: barWidth,
             barMaxWidth: barMaxWidth,
@@ -78,13 +94,13 @@ export function calBarWidthAndOffset(barSeries, api) {
             barCategoryGap: barCategoryGap,
             axisKey: getAxisKey(baseAxis),
             stackId: getSeriesStackId(seriesModel)
-        };
+        });
     });
 
-    return doCalBarWidthAndOffset(seriesInfoList, api);
+    return doCalBarWidthAndOffset(seriesInfoList);
 }
 
-function doCalBarWidthAndOffset(seriesInfoList, api) {
+function doCalBarWidthAndOffset(seriesInfoList) {
     // Columns info on each category axis. Key is cartesian name
     var columnsMap = {};
 
@@ -198,21 +214,28 @@ function doCalBarWidthAndOffset(seriesInfoList, api) {
 }
 
 /**
+ * @param {Object} barWidthAndOffset The result of makeColumnLayout
+ * @param {module:echarts/coord/Axis} axis
+ * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.
+ * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.
+ */
+export function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {
+    if (barWidthAndOffset && axis) {
+        var result = barWidthAndOffset[getAxisKey(axis)];
+        if (result != null && seriesModel != null) {
+            return result[getSeriesStackId(seriesModel)];
+        }
+    }
+}
+
+/**
  * @param {string} seriesType
  * @param {module:echarts/model/Global} ecModel
- * @param {module:echarts/ExtensionAPI} api
  */
-export function layout(seriesType, ecModel, api) {
+export function layout(seriesType, ecModel) {
 
-    var seriesModels = [];
-    ecModel.eachSeriesByType(seriesType, function (seriesModel) {
-        // Check series coordinate, do layout for cartesian2d only
-        if (seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d') {
-            seriesModels.push(seriesModel);
-        }
-    });
-
-    var barWidthAndOffset = calBarWidthAndOffset(seriesModels);
+    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);
+    var barWidthAndOffset = makeColumnLayout(seriesModels);
 
     var lastStackCoords = {};
     var lastStackCoordsOrigin = {};
@@ -244,12 +267,7 @@ export function layout(seriesType, ecModel, api) {
         var stacked = isDimensionStacked(data, valueDim, baseDim);
         var isValueAxisH = valueAxis.isHorizontal();
 
-        var valueAxisStart = (
-                zrUtil.indexOf(baseAxis.getAxesOnZeroOf(), valueAxis) >= 0
-                || stacked
-            )
-            ? valueAxis.toGlobalCoord(valueAxis.dataToCoord(0))
-            : valueAxis.getGlobalExtent()[0];
+        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);
 
         for (var idx = 0, len = data.count(); idx < len; idx++) {
             var value = data.get(valueDim, idx);
@@ -318,4 +336,76 @@ export function layout(seriesType, ecModel, api) {
     }, this);
 }
 
+// TODO: Do not support stack in large mode yet.
+export var largeLayout = {
+
+    seriesType: 'bar',
+
+    plan: createRenderPlanner(),
 
+    reset: function (seriesModel) {
+        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {
+            return;
+        }
+
+        var data = seriesModel.getData();
+        var cartesian = seriesModel.coordinateSystem;
+        var baseAxis = cartesian.getBaseAxis();
+        var valueAxis = cartesian.getOtherAxis(baseAxis);
+        var valueDim = data.mapDimension(valueAxis.dim);
+        var baseDim = data.mapDimension(baseAxis.dim);
+        var valueAxisHorizontal = valueAxis.isHorizontal();
+        var valueDimIdx = valueAxisHorizontal ? 0 : 1;
+
+        var barWidth = retrieveColumnLayout(
+            makeColumnLayout([seriesModel]), baseAxis, seriesModel
+        ).width;
+        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line
+            barWidth = LARGE_BAR_MIN_WIDTH;
+        }
+
+        return {progress: progress};
+
+        function progress(params, data) {
+
+            var largePoints = new LargeArr(params.count * 2);
+            var dataIndex;
+            var coord = [];
+            var valuePair = [];
+            var offset = 0;
+
+            while ((dataIndex = params.next()) != null) {
+                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);
+                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);
+
+                coord = cartesian.dataToPoint(valuePair, null, coord);
+                largePoints[offset++] = coord[0];
+                largePoints[offset++] = coord[1];
+            }
+
+            data.setLayout({
+                largePoints: largePoints,
+                barWidth: barWidth,
+                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),
+                valueAxisHorizontal: valueAxisHorizontal
+            });
+        }
+    }
+};
+
+function isOnCartesian(seriesModel) {
+    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';
+}
+
+function isInLargeMode(seriesModel) {
+    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;
+}
+
+function getValueAxisStart(baseAxis, valueAxis, stacked) {
+    return (
+        zrUtil.indexOf(baseAxis.getAxesOnZeroOf(), valueAxis) >= 0
+        || stacked
+    )
+    ? valueAxis.toGlobalCoord(valueAxis.dataToCoord(0))
+    : valueAxis.getGlobalExtent()[0];
+}
diff --git a/test/bar-large1.html b/test/bar-large1.html
new file mode 100644
index 0000000..a2114b8
--- /dev/null
+++ b/test/bar-large1.html
@@ -0,0 +1,132 @@
+<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>
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+            .test-title {
+                background: #146402;
+                color: #fff;
+            }
+        </style>
+
+        <div id="main0"></div>
+
+        <script>
+
+            function ValueGenerator(baseValue) {
+                this._baseValue = baseValue;
+            }
+            ValueGenerator.prototype.next = function () {
+                var value = this._baseValue += Math.random() * 20 - 10;
+                return Math.max(0, Math.round(value) + 3000);
+            }
+
+            require([
+                'echarts'
+            ], function (echarts) {
+
+                var count = 5e5;
+                // var count = 1e6;
+
+                var xAxisData = [];
+                var data1 = [];
+                var data2 = [];
+                var generator1 = new ValueGenerator(Math.random() * 1000);
+                // var generator2 = new ValueGenerator(Math.random() * 5000);
+
+                for (var i = 0; i < count; i++) {
+                    xAxisData.push('category' + i);
+                    data1.push(generator1.next().toFixed(2));
+                    // data2.push(generator2.next().toFixed(2));
+                }
+
+                var option = {
+                    title: {
+                        text: echarts.format.addCommas(count) + ' Bars',
+                        left: 10
+                    },
+                    legend: {
+                        data: ['bar', 'bar2', 'bar3', 'bar4'],
+                        align: 'left'
+                    },
+                    toolbox: {
+                        // y: 'bottom',
+                        feature: {
+                            magicType: {
+                                type: ['line', 'bar', 'stack', 'tiled']
+                            },
+                            dataZoom: {
+                                yAxisIndex: false
+                            },
+                            dataView: {},
+                            saveAsImage: {
+                                pixelRatio: 2
+                            }
+                        }
+                    },
+                    tooltip: {
+                        trigger: 'axis',
+                        axisPointer: {
+                            type: 'shadow'
+                        }
+                    },
+                    dataZoom: [{
+                        // startValue: 48,
+                        // endValue: 99,
+                        type: 'inside'
+                    }, {
+                        // startValue: 48,
+                        // endValue: 99,
+                        type: 'slider'
+                    }],
+                    xAxis: {
+                        data: xAxisData,
+                        silent: false,
+                        splitLine: {
+                            show: false
+                        },
+                        splitArea: {
+                            show: false
+                        }
+                    },
+                    yAxis: {
+                        splitArea: {
+                            show: false
+                        }
+                    },
+                    series: [{
+                        name: 'bar',
+                        type: 'bar',
+                        // stack: 'one',
+                        data: data1,
+                        itemStyle: {
+                            color: 'green'
+                            // borderColor: 'yellow'
+                        },
+                        large: true
+                        // progressiveChunkMode: 'sequential'
+                    // }, {
+                    //     show: false,
+                    //     name: 'bar2',
+                    //     type: 'bar',
+                    //     stack: 'one',
+                    //     data: data[1]
+                    }]
+                };
+
+                testHelper.create(echarts, 'main0', {
+                    option: option
+                });
+
+            });
+        </script>
+    </body>
+</html>
\ No newline at end of file
diff --git a/test/candlestick-large2.html b/test/candlestick-large2.html
index 9c4019b..e91528f 100644
--- a/test/candlestick-large2.html
+++ b/test/candlestick-large2.html
@@ -34,6 +34,7 @@
 
             // The data count is from a real requirement.
             var rawDataCount = 2e5;
+            // var rawDataCount = 2e2;
 
             function run() {
                 var data = generateOHLC(rawDataCount);
@@ -47,16 +48,16 @@
                 var xValue = +new Date(2011, 0, 1);
                 var minute = 60 * 1000;
                 var baseValue = Math.random() * 12000;
-                var tmpVals = new Array(4);
+                var boxVals = new Array(4);
                 var dayRange = 12;
 
                 for (var i = 0; i < count; i++) {
                     baseValue = baseValue + Math.random() * 20 - 10;
 
                     for (var j = 0; j < 4; j++) {
-                        tmpVals[j] = (Math.random() - 0.5) * dayRange + baseValue;
+                        boxVals[j] = (Math.random() - 0.5) * dayRange + baseValue;
                     }
-                    tmpVals.sort();
+                    boxVals.sort();
 
                     var idxRandom = Math.random();
                     var openIdx = Math.round(Math.random() * 3);
@@ -64,15 +65,17 @@
                     if (closeIdx === openIdx) {
                         closeIdx++;
                     }
+                    var volumn = boxVals[3] * (1000 + Math.random() * 500);
 
-                    // ['open', 'close', 'lowest', 'highest']
+                    // ['open', 'close', 'lowest', 'highest', 'volumn']
                     // [1, 4, 3, 2]
                     data.push([
                         echarts.format.formatTime('yyyy-MM-dd hh:mm:ss', xValue += minute),
-                        +tmpVals[openIdx].toFixed(2), // open
-                        +tmpVals[3].toFixed(2), // highest
-                        +tmpVals[0].toFixed(2), // lowest
-                        +tmpVals[closeIdx].toFixed(2)  // close
+                        +boxVals[openIdx].toFixed(2), // open
+                        +boxVals[3].toFixed(2), // highest
+                        +boxVals[0].toFixed(2), // lowest
+                        +boxVals[closeIdx].toFixed(2),  // close
+                        volumn.toFixed(0)
                     ]);
                 }
 
@@ -99,6 +102,11 @@
 
                 frameInsight.init(echarts, 'duration');
 
+                var upColor = '#ec0000';
+                var upBorderColor = '#8A0000';
+                var downColor = '#00da3c';
+                var downBorderColor = '#008F28';
+
                 var option = {
                     dataset: {
                         source: rawData
@@ -137,12 +145,12 @@
                             right: '10%',
                             height: 300
                         },
-                        // {
-                        //     left: '10%',
-                        //     right: '10%',
-                        //     height: 70,
-                        //     bottom: 80
-                        // }
+                        {
+                            left: '10%',
+                            right: '10%',
+                            height: 70,
+                            bottom: 80
+                        }
                     ],
                     xAxis: [
                         {
@@ -156,20 +164,19 @@
                             min: 'dataMin',
                             max: 'dataMax'
                         },
-                        // {
-                        //     type: 'category',
-                        //     gridIndex: 1,
-                        //     data: data.categoryData,
-                        //     scale: true,
-                        //     boundaryGap : false,
-                        //     axisLine: {onZero: false},
-                        //     axisTick: {show: false},
-                        //     splitLine: {show: false},
-                        //     axisLabel: {show: false},
-                        //     splitNumber: 20,
-                        //     min: 'dataMin',
-                        //     max: 'dataMax'
-                        // }
+                        {
+                            type: 'category',
+                            gridIndex: 1,
+                            scale: true,
+                            boundaryGap : false,
+                            axisLine: {onZero: false},
+                            axisTick: {show: false},
+                            splitLine: {show: false},
+                            axisLabel: {show: false},
+                            splitNumber: 20,
+                            min: 'dataMin',
+                            max: 'dataMax'
+                        }
                     ],
                     yAxis: [
                         {
@@ -178,26 +185,26 @@
                                 show: true
                             }
                         },
-                        // {
-                        //     scale: true,
-                        //     gridIndex: 1,
-                        //     splitNumber: 2,
-                        //     axisLabel: {show: false},
-                        //     axisLine: {show: false},
-                        //     axisTick: {show: false},
-                        //     splitLine: {show: false}
-                        // }
+                        {
+                            scale: true,
+                            gridIndex: 1,
+                            splitNumber: 2,
+                            axisLabel: {show: false},
+                            axisLine: {show: false},
+                            axisTick: {show: false},
+                            splitLine: {show: false}
+                        }
                     ],
                     dataZoom: [
                         {
                             type: 'inside',
-                            // xAxisIndex: [0, 1],
+                            xAxisIndex: [0, 1],
                             start: 10,
                             end: 100
                         },
                         {
                             show: true,
-                            // xAxisIndex: [0, 1],
+                            xAxisIndex: [0, 1],
                             type: 'slider',
                             bottom: 10,
                             start: 10,
@@ -210,25 +217,19 @@
                             type: 'candlestick',
                             // progressiveMode: 'linear',
                             // data: data,
+                            itemStyle: {
+                                color: upColor,
+                                color0: downColor,
+                                borderColor: upBorderColor,
+                                borderColor0: downBorderColor
+                            },
                             encode: {
                                 x: 0,
                                 y: [1, 4, 3, 2]
                             },
                             // progressive: false
                             // progressive: progressive
-                            // tooltip: {
-                            //     formatter: function (param) {
-                            //         var param = param[0];
-                            //         return [
-                            //             'Date: ' + param.name + '<hr size=1 style="margin: 3px 0">',
-                            //             'Open: ' + param.data[0] + '<br/>',
-                            //             'Close: ' + param.data[1] + '<br/>',
-                            //             'Lowest: ' + param.data[2] + '<br/>',
-                            //             'Highest: ' + param.data[3] + '<br/>'
-                            //         ].join('')
-                            //     }
-                            // }
-                        } //,
+                        },
                         // {
                         //     name: 'MA5',
                         //     type: 'line',
@@ -265,13 +266,17 @@
                         //         normal: {opacity: 0.5}
                         //     }
                         // },
-                        // {
-                        //     name: 'Volumn',
-                        //     type: 'bar',
-                        //     xAxisIndex: 1,
-                        //     yAxisIndex: 1,
-                        //     data: data.volumns
-                        // }
+                        {
+                            name: 'Volumn',
+                            type: 'bar',
+                            xAxisIndex: 1,
+                            yAxisIndex: 1,
+                            large: true,
+                            encode: {
+                                x: 0,
+                                y: 5
+                            }
+                        }
                     ]
                 };
 

-- 
To stop receiving notification emails like this one, please contact
sushuang@apache.org.

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


[incubator-echarts] 02/03: Enhance dataZoom: do not trigger if range not changed, otherwise cause bad effect when progressive rendering.

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit df46e28e729b1c89344756c29a3f1e21323816d8
Author: sushuang <su...@gmail.com>
AuthorDate: Wed Apr 18 03:25:38 2018 +0800

    Enhance dataZoom: do not trigger if range not changed, otherwise cause bad effect when progressive rendering.
---
 src/component/dataZoom/InsideZoomView.js | 28 ++++++++++++++++++----------
 src/component/dataZoom/SliderZoomView.js | 16 +++++++++++-----
 src/component/dataZoom/roams.js          | 16 +---------------
 src/util/throttle.js                     |  8 ++++++++
 4 files changed, 38 insertions(+), 30 deletions(-)

diff --git a/src/component/dataZoom/InsideZoomView.js b/src/component/dataZoom/InsideZoomView.js
index dc01599..668f041 100644
--- a/src/component/dataZoom/InsideZoomView.js
+++ b/src/component/dataZoom/InsideZoomView.js
@@ -28,12 +28,10 @@ var InsideZoomView = DataZoomView.extend({
     render: function (dataZoomModel, ecModel, api, payload) {
         InsideZoomView.superApply(this, 'render', arguments);
 
-        // Notice: origin this._range should be maintained, and should not be re-fetched
-        // from dataZoomModel when payload.type is 'dataZoom', otherwise 'pan' or 'zoom'
-        // info will be missed because of 'throttle' of this.dispatchAction.
-        if (roams.shouldRecordRange(payload, dataZoomModel.id)) {
-            this._range = dataZoomModel.getPercentRange();
-        }
+        // Hance the `throttle` util ensures to preserve command order,
+        // here simply updating range all the time will not cause missing
+        // any of the the roam change.
+        this._range = dataZoomModel.getPercentRange();
 
         // Reset controllers.
         zrUtil.each(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {
@@ -85,7 +83,8 @@ var InsideZoomView = DataZoomView.extend({
      * @private
      */
     _onPan: function (coordInfo, coordSysName, controller, dx, dy, oldX, oldY, newX, newY) {
-        var range = this._range.slice();
+        var lastRange = this._range;
+        var range = lastRange.slice();
 
         // Calculate transform by the first axis.
         var axisModel = coordInfo.axisModels[0];
@@ -103,14 +102,19 @@ var InsideZoomView = DataZoomView.extend({
 
         sliderMove(percentDelta, range, [0, 100], 'all');
 
-        return (this._range = range);
+        this._range = range;
+
+        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {
+            return range;
+        }
     },
 
     /**
      * @private
      */
     _onZoom: function (coordInfo, coordSysName, controller, scale, mouseX, mouseY) {
-        var range = this._range.slice();
+        var lastRange = this._range;
+        var range = lastRange.slice();
 
         // Calculate transform by the first axis.
         var axisModel = coordInfo.axisModels[0];
@@ -136,7 +140,11 @@ var InsideZoomView = DataZoomView.extend({
 
         sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);
 
-        return (this._range = range);
+        this._range = range;
+
+        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {
+            return range;
+        }
     }
 
 });
diff --git a/src/component/dataZoom/SliderZoomView.js b/src/component/dataZoom/SliderZoomView.js
index 25c71e1..9dcde39 100644
--- a/src/component/dataZoom/SliderZoomView.js
+++ b/src/component/dataZoom/SliderZoomView.js
@@ -529,6 +529,7 @@ var SliderZoomView = DataZoomView.extend({
      * @private
      * @param {(number|string)} handleIndex 0 or 1 or 'all'
      * @param {number} delta
+     * @return {boolean} changed
      */
     _updateInterval: function (handleIndex, delta) {
         var dataZoomModel = this.dataZoomModel;
@@ -548,10 +549,13 @@ var SliderZoomView = DataZoomView.extend({
                 ? linearMap(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null
         );
 
-        this._range = asc([
+        var lastRange = this._range;
+        var range = this._range = asc([
             linearMap(handleEnds[0], viewExtend, percentExtent, true),
             linearMap(handleEnds[1], viewExtend, percentExtent, true)
         ]);
+
+        return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];
     },
 
     /**
@@ -697,13 +701,15 @@ var SliderZoomView = DataZoomView.extend({
         var barTransform = this._displayables.barGroup.getLocalTransform();
         var vertex = graphic.applyTransform([dx, dy], barTransform, true);
 
-        this._updateInterval(handleIndex, vertex[0]);
+        var changed = this._updateInterval(handleIndex, vertex[0]);
 
         var realtime = this.dataZoomModel.get('realtime');
 
         this._updateView(!realtime);
 
-        realtime && this._dispatchZoomAction();
+        // Avoid dispatch dataZoom repeatly but range not changed,
+        // which cause bad visual effect when progressive enabled.
+        changed && realtime && this._dispatchZoomAction();
     },
 
     _onDragEnd: function () {
@@ -729,9 +735,9 @@ var SliderZoomView = DataZoomView.extend({
         var handleEnds = this._handleEnds;
         var center = (handleEnds[0] + handleEnds[1]) / 2;
 
-        this._updateInterval('all', localPoint[0] - center);
+        var changed = this._updateInterval('all', localPoint[0] - center);
         this._updateView();
-        this._dispatchZoomAction();
+        changed && this._dispatchZoomAction();
     },
 
     /**
diff --git a/src/component/dataZoom/roams.js b/src/component/dataZoom/roams.js
index d4541b7..21a8261 100644
--- a/src/component/dataZoom/roams.js
+++ b/src/component/dataZoom/roams.js
@@ -100,20 +100,6 @@ export function unregister(api, dataZoomId) {
 /**
  * @public
  */
-export function shouldRecordRange(payload, dataZoomId) {
-    if (payload && payload.type === 'dataZoom' && payload.batch) {
-        for (var i = 0, len = payload.batch.length; i < len; i++) {
-            if (payload.batch[i].dataZoomId === dataZoomId) {
-                return false;
-            }
-        }
-    }
-    return true;
-}
-
-/**
- * @public
- */
 export function generateCoordId(coordModel) {
     return coordModel.type + '\0_' + coordModel.id;
 }
@@ -170,7 +156,7 @@ function wrapAndDispatch(record, getRange) {
         });
     });
 
-    record.dispatchAction(batch);
+    batch.length && record.dispatchAction(batch);
 }
 
 /**
diff --git a/src/util/throttle.js b/src/util/throttle.js
index 143d7ab..3cee4c3 100755
--- a/src/util/throttle.js
+++ b/src/util/throttle.js
@@ -42,6 +42,14 @@ export function throttle(fn, delay, debounce) {
 
         clearTimeout(timer);
 
+        // Here we should make sure that: the `exec` SHOULD NOT be called later
+        // than a new call of `cb`, that is, preserving the command order. Consider
+        // calculating "scale rate" when roaming as an example. When a call of `cb`
+        // happens, either the `exec` is called dierectly, or the call is delayed.
+        // But the delayed call should never be later than next call of `cb`. Under
+        // this assurance, we can simply update view state each time `dispatchAction`
+        // triggered by user roaming, but not need to add extra code to avoid the
+        // state being "rolled-back".
         if (thisDebounce) {
             timer = setTimeout(exec, thisDelay);
         }

-- 
To stop receiving notification emails like this one, please contact
sushuang@apache.org.

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