@visactor/vchart
Version:
charts lib based @visactor/VGrammar
323 lines (290 loc) • 14.5 kB
JavaScript
import { STATE_VALUE_ENUM } from "../../compile/mark/interface";
import { HOOK_EVENT } from "../../constant/event";
import { AttributeLevel } from "../../constant/attribute";
import { DEFAULT_DATA_KEY } from "../../constant/data";
import { CartesianSeries } from "../cartesian/cartesian";
import { SeriesTypeEnum } from "../interface/type";
import { registerDataSetInstanceTransform } from "../../data/register";
import { flatten } from "../../data/transforms/flatten";
import { isValidNumber, Bounds, Matrix, mixin, merge } from "@visactor/vutils";
import { DataView } from "@visactor/vdataset";
import { hierarchyDimensionStatistics } from "../../data/transforms/hierarchy-dimension-statistics";
import { addVChartProperty } from "../../data/transforms/add-property";
import { addHierarchyDataKey, initHierarchyKeyMap } from "../../data/transforms/data-key";
import { DEFAULT_HIERARCHY_ROOT } from "../../constant/hierarchy";
import { TreemapTooltipHelper } from "./tooltip-helper";
import { animationConfig, userAnimationConfig } from "../../animation/utils";
import { registerFadeInOutAnimation } from "../../animation/config";
import { Zoomable } from "../../interaction/zoom/zoomable";
import { Drillable } from "../../interaction/drill/drillable";
import { registerRectMark } from "../../mark/rect";
import { registerTextMark } from "../../mark/text";
import { treemapSeriesMark } from "./constant";
import { Factory } from "../../core/factory";
import { registerTreemapAnimation } from "./animation";
import { TreemapSeriesSpecTransformer } from "./treemap-transform";
import { appendHierarchyFields } from "../util/hierarchy";
import { registerMarkFilterTransform } from "../../mark/transform/filter";
import { registerMarkMapTransform } from "../../mark/transform/map";
import { treemapLayout } from "../../data/transforms/treemap";
import { treemap } from "../../theme/builtin/common/series/treemap";
export class TreemapSeries extends CartesianSeries {
constructor() {
super(...arguments), this.type = SeriesTypeEnum.treemap, this.transformerConstructor = TreemapSeriesSpecTransformer,
this._categoryField = "name", this._valueField = "value", this._viewBox = new Bounds,
this._enableAnimationHook = this.enableMarkAnimation.bind(this), this.isHierarchyData = () => !0;
}
getCategoryField() {
return this._categoryField;
}
setCategoryField(f) {
return this._categoryField = f, this._categoryField;
}
getValueField() {
return this._valueField;
}
setValueField(f) {
return this._valueField = f, this._valueField;
}
setAttrFromSpec() {
var _a;
super.setAttrFromSpec(), this.setCategoryField(this._spec.categoryField), this.setValueField(this._spec.valueField),
this.setSeriesField(null !== (_a = this._spec.seriesField) && void 0 !== _a ? _a : DEFAULT_HIERARCHY_ROOT),
this._spec.roam && (this.initZoomable(this.event, this._option.mode), this._matrix = new Matrix),
this._spec.drill && this.initDrillable({
event: this.event,
mode: this._option.mode,
drillField: () => {
var _a, _b;
return null !== (_b = null !== (_a = this._spec.drillField) && void 0 !== _a ? _a : this._categoryField) && void 0 !== _b ? _b : DEFAULT_DATA_KEY;
},
getRawData: () => this.getRawData()
}), isValidNumber(this._spec.maxDepth) && (this._maxDepth = this._spec.maxDepth - 1);
}
initData() {
var _a, _b, _c, _d, _e;
super.initData(), registerDataSetInstanceTransform(this._dataSet, "treemap", treemapLayout),
null === (_a = this._data.getDataView()) || void 0 === _a || _a.transform({
type: "treemap",
options: {
nameField: this._categoryField,
valueField: this._valueField,
getViewBox: () => this._viewBox.empty() ? null : {
x0: this._viewBox.x1,
x1: this._viewBox.x2,
y0: this._viewBox.y1,
y1: this._viewBox.y2
},
maxDepth: this._maxDepth,
gapWidth: this._spec.gapWidth,
padding: this._spec.nodePadding,
splitType: this._spec.splitType,
aspectRatio: this._spec.aspectRatio,
labelPadding: (null === (_b = this._spec.nonLeafLabel) || void 0 === _b ? void 0 : _b.visible) ? null === (_c = this._spec.nonLeafLabel) || void 0 === _c ? void 0 : _c.padding : 0,
labelPosition: null === (_d = this._spec.nonLeafLabel) || void 0 === _d ? void 0 : _d.position,
minVisibleArea: null !== (_e = this._spec.minVisibleArea) && void 0 !== _e ? _e : 10,
minChildrenVisibleArea: this._spec.minChildrenVisibleArea,
minChildrenVisibleSize: this._spec.minChildrenVisibleSize
}
}), this.getViewData() && this._spec.drill && this.initDrillableData(this._dataSet);
}
_runTreemapTransform(render = !1) {
this._data.getDataView().reRunAllTransform(), render && this.getCompiler().renderNextTick();
}
_addDataIndexAndKey() {
var _a;
(null === (_a = this._rawData) || void 0 === _a ? void 0 : _a.dataSet) && (registerDataSetInstanceTransform(this._rawData.dataSet, "addVChartProperty", addVChartProperty),
this._rawData.transform({
type: "addVChartProperty",
options: {
beforeCall: initHierarchyKeyMap.bind(this),
call: addHierarchyDataKey
}
}));
}
getRawDataStatisticsByField(field, isNumeric) {
var _a;
if (this._rawStatisticsCache || (this._rawStatisticsCache = {}), !this._rawStatisticsCache[field] && this._rawData) {
const result = hierarchyDimensionStatistics([ this._rawData ], {
fields: [ {
key: field,
operations: isNumeric ? [ "min", "max" ] : [ "values" ]
} ]
})[field];
this._rawStatisticsCache[field] = merge(null !== (_a = this._rawStatisticsCache[field]) && void 0 !== _a ? _a : {}, result);
}
return this._rawStatisticsCache[field];
}
_createHierarchyDataStatistics(dataName, rawData) {
registerDataSetInstanceTransform(this._dataSet, "hierarchyDimensionStatistics", hierarchyDimensionStatistics),
registerDataSetInstanceTransform(this._dataSet, "flatten", flatten);
const data = new DataView(this._dataSet, {
name: dataName
});
return data.parse(rawData, {
type: "dataview"
}), data.transform({
type: "hierarchyDimensionStatistics",
options: {
fields: () => {
const fields = this.getStatisticFields();
return this._seriesField && this._seriesField !== this._categoryField && fields.push({
key: this._seriesField,
operations: [ "values" ]
}), fields;
}
}
}, !1), data;
}
getStatisticFields() {
return appendHierarchyFields(super.getStatisticFields(), this._categoryField, this._valueField);
}
initMark() {
const nonLeafMark = this._createMark(TreemapSeries.mark.nonLeaf, {
isSeriesMark: !0
});
nonLeafMark && (nonLeafMark.setTransform([ {
type: "filter",
callback: datum => !this._shouldFilterElement(datum, "nonLeaf")
} ]), this._nonLeafMark = nonLeafMark);
const leafMark = this._createMark(TreemapSeries.mark.leaf, {
isSeriesMark: !0
});
leafMark && (leafMark.setTransform([ {
type: "filter",
callback: datum => !this._shouldFilterElement(datum, "leaf")
} ]), this._leafMark = leafMark);
}
initMarkStyle() {
this._initLeafMarkStyle(), this._initNonLeafMarkStyle();
}
_initLeafMarkStyle() {
this._leafMark && this.setMarkStyle(this._leafMark, {
x: datum => datum.x0,
y: datum => datum.y0,
x1: datum => datum.x1,
y1: datum => datum.y1,
fill: this.getColorAttribute()
}, STATE_VALUE_ENUM.STATE_NORMAL, AttributeLevel.Series);
}
_initNonLeafMarkStyle() {
this._nonLeafMark && this.setMarkStyle(this._nonLeafMark, {
x: datum => datum.x0,
y: datum => datum.y0,
x1: datum => datum.x1,
y1: datum => datum.y1,
fill: this.getColorAttribute()
}, STATE_VALUE_ENUM.STATE_NORMAL, AttributeLevel.Series);
}
_initRichStyleOfLabelMark(labelMark) {
"rich" === labelMark.getTextType() && this.setMarkStyle(labelMark, {
maxWidth: datum => Math.abs(datum.x0 - datum.x1),
maxHeight: datum => Math.abs(datum.y0 - datum.y1),
ellipsis: !0
}, STATE_VALUE_ENUM.STATE_NORMAL, AttributeLevel.Series);
}
initLabelMarkStyle(labelMark) {
labelMark && (this._labelMark = labelMark, labelMark.setRule("treemap"), this.setMarkStyle(labelMark, {
x: datum => (datum.x0 + datum.x1) / 2,
y: datum => (datum.y0 + datum.y1) / 2,
text: datum => {
var _a;
return null === (_a = datum.datum[datum.depth]) || void 0 === _a ? void 0 : _a[this.getDimensionField()[0]];
},
maxLineWidth: datum => datum.x1 === datum.x0 ? Number.MIN_VALUE : datum.x1 - datum.x0
}, STATE_VALUE_ENUM.STATE_NORMAL, AttributeLevel.Series), this._initRichStyleOfLabelMark(labelMark));
}
initNonLeafLabelMarkStyle(labelMark) {
labelMark && (this._nonLeafLabelMark = labelMark, labelMark.setRule("treemap"),
this.setMarkStyle(labelMark, {
x: datum => datum.labelRect ? (datum.labelRect.x0 + datum.labelRect.x1) / 2 : (datum.x0 + datum.x1) / 2,
y: datum => datum.labelRect ? (datum.labelRect.y0 + datum.labelRect.y1) / 2 : (datum.y0 + datum.y1) / 2,
text: datum => {
var _a;
return null === (_a = datum.datum[datum.depth]) || void 0 === _a ? void 0 : _a[this.getDimensionField()[0]];
},
maxLineWidth: datum => datum.x1 === datum.x0 ? Number.MIN_VALUE : datum.x1 - datum.x0
}, STATE_VALUE_ENUM.STATE_NORMAL, AttributeLevel.Series), this._initRichStyleOfLabelMark(labelMark));
}
initAnimation() {
this.getMarksInType("rect").forEach((mark => {
var _a;
mark.setAnimationConfig(animationConfig(null === (_a = Factory.getAnimationInKey("treemap")) || void 0 === _a ? void 0 : _a(), userAnimationConfig(mark.name, this._spec, this._markAttributeContext)));
}));
}
initEvent() {
super.initEvent(), this._spec.roam && (this.initDragEventOfSeries(this), this.event.on("panmove", (e => {
this.handlePan(e);
})), this.initZoomEventOfSeries(this), this.event.on("zoom", (e => {
this.handleZoom(e);
}))), this._spec.drill && this.bindDrillEvent();
}
_getDataIdKey() {
return "key";
}
initTooltip() {
this._tooltipHelper = new TreemapTooltipHelper(this), this._leafMark && this._tooltipHelper.activeTriggerSet.mark.add(this._leafMark),
this._nonLeafMark && this._tooltipHelper.activeTriggerSet.mark.add(this._nonLeafMark);
}
_shouldFilterElement(datum, nodeType) {
const isLeaf = datum.isLeaf;
return "leaf" === nodeType ? !isLeaf : isLeaf;
}
handlePan(event) {
const {delta: delta} = event;
if (0 === delta[0] && 0 === delta[1]) return;
this._matrix.reset(), this._matrix.translate(delta[0], delta[1]);
const {a: a, b: b, c: c, d: d, e: e, f: f} = this._matrix;
this._matrix.multiply(a, b, c, d, e, f), this._viewBox.transformWithMatrix(this._matrix),
this._runTreemapTransform(!0);
}
handleZoom(event) {
const {scale: scale, scaleCenter: scaleCenter} = event;
if (1 === scale) return;
this._matrix.reset();
const {x: x, y: y} = scaleCenter;
this._matrix.translate(x, y), this._matrix.scale(scale, scale), this._matrix.translate(-x, -y);
const {a: a, b: b, c: c, d: d, e: e, f: f} = this._matrix;
this._matrix.multiply(a, b, c, d, e, f), this.disableMarkAnimation(), this.event.on(HOOK_EVENT.AFTER_DO_RENDER, this._enableAnimationHook),
this._viewBox.transformWithMatrix(this._matrix), this._runTreemapTransform(!0);
}
getDimensionField() {
return [ this._categoryField ];
}
getMeasureField() {
return [ this._valueField ];
}
onLayoutEnd() {
super.onLayoutEnd(), this._viewBox.set(0, 0, this.getLayoutRect().width, this.getLayoutRect().height),
this._runTreemapTransform();
}
enableMarkAnimation() {
this.getMarks().forEach((mark => {})), [ this._labelMark, this._nonLeafLabelMark ].forEach((m => {
m && m.getComponent() && m.getComponent().getProduct().getGroupGraphicItem().enableAnimation();
})), this.event.off(HOOK_EVENT.AFTER_DO_RENDER, this._enableAnimationHook);
}
disableMarkAnimation() {
this.getMarks().forEach((mark => {})), [ this._labelMark, this._nonLeafLabelMark ].forEach((m => {
m && m.getComponent() && m.getComponent().getProduct().getGroupGraphicItem().disableAnimation();
}));
}
getDefaultShapeType() {
return "square";
}
getActiveMarks() {
return [ this._nonLeafMark, this._leafMark ];
}
getMarkData(datum) {
return (null == datum ? void 0 : datum.datum) ? datum.datum[datum.datum.length - 1] : datum;
}
}
TreemapSeries.type = SeriesTypeEnum.treemap, TreemapSeries.mark = treemapSeriesMark,
TreemapSeries.builtInTheme = {
treemap: treemap
}, TreemapSeries.transformerConstructor = TreemapSeriesSpecTransformer, mixin(TreemapSeries, Drillable),
mixin(TreemapSeries, Zoomable);
export const registerTreemapSeries = () => {
registerMarkFilterTransform(), registerMarkMapTransform(), registerRectMark(), registerTextMark(),
registerTreemapAnimation(), registerFadeInOutAnimation(), Factory.registerSeries(TreemapSeries.type, TreemapSeries);
};
//# sourceMappingURL=treemap.js.map