唯杰地图 logo唯杰地图
VJMAP
EN

preview

vjcad/references/command/preview.md 4.6 KB119 行
原文

本文回答:拖动 / 取点过程中的"实时预览图"用 Engine.drawPreviewEntity(ent) / Engine.drawPreviewEntities([e1, e2]) + Engine.clearPreview() 控制;通常配合 PointInputOptions.callback(鼠标移动时被调用,参数是画布坐标 → Engine.canvasToWcs(canvasPt) 转世界坐标)。命令结束 / 异常时一定要 Engine.clearPreview()。

一、最小预览(圆心 + 拖半径)

class CirclePreviewCommand {
  constructor() { this.center = null; }

  async main() {
    Engine.undoManager.start_undoMark('绘制圆');
    try {
      if (!await this.getCenter()) return;
      const r = await this.getRadius();
      if (r == null) return;
      const c = new CircleEnt([this.center.x, this.center.y], r);
      c.setDefaults();
      Engine.addEntities(c);
    } finally {
      Engine.undoManager.end_undoMark();
      Engine.clearPreview();
    }
  }

  async getCenter() {
    const opt = new PointInputOptions('指定圆心:');
    const r = await Engine.getPoint(opt);
    if (r.status !== InputStatusEnum.OK) return false;
    this.center = r.value;
    return true;
  }

  async getRadius() {
    const opt = new PointInputOptions('指定半径:');
    opt.useBasePoint = true;
    opt.basePoint = this.center;

    opt.callback = (canvasPt) => {
      const wp = Engine.canvasToWcs(canvasPt);
      const r = Math.hypot(wp.x - this.center.x, wp.y - this.center.y);
      if (r > 0) {
        const preview = new CircleEnt([this.center.x, this.center.y], r);
        preview.setDefaults();
        Engine.clearPreview();
        Engine.drawPreviewEntity(preview);
      }
    };

    const r = await Engine.getPoint(opt);
    if (r.status !== InputStatusEnum.OK) return null;
    return Math.hypot(r.value.x - this.center.x, r.value.y - this.center.y);
  }
}

MCP 参考:vjcad/example/command/03withpreview.js。

二、隐藏默认橡皮筋线 + 自定义预览

const opt = new PointInputOptions('指定终点:');
opt.useBasePoint   = true;
opt.basePoint      = startPoint;
opt.hideRubberBand = true;   // 关掉默认橡皮筋

opt.callback = (canvasPt) => {
  const wp = Engine.canvasToWcs(canvasPt);
  const previewLine   = new LineEnt([startPoint.x, startPoint.y], [wp.x, wp.y]);
  const endpointMark  = new CircleEnt([wp.x, wp.y], 3);
  previewLine.setDefaults();  endpointMark.setDefaults();
  Engine.clearPreview();
  Engine.drawPreviewEntities([previewLine, endpointMark]);
};

MCP 参考:vjcad/example/input/02getpointwithbase.js。

三、底层等价 API(pcanvas.drawControl)

const dc = Engine.pcanvas.drawControl;
dc.drawPreviewEntity(ent);
dc.drawPreviewEntities([e1, e2]);
dc.drawHighLightEntity(ent);
dc.previewGraphics.clear();

dc.setPreviewPosition(point);
dc.setPreviewRotation(angle);
dc.setPreviewScale(sx, sy);
dc.resetPreview();

MCP 参考:vjcad/doc/command/api-reference.md。

便捷封装(推荐):

便捷 API 等价
Engine.drawPreviewEntity(ent) Engine.pcanvas.drawControl.drawPreviewEntity(ent)
Engine.drawPreviewEntities([e1, e2]) Engine.pcanvas.drawControl.drawPreviewEntities([...])
Engine.clearPreview() Engine.pcanvas.drawControl.clearPreview()(先移除 MText 等子容器再 previewGraphics.clear();只调 previewGraphics.clear() 清不掉 MText 预览)

来源:示例 vjcad/example/command/03withpreview.js、vjcad/example/input/02getpointwithbase.js 中实际用 Engine.drawPreviewEntity / Engine.clearPreview。

四、注意

  1. callback 拿到的是画布坐标,必须 Engine.canvasToWcs(canvasPt) 转世界坐标后再算长度 / 角度。
  2. 每次 callback 触发都要先 Engine.clearPreview(),否则预览图会重叠。
  3. 注册命令的 main() 返回(或抛异常)后,框架会自动 drawControl.resetPreview(),finally 里再 Engine.clearPreview() 属防御写法;脚本里直接调 getPoint 画预览(不经命令框架)时才必须自己清。Esc 让输入返回 status === InputStatusEnum.Cancel,不会抛异常——finally 主要用于保证 end_undoMark() 执行。

反例

  • 直接把 canvasPt.x / canvasPt.y 当作图纸坐标:会跟随屏幕不跟随图纸缩放。
  • callback 里不 clear 直接 drawPreviewEntity:预览图随鼠标增长而堆叠。

参考(官方文档 MCP)

  • 文档:vjcad/doc/command/index.md、vjcad/doc/command/api-reference.md
  • 示例:vjcad/example/command/03withpreview.js、vjcad/example/input/02getpointwithbase.js、vjcad/example/input/06getkeyword.js