基础控件用于在自定义对话框或面板中构建用户界面。
专门用于 CAD 数值输入的组件,支持精度控制、多选状态显示、输入验证等功能。
<input-number></input-number>
import { NumberInputComponent } from 'vjcad';
// 创建数字输入组件
const input = document.createElement('input-number') as NumberInputComponent;
// 设置初始值
input.setValue(100.5);
// 设置精度(小数位数)
input.luprec = 4;
// 监听值变化
input.addEventListener('change', (e: CustomEvent) => {
console.log('新值:', e.detail.value);
});
// 添加到 DOM
container.appendChild(input);
| 属性 | 类型 | 默认值 | 说明 |
|---|
value | number | 0 | 当前数值 |
luprec | number | 6 | 小数位精度 |
disabled | boolean | false | 是否禁用 |
allowZero | boolean | false | 是否允许零值 |
allowMinus | boolean | false | 是否允许负值 |
theme | string | "dark" | 主题 ("dark" 或 "light") |
| 方法 | 说明 |
|---|
setValue(value: number) | 设置数值并格式化显示 |
updateValue(value: number) | 更新数值并刷新界面 |
setNumbers(values: number[]) | 设置多个数值(多选状态时显示"多个") |
setDisabled(disabled: boolean) | 设置禁用状态 |
invokeChanged() | 手动触发值变化处理 |
| 事件 | 说明 |
|---|
change | 值变化时触发,event.detail.value 包含新值 |
组件会根据输入状态自动添加 CSS 类:
| CSS 类 | 说明 |
|---|
valid | 输入值有效且已修改 |
invalid | 输入值无效(如负数但不允许负值) |
error | 输入错误 |
import { LitElement, html, css } from 'vjcad';
import { NumberInputComponent } from 'vjcad';
class PropertyPanel extends LitElement {
render() {
return html`
<div class="property-row">
<label>X 坐标:</label>
<input-number
.value=${this.x}
.luprec=${4}
.allowMinus=${true}
@change=${this.onXChange}
></input-number>
</div>
<div class="property-row">
<label>Y 坐标:</label>
<input-number
.value=${this.y}
.luprec=${4}
.allowMinus=${true}
@change=${this.onYChange}
></input-number>
</div>
<div class="property-row">
<label>半径:</label>
<input-number
.value=${this.radius}
.luprec=${4}
.allowZero=${false}
.allowMinus=${false}
@change=${this.onRadiusChange}
></input-number>
</div>
`;
}
}
工具栏按钮组件,支持图标、主题和状态切换。
<tool-bar-button></tool-bar-button>
// 使用 HTML
const button = document.createElement('tool-bar-button');
button.setAttribute('title', '绘制直线');
button.setAttribute('execute', 'LINE');
button.setAttribute('src', '/images/commands/line.svg');
// 监听点击
button.addEventListener('execute', (e: CustomEvent) => {
console.log('执行命令:', e.detail.excuteStr);
});
| 属性 | 类型 | 说明 |
|---|
src | string | 图标路径(如 /images/commands/line.svg) |
svgContent | string | 内联 SVG 内容(优先级高于 src) |
title | string | 按钮提示文本 |
execute | string | 关联的命令名称 |
theme | string | 主题 ("dark" 或 "light") |
isOn | boolean | 是否处于激活状态 |
preSelectMode | string | 预选择模式 ("true" 或 "false") |
| 事件 | 说明 |
|---|
execute | 点击时触发,event.detail.excuteStr 包含命令名称 |
<div class="toolbar">
<tool-bar-button
title="直线"
execute="LINE"
src="/images/commands/line.svg"
theme="dark"
></tool-bar-button>
<tool-bar-button
title="圆"
execute="CIRCLE"
src="/images/commands/circle.svg"
theme="dark"
></tool-bar-button>
<tool-bar-button
title="矩形"
execute="RECTANGLE"
src="/images/commands/rectangle.svg"
theme="dark"
></tool-bar-button>
</div>
用于显示线型的可视化预览,支持简单线型和复杂线型(包含文字和形状)。
<linetype-preview></linetype-preview>
const preview = document.createElement('linetype-preview');
preview.linetypeName = 'Hidden';
preview.width = 200;
preview.height = 20;
preview.scale = 1.0;
container.appendChild(preview);
| 属性 | 类型 | 默认值 | 说明 |
|---|
linetypeName | string | "Continuous" | 线型名称 |
width | number | 200 | 预览宽度(像素) |
height | number | 20 | 预览高度(像素) |
scale | number | 1.0 | 显示比例 |
| 线型名称 | 效果 |
|---|
Continuous | 实线 |
Hidden | 虚线(短划线) |
Center | 中心线(长划-短划) |
Phantom | 双点划线 |
import { LitElement, html } from 'vjcad';
class LinetypeList extends LitElement {
linetypes = ['Continuous', 'Hidden', 'Center', 'Phantom', 'Dashed'];
render() {
return html`
<div class="linetype-list">
${this.linetypes.map(lt => html`
<div class="linetype-item" @click=${() => this.select(lt)}>
<span class="name">${lt}</span>
<linetype-preview
.linetypeName=${lt}
.width=${150}
.height=${16}
></linetype-preview>
</div>
`)}
</div>
`;
}
select(linetype: string) {
this.dispatchEvent(new CustomEvent('select', {
detail: { linetype }
}));
}
}
用于在执行多步操作时创建撤销点,确保操作可以作为一个整体撤销。
import { startUndoMark, endUndoMark } from 'vjcad';
// 开始撤销标记
startUndoMark();
// 执行多个操作...
entity1.move(dx, dy);
entity2.move(dx, dy);
entity3.move(dx, dy);
// 结束撤销标记
endUndoMark();
// 现在这些操作可以作为一个整体撤销
import { startUndoMark, endUndoMark, Engine } from 'vjcad';
/**
* 批量缩放选中的图元
*/
function scaleSelectedEntities(factor: number) {
const selected = Engine.selection.getSelectedEntities();
if (selected.length === 0) return;
// 标记撤销开始
startUndoMark();
try {
// 计算中心点
const bounds = Engine.selection.getBounds();
const centerX = (bounds.minX + bounds.maxX) / 2;
const centerY = (bounds.minY + bounds.maxY) / 2;
// 缩放每个图元
for (const entity of selected) {
entity.scale(centerX, centerY, factor);
}
Engine.redraw();
} finally {
// 标记撤销结束
endUndoMark();
}
}
// 使用
scaleSelectedEntities(2.0); // 放大 2 倍
// 用户按 Ctrl+Z 可以一次性撤销所有缩放操作
startUndoMark() 和 endUndoMark() 必须成对使用- 建议使用
try...finally 确保 endUndoMark() 始终被调用 - 不要嵌套使用撤销标记
import { LitElement, html, css } from 'vjcad';
import {
NumberInputComponent,
startUndoMark,
endUndoMark,
Engine
} from 'vjcad';
class CircleEditor extends LitElement {
static properties = {
entity: { type: Object }
};
declare entity: any;
render() {
if (!this.entity) {
return html`<div>请选择一个圆</div>`;
}
return html`
<div class="editor">
<h3>圆属性</h3>
<div class="row">
<label>圆心 X:</label>
<input-number
.value=${this.entity.center.x}
.luprec=${4}
.allowMinus=${true}
@change=${(e: CustomEvent) => this.updateCenterX(e.detail.value)}
></input-number>
</div>
<div class="row">
<label>圆心 Y:</label>
<input-number
.value=${this.entity.center.y}
.luprec=${4}
.allowMinus=${true}
@change=${(e: CustomEvent) => this.updateCenterY(e.detail.value)}
></input-number>
</div>
<div class="row">
<label>半径:</label>
<input-number
.value=${this.entity.radius}
.luprec=${4}
.allowZero=${false}
.allowMinus=${false}
@change=${(e: CustomEvent) => this.updateRadius(e.detail.value)}
></input-number>
</div>
</div>
`;
}
updateCenterX(value: string) {
startUndoMark();
this.entity.center.x = parseFloat(value);
this.entity.update();
endUndoMark();
Engine.redraw();
}
updateCenterY(value: string) {
startUndoMark();
this.entity.center.y = parseFloat(value);
this.entity.update();
endUndoMark();
Engine.redraw();
}
updateRadius(value: string) {
startUndoMark();
this.entity.radius = parseFloat(value);
this.entity.update();
endUndoMark();
Engine.redraw();
}
static styles = css`
.editor {
padding: 16px;
background: var(--dialog-contents-color, #f5f7fa);
}
.row {
display: flex;
align-items: center;
margin-bottom: 8px;
}
label {
width: 80px;
font-size: 14px;
}
input-number {
flex: 1;
height: 28px;
}
`;
}
customElements.define('circle-editor', CircleEditor);
轻量级 Toast 消息提示工具,用于显示临时性的操作反馈。
import { message } from 'vjcad';
// 显示信息消息(蓝色)
message.info("操作成功");
// 显示错误消息(红色)
message.error("操作失败");
// 显示警告消息(橙色)
message.warn("请注意检查");
// 显示成功消息(绿色)
message.success("保存成功");
// 多参数(自动拼接)
message.info("加载完成", 100, "条数据");
// 显示: "加载完成 100 条数据"
message.info({
content: "正在保存...",
duration: 0, // 0 表示不自动关闭
key: "saving" // 相同 key 的消息会覆盖
});
// 稍后更新同一消息
message.info({
content: "保存成功!",
duration: 3,
key: "saving"
});
| 参数 | 类型 | 默认值 | 说明 |
|---|
content | string | - | 消息内容 |
duration | number | 3 | 显示时长(秒),0 表示不自动关闭 |
key | string | - | 唯一标识,相同 key 的消息会覆盖 |
| 方法 | 说明 |
|---|
message.info(...args) | 显示信息消息(蓝色) |
message.error(...args) | 显示错误消息(红色) |
message.warn(...args) | 显示警告消息(橙色) |
message.success(...args) | 显示成功消息(绿色) |
- 最多 3 条:同时最多显示 3 条消息,超出时最旧的消息会以动画向上滑出
- 自动消失:默认 3 秒后自动消失
- 消息覆盖:相同
key 的消息会覆盖之前的消息 - 顶部居中:消息显示在页面顶部居中位置
import { message, Engine, CircleEnt } from 'vjcad';
// 创建圆并给出反馈
const circle = new CircleEnt([100, 100], 50);
circle.setDefaults();
Engine.addEntities(circle);
Engine.zoomExtents();
message.info("圆已创建");
import { message } from 'vjcad';
// 开始处理
message.info({
content: "正在处理...",
duration: 0,
key: "progress"
});
// 处理完成后更新
setTimeout(() => {
message.info({
content: "处理完成!",
duration: 3,
key: "progress"
});
}, 2000);
import { message } from 'vjcad';
try {
// 一些可能失败的操作
await loadFile(path);
message.info("文件加载成功");
} catch (e) {
message.error({
content: `加载失败: ${e.message}`,
duration: 5
});
}