Forge Viewer自定义复合标记开发:矩形内嵌可编辑文本框需求
Forge Viewer 自定义联动复合Markup实现方案
针对你在Forge Viewer中创建矩形+底部文本框复合标记遇到的问题,以下是具体实现方案:
核心思路
通过自定义Markup子类,将矩形和文本框作为子元素统一管理,绑定两者的位置变换、禁用文本框单独拖拽,同时实现文本编辑功能,确保整个复合标记作为单个单元联动。
完整实现代码
class CustomCompoundMarkup extends Autodesk.Viewing.Extensions.Markups.Core.Markup { constructor(markupsCore, id) { super(markupsCore, id); this.rectMarkup = null; this.textMarkup = null; this.isEditingText = false; } // 初始化复合标记:创建矩形与文本框 initialize(x, y, width, height) { // 创建外层矩形标记 this.rectMarkup = this.markupsCore.createMarkup('rect', { x: x, y: y, width: width, height: height, fillColor: 'rgba(255, 255, 0, 0.2)', strokeColor: '#ff0000', strokeWidth: 2 }); // 计算文本框位置:矩形底部居中,预留内边距 const textPadding = 5; const textHeight = 20; const textX = x + (width / 2); const textY = y + height - textHeight - textPadding; // 创建内部文本标记 this.textMarkup = this.markupsCore.createMarkup('text', { x: textX, y: textY, text: '默认标注文本', fontSize: 14, fillColor: 'rgba(0, 0, 0, 0.8)', strokeColor: 'transparent', textAlign: 'center' }); // 禁用文本框单独拖拽 this.textMarkup.draggable = false; // 阻止文本框鼠标事件冒泡,避免干扰矩形拖拽 this.textMarkup.onPointerDown = (e) => { e.stopPropagation(); if (!this.isEditingText) { this.startTextEditing(); } }; // 监听矩形拖拽/缩放事件,同步文本框位置 this.rectMarkup.onDrag = () => this.syncTextPosition(); this.rectMarkup.onResize = () => this.syncTextPosition(); // 将子标记加入复合标记管理 this.addChild(this.rectMarkup); this.addChild(this.textMarkup); } // 同步文本框到矩形底部居中位置 syncTextPosition() { const rectBounds = this.rectMarkup.getBoundingRect(); const textBounds = this.textMarkup.getBoundingRect(); const textPadding = 5; const targetX = rectBounds.x + (rectBounds.width / 2); const targetY = rectBounds.y + rectBounds.height - textBounds.height - textPadding; this.textMarkup.setPosition(targetX, targetY); this.markupsCore.render(); } // 启动文本编辑功能 startTextEditing() { this.isEditingText = true; const textBounds = this.textMarkup.getBoundingRect(); // 创建临时输入框覆盖文本区域 const input = document.createElement('input'); input.type = 'text'; input.value = this.textMarkup.text; input.style.position = 'absolute'; input.style.left = `${textBounds.x}px`; input.style.top = `${textBounds.y}px`; input.style.width = `${textBounds.width}px`; input.style.height = `${textBounds.height}px`; input.style.fontSize = '14px'; input.style.textAlign = 'center'; input.style.border = 'none'; input.style.background = 'rgba(255,255,255,0.9)'; input.style.zIndex = 1000; document.body.appendChild(input); input.focus(); // 编辑完成后同步文本并清理输入框 const finishEditing = () => { this.textMarkup.text = input.value; this.markupsCore.render(); document.body.removeChild(input); this.isEditingText = false; }; input.addEventListener('blur', finishEditing); input.addEventListener('keydown', (e) => { if (e.key === 'Enter') finishEditing(); }); } // 重写父类拖拽逻辑,确保复合标记整体联动 onDrag(e) { super.onDrag(e); this.syncTextPosition(); } // 重选选中逻辑,确保复合标记整体被选中 setSelected(selected) { super.setSelected(selected); this.rectMarkup.setSelected(selected); this.textMarkup.setSelected(selected); } }
使用方式
// 确保已加载Markups扩展并进入编辑模式 const markupsExtension = viewer.getExtension('Autodesk.Viewing.MarkupsCore'); markupsExtension.enterEditMode(); // 创建自定义复合标记(示例坐标:x=100, y=100, 宽200, 高150) const compoundMarkup = new CustomCompoundMarkup(markupsExtension.core, 'custom-compound-001'); compoundMarkup.initialize(100, 100, 200, 150); markupsExtension.core.addMarkup(compoundMarkup); markupsExtension.core.render();
问题对应解决说明
- 文本框显示在矩形内部底部:通过
getBoundingRect()获取矩形和文本框的尺寸,计算底部居中坐标,确保文本框位置始终贴合矩形底部。 - 拖拽矩形时文本同步跟随:监听矩形的
onDrag和onResize事件,实时调用syncTextPosition()更新文本框位置。 - 限制文本框单独拖拽:设置文本框
draggable = false,并阻止其鼠标事件冒泡,仅允许父矩形触发拖拽。 - 文本框可编辑:点击文本时创建临时输入框,编辑完成后同步文本内容到标记,实现编辑功能。
内容的提问来源于stack exchange,提问作者fumakiya dhara
相关产品推荐
相关产品推荐

