@visactor/vrender-components
Version:
components library for dp visualization
193 lines (188 loc) • 12.4 kB
JavaScript
"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