draw-tools
本文回答:
vjmap.Draw.Tool控件用法 —— 选项 / 模式 / API / 事件 / 样式。
一、创建 Draw 控件
const draw = new vjmap.Draw.Tool({
keybindings: true, // 键盘交互
touchEnabled: true,
boxSelect: true, // shift+拖 框选
snap: true, // 捕捉
guides: true, // 对齐辅助线(经过已有顶点的水平/竖直参考线,不是网格)
snapOptions: {
snapPx: 15,
snapToMidPoints: false,
snapVertexPriorityDistance: 1.25,
snapGridPx: 2000 // 辅助线的半长(像素),不是网格间距
},
controls: {
point: true, line_string: true, polygon: true, trash: true
},
displayControlsDefault: true
});
map.addControl(draw, "top-right");
二、模式(mode)
| mode | 说明 |
|---|---|
static |
非编辑态,可 hover / click 高亮 |
simple_select |
选择、删除、拖整体 |
direct_select |
选、删、拖顶点 |
draw_point |
画点 |
draw_line_string |
画线 |
draw_polygon |
画多边形 |
draw_circle |
画圆 |
draw_rectangle |
画矩形 |
splitLineMode |
切割线 |
cutPolygonMode |
切割多边形 |
切换:
draw.changeMode("draw_line_string");
draw.getMode(); // 当前模式
坑位:
changeMode("direct_select")必须带{ featureId },否则抛You must provide a featureId;其余模式可裸名切换。
三、常用 API
// 增/查
const ids = draw.add({ type: "Feature", geometry: { type: "Point", coordinates: [0,0] } });
draw.get(id);
draw.getAll();
draw.getSelected();
draw.getSelectedIds();
// 删
draw.delete(id);
draw.delete([id1, id2]);
draw.deleteAll();
draw.trash(); // 调当前模式的"删除"动作
// 批量替换
draw.set(featureCollection);
// 历史
draw.undo();
draw.redo();
draw.clearHistory();
// 刷新(改 geometry 后调)
draw.forceRefresh();
// 组合(⚠️ 只在 simple_select 模式下可用(组合需选中 ≥2 个)——其它模式下调用抛
// "onCombineFeatures is not a function",组合 / 取消组合处理器只注册在 simple_select 上)
draw.combineFeatures();
draw.uncombineFeatures();
四、设置 Feature 属性
draw.setFeatureProperty(id, "color", "#f00");
draw.setFeatureProperty(id, "line_width", 3);
draw.setFeatureProperty(id, "hoverPointer", true); // 浏览模式高亮
draw.setFeatureProperty(id, "hover_color", "#ff0");
draw.setFeatureProperty(id, "isLocked", true); // 锁定
draw.setFeatureProperty(id, "isOff", true); // 隐藏
draw.setFeatureProperty(id, "noSnap", true); // 禁捕捉
draw.setFeatureProperty(id, "disable_edit", true); // 禁编辑
draw.setFeatureProperty(id, "minZoom", 5);
draw.setFeatureProperty(id, "maxZoom", 10);
draw.setFeatureProperty(id, "extrusionHeight", 100); // 多边形拉伸
点的额外属性:
draw.setFeatureProperty(id, "icon_image", "my-icon");
draw.setFeatureProperty(id, "icon_size", 1.2);
draw.setFeatureProperty(id, "text", "A");
draw.setFeatureProperty(id, "text_size", 22);
draw.setFeatureProperty(id, "symbol", true); // 带图标+文字
五、事件
map.on("draw.create", e => console.log("新建", e.features));
map.on("draw.update", e => console.log("更新", e.action, e.features));
map.on("draw.delete", e => console.log("删除", e.features));
map.on("draw.selectionchange", e => console.log("选中", e.features));
map.on("draw.modechange", e => console.log("模式", e.mode));
map.on("draw.render", () => console.log("重绘"));
map.on("draw.actionable", e => console.log("可操作", e.actions));
map.on("draw.updatecoordinate", e => console.log("坐标", e.lnglat));
map.on("draw.simpleselect.contextmenu", e => { /* 右键 */ });
map.on("draw.directselect.contextmenu", e => { /* 右键 */ });
map.on("draw.custom", e => {
if (e.customName === "clickedLocked") { /* 点了锁定图形 */ }
});
// static 模式
map.on("draw.static.mouseenter", e => { /* popup */ });
map.on("draw.static.mouseleave", e => { /* popup remove */ });
map.on("draw.static.click", e => { /* 点击 */ });
六、自定义控件按钮
⚠️ addControls 里与内置按钮同 id 的项会被丢弃(内置 id:drawCircle / drawRectangle / splitLine / cutPolygon / undo / redo / snap_mode_snap / snap_mode_grid),内置按钮照常保留——自定义按钮要用新 id;要隐藏内置按钮设 opts.controls.<id> = false(如 opts.controls.splitLine = false)。
const opts = vjmap.cloneDeep(vjmap.Draw.defaultOptions());
opts.addControls = [
{
id: "myCircle", title: "画圆", className: "vjmap-map-draw_circle",
onActivate: (ctx) => ctx.api.changeMode("draw_circle")
},
{
id: "mySplitLine", title: "切线", className: "vjmap-map-draw-cut-line",
onActivate: (ctx) => ctx.api.changeMode("splitLineMode", { spliter: "line_string" })
},
{
id: "myUndo", title: "撤销", className: "vjmap-map-draw_undo",
onActivate: (ctx) => ctx.api.undo()
},
{
id: "mySnap", title: "捕捉", isCheckbox: true, checked: true,
className: "snap_mode_snap",
onActivate: (ctx, e) => ctx.options.snap = e.target.checked
}
];
// 隐藏同功能的内置按钮
Object.assign(opts.controls, { drawCircle: false, splitLine: false, undo: false, snap_mode_snap: false });
const draw = new vjmap.Draw.Tool(opts);
七、绘制时禁用键盘
map.setCustomKeyValue("_disable_drawkey_backspacekey", true);
map.setCustomKeyValue("_disable_drawkey_escapekey", true);
map.setCustomKeyValue("_disable_drawkey_enterkey", true);
八、默认样式修改
Draw.defaultOptions() 只是浅拷贝,styles / controls / addControls 是全局共享对象——直接改会污染之后所有 Draw 实例(含 actionDraw* 内部建的临时实例),先 vjmap.cloneDeep:
const opts = vjmap.cloneDeep(vjmap.Draw.defaultOptions());
opts.styles[7].paint["line-width"] = 4; // 线宽
opts.styles[7].paint["line-color"] = "#0f0";
opts.midpoints = false; // 不显示中点
const draw = new vjmap.Draw.Tool(opts);
九、仅 action 模式(不显示工具栏)
const opts = vjmap.cloneDeep(vjmap.Draw.defaultOptions());
opts.isActionDrawMode = true; // 不生成按钮
const draw = new vjmap.Draw.Tool(opts);
map.addControl(draw, "top-right");
// 用自己的实例驱动绘制:changeMode + 按 styleId 过滤 draw.create
map.on("draw.create", e => { if (e.styleId === draw.options.styleId) console.log(e.features); });
draw.changeMode("draw_line_string");
注意:vjmap.Draw.actionDraw* 每次都自建并在结束后移除一个临时 Tool,不会画进你的 draw 实例;要把结果放进自己的实例,拿 resolve 的 features 再 draw.add(...)。
十、常见坑
setFeatureProperty后不可见 →draw.forceRefresh()。- 触摸端体验差 → 调大
touchBuffer(默认 25)。 - 多个 Draw 实例事件乱:不同 draw 的 options.styleId 不同,在事件回调里比较
e.styleId过滤。 draw.add(feature)但 id 已存在 → 实际是 update,不是新建;要唯一可以delete+add。- 程序化增删不进历史、不发事件:
add/delete/set/deleteAll只写 store + render(api.add不发draw.create,api.delete走silent:true)。历史记录只在draw.create/update/delete/combine事件的监听里生成——即undo/redo只覆盖交互操作,对程序化add是 no-op。需要可撤销的程序化改动要自己管快照,或走draw.set+ 自建历史。