@visactor/vchart
Version:
charts lib based @visactor/VGrammar
248 lines (230 loc) • 13.5 kB
JavaScript
import { ComponentTypeEnum } from "../interface/type";
import { STACK_FIELD_TOTAL_BOTTOM, STACK_FIELD_TOTAL_TOP } from "../../constant/data";
import { ChartEvent, HOOK_EVENT } from "../../constant/event";
import { AttributeLevel } from "../../constant/attribute";
import { LayoutZIndex } from "../../constant/layout";
import { mergeSpec } from "@visactor/vutils-extension";
import { eachSeries } from "../../util/model";
import { defaultLabelConfig, textAttribute } from "./util";
import { registerComponentMark } from "../../mark/component";
import { BaseLabelComponent } from "./base-label";
import { array, isArray, isFunction, isValid, pickWithout } from "@visactor/vutils";
import { Factory } from "../../core/factory";
import { registerLabelMark } from "../../mark/label";
import { LabelSpecTransformer } from "./label-transformer";
import { DataLabel } from "@visactor/vrender-components";
export class Label extends BaseLabelComponent {
constructor(spec, options) {
super(spec, options), this.type = ComponentTypeEnum.label, this.name = ComponentTypeEnum.label,
this.specKey = "label", this.transformerConstructor = LabelSpecTransformer, this.layoutZIndex = LayoutZIndex.Label,
this._layoutRule = spec.labelLayout || "series";
}
static getSpecInfo(chartSpec, chartSpecInfo) {
const specInfo = [], regionSpecInfo = (null == chartSpecInfo ? void 0 : chartSpecInfo.region) || [];
return regionSpecInfo.forEach(((regionInfo, i) => {
(regionInfo.seriesIndexes || []).some((seriesIndex => {
const seriesInfo = chartSpecInfo.series[seriesIndex], {markLabelSpec: markLabelSpec = {}} = seriesInfo;
return Object.values(markLabelSpec).some((labelSpecList => Array.isArray(labelSpecList) && (labelSpecList => labelSpecList.some((labelSpec => labelSpec.visible)))(labelSpecList)));
})) && specInfo.push({
spec: chartSpec,
type: ComponentTypeEnum.label,
specInfoPath: [ "component", this.specKey, i ],
regionIndexes: [ i ]
});
})), specInfo;
}
init(option) {
super.init(option), this.initEvent(), this._initTextMark(), this._initLabelComponent(),
this._initTextMarkStyle();
}
reInit(spec) {
super.reInit(spec), this._labelInfoMap && (this._labelInfoMap.forEach((labelInfos => {
labelInfos.forEach((({labelMark: labelMark}) => {
labelMark.release();
}));
})), this._labelInfoMap.clear()), this._labelInfoMap && this._labelInfoMap.clear(),
this._initTextMark(), this._initLabelComponent(), this._initTextMarkStyle();
}
initEvent() {
this.event.on(ChartEvent.dataZoomChange, (() => {
this._labelComponentMap.forEach(((info, component) => {
const graphicItem = component.getComponent();
graphicItem && graphicItem.disableAnimation();
})), this.event.on(HOOK_EVENT.AFTER_MARK_RENDER_END, enableAnimation);
}));
const enableAnimation = () => {
this._labelComponentMap.forEach(((info, component) => {
const graphicItem = component.getComponent();
graphicItem && graphicItem.enableAnimation();
})), this.event.off(HOOK_EVENT.AFTER_MARK_RENDER_END, enableAnimation);
};
}
_initTextMark() {
this._labelInfoMap || (this._labelInfoMap = new Map), this._labelComponentMap || (this._labelComponentMap = new Map),
eachSeries(this._regions, (series => {
const {markLabelSpec: markLabelSpec = {}} = series.getSpecInfo(), markNames = Object.keys(markLabelSpec), region = series.getRegion();
this._labelInfoMap.get(region) || this._labelInfoMap.set(region, []);
for (let i = 0; i < markNames.length; i++) {
const markName = markNames[i], mark = series.getMarkInName(markName);
mark && markLabelSpec[markName].forEach(((spec, index) => {
var _a, _b, _c;
if (spec.visible) {
const info = this._labelInfoMap.get(region), labelMark = this._createMark({
type: "label",
name: `${null !== (_a = series.userId) && void 0 !== _a ? _a : series.id}-${markName}-label-${index}`
}, {
attributeContext: series.getMarkAttributeContext()
});
spec.showRelatedMarkTooltip && (null === (_c = null === (_b = series.tooltipHelper) || void 0 === _b ? void 0 : _b.activeTriggerSet.mark) || void 0 === _c || _c.add(labelMark)),
labelMark.setTarget(mark), info.push({
labelMark: labelMark,
baseMark: mark,
series: series,
labelSpec: spec
});
}
}));
}
}));
}
_initLabelComponent() {
const removedComponents = {};
this._labelComponentMap.forEach(((labelInfo, comp) => {
removedComponents[comp.name] = comp;
})), this._labelInfoMap.forEach(((regionLabelInfo, region) => {
if ("region" === this._layoutRule) {
let isNew = !1;
const labelName = `${region.getGroupMark().name}-label-component`;
let component = removedComponents[labelName];
component || (isNew = !0, component = this._createMark({
type: "component",
name: labelName
}, {
componentType: "label"
}, {
support3d: this._spec.support3d
})), component && (isNew && (component.setSkipBeforeLayouted(!0), this._marks.addMark(component),
regionLabelInfo.forEach((labelInfo => {
var _a;
null === (_a = labelInfo.baseMark.getData()) || void 0 === _a || _a.addRelatedMark(component);
}))), regionLabelInfo[0] && isValid(regionLabelInfo[0].labelSpec.zIndex) && component.setMarkConfig({
zIndex: regionLabelInfo[0].labelSpec.zIndex
}), this._labelComponentMap.set(component, (() => this._labelInfoMap.get(region))),
removedComponents[labelName] = null);
} else regionLabelInfo.forEach(((labelInfo, i) => {
var _a;
let isNew = !1;
const labelName = `${labelInfo.labelMark.name}-component`;
let component = removedComponents[labelName];
component || (isNew = !0, component = this._createMark({
type: "component",
name: labelName
}, {
componentType: "label",
noSeparateStyle: !0
}, {
support3d: labelInfo.baseMark.getMarkConfig().support3d
})), component && (isValid(labelInfo.labelSpec.zIndex) && component.setMarkConfig({
zIndex: labelInfo.labelSpec.zIndex
}), isNew && (component.setSkipBeforeLayouted(!0), this._marks.addMark(component),
null === (_a = labelInfo.baseMark.getData()) || void 0 === _a || _a.addRelatedMark(component)),
this._labelComponentMap.set(component, (() => this._labelInfoMap.get(region)[i])),
removedComponents[labelName] = null);
}));
})), Object.keys(removedComponents).forEach((name => {
const comp = removedComponents[name];
comp && (comp.release(), this._labelComponentMap.delete(comp));
}));
}
_initTextMarkStyle() {
this._labelComponentMap.forEach(((labelInfoCb, labelComponent) => {
array(labelInfoCb()).forEach((({labelMark: labelMark}) => {
labelMark.setComponent(labelComponent);
}));
})), this._labelInfoMap.forEach((labelInfos => {
labelInfos.forEach((info => {
var _a, _b;
const {labelMark: labelMark, labelSpec: labelSpec, series: series} = info;
if (this.initMarkStyleWithSpec(labelMark, labelSpec), isFunction(null == labelSpec ? void 0 : labelSpec.getStyleHandler)) {
const styleHandler = labelSpec.getStyleHandler(series);
null == styleHandler || styleHandler.call(series, labelMark, labelSpec);
}
(null === (_b = null === (_a = labelMark.stateStyle) || void 0 === _a ? void 0 : _a.normal) || void 0 === _b ? void 0 : _b.lineWidth) && labelMark.setAttribute("stroke", series.getColorAttribute(), "normal", AttributeLevel.Base_Series);
}));
}));
}
updateLayoutAttribute() {
super.updateLayoutAttribute(), this._labelComponentMap.forEach(((labelInfoCb, labelComponent) => {
const labelInfo = labelInfoCb();
isArray(labelInfo) ? this._updateMultiLabelAttribute(labelInfo, labelComponent) : this._updateSingleLabelAttribute(labelInfo, labelComponent);
}));
}
_updateMultiLabelAttribute(labelInfo, labelComponent) {
this._updateLabelComponentAttribute(labelComponent, labelInfo.map((({baseMark: baseMark}) => baseMark)), labelInfo);
}
_updateSingleLabelAttribute(labelInfo, labelComponent) {
const {baseMark: baseMark} = labelInfo;
this._updateLabelComponentAttribute(labelComponent, baseMark, [ labelInfo ]);
}
_updateLabelComponentAttribute(labelComponent, baseMark, labelInfos) {
const totalLabels = this._option.getComponentsByType("totalLabel");
labelComponent.setMarkConfig({
interactive: !1
}), labelComponent.setSimpleStyle({
labelStyle: labelIndex => {
var _a, _b;
const labelInfo = labelInfos[labelIndex], {labelSpec: labelSpec, labelMark: labelMark, series: series} = labelInfo, rule = labelMark.getRule(), interactive = this._interactiveConfig(labelSpec), centerOffset = null !== (_b = null === (_a = this._spec) || void 0 === _a ? void 0 : _a.centerOffset) && void 0 !== _b ? _b : 0;
let spec = mergeSpec({
textStyle: Object.assign({
pickable: !0 === labelSpec.interactive
}, labelSpec.style),
overlap: {
avoidMarks: totalLabels.map((cmp => cmp.getMarks()[0].getProductId()))
}
}, defaultLabelConfig(rule, labelInfo), Object.assign(Object.assign(Object.assign({}, pickWithout(labelSpec, [ "position", "style", "state", "type", "stackDataFilterType", "getStyleHandler" ])), interactive), {
centerOffset: centerOffset
}), labelSpec.stackDataFilterType ? {
dataFilter: "min" === labelSpec.stackDataFilterType ? data => data.filter((d => d.data[STACK_FIELD_TOTAL_BOTTOM])) : data => data.filter((d => d.data[STACK_FIELD_TOTAL_TOP]))
} : {});
return series && series.parseLabelStyle && (spec = series.parseLabelStyle(spec, labelSpec, labelMark)),
"line" !== rule && "area" !== rule || (spec.type = rule), spec;
},
size: () => {
var _a;
return Object.assign({
padding: null === (_a = labelInfos[0].labelSpec.overlap) || void 0 === _a ? void 0 : _a.padding
}, labelInfos[0].series.getRegion().getLayoutRect());
},
itemEncoder: (datum, {labelIndex: labelIndex}) => labelInfos[labelIndex] && !labelInfos[labelIndex].labelMark.skipEncode ? textAttribute(labelInfos[labelIndex], datum, labelInfos[labelIndex].labelSpec.formatMethod, labelInfos[labelIndex].labelSpec.formatter) : {
data: datum
}
}), this._setTransformOfComponent(labelComponent, baseMark);
}
compileMarks() {
this.getMarks().forEach((m => {
const labelInfo = this._labelComponentMap.get(m)();
let group;
group = isArray(labelInfo) ? labelInfo[0].series.getRegion().getGroupMark().getProduct() : labelInfo.series.getRegion().getGroupMark().getProduct(),
m.compile({
group: group
});
}));
}
getLabelInfoByTextGraphic(text) {
let labelInfo;
const vrenderLabel = null == text ? void 0 : text.parent, vrenderDataLabel = null == vrenderLabel ? void 0 : vrenderLabel.parent;
if (vrenderDataLabel) {
const labelIndex = vrenderDataLabel.getChildren().indexOf(vrenderLabel);
this._labelComponentMap.forEach(((infoFunc, component) => {
component.getComponent() === vrenderDataLabel && (labelInfo = array(infoFunc())[labelIndex]);
}));
}
return labelInfo;
}
}
Label.type = ComponentTypeEnum.label, Label.specKey = "label", Label.transformerConstructor = LabelSpecTransformer;
export const registerLabel = () => {
Factory.registerGraphicComponent(Label.type, (attrs => new DataLabel(attrs))), registerLabelMark(),
registerComponentMark(), Factory.registerComponent(Label.type, Label, !0, 1 / 0);
};
//# sourceMappingURL=label.js.map