预览视图(PreviewView)
文档:
vjcad/doc/ui/preview-view.md示例:vjcad/example/ui/03previewview.js— 基础 PreviewView
1. 用途
PreviewView 是一个独立 Web Component,用来在 不影响主视图 的前提下显示 CAD 实体或文档。常见场景:
- 块 / 符号库小图预览
- 对话框里"预览效果"
- 缩略图 / 截图
- Hover 提示框中显示局部内容
它是只读 / 极简的:没有命令系统,没有侧边栏,只支持基本缩放和平移。
2. 模式 1:addEntity
const { PreviewView, LineEnt, CircleEnt, TextEnt } = vjcad;
const preview = new PreviewView({
backgroundColor: 0x1a242e, // 深色背景
interactive: true, // 允许鼠标缩放 / 平移
defaultColor: 0x00ff00 // 默认绘制颜色(绿色)
});
document.getElementById('preview-container').appendChild(preview);
await preview.onLoad(); // 等待初始化
const line = new LineEnt([0, 0], [100, 50]); line.setDefaults();
preview.addEntity(line); // 用默认颜色
const circle = new CircleEnt([50, 50], 30); circle.setDefaults();
preview.addEntity(circle, 0xff0000); // 第二参数覆盖颜色
preview.zoomExtents(); // 缩放到所有内容(方法名是 zoomExtents,不是 zoomToFit)
特点:
- 实体只是绘制进预览,不会真的写入文档;
addEntity不触发回调 / 事件 - 第二个
color参数是 RGB 数值(0xRRGGBB),不是 ACI 颜色索引 - ⚠️
addEntity用的是不依赖 Engine 的简化绘制器,只画LINE / CIRCLE / ARC / ELLIPSE,SPLINE画成控制点折线;分支里判断的是'POLYLINE',而PolylineEnt.type实际是'PLINE',所以多段线也画不出;文字、填充、块、标注等一律忽略。要预览这些用loadDocument(DbDoc 数据)或renderEntitiesDirect(entities)(用当前文档上下文的完整渲染器,实体须来自当前文档)
3. 模式 2:loadDocument(含图层 / 块 / 完整数据)
import { Engine } from 'vjcad';
// loadDocument 接收 DbDoc 结构:可来自 Engine.currentDoc.toDb(),或手工拼装 DbDoc 字面量
const fullDoc = Engine.currentDoc.toDb();
// PreviewViewConfig 仅 5 键:backgroundColor/backgroundAlpha/interactive/defaultColor/resolution
// (showAxis、showUcsIcon 属于 MainViewConfig,PreviewView 不支持)
const preview = new PreviewView({
backgroundColor: 0x1a242e,
interactive: true
});
container.appendChild(preview);
await preview.onLoad();
await preview.loadDocument(fullDoc); // 真正还原图层 / 颜色 / 字体
preview.zoomExtents();
loadDocument 与 addEntity 区别:
| 特性 | addEntity |
loadDocument |
|---|---|---|
| 数据形态 | 单个实体对象(仅线 / 圆 / 弧 / 椭圆 / 样条近似) | 完整 vjcad 文档(含图层 / 字体 / 块,各类实体) |
| 颜色 | 必须自己传或用默认 | 还原原图所有属性 |
| 字体 / 中文 | 默认字体 | 文档自带字体 |
| 用途 | 临时预览几条线 | 真实图纸缩略 / 别处加载的图 |
4. PreviewView 选项
// 真实签名:PreviewViewConfig——只有这 5 个键
interface PreviewViewConfig {
backgroundColor?: number; // 背景色,默认 0x1a242e
backgroundAlpha?: number; // 背景透明度 0-1,默认 1(设 0 可导出透明 PNG)
interactive?: boolean; // 是否允许鼠标交互(缩放 / 平移),默认 true
defaultColor?: number; // 实体默认绘制颜色,默认白色 0xffffff
resolution?: number; // canvas 像素比,默认 window.devicePixelRatio(离屏导出设 1)
}
⚠️ 上游文档把
showAxis/showUcsIcon/showFps/fontPath/fontName/fontKind列进 PreviewView 选项——这些键在PreviewViewConfig里不存在,传了会被忽略(showUcsIcon等是MainViewConfig的键,不是 PreviewView 的)。
5. 常用方法
class PreviewView extends LitElement {
onLoad(): Promise<void>;
addEntity(ent: EntityBase, color?: number): void;
addEntities(ents: EntityBase[], color?: number): void;
clear(): void; // 清空所有实体
loadDocument(dbDocument: any, blockName?: string): Promise<void>;
zoomExtents(): void;
setView(center: Point2D, zoom: number): void; // 定点缩放
get zoom(): number; // 当前缩放 —— getter,写 preview.zoom,不要加 ()
get viewCenter(): Point2D; // getter(返回副本)
get document(): CadDocument | null; // getter:loadDocument 后的预览文档
renderEntitiesDirect(entities: EntityBase[], backgroundGray?: number): void;
toThumbnail(width?: number, height?: number, format?: 'png' | 'jpeg'): string; // dataURL
getEntityBounds(): BoundingBox | null;
forceResize(): void;
}
⚠️
zoomToFit/zoomScale/pan/setBackground/captureScreenshot/destroy都不是PreviewView的方法:缩放用zoomExtents/setView,截图用toThumbnail(同步返回 dataURL), 销毁用preview.remove()(disconnectedCallback负责清理)。
6. 在对话框里嵌入
class MySymbolPreviewDialog extends ModalDialogBase {
static dialogTitle = '符号预览';
async firstUpdated() {
await super.firstUpdated(); // ★ 必须:基类在这里取 base-dialog,漏掉则 startDialog 立即返回、对话框一闪而过
const host = this.shadowRoot.querySelector('#preview-host');
this._preview = new PreviewView({ backgroundColor: 0x222, interactive: true });
host.appendChild(this._preview);
await this._preview.onLoad();
await this._preview.loadDocument(this.symbolDoc);
this._preview.zoomExtents();
}
renderContent() {
return html`<div id="preview-host" style="width: 400px; height: 300px;"></div>`;
}
cancel() {
this._preview?.remove(); // PreviewView 无 destroy();移除即触发 disconnectedCallback 清理
super.cancel();
}
}
customElements.define('my-symbol-preview-dialog', MySymbolPreviewDialog); // 不注册 new 时抛 Illegal constructor
const dlg = new MySymbolPreviewDialog();
dlg.symbolDoc = someDbDoc;
await dlg.startDialog();
7. 中文字体
// PreviewViewConfig 没有字体字段——字体是全局的,经 wasm 服务加载:
const { getWebCadCoreService, Engine, PreviewView } = vjcad;
await getWebCadCoreService().loadFont('/fonts/simsun.ttf', '宋体', 'ttf');
// 或批量:loadFonts([{ path: '/fonts/simsun.ttf', name: '宋体', kind: 'ttf' }])
const preview = new PreviewView({ backgroundColor: 0x1a242e });
container.appendChild(preview);
await preview.onLoad();
// ⚠️ addEntity 不画文字(简化绘制器只认线/圆/弧/椭圆)。文字要走 loadDocument:
const doc = Engine.currentDoc.toDb(); // 或只含文字实体的 DbDoc
await preview.loadDocument(doc);
preview.zoomExtents();
// 或:已在当前文档里的 TextEnt 实例 → preview.renderEntitiesDirect([textEnt]);
不传字体时中文会显示为方框,只有 ASCII 字符正常。
loadFont返回Promise<FontInfo | null>;fontKind可选'ttf' | 'woff' | 'otf' | 'shx'。
红旗
- 必须
await preview.onLoad()再addEntity/loadDocument:未初始化时它们直接throw Error('Graphics not initialized')(不是静默丢绘制) - 销毁页面 / 切换路由前要把元素
preview.remove()(触发disconnectedCallback清理),否则有 WebGL context 泄漏 loadDocument接收 DbDoc 结构(currentDoc.toDb()或手工拼装),**不能把Engine.currentDoc直接传进去(结构不同;可取currentDoc.toDb()的 DbDoc 结构)- 一个页面里 PreviewView 不要超过 ~5 个,每个都吃一个 WebGL 上下文
参考(官方文档 MCP)
- 文档:
vjcad/doc/ui/preview-view.md - 示例:
vjcad/example/ui/03previewview.js— 基础 PreviewView