define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
var numberUtil = require('../util/number');
var parsePercent = numberUtil.parsePercent;
function getSeriesStackId(seriesModel) {
return seriesModel.get('stack') || '__ec_stack_' + seriesModel.seriesIndex;
}
function calBarWidthAndOffset(barSeries, api) {
// Columns info on each category axis. Key is cartesian name
var columnsMap = {};
zrUtil.each(barSeries, function (seriesModel, idx) {
var cartesian = seriesModel.coordinateSystem;
var baseAxis = cartesian.getBaseAxis();
var columnsOnAxis = columnsMap[baseAxis.index] || {
remainedWidth: baseAxis.getBandWidth(),
autoWidthCount: 0,
categoryGap: '20%',
gap: '30%',
axis: baseAxis,
stacks: {}
};
var stacks = columnsOnAxis.stacks;
columnsMap[baseAxis.index] = columnsOnAxis;
var stackId = getSeriesStackId(seriesModel);
if (!stacks[stackId]) {
columnsOnAxis.autoWidthCount++;
}
stacks[stackId] = stacks[stackId] || {
width: 0,
maxWidth: 0
};
var barWidth = seriesModel.get('barWidth');
var barMaxWidth = seriesModel.get('barMaxWidth');
var barGap = seriesModel.get('barGap');
var barCategoryGap = seriesModel.get('barCategoryGap');
// TODO
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 baseAxis = columnsOnAxis.axis;
var bandWidth = baseAxis.getBandWidth();
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 (!column.width && maxWidth && maxWidth < autoWidth) {
maxWidth = Math.min(maxWidth, remainedWidth);
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;
}
/**
* @param {string} seriesType
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
function barLayoutGrid(seriesType, ecModel, api) {
var barWidthAndOffset = calBarWidthAndOffset(
zrUtil.filter(
ecModel.getSeriesByType(seriesType),
function (seriesModel) {
return !ecModel.isSeriesFiltered(seriesModel)
&& seriesModel.coordinateSystem
&& seriesModel.coordinateSystem.type === 'cartesian2d';
}
)
);
var lastStackCoords = {};
ecModel.eachSeriesByType(seriesType, function (seriesModel) {
var data = seriesModel.getData();
var cartesian = seriesModel.coordinateSystem;
var baseAxis = cartesian.getBaseAxis();
var stackId = getSeriesStackId(seriesModel);
var columnLayoutInfo = barWidthAndOffset[baseAxis.index][stackId];
var columnOffset = columnLayoutInfo.offset;
var columnWidth = columnLayoutInfo.width;
var valueAxis = cartesian.getOtherAxis(baseAxis);
var barMinHeight = seriesModel.get('barMinHeight') || 0;
var valueAxisStart = baseAxis.onZero
? valueAxis.toGlobalCoord(valueAxis.dataToCoord(0))
: valueAxis.getGlobalExtent()[0];
var coords = cartesian.dataToPoints(data, true);
lastStackCoords[stackId] = lastStackCoords[stackId] || [];
data.setLayout({
offset: columnOffset,
size: columnWidth
});
data.each(valueAxis.dim, function (value, idx) {
// ???
if (isNaN(value)) {
return;
}
if (!lastStackCoords[stackId][idx]) {
lastStackCoords[stackId][idx] = {
// Positive stack
p: valueAxisStart,
// Negative stack
n: valueAxisStart
};
}
var sign = value >= 0 ? 'p' : 'n';
var coord = coords[idx];
var lastCoord = lastStackCoords[stackId][idx][sign];
var x, y, width, height;
if (valueAxis.isHorizontal()) {
x = lastCoord;
y = coord[1] + columnOffset;
width = coord[0] - lastCoord;
height = columnWidth;
if (Math.abs(width) < barMinHeight) {
width = (width < 0 ? -1 : 1) * barMinHeight;
}
lastStackCoords[stackId][idx][sign] += width;
}
else {
x = coord[0] + columnOffset;
y = lastCoord;
width = columnWidth;
height = coord[1] - lastCoord;
if (Math.abs(height) < barMinHeight) {
// Include zero to has a positive bar
height = (height <= 0 ? -1 : 1) * barMinHeight;
}
lastStackCoords[stackId][idx][sign] += height;
}
data.setItemLayout(idx, {
x: x,
y: y,
width: width,
height: height
});
}, true);
}, this);
}
return barLayoutGrid;
});
|