input-manager
本文回答:
mapcadLayer.inputManager全部方法 ——getPoint / getEntity / getSelections / getReal / getInteger / getKeyword / getString / cancelCurrentInput。
一、InputResult 结构(真实字段)
所有 get* 方法返回 Promise<InputResult>(或对应的 XxxInputResult 子类):
class InputResult {
status: InputStatusEnum; // 'ok' | 'cancel' | 'enter' | 'keyword' | 'isNumber' | 'none'
value: Point2D; // getPoint 的点结果;数值型子类里 value 是 number/string
stringResult: string; // 原始输入串(含用户键入的关键字)
numberValue?: number; // status==='isNumber' 时用户直接输入的数值
entity?: EntityBase; // getEntity 结果
entities?: EntityBase[]; // getSelections 结果
pickPoint?: Point2D; // 拾取点
snapEntityId?: string;
snapType?: string;
}
注意字段名:点结果在 r.value(Point2D),不是 r.point;关键字看 status==='keyword' + r.stringResult,没有 r.keyword 字段。
getPoint 从不返回 'enter'(1.0.1 中只有单选 getEntity 在回车/空格时返回它):等待点时按回车/空格、右键、Esc 一律返回 'cancel'——"回车结束循环取点"就按 status !== 'ok' 退出(内置 PLINE/SPLINE 即如此)。getPoint 实际只会给 ok / cancel / keyword / isNumber。另:getKeyword 选中关键字返回的是 status: 'ok' + r.value(不是 'keyword')。
const r = await im.getPoint({ message: '指定起点' });
if (r.status === vjmapext.InputStatusEnum.OK) {
use(r.value); // Point2D
} else if (r.status === vjmapext.InputStatusEnum.Cancel) {
return;
}
二、getPoint
getPoint(options?: PointInputOptions): Promise<InputResult>
class PointInputOptions {
message: string; // 提示语(字段名是 message,不是 prompt)
useBasePoint: boolean; // 是否启用橡皮筋起点
basePoint: Point2D; // 橡皮筋起点(须先设 useBasePoint)
keywords: string[]; // 可选关键字列表
keywordTips?: Record<string, string>; // 关键字按钮悬浮提示
callback?: (cursorCadPt: Point2D) => void; // 光标移动回调
allowNumberResult: boolean; // 允许直接键入数字(status='isNumber',结果在 numberValue)
useForceAngle: boolean; // 强制角度:只对键入距离(resolvePointByDistance)生效,不约束鼠标拾取
forceAngle: number; // 弧度
ignoreOrthoMode: boolean; // 1.0.1 无正交模式,此字段未被读取
}
const r = await im.getPoint({
message: '指定终点 [闭合(C)/撤销(U)]',
useBasePoint: true,
basePoint: start,
keywords: ['C', 'U']
});
if (r.status === 'keyword') {
if (r.stringResult === 'C') closePolyline();
else if (r.stringResult === 'U') undoLast();
}
getPoint 自动启用对象捕捉(见 snap)。
三、getEntity / getSelections
getEntity(options?: EntityInputOptions): Promise<InputResult>
class EntityInputOptions {
message: string;
filter?: (entity) => boolean; // 类型过滤
keywords: string[];
keywordTips?: Record<string, string>;
multiple: boolean; // 允许多选
useExistingSelection: boolean; // 复用已有选集
}
getSelections(options?: SelectionInputOptions): Promise<InputResult>
class SelectionInputOptions { message: string } // 只有 message
// 单选/过滤 → getEntity
const r = await im.getEntity({
message: '选择一条线',
filter: e => e.type === 'LINE'
});
if (r.status === 'ok') use(r.entity);
// 框选多个 → getSelections
const rs = await im.getSelections({ message: '选择要删除的实体' });
if (rs.status === 'ok') rs.entities.forEach(e => mapcadLayer.deleteEntity(e.id));
getSelections 等待中:单击实体 = toggle 选中;单击空白处 = 立即结束选择(返回 ok + 当前选集,与 AutoCAD"点空白开窗口"不同);从空白处拖动才是框选(左→右 窗口 / 右→左 交叉,追加到选集);回车/空格结束;右键无反应。
四、getReal / getInteger
getReal(options?: RealInputOptions): Promise<RealInputResult> // { status, value: number }
class RealInputOptions {
message: string;
keywords: string[];
keywordTips?: Record<string, string>;
defaultValue: number;
lowerLimit?: number; // 字段名是 lowerLimit/upperLimit,不是 min/max
upperLimit?: number;
}
const r = await im.getReal({
message: '输入半径',
defaultValue: 10,
lowerLimit: 0.1,
upperLimit: 1000
});
if (r.status === 'ok') use(r.value); // number
getInteger 同接口(IntegerInputOptions),lowerLimit/upperLimit 有默认值 0/1024(非必填),只接受整数。
五、getKeyword
getKeyword(options?: KeywordInputOptions): Promise<KeywordInputResult> // { status, value: string }
class KeywordInputOptions {
message: string;
keywords: string[];
keywordTips?: Record<string, string>;
defaultKeyword: string;
}
const r = await im.getKeyword({
message: '选操作',
keywords: ['移动', '复制', '旋转'],
defaultKeyword: '移动'
});
// r.value: '移动' | '复制' | '旋转'
UI 层在命令栏显示按钮;也接受键盘输入。
六、getString
getString(options?: StringInputOptions): Promise<StringInputResult> // { status, value: string }
class StringInputOptions { message; keywords; keywordTips?; allowEmpty: boolean; defaultValue: string }
const r = await im.getString({ message: '输入文字', defaultValue: '标注' });
if (r.status === 'ok') use(r.value); // string
自由文本落在
r.value,r.stringResult此时为""——stringResult只在关键字路径填充(见getKeyword/getPoint的status==='keyword'分支)。
七、getDistanceOrTwoPoints(独立函数,不在 im 上)
const r = await vjmapext.getDistanceOrTwoPoints(im, '输入距离或指定第一点', '指定第二点');
// 用户可直接键入数字,或点两点取间距;结果在 r.numberValue
// 注意:直接键入数字的 'isNumber' 已被函数内部归一为 'ok'——返回值只有 'ok'/'cancel'/'keyword'
if (r.status === 'ok') use(r.numberValue);
CIRCLE TTR 半径、OFFSET 距离用这个。注意它是导出的工具函数,不是 im.getDistance()。
八、cancelCurrentInput
mapcadLayer.inputManager.cancelCurrentInput();
让当前 get* Promise 以 status: 'cancel' resolve,命令流程顺势 return。
程序化落地:resolve*Value 族(自动化/测试通道)
挂起的 get* Promise 可以用对应类型的 resolve*Value 直接落地,不依赖真实 UI 输入:
im.resolvePointByValue(x, y); // 落地 getPoint(绝对坐标)
im.resolvePointByDistance(dist); // getPoint:直接键入距离
im.resolvePointByRelative(dx, dy); // getPoint:相对 basePoint 直角偏移
im.resolvePointByPolar(dist, angleDeg); // getPoint:相对 basePoint 极坐标(角度为度)
im.resolveStringValue('文字'); // 落地 getString
im.resolveRealValue(3.14); // 落地 getReal
im.resolveIntegerValue(7); // 落地 getInteger
im.resolveKeywordValue('移动'); // 落地 getKeyword / getPoint 的关键字分支
类型必须对得上:getInteger 挂起时调 resolveStringValue("7") 不会 resolve(Promise 一直挂起直到超时/cancel)——整数输入只能走 resolveIntegerValue。实体选择(getEntity/getSelections)没有对应的 resolve 方法,只能走真实拾取或 cancelCurrentInput。
九、微调
| 属性 | 说明 |
|---|---|
im.nudgePixels |
方向键微移像素数(默认 1) |
im.nudgeRotateDeg |
微旋转角度,度(默认 1) |
im.nudgeScaleFactor |
微缩放因子(默认 1.02) |
十、典型场景:画直线
class MyLineCmd {
async main(ctx) { // 实例方法(registry 内部 new 后调用),不能写 static
const { inputManager: im, store, drawingDefaults: defaults } = ctx;
const p1 = await im.getPoint({ message: '指定起点' });
if (p1.status !== 'ok') return;
const p2 = await im.getPoint({
message: '指定终点 [撤销(U)]',
useBasePoint: true,
basePoint: p1.value,
keywords: ['U']
});
if (p2.status !== 'ok') return;
const line = new vjmapext.LineEnt(p1.value, p2.value);
line.color = defaults.color;
store.add(line);
}
}
mapcadLayer.commandRegistry.register('MYLINE', MyLineCmd, '画直线');
十一、常见坑
- 不判断 status 直接用
r.value:取消时值不可靠 → 先判'ok'。 - 把点结果当
r.point:字段是r.value(Point2D)。 - options 用
prompt:字段名是message。 getSelection(单数)不存在:多选是getSelections;单选/过滤用getEntity(EntityInputOptions 才有filter/multiple/useExistingSelection)。- 橡皮筋不显示:须
useBasePoint: true+basePoint一起给,没有单独的rubberBand开关。 - keywords 不写在 message 里:用户不知道可用关键字;提示语括号带上。
- getSelections 返回空数组:用户直接 Enter/空格,或第一下就单击了空白处;status 仍
'ok'但entities=[]。
相关
- 捕捉 → snap
- 预览 → preview
- 自定义命令 → custom-command