UNPKG

@visactor/vrender-components

Version:

components library for dp visualization

336 lines (317 loc) 20.9 kB
var __rest = this && this.__rest || function(s, e) { var t = {}; for (var p in s) Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0 && (t[p] = s[p]); if (null != s && "function" == typeof Object.getOwnPropertySymbols) { var i = 0; for (p = Object.getOwnPropertySymbols(s); i < p.length; i++) e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]) && (t[p[i]] = s[p[i]]); } return t; }; import { get, isNil, merge, isNumberClose, isEmpty, isFunction, isValidNumber, isValid, normalizePadding, mixin, last as peek } from "@visactor/vutils"; import { graphicCreator } from "@visactor/vrender-core"; import { Segment } from "../segment"; import { angleTo } from "../util/matrix"; import { AxisBase } from "./base"; import { DEFAULT_AXIS_THEME } from "./config"; import { AXIS_ELEMENT_NAME, DEFAULT_STATES, TopZIndex } from "./constant"; import { measureTextSize } from "../util"; import { autoHide as autoHideFunc } from "./overlap/auto-hide"; import { autoRotate as autoRotateFunc, getXAxisLabelAlign, getYAxisLabelAlign } from "./overlap/auto-rotate"; import { autoLimit as autoLimitFunc } from "./overlap/auto-limit"; import { autoWrap as autoWrapFunc } from "./overlap/auto-wrap"; import { alignAxisLabels } from "../util/align"; import { LineAxisMixin } from "./mixin/line"; import { loadLineAxisComponent } from "./register"; import { getAxisBreakSymbolAttrs } from "./util"; loadLineAxisComponent(); export class LineAxis extends AxisBase { constructor(attributes, options) { super((null == options ? void 0 : options.skipDefault) ? attributes : merge({}, LineAxis.defaultAttributes, attributes), options); } _renderInner(container) { var _a; if (this._breaks = null, this.attribute.breaks && this.attribute.breaks.length) { const transformedBreaks = []; for (let index = 0; index < this.attribute.breaks.length; index++) { const aBreak = this.attribute.breaks[index], {range: range, breakSymbol: breakSymbol, rawRange: rawRange} = aBreak; transformedBreaks.push({ startPoint: this.getTickCoord(range[0]), endPoint: this.getTickCoord(range[1]), range: range, breakSymbol: breakSymbol, rawRange: rawRange }); } this._breaks = transformedBreaks; } super._renderInner(container), this._breaks && this._breaks.length && this._breaks.forEach(((b, index) => { const {startPoint: startPoint, endPoint: endPoint, breakSymbol: breakSymbol, rawRange: rawRange} = b; if (!1 !== (null == breakSymbol ? void 0 : breakSymbol.visible)) { const axisBreakGroup = graphicCreator.group({ zIndex: TopZIndex }); axisBreakGroup.name = AXIS_ELEMENT_NAME.axisBreak, axisBreakGroup.id = this._getNodeId(`${AXIS_ELEMENT_NAME.axisBreak}-${index}`), axisBreakGroup.data = rawRange; const symbolStyle = getAxisBreakSymbolAttrs(breakSymbol), shape1 = graphicCreator.symbol(Object.assign({ x: startPoint.x, y: startPoint.y }, symbolStyle)); shape1.name = AXIS_ELEMENT_NAME.axisBreakSymbol; const shape2 = graphicCreator.symbol(Object.assign({ x: endPoint.x, y: endPoint.y }, symbolStyle)); shape2.name = AXIS_ELEMENT_NAME.axisBreakSymbol, axisBreakGroup.add(shape1), axisBreakGroup.add(shape2), container.add(axisBreakGroup); } })); const {panel: panel} = this.attribute; if (panel && panel.visible) { const axisContainer = this.axisContainer, axisContainerBounds = axisContainer.AABBBounds, bgRect = graphicCreator.rect(Object.assign({ x: axisContainerBounds.x1, y: axisContainerBounds.y1, width: axisContainerBounds.width(), height: axisContainerBounds.height() }, panel.style)); bgRect.name = AXIS_ELEMENT_NAME.background, bgRect.id = this._getNodeId("background"), bgRect.states = merge({}, DEFAULT_STATES, null !== (_a = panel.state) && void 0 !== _a ? _a : {}), axisContainer.insertBefore(bgRect, axisContainer.firstChild); } } renderLine(container) { const {start: start, end: end, line: line} = this.attribute, _a = line, {startSymbol: startSymbol, endSymbol: endSymbol, style: style, state: state} = _a, restLineAttrs = __rest(_a, [ "startSymbol", "endSymbol", "style", "state" ]), lineAttrs = Object.assign({ startSymbol: startSymbol, endSymbol: endSymbol, lineStyle: style }, restLineAttrs); if (this._breaks && this._breaks.length) { const linePoints = []; let lastStartPoint = start; this._breaks.forEach((b => { const {startPoint: startPoint, endPoint: endPoint} = b; linePoints.push([ lastStartPoint, startPoint ]), lastStartPoint = endPoint; })), linePoints.push([ lastStartPoint, end ]), lineAttrs.points = linePoints, lineAttrs.multiSegment = !0; } else lineAttrs.points = [ start, end ]; isEmpty(state) || (lineAttrs.state = { line: merge({}, DEFAULT_STATES, state), symbol: merge({}, DEFAULT_STATES, state) }); const axisLineGroup = new Segment(lineAttrs); axisLineGroup.name = AXIS_ELEMENT_NAME.line, axisLineGroup.id = this._getNodeId("line"), container.add(axisLineGroup); } getTextAlign(vector) { let align = "center"; return isNumberClose(vector[0], 0) ? isNumberClose(vector[1], 0) ? Object.is(vector[1], -0) ? align = "start" : Object.is(vector[0], -0) && (align = "end") : align = "center" : vector[0] > 0 ? align = "start" : vector[0] < 0 && (align = "end"), align; } getTitleAttribute() { var _a, _b, _c; const _d = this.attribute.title, {position: position = "middle", space: space = 4, textStyle: textStyle = {}, autoRotate: autoRotate = !0, shape: shape, background: background, state: state = {}, maxWidth: maxWidth} = _d, restAttrs = __rest(_d, [ "position", "space", "textStyle", "autoRotate", "shape", "background", "state", "maxWidth" ]); let percent = .5; "start" === position ? percent = 0 : "end" === position && (percent = 1); const {verticalFactor: verticalFactor = 1} = this.attribute, factor = -1 * verticalFactor, point = this.getTickCoord(percent), axisVector = this.getRelativeVector(); let labelLength = 0; if ((null === (_a = this.attribute.label) || void 0 === _a ? void 0 : _a.visible) && !1 === this.attribute.label.inside) { const space = +get(this.attribute, "label.space", 4); labelLength += space; const layerCount = Object.keys(this.axisLabelLayerSize).length; if (0 === axisVector[1]) { const labelBoundsHeight = this.axisLabelsContainer ? this.axisLabelsContainer.AABBBounds.height() : 0; isFinite(labelBoundsHeight) ? labelLength += labelBoundsHeight + (layerCount - 1) * space : labelLength = 0; } else if (0 === axisVector[0]) if (this.axisLabelsContainer && this.axisLabelsContainer.AABBBounds && !this.axisLabelsContainer.AABBBounds.empty()) { const baseX = this.axisLabelLayerSize[0].labelPos, bounds = this.axisLabelsContainer.AABBBounds; labelLength += (1 === factor ? bounds.x2 > baseX ? Math.min(bounds.x2 - baseX, bounds.width()) : 0 : bounds.x1 < baseX ? Math.min(baseX - bounds.x1, bounds.width()) : 0) + (layerCount - 1) * space; } else labelLength = 0; else Object.keys(this.axisLabelLayerSize).forEach(((layer, index) => { labelLength += this.axisLabelLayerSize[layer].width + (index > 0 ? space : 0); })); } let tickLength = 0; (null === (_b = this.attribute.tick) || void 0 === _b ? void 0 : _b.visible) && !1 === this.attribute.tick.inside && (tickLength = this.attribute.tick.length || 4), (null === (_c = this.attribute.subTick) || void 0 === _c ? void 0 : _c.visible) && !1 === this.attribute.subTick.inside && (tickLength = Math.max(tickLength, this.attribute.subTick.length || 2)); const offset = tickLength + labelLength + space, titlePoint = this.getVerticalCoord(point, offset, !1), vector = this.getVerticalVector(offset, !1, { x: 0, y: 0 }); let textAlign, textBaseline, {angle: angle} = restAttrs; if (textAlign = "start" === position ? "start" : "end" === position ? "end" : "center", isNil(angle) && autoRotate) { angle = angleTo(axisVector, [ 1, 0 ], !0); const {verticalFactor: verticalFactor = 1} = this.attribute; textBaseline = 1 === -1 * verticalFactor ? "bottom" : "top"; } else textAlign = this.getTextAlign(vector), textBaseline = this.getTextBaseline(vector, !1); let maxTagWidth = maxWidth; if (isNil(maxTagWidth)) { const {verticalLimitSize: verticalLimitSize, verticalMinSize: verticalMinSize, orient: orient} = this.attribute, limitSize = Math.min(verticalLimitSize || 1 / 0, verticalMinSize || 1 / 0); if (isValidNumber(limitSize)) { if ("bottom" === orient || "top" === orient) if (angle !== Math.PI / 2) { const cosValue = Math.abs(Math.cos(null != angle ? angle : 0)); maxTagWidth = cosValue < 1e-6 ? 1 / 0 : this.attribute.end.x / cosValue; } else maxTagWidth = limitSize - offset; else if (angle && 0 !== angle) { const sinValue = Math.abs(Math.sin(angle)); maxTagWidth = sinValue < 1e-6 ? 1 / 0 : this.attribute.end.y / sinValue; } else maxTagWidth = limitSize - offset; } } const attrs = Object.assign(Object.assign(Object.assign({}, titlePoint), restAttrs), { maxWidth: maxTagWidth, textStyle: Object.assign({ textAlign: textAlign, textBaseline: textBaseline }, textStyle), state: { text: merge({}, DEFAULT_STATES, state.text), shape: merge({}, DEFAULT_STATES, state.shape), panel: merge({}, DEFAULT_STATES, state.background) } }); return attrs.angle = angle, shape && shape.visible && (attrs.shape = Object.assign({ visible: !0 }, shape.style), shape.space && (attrs.space = shape.space)), background && background.visible && (attrs.panel = Object.assign({ visible: !0 }, background.style)), attrs; } getTextBaseline(vector, inside) { let base = "middle"; const {verticalFactor: verticalFactor = 1} = this.attribute, factor = (inside ? 1 : -1) * verticalFactor; return isNumberClose(vector[1], 0) ? base = !isNumberClose(vector[0], 0) || Object.is(vector[0], -0) || Object.is(vector[1], -0) ? "middle" : 1 === factor ? "bottom" : "top" : vector[1] > 0 ? base = "top" : vector[1] < 0 && (base = "bottom"), base; } getLabelAlign(vector, inside, angle) { const orient = this.attribute.orient; if ([ "top", "bottom", "right", "left" ].includes(orient) || 0 === vector[0] && 0 === vector[1]) { if ("top" === orient || "bottom" === orient) return getXAxisLabelAlign(inside ? "bottom" === orient ? "top" : "bottom" : orient, angle); if ("left" === orient || "right" === orient) return getYAxisLabelAlign(inside ? "left" === orient ? "right" : "left" : orient, angle); } return { textAlign: this.getTextAlign(vector), textBaseline: this.getTextBaseline(vector, inside) }; } beforeLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) { var _a, _b, _c, _d; const {flush: flush = !1} = this.attribute.label || {}; if (flush && labelShapes.length) { const {orient: orient, start: axisStart, end: axisEnd} = this.attribute, isX = "bottom" === orient || "top" === orient, first = labelShapes[0], last = peek(labelShapes), isInverse = isX ? first.attribute.x > last.attribute.x : first.attribute.y < last.attribute.y; if (isX) { const leftMostLabel = isInverse ? last : first, rightMostLabel = isInverse ? first : last, left = axisStart.x, right = axisEnd.x, leftBound = leftMostLabel.AABBBounds.x1, rightBound = rightMostLabel.AABBBounds.x2; if (leftBound < left) { leftMostLabel.attribute.angle ? leftMostLabel.setAttributes({ dx: (null !== (_a = leftMostLabel.attribute.dx) && void 0 !== _a ? _a : 0) + left - leftBound }) : leftMostLabel.setAttributes({ x: left, textAlign: "left" }); } if (rightBound > right) { rightMostLabel.attribute.angle ? rightMostLabel.setAttributes({ dx: (null !== (_b = rightMostLabel.attribute.dx) && void 0 !== _b ? _b : 0) + right - rightBound }) : rightMostLabel.setAttributes({ x: right, textAlign: "right" }); } } else { const bottomMostLabel = isInverse ? last : first, topMostLabel = isInverse ? first : last, bottomBound = bottomMostLabel.AABBBounds.y2, topBound = topMostLabel.AABBBounds.y1, top = axisStart.y, bottom = axisEnd.y; if (topBound < top) { topMostLabel.attribute.angle ? topMostLabel.setAttributes({ dy: (null !== (_c = topMostLabel.attribute.dy) && void 0 !== _c ? _c : 0) + top - topBound }) : topMostLabel.setAttributes({ y: top, textBaseline: "top" }); } if (bottomBound > bottom) { bottomMostLabel.attribute.angle ? bottomMostLabel.setAttributes({ dy: (null !== (_d = bottomMostLabel.attribute.dy) && void 0 !== _d ? _d : 0) + bottom - bottomBound }) : bottomMostLabel.setAttributes({ y: bottom, textBaseline: "bottom" }); } } } } handleLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) { if (isEmpty(labelShapes)) return; const {verticalLimitSize: verticalLimitSize, label: label, orient: orient} = this.attribute, limitLength = this._getAxisLabelLimitLength(verticalLimitSize, layerCount), {layoutFunc: layoutFunc, autoRotate: autoRotate, autoRotateAngle: autoRotateAngle, autoLimit: autoLimit, limitEllipsis: limitEllipsis, autoHide: autoHide, autoHideMethod: autoHideMethod, autoHideSeparation: autoHideSeparation, lastVisible: lastVisible, firstVisible: firstVisible, autoWrap: autoWrap, overflowLimitLength: overflowLimitLength} = label; if (isFunction(layoutFunc)) layoutFunc(labelShapes, labelData, layer, this); else { if (autoRotate) autoRotateFunc(labelShapes, { labelRotateAngle: autoRotateAngle, orient: orient }); else if (autoWrap) { const axisLength = "left" === orient || "right" === orient ? Math.abs(this.attribute.start.y - this.attribute.end.y) : Math.abs(this.attribute.start.x - this.attribute.end.x); autoWrapFunc(labelShapes, { orient: orient, limitLength: limitLength, axisLength: axisLength, ellipsis: limitEllipsis }); } if (!autoWrap && autoLimit && isValidNumber(limitLength) && limitLength > 0) { const isVertical = "left" === orient || "right" === orient, axisLength = isVertical ? Math.abs(this.attribute.start.y - this.attribute.end.y) : Math.abs(this.attribute.start.x - this.attribute.end.x), verticalLimitLength = isVertical ? axisLength / labelShapes.length : autoHide || autoRotate ? 1 / 0 : axisLength / labelShapes.length; autoLimitFunc(labelShapes, { limitLength: limitLength, verticalLimitLength: verticalLimitLength, ellipsis: limitEllipsis, orient: orient, axisLength: axisLength, overflowLimitLength: overflowLimitLength }); } autoHide && autoHideFunc(labelShapes, { orient: orient, method: autoHideMethod, separation: autoHideSeparation, lastVisible: lastVisible, firstVisible: firstVisible }); } } afterLabelsOverlap(labelShapes, labelData, labelContainer, layer, layerCount) { const {verticalLimitSize: verticalLimitSize, orient: orient} = this.attribute, isHorizontal = "bottom" === orient || "top" === orient, axisLabelContainerBounds = labelContainer.AABBBounds; let axisLabelContainerSize = isHorizontal ? axisLabelContainerBounds.height() : axisLabelContainerBounds.width(); const {verticalMinSize: verticalMinSize} = this.attribute; if (isValidNumber(verticalMinSize) && (!isValidNumber(verticalLimitSize) || verticalMinSize <= verticalLimitSize)) { const minSize = this._getAxisLabelLimitLength(verticalMinSize, layerCount); let x, y; axisLabelContainerSize = Math.max(axisLabelContainerSize, minSize), "left" === orient ? (x = axisLabelContainerBounds.x2 - axisLabelContainerSize, y = axisLabelContainerBounds.y1) : "right" === orient ? (x = axisLabelContainerBounds.x1, y = axisLabelContainerBounds.y1) : "top" === orient ? (x = axisLabelContainerBounds.x1, y = axisLabelContainerBounds.y2 - axisLabelContainerSize) : "bottom" === orient && (x = axisLabelContainerBounds.x1, y = axisLabelContainerBounds.y1); const bgRect = graphicCreator.rect({ x: x, y: y, width: isHorizontal ? axisLabelContainerBounds.width() : axisLabelContainerSize, height: isHorizontal ? axisLabelContainerSize : axisLabelContainerBounds.height(), pickable: !1 }); bgRect.name = AXIS_ELEMENT_NAME.axisLabelBackground, bgRect.id = this._getNodeId("axis-label-background"), labelContainer.insertBefore(bgRect, labelContainer.firstChild); } if (isValid(this.attribute.label.containerAlign)) { let start; "left" === orient ? start = axisLabelContainerBounds.x2 - axisLabelContainerSize : "right" === orient ? start = axisLabelContainerBounds.x1 : "top" === orient ? start = axisLabelContainerBounds.y2 - axisLabelContainerSize : "bottom" === orient && (start = axisLabelContainerBounds.y1), alignAxisLabels(labelShapes, start, axisLabelContainerSize, orient, this.attribute.label.containerAlign); } } _getAxisLabelLimitLength(limitSize, layerCount) { var _a, _b, _c, _d, _e; const {label: label, title: title, line: line, tick: tick} = this.attribute, labelSpace = null !== (_a = label.space) && void 0 !== _a ? _a : 4; let limitLength = limitSize, titleHeight = 0, titleSpacing = 0; const axisLineWidth = line && line.visible ? null !== (_b = line.style.lineWidth) && void 0 !== _b ? _b : 1 : 0, tickLength = tick && tick.visible ? null !== (_c = tick.length) && void 0 !== _c ? _c : 4 : 0; if (title && title.visible && "string" == typeof title.text) { titleHeight = measureTextSize(title.text, title.textStyle, null === (_e = null === (_d = this.stage) || void 0 === _d ? void 0 : _d.getTheme()) || void 0 === _e ? void 0 : _e.text).height; const padding = normalizePadding(title.padding); titleSpacing = title.space + padding[0] + padding[2]; } return limitLength && (limitLength = (limitLength - labelSpace - titleSpacing - titleHeight - axisLineWidth - tickLength) / layerCount), limitLength; } release() { super.release(), this._breaks = null; } } LineAxis.defaultAttributes = DEFAULT_AXIS_THEME, mixin(LineAxis, LineAxisMixin); //# sourceMappingURL=line.js.map