Skip to content

Commit

Permalink
docs(#4): 📝 improved inline documentation in the code
Browse files Browse the repository at this point in the history
  • Loading branch information
franmagn committed Oct 22, 2025
1 parent f0bbe5c commit 294bc97
Showing 1 changed file with 116 additions and 12 deletions.
128 changes: 116 additions & 12 deletions src/AnnotationControl/annotationPanel.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { initAnnotationPersistence } from './persistence'

/**
* Annotations Panel
* Injects a custom Annotations section for storing camera positions,
* that will (later) be used for letting users rapidly jump to saved views.
* Initialize and inject the Annotations sidebar panel, used for managing saved camera views.
*
* Creates (or re-uses) a container with id `annotations_list`, renders the
* saved annotation entries from the project's jsTree, wires UI controls
* (jump, delete, toggle, inline editing), and hooks into Potree's
* annotation events to keep the list in sync.
*
* Side effects:
* - Mutates DOM by injecting a panel and a "Add a location" button.
* - Registers event listeners on viewer.scene.annotations to refresh the list.
* - Attaches click/dblclick handlers and inline edit inputs that commit
* edits back to jsTree and the live annotation objects.
*
* @param {Object} viewer - Potree viewer instance (used to read camera/pivot,
* jump the view, and access viewer.scene.annotations).
*/
export function initAnnotationsPanel(viewer) {
// Container management
Expand Down Expand Up @@ -61,19 +73,40 @@ export function initAnnotationsPanel(viewer) {
return
}

// UI update
// Helper: normalize different vector shapes into [x,y,z] (necessary for handling both Three.js Vector3 and serialized data stored in the jsTree)
/**
* Normalize a vector-like input into an [x,y,z] array. (necessary for handling both Three.js Vector3 and serialized data stored in the jsTree)
*
* Accepts:
* - Array [x,y,z]
* - Three.js Vector3 with toArray()
* - Plain object {x,y,z}
*
* Returns null for invalid input.
*
* @param {*} v - value to normalize
* @returns {Array<number>|null} an [x,y,z] array or null
*/
function vecToArray(v) {
if (!v) return null
if (Array.isArray(v)) return v
if (typeof v.toArray === 'function') return v.toArray()
if (v.x != null && v.y != null && v.z != null) return [v.x, v.y, v.z]
return null
}
// Monotonic numbering: assign an increasing number to each UUID and never reuse numbers.

const _uuidToIndex = new Map()
let _nextIndex = 1

/**
* Return a monotonic index number for a UUID (Universally Unique Identifier).
*
* The function assigns an incrementing integer to each UUID the first time
* it is seen and never reuses numbers. Useful to produce human-readable
* default names (e.g. "Annotation #3") when nodes are missing titles.
*
* @param {string} uuid - UUID string for the annotation
* @returns {number|null} index assigned to the UUID, or null if uuid falsy
*/
function _ensureIndexForUUID(uuid) {
if (!uuid) return null
if (!_uuidToIndex.has(uuid)) {
Expand Down Expand Up @@ -107,6 +140,14 @@ export function initAnnotationsPanel(viewer) {

function _getAnnotationsRoot() {
const t = _getJSTree()
/**
* Find the live annotation object in the viewer.scene by UUID.
*
* Returns the live annotation or null.
*
* @param {string} uuid - annotation UUID
* @returns {Object|null} live annotation object or null if not found
*/
try {
return t ? t.get_json('annotations') : null
} catch (e) {
Expand Down Expand Up @@ -189,6 +230,23 @@ export function initAnnotationsPanel(viewer) {
return null
}
function updateAnnotationsList() {
/**
* Rebuild the annotation list UI from the project's jsTree data.
*
* This function:
* - Clears and re-populates the `targetContainer` with a row per annotation.
* - Ensures default labels for unnamed annotations (using monotonic numbering).
* - Renders header, toggle triangle, edit label, jump/delete controls, description,
* and read-only camera/point info.
* - Wires events for inline editing, jump, delete, and header click-to-toggle.
*
* Side effects:
* - Mutates DOM inside `targetContainer`.
* - May call `_renameJSTreeNode` to rename nodes when needed.
* - Uses `_findLiveAnnotationByUUID` to prefer live object positions over serialized values.
* - Event listeners stop propagation where necessary so double-click and button
* behaviour are preserved.
*/
// Implementation for listing annotations
targetContainer.innerHTML = ''
const annotationsTree = _getJSTree()
Expand Down Expand Up @@ -280,7 +338,6 @@ export function initAnnotationsPanel(viewer) {
toggle.title = 'Toggle details'

// Jump button

const jumpBtn = document.createElement('button')
jumpBtn.className = 'jump-btn'
jumpBtn.title = 'Move to this position'
Expand Down Expand Up @@ -310,7 +367,6 @@ export function initAnnotationsPanel(viewer) {
try {
jumpBtn.setAttribute('aria-pressed', 'true')
jumpBtn.classList.add('recently-pressed')
// remove after short delay to allow CSS fade-out
window.setTimeout(() => {
try {
jumpBtn.classList.remove('recently-pressed')
Expand All @@ -332,7 +388,7 @@ export function initAnnotationsPanel(viewer) {
const uuid = annData.uuid

if (uuid && viewer && viewer.scene && viewer.scene.annotations) {
// Find the live annotation instance by UUID (Universally Unique Identifier)
// Find the live annotation instance by UUID
let candidates = []
try {
candidates =
Expand Down Expand Up @@ -527,8 +583,21 @@ export function initAnnotationsPanel(viewer) {
})
}

// Start inline editing for a given annotation UUID (opens an input in the sidebar)
function startInlineEditForUUID(uuid) {
/**
* Start inline editing of an annotation title (opens an input in the sidebar).
*
* Replaces the `.annotation-label` with a text input and handles commit/abort:
* - On commit, updates the label in the sidebar, updates the jsTree node text,
* and updates the live annotation object's title (via `_commitEditedName`).
* - On abort, restores the original label without committing.
*
* Special handling:
* - If the label contains a decorative edit-hint span, the hint text is not
* included in the input value and is re-attached to the restored label.
*
* @param {string} uuid - annotation UUID to edit
*/
if (!uuid) return
const labelEl = targetContainer.querySelector(
`.annotation-label[data-uuid="${uuid}"]`
Expand Down Expand Up @@ -614,8 +683,16 @@ export function initAnnotationsPanel(viewer) {
})
}

// Start inline editing for an annotation description (multiline)
function startInlineDescriptionEditForUUID(uuid) {
/**
* Start inline editing of an annotation description (multiline).
*
* Replaces the `.annotation-desc` container with a textarea. Behavior mirrors
* `startInlineEditForUUID` but handles multiline input. Commit updates both
* the jsTree node data and the live annotation object's description.
*
* @param {string} uuid - annotation UUID to edit
*/
if (!uuid) return
const descEl = targetContainer.querySelector(
`.annotation-desc[data-uuid="${uuid}"]`
Expand Down Expand Up @@ -695,6 +772,14 @@ export function initAnnotationsPanel(viewer) {
}

function _commitEditedDescription(uuid, description) {
/**
* Commit a changed annotation description to jsTree and to the live annotation.
*
* Also updates any cached node data used by the sidebar.
*
* @param {string} uuid - annotation UUID
* @param {string} description - new description text
*/
if (!uuid) return
try {
const tree = _getJSTree()
Expand Down Expand Up @@ -737,6 +822,15 @@ export function initAnnotationsPanel(viewer) {
}

function _commitEditedName(uuid, name) {
/**
* Commit a changed annotation name to jsTree and to the live annotation object.
*
* This updates the jsTree node text (if accessible) and mutates the live
* annotation instance's title/name/data so the viewer label matches.
*
* @param {string} uuid - annotation UUID
* @param {string} name - new name to commit
*/
if (!uuid) return
// update jsTree node text
try {
Expand Down Expand Up @@ -769,8 +863,18 @@ export function initAnnotationsPanel(viewer) {
setTimeout(updateAnnotationsList, 0)
}

// Add Annotation UI (mimics Potree toolbar/pinpoint-button logic)
function createAddButton() {
/**
* Create and insert the "Add a location" button for annotations.
*
* The button:
* - Captures the current camera view when clicked.
* - Starts Potree's annotation insertion mode.
* - Waits for placement completion and triggers `updateAnnotationsList`.
*
* Side effects:
* - Inserts a button into the DOM near the annotations list.
*/
const btn = document.createElement('button')
btn.className = 'annotation-add-button'
btn.setAttribute('aria-label', 'Add a new saved location')
Expand Down

0 comments on commit 294bc97

Please sign in to comment.