UNPKG

@visactor/vchart

Version:

charts lib based @visactor/VGrammar

348 lines (315 loc) 17.2 kB
import { degreeToRadian, isValid } from "@visactor/vutils"; import { DataView } from "@visactor/vdataset"; import { ARC_START_ANGLE, ARC_END_ANGLE, ARC_RATIO, ARC_MIDDLE_ANGLE, ARC_RADIAN, ARC_QUADRANT, ARC_K, POLAR_START_RADIAN, POLAR_END_RADIAN } from "../../constant/polar"; import { AttributeLevel } from "../../constant/attribute"; import { DEFAULT_DATA_KEY, DEFAULT_DATA_INDEX } from "../../constant/data"; import { PREFIX } from "../../constant/base"; import { normalizeStartEndAngle } from "../../util/math"; import { isSpecValueWithScale } from "../../util/scale"; import { field } from "../../util/object"; import { PolarSeries } from "../polar/polar"; import { SeriesTypeEnum } from "../interface/type"; import { pie } from "../../data/transforms/pie"; import { registerDataSetInstanceTransform } from "../../data/register"; import { registerEmptyCircleAnimation, registerPieAnimation } from "./animation/animation"; import { animationConfig, shouldMarkDoMorph, userAnimationConfig } from "../../animation/utils"; import { AnimationStateEnum } from "../../animation/interface"; import { centerOffsetConfig } from "./animation/centerOffset"; import { registerArcMark } from "../../mark/arc"; import { pieSeriesMark } from "./constant"; import { Factory } from "../../core/factory"; import { isNil, polarToCartesian } from "@visactor/vutils"; import { PieSeriesSpecTransformer } from "./pie-transformer"; import { DEFAULT_LABEL_VISIBLE } from "../../constant/label"; import { ChartEvent } from "../../constant/event"; import { computeLayoutRadius } from "../../component/axis/polar/util/common"; import { calcLayoutNumber } from "../../util/space"; import { CompilableData } from "../../compile/data"; import { pie as pieTheme } from "../../theme/builtin/common/series/pie"; export class BasePieSeries extends PolarSeries { constructor() { super(...arguments), this.transformerConstructor = PieSeriesSpecTransformer, this._pieMarkName = "pie", this._pieMarkType = "arc", this.getCenter = () => { var _a, _b; const layoutRect = this._region.getLayoutRect(); return { x: calcLayoutNumber(null === (_a = this._spec) || void 0 === _a ? void 0 : _a.centerX, layoutRect.width, layoutRect, layoutRect.width / 2), y: calcLayoutNumber(null === (_b = this._spec) || void 0 === _b ? void 0 : _b.centerY, layoutRect.height, layoutRect, layoutRect.height / 2) }; }, this._startAngle = POLAR_START_RADIAN, this._endAngle = POLAR_END_RADIAN, this._pieMark = null, this._labelMark = null, this._labelLineMark = null, this._emptyArcMark = null, this.dataToCentralPosition = datum => { const angle = datum[ARC_MIDDLE_ANGLE]; if (isNil(angle)) return null; const radius = this.computeDatumRadius(datum), innerRadius = this.computeDatumInnerRadius(datum), center = this.computeCenter(datum); return polarToCartesian(center, (radius + innerRadius) / 2, angle); }; } _buildMarkAttributeContext() { super._buildMarkAttributeContext(), this._markAttributeContext.getCenter = () => ({ x: () => this.getCenter().x, y: () => this.getCenter().y }), this._markAttributeContext.startAngleScale = datum => this.startAngleScale(datum), this._markAttributeContext.endAngleScale = datum => this.endAngleScale(datum); } setAttrFromSpec() { var _a, _b, _c, _d, _e, _f; super.setAttrFromSpec(), this._centerOffset = null !== (_a = this._spec.centerOffset) && void 0 !== _a ? _a : 0, this._cornerRadius = null !== (_b = this._spec.cornerRadius) && void 0 !== _b ? _b : 0; const normalized = normalizeStartEndAngle(isValid(this._spec.startAngle) ? degreeToRadian(this._spec.startAngle) : this._startAngle, isValid(this._spec.endAngle) ? degreeToRadian(this._spec.endAngle) : this._endAngle); this._startAngle = normalized.startAngle, this._endAngle = normalized.endAngle, this._padAngle = isValid(this._spec.padAngle) ? degreeToRadian(this._spec.padAngle) : 0, this.setAngleField(this._spec.valueField || this._spec.angleField), this._spec.categoryField && this.setSeriesField(this._spec.categoryField), this._radiusField = [], this._specAngleField = this._angleField.slice(), this._specRadiusField = [], this._showEmptyCircle = null !== (_d = null === (_c = this._spec.emptyPlaceholder) || void 0 === _c ? void 0 : _c.showEmptyCircle) && void 0 !== _d && _d, this._showAllZero = null !== (_e = this._spec.showAllZero) && void 0 !== _e && _e, this._supportNegative = null !== (_f = this._spec.supportNegative) && void 0 !== _f && _f; } initData() { super.initData(); const viewData = this.getViewData(); if (!viewData) return; registerDataSetInstanceTransform(this._dataSet, "pie", pie), viewData.transform({ type: "pie", options: { angleField: () => this._angleField[0], startAngle: () => this._startAngle, endAngle: () => this._endAngle, minAngle: () => isValid(this._spec.minAngle) ? degreeToRadian(this._spec.minAngle) : 0, asStartAngle: ARC_START_ANGLE, asEndAngle: ARC_END_ANGLE, asRatio: ARC_RATIO, asMiddleAngle: ARC_MIDDLE_ANGLE, asRadian: ARC_RADIAN, asQuadrant: ARC_QUADRANT, asK: ARC_K, showAllZero: this._showAllZero, supportNegative: this._supportNegative, showEmptyCircle: this._showEmptyCircle } }, !1); const viewDataLabel = new DataView(this._dataSet, { name: `${PREFIX}_series_${this.id}_viewDataLabel` }); viewDataLabel.parse([ this.getViewData() ], { type: "dataview" }), this._viewDataLabel = new CompilableData(this._option, viewDataLabel); } compileData() { var _a; super.compileData(), null === (_a = this._viewDataLabel) || void 0 === _a || _a.compile(); } initMark() { this._pieMark = this._createMark(Object.assign(Object.assign({}, BasePieSeries.mark.pie), { name: this._pieMarkName, type: this._pieMarkType }), { key: DEFAULT_DATA_KEY, groupKey: this._seriesField, skipBeforeLayouted: !0, isSeriesMark: !0 }, { morph: shouldMarkDoMorph(this._spec, this._pieMarkName), morphElementKey: this._seriesField }), this._showEmptyCircle && (this._emptyArcMark = this._createMark({ name: "emptyCircle", type: "arc" }, { dataView: !1 }), this._data.addRelatedMark(this._emptyArcMark)); } startAngleScale(datum) { return field(ARC_START_ANGLE)(datum); } endAngleScale(datum) { return field(ARC_END_ANGLE)(datum); } _computeLayoutRadius() { return computeLayoutRadius((() => this._spec.layoutRadius), this.getLayoutRect, this.getCenter, (() => ({ startAngle: this._startAngle, endAngle: this._endAngle }))); } initMarkStyle() { const initialStyle = { x: () => this.getCenter().x, y: () => this.getCenter().y, fill: this.getColorAttribute(), outerRadius: isSpecValueWithScale(this._outerRadius) ? this._outerRadius : () => this._computeLayoutRadius() * this._outerRadius, innerRadius: isSpecValueWithScale(this._innerRadius) ? this._innerRadius : () => this._computeLayoutRadius() * this._innerRadius, cornerRadius: () => this._computeLayoutRadius() * this._cornerRadius, startAngle: datum => this.startAngleScale(datum), endAngle: datum => this.endAngleScale(datum), padAngle: this._padAngle, centerOffset: this._centerOffset }, pieMark = this._pieMark; pieMark && this.setMarkStyle(pieMark, initialStyle, "normal", AttributeLevel.Series); const emptyPieMark = this._emptyArcMark; emptyPieMark && this.setMarkStyle(emptyPieMark, Object.assign(Object.assign({}, initialStyle), { visible: () => { const data = this.getViewData().latestData; return !data || !data.length; } }), "normal", AttributeLevel.Series); } getInteractionTriggers() { return this._parseInteractionConfig(this._pieMark ? [ this._pieMark ] : []); } initTooltip() { super.initTooltip(), this._pieMark && this._tooltipHelper.activeTriggerSet.mark.add(this._pieMark); } initMarkStyleWithSpec(mark, spec) { if (super.initMarkStyleWithSpec(mark, spec), mark.name === this._pieMarkName) { const pieSpec = this.getSpec()[mark.name]; if (pieSpec) for (const state in pieSpec.state || {}) this.setMarkStyle(mark, this.generateRadiusStyle(pieSpec.state[state]), state, AttributeLevel.User_Mark); } "emptyCircle" === mark.name && this.setMarkStyle(mark, this.generateRadiusStyle(spec.style), "normal", AttributeLevel.User_Mark); } initLabelMarkStyle(textMark) { textMark && this.setMarkStyle(textMark, { visible: field(DEFAULT_LABEL_VISIBLE).bind(this), text: datum => datum[this.getDimensionField()[0]], fill: this.getColorAttribute(), z: this.dataToPositionZ.bind(this) }); } afterInitMark() { super.afterInitMark(); } initEvent() { var _a; super.initEvent(), null === (_a = this._viewDataLabel.getDataView()) || void 0 === _a || _a.target.addListener("change", this.viewDataLabelUpdate.bind(this)); } initGroups() {} onLayoutEnd() { this._viewDataLabel.getDataView().reRunAllTransform(), this.onMarkPositionUpdate(), super.onLayoutEnd(); } getDimensionField() { return this._seriesField ? [ this._seriesField ] : []; } getMeasureField() { return this._specAngleField; } viewDataLabelUpdate() { this.event.emit(ChartEvent.viewDataLabelUpdate, { model: this }), this._viewDataLabel.updateData(); } generateRadiusStyle(spec) { if (!spec) return; const style = {}; return spec.outerRadius && (style.outerRadius = () => this._computeLayoutRadius() * spec.outerRadius), spec.innerRadius && (style.innerRadius = () => this._computeLayoutRadius() * spec.innerRadius), spec.cornerRadius && (style.cornerRadius = () => this._computeLayoutRadius() * spec.cornerRadius), style; } computeCenter(datum) { return { x: this._pieMark.getAttribute("x", datum, "normal"), y: this._pieMark.getAttribute("y", datum, "normal") }; } getRadius(state = "normal") { var _a, _b, _c, _d, _e, _f, _g; const styleRadius = "normal" === state ? null === (_c = null === (_b = this.getSpec()[(null === (_a = this._pieMark) || void 0 === _a ? void 0 : _a.name) || "pie"]) || void 0 === _b ? void 0 : _b.style) || void 0 === _c ? void 0 : _c.outerRadius : null === (_g = null === (_f = null === (_e = this.getSpec()[(null === (_d = this._pieMark) || void 0 === _d ? void 0 : _d.name) || "pie"]) || void 0 === _e ? void 0 : _e.state) || void 0 === _f ? void 0 : _f[state]) || void 0 === _g ? void 0 : _g.outerRadius; return null != styleRadius ? styleRadius : this._outerRadius; } getInnerRadius(state = "normal") { var _a, _b, _c, _d, _e, _f, _g; const styleRadius = "normal" === state ? null === (_c = null === (_b = this.getSpec()[(null === (_a = this._pieMark) || void 0 === _a ? void 0 : _a.name) || "pie"]) || void 0 === _b ? void 0 : _b.style) || void 0 === _c ? void 0 : _c.innerRadius : null === (_g = null === (_f = null === (_e = this.getSpec()[(null === (_d = this._pieMark) || void 0 === _d ? void 0 : _d.name) || "pie"]) || void 0 === _e ? void 0 : _e.state) || void 0 === _f ? void 0 : _f[state]) || void 0 === _g ? void 0 : _g.innerRadius; return null != styleRadius ? styleRadius : this._innerRadius; } computeRadius(r, k) { return this._computeLayoutRadius() * r * (isNil(k) ? 1 : k) + this._centerOffset; } computeDatumRadius(datum, state) { return this._computeLayoutRadius() * this.getRadius(state) + this._centerOffset; } _compareSpec(spec, prevSpec, ignoreCheckKeys) { ignoreCheckKeys = null != ignoreCheckKeys ? ignoreCheckKeys : { data: !0 }; const defaultIgnoreKeys = [ "centerX", "centerY", "centerOffset", "radius", "innerRadius", "cornerRadius", "startAngle", "endAngle", "padAngle" ]; defaultIgnoreKeys.forEach((key => { ignoreCheckKeys[key] = !0; })); const result = super._compareSpec(spec, prevSpec, ignoreCheckKeys); return spec = null != spec ? spec : {}, defaultIgnoreKeys.some((key => spec[key] !== prevSpec[key])) && (result.reRender = !0, result.change = !0), result; } computeDatumInnerRadius(datum, state) { return this._computeLayoutRadius() * this.getInnerRadius(state) + this._centerOffset; } dataToPosition(datum, checkInViewData) { const angle = datum[ARC_MIDDLE_ANGLE]; if (isNil(angle)) return null; if (checkInViewData && !this.isDatumInViewData(datum)) return null; const radius = this.computeDatumRadius(datum), center = this.computeCenter(datum); return polarToCartesian(center, radius, angle); } initAnimation() { var _a, _b, _c; const animationParams = { growFrom: (datum, graphic, state) => { var _a, _b; if (state === AnimationStateEnum.appear) return this._startAngle; if (state === AnimationStateEnum.disappear) return this._endAngle; const outState = [ AnimationStateEnum.disappear, AnimationStateEnum.exit ], markElements = this._pieMark.getGraphics(), data = datum, dataIndex = null == data ? void 0 : data[DEFAULT_DATA_INDEX]; if (void 0 === markElements.find((e => { var _a; return (null === (_a = e.context.data[0]) || void 0 === _a ? void 0 : _a[DEFAULT_DATA_INDEX]) < dataIndex; }))) return this._startAngle; if (void 0 === markElements.find((e => { var _a; return (null === (_a = e.context.data[0]) || void 0 === _a ? void 0 : _a[DEFAULT_DATA_INDEX]) > dataIndex; }))) return this._endAngle; const prevMarkElement = [ ...markElements ].reverse().find((e => { var _a; return (null === (_a = e.context.data[0]) || void 0 === _a ? void 0 : _a[DEFAULT_DATA_INDEX]) < dataIndex; })); return outState.includes(state) ? null === (_a = null == prevMarkElement ? void 0 : prevMarkElement.getFinalAttribute()) || void 0 === _a ? void 0 : _a.endAngle : null === (_b = null == prevMarkElement ? void 0 : prevMarkElement.attribute) || void 0 === _b ? void 0 : _b.endAngle; } }, appearPreset = null === (_a = this._spec.animationAppear) || void 0 === _a ? void 0 : _a.preset; if (this._pieMark) { const pieAnimationConfig = animationConfig(null === (_b = Factory.getAnimationInKey("pie")) || void 0 === _b ? void 0 : _b(animationParams, appearPreset), userAnimationConfig("pie", this._spec, this._markAttributeContext)); pieAnimationConfig.normal && pieAnimationConfig.normal.type && (pieAnimationConfig.normal = centerOffsetConfig(this._pieMark, pieAnimationConfig.normal)), this._pieMark.setAnimationConfig(pieAnimationConfig); } if (this._emptyArcMark) { const pieAnimationConfig = animationConfig(null === (_c = Factory.getAnimationInKey("emptyCircle")) || void 0 === _c ? void 0 : _c(animationParams, null != appearPreset ? appearPreset : "fadeIn")); this._emptyArcMark.setAnimationConfig(pieAnimationConfig); } } getDefaultShapeType() { return "circle"; } getGroupFields() { return []; } getStackGroupFields() { return []; } getStackValueField() { return ""; } _noAnimationDataKey(datum, index) { return index; } getActiveMarks() { return [ this._pieMark ]; } } BasePieSeries.transformerConstructor = PieSeriesSpecTransformer, BasePieSeries.mark = pieSeriesMark, BasePieSeries.builtInTheme = { pie: pieTheme }; export class PieSeries extends BasePieSeries { constructor() { super(...arguments), this.type = SeriesTypeEnum.pie; } } PieSeries.type = SeriesTypeEnum.pie; export const registerPieSeries = () => { registerArcMark(), registerPieAnimation(), registerEmptyCircleAnimation(), Factory.registerSeries(PieSeries.type, PieSeries); }; //# sourceMappingURL=pie.js.map