@visactor/vrender-components
Version:
components library for dp visualization
334 lines (330 loc) • 19.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.AxisBase = void 0;
const vrender_core_1 = require("@visactor/vrender-core"), vutils_1 = require("@visactor/vutils"), util_1 = require("../util"), constant_1 = require("../constant"), constant_2 = require("./constant"), config_1 = require("./config"), tag_1 = require("../tag/tag"), util_2 = require("./util"), interaction_1 = require("../util/interaction"), animate_component_1 = require("../animation/animate-component"), config_2 = require("./animate/config");
class AxisBase extends animate_component_1.AnimateComponent {
constructor() {
super(...arguments), this.name = "axis", this.data = [], this.tickLineItems = [],
this.subTickLineItems = [], this.axisLabelLayerSize = {}, this.axisLabelsContainer = null,
this._onHover = e => {
this._lastHover = (0, interaction_1.dispatchHoverState)(e, this.axisContainer, this._lastHover);
}, this._onUnHover = e => {
this._lastHover = (0, interaction_1.dispatchUnHoverState)(e, this.axisContainer, this._lastHover);
}, this._onClick = e => {
this._lastSelect = (0, interaction_1.dispatchClickState)(e, this.axisContainer, this._lastSelect);
};
}
getInnerView() {
return this._innerView;
}
getPrevInnerView() {
return this._prevInnerView;
}
getBoundsWithoutRender(attributes) {
const currentAttribute = (0, vutils_1.cloneDeep)(this.attribute);
currentAttribute.scale = this.attribute.scale, this.attribute = attributes;
const offscreenGroup = vrender_core_1.graphicCreator.group({
x: this.attribute.x,
y: this.attribute.y
});
return this.add(offscreenGroup), this._renderInner(offscreenGroup), this.removeChild(offscreenGroup),
this.attribute = currentAttribute, offscreenGroup.AABBBounds;
}
render() {
this._prepare(), this._prevInnerView = this._innerView && (0, util_2.getElMap)(this._innerView),
this.removeAllChild(!0), this._innerView = vrender_core_1.graphicCreator.group({
x: 0,
y: 0,
pickable: !1
}), this.add(this._innerView), this._renderInner(this._innerView), this._bindEvent(),
this.runAnimation();
}
_prepare() {
this._prepareAnimate(config_2.DefaultAxisAnimation);
}
_bindEvent() {
if (this.attribute.disableTriggerEvent) return;
const {hover: hover, select: select} = this.attribute;
hover && (this._innerView.addEventListener("pointermove", this._onHover), this._innerView.addEventListener("pointerout", this._onUnHover)),
select && this._innerView.addEventListener("pointerdown", this._onClick);
}
_renderInner(container) {
const {title: title, label: label, tick: tick, line: line, items: items} = this.attribute, axisContainer = vrender_core_1.graphicCreator.group({
x: 0,
y: 0,
zIndex: 1,
pickable: !1
});
if (axisContainer.name = constant_2.AXIS_ELEMENT_NAME.axisContainer, axisContainer.id = this._getNodeId("container"),
axisContainer.setMode(this.mode), this.axisContainer = axisContainer, container.add(axisContainer),
line && line.visible && this.renderLine(axisContainer), items && items.length && (this.data = this._transformItems(items[0]),
tick && tick.visible && this.renderTicks(axisContainer), label && label.visible)) {
const labelGroup = vrender_core_1.graphicCreator.group({
x: 0,
y: 0,
pickable: !1
});
labelGroup.name = constant_2.AXIS_ELEMENT_NAME.labelContainer, labelGroup.id = this._getNodeId("label-container"),
this.axisLabelsContainer = labelGroup, axisContainer.add(labelGroup), items.forEach(((axisItems, layer) => {
const layerLabelGroup = this.renderLabels(labelGroup, axisItems, layer), labels = layerLabelGroup.getChildren();
this.beforeLabelsOverlap(labels, axisItems, layerLabelGroup, layer, items.length),
this.handleLabelsOverlap(labels, axisItems, layerLabelGroup, layer, items.length),
this.afterLabelsOverlap(labels, axisItems, layerLabelGroup, layer, items.length);
let maxTextWidth = 0, maxTextHeight = 0, textAlign = "center", textBaseline = "middle", labelPos = 0;
labels.forEach(((label, index) => {
var _a;
const labelStyle = label.attribute, angle = null !== (_a = labelStyle.angle) && void 0 !== _a ? _a : 0, textBounds = label.AABBBounds;
let textWidth = textBounds.width(), textHeight = textBounds.height();
angle && (textWidth = Math.abs(textWidth * Math.cos(angle)), textHeight = Math.abs(textHeight * Math.sin(angle))),
maxTextWidth = Math.max(maxTextWidth, textWidth), maxTextHeight = Math.max(maxTextHeight, textHeight),
textAlign = labelStyle.textAlign, textBaseline = labelStyle.textBaseline, 0 === index && (labelPos = labelStyle.x);
})), this.axisLabelLayerSize[layer] = {
width: maxTextWidth,
height: maxTextHeight,
labelPos: labelPos,
textAlign: textAlign,
textBaseline: textBaseline
};
}));
}
title && title.visible && this.renderTitle(axisContainer);
}
renderTicks(container) {
const tickLineItems = this.getTickLineItems(), tickLineGroup = vrender_core_1.graphicCreator.group({
x: 0,
y: 0,
pickable: !1
});
tickLineGroup.name = constant_2.AXIS_ELEMENT_NAME.tickContainer, tickLineGroup.id = this._getNodeId("tick-container"),
container.add(tickLineGroup), tickLineItems.forEach(((item, index) => {
var _a;
const line = vrender_core_1.graphicCreator.line(Object.assign({}, this._getTickLineAttribute("tick", item, index, tickLineItems)));
if (line.name = constant_2.AXIS_ELEMENT_NAME.tick, line.id = this._getNodeId(item.id),
(0, vutils_1.isEmpty)(null === (_a = this.attribute.tick) || void 0 === _a ? void 0 : _a.state)) line.states = constant_1.DEFAULT_STATES; else {
const data = this.data[index], tickLineState = (0, vutils_1.merge)({}, constant_1.DEFAULT_STATES, this.attribute.tick.state);
Object.keys(tickLineState).forEach((key => {
(0, vutils_1.isFunction)(tickLineState[key]) && (tickLineState[key] = tickLineState[key](data.rawValue, index, data, this.data));
})), line.states = tickLineState;
}
tickLineGroup.add(line);
})), this.tickLineItems = tickLineItems;
const {subTick: subTick} = this.attribute;
if (subTick && subTick.visible) {
const subTickLineItems = this.getSubTickLineItems();
subTickLineItems.length && subTickLineItems.forEach(((item, index) => {
const line = vrender_core_1.graphicCreator.line(Object.assign({}, this._getTickLineAttribute("subTick", item, index, tickLineItems)));
if (line.name = constant_2.AXIS_ELEMENT_NAME.subTick, line.id = this._getNodeId(`${index}`),
(0, vutils_1.isEmpty)(subTick.state)) line.states = constant_1.DEFAULT_STATES; else {
const subTickLineState = (0, vutils_1.merge)({}, constant_1.DEFAULT_STATES, subTick.state);
Object.keys(subTickLineState).forEach((key => {
(0, vutils_1.isFunction)(subTickLineState[key]) && (subTickLineState[key] = subTickLineState[key](item.value, index, item, tickLineItems));
})), line.states = subTickLineState;
}
tickLineGroup.add(line);
})), this.subTickLineItems = subTickLineItems;
}
}
renderLabels(container, items, layer) {
const {dataFilter: dataFilter} = this.attribute.label;
dataFilter && (0, vutils_1.isFunction)(dataFilter) && (items = dataFilter(items, layer));
const data = this._transformItems(items), labelGroup = vrender_core_1.graphicCreator.group({
x: 0,
y: 0,
pickable: !1
});
return labelGroup.name = `${constant_2.AXIS_ELEMENT_NAME.labelContainer}-layer-${layer}`,
labelGroup.id = this._getNodeId(`label-container-layer-${layer}`), container.add(labelGroup),
data.forEach(((item, index) => {
var _a;
const labelStyle = this._getLabelAttribute(item, index, data, layer), text = (0,
util_1.createTextGraphicByType)(labelStyle);
if (text.name = constant_2.AXIS_ELEMENT_NAME.label, text.id = this._getNodeId(`layer${layer}-label-${item.id}`),
(0, vutils_1.isEmpty)(null === (_a = this.attribute.label) || void 0 === _a ? void 0 : _a.state)) text.states = constant_1.DEFAULT_STATES; else {
const labelState = (0, vutils_1.merge)({}, constant_1.DEFAULT_STATES, this.attribute.label.state);
Object.keys(labelState).forEach((key => {
(0, vutils_1.isFunction)(labelState[key]) && (labelState[key] = labelState[key](item, index, data, layer));
})), text.states = labelState;
}
text.data = Object.assign(Object.assign({}, item), {
index: index,
layer: layer
}), labelGroup.add(text);
})), labelGroup;
}
renderTitle(container) {
const titleAttributes = this.getTitleAttribute(), axisTitle = new tag_1.Tag(Object.assign({}, titleAttributes));
axisTitle.name = constant_2.AXIS_ELEMENT_NAME.title, axisTitle.id = this._getNodeId("title"),
container.add(axisTitle);
}
getVerticalCoord(point, offset, inside) {
return (0, util_2.getVerticalCoord)(point, this.getVerticalVector(offset, inside, point));
}
getTickLineItems() {
const {tick: tick} = this.attribute, data = this.data, tickLineItems = [], {alignWithLabel: alignWithLabel, inside: inside = !1, length: length, dataFilter: dataFilter} = tick;
let tickSegment = 1;
return data.length >= 2 && (tickSegment = data[1].value - data[0].value), (dataFilter && (0,
vutils_1.isFunction)(dataFilter) ? dataFilter(data) : data).forEach((item => {
let point = item.point, tickValue = item.value;
if (!alignWithLabel) {
const value = item.value - tickSegment / 2;
if (this.isInValidValue(value)) return;
point = this.getTickCoord(value), tickValue = value;
}
const endPoint = this.getVerticalCoord(point, length, inside);
if ("3d" === this.mode) {
const vec = this.getVerticalVector(length, inside, point);
let alpha = 0, beta = 0;
(0, vutils_1.abs)(vec[0]) > (0, vutils_1.abs)(vec[1]) ? alpha = vutils_1.pi / 2 * (endPoint.x > point.x ? 1 : -1) : beta = vutils_1.pi / 2 * (endPoint.y > point.y ? -1 : 1),
tickLineItems.push({
start: point,
end: endPoint,
value: tickValue,
id: `tick-${item.id}`,
anchor: [ point.x, point.y ],
alpha: alpha,
beta: beta
});
} else tickLineItems.push({
start: point,
end: endPoint,
value: tickValue,
id: `tick-${item.id}`
});
})), tickLineItems;
}
getSubTickLineItems() {
const {subTick: subTick} = this.attribute, subTickLineItems = [], {count: subCount = 4, inside: inside = !1, length: length = 2} = subTick, tickLineItems = this.tickLineItems, tickLineCount = tickLineItems.length;
if (tickLineCount >= 2) for (let i = 0; i < tickLineCount - 1; i++) {
const pre = tickLineItems[i], next = tickLineItems[i + 1];
for (let j = 0; j < subCount; j++) {
const percent = (j + 1) / (subCount + 1), value = (1 - percent) * pre.value + percent * next.value, point = this.getTickCoord(value), endPoint = this.getVerticalCoord(point, length, inside);
subTickLineItems.push({
start: point,
end: endPoint,
value: value,
id: `sub-tick-${value}`
});
}
}
return subTickLineItems;
}
_getTickLineAttribute(type, tickItem, index, tickItems) {
let style = (0, vutils_1.get)(this.attribute, `${type}.style`);
const data = this.data[index];
style = (0, vutils_1.isFunction)(style) ? (0, vutils_1.merge)({}, (0, vutils_1.get)(config_1.DEFAULT_AXIS_THEME, `${type}.style`), "tick" === type ? style(data.rawValue, index, data, this.data) : style(tickItem.value, index, tickItem, tickItems)) : style;
const {start: start, end: end, anchor: anchor, alpha: alpha, beta: beta} = tickItem;
return Object.assign({
points: [ start, end ],
anchor: anchor,
alpha: alpha,
beta: beta
}, style);
}
_getLabelAttribute(tickDatum, index, tickData, layer) {
var _a, _b;
const {space: space = 4, inside: inside = !1, formatMethod: formatMethod, type: type = "text", text: text} = this.attribute.label;
let offset = space, tickLength = 0;
(null === (_a = this.attribute.tick) || void 0 === _a ? void 0 : _a.visible) && this.attribute.tick.inside === inside && (tickLength = this.attribute.tick.length || 4),
(null === (_b = this.attribute.subTick) || void 0 === _b ? void 0 : _b.visible) && this.attribute.subTick.inside === inside && (tickLength = Math.max(tickLength, this.attribute.subTick.length || 2)),
offset += tickLength;
const axisVector = this.getRelativeVector(tickDatum.point);
layer > 0 && (0 === axisVector[1] ? offset += (this.axisLabelLayerSize[layer - 1].height + (0,
vutils_1.get)(this.attribute, "label.space", 4)) * layer : offset += (this.axisLabelLayerSize[layer - 1].width + (0,
vutils_1.get)(this.attribute, "label.space", 4)) * layer);
const point = this.getVerticalCoord(tickDatum.point, offset, inside), vector = this.getVerticalVector(offset || 1, inside, point), textContent = formatMethod ? formatMethod(`${tickDatum.label}`, tickDatum, index, tickData, layer) : tickDatum.label;
let {style: textStyle} = this.attribute.label;
textStyle = (0, vutils_1.isFunction)(textStyle) ? (0, vutils_1.merge)({}, config_1.DEFAULT_AXIS_THEME.label.style, textStyle(tickDatum, index, tickData, layer)) : textStyle;
const labelAlign = this.getLabelAlign(vector, inside, textStyle.angle);
return textStyle = (0, vutils_1.merge)(labelAlign, textStyle), (0, vutils_1.isFunction)(textStyle.text) && (textStyle.text = textStyle.text({
label: tickDatum.label,
value: tickDatum.rawValue,
index: tickDatum.index,
layer: layer
})), Object.assign(Object.assign(Object.assign({}, this.getLabelPosition(point, vector, textContent, textStyle)), {
text: null != text ? text : textContent,
_originText: tickDatum.label,
lineHeight: null == textStyle ? void 0 : textStyle.fontSize,
type: type
}), textStyle);
}
getLabelPosition(point, vector, text, style) {
return point;
}
_transformItems(items) {
const data = [];
return items.forEach((item => {
var _a;
data.push(Object.assign(Object.assign({}, item), {
point: this.getTickCoord(item.value),
id: null !== (_a = item.id) && void 0 !== _a ? _a : item.label
}));
})), data;
}
runAnimation() {
const lastScale = this.lastScale;
if (this.attribute.scale) {
const scale = this.attribute.scale;
this.lastScale = scale.clone(), this.lastScale.range([ 0, 1 ]);
}
if (this.attribute.animation && this.applyAnimationState) {
const currentInnerView = this.getInnerView(), prevInnerView = this.getPrevInnerView();
if (!prevInnerView) return;
const animationConfig = this._animationConfig;
this._newElementAttrMap = {}, (0, util_1.traverseGroup)(currentInnerView, (el => {
var _a;
if ("group" !== el.type && el.id) {
const oldEl = prevInnerView[el.id];
if (el.setFinalAttributes(el.attribute), oldEl) {
oldEl.release();
const oldAttrs = oldEl.attribute, finalAttrs = el.getFinalAttribute(), diffAttrs = (0,
vrender_core_1.diff)(oldAttrs, finalAttrs);
let hasDiff = Object.keys(diffAttrs).length > 0;
if ("opacity" in oldAttrs && finalAttrs.opacity !== oldAttrs.opacity && (diffAttrs.opacity = null !== (_a = finalAttrs.opacity) && void 0 !== _a ? _a : 1,
hasDiff = !0), animationConfig.update && hasDiff) {
this._newElementAttrMap[el.id] = {
state: "update",
node: el,
attrs: el.attribute
};
const oldAttrs = oldEl.attribute;
el.setAttributes(oldAttrs), el.applyAnimationState([ "update" ], [ {
name: "update",
animation: Object.assign(Object.assign({
selfOnly: !0
}, animationConfig.update), {
type: "axisUpdate",
customParameters: {
config: animationConfig.update,
diffAttrs: diffAttrs,
lastScale: lastScale
}
})
} ]);
}
} else animationConfig.enter && (this._newElementAttrMap[el.id] = {
state: "enter",
node: el,
attrs: el.attribute
}, el.applyAnimationState([ "enter" ], [ {
name: "enter",
animation: Object.assign(Object.assign({}, animationConfig.enter), {
type: "axisEnter",
selfOnly: !0,
customParameters: {
config: animationConfig.enter,
lastScale: lastScale,
getTickCoord: this.getTickCoord.bind(this)
}
})
} ]));
}
}));
}
}
release() {
super.release(), this._prevInnerView = null, this._innerView = null;
}
}
exports.AxisBase = AxisBase;
//# sourceMappingURL=base.js.map