编辑、选择与撤销
实体编辑、选择集操作、撤销系统。
实体变换
移动
const { LineEnt, Point2D, Engine } = vjcad;
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();
Engine.addEntities(line);
// 移动实体:从 from 点移动到 to 点
line.move([0, 0], [50, 30]); // 支持 [x, y] 数组形式
// 必须重绘才能看到变化
Engine.regen();
复制
// 使用 clone() 创建独立副本
const original = new LineEnt([0, 0], [100, 0]);
original.setDefaults();
Engine.addEntities(original);
const copy = original.clone();
copy.move([0, 0], [0, 50]); // 移动副本
copy.color = 2; // 修改副本属性
Engine.addEntities(copy); // 添加副本
Engine.regen();
旋转
const { Point2D, Engine } = vjcad;
// rotate(basePoint, angle) - 绕基点旋转(角度为弧度)
const basePoint = new Point2D(50, 50); // PointInput:Point2D 或 [x,y] 数组均可
entity.rotate(basePoint, Math.PI / 4); // 旋转 45°
Engine.regen();
缩放
const { Point2D, Engine } = vjcad;
// scale(basePoint, scaleFactor) - 以基点为中心缩放
const basePoint = new Point2D(0, 0);
entity.scale(basePoint, 0.5); // 缩小到 0.5 倍
entity.scale(basePoint, 2.0); // 放大到 2 倍
Engine.regen();
镜像
const { Point2D, Engine } = vjcad;
// mirror(p1, p2) - 沿 p1-p2 定义的直线镜像
const p1 = new Point2D(100, 0);
const p2 = new Point2D(100, 100);
entity.mirror(p1, p2); // 沿 x=100 垂直线镜像
Engine.regen();
注意:
move()/rotate()/scale()/mirror()的点参数均为PointInput——Point2D对象或[x, y]数组均可- 变换后必须调用
Engine.regen()才能看到变化
删除实体
const { Engine } = vjcad;
// 删除单个实体
Engine.eraseEntities(entity);
// 删除多个实体
Engine.eraseEntities([entity1, entity2, entity3]);
// 删除后 entity.isAlive 变为 false
console.log(entity.isAlive); // false
绘图顺序
const { Engine } = vjcad;
// 方式1:使用命令
await Engine.editor.executerWithOp('ENTDRAWFRONT'); // 选中图形置于最前
await Engine.editor.executerWithOp('ENTDRAWBACK'); // 选中图形置于最后
await Engine.editor.executerWithOp('LAYDRAWFRONT'); // 选中图形的图层置于最前
await Engine.editor.executerWithOp('LAYDRAWBACK'); // 选中图形的图层置于最后
// 方式2:直接操作 items 数组
const items = Engine.currentSpace.items;
const idx = items.indexOf(entity);
if (idx > -1) {
items.splice(idx, 1); // 移除
items.push(entity); // 添加到末尾(最前面)
Engine.pcanvas.regen(true);
}
分组
const { GroupEnt, LineEnt, CircleEnt, Engine } = vjcad;
// 创建实体
const line = new LineEnt([0, 0], [100, 0]);
const circle = new CircleEnt([50, 50], 20);
line.setDefaults();
circle.setDefaults();
// 创建组
const group = new GroupEnt("MyGroup", [line, circle]);
group.setDefaults();
Engine.addEntities(group);
// 访问组内实体(items 是数组属性,另有 count 属性可取数量)
group.items.forEach((item, index) => {
console.log(`${index}: ${item.type}, 颜色: ${item.color}`);
});
// 炸开组
const explodedEntities = group.explode();
explodedEntities.forEach(ent => {
Engine.addEntities(ent);
});
Engine.eraseEntities(group);
Engine.regen(true);
// 使用命令
await Engine.editor.executerWithOp('GROUP'); // 创建组
await Engine.editor.executerWithOp('UNGROUP'); // 取消组
高亮
const { Engine } = vjcad;
// 高亮指定实体
Engine.highLightEntities([entity1, entity2]);
// 清除高亮
Engine.clearHighLight();
// 高亮是临时视觉效果,不影响实体属性
选择集操作
设置选择集
const { Engine } = vjcad;
// 选择单个实体
Engine.ssSetFirst([entity]);
// 选择多个实体
Engine.ssSetFirst([entity1, entity2, entity3]);
// 清空选择集
Engine.ssSetFirst([]);
// 选择所有实体(getEntities 含已删除实体,须过滤 isAlive)
const allEntities = Engine.getEntities(ent => ent.isAlive);
Engine.ssSetFirst(allEntities);
获取选择集
const { Engine } = vjcad;
// 获取当前选择集
const selected = Engine.ssGetFirst();
console.log(`选中 ${selected.length} 个实体`);
// 遍历选择集
selected.forEach((entity, index) => {
console.log(`${index + 1}. 类型: ${entity.type}, 颜色: ${entity.color}`);
});
// 对选择集进行操作
selected.forEach(entity => {
entity.color = 1;
});
Engine.regen();
获取实体
获取所有实体
const { Engine } = vjcad;
// getEntities() 返回 currentSpace.items 原样——含已删除实体(isAlive=false)
const allEntities = Engine.getEntities(ent => ent.isAlive); // 或 Engine.currentSpace.aliveItems
注意:下面的 getEntitiesByType / 条件过滤同样含已删除实体,实际使用时条件里带上 ent.isAlive(或对结果 .filter(e => e.isAlive))。
按类型获取
const { Engine } = vjcad;
const lines = Engine.getEntitiesByType('LINE');
const circles = Engine.getEntitiesByType('CIRCLE');
const arcs = Engine.getEntitiesByType('ARC');
const plines = Engine.getEntitiesByType('PLINE');
const texts = Engine.getEntitiesByType('TEXT');
const mtexts = Engine.getEntitiesByType('MTEXT');
const inserts = Engine.getEntitiesByType('INSERT');
const hatches = Engine.getEntitiesByType('HATCH');
按条件过滤
const { Engine } = vjcad;
// 按颜色过滤
const redEntities = Engine.getEntities(ent => ent.color === 1);
// 按图层过滤
const layerAEntities = Engine.getEntities(ent => ent.layer === "图层A");
// 组合条件
const redLines = Engine.getEntities(ent =>
ent.type === "LINE" && ent.color === 1
);
// 自定义复杂条件
const largeCircles = Engine.getEntities(ent =>
ent.type === "CIRCLE" && ent.radius > 50
);
// 排除某些实体
const notHidden = Engine.getEntities(ent =>
ent.layer !== "隐藏图层"
);
撤销系统
基本撤销/重做
const { Engine } = vjcad;
const undoMgr = Engine.undoManager;
// 检查是否可撤销/重做
if (undoMgr.canUndo()) {
undoMgr.undo();
}
if (undoMgr.canRedo()) {
undoMgr.redo();
}
撤销标记
const { Engine, Point2D } = vjcad;
const undoMgr = Engine.undoManager;
// 添加/删除实体的撤销标记——仅在用底层 Engine.pcanvas.addEntity / currentSpace.erase 时手动补;
// Engine.addEntities / eraseEntities 已自动记录;重复 added_undoMark 会在撤销时多删一个无关实体
undoMgr.added_undoMark([entity1, entity2]);
undoMgr.erased_undoMark([entity1, entity2]);
// 移动操作的撤销标记
const fromPt = new Point2D(0, 0);
const toPt = new Point2D(40, 0);
entity.move(fromPt, toPt);
undoMgr.moved_undoMark([entity], fromPt, toPt);
// 旋转操作的撤销标记
undoMgr.rotate_undoMark(entities, basePoint, angle);
// 缩放操作的撤销标记
undoMgr.scaled_undoMark(entities, basePoint, scale);
注意:Engine.addEntities() 和 Engine.eraseEntities() 会自动记录撤销。
撤销分组
将多个操作合并为一次撤销。
const { Engine, LineEnt, CircleEnt, Point2D } = vjcad;
const undoMgr = Engine.undoManager;
// 开始撤销组
undoMgr.start_undoMark();
try {
// 执行多个操作
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();
Engine.addEntities(line);
const circle = new CircleEnt([50, 50], 30);
circle.setDefaults();
Engine.addEntities(circle);
// 移动操作
line.move([0, 0], [50, 0]);
undoMgr.moved_undoMark([line], new Point2D(0, 0), new Point2D(50, 0));
} finally {
// 结束撤销组(必须确保调用)
undoMgr.end_undoMark();
}
// 撤销时会一次性撤销整个组内的所有操作
视图操作
缩放
const { Engine } = vjcad;
// 缩放到全图
Engine.zoomExtents();
// 缩放到指定实体
Engine.zoomToEntities([entity1, entity2]);
// 带边距的缩放
Engine.zoomToEntities(entities, {
padding: { top: 50, bottom: 50, left: 50, right: 50 }
});
刷新显示
const { Engine } = vjcad;
// render() - 最底层渲染,只执行 GPU 绘制
Engine.render();
// redraw() - 更新视图变换后渲染
Engine.redraw();
// regen() - 局部更新,只重绘已修改的实体(快)
Engine.regen();
// regen(true) - 完全重绘所有图形(慢)
Engine.regen(true);
预览
const { Engine } = vjcad;
// 绘制预览实体
Engine.drawPreviewEntity(entity);
Engine.drawPreviewEntities([entity1, entity2]);
// 清除预览
Engine.clearPreview();
设置视图中心
const { Engine, Point2D } = vjcad;
// 设置视图中心点
Engine.setCenter(new Point2D(100, 100));
// 带边距的设置
Engine.setCenter(new Point2D(100, 100), true, {
top: 50, bottom: 50, left: 50, right: 50
});
背景色
const { Engine } = vjcad;
// 设置背景灰度值 0-255:0 与 255 是特例,其余值为 rgb(v,v,v)
Engine.setBgc(0); // 默认深色背景 #212830(不是纯黑)
Engine.setBgc(33); // rgb(33,33,33) 深灰(不是默认深色背景)
Engine.setBgc(1); // 近似纯黑 rgb(1,1,1)
Engine.setBgc(255); // 纯白 #FFFFFF
Engine.redraw();
主题
const { Engine } = vjcad;
// 切换主题(THEME_MODE 的 setter 已自动调用 setBgc(0/255),无需再手动 setBgc;
// 若再 setBgc(33) 反而会把默认深色背景 #212830 覆盖成灰色)
Engine.THEME_MODE = 0; // 深色主题
Engine.redraw();
Engine.THEME_MODE = 1; // 浅色主题
Engine.redraw();
// 检查当前主题
const isDark = Engine.isDarkTheme();
屏幕范围
const { Engine } = vjcad;
// 获取屏幕边界(世界坐标系)
const bounds = Engine.getScreenBoundsWcs();
// 返回: BoundingBox 类实例——{ pt1, pt2, minX, minY, maxX, maxY, width, height, center, ... }
// 获取屏幕内的实体
const screenEntities = Engine.getScreenEntities();
const expandedEntities = Engine.getScreenEntities(1.5); // 扩展 1.5 倍范围
缩放因子
const { Engine } = vjcad;
// 获取当前缩放比例
const zoom = Engine.currentSpace.zoom;
// 设置滚轮缩放因子(百分比,默认 75):每格滚轮 zoom 除/乘以 ZOOMFACTOR/100
// 值越小每格缩放越大(越快);100 = 滚轮不缩放;ZOOMFACTOR 命令只接受 ≥60
Engine.ZOOMFACTOR = 60; // 缩放更快(每格约 1.67 倍)
Engine.ZOOMFACTOR = 90; // 缩放更慢(每格约 1.11 倍)