提交 f5f45219 编写于 作者: D deqingli

Merge branch 'master' of https://github.com/ecomfe/echarts

import * as zrUtil from 'zrender/src/core/util';
import ChartView from '../../view/Chart';
import * as graphic from '../../util/graphic';
import {viewMixin} from '../helper/whiskerBoxCommon';
import Path from 'zrender/src/graphic/Path';
// Update common properties
var NORMAL_ITEM_STYLE_PATH = ['itemStyle'];
var EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'];
var BoxplotView = ChartView.extend({
type: 'boxplot',
getStyleUpdater: function () {
return updateStyle;
render: function (seriesModel, ecModel, api) {
var data = seriesModel.getData();
var group = this.group;
var oldData = this._data;
// There is no old data only when first rendering or switching from
// stream mode to normal mode, where previous elements should be removed.
if (!this._data) {
group.removeAll();
}
var constDim = seriesModel.get('layout') === 'horizontal' ? 1 : 0;
data.diff(oldData)
.add(function (newIdx) {
if (data.hasValue(newIdx)) {
var itemLayout = data.getItemLayout(newIdx);
var symbolEl = createNormalBox(itemLayout, data, newIdx, constDim, true);
data.setItemGraphicEl(newIdx, symbolEl);
group.add(symbolEl);
}
})
.update(function (newIdx, oldIdx) {
var symbolEl = oldData.getItemGraphicEl(oldIdx);
// Empty data
if (!data.hasValue(newIdx)) {
group.remove(symbolEl);
return;
}
var itemLayout = data.getItemLayout(newIdx);
if (!symbolEl) {
symbolEl = createNormalBox(itemLayout, data, newIdx, constDim);
}
else {
updateNormalBoxData(itemLayout, symbolEl, data, newIdx);
}
group.add(symbolEl);
data.setItemGraphicEl(newIdx, symbolEl);
})
.remove(function (oldIdx) {
var el = oldData.getItemGraphicEl(oldIdx);
el && group.remove(el);
})
.execute();
this._data = data;
},
remove: function (ecModel) {
var group = this.group;
var data = this._data;
this._data = null;
data && data.eachItemGraphicEl(function (el) {
el && group.remove(el);
});
},
dispose: zrUtil.noop
});
zrUtil.mixin(BoxplotView, viewMixin, true);
// Update common properties
var normalStyleAccessPath = ['itemStyle'];
var emphasisStyleAccessPath = ['emphasis', 'itemStyle'];
var BoxPath = Path.extend({
type: 'boxplotBoxPath',
function updateStyle(data, idx, boxEl, whiskerEl, bodyEl) {
var itemModel = data.getItemModel(idx);
var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath);
var borderColor = data.getItemVisual(idx, 'color');
shape: {},
buildPath: function (ctx, shape) {
var ends = shape.points;
var i = 0;
ctx.moveTo(ends[i][0], ends[i][1]);
i++;
for (; i < 4; i++) {
ctx.lineTo(ends[i][0], ends[i][1]);
}
ctx.closePath();
for (; i < ends.length; i++) {
ctx.moveTo(ends[i][0], ends[i][1]);
i++;
ctx.lineTo(ends[i][0], ends[i][1]);
}
}
});
function createNormalBox(itemLayout, data, dataIndex, constDim, isInit) {
var ends = itemLayout.ends;
var el = new BoxPath({
shape: {
points: isInit
? transInit(ends, constDim, itemLayout)
: ends
}
});
updateNormalBoxData(itemLayout, el, data, dataIndex, isInit);
return el;
}
function updateNormalBoxData(itemLayout, el, data, dataIndex, isInit) {
var seriesModel = data.hostModel;
var updateMethod = graphic[isInit ? 'initProps' : 'updateProps'];
updateMethod(
el,
{shape: {points: itemLayout.ends}},
seriesModel,
dataIndex
);
var itemModel = data.getItemModel(dataIndex);
var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH);
var borderColor = data.getItemVisual(dataIndex, 'color');
// Exclude borderColor.
var itemStyle = normalItemStyleModel.getItemStyle(['borderColor']);
itemStyle.stroke = borderColor;
itemStyle.strokeNoScale = true;
el.useStyle(itemStyle);
whiskerEl.style.set(itemStyle);
whiskerEl.style.stroke = borderColor;
whiskerEl.dirty();
el.z2 = 100;
bodyEl.style.set(itemStyle);
bodyEl.style.stroke = borderColor;
bodyEl.dirty();
var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();
graphic.setHoverStyle(el, hoverStyle);
}
var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
graphic.setHoverStyle(boxEl, hoverStyle);
function transInit(points, dim, itemLayout) {
return zrUtil.map(points, function (point) {
point = point.slice();
point[dim] = itemLayout.initBaseline;
return point;
});
}
export default BoxplotView;
......@@ -108,86 +108,71 @@ function layoutSingleSeries(seriesModel, offset, boxWidth) {
var coordSys = seriesModel.coordinateSystem;
var data = seriesModel.getData();
var halfWidth = boxWidth / 2;
var chartLayout = seriesModel.get('layout');
var variableDim = chartLayout === 'horizontal' ? 0 : 1;
var constDim = 1 - variableDim;
var cDimIdx = seriesModel.get('layout') === 'horizontal' ? 0 : 1;
var vDimIdx = 1 - cDimIdx;
var coordDims = ['x', 'y'];
var vDims = [];
var cDim;
zrUtil.each(data.dimensions, function (dimName) {
var dimInfo = data.getDimensionInfo(dimName);
var coordDim = dimInfo.coordDim;
if (coordDim === coordDims[constDim]) {
vDims.push(dimName);
}
else if (coordDim === coordDims[variableDim]) {
cDim = dimName;
}
});
var cDim = data.mapDimension(coordDims[cDimIdx]);
var vDims = data.mapDimension(coordDims[vDimIdx], true);
if (cDim == null || vDims.length < 5) {
return;
}
data.each([cDim].concat(vDims), function () {
var args = arguments;
var axisDimVal = args[0];
var idx = args[vDims.length + 1];
var median = getPoint(args[3]);
var end1 = getPoint(args[1]);
var end5 = getPoint(args[5]);
var whiskerEnds = [
[end1, getPoint(args[2])],
[end5, getPoint(args[4])]
];
layEndLine(end1);
layEndLine(end5);
layEndLine(median);
var bodyEnds = [];
addBodyEnd(whiskerEnds[0][1], 0);
addBodyEnd(whiskerEnds[1][1], 1);
data.setItemLayout(idx, {
chartLayout: chartLayout,
initBaseline: median[constDim],
median: median,
bodyEnds: bodyEnds,
whiskerEnds: whiskerEnds
for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {
var axisDimVal = data.get(cDim, dataIndex);
var median = getPoint(axisDimVal, vDims[2], dataIndex);
var end1 = getPoint(axisDimVal, vDims[0], dataIndex);
var end2 = getPoint(axisDimVal, vDims[1], dataIndex);
var end4 = getPoint(axisDimVal, vDims[3], dataIndex);
var end5 = getPoint(axisDimVal, vDims[4], dataIndex);
var ends = [];
addBodyEnd(ends, end2, 0);
addBodyEnd(ends, end4, 1);
ends.push(end1, end2, end5, end4);
layEndLine(ends, end1);
layEndLine(ends, end5);
layEndLine(ends, median);
data.setItemLayout(dataIndex, {
initBaseline: median[vDimIdx],
ends: ends
});
}
function getPoint(val) {
var p = [];
p[variableDim] = axisDimVal;
p[constDim] = val;
var point;
if (isNaN(axisDimVal) || isNaN(val)) {
point = [NaN, NaN];
}
else {
point = coordSys.dataToPoint(p);
point[variableDim] += offset;
}
return point;
function getPoint(axisDimVal, dimIdx, dataIndex) {
var val = data.get(dimIdx, dataIndex);
var p = [];
p[cDimIdx] = axisDimVal;
p[vDimIdx] = val;
var point;
if (isNaN(axisDimVal) || isNaN(val)) {
point = [NaN, NaN];
}
function addBodyEnd(point, start) {
var point1 = point.slice();
var point2 = point.slice();
point1[variableDim] += halfWidth;
point2[variableDim] -= halfWidth;
start
? bodyEnds.push(point1, point2)
: bodyEnds.push(point2, point1);
else {
point = coordSys.dataToPoint(p);
point[cDimIdx] += offset;
}
return point;
}
function layEndLine(endCenter) {
var line = [endCenter.slice(), endCenter.slice()];
line[0][variableDim] -= halfWidth;
line[1][variableDim] += halfWidth;
whiskerEnds.push(line);
}
});
function addBodyEnd(ends, point, start) {
var point1 = point.slice();
var point2 = point.slice();
point1[cDimIdx] += halfWidth;
point2[cDimIdx] -= halfWidth;
start
? ends.push(point1, point2)
: ends.push(point2, point1);
}
function layEndLine(ends, endCenter) {
var from = endCenter.slice();
var to = endCenter.slice();
from[cDimIdx] -= halfWidth;
to[cDimIdx] += halfWidth;
ends.push(from, to);
}
}
import * as zrUtil from 'zrender/src/core/util';
import SeriesModel from '../../model/Series';
import {seriesModelMixin} from '../helper/whiskerBoxCommon';
// import {calculateCandleWidth} from './helper';
var CandlestickSeries = SeriesModel.extend({
......@@ -57,7 +56,10 @@ var CandlestickSeries = SeriesModel.extend({
barWidth: null,
large: true,
largeThreshold: 500,
largeThreshold: 600,
progressive: 5e3,
progressiveThreshold: 1e4,
animationUpdate: false,
animationEasing: 'linear',
......@@ -77,11 +79,6 @@ var CandlestickSeries = SeriesModel.extend({
return itemLayout && selectors.rect(itemLayout.brushRect);
}
// isLargeMode: function (data) {
// // Experience number
// return calculateCandleWidth(this, data) <= 1;
// }
});
zrUtil.mixin(CandlestickSeries, seriesModelMixin, true);
......
import * as zrUtil from 'zrender/src/core/util';
import ChartView from '../../view/Chart';
import * as graphic from '../../util/graphic';
import {viewMixin} from '../helper/whiskerBoxCommon';
import Path from 'zrender/src/graphic/Path';
var NORMAL_ITEM_STYLE_PATH = ['itemStyle'];
var EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'];
var SKIP_PROPS = ['color', 'color0', 'borderColor', 'borderColor0'];
var CandlestickView = ChartView.extend({
type: 'candlestick',
getStyleUpdater: function () {
return updateStyle;
render: function (seriesModel, ecModel, api) {
this._updateDrawMode(seriesModel);
this._isLargeDraw
? this._renderLarge(seriesModel)
: this._renderNormal(seriesModel);
},
incrementalPrepareRender: function (seriesModel, ecModel, api) {
this._clear();
this._updateDrawMode(seriesModel);
},
incrementalRender: function (params, seriesModel, ecModel, api) {
this._isLargeDraw
? this._incrementalRenderLarge(params, seriesModel)
: this._incrementalRenderNormal(params, seriesModel);
},
_updateDrawMode: function (seriesModel) {
var isLargeDraw = seriesModel.pipelineContext.large;
if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {
this._isLargeDraw = isLargeDraw;
this._clear();
}
},
_clear: function () {
this.group.removeAll();
this._data = null;
},
_renderNormal: function (seriesModel) {
// var largePoints = data.getLayout('largePoints');
var data = seriesModel.getData();
var oldData = this._data;
var group = this.group;
var isSimpleBox = data.getLayout('isSimpleBox');
// There is no old data only when first rendering or switching from
// stream mode to normal mode, where previous elements should be removed.
if (!this._data) {
group.removeAll();
}
data.diff(oldData)
.add(function (newIdx) {
if (data.hasValue(newIdx)) {
var el;
var itemLayout = data.getItemLayout(newIdx);
el = createNormalBox(itemLayout, newIdx, true);
graphic.initProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);
setBoxCommon(el, data, newIdx, isSimpleBox);
group.add(el);
data.setItemGraphicEl(newIdx, el);
}
})
.update(function (newIdx, oldIdx) {
var el = oldData.getItemGraphicEl(oldIdx);
// Empty data
if (!data.hasValue(newIdx)) {
group.remove(el);
return;
}
var itemLayout = data.getItemLayout(newIdx);
if (!el) {
el = createNormalBox(itemLayout, newIdx);
}
else {
graphic.updateProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);
}
setBoxCommon(el, data, newIdx, isSimpleBox);
group.add(el);
data.setItemGraphicEl(newIdx, el);
})
.remove(function (oldIdx) {
var el = oldData.getItemGraphicEl(oldIdx);
el && group.remove(el);
})
.execute();
this._data = data;
},
_renderLarge: function (seriesModel) {
var group = this.group;
group.removeAll();
createLarge(seriesModel, group);
},
_incrementalRenderNormal: function (params, seriesModel) {
var data = seriesModel.getData();
var isSimpleBox = data.getLayout('isSimpleBox');
for (var dataIndex = params.start; dataIndex < params.end; dataIndex++) {
var el;
var itemLayout = data.getItemLayout(dataIndex);
el = createNormalBox(itemLayout, dataIndex);
setBoxCommon(el, data, dataIndex, isSimpleBox);
el.incremental = true;
this.group.add(el);
}
},
_incrementalRenderLarge: function (params, seriesModel) {
createLarge(seriesModel, this.group, true);
},
remove: function (ecModel) {
var group = this.group;
var data = this._data;
this._data = null;
data && data.eachItemGraphicEl(function (el) {
el && group.remove(el);
});
},
dispose: zrUtil.noop
});
zrUtil.mixin(CandlestickView, viewMixin, true);
// Update common properties
var normalStyleAccessPath = ['itemStyle'];
var emphasisStyleAccessPath = ['emphasis', 'itemStyle'];
var NormalBoxPath = Path.extend({
type: 'normalCandlestickBox',
shape: {},
buildPath: function (ctx, shape) {
var ends = shape.points;
function updateStyle(data, idx, boxEl, whiskerEl, bodyEl) {
var itemModel = data.getItemModel(idx);
var normalItemStyleModel = itemModel.getModel(normalStyleAccessPath);
var color = data.getItemVisual(idx, 'color');
var borderColor = data.getItemVisual(idx, 'borderColor') || color;
if (this.__simpleBox) {
ctx.moveTo(ends[4][0], ends[4][1]);
ctx.lineTo(ends[6][0], ends[6][1]);
}
else {
ctx.moveTo(ends[0][0], ends[0][1]);
ctx.lineTo(ends[1][0], ends[1][1]);
ctx.lineTo(ends[2][0], ends[2][1]);
ctx.lineTo(ends[3][0], ends[3][1]);
ctx.closePath();
ctx.moveTo(ends[4][0], ends[4][1]);
ctx.lineTo(ends[5][0], ends[5][1]);
ctx.moveTo(ends[6][0], ends[6][1]);
ctx.lineTo(ends[7][0], ends[7][1]);
}
}
});
function createNormalBox(itemLayout, dataIndex, isInit) {
var ends = itemLayout.ends;
return new NormalBoxPath({
shape: {
points: isInit
? transInit(ends, itemLayout)
: ends
},
z2: 100
});
}
function setBoxCommon(el, data, dataIndex, isSimpleBox) {
var itemModel = data.getItemModel(dataIndex);
var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH);
var color = data.getItemVisual(dataIndex, 'color');
var borderColor = data.getItemVisual(dataIndex, 'borderColor') || color;
// Color must be excluded.
// Because symbol provide setColor individually to set fill and stroke
var itemStyle = normalItemStyleModel.getItemStyle(
['color', 'color0', 'borderColor', 'borderColor0']
);
var itemStyle = normalItemStyleModel.getItemStyle(SKIP_PROPS);
el.useStyle(itemStyle);
el.style.strokeNoScale = true;
el.style.fill = color;
el.style.stroke = borderColor;
el.__simpleBox = isSimpleBox;
var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();
graphic.setHoverStyle(el, hoverStyle);
}
function transInit(points, itemLayout) {
return zrUtil.map(points, function (point) {
point = point.slice();
point[1] = itemLayout.initBaseline;
return point;
});
}
whiskerEl.useStyle(itemStyle);
whiskerEl.style.stroke = borderColor;
bodyEl.useStyle(itemStyle);
bodyEl.style.fill = color;
bodyEl.style.stroke = borderColor;
var LargeBoxPath = Path.extend({
var hoverStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
graphic.setHoverStyle(boxEl, hoverStyle);
type: 'largeCandlestickBox',
shape: {},
buildPath: function (ctx, shape) {
// Drawing lines is more efficient than drawing
// a whole line or drawing rects.
var points = shape.points;
for (var i = 0; i < points.length;) {
if (this.__sign === points[i++]) {
var x = points[i++];
ctx.moveTo(x, points[i++]);
ctx.lineTo(x, points[i++]);
}
else {
i += 3;
}
}
}
});
function createLarge(seriesModel, group, incremental) {
var data = seriesModel.getData();
var largePoints = data.getLayout('largePoints');
var elP = new LargeBoxPath({
shape: {points: largePoints},
__sign: 1
});
group.add(elP);
var elN = new LargeBoxPath({
shape: {points: largePoints},
__sign: -1
});
group.add(elN);
setLargeStyle(1, elP, seriesModel, data);
setLargeStyle(-1, elN, seriesModel, data);
if (incremental) {
elP.incremental = true;
elN.incremental = true;
}
}
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;
// Color must be excluded.
// Because symbol provide setColor individually to set fill and stroke
var itemStyle = normalItemStyleModel.getItemStyle(SKIP_PROPS);
el.useStyle(itemStyle);
el.style.fill = null;
el.style.stroke = borderColor;
// No different
// el.style.lineWidth = .5;
}
export default CandlestickView;
import {subPixelOptimize} from '../../util/graphic';
import createRenderPlanner from '../helper/createRenderPlanner';
import {calculateCandleWidth} from './helper';
import {parsePercent} from '../../util/number';
import {retrieve2} from 'zrender/src/core/util';
var LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;
......@@ -12,15 +13,11 @@ export default {
reset: function (seriesModel) {
var pipelineContext = seriesModel.pipelineContext;
var isLargeRender = pipelineContext.large;
var coordSys = seriesModel.coordinateSystem;
var data = seriesModel.getData();
var candleWidth = calculateCandleWidth(seriesModel, data);
var chartLayout = seriesModel.get('layout');
var cDimIdx = chartLayout === 'horizontal' ? 0 : 1;
var vDimIdx = 1 - cDimIdx;
var cDimIdx = 0;
var vDimIdx = 1;
var coordDims = ['x', 'y'];
var cDim = data.mapDimension(coordDims[cDimIdx]);
var vDims = data.mapDimension(coordDims[vDimIdx], true);
......@@ -29,20 +26,25 @@ export default {
var lowestDim = vDims[2];
var highestDim = vDims[3];
data.setLayout({
candleWidth: candleWidth,
// The value is experimented visually.
isSimpleBox: candleWidth <= 1.3
});
if (cDim == null || vDims.length < 4) {
return;
}
return {progress: isLargeRender ? largeProgress : normalProgress};
return {
progress: seriesModel.pipelineContext.large
? largeProgress : normalProgress
};
function normalProgress(params, data) {
for (var dataIndex = params.start; dataIndex < params.end; dataIndex++) {
layoutDataItem(dataIndex);
}
function layoutDataItem(dataIndex) {
var axisDimVal = data.get(cDim, dataIndex);
var openVal = data.get(openDim, dataIndex);
var closeVal = data.get(closeDim, dataIndex);
......@@ -57,28 +59,22 @@ export default {
var lowestPoint = getPoint(lowestVal, axisDimVal);
var highestPoint = getPoint(highestVal, axisDimVal);
var whiskerEnds = [
[
subPixelOptimizePoint(highestPoint),
subPixelOptimizePoint(ocHighPoint)
],
[
subPixelOptimizePoint(lowestPoint),
subPixelOptimizePoint(ocLowPoint)
]
];
var bodyEnds = [];
addBodyEnd(bodyEnds, ocHighPoint, 0);
addBodyEnd(bodyEnds, ocLowPoint, 1);
var ends = [];
addBodyEnd(ends, ocHighPoint, 0);
addBodyEnd(ends, ocLowPoint, 1);
ends.push(
subPixelOptimizePoint(highestPoint),
subPixelOptimizePoint(ocHighPoint),
subPixelOptimizePoint(lowestPoint),
subPixelOptimizePoint(ocLowPoint)
);
data.setItemLayout(dataIndex, {
chartLayout: chartLayout,
sign: getSign(data, dataIndex, openVal, closeVal, closeDim),
initBaseline: openVal > closeVal
? ocHighPoint[vDimIdx] : ocLowPoint[vDimIdx], // open point.
bodyEnds: bodyEnds,
whiskerEnds: whiskerEnds,
ends: ends,
brushRect: makeBrushRect(lowestVal, highestVal, axisDimVal)
});
}
......@@ -92,7 +88,7 @@ export default {
: coordSys.dataToPoint(p);
}
function addBodyEnd(bodyEnds, point, start) {
function addBodyEnd(ends, point, start) {
var point1 = point.slice();
var point2 = point.slice();
......@@ -104,8 +100,8 @@ export default {
);
start
? bodyEnds.push(point1, point2)
: bodyEnds.push(point2, point1);
? ends.push(point1, point2)
: ends.push(point2, point1);
}
function makeBrushRect(lowestVal, highestVal, axisDimVal) {
......@@ -131,7 +127,7 @@ export default {
function largeProgress(params, data) {
var segCount = params.end - params.start;
// Structure: [sign, x1, y1, x2, y2, sign, x1, y1, x2, y2, ...]
// Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...]
var points = new LargeArr(segCount * 5);
for (
......@@ -159,16 +155,12 @@ export default {
point = coordSys.dataToPoint(tmpIn, null, tmpOut);
points[offset++] = point ? point[0] : NaN;
points[offset++] = point ? point[1] : NaN;
tmpIn[vDimIdx] = highestVal;
point = coordSys.dataToPoint(tmpIn, null, tmpOut);
points[offset++] = point ? point[0] : NaN;
points[offset++] = point ? point[1] : NaN;
}
data.setLayout('largePoints', points);
data.setLayout('candleWidth', candleWidth);
data.setLayout('candleWidth', candleWidth);
}
}
};
......@@ -191,3 +183,30 @@ function getSign(data, dataIndex, openVal, closeVal, closeDim) {
return sign;
}
function calculateCandleWidth(seriesModel, data) {
var baseAxis = seriesModel.getBaseAxis();
var extent;
var bandWidth = baseAxis.type === 'category'
? baseAxis.getBandWidth()
: (
extent = baseAxis.getExtent(),
Math.abs(extent[1] - extent[0]) / data.count()
);
var barMaxWidth = parsePercent(
retrieve2(seriesModel.get('barMaxWidth'), bandWidth),
bandWidth
);
var barMinWidth = parsePercent(
retrieve2(seriesModel.get('barMinWidth'), 1),
bandWidth
);
var barWidth = seriesModel.get('barWidth');
return barWidth != null
? parsePercent(barWidth, bandWidth)
// Put max outer to ensure bar visible in spite of overlap.
: Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);
}
......@@ -17,12 +17,14 @@ export default {
reset: function (seriesModel, ecModel) {
var data = seriesModel.getData();
var pipelineContext = seriesModel.pipelineContext;
var isLargeRender = pipelineContext.large;
var largePoints = isLargeRender && data.getLayout('largePoints');
var isLargeRender = seriesModel.pipelineContext.large;
data.setVisual({
legendSymbol: 'roundRect'
legendSymbol: 'roundRect',
colorP: getColor(1, seriesModel),
colorN: getColor(-1, seriesModel),
borderColorP: getBorderColor(1, seriesModel),
borderColorN: getBorderColor(-1, seriesModel)
});
// Only visible series has each data be visual encoded
......@@ -30,28 +32,36 @@ export default {
return;
}
return !isLargeRender && {progress: progress};
function progress(params, data) {
for (var dataIndex = params.start; dataIndex < params.end; dataIndex++) {
var itemModel = data.getItemModel(dataIndex);
var sign = isLargeRender
? largePoints[(dataIndex - params.start) * 5]
: data.getItemLayout(dataIndex).sign;
var sign = data.getItemLayout(dataIndex).sign;
data.setItemVisual(
dataIndex,
{
color: itemModel.get(
sign > 0 ? positiveColorQuery : negativeColorQuery
),
borderColor: itemModel.get(
sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery
)
color: getColor(sign, itemModel),
borderColor: getBorderColor(sign, itemModel)
}
);
}
}
return {progress: progress};
function getColor(sign, model) {
return model.get(
sign > 0 ? positiveColorQuery : negativeColorQuery
);
}
function getBorderColor(sign, model) {
return model.get(
sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery
);
}
}
};
\ No newline at end of file
import {parsePercent} from '../../util/number';
import {retrieve2} from 'zrender/src/core/util';
export function calculateCandleWidth(seriesModel, data) {
var baseAxis = seriesModel.getBaseAxis();
var extent;
var bandWidth = baseAxis.type === 'category'
? baseAxis.getBandWidth()
: (
extent = baseAxis.getExtent(),
Math.abs(extent[1] - extent[0]) / data.count()
);
var barMaxWidth = parsePercent(
retrieve2(seriesModel.get('barMaxWidth'), bandWidth),
bandWidth
);
var barMinWidth = parsePercent(
retrieve2(seriesModel.get('barMinWidth'), 1),
bandWidth
);
var barWidth = seriesModel.get('barWidth');
return barWidth != null
? parsePercent(barWidth, bandWidth)
// Put max outer to ensure bar visible in spite of overlap.
: Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);
}
......@@ -163,6 +163,7 @@ largeLineProto.incrementalUpdate = function (taskParams, data) {
lineEl.setShape({
segs: data.getLayout('linesPoints')
});
this._setCommon(lineEl, data, !!this._incremental);
if (!this._incremental) {
......
......@@ -87,6 +87,12 @@ function doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScop
lineDrawProto.updateLayout = function () {
var lineData = this._lineData;
// Do not support update layout in incremental mode.
if (!lineData) {
return;
}
lineData.eachItemGraphicEl(function (el, idx) {
el.updateLayout(lineData, idx);
}, this);
......@@ -111,7 +117,9 @@ lineDrawProto.incrementalUpdate = function (taskParams, lineData) {
if (lineNeedsDraw(itemLayout)) {
var el = new this._ctor(lineData, idx, this._seriesScope);
el.traverse(updateIncrementalAndHover);
this.group.add(el);
lineData.setItemGraphicEl(idx, el);
}
}
};
......
/**
* @module echarts/chart/helper/Symbol
*/
import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import Path from 'zrender/src/graphic/Path';
// ------------------
// -- Whisker Path --
// ------------------
var WhiskerPath = Path.extend({
type: 'whiskerInBox',
shape: {},
buildPath: function (ctx, shape) {
for (var i in shape) {
if (shape.hasOwnProperty(i) && i.indexOf('ends') === 0) {
var pts = shape[i];
ctx.moveTo(pts[0][0], pts[0][1]);
ctx.lineTo(pts[1][0], pts[1][1]);
}
}
}
});
// ----------------
// -- Normal Box --
// ----------------
var BODY_INDEX = 0;
var WHISKER_INDEX = 1;
/**
* @param {module:echarts/data/List} data
* @param {number} idx
* @param {Function} styleUpdater
* @param {boolean} isInit
*/
function createNormalBox(data, dataIndex, styleUpdater, isInit) {
var boxEl = new graphic.Group();
var itemLayout = data.getItemLayout(dataIndex);
var constDim = itemLayout.chartLayout === 'horizontal' ? 1 : 0;
// Whisker element.
boxEl.add(new graphic.Polygon({
shape: {
points: isInit
? transInit(itemLayout.bodyEnds, constDim, itemLayout)
: itemLayout.bodyEnds
},
style: {strokeNoScale: true},
z2: 100
}));
// Box element.
var whiskerEnds = zrUtil.map(itemLayout.whiskerEnds, function (ends) {
return isInit ? transInit(ends, constDim, itemLayout) : ends;
});
boxEl.add(new WhiskerPath({
shape: makeWhiskerEndsShape(whiskerEnds),
style: {strokeNoScale: true},
z2: 100
}));
updateNormalBoxData(boxEl, data, dataIndex, styleUpdater, isInit);
return boxEl;
}
function updateNormalBoxData(boxEl, data, dataIndex, styleUpdater, isInit) {
var seriesModel = boxEl._seriesModel = data.hostModel;
var itemLayout = data.getItemLayout(dataIndex);
var updateMethod = graphic[isInit ? 'initProps' : 'updateProps'];
var whiskerEl = boxEl.childAt(WHISKER_INDEX);
var bodyEl = boxEl.childAt(BODY_INDEX);
updateMethod(
bodyEl,
{shape: {points: itemLayout.bodyEnds}},
seriesModel, dataIndex
);
updateMethod(
whiskerEl,
{shape: makeWhiskerEndsShape(itemLayout.whiskerEnds)},
seriesModel, dataIndex
);
styleUpdater(data, dataIndex, boxEl, whiskerEl, bodyEl);
}
function transInit(points, dim, itemLayout) {
return zrUtil.map(points, function (point) {
point = point.slice();
point[dim] = itemLayout.initBaseline;
return point;
});
}
function makeWhiskerEndsShape(whiskerEnds) {
// zr animation only support 2-dim array.
var shape = {};
zrUtil.each(whiskerEnds, function (ends, i) {
shape['ends' + i] = ends;
});
return shape;
}
// ---------------
// -- Large Box --
// ---------------
var NORMAL_STYLE_ACCESS_PATH = ['itemStyle'];
var EMPHASIS_STYLE_ACCESS_PATH = ['emphasis', 'itemStyle'];
function createLargeBox(data, largePoints, dataIndex, segmentStart) {
var boxEl = new graphic.Line({
shape: largeBoxMakeShape(largePoints, dataIndex, segmentStart)
});
boxEl.__largeWhiskerBox = true;
largeBoxSetStyle(boxEl, data, dataIndex);
return boxEl;
}
function largeBoxMakeShape(largePoints, dataIndex, segmentStart) {
var baseIdx = (dataIndex - (segmentStart || 0)) * 5;
return {
x1: largePoints[baseIdx + 1],
y1: largePoints[baseIdx + 2],
x2: largePoints[baseIdx + 3],
y2: largePoints[baseIdx + 4]
};
}
function updateLargeBoxData(boxEl, data, dataIndex) {
graphic.updateProps(
boxEl,
{shape: largeBoxMakeShape(data.getLayout('largePoints'), dataIndex, 0)},
data.hostModel,
dataIndex
);
largeBoxSetStyle(boxEl, data, dataIndex);
}
function largeBoxSetStyle(boxEl, data, dataIndex) {
var itemModel = data.getItemModel(dataIndex);
var normalItemStyleModel = itemModel.getModel(NORMAL_STYLE_ACCESS_PATH);
var color = data.getItemVisual(dataIndex, 'color');
var borderColor = data.getItemVisual(dataIndex, 'borderColor') || color;
// Color must be excluded.
// Because symbol provide setColor individually to set fill and stroke
var itemStyle = normalItemStyleModel.getItemStyle(
['color', 'color0', 'borderColor', 'borderColor0']
);
boxEl.useStyle(itemStyle);
boxEl.style.stroke = borderColor;
var hoverStyle = itemModel.getModel(EMPHASIS_STYLE_ACCESS_PATH).getItemStyle();
graphic.setHoverStyle(boxEl, hoverStyle);
}
// --------------------
// -- WhiskerBoxDraw --
// --------------------
/**
* @constructor
* @alias module:echarts/chart/helper/WhiskerBoxDraw
*/
function WhiskerBoxDraw(styleUpdater) {
this.group = new graphic.Group();
this.styleUpdater = styleUpdater;
}
var whiskerBoxDrawProto = WhiskerBoxDraw.prototype;
/**
* Update symbols draw by new data
* @param {module:echarts/data/List} data
*/
whiskerBoxDrawProto.updateData = function (data) {
var group = this.group;
var oldData = this._data;
var styleUpdater = this.styleUpdater;
var pipelineContext = data.hostModel.pipelineContext;
var isLargeRender = pipelineContext.large;
var largePoints = isLargeRender && data.getLayout('largePoints');
// There is no old data only when first rendering or switching from
// stream mode to normal mode, where previous elements should be removed.
if (!this._data) {
group.removeAll();
}
data.diff(oldData)
.add(function (newIdx) {
if (data.hasValue(newIdx)) {
var symbolEl = isLargeRender
? createLargeBox(data, largePoints, newIdx)
: createNormalBox(data, newIdx, styleUpdater, true);
data.setItemGraphicEl(newIdx, symbolEl);
group.add(symbolEl);
}
})
.update(function (newIdx, oldIdx) {
var symbolEl = oldData.getItemGraphicEl(oldIdx);
// Empty data
if (!data.hasValue(newIdx)) {
group.remove(symbolEl);
return;
}
if (symbolEl && symbolEl.__largeWhiskerBox ^ isLargeRender) {
group.remove(symbolEl);
symbolEl = null;
}
if (!symbolEl) {
symbolEl = isLargeRender
? createLargeBox(data, largePoints, newIdx)
: createNormalBox(data, newIdx, styleUpdater);
}
else {
isLargeRender
? updateLargeBoxData(symbolEl, data, newIdx)
: updateNormalBoxData(symbolEl, data, newIdx, styleUpdater);
}
// Add back
group.add(symbolEl);
data.setItemGraphicEl(newIdx, symbolEl);
})
.remove(function (oldIdx) {
var el = oldData.getItemGraphicEl(oldIdx);
el && group.remove(el);
})
.execute();
this._data = data;
};
whiskerBoxDrawProto.incrementalPrepareUpdate = function (seriesModel, ecModel, api) {
this.group.removeAll();
this._data = null;
};
whiskerBoxDrawProto.incrementalUpdate = function (params, seriesModel, ecModel, api) {
var data = seriesModel.getData();
var pipelineContext = seriesModel.pipelineContext;
var isLargeRender = pipelineContext.large;
var largePoints = isLargeRender && data.getLayout('largePoints');
for (var idx = params.start; idx < params.end; idx++) {
var symbolEl = isLargeRender
? createLargeBox(data, largePoints, idx, params.start)
: createNormalBox(data, idx, this.styleUpdater, true);
symbolEl.incremental = true;
this.group.add(symbolEl);
}
};
/**
* Remove symbols.
* @param {module:echarts/data/List} data
*/
whiskerBoxDrawProto.remove = function () {
var group = this.group;
var data = this._data;
this._data = null;
data && data.eachItemGraphicEl(function (el) {
el && group.remove(el);
});
};
export default WhiskerBoxDraw;
......@@ -11,10 +11,10 @@ export default function () {
var pipelineContext = seriesModel.pipelineContext;
var originalLarge = fields.large;
var originalProgressive = fields.canProgressiveRender;
var originalProgressive = fields.progressiveRender;
var large = fields.large = pipelineContext.large;
var progressive = fields.canProgressiveRender = pipelineContext.canProgressiveRender;
var progressive = fields.progressiveRender = pipelineContext.progressiveRender;
return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';
};
......
import createListSimply from '../helper/createListSimply';
import WhiskerBoxDraw from '../helper/WhiskerBoxDraw';
import * as zrUtil from 'zrender/src/core/util';
import {getDimensionTypeByAxis} from '../../data/helper/dimensionHelper';
......@@ -110,34 +109,3 @@ export var seriesModelMixin = {
}
};
export var viewMixin = {
init: function () {
/**
* Old data.
* @private
* @type {module:echarts/chart/helper/WhiskerBoxDraw}
*/
var whiskerBoxDraw = this._whiskerBoxDraw = new WhiskerBoxDraw(
this.getStyleUpdater()
);
this.group.add(whiskerBoxDraw.group);
},
render: function (seriesModel, ecModel, api) {
this._whiskerBoxDraw.updateData(seriesModel.getData());
},
incrementalPrepareRender: function (seriesModel, ecModel, api) {
this._whiskerBoxDraw.incrementalPrepareUpdate(seriesModel, ecModel, api);
},
incrementalRender: function (params, seriesModel, ecModel, api) {
this._whiskerBoxDraw.incrementalUpdate(params, seriesModel, ecModel, api);
},
remove: function (ecModel) {
this._whiskerBoxDraw.remove();
}
};
......@@ -82,8 +82,9 @@ export default echarts.extendChartView({
updateTransform: function (seriesModel, ecModel, api) {
var data = seriesModel.getData();
var pipelineContext = seriesModel.pipelineContext;
if (!this._finished || seriesModel.pipelineContext.large) {
if (!this._finished || pipelineContext.large || pipelineContext.progressiveRender) {
// TODO Don't have to do update in large mode. Only do it when there are millions of data.
return {
update: true
......
......@@ -23,7 +23,7 @@ export default {
points = new Float32Array(segCount + totalCoordsCount * 2);
}
else {
points = new Float32Array(segCount * 2);
points = new Float32Array(segCount * 4);
}
var offset = 0;
......
......@@ -102,7 +102,7 @@ function computeNodeBreadths(nodes, nodeWidth, width) {
++x;
}
moveSinksRight(nodes, x);
// moveSinksRight(nodes, x);
kx = (width - nodeWidth) / (x - 1);
scaleNodeBreadths(nodes, kx);
......
......@@ -441,7 +441,7 @@ function Edge(n1, n2, dataIndex) {
* @param {string} [path]
* @return {module:echarts/model/Model}
*/
Edge.prototype.getModel = function (path) {
Edge.prototype.getModel = function (path) {
if (this.dataIndex < 0) {
return;
}
......
......@@ -90,7 +90,7 @@ proto.getPerformArgs = function (task, isBlock) {
var pCtx = pipeline.context;
var incremental = !isBlock
&& pipeline.progressiveEnabled
&& (!pCtx || pCtx.canProgressiveRender)
&& (!pCtx || pCtx.progressiveRender)
&& task.__idxInPipeline > pipeline.bockIndex;
return {step: incremental ? pipeline.step : null};
......@@ -112,19 +112,19 @@ proto.updateStreamModes = function (seriesModel, view) {
var data = seriesModel.getData();
var dataLen = data.count();
// `canProgressiveRender` means that can render progressively in each
// `progressiveRender` means that can render progressively in each
// animation frame. Note that some types of series do not provide
// `view.incrementalPrepareRender` but support `chart.appendData`. We
// use the term `incremental` but not `progressive` to describe the
// case that `chart.appendData`.
var canProgressiveRender = pipeline.progressiveEnabled
var progressiveRender = pipeline.progressiveEnabled
&& view.incrementalPrepareRender
&& dataLen >= pipeline.threshold;
var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');
seriesModel.pipelineContext = pipeline.context = {
canProgressiveRender: canProgressiveRender,
progressiveRender: progressiveRender,
large: large
};
};
......
......@@ -189,11 +189,11 @@ function renderTaskReset(context) {
var api = context.api;
var payload = context.payload;
// ???! remove updateView updateVisual
var canProgressiveRender = seriesModel.pipelineContext.canProgressiveRender;
var progressiveRender = seriesModel.pipelineContext.progressiveRender;
var view = context.view;
var updateMethod = payload && inner(payload).updateMethod;
var methodName = canProgressiveRender
var methodName = progressiveRender
? 'incrementalPrepareRender'
: (updateMethod && view[updateMethod])
? updateMethod
......
......@@ -34,11 +34,15 @@
name: 'stream-cases',
whiteList: [
'lines-ny-appendData.html',
'scatter-stream-large.html',
'scatter-stream-not-large.html',
'scatter-random-stream.html',
'scatter-random-stream-fix-axis.html',
'scatter-gps.html',
'scatter-weibo.html',
'lines-flight.html',
'lines-stream-large.html',
'lines-stream-not-large.html',
'stream-filter.html',
'scatter-stream-visual.html'
]
......
......@@ -124,6 +124,11 @@
{
name: 'category0',
type: 'boxplot',
itemStyle: {
color: '#a32',
borderColor: '#429',
borderWidth: 3
},
data: data[0].boxData
},
{
......
......@@ -183,22 +183,28 @@
{
type: 'inside',
// xAxisIndex: [0, 1],
// start: 10,
// start: 99,
// end: 100
// startValue: '2010-08-17',
// endValue: '2012-08-06'
},
{
show: true,
// xAxisIndex: [0, 1],
type: 'slider',
bottom: 10,
// start: 10,
// start: 99,
// end: 100
// startValue: '2010-08-17',
// endValue: '2012-08-06'
}
],
animation: false,
series: [
{
name: 'Dow-Jones index',
type: 'candlestick',
// large: false,
encode: {
x: 0,
y: [1, 2, 3, 4]
......@@ -271,7 +277,7 @@
var panel = document.getElementById('panel0');
var chart = testHelper.create(echarts, 'main0', {
title: 'Use dataset',
title: 'Use dataset. Check item tooltip in large mode.',
option: option,
height: 550
});
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="../dist/echarts.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>
<div id="panel0"></div>
<script>
// The data count is from a real requirement.
var rawDataCount = 2e5;
var progressive = 4e3;
function run() {
var data = generateOHLC(rawDataCount);
var result = reorder(data);
init(result.data, result.categoryData);
}
function generateOHLC(count) {
var data = [];
var xValue = +new Date(2011, 0, 1);
var minute = 60 * 1000;
var baseValue = Math.random() * 12000;
var tmpVals = 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;
}
tmpVals.sort();
var idxRandom = Math.random();
var openIdx = Math.round(Math.random() * 3);
var closeIdx = Math.round(Math.random() * 2);
if (closeIdx === openIdx) {
closeIdx++;
}
// ['open', 'close', 'lowest', 'highest']
// [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
]);
}
return data;
}
function reorder(data) {
var categoryData = new Array(data.length);
var categoryMap = {};
for (var i = 0; i < data.length; i++) {
categoryData[i] = data[i][0];
categoryMap[categoryData[i]] = i;
}
var newData = new Array(data.length);
var step = Math.round(data.length / progressive);
var newOffset = 0;
for (var offset = 0; offset < step; offset++) {
for (var i = offset; i < data.length; i += step) {
var item = data[i].slice();
newData[newOffset++] = item;
item[0] = categoryMap[item[0]];
}
}
return {data: newData, categoryData: categoryData};
}
function calculateMA(dayCount, data) {
var result = [];
for (var i = 0, len = data.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++) {
sum += data[i - j][2];
}
result.push(+(sum / dayCount).toFixed(3));
}
return result;
}
function init(rawData, categoryData) {
var option = {
dataset: {
source: rawData
},
backgroundColor: '#eee',
// animation: false,
legend: {
left: 0
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line'
}
},
toolbox: {
feature: {
dataZoom: {
yAxisIndex: false
},
brush: {
type: ['polygon', 'rect', 'lineX', 'lineY', 'keep', 'clear']
}
}
},
// brush: {
// xAxisIndex: 'all',
// brushLink: 'all',
// outOfBrush: {
// colorAlpha: 0.1
// }
// },
grid: [
{
left: '10%',
right: '10%',
height: 300
},
// {
// left: '10%',
// right: '10%',
// height: 70,
// bottom: 80
// }
],
xAxis: [
{
type: 'category',
scale: true,
boundaryGap : false,
axisLine: {onZero: false},
splitLine: {show: false},
splitNumber: 20,
min: 'dataMin',
max: 'dataMax',
data: categoryData
},
// {
// 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'
// }
],
yAxis: [
{
scale: true,
splitArea: {
show: true
}
},
// {
// scale: true,
// gridIndex: 1,
// splitNumber: 2,
// axisLabel: {show: false},
// axisLine: {show: false},
// axisTick: {show: false},
// splitLine: {show: false}
// }
],
dataZoom: [
{
type: 'inside',
// xAxisIndex: [0, 1],
start: 10,
end: 100
},
{
show: true,
// xAxisIndex: [0, 1],
type: 'slider',
bottom: 10,
start: 10,
end: 100
}
],
series: [
{
name: 'Fake index',
type: 'candlestick',
// data: data,
encode: {
x: 0,
y: [1, 4, 3, 2]
},
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',
// data: calculateMA(5, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'MA10',
// type: 'line',
// data: calculateMA(10, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'MA20',
// type: 'line',
// data: calculateMA(20, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'MA30',
// type: 'line',
// data: calculateMA(30, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'Volumn',
// type: 'bar',
// xAxisIndex: 1,
// yAxisIndex: 1,
// data: data.volumns
// }
]
};
var panel = document.getElementById('panel0');
var chart = testHelper.create(echarts, 'main0', {
title: 'Fake OHLC data',
option: option,
height: 550
});
// chart && chart.on('brushSelected', renderBrushed);
// function renderBrushed(params) {
// var sum = 0;
// var min = Infinity;
// var max = -Infinity;
// var countBySeries = [];
// var brushComponent = params.batch[0];
// var rawIndices = brushComponent.selected[0].dataIndex;
// for (var i = 0; i < rawIndices.length; i++) {
// var val = data.values[rawIndices[i]][1];
// sum += val;
// min = Math.min(val, min);
// max = Math.max(val, max);
// }
// panel.innerHTML = [
// '<h3>STATISTICS:</h3>',
// 'SUM of open: ' + (sum / rawIndices.length).toFixed(4) + '<br>',
// 'MIN of open: ' + min.toFixed(4) + '<br>',
// 'MAX of open: ' + max.toFixed(4) + '<br>'
// ].join(' ');
// }
// chart && chart.dispatchAction({
// type: 'brush',
// areas: [
// {
// brushType: 'lineX',
// coordRange: ['2016-06-02', '2016-06-20'],
// xAxisIndex: 0
// }
// ]
// });
}
run();
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="../dist/echarts.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="lib/frameInsight.js"></script>
<link rel="stylesheet" href="lib/reset.css" />
</head>
<body>
<style>
.test-title {
background: #146402;
color: #fff;
}
</style>
<div id="main0"></div>
<div id="panel0"></div>
<div id="duration"></div>
<script>
// The data count is from a real requirement.
var rawDataCount = 2e5;
function run() {
var data = generateOHLC(rawDataCount);
// var result = reorder(data);
init(data);
}
function generateOHLC(count) {
var data = [];
var xValue = +new Date(2011, 0, 1);
var minute = 60 * 1000;
var baseValue = Math.random() * 12000;
var tmpVals = 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;
}
tmpVals.sort();
var idxRandom = Math.random();
var openIdx = Math.round(Math.random() * 3);
var closeIdx = Math.round(Math.random() * 2);
if (closeIdx === openIdx) {
closeIdx++;
}
// ['open', 'close', 'lowest', 'highest']
// [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
]);
}
return data;
}
function calculateMA(dayCount, data) {
var result = [];
for (var i = 0, len = data.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++) {
sum += data[i - j][2];
}
result.push(+(sum / dayCount).toFixed(3));
}
return result;
}
function init(rawData) {
frameInsight.init(echarts, 'duration');
var option = {
dataset: {
source: rawData
},
backgroundColor: '#eee',
// animation: false,
legend: {
left: 0
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line'
}
},
toolbox: {
feature: {
dataZoom: {
yAxisIndex: false
},
brush: {
type: ['polygon', 'rect', 'lineX', 'lineY', 'keep', 'clear']
}
}
},
// brush: {
// xAxisIndex: 'all',
// brushLink: 'all',
// outOfBrush: {
// colorAlpha: 0.1
// }
// },
grid: [
{
left: '10%',
right: '10%',
height: 300
},
// {
// left: '10%',
// right: '10%',
// height: 70,
// bottom: 80
// }
],
xAxis: [
{
type: 'category',
scale: true,
boundaryGap : false,
axisLine: {onZero: false},
splitLine: {show: false},
splitNumber: 20,
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'
// }
],
yAxis: [
{
scale: true,
splitArea: {
show: true
}
},
// {
// scale: true,
// gridIndex: 1,
// splitNumber: 2,
// axisLabel: {show: false},
// axisLine: {show: false},
// axisTick: {show: false},
// splitLine: {show: false}
// }
],
dataZoom: [
{
type: 'inside',
// xAxisIndex: [0, 1],
start: 10,
end: 100
},
{
show: true,
// xAxisIndex: [0, 1],
type: 'slider',
bottom: 10,
start: 10,
end: 100
}
],
series: [
{
name: 'Fake index',
type: 'candlestick',
// data: data,
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',
// data: calculateMA(5, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'MA10',
// type: 'line',
// data: calculateMA(10, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'MA20',
// type: 'line',
// data: calculateMA(20, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'MA30',
// type: 'line',
// data: calculateMA(30, data),
// smooth: true,
// lineStyle: {
// normal: {opacity: 0.5}
// }
// },
// {
// name: 'Volumn',
// type: 'bar',
// xAxisIndex: 1,
// yAxisIndex: 1,
// data: data.volumns
// }
]
};
var panel = document.getElementById('panel0');
var chart = testHelper.create(echarts, 'main0', {
title: 'Fake OHLC data',
option: option,
height: 550
});
// chart && chart.on('brushSelected', renderBrushed);
// function renderBrushed(params) {
// var sum = 0;
// var min = Infinity;
// var max = -Infinity;
// var countBySeries = [];
// var brushComponent = params.batch[0];
// var rawIndices = brushComponent.selected[0].dataIndex;
// for (var i = 0; i < rawIndices.length; i++) {
// var val = data.values[rawIndices[i]][1];
// sum += val;
// min = Math.min(val, min);
// max = Math.max(val, max);
// }
// panel.innerHTML = [
// '<h3>STATISTICS:</h3>',
// 'SUM of open: ' + (sum / rawIndices.length).toFixed(4) + '<br>',
// 'MIN of open: ' + min.toFixed(4) + '<br>',
// 'MAX of open: ' + max.toFixed(4) + '<br>'
// ].join(' ');
// }
// chart && chart.dispatchAction({
// type: 'brush',
// areas: [
// {
// brushType: 'lineX',
// coordRange: ['2016-06-02', '2016-06-20'],
// xAxisIndex: 0
// }
// ]
// });
}
run();
</script>
</body>
</html>
\ No newline at end of file
......@@ -150,6 +150,11 @@
name: '上证指数',
type: 'candlestick',
data: data.values,
// itemStyle: {
// borderColor: '#345',
// borderColor0: '#998',
// borderWidth: 2
// },
tooltip: {
formatter: function (param) {
var param = param[0];
......
......@@ -139,9 +139,9 @@
var domStyle = dom.style;
// domStyle.border = '2px solid #333';
domStyle.boxShadow = '0 0 3px #000';
domStyle.backgroundColor = '#fff';
domStyle.backgroundColor = '#eee';
domStyle.padding = '0';
domStyle.height = '80px';
domStyle.height = '60px';
domStyle.margin = '10px 20px';
var domWidth = getSize(dom, 0);
......
......@@ -59,7 +59,7 @@
},
yAxis: {
},
dataZoom: [{}, {type: 'inside'}],
dataZoom: [{end: 90}, {type: 'inside', end: 90}],
series: [{
name: 'large-line',
type: 'line',
......
......@@ -111,7 +111,7 @@
largeThreshold: 100,
lineStyle: {
normal: {
opacity: 0.05,
opacity: 0.5,
width: 0.5,
curveness: 0.3
}
......
<html>
<head>
<meta charset='utf-8'>
<script src='lib/esl.js'></script>
<script src='lib/config.js'></script>
<script src='lib/jquery.min.js'></script>
<script src='lib/testHelper.js'></script>
<link rel="stylesheet" href="lib/reset.css" />
<meta name='viewport' content='width=device-width, initial-scale=1' />
</head>
<body>
<style>
html, body, #main0 {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<div id='main0'></div>
<script>
var xs = [440000, 450000];
var ys = [4368000, 4537000];
require([
'echarts'
], function (echarts) {
$.get('../map/json/world.json', function (worldJson) {
echarts.registerMap('world', worldJson);
var linesCount = 35663;
var chart;
var routes = [];
var lngStep = 0.01;
var lng0 = -160;
var lng1 = lng0 + linesCount * lngStep;
for (var i = 0; i < linesCount; i++) {
var lng = lng0 + i * lngStep;
var lat0 = 0;
var lat1 = 90;
// if (i % 1000 < 500) {
// lat0 = 30;
// lat1 = 120;
// }
routes.push([[lng, lat0], [lng, lat1]]);
}
var option = {
title: {
text: 'World Flights',
left: 'center',
textStyle: {
color: '#eee'
}
},
backgroundColor: '#003',
tooltip: {
formatter: function (param) {
return 'Line: ' + param.dataIndex;
}
},
geo: {
map: 'world',
left: 0,
right: 0,
zoom: 0.3,
roam: true,
silent: true,
itemStyle: {
normal: {
borderColor: '#003',
color: '#005'
}
}
},
series: [{
type: 'lines',
coordinateSystem: 'geo',
blendModel: 'lighter',
data: routes,
large: true,
// large: false,
largeThreshold: 0,
// progressive: 5e3,
progressiveThreshold: 101,
lineStyle: {
normal: {
opacity: 1,
width: 1,
// curveness: 0.3
}
},
// blendMode: 'lighter'
}, {
type: 'scatter',
coordinateSystem: 'geo',
symbolSize: 5,
color: ['green'],
data: [
{
value: [lng0, 30],
label: {
show: true,
position: 'top',
formatter: 'longitude start'
}
}, {
value: [lng1, 30],
label: {
show: true,
position: 'top',
formatter: 'longitude end'
}
}
]
}]
};
var chart = testHelper.create(echarts, 'main0', {
title: [
linesCount + ' lines should be rendered vertically side by side ',
'from the left green point to the right green point, NO GAP.',
'( large:true and el.incremetal = true) ',
'And check roam.'
],
option: option,
height: 550
});
chart.on('finished', function () {
console.log('finished');
});
});
});
</script>
</body>
</html>
\ No newline at end of file
<html>
<head>
<meta charset='utf-8'>
<script src='lib/esl.js'></script>
<script src='lib/config.js'></script>
<script src='lib/jquery.min.js'></script>
<script src="lib/dat.gui.min.js"></script>
<meta name='viewport' content='width=device-width, initial-scale=1' />
</head>
<body>
<style>
html, body, #main {
width: 100%;
height: 100%;
margin: 0;
}
#info {
position: fixed;
left: 5;
top: 5;
height: 100px;
width: 200px;
background: #fff;
border: 2px solid #999;
z-index: 9999;
}
</style>
<div id="info">Rendering (large: false), please wait ...</div>
<div id='main'></div>
<script>
var xs = [440000, 450000];
var ys = [4368000, 4537000];
var dataURL = './data/flight.json';
require([
'echarts'
// 'echarts/chart/lines',
// 'echarts/component/legend',
// 'extension/bmap'
], function (echarts) {
$.get('../map/json/world.json', function (worldJson) {
echarts.registerMap('world', worldJson);
$.get(dataURL, function (data) {
var config = {
dataLoading: 'whole',
streamThreshold: 0,
streamRender: true,
largeModel: true
};
var chart;
var infoEl = document.getElementById('info');
init();
function init() {
if (chart) {
chart.dispose();
}
chart = echarts.init(document.getElementById('main'));
function getAirportCoord(idx) {
return [data.airports[idx][3], data.airports[idx][4]];
}
var routes = data.routes.map(function (airline) {
return [
getAirportCoord(airline[1]),
getAirportCoord(airline[2])
];
});
var option = {
streamStep: 4000,
title: {
text: 'World Flights',
left: 'center',
textStyle: {
color: '#eee'
}
},
backgroundColor: '#003',
tooltip: {
formatter: function (param) {
var route = data.routes[param.dataIndex];
return data.airports[route[1]][1] + ' > ' + data.airports[route[2]][1];
}
},
geo: {
map: 'world',
left: 0,
right: 0,
roam: true,
silent: true,
itemStyle: {
normal: {
borderColor: '#003',
color: '#005'
}
}
},
series: [{
type: 'lines',
coordinateSystem: 'geo',
blendModel: 'lighter',
data: routes,
// Test not large mode.
large: false,
largeThreshold: 100,
lineStyle: {
normal: {
opacity: 0.05,
width: 0.5,
curveness: 0.3
}
},
// 设置混合模式为叠加
blendMode: 'lighter'
}]
};
chart.on('finished', function () {
infoEl.innerHTML = 'Finished (large: false). Please test roam (in not large mode, should no error thrown';
});
chart.setOption(option);
}
});
});
});
</script>
</body>
</html>
\ No newline at end of file
<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>
</head>
<body>
<style>
html, body, #main {
width: 100%;
height: 90%;
/*border: 1px solid #000;*/
}
</style>
<div id="main"><div>
<script>
require([
'echarts'
// 'echarts/chart/sankey',
// 'echarts/component/tooltip'
], function (echarts) {
var chart = echarts.init(document.getElementById('main'), null, {
});
window.onresize = function () {
chart.resize();
};
chart.on('click', function (params) {
console.log(params, params.data);
});
var data = {
nodes: [
{name: 'Brazil'},
{name: 'Canada'},
{name: 'Mexico'},
{name: 'USA'},
{name: 'Portugal'},
{name: 'France'},
{name: 'Spain'},
{name: 'England'},
{name: 'Angola'},
{name: 'Senegal'},
{name: 'Morocco'},
{name: 'South Africa'},
{name: 'Mali'},
{name: 'China'},
{name: 'India'},
{name: 'Japan'}
],
links: [
{source: 'Brazil', target: 'Portugal', value: 5},
{source: 'Brazil', target: 'France', value: 1},
{source: 'Brazil', target: 'Spain', value: 1},
{source: 'Brazil', target: 'England', value: 1},
{source: 'Canada', target: 'Portugal', value: 1},
{source: 'Canada', target: 'France', value: 5},
{source: 'Canada', target: 'England', value: 1},
{source: 'Mexico', target: 'Portugal', value: 1},
{source: 'Mexico', target: 'France', value: 1},
{source: 'Mexico', target: 'Spain', value: 5},
{source: 'Mexico', target: 'England', value: 1},
{source: 'USA', target: 'Portugal', value: 1},
{source: 'USA', target: 'France', value: 1},
{source: 'USA', target: 'Spain', value: 1},
{source: 'USA', target: 'England', value: 5},
{source: 'Portugal', target: 'Angola', value: 2},
{source: 'Portugal', target: 'Senegal', value: 1},
{source:'Portugal', target: 'Morocco', value: 1},
{source: 'Portugal', target: 'South Africa', value: 3},
{source: 'France', target: 'Angola', value: 1},
{source: 'France', target: 'Senegal', value: 3},
{source: 'France', target: 'Mali', value: 3},
{source: 'France', target: 'Morocco', value: 3},
{source: 'France', target: 'South Africa', value: 1},
{source: 'Spain', target: 'Senegal', value: 1},
{source: 'Spain', target: 'Morocco', value: 3},
{source: 'Spain', target: 'South Africa', value: 1},
{source: 'England', target: 'Angola', value: 1},
{source: 'England', target: 'Senegal', value: 1},
{source: 'England', target: 'Morocco', value: 2},
{source: 'England', target: 'South Africa', value: 7},
{source: 'South Africa', target: 'China', value: 5},
{source: 'South Africa', target: 'India', value: 1},
{source: 'South Africa', target: 'Japan', value: 3},
{source: 'Angola', target: 'China', value: 5},
{source: 'Angola', target: 'India', value: 1},
{source: 'Angola', target: 'Japan', value: 3},
{source: 'Senegal', target: 'China', value: 5},
{source: 'Senegal', target: 'India', value: 1},
{source: 'Senegal', target: 'Japan', value: 3},
{source: 'Mali', target: 'China', value: 5},
{source: 'Mali', target: 'India', value: 1},
{source: 'Mali', target: 'Japan', value: 3},
{source: 'Morocco', target: 'China', value: 5},
{source: 'Morocco', target: 'India', value: 1},
{source: 'Morocco', target: 'Japan', value: 3}
]
};
chart.setOption({
color: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061'],
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
animation: false,
series: [
{
type: 'sankey',
layout:'none',
data: data.nodes,
links: data.links,
// data: [],
// links: [],
lineStyle: {
normal: {
color: 'source',
curveness: 0.5
}
}
}
]
});
});
</script>
</body>
</html>
\ No newline at end of file
<html>
<head>
<meta charset='utf-8'>
<script src='lib/esl.js'></script>
<script src='lib/config.js'></script>
<script src='lib/jquery.min.js'></script>
<script src='lib/testHelper.js'></script>
<link rel="stylesheet" href="lib/reset.css" />
<meta name='viewport' content='width=device-width, initial-scale=1' />
</head>
<body>
<style>
html, body, #main0 {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<div id='main0'></div>
<script>
var xs = [440000, 450000];
var ys = [4368000, 4537000];
require([
'echarts'
], function (echarts) {
$.get('../map/json/world.json', function (worldJson) {
echarts.registerMap('world', worldJson);
var count = 35663;
var lngCount = 1000;
var chart;
var points = [];
var lngStep = 0.3;
var latStep = 1;
var lng0 = -160;
var lng1 = lng0 + lngCount * lngStep;
var lat0 = 0;
var lat1 = lat0 + Math.floor(count / lngCount) * latStep;
for (var i = 0; i < count; i++) {
var iLng = i % lngCount;
var iLat = Math.floor(i / lngCount);
var lng = lng0 + iLng * lngStep;
var lat = lat0 + iLat * latStep;
points.push([lng, lat]);
}
var option = {
title: {
text: 'World Flights',
left: 'center',
textStyle: {
color: '#eee'
}
},
backgroundColor: '#003',
tooltip: {
formatter: function (param) {
return 'Point: ' + param.value[0] + ', ' + param.value[1];
}
},
geo: {
map: 'world',
left: 0,
right: 0,
zoom: 0.5,
roam: true,
silent: true,
itemStyle: {
normal: {
borderColor: '#003',
color: '#005'
}
}
},
series: [{
type: 'scatter',
coordinateSystem: 'geo',
blendModel: 'lighter',
data: points,
symbol: 'rect',
symbolSize: 6,
large: true,
// large: false,
largeThreshold: 100,
progressiveThreshold: 101
}, {
type: 'scatter',
coordinateSystem: 'geo',
symbolSize: 5,
color: ['green'],
data: [
{
value: [lng0, lat0],
label: {
show: true,
position: 'top',
formatter: 'bottom-left'
}
}, {
value: [lng1, lat0],
label: {
show: true,
position: 'top',
formatter: 'bottom-right'
}
}, {
value: [lng0, lat1],
label: {
show: true,
position: 'bottom',
formatter: 'top-left'
}
}, {
value: [lng1, lat1],
label: {
show: true,
position: 'bottom',
formatter: 'top-right'
}
}
]
}]
};
var chart = testHelper.create(echarts, 'main0', {
title: [
count + ' points should be rendered in the area of the 4 green points',
'( large:true and el.incremetal = true) ',
'And check roam.'
],
option: option,
height: 550
});
chart.on('finished', function () {
console.log('finished');
});
});
});
</script>
</body>
</html>
\ No newline at end of file
<html>
<head>
<meta charset='utf-8'>
<script src='lib/esl.js'></script>
<script src='lib/config.js'></script>
<script src='lib/jquery.min.js'></script>
<script src='lib/testHelper.js'></script>
<link rel="stylesheet" href="lib/reset.css" />
<meta name='viewport' content='width=device-width, initial-scale=1' />
</head>
<body>
<style>
html, body, #main0 {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<div id='main0'></div>
<script>
var xs = [440000, 450000];
var ys = [4368000, 4537000];
require([
'echarts'
], function (echarts) {
$.get('../map/json/world.json', function (worldJson) {
echarts.registerMap('world', worldJson);
var count = 35663;
var lngCount = 1000;
var chart;
var points = [];
var lngStep = 0.3;
var latStep = 1;
var lng0 = -160;
var lng1 = lng0 + lngCount * lngStep;
var lat0 = 0;
var lat1 = lat0 + Math.floor(count / lngCount) * latStep;
for (var i = 0; i < count; i++) {
var iLng = i % lngCount;
var iLat = Math.floor(i / lngCount);
var lng = lng0 + iLng * lngStep;
var lat = lat0 + iLat * latStep;
points.push([lng, lat]);
}
var option = {
title: {
text: 'World Flights',
left: 'center',
textStyle: {
color: '#eee'
}
},
backgroundColor: '#003',
tooltip: {
formatter: function (param) {
return 'Point: ' + param.value[0] + ', ' + param.value[1];
}
},
geo: {
map: 'world',
left: 0,
right: 0,
zoom: 0.5,
roam: true,
silent: true,
itemStyle: {
normal: {
borderColor: '#003',
color: '#005'
}
}
},
series: [{
type: 'scatter',
coordinateSystem: 'geo',
blendModel: 'lighter',
data: points,
symbol: 'rect',
symbolSize: 6,
// large: true,
large: false,
largeThreshold: 100,
progressiveThreshold: 101
}, {
type: 'scatter',
coordinateSystem: 'geo',
symbolSize: 5,
color: ['green'],
data: [
{
value: [lng0, lat0],
label: {
show: true,
position: 'top',
formatter: 'bottom-left'
}
}, {
value: [lng1, lat0],
label: {
show: true,
position: 'top',
formatter: 'bottom-right'
}
}, {
value: [lng0, lat1],
label: {
show: true,
position: 'bottom',
formatter: 'top-left'
}
}, {
value: [lng1, lat1],
label: {
show: true,
position: 'bottom',
formatter: 'top-right'
}
}
]
}]
};
var chart = testHelper.create(echarts, 'main0', {
title: [
count + ' points should be rendered in the area of the 4 green points',
'( large:true and el.incremetal = true) ',
'And check roam.'
],
option: option,
height: 550
});
chart.on('finished', function () {
console.log('finished');
});
});
});
</script>
</body>
</html>
\ No newline at end of file
......@@ -47,6 +47,7 @@
series:[
{
type: 'tree',
id: 'a',
data: [data],
......@@ -78,6 +79,20 @@
}
]
});
setTimeout(function () {
var newData = echarts.util.clone(data);
newData.children.splice(0, 1);
chart.setOption({
series: {
id: 'a',
data: [newData]
}
});
}, 1000);
});
});
</script>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册