diff --git a/src/AnnotationControl/annotationPanel.js b/src/AnnotationControl/annotationPanel.js index 79d1d9c..5feb80e 100644 --- a/src/AnnotationControl/annotationPanel.js +++ b/src/AnnotationControl/annotationPanel.js @@ -69,7 +69,6 @@ export function initAnnotationsPanel(viewer) { return null } // Monotonic numbering: assign an increasing number to each UUID and never reuse numbers. - // Stored in-memory for the session; later we can persist to a file. const _uuidToIndex = new Map() let _nextIndex = 1 @@ -114,7 +113,7 @@ export function initAnnotationsPanel(viewer) { for (const a of coll) { if (!a) continue if (a.uuid === uuid || (a.data && a.data.uuid === uuid)) return a - } + } } catch (e) { // fallback try { @@ -161,7 +160,6 @@ export function initAnnotationsPanel(viewer) { if (live) { if (typeof live.title !== 'undefined') live.title = newName if (typeof live.name !== 'undefined') live.name = newName - // for Potree Annotation object, data.title or similar may be used if (live.data) live.data.title = newName } } catch (e) { @@ -170,18 +168,29 @@ export function initAnnotationsPanel(viewer) { } } } catch (e) { - // ignore failures; we just won't rename nodes in that case + // ignore failures } - // Build list entries for each annotation node - annotationsRoot.children.forEach((node) => { + // Build list entries for each annotation node + annotationsRoot.children.forEach((node) => { const row = document.createElement('div') row.className = 'annotation-row' - const label = document.createElement('span') - label.textContent = node.text || 'Unnamed' + const label = document.createElement('span') + label.textContent = node.text || 'Unnamed' label.className = 'annotation-label' + // attach uuid for editing + try { + const uuid = (node.data && node.data.uuid) || null + if (uuid) label.dataset.uuid = uuid + } catch (e) {} + // double-click label to edit + label.addEventListener('dblclick', (ev) => { + ev.stopPropagation() + const uuid = label.dataset.uuid + if (uuid) startInlineEditForUUID(uuid) + }) // Jump button @@ -209,7 +218,7 @@ export function initAnnotationsPanel(viewer) { annPos || vecToArray(ann.cameraTarget) || viewer.scene.view.getPivot() - viewer.scene.view.setView(camPos, target, 4000) + viewer.scene.view.setView(camPos, target, 4000) //animation duration in ms } } row.appendChild(jumpBtn) @@ -276,7 +285,7 @@ export function initAnnotationsPanel(viewer) { row.appendChild(label) row.appendChild(delBtn) - // show saved camera info if present + // show saved camera and point info try { const ann = node.data || {} @@ -308,6 +317,78 @@ export function initAnnotationsPanel(viewer) { }) } + // Start inline editing for a given annotation UUID (opens an input in the sidebar) + function startInlineEditForUUID(uuid) { + if (!uuid) return + // find the row label element + const labelEl = targetContainer.querySelector(`.annotation-label[data-uuid="${uuid}"]`) + if (!labelEl) return + const oldText = labelEl.textContent || '' + const input = document.createElement('input') + input.type = 'text' + input.value = oldText + input.className = 'annotation-edit-input' + labelEl.replaceWith(input) + input.focus() + input.select() + + function finish(commit) { + const newText = commit ? input.value.trim() || oldText : oldText + // restore label + const newLabel = document.createElement('span') + newLabel.className = 'annotation-label' + newLabel.textContent = newText + newLabel.dataset.uuid = uuid + newLabel.addEventListener('dblclick', (ev) => { + ev.stopPropagation() + startInlineEditForUUID(uuid) + }) + input.replaceWith(newLabel) + // commit to jsTree and live annotation + _commitEditedName(uuid, newText) + } + + input.addEventListener('blur', () => finish(true)) + input.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + finish(true) + } else if (e.key === 'Escape') { + finish(false) + } + }) + } + + function _commitEditedName(uuid, name) { + if (!uuid) return + // update jsTree node text + try { + const tree = $('#jstree_scene').jstree && $('#jstree_scene').jstree() + if (tree) { + const annotationsRoot = tree.get_json('annotations') + if (annotationsRoot && annotationsRoot.children) { + const node = annotationsRoot.children.find((c) => (c.data && c.data.uuid) === uuid) + if (node) { + _renameJSTreeNode(node.id, name) + node.text = name + } + } + } + } catch (e) {} + + // update live annotation + try { + const live = _findLiveAnnotationByUUID(uuid) + if (live) { + if (typeof live.title !== 'undefined') live.title = name + if (typeof live.name !== 'undefined') live.name = name + if (live.data) live.data.title = name + } + } catch (e) {} + + // refresh sidebar to reflect changes + setTimeout(updateAnnotationsList, 0) + } + // Add Annotation UI (mimics Potree toolbar/pinpoint-button logic) function createAddButton() { const btn = document.createElement('button')