Files
lan-manager/web/node_modules/@antv/g-base/lib/abstract/element.js
openclaw 0a5f6a8047 Initial commit: Lan-manager project code
- Go backend (server/)
- Frontend (web/, server/static/)
- Database and deployment files
- Scripts and docs

Co-Authored-By: 狸花猫/Claude-Qwen3.6-Plus 🐾
2026-04-20 00:52:58 +08:00

733 lines
25 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var util_1 = require("@antv/util");
var matrix_util_1 = require("@antv/matrix-util");
var util_2 = require("../util/util");
var matrix_1 = require("../util/matrix");
var base_1 = require("./base");
var transform = matrix_util_1.ext.transform;
var MATRIX = 'matrix';
var CLONE_CFGS = ['zIndex', 'capture', 'visible', 'type'];
// 可以在 toAttrs 中设置,但不属于绘图属性的字段
var RESERVED_PORPS = ['repeat'];
var DELEGATION_SPLIT = ':';
var WILDCARD = '*';
// 需要考虑数组嵌套数组的场景
// 数组嵌套对象的场景不考虑
function _cloneArrayAttr(arr) {
var result = [];
for (var i = 0; i < arr.length; i++) {
if (util_1.isArray(arr[i])) {
result.push([].concat(arr[i]));
}
else {
result.push(arr[i]);
}
}
return result;
}
function getFormatFromAttrs(toAttrs, shape) {
var fromAttrs = {};
var attrs = shape.attrs;
for (var k in toAttrs) {
fromAttrs[k] = attrs[k];
}
return fromAttrs;
}
function getFormatToAttrs(props, shape) {
var toAttrs = {};
var attrs = shape.attr();
util_1.each(props, function (v, k) {
if (RESERVED_PORPS.indexOf(k) === -1 && !util_1.isEqual(attrs[k], v)) {
toAttrs[k] = v;
}
});
return toAttrs;
}
function checkExistedAttrs(animations, animation) {
if (animation.onFrame) {
return animations;
}
var startTime = animation.startTime, delay = animation.delay, duration = animation.duration;
var hasOwnProperty = Object.prototype.hasOwnProperty;
util_1.each(animations, function (item) {
// 后一个动画开始执行的时间 < 前一个动画的结束时间 && 后一个动画的执行时间 > 前一个动画的延迟
if (startTime + delay < item.startTime + item.delay + item.duration && duration > item.delay) {
util_1.each(animation.toAttrs, function (v, k) {
if (hasOwnProperty.call(item.toAttrs, k)) {
delete item.toAttrs[k];
delete item.fromAttrs[k];
}
});
}
});
return animations;
}
var Element = /** @class */ (function (_super) {
tslib_1.__extends(Element, _super);
function Element(cfg) {
var _this = _super.call(this, cfg) || this;
/**
* @protected
* 图形属性
* @type {ShapeAttrs}
*/
_this.attrs = {};
var attrs = _this.getDefaultAttrs();
util_1.mix(attrs, cfg.attrs);
_this.attrs = attrs;
_this.initAttrs(attrs);
_this.initAnimate(); // 初始化动画
return _this;
}
// override
Element.prototype.getDefaultCfg = function () {
return {
visible: true,
capture: true,
zIndex: 0,
};
};
/**
* @protected
* 获取默认的属相
*/
Element.prototype.getDefaultAttrs = function () {
return {
matrix: this.getDefaultMatrix(),
opacity: 1,
};
};
/**
* @protected
* 一些方法调用会引起画布变化
* @param {ChangeType} changeType 改变的类型
*/
Element.prototype.onCanvasChange = function (changeType) { };
/**
* @protected
* 初始化属性,有些属性需要加工
* @param {object} attrs 属性值
*/
Element.prototype.initAttrs = function (attrs) { };
/**
* @protected
* 初始化动画
*/
Element.prototype.initAnimate = function () {
this.set('animable', true);
this.set('animating', false);
};
Element.prototype.isGroup = function () {
return false;
};
Element.prototype.getParent = function () {
return this.get('parent');
};
Element.prototype.getCanvas = function () {
return this.get('canvas');
};
Element.prototype.attr = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var name = args[0], value = args[1];
if (!name)
return this.attrs;
if (util_1.isObject(name)) {
for (var k in name) {
this.setAttr(k, name[k]);
}
this.afterAttrsChange(name);
return this;
}
if (args.length === 2) {
this.setAttr(name, value);
this.afterAttrsChange((_a = {},
_a[name] = value,
_a));
return this;
}
return this.attrs[name];
};
// 是否被裁剪,被裁剪则不显示,不参与拾取
Element.prototype.isClipped = function (refX, refY) {
var clip = this.getClip();
return clip && !clip.isHit(refX, refY);
};
/**
* 内部设置属性值的接口
* @param {string} name 属性名
* @param {any} value 属性值
*/
Element.prototype.setAttr = function (name, value) {
var originValue = this.attrs[name];
if (originValue !== value) {
this.attrs[name] = value;
this.onAttrChange(name, value, originValue);
}
};
/**
* @protected
* 属性值发生改变
* @param {string} name 属性名
* @param {any} value 属性值
* @param {any} originValue 属性值
*/
Element.prototype.onAttrChange = function (name, value, originValue) {
if (name === 'matrix') {
this.set('totalMatrix', null);
}
};
/**
* 属性更改后需要做的事情
* @protected
*/
Element.prototype.afterAttrsChange = function (targetAttrs) {
if (this.cfg.isClipShape) {
var applyTo = this.cfg.applyTo;
if (applyTo) {
applyTo.onCanvasChange('clip');
}
}
else {
this.onCanvasChange('attr');
}
};
Element.prototype.show = function () {
// 不是高频操作直接使用 set
this.set('visible', true);
this.onCanvasChange('show');
return this;
};
Element.prototype.hide = function () {
// 不是高频操作直接使用 set
this.set('visible', false);
this.onCanvasChange('hide');
return this;
};
Element.prototype.setZIndex = function (zIndex) {
this.set('zIndex', zIndex);
var parent = this.getParent();
if (parent) {
// 改变 zIndex 不应该立即触发渲染 (调用 onCanvasChange('zIndex')),需要经过 sort 再触发
parent.sort();
}
return this;
};
Element.prototype.toFront = function () {
var parent = this.getParent();
if (!parent) {
return;
}
var children = parent.getChildren();
var el = this.get('el');
var index = children.indexOf(this);
children.splice(index, 1);
children.push(this);
this.onCanvasChange('zIndex');
};
Element.prototype.toBack = function () {
var parent = this.getParent();
if (!parent) {
return;
}
var children = parent.getChildren();
var el = this.get('el');
var index = children.indexOf(this);
children.splice(index, 1);
children.unshift(this);
this.onCanvasChange('zIndex');
};
Element.prototype.remove = function (destroy) {
if (destroy === void 0) { destroy = true; }
var parent = this.getParent();
if (parent) {
util_2.removeFromArray(parent.getChildren(), this);
if (!parent.get('clearing')) {
// 如果父元素正在清理,当前元素不触发 remove
this.onCanvasChange('remove');
}
}
else {
this.onCanvasChange('remove');
}
if (destroy) {
this.destroy();
}
};
Element.prototype.resetMatrix = function () {
this.attr(MATRIX, this.getDefaultMatrix());
this.onCanvasChange('matrix');
};
Element.prototype.getMatrix = function () {
return this.attr(MATRIX);
};
Element.prototype.setMatrix = function (m) {
this.attr(MATRIX, m);
this.onCanvasChange('matrix');
};
// 获取总的 matrix
Element.prototype.getTotalMatrix = function () {
var totalMatrix = this.cfg.totalMatrix;
if (!totalMatrix) {
var currentMatrix = this.attr('matrix');
var parentMatrix = this.cfg.parentMatrix;
if (parentMatrix && currentMatrix) {
totalMatrix = matrix_1.multiplyMatrix(parentMatrix, currentMatrix);
}
else {
totalMatrix = currentMatrix || parentMatrix;
}
this.set('totalMatrix', totalMatrix);
}
return totalMatrix;
};
// 上层分组设置 matrix
Element.prototype.applyMatrix = function (matrix) {
var currentMatrix = this.attr('matrix');
var totalMatrix = null;
if (matrix && currentMatrix) {
totalMatrix = matrix_1.multiplyMatrix(matrix, currentMatrix);
}
else {
totalMatrix = currentMatrix || matrix;
}
this.set('totalMatrix', totalMatrix);
this.set('parentMatrix', matrix);
};
/**
* @protected
* 获取默认的矩阵
* @returns {number[]|null} 默认的矩阵
*/
Element.prototype.getDefaultMatrix = function () {
return null;
};
// 将向量应用设置的矩阵
Element.prototype.applyToMatrix = function (v) {
var matrix = this.attr('matrix');
if (matrix) {
return matrix_1.multiplyVec2(matrix, v);
}
return v;
};
// 根据设置的矩阵,将向量转换相对于图形/分组的位置
Element.prototype.invertFromMatrix = function (v) {
var matrix = this.attr('matrix');
if (matrix) {
var invertMatrix = matrix_1.invert(matrix);
if (invertMatrix) {
return matrix_1.multiplyVec2(invertMatrix, v);
}
}
return v;
};
// 设置 clip
Element.prototype.setClip = function (clipCfg) {
var canvas = this.getCanvas();
// 应该只设置当前元素的 clip不应该去修改 clip 本身,方便 clip 被复用
// TODO: setClip 的传参既 shape 配置,也支持 shape 对象
// const preShape = this.get('clipShape');
// if (preShape) {
// // 将之前的 clipShape 销毁
// preShape.destroy();
// }
var clipShape = null;
// 如果配置项为 null则不移除 clipShape
if (clipCfg) {
var ShapeBase = this.getShapeBase();
var shapeType = util_1.upperFirst(clipCfg.type);
var Cons = ShapeBase[shapeType];
if (Cons) {
clipShape = new Cons({
type: clipCfg.type,
isClipShape: true,
applyTo: this,
attrs: clipCfg.attrs,
canvas: canvas,
});
}
}
this.set('clipShape', clipShape);
this.onCanvasChange('clip');
return clipShape;
};
Element.prototype.getClip = function () {
// 高频率调用的地方直接使用 this.cfg.xxx
var clipShape = this.cfg.clipShape;
// 未设置时返回 Null保证一致性
if (!clipShape) {
return null;
}
return clipShape;
};
Element.prototype.clone = function () {
var _this = this;
var originAttrs = this.attrs;
var attrs = {};
util_1.each(originAttrs, function (i, k) {
if (util_1.isArray(originAttrs[k])) {
attrs[k] = _cloneArrayAttr(originAttrs[k]);
}
else {
attrs[k] = originAttrs[k];
}
});
var cons = this.constructor;
// @ts-ignore
var clone = new cons({ attrs: attrs });
util_1.each(CLONE_CFGS, function (cfgName) {
clone.set(cfgName, _this.get(cfgName));
});
return clone;
};
Element.prototype.destroy = function () {
var destroyed = this.destroyed;
if (destroyed) {
return;
}
this.attrs = {};
_super.prototype.destroy.call(this);
// this.onCanvasChange('destroy');
};
/**
* 是否处于动画暂停状态
* @return {boolean} 是否处于动画暂停状态
*/
Element.prototype.isAnimatePaused = function () {
return this.get('_pause').isPaused;
};
/**
* 执行动画,支持多种函数签名
* 1. animate(toAttrs: ElementAttrs, duration: number, easing?: string, callback?: () => void, delay?: number)
* 2. animate(onFrame: OnFrame, duration: number, easing?: string, callback?: () => void, delay?: number)
* 3. animate(toAttrs: ElementAttrs, cfg: AnimateCfg)
* 4. animate(onFrame: OnFrame, cfg: AnimateCfg)
* 各个参数的含义为:
* toAttrs 动画最终状态
* onFrame 自定义帧动画函数
* duration 动画执行时间
* easing 动画缓动效果
* callback 动画执行后的回调
* delay 动画延迟时间
*/
Element.prototype.animate = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!this.get('timeline') && !this.get('canvas')) {
return;
}
this.set('animating', true);
var timeline = this.get('timeline');
if (!timeline) {
timeline = this.get('canvas').get('timeline');
this.set('timeline', timeline);
}
var animations = this.get('animations') || [];
// 初始化 tick
if (!timeline.timer) {
timeline.initTimer();
}
var toAttrs = args[0], duration = args[1], _a = args[2], easing = _a === void 0 ? 'easeLinear' : _a, _b = args[3], callback = _b === void 0 ? util_1.noop : _b, _c = args[4], delay = _c === void 0 ? 0 : _c;
var onFrame;
var repeat;
var pauseCallback;
var resumeCallback;
var animateCfg;
// 第二个参数,既可以是动画最终状态 toAttrs也可以是自定义帧动画函数 onFrame
if (util_1.isFunction(toAttrs)) {
onFrame = toAttrs;
toAttrs = {};
}
else if (util_1.isObject(toAttrs) && toAttrs.onFrame) {
// 兼容 3.0 中的写法onFrame 和 repeat 可在 toAttrs 中设置
onFrame = toAttrs.onFrame;
repeat = toAttrs.repeat;
}
// 第二个参数,既可以是执行时间 duration也可以是动画参数 animateCfg
if (util_1.isObject(duration)) {
animateCfg = duration;
duration = animateCfg.duration;
easing = animateCfg.easing || 'easeLinear';
delay = animateCfg.delay || 0;
// animateCfg 中的设置优先级更高
repeat = animateCfg.repeat || repeat || false;
callback = animateCfg.callback || util_1.noop;
pauseCallback = animateCfg.pauseCallback || util_1.noop;
resumeCallback = animateCfg.resumeCallback || util_1.noop;
}
else {
// 第四个参数,既可以是回调函数 callback也可以是延迟时间 delay
if (util_1.isNumber(callback)) {
delay = callback;
callback = null;
}
// 第三个参数,既可以是缓动参数 easing也可以是回调函数 callback
if (util_1.isFunction(easing)) {
callback = easing;
easing = 'easeLinear';
}
else {
easing = easing || 'easeLinear';
}
}
var formatToAttrs = getFormatToAttrs(toAttrs, this);
var animation = {
fromAttrs: getFormatFromAttrs(formatToAttrs, this),
toAttrs: formatToAttrs,
duration: duration,
easing: easing,
repeat: repeat,
callback: callback,
pauseCallback: pauseCallback,
resumeCallback: resumeCallback,
delay: delay,
startTime: timeline.getTime(),
id: util_1.uniqueId(),
onFrame: onFrame,
pathFormatted: false,
};
// 如果动画元素队列中已经有这个图形了
if (animations.length > 0) {
// 先检查是否需要合并属性。若有相同的动画,将该属性从前一个动画中删除,直接用后一个动画中
animations = checkExistedAttrs(animations, animation);
}
else {
// 否则将图形添加到动画元素队列
timeline.addAnimator(this);
}
animations.push(animation);
this.set('animations', animations);
this.set('_pause', { isPaused: false });
};
/**
* 停止动画
* @param {boolean} toEnd 是否到动画的最终状态
*/
Element.prototype.stopAnimate = function (toEnd) {
var _this = this;
if (toEnd === void 0) { toEnd = true; }
var animations = this.get('animations');
util_1.each(animations, function (animation) {
// 将动画执行到最后一帧
if (toEnd) {
if (animation.onFrame) {
_this.attr(animation.onFrame(1));
}
else {
_this.attr(animation.toAttrs);
}
}
if (animation.callback) {
// 动画停止时的回调
animation.callback();
}
});
this.set('animating', false);
this.set('animations', []);
};
/**
* 暂停动画
*/
Element.prototype.pauseAnimate = function () {
var timeline = this.get('timeline');
var animations = this.get('animations');
var pauseTime = timeline.getTime();
util_1.each(animations, function (animation) {
animation._paused = true;
animation._pauseTime = pauseTime;
if (animation.pauseCallback) {
// 动画暂停时的回调
animation.pauseCallback();
}
});
// 记录下是在什么时候暂停的
this.set('_pause', {
isPaused: true,
pauseTime: pauseTime,
});
return this;
};
/**
* 恢复动画
*/
Element.prototype.resumeAnimate = function () {
var timeline = this.get('timeline');
var current = timeline.getTime();
var animations = this.get('animations');
var pauseTime = this.get('_pause').pauseTime;
// 之后更新属性需要计算动画已经执行的时长,如果暂停了,就把初始时间调后
util_1.each(animations, function (animation) {
animation.startTime = animation.startTime + (current - pauseTime);
animation._paused = false;
animation._pauseTime = null;
if (animation.resumeCallback) {
animation.resumeCallback();
}
});
this.set('_pause', {
isPaused: false,
});
this.set('animations', animations);
return this;
};
/**
* 触发委托事件
* @param {string} type 事件类型
* @param {GraphEvent} eventObj 事件对象
*/
Element.prototype.emitDelegation = function (type, eventObj) {
var _this = this;
var paths = eventObj.propagationPath;
var events = this.getEvents();
var relativeShape;
if (type === 'mouseenter') {
relativeShape = eventObj.fromShape;
}
else if (type === 'mouseleave') {
relativeShape = eventObj.toShape;
}
var _loop_1 = function (i) {
var element = paths[i];
// 暂定跟 name 绑定
var name_1 = element.get('name');
if (name_1) {
// 第一个 mouseenter 和 mouseleave 的停止即可,因为后面的都是前面的 Parent
if (
// 只有 element 是 Group 或者 Canvas 的时候,才需要判断 isParent
(element.isGroup() || (element.isCanvas && element.isCanvas())) &&
relativeShape &&
util_2.isParent(element, relativeShape)) {
return "break";
}
if (util_1.isArray(name_1)) {
util_1.each(name_1, function (subName) {
_this.emitDelegateEvent(element, subName, eventObj);
});
}
else {
this_1.emitDelegateEvent(element, name_1, eventObj);
}
}
};
var this_1 = this;
// 至少有一个对象,且第一个对象为 shape
for (var i = 0; i < paths.length; i++) {
var state_1 = _loop_1(i);
if (state_1 === "break")
break;
}
};
Element.prototype.emitDelegateEvent = function (element, name, eventObj) {
var events = this.getEvents();
// 事件委托的形式 name:type
var eventName = name + DELEGATION_SPLIT + eventObj.type;
if (events[eventName] || events[WILDCARD]) {
// 对于通配符 *,事件名称 = 委托事件名称
eventObj.name = eventName;
eventObj.currentTarget = element;
eventObj.delegateTarget = this;
// 将委托事件的监听对象 delegateObject 挂载到事件对象上
eventObj.delegateObject = element.get('delegateObject');
this.emit(eventName, eventObj);
}
};
/**
* 移动元素
* @param {number} translateX 水平移动距离
* @param {number} translateY 垂直移动距离
* @return {IElement} 元素
*/
Element.prototype.translate = function (translateX, translateY) {
if (translateX === void 0) { translateX = 0; }
if (translateY === void 0) { translateY = 0; }
var matrix = this.getMatrix();
var newMatrix = transform(matrix, [['t', translateX, translateY]]);
this.setMatrix(newMatrix);
return this;
};
/**
* 移动元素到目标位置
* @param {number} targetX 目标位置的水平坐标
* @param {number} targetX 目标位置的垂直坐标
* @return {IElement} 元素
*/
Element.prototype.move = function (targetX, targetY) {
var x = this.attr('x') || 0;
var y = this.attr('y') || 0;
this.translate(targetX - x, targetY - y);
return this;
};
/**
* 移动元素到目标位置,等价于 move 方法。由于 moveTo 的语义性更强,因此在文档中推荐使用 moveTo 方法
* @param {number} targetX 目标位置的 x 轴坐标
* @param {number} targetY 目标位置的 y 轴坐标
* @return {IElement} 元素
*/
Element.prototype.moveTo = function (targetX, targetY) {
return this.move(targetX, targetY);
};
/**
* 缩放元素
* @param {number} ratioX 水平缩放比例
* @param {number} ratioY 垂直缩放比例
* @return {IElement} 元素
*/
Element.prototype.scale = function (ratioX, ratioY) {
var matrix = this.getMatrix();
var newMatrix = transform(matrix, [['s', ratioX, ratioY || ratioX]]);
this.setMatrix(newMatrix);
return this;
};
/**
* 以画布左上角 (0, 0) 为中心旋转元素
* @param {number} radian 旋转角度(弧度值)
* @return {IElement} 元素
*/
Element.prototype.rotate = function (radian) {
var matrix = this.getMatrix();
var newMatrix = transform(matrix, [['r', radian]]);
this.setMatrix(newMatrix);
return this;
};
/**
* 以起始点为中心旋转元素
* @param {number} radian 旋转角度(弧度值)
* @return {IElement} 元素
*/
Element.prototype.rotateAtStart = function (rotate) {
var _a = this.attr(), x = _a.x, y = _a.y;
var matrix = this.getMatrix();
var newMatrix = transform(matrix, [
['t', -x, -y],
['r', rotate],
['t', x, y],
]);
this.setMatrix(newMatrix);
return this;
};
/**
* 以任意点 (x, y) 为中心旋转元素
* @param {number} radian 旋转角度(弧度值)
* @return {IElement} 元素
*/
Element.prototype.rotateAtPoint = function (x, y, rotate) {
var matrix = this.getMatrix();
var newMatrix = transform(matrix, [
['t', -x, -y],
['r', rotate],
['t', x, y],
]);
this.setMatrix(newMatrix);
return this;
};
return Element;
}(base_1.default));
exports.default = Element;
//# sourceMappingURL=element.js.map