UNPKG

@visactor/vrender-components

Version:

components library for dp visualization

193 lines (188 loc) 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: !0 }), exports.Brush = void 0; const vrender_core_1 = require("@visactor/vrender-core"), vutils_1 = require("@visactor/vutils"), base_1 = require("../core/base"), type_1 = require("./type"), config_1 = require("./config"), register_1 = require("./register"), delayMap = { debounce: vutils_1.debounce, throttle: vutils_1.throttle }; (0, register_1.loadBrushComponent)(); class Brush extends base_1.AbstractComponent { constructor(attributes, options) { super((null == options ? void 0 : options.skipDefault) ? attributes : (0, vutils_1.merge)({}, Brush.defaultAttributes, attributes)), this.name = "brush", this._activeBrushState = !1, this._activeDrawState = !1, this._cacheDrawPoints = [], this._activeMoveState = !1, this._operatingMaskMoveDx = 0, this._operatingMaskMoveDy = 0, this._operatingMaskMoveRangeX = [ -1 / 0, 1 / 0 ], this._operatingMaskMoveRangeY = [ -1 / 0, 1 / 0 ], this._brushMaskAABBBoundsDict = {}, this._firstUpdate = !0, this._onBrushStart = e => { const {updateTrigger: updateTrigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.updateTrigger, endTrigger: endTrigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.endTrigger, brushMoved: brushMoved = !0} = this.attribute; (0, vutils_1.array)(updateTrigger).forEach((t => this.stage.addEventListener(t, this._onBrushingWithDelay))), (0, vutils_1.array)(endTrigger).forEach((t => this.stage.addEventListener(t, this._onBrushEnd))), e.stopPropagation(), this._firstUpdate = !0, this._activeMoveState = brushMoved && this._isPosInBrushMask(e), this._activeDrawState = !this._activeMoveState, this._startPos = this.eventPosToStagePos(e), this._cacheDrawPoints = [ this._startPos ]; }, this._onBrushing = e => { this._outOfInteractiveRange(e) || (e.stopPropagation(), this._firstUpdate ? (this._activeDrawState && this._initDraw(e), this._activeMoveState && this._initMove(e), this._firstUpdate = !1) : (this._activeDrawState && this._drawing(e), this._activeMoveState && this._moving(e))); }, this._onBrushingWithDelay = 0 === this.attribute.delayTime ? this._onBrushing : delayMap[this.attribute.delayType](this._onBrushing, this.attribute.delayTime), this._onBrushEnd = e => { this._releaseBrushUpdateEvents(), e.preventDefault(), this._activeDrawState && this._drawEnd(e), this._activeMoveState && this._moveEnd(e), this._activeDrawState = !1, this._activeMoveState = !1; }, this._onBrushClear = e => { e.preventDefault(), this._isEmptyMask() || (this._clearMask(), this._dispatchBrushEvent(type_1.IOperateType.brushClear, e)), this._activeDrawState = !1, this._activeMoveState = !1; }; } _bindBrushEvents() { if (this.releaseBrushEvents(), this.attribute.disableTriggerEvent) return; const {trigger: trigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.trigger, resetTrigger: resetTrigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.resetTrigger} = this.attribute; (0, vutils_1.array)(trigger).forEach((t => this.stage.addEventListener(t, this._onBrushStart))), (0, vutils_1.array)(resetTrigger).forEach((t => this.stage.addEventListener(t, this._onBrushClear))); } _initDraw(e) { const {brushMode: brushMode} = this.attribute, pos = this.eventPosToStagePos(e); this._cacheDrawPoints.push(pos), "single" === brushMode && this._clearMask(), this._addBrushMask(), this._dispatchBrushEvent(type_1.IOperateType.drawStart, e), this._activeBrushState = !1; } _initMove(e) { var _a, _b; this._cacheMovePoint = this.eventPosToStagePos(e), this._operatingMaskMoveDx = null !== (_a = this._operatingMask.attribute.dx) && void 0 !== _a ? _a : 0, this._operatingMaskMoveDy = null !== (_b = this._operatingMask.attribute.dy) && void 0 !== _b ? _b : 0; const {interactiveRange: interactiveRange} = this.attribute, {minY: minY = -1 / 0, maxY: maxY = 1 / 0, minX: minX = -1 / 0, maxX: maxX = 1 / 0} = interactiveRange, {x1: x1, x2: x2, y1: y1, y2: y2} = this._operatingMask.globalAABBBounds, minMoveStepX = minX - x1, maxMoveStepX = maxX - x2, minMoveStepY = minY - y1, maxMoveStepY = maxY - y2; this._operatingMaskMoveRangeX = [ minMoveStepX, maxMoveStepX ], this._operatingMaskMoveRangeY = [ minMoveStepY, maxMoveStepY ], this._operatingMask.setAttribute("pickable", !0), this._dispatchBrushEvent(type_1.IOperateType.moveStart, e); } _drawing(e) { var _a; const pos = this.eventPosToStagePos(e), {brushType: brushType, sizeThreshold: sizeThreshold = config_1.DEFAULT_SIZE_THRESHOLD} = this.attribute, cacheLength = this._cacheDrawPoints.length; if (cacheLength > 0) { const lastPos = null !== (_a = this._cacheDrawPoints[this._cacheDrawPoints.length - 1]) && void 0 !== _a ? _a : {}; if (pos.x === lastPos.x && pos.y === lastPos.y) return; } "polygon" === brushType || cacheLength <= 1 ? this._cacheDrawPoints.push(pos) : this._cacheDrawPoints[cacheLength - 1] = pos; const maskPoints = this._computeMaskPoints(); this._operatingMask.setAttribute("points", maskPoints); const {x: x1, y: y1} = this._startPos, {x: x2, y: y2} = this.eventPosToStagePos(e); (Math.abs(x2 - x1) > sizeThreshold || Math.abs(y1 - y2) > sizeThreshold) && (1 !== Object.keys(this._brushMaskAABBBoundsDict).length || this._activeBrushState ? this._dispatchBrushEvent(type_1.IOperateType.drawing, e) : (this._activeBrushState = !0, this._dispatchBrushEvent(type_1.IOperateType.brushActive, e))); } _moving(e) { const startPos = this._cacheMovePoint, pos = this.eventPosToStagePos(e); if (pos.x === (null == startPos ? void 0 : startPos.x) && pos.y === (null == startPos ? void 0 : startPos.y)) return; const moveStepX = pos.x - startPos.x, moveStepY = pos.y - startPos.y, moveX = Math.min(this._operatingMaskMoveRangeX[1], Math.max(this._operatingMaskMoveRangeX[0], moveStepX)) + this._operatingMaskMoveDx, moveY = Math.min(this._operatingMaskMoveRangeY[1], Math.max(this._operatingMaskMoveRangeY[0], moveStepY)) + this._operatingMaskMoveDy; this._operatingMask.setAttributes({ dx: moveX, dy: moveY }), this._brushMaskAABBBoundsDict[this._operatingMask.name] = this._operatingMask.AABBBounds, this._dispatchBrushEvent(type_1.IOperateType.moving, e); } _drawEnd(e) { const {removeOnClick: removeOnClick = !0, sizeThreshold: sizeThreshold = config_1.DEFAULT_SIZE_THRESHOLD} = this.attribute; if (this._outOfInteractiveRange(e)) this._isEmptyMask() || (this._clearMask(), this._dispatchBrushEvent(type_1.IOperateType.brushClear, e)); else { const {x: x1, y: y1} = this._startPos, {x: x2, y: y2} = this.eventPosToStagePos(e); Math.abs(x2 - x1) <= 1 && Math.abs(y2 - y1) <= 1 && removeOnClick ? this._isEmptyMask() || (this._clearMask(), this._dispatchBrushEvent(type_1.IOperateType.brushClear, e)) : Math.abs(x2 - x1) < sizeThreshold && Math.abs(y1 - y2) < sizeThreshold ? (delete this._brushMaskAABBBoundsDict[this._operatingMask.name], this._container.setAttributes({}), this._container.removeChild(this._operatingMask), this._isEmptyMask() && this._dispatchBrushEvent(type_1.IOperateType.brushClear, e)) : (this._brushMaskAABBBoundsDict[this._operatingMask.name] = this._operatingMask.AABBBounds, this._dispatchBrushEvent(type_1.IOperateType.drawEnd, e)); } } _moveEnd(e) { this._operatingMask && this._operatingMask.setAttribute("pickable", !1), this._dispatchBrushEvent(type_1.IOperateType.moveEnd, e); } render() { this._bindBrushEvents(); const group = this.createOrUpdateChild("brush-container", {}, "group"); this._container = group; } releaseBrushEvents() { const {trigger: trigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.trigger, resetTrigger: resetTrigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.resetTrigger} = this.attribute; (0, vutils_1.array)(trigger).forEach((t => this.stage.removeEventListener(t, this._onBrushStart))), (0, vutils_1.array)(resetTrigger).forEach((t => this.stage.removeEventListener(t, this._onBrushClear))), this._releaseBrushUpdateEvents(); } _releaseBrushUpdateEvents() { const {updateTrigger: updateTrigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.updateTrigger, endTrigger: endTrigger = config_1.DEFAULT_BRUSH_ATTRIBUTES.endTrigger} = this.attribute; (0, vutils_1.array)(updateTrigger).forEach((t => this.stage.removeEventListener(t, this._onBrushingWithDelay))), (0, vutils_1.array)(endTrigger).forEach((t => this.stage.removeEventListener(t, this._onBrushEnd))); } _computeMaskPoints() { const {brushType: brushType, xRange: xRange = [ 0, 0 ], yRange: yRange = [ 0, 0 ]} = this.attribute; let maskPoints = []; const startPoint = this._cacheDrawPoints[0], endPoint = this._cacheDrawPoints[this._cacheDrawPoints.length - 1]; return maskPoints = "rect" === brushType ? [ startPoint, { x: endPoint.x, y: startPoint.y }, endPoint, { x: startPoint.x, y: endPoint.y } ] : "x" === brushType ? [ { x: startPoint.x, y: yRange[0] }, { x: endPoint.x, y: yRange[0] }, { x: endPoint.x, y: yRange[1] }, { x: startPoint.x, y: yRange[1] } ] : "y" === brushType ? [ { x: xRange[0], y: startPoint.y }, { x: xRange[0], y: endPoint.y }, { x: xRange[1], y: endPoint.y }, { x: xRange[1], y: startPoint.y } ] : (0, vutils_1.cloneDeep)(this._cacheDrawPoints), maskPoints; } _addBrushMask() { var _a; const {brushStyle: brushStyle, hasMask: hasMask} = this.attribute, brushMask = vrender_core_1.graphicCreator.polygon(Object.assign(Object.assign({ points: (0, vutils_1.cloneDeep)(this._cacheDrawPoints), cursor: "move", pickable: !1 }, brushStyle), { opacity: hasMask ? null !== (_a = brushStyle.opacity) && void 0 !== _a ? _a : 1 : 0 })); brushMask.name = `brush-${Date.now()}`, this._operatingMask = brushMask, this._container.add(brushMask), this._brushMaskAABBBoundsDict[brushMask.name] = brushMask.AABBBounds; } _isPosInBrushMask(e) { const pos = this.eventPosToStagePos(e), brushMasks = this._container.getChildren(); for (let i = 0; i < brushMasks.length; i++) { const {points: points = [], dx: dx = 0, dy: dy = 0} = brushMasks[i].attribute, pointsConsiderOffset = points.map((point => ({ x: point.x + dx, y: point.y + dy }))); if ((0, vutils_1.polygonContainPoint)(pointsConsiderOffset, pos.x, pos.y)) return this._operatingMask = brushMasks[i], !0; } return !1; } _outOfInteractiveRange(e) { const {interactiveRange: interactiveRange} = this.attribute, {minY: minY = -1 / 0, maxY: maxY = 1 / 0, minX: minX = -1 / 0, maxX: maxX = 1 / 0} = interactiveRange, pos = this.eventPosToStagePos(e); return pos.x > maxX || pos.x < minX || pos.y > maxY || pos.y < minY; } _dispatchBrushEvent(operateType, e) { this._dispatchEvent(operateType, { operateMask: this._operatingMask, operatedMaskAABBBounds: this._brushMaskAABBBoundsDict, event: e }); } _clearMask() { this._brushMaskAABBBoundsDict = {}, this._container.removeAllChild(), this._operatingMask = null; } _isEmptyMask() { return (0, vutils_1.isEmpty)(this._brushMaskAABBBoundsDict) || Object.keys(this._brushMaskAABBBoundsDict).every((key => this._brushMaskAABBBoundsDict[key].empty())); } } exports.Brush = Brush, Brush.defaultAttributes = config_1.DEFAULT_BRUSH_ATTRIBUTES; //# sourceMappingURL=brush.js.map