提交 c40a19a6 编写于 作者: O Ovilia

add radial bar chart for polar system

上级 2ac7cc7d
......@@ -8,9 +8,12 @@ define(function (require) {
require('./bar/BarView');
var barLayoutGrid = require('../layout/barGrid');
var barLayoutPolar = require('../layout/barPolar');
var echarts = require('../echarts');
echarts.registerLayout(zrUtil.curry(barLayoutGrid, 'bar'));
echarts.registerLayout(zrUtil.curry(barLayoutPolar, 'bar'));
// Visual coding for legend
echarts.registerVisual(function (ecModel) {
ecModel.eachSeriesByType('bar', function (seriesModel) {
......
......@@ -19,8 +19,13 @@ define(function (require) {
render: function (seriesModel, ecModel, api) {
var coordinateSystemType = seriesModel.get('coordinateSystem');
if (coordinateSystemType === 'cartesian2d') {
this._renderOnCartesian(seriesModel, ecModel, api);
if (coordinateSystemType === 'cartesian2d'
|| coordinateSystemType === 'polar')
{
this._render(seriesModel, ecModel, api);
}
else if (__DEV__) {
console.warn('Only cartesian2d and polar supported for bar.');
}
return this.group;
......@@ -28,14 +33,22 @@ define(function (require) {
dispose: zrUtil.noop,
_renderOnCartesian: function (seriesModel, ecModel, api) {
_render: function (seriesModel, ecModel, api) {
var group = this.group;
var data = seriesModel.getData();
var oldData = this._data;
var cartesian = seriesModel.coordinateSystem;
var baseAxis = cartesian.getBaseAxis();
var isHorizontal = baseAxis.isHorizontal();
var coord = seriesModel.coordinateSystem;
var baseAxis = coord.getBaseAxis();
var isHorizontalOrRadial;
if (coord.type === 'cartesian2d') {
isHorizontalOrRadial = baseAxis.isHorizontal();
}
else if (coord.type === 'polar') {
isHorizontalOrRadial = baseAxis.dim === 'angle';
}
var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
data.diff(oldData)
......@@ -45,12 +58,14 @@ define(function (require) {
}
var itemModel = data.getItemModel(dataIndex);
var layout = getRectItemLayout(data, dataIndex, itemModel);
var el = createRect(data, dataIndex, itemModel, layout, isHorizontal, animationModel);
var layout = getLayout(coord, data, dataIndex, itemModel);
var el = createElement(coord, data, dataIndex, itemModel,
layout, isHorizontalOrRadial, animationModel);
data.setItemGraphicEl(dataIndex, el);
group.add(el);
updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal);
updateStyle(el, data, dataIndex, itemModel, layout,
seriesModel, isHorizontalOrRadial);
})
.update(function (newIndex, oldIndex) {
var el = oldData.getItemGraphicEl(oldIndex);
......@@ -61,23 +76,27 @@ define(function (require) {
}
var itemModel = data.getItemModel(newIndex);
var layout = getRectItemLayout(data, newIndex, itemModel);
var layout = getLayout(coord, data, newIndex, itemModel);
if (el) {
graphic.updateProps(el, {shape: layout}, animationModel, newIndex);
}
else {
el = createRect(data, newIndex, itemModel, layout, isHorizontal, animationModel, true);
el = createElement(coord, data, dataIndex, itemModel,
layout, isHorizontalOrRadial, animationModel, true);
}
data.setItemGraphicEl(newIndex, el);
// Add back
group.add(el);
updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontal);
// TODO: update different coord
updateStyle(el, data, newIndex, itemModel, layout,
seriesModel, isHorizontalOrRadial);
})
.remove(function (dataIndex) {
var el = oldData.getItemGraphicEl(dataIndex);
// TODO: remove sector
el && removeRect(dataIndex, animationModel, el);
})
.execute();
......@@ -101,7 +120,23 @@ define(function (require) {
}
});
function createRect(data, dataIndex, itemModel, layout, isHorizontal, animationModel, isUpdate) {
// Create rect or sector based on coord
function createElement(coord, data, dataIndex, itemModel, layout,
isHorizontalOrRadial, animationModel, isUpdate)
{
if (coord.type === 'cartesian2d') {
return createRect(data, dataIndex, itemModel, layout,
isHorizontalOrRadial, animationModel, isUpdate);
}
else if (coord.type === 'polar') {
return createSector(data, dataIndex, itemModel, layout,
isHorizontalOrRadial, animationModel, isUpdate);
}
}
function createRect(data, dataIndex, itemModel, layout, isHorizontal,
animationModel, isUpdate)
{
var rect = new graphic.Rect({shape: zrUtil.extend({}, layout)});
// Animation
......@@ -119,6 +154,26 @@ define(function (require) {
return rect;
}
function createSector(data, dataIndex, itemModel, layout, isRadial,
animationModel, isUpdate)
{
var sector = new graphic.Sector({ shape: zrUtil.extend({}, layout) });
// Animation
if (animationModel) {
var sectorShape = sector.shape;
var animateProperty = isRadial ? 'r' : 'endAngle';
var animateTarget = {};
sectorShape[animateProperty] = 0;
animateTarget[animateProperty] = layout[animateProperty];
graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {
shape: animateTarget
}, animationModel, dataIndex);
}
return sector;
}
function removeRect(dataIndex, animationModel, el) {
// Not show text when animating
el.style.text = '';
......@@ -131,6 +186,15 @@ define(function (require) {
});
}
function getLayout(coord, data, dataIndex, itemModel) {
if (coord.type === 'cartesian2d') {
return getRectItemLayout(data, dataIndex, itemModel);
}
else if (coord.type === 'polar') {
return getSectorItemLayout(data, dataIndex, itemModel);
}
}
function getRectItemLayout(data, dataIndex, itemModel) {
var layout = data.getItemLayout(dataIndex);
var fixedLineWidth = getLineWidth(itemModel, layout);
......@@ -146,13 +210,32 @@ define(function (require) {
};
}
function getSectorItemLayout(data, dataIndex, itemModel) {
var layout = data.getItemLayout(dataIndex);
// var fixedLineWidth = getLineWidth(itemModel, layout);
// fix layout with lineWidth
// var signX = layout.width > 0 ? 1 : -1;
// var signY = layout.height > 0 ? 1 : -1;
return {
cx: layout.cx,
cy: layout.cy,
r0: layout.r0,
r: layout.r,
startAngle: layout.startAngle,
endAngle: layout.endAngle
};
}
function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal) {
var color = data.getItemVisual(dataIndex, 'color');
var opacity = data.getItemVisual(dataIndex, 'opacity');
var itemStyleModel = itemModel.getModel('itemStyle.normal');
var hoverStyle = itemModel.getModel('itemStyle.emphasis').getBarItemStyle();
el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);
if (isHorizontal) {
el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);
}
el.useStyle(zrUtil.defaults(
{
......
......@@ -10,12 +10,6 @@ define(function(require) {
type: 'series.__base_bar__',
getInitialData: function (option, ecModel) {
if (__DEV__) {
var coordSys = option.coordinateSystem;
if (coordSys !== 'cartesian2d') {
throw new Error('Bar only support cartesian2d coordinateSystem');
}
}
return createListFromArray(option.data, this, ecModel);
},
......
......@@ -172,8 +172,9 @@ define(function(require) {
* `[[10, 10], [20, 20], [30, 30]]`
*/
dataToPoints: function (data) {
var that = this;
return data.mapArray(this.dimensions, function (radius, angle) {
return this.dataToPoint([radius, angle]);
return that.dataToPoint([radius, angle]);
}, this);
},
......
......@@ -44,9 +44,6 @@ define(function (require) {
function DefaultDataProvider(dataArray) {
this._array = dataArray || [];
}
DefaultDataProvider.prototype.pure = false;
DefaultDataProvider.prototype.count = function () {
return this._array.length;
};
......@@ -234,8 +231,6 @@ define(function (require) {
* @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number
*/
listProto.initData = function (data, nameList, dimValueGetter) {
data = data || [];
var isDataArray = zrUtil.isArray(data);
if (isDataArray) {
data = new DefaultDataProvider(data);
......
......@@ -161,6 +161,11 @@ define(function(require) {
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
// Check series coordinate, do layout for cartesian2d only
if (seriesModel.coordinateSystem.type !== 'cartesian2d') {
return;
}
var data = seriesModel.getData();
var cartesian = seriesModel.coordinateSystem;
var baseAxis = cartesian.getBaseAxis();
......
define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
var parsePercent = require('../util/number').parsePercent;
function getSeriesStackId(seriesModel) {
return seriesModel.get('stack')
|| '__ec_stack_' + seriesModel.seriesIndex;
}
/**
* @param {string} seriesType
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
function barLayoutPolar(seriesType, ecModel, api) {
var width = api.getWidth();
var height = api.getHeight();
var size = Math.min(width, height);
var lastStackCoords = {};
var lastStackCoordsOrigin = {};
var barWidthAndOffset = calRadialBar(
zrUtil.filter(
ecModel.getSeriesByType(seriesType),
function (seriesModel) {
return !ecModel.isSeriesFiltered(seriesModel)
&& seriesModel.coordinateSystem
&& seriesModel.coordinateSystem.type === 'polar';
}
)
);
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
console.log('');
// Check series coordinate, do layout for polar only
if (seriesModel.coordinateSystem.type !== 'polar') {
return;
}
var data = seriesModel.getData();
var polar = seriesModel.coordinateSystem;
var baseAxis = polar.getBaseAxis();
var axisExtent = baseAxis.getExtent();
var stackId = getSeriesStackId(seriesModel);
var columnLayoutInfo =
barWidthAndOffset[getAxisKey(baseAxis)][stackId];
var columnOffset = columnLayoutInfo.offset;
var columnWidth = columnLayoutInfo.width;
var valueAxis = polar.getOtherAxis(baseAxis);
var center = seriesModel.get('center') || ['50%', '50%'];
var cx = parsePercent(center[0], width);
var cy = parsePercent(center[1], height);
var radius = size;
var barMinHeight = seriesModel.get('barMinHeight') || 0;
var bandWidth = baseAxis.type === 'category'
? baseAxis.getBandWidth()
: (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());
var valueAxisStart = valueAxis.getExtent()[0];
var coords = polar.dataToPoints(data, true);
lastStackCoords[stackId] = lastStackCoords[stackId] || [];
lastStackCoordsOrigin[stackId] = lastStackCoordsOrigin[stackId] || []; // Fix #4243
data.each(valueAxis.dim, function (value, idx) {
if (isNaN(value)) {
return;
}
if (!lastStackCoords[stackId][idx]) {
lastStackCoords[stackId][idx] = {
p: valueAxisStart, // Positive stack
n: valueAxisStart // Negative stack
};
lastStackCoordsOrigin[stackId][idx] = {
p: valueAxisStart, // Positive stack
n: valueAxisStart // Negative stack
};
}
var sign = value >= 0 ? 'p' : 'n';
var coord = polar.pointToCoord(coords[idx]);
var lastCoord = lastStackCoords[stackId][idx][sign];
var lastCoordOrigin = lastStackCoordsOrigin[stackId][idx][sign];
var r0;
var r;
var startAngle;
var endAngle;
if (valueAxis.dim === 'radius') {
// radial sector
r0 = lastCoordOrigin;
r = coord[0];
startAngle = (-coord[1] - bandWidth / 2
+ (bandWidth - columnWidth) / 2) * Math.PI / 180;
endAngle = startAngle + columnWidth * Math.PI / 180;
lastStackCoordsOrigin[stackId][idx][sign] += coord[0];
}
else {
// tangential sector
r0 = coord[0] - columnWidth / 2;
r = r0 + columnWidth;
var extent = valueAxis.getExtent();
var limit = function (x) {
return Math.ceil(Math.floor(x, extent[1]), extent[0]);
};
startAngle = -limit(lastCoordOrigin) * Math.PI / 180;
endAngle = -limit(coord[1]) * Math.PI / 180;
console.log(lastCoordOrigin, coord[1]);
if (startAngle === endAngle) {
// check if need to add a round for endAngle
if (value > 0) {
endAngle += Math.PI * 2;
}
else if (value < 0) {
endAngle -= Math.PI * 2;
}
}
lastStackCoordsOrigin[stackId][idx][sign] = coord[1];
}
data.setItemLayout(idx, {
cx: cx,
cy: cy,
r0: r0,
r: r,
startAngle: startAngle,
endAngle: endAngle
});
});
}, this);
}
function getSeriesStackId(seriesModel) {
return seriesModel.get('stack') || '__ec_stack_' + seriesModel.seriesIndex;
}
function getAxisKey(axis) {
return axis.dim;
}
/**
* Calculate bar width and offset for radial bar charts
*/
function calRadialBar(barSeries, api) {
// Columns info on each category axis. Key is polar name
var columnsMap = {};
zrUtil.each(barSeries, function (seriesModel, idx) {
var data = seriesModel.getData();
var polar = seriesModel.coordinateSystem;
var radiusAxis = polar.getRadiusAxis();
var angleAxis = polar.getAngleAxis();
var baseAxis = polar.getBaseAxis();
var axisExtent = baseAxis.getExtent();
var bandWidth = baseAxis.type === 'category'
? baseAxis.getBandWidth()
: (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());
var columnsOnAxis = columnsMap[getAxisKey(baseAxis)] || {
bandWidth: bandWidth,
remainedWidth: bandWidth,
autoWidthCount: 0,
categoryGap: '20%',
gap: '30%',
stacks: {}
};
var stacks = columnsOnAxis.stacks;
columnsMap[getAxisKey(baseAxis)] = columnsOnAxis;
var stackId = getSeriesStackId(seriesModel);
if (!stacks[stackId]) {
columnsOnAxis.autoWidthCount++;
}
stacks[stackId] = stacks[stackId] || {
width: 0,
maxWidth: 0
};
var barWidth = parsePercent(
seriesModel.get('barWidth'), bandWidth
);
var barMaxWidth = parsePercent(
seriesModel.get('barMaxWidth'), bandWidth
);
var barGap = seriesModel.get('barGap');
var barCategoryGap = seriesModel.get('barCategoryGap');
if (barWidth && !stacks[stackId].width) {
barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);
stacks[stackId].width = barWidth;
columnsOnAxis.remainedWidth -= barWidth;
}
barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);
(barGap != null) && (columnsOnAxis.gap = barGap);
(barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);
});
var result = {};
zrUtil.each(columnsMap, function (columnsOnAxis, coordSysName) {
result[coordSysName] = {};
var stacks = columnsOnAxis.stacks;
var bandWidth = columnsOnAxis.bandWidth;
var categoryGap = parsePercent(columnsOnAxis.categoryGap, bandWidth);
var barGapPercent = parsePercent(columnsOnAxis.gap, 1);
var remainedWidth = columnsOnAxis.remainedWidth;
var autoWidthCount = columnsOnAxis.autoWidthCount;
var autoWidth = (remainedWidth - categoryGap)
/ (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
autoWidth = Math.max(autoWidth, 0);
// Find if any auto calculated bar exceeded maxBarWidth
zrUtil.each(stacks, function (column, stack) {
var maxWidth = column.maxWidth;
if (maxWidth && maxWidth < autoWidth) {
maxWidth = Math.min(maxWidth, remainedWidth);
if (column.width) {
maxWidth = Math.min(maxWidth, column.width);
}
remainedWidth -= maxWidth;
column.width = maxWidth;
autoWidthCount--;
}
});
// Recalculate width again
autoWidth = (remainedWidth - categoryGap)
/ (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
autoWidth = Math.max(autoWidth, 0);
var widthSum = 0;
var lastColumn;
zrUtil.each(stacks, function (column, idx) {
if (!column.width) {
column.width = autoWidth;
}
lastColumn = column;
widthSum += column.width * (1 + barGapPercent);
});
if (lastColumn) {
widthSum -= lastColumn.width * barGapPercent;
}
var offset = -widthSum / 2;
zrUtil.each(stacks, function (column, stackId) {
result[coordSysName][stackId] = result[coordSysName][stackId] || {
offset: offset,
width: column.width
};
offset += column.width * (1 + barGapPercent);
});
});
return result;
}
return barLayoutPolar;
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册