362 lines
11 KiB
JavaScript
362 lines
11 KiB
JavaScript
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
var _config = require("../../config");
|
|
|
|
var __DEV__ = _config.__DEV__;
|
|
|
|
var echarts = require("../../echarts");
|
|
|
|
var zrUtil = require("zrender/lib/core/util");
|
|
|
|
var graphic = require("../../util/graphic");
|
|
|
|
var _helper = require("./helper");
|
|
|
|
var setLabel = _helper.setLabel;
|
|
|
|
var Model = require("../../model/Model");
|
|
|
|
var barItemStyle = require("./barItemStyle");
|
|
|
|
var Path = require("zrender/lib/graphic/Path");
|
|
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
var BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth']; // FIXME
|
|
// Just for compatible with ec2.
|
|
|
|
zrUtil.extend(Model.prototype, barItemStyle);
|
|
|
|
var _default = echarts.extendChartView({
|
|
type: 'bar',
|
|
render: function (seriesModel, ecModel, api) {
|
|
this._updateDrawMode(seriesModel);
|
|
|
|
var coordinateSystemType = seriesModel.get('coordinateSystem');
|
|
|
|
if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') {
|
|
this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api);
|
|
} else {}
|
|
|
|
return this.group;
|
|
},
|
|
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();
|
|
}
|
|
},
|
|
_renderNormal: function (seriesModel, ecModel, api) {
|
|
var group = this.group;
|
|
var data = seriesModel.getData();
|
|
var oldData = this._data;
|
|
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).add(function (dataIndex) {
|
|
if (!data.hasValue(dataIndex)) {
|
|
return;
|
|
}
|
|
|
|
var itemModel = data.getItemModel(dataIndex);
|
|
var layout = getLayout[coord.type](data, dataIndex, itemModel);
|
|
var el = elementCreator[coord.type](data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel);
|
|
data.setItemGraphicEl(dataIndex, el);
|
|
group.add(el);
|
|
updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
|
|
}).update(function (newIndex, oldIndex) {
|
|
var el = oldData.getItemGraphicEl(oldIndex);
|
|
|
|
if (!data.hasValue(newIndex)) {
|
|
group.remove(el);
|
|
return;
|
|
}
|
|
|
|
var itemModel = data.getItemModel(newIndex);
|
|
var layout = getLayout[coord.type](data, newIndex, itemModel);
|
|
|
|
if (el) {
|
|
graphic.updateProps(el, {
|
|
shape: layout
|
|
}, animationModel, newIndex);
|
|
} else {
|
|
el = elementCreator[coord.type](data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true);
|
|
}
|
|
|
|
data.setItemGraphicEl(newIndex, el); // Add back
|
|
|
|
group.add(el);
|
|
updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
|
|
}).remove(function (dataIndex) {
|
|
var el = oldData.getItemGraphicEl(dataIndex);
|
|
|
|
if (coord.type === 'cartesian2d') {
|
|
el && removeRect(dataIndex, animationModel, el);
|
|
} else {
|
|
el && removeSector(dataIndex, animationModel, el);
|
|
}
|
|
}).execute();
|
|
this._data = data;
|
|
},
|
|
_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 && ecModel.get('animation') && data && !this._isLargeDraw) {
|
|
data.eachItemGraphicEl(function (el) {
|
|
if (el.type === 'sector') {
|
|
removeSector(el.dataIndex, ecModel, el);
|
|
} else {
|
|
removeRect(el.dataIndex, ecModel, el);
|
|
}
|
|
});
|
|
} else {
|
|
group.removeAll();
|
|
}
|
|
|
|
this._data = null;
|
|
}
|
|
});
|
|
|
|
var elementCreator = {
|
|
cartesian2d: function (data, dataIndex, itemModel, layout, isHorizontal, animationModel, isUpdate) {
|
|
var rect = new graphic.Rect({
|
|
shape: zrUtil.extend({}, layout)
|
|
}); // Animation
|
|
|
|
if (animationModel) {
|
|
var rectShape = rect.shape;
|
|
var animateProperty = isHorizontal ? 'height' : 'width';
|
|
var animateTarget = {};
|
|
rectShape[animateProperty] = 0;
|
|
animateTarget[animateProperty] = layout[animateProperty];
|
|
graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {
|
|
shape: animateTarget
|
|
}, animationModel, dataIndex);
|
|
}
|
|
|
|
return rect;
|
|
},
|
|
polar: function (data, dataIndex, itemModel, layout, isRadial, animationModel, isUpdate) {
|
|
// Keep the same logic with bar in catesion: use end value to control
|
|
// direction. Notice that if clockwise is true (by default), the sector
|
|
// will always draw clockwisely, no matter whether endAngle is greater
|
|
// or less than startAngle.
|
|
var clockwise = layout.startAngle < layout.endAngle;
|
|
var sector = new graphic.Sector({
|
|
shape: zrUtil.defaults({
|
|
clockwise: clockwise
|
|
}, layout)
|
|
}); // Animation
|
|
|
|
if (animationModel) {
|
|
var sectorShape = sector.shape;
|
|
var animateProperty = isRadial ? 'r' : 'endAngle';
|
|
var animateTarget = {};
|
|
sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;
|
|
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 = null;
|
|
graphic.updateProps(el, {
|
|
shape: {
|
|
width: 0
|
|
}
|
|
}, animationModel, dataIndex, function () {
|
|
el.parent && el.parent.remove(el);
|
|
});
|
|
}
|
|
|
|
function removeSector(dataIndex, animationModel, el) {
|
|
// Not show text when animating
|
|
el.style.text = null;
|
|
graphic.updateProps(el, {
|
|
shape: {
|
|
r: el.shape.r0
|
|
}
|
|
}, animationModel, dataIndex, function () {
|
|
el.parent && el.parent.remove(el);
|
|
});
|
|
}
|
|
|
|
var getLayout = {
|
|
cartesian2d: function (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 {
|
|
x: layout.x + signX * fixedLineWidth / 2,
|
|
y: layout.y + signY * fixedLineWidth / 2,
|
|
width: layout.width - signX * fixedLineWidth,
|
|
height: layout.height - signY * fixedLineWidth
|
|
};
|
|
},
|
|
polar: function (data, dataIndex, itemModel) {
|
|
var layout = data.getItemLayout(dataIndex);
|
|
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, isPolar) {
|
|
var color = data.getItemVisual(dataIndex, 'color');
|
|
var opacity = data.getItemVisual(dataIndex, 'opacity');
|
|
var itemStyleModel = itemModel.getModel('itemStyle');
|
|
var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();
|
|
|
|
if (!isPolar) {
|
|
el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);
|
|
}
|
|
|
|
el.useStyle(zrUtil.defaults({
|
|
fill: color,
|
|
opacity: opacity
|
|
}, itemStyleModel.getBarItemStyle()));
|
|
var cursorStyle = itemModel.getShallow('cursor');
|
|
cursorStyle && el.attr('cursor', cursorStyle);
|
|
var labelPositionOutside = isHorizontal ? layout.height > 0 ? 'bottom' : 'top' : layout.width > 0 ? 'left' : 'right';
|
|
|
|
if (!isPolar) {
|
|
setLabel(el.style, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside);
|
|
}
|
|
|
|
graphic.setHoverStyle(el, hoverStyle);
|
|
} // In case width or height are too small.
|
|
|
|
|
|
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');
|
|
}
|
|
|
|
module.exports = _default; |