Files
lan-manager/web/node_modules/@antv/g-canvas/lib/canvas.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

247 lines
9.9 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 g_base_1 = require("@antv/g-base");
var hit_1 = require("./util/hit");
var Shape = require("./shape");
var group_1 = require("./group");
var util_1 = require("./util/util");
var draw_1 = require("./util/draw");
var Canvas = /** @class */ (function (_super) {
tslib_1.__extends(Canvas, _super);
function Canvas() {
return _super !== null && _super.apply(this, arguments) || this;
}
Canvas.prototype.getDefaultCfg = function () {
var cfg = _super.prototype.getDefaultCfg.call(this);
// 设置渲染引擎为 canvas只读属性
cfg['renderer'] = 'canvas';
// 是否自动绘制,不需要用户调用 draw 方法
cfg['autoDraw'] = true;
// 是否允许局部刷新图表
cfg['localRefresh'] = true;
cfg['refreshElements'] = [];
// 是否在视图内自动裁剪
cfg['clipView'] = true;
// 是否使用快速拾取的方案,默认为 false上层可以打开
cfg['quickHit'] = false;
return cfg;
};
/**
* 一些方法调用会引起画布变化
* @param {ChangeType} changeType 改变的类型
*/
Canvas.prototype.onCanvasChange = function (changeType) {
/**
* 触发画布更新的三种 changeType
* 1. attr: 修改画布的绘图属性
* 2. sort: 画布排序,图形的层次会发生变化
* 3. changeSize: 改变画布大小
*/
if (changeType === 'attr' || changeType === 'sort' || changeType === 'changeSize') {
this.set('refreshElements', [this]);
this.draw();
}
};
Canvas.prototype.getShapeBase = function () {
return Shape;
};
Canvas.prototype.getGroupBase = function () {
return group_1.default;
};
/**
* 获取屏幕像素比
*/
Canvas.prototype.getPixelRatio = function () {
var pixelRatio = this.get('pixelRatio') || util_1.getPixelRatio();
// 不足 1 的取 1超出 1 的取整
return pixelRatio >= 1 ? Math.ceil(pixelRatio) : 1;
};
Canvas.prototype.getViewRange = function () {
return {
minX: 0,
minY: 0,
maxX: this.cfg.width,
maxY: this.cfg.height,
};
};
// 复写基类的方法生成标签
Canvas.prototype.createDom = function () {
var element = document.createElement('canvas');
var context = element.getContext('2d');
// 缓存 context 对象
this.set('context', context);
return element;
};
Canvas.prototype.setDOMSize = function (width, height) {
_super.prototype.setDOMSize.call(this, width, height);
var context = this.get('context');
var el = this.get('el');
var pixelRatio = this.getPixelRatio();
el.width = pixelRatio * width;
el.height = pixelRatio * height;
// 设置 canvas 元素的宽度和高度,会重置缩放,因此 context.scale 需要在每次设置宽、高后调用
if (pixelRatio > 1) {
context.scale(pixelRatio, pixelRatio);
}
};
// 复写基类方法
Canvas.prototype.clear = function () {
_super.prototype.clear.call(this);
this._clearFrame(); // 需要清理掉延迟绘制的帧
var context = this.get('context');
var element = this.get('el');
context.clearRect(0, 0, element.width, element.height);
};
Canvas.prototype.getShape = function (x, y) {
var shape;
if (this.get('quickHit')) {
shape = hit_1.getShape(this, x, y);
}
else {
shape = _super.prototype.getShape.call(this, x, y, null);
}
return shape;
};
// 对绘制区域边缘取整,避免浮点数问题
Canvas.prototype._getRefreshRegion = function () {
var elements = this.get('refreshElements');
var viewRegion = this.getViewRange();
var region;
// 如果是当前画布整体发生了变化,则直接重绘整个画布
if (elements.length && elements[0] === this) {
region = viewRegion;
}
else {
region = draw_1.getMergedRegion(elements);
if (region) {
region.minX = Math.floor(region.minX);
region.minY = Math.floor(region.minY);
region.maxX = Math.ceil(region.maxX);
region.maxY = Math.ceil(region.maxY);
region.maxY += 1; // 在很多环境下字体的高低会不一致,附加一像素,避免残影
var clipView = this.get('clipView');
// 自动裁剪不在 view 内的区域
if (clipView) {
region = draw_1.mergeView(region, viewRegion);
}
}
}
return region;
};
/**
* 刷新图形元素,这里仅仅是放入队列,下次绘制时进行绘制
* @param {IElement} element 图形元素
*/
Canvas.prototype.refreshElement = function (element) {
var refreshElements = this.get('refreshElements');
refreshElements.push(element);
// if (this.get('autoDraw')) {
// this._startDraw();
// }
};
// 清理还在进行的绘制
Canvas.prototype._clearFrame = function () {
var drawFrame = this.get('drawFrame');
if (drawFrame) {
// 如果全部渲染时,存在局部渲染,则抛弃掉局部渲染
util_1.clearAnimationFrame(drawFrame);
this.set('drawFrame', null);
this.set('refreshElements', []);
}
};
// 手工调用绘制接口
Canvas.prototype.draw = function () {
var drawFrame = this.get('drawFrame');
if (this.get('autoDraw') && drawFrame) {
return;
}
this._startDraw();
};
// 绘制所有图形
Canvas.prototype._drawAll = function () {
var context = this.get('context');
var element = this.get('el');
var children = this.getChildren();
context.clearRect(0, 0, element.width, element.height);
draw_1.applyAttrsToContext(context, this);
draw_1.drawChildren(context, children);
// 对于 https://github.com/antvis/g/issues/422 的场景,全局渲染的模式下也会记录更新的元素队列,因此全局渲染完后也需要置空
this.set('refreshElements', []);
};
// 绘制局部
Canvas.prototype._drawRegion = function () {
var context = this.get('context');
var refreshElements = this.get('refreshElements');
var children = this.getChildren();
var region = this._getRefreshRegion();
// 需要注意可能没有 region 的场景
// 一般发生在设置了 localRefresh ,在没有图形发生变化的情况下,用户调用了 draw
if (region) {
// 清理指定区域
context.clearRect(region.minX, region.minY, region.maxX - region.minX, region.maxY - region.minY);
// 保存上下文,设置 clip
context.save();
context.beginPath();
context.rect(region.minX, region.minY, region.maxX - region.minX, region.maxY - region.minY);
context.clip();
draw_1.applyAttrsToContext(context, this);
// 确认更新的元素,这个优化可以提升 10 倍左右的性能10W 个带有 group 的节点,局部渲染会从 90ms 下降到 5-6 ms
draw_1.checkRefresh(this, children, region);
// 绘制子元素
draw_1.drawChildren(context, children, region);
context.restore();
}
else if (refreshElements.length) {
// 防止发生改变的 elements 没有 region 的场景,这会发生在多个情况下
// 1. 空的 group
// 2. 所有 elements 没有在绘图区域
// 3. group 下面的 elements 隐藏掉
// 如果不进行清理 hasChanged 的状态会不正确
draw_1.clearChanged(refreshElements);
}
util_1.each(refreshElements, function (element) {
if (element.get('hasChanged')) {
// 在视窗外的 Group 元素会加入到更新队列里,但实际却没有执行 draw() 逻辑,也就没有清除 hasChanged 标记
// 即已经重绘完、但 hasChanged 标记没有清除的元素,需要统一清除掉。主要是 Group 存在问题,具体原因待排查
element.set('hasChanged', false);
}
});
this.set('refreshElements', []);
};
// 触发绘制
Canvas.prototype._startDraw = function () {
var _this = this;
var drawFrame = this.get('drawFrame');
var drawFrameCallback = this.get('drawFrameCallback');
if (!drawFrame) {
drawFrame = util_1.requestAnimationFrame(function () {
if (_this.get('localRefresh')) {
_this._drawRegion();
}
else {
_this._drawAll();
}
_this.set('drawFrame', null);
if (drawFrameCallback) {
drawFrameCallback();
}
});
this.set('drawFrame', drawFrame);
}
};
Canvas.prototype.skipDraw = function () { };
Canvas.prototype.removeDom = function () {
var el = this.get('el');
// 需要清理 canvas 画布内容否则ios下 创建的canvas垃圾未回收导致Total canvas memory use exceeds问题
// 相关问题列表
// https://stackoverflow.com/questions/52532614/total-canvas-memory-use-exceeds-the-maximum-limit-safari-12
// https://github.com/openlayers/openlayers/issues/9291
el.width = 0;
el.height = 0;
el.parentNode.removeChild(el);
};
return Canvas;
}(g_base_1.AbstractCanvas));
exports.default = Canvas;
//# sourceMappingURL=canvas.js.map