in src/chart/bar/BarView.ts [193:461]
private _renderNormal(
seriesModel: BarSeriesModel,
ecModel: GlobalModel,
api: ExtensionAPI,
payload: Payload
): void {
const group = this.group;
const data = seriesModel.getData();
const oldData = this._data;
const coord = seriesModel.coordinateSystem;
const baseAxis = coord.getBaseAxis();
let isHorizontalOrRadial: boolean;
if (coord.type === 'cartesian2d') {
isHorizontalOrRadial = (baseAxis as Axis2D).isHorizontal();
}
else if (coord.type === 'polar') {
isHorizontalOrRadial = baseAxis.dim === 'angle';
}
const animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
const realtimeSortCfg = shouldRealtimeSort(seriesModel, coord);
if (realtimeSortCfg) {
this._enableRealtimeSort(realtimeSortCfg, data, api);
}
const needsClip = seriesModel.get('clip', true) || realtimeSortCfg;
const coordSysClipArea = getClipArea(coord, data);
// If there is clipPath created in large mode. Remove it.
group.removeClipPath();
// We don't use clipPath in normal mode because we needs a perfect animation
// And don't want the label are clipped.
const roundCap = seriesModel.get('roundCap', true);
const drawBackground = seriesModel.get('showBackground', true);
const backgroundModel = seriesModel.getModel('backgroundStyle');
const barBorderRadius = backgroundModel.get('borderRadius') || 0;
const bgEls: BarView['_backgroundEls'] = [];
const oldBgEls = this._backgroundEls;
const isInitSort = payload && payload.isInitSort;
const isChangeOrder = payload && payload.type === 'changeAxisOrder';
function createBackground(dataIndex: number) {
const bgLayout = getLayout[coord.type](data, dataIndex);
const bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout);
bgEl.useStyle(backgroundModel.getItemStyle());
// Only cartesian2d support borderRadius.
if (coord.type === 'cartesian2d') {
(bgEl as Rect).setShape('r', barBorderRadius);
}
else {
(bgEl as Sector).setShape('cornerRadius', barBorderRadius);
}
bgEls[dataIndex] = bgEl;
return bgEl;
};
data.diff(oldData)
.add(function (dataIndex) {
const itemModel = data.getItemModel<BarDataItemOption>(dataIndex);
const layout = getLayout[coord.type](data, dataIndex, itemModel);
if (drawBackground) {
createBackground(dataIndex);
}
// If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy".
if (!data.hasValue(dataIndex) || !isValidLayout[coord.type](layout)) {
return;
}
let isClipped = false;
if (needsClip) {
// Clip will modify the layout params.
// And return a boolean to determine if the shape are fully clipped.
isClipped = clip[coord.type](coordSysClipArea, layout);
}
const el = elementCreator[coord.type](
seriesModel,
data,
dataIndex,
layout,
isHorizontalOrRadial,
animationModel,
baseAxis.model,
false,
roundCap
);
if (realtimeSortCfg) {
/**
* Force label animation because even if the element is
* ignored because it's clipped, it may not be clipped after
* changing order. Then, if not using forceLabelAnimation,
* the label animation was never started, in which case,
* the label will be the final value and doesn't have label
* animation.
*/
(el as ECElement).forceLabelAnimation = true;
}
updateStyle(
el, data, dataIndex, itemModel, layout,
seriesModel, isHorizontalOrRadial, coord.type === 'polar'
);
if (isInitSort) {
(el as Rect).attr({ shape: layout });
}
else if (realtimeSortCfg) {
updateRealtimeAnimation(
realtimeSortCfg,
animationModel,
el as Rect,
layout as LayoutRect,
dataIndex,
isHorizontalOrRadial,
false,
false
);
}
else {
initProps(el, {shape: layout} as any, seriesModel, dataIndex);
}
data.setItemGraphicEl(dataIndex, el);
group.add(el);
el.ignore = isClipped;
})
.update(function (newIndex, oldIndex) {
const itemModel = data.getItemModel<BarDataItemOption>(newIndex);
const layout = getLayout[coord.type](data, newIndex, itemModel);
if (drawBackground) {
let bgEl: Rect | Sector;
if (oldBgEls.length === 0) {
bgEl = createBackground(oldIndex);
}
else {
bgEl = oldBgEls[oldIndex];
bgEl.useStyle(backgroundModel.getItemStyle());
// Only cartesian2d support borderRadius.
if (coord.type === 'cartesian2d') {
(bgEl as Rect).setShape('r', barBorderRadius);
}
else {
(bgEl as Sector).setShape('cornerRadius', barBorderRadius);
}
bgEls[newIndex] = bgEl;
}
const bgLayout = getLayout[coord.type](data, newIndex);
const shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord);
updateProps<RectProps | SectorProps>(bgEl, { shape }, animationModel, newIndex);
}
let el = oldData.getItemGraphicEl(oldIndex) as BarPossiblePath;
if (!data.hasValue(newIndex) || !isValidLayout[coord.type](layout)) {
group.remove(el);
return;
}
let isClipped = false;
if (needsClip) {
isClipped = clip[coord.type](coordSysClipArea, layout);
if (isClipped) {
group.remove(el);
}
}
const roundCapChanged = el && (el.type === 'sector' && roundCap || el.type === 'sausage' && !roundCap);
if (roundCapChanged) {
// roundCap changed, there is no way to use animation from a `sector` to a `sausage` shape,
// so remove the old one and create a new shape
el && removeElementWithFadeOut(el, seriesModel, oldIndex);
el = null;
}
if (!el) {
el = elementCreator[coord.type](
seriesModel,
data,
newIndex,
layout,
isHorizontalOrRadial,
animationModel,
baseAxis.model,
true,
roundCap
);
}
else {
saveOldStyle(el);
}
if (realtimeSortCfg) {
(el as ECElement).forceLabelAnimation = true;
}
if (isChangeOrder) {
const textEl = el.getTextContent();
if (textEl) {
const labelInnerStore = labelInner(textEl);
if (labelInnerStore.prevValue != null) {
/**
* Set preValue to be value so that no new label
* should be started, otherwise, it will take a full
* `animationDurationUpdate` time to finish the
* animation, which is not expected.
*/
labelInnerStore.prevValue = labelInnerStore.value;
}
}
}
// Not change anything if only order changed.
// Especially not change label.
else {
updateStyle(
el, data, newIndex, itemModel, layout,
seriesModel, isHorizontalOrRadial, coord.type === 'polar'
);
}
if (isInitSort) {
(el as Rect).attr({ shape: layout });
}
else if (realtimeSortCfg) {
updateRealtimeAnimation(
realtimeSortCfg,
animationModel,
el as Rect,
layout as LayoutRect,
newIndex,
isHorizontalOrRadial,
true,
isChangeOrder
);
}
else {
updateProps(el, {
shape: layout
} as any, seriesModel, newIndex, null);
}
data.setItemGraphicEl(newIndex, el);
el.ignore = isClipped;
group.add(el);
})
.remove(function (dataIndex) {
const el = oldData.getItemGraphicEl(dataIndex) as Path;
el && removeElementWithFadeOut(el, seriesModel, dataIndex);
})
.execute();
const bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group());
bgGroup.removeAll();
for (let i = 0; i < bgEls.length; ++i) {
bgGroup.add(bgEls[i]);
}
group.add(bgGroup);
this._backgroundEls = bgEls;
this._data = data;
}