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:37 UTC

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

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