"use strict"; /** Render references from the active diagram to concepts linked from other CMaps. */ export class CmapBoundaryReferenceView { constructor({ canvas, zoomFactor, mapTitle, surfaceElement, itemCenter, onOpenReference }) { this.canvas = canvas; this.zoomFactor = zoomFactor; this.mapTitle = mapTitle || ""; this.surfaceElement = surfaceElement; this.itemCenter = itemCenter; this.onOpenReference = onOpenReference; this.layer = null; } clear() { if (this.layer) this.layer.remove(); this.layer = null; } render(references = []) { this.clear(); if (!references.length) return; const surface = this.surfaceElement(); if (!surface) return; const layer = document.createElement("div"); layer.className = "rw-cmap-boundary-layer"; const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.classList.add("rw-cmap-boundary-lines"); const definitions = document.createElementNS("http://www.w3.org/2000/svg", "defs"); const marker = document.createElementNS("http://www.w3.org/2000/svg", "marker"); marker.setAttribute("id", "rw-cmap-boundary-arrow"); marker.setAttribute("viewBox", "0 0 10 10"); marker.setAttribute("refX", "9"); marker.setAttribute("refY", "5"); marker.setAttribute("markerWidth", "7"); marker.setAttribute("markerHeight", "7"); marker.setAttribute("orient", "auto-start-reverse"); const arrow = document.createElementNS("http://www.w3.org/2000/svg", "path"); arrow.setAttribute("d", "M 0 0 L 10 5 L 0 10 z"); arrow.setAttribute("fill", "#808080"); marker.append(arrow); definitions.append(marker); svg.append(definitions); layer.append(svg); surface.append(layer); this.layer = layer; const factor = this.zoomFactor(); const viewLeft = this.canvas.scrollLeft / factor; const viewTop = this.canvas.scrollTop / factor; const viewWidth = this.canvas.clientWidth / factor; const viewHeight = this.canvas.clientHeight / factor; const buttonWidth = 190; const occupied = { left: [], right: [] }; const reserveY = (side, desired) => { let y = Math.max(viewTop + 12, Math.min(desired, viewTop + viewHeight - 40)); while (occupied[side].some((used) => Math.abs(used - y) < 34)) y += 34; if (y > viewTop + viewHeight - 40) y = viewTop + 12; occupied[side].push(y); return y; }; for (const reference of references) { const inside = this.itemCenter(reference.insideRecord); const side = inside.x < viewLeft + (viewWidth / 2) ? "left" : "right"; const x = side === "left" ? viewLeft + 12 : viewLeft + viewWidth - buttonWidth - 12; const y = reserveY(side, inside.y - 15); const button = document.createElement("button"); button.type = "button"; button.className = `rw-cmap-boundary-reference rw-cmap-boundary-reference-${side}`; button.style.transform = `translate(${x}px, ${y}px)`; button.style.width = `${buttonWidth}px`; if (reference.linkingPhraseLabel) { button.append(document.createTextNode(reference.linkingPhraseLabel)); button.append(document.createTextNode(" →")); button.append(document.createElement("br")); } button.append(document.createTextNode(reference.label)); if (this.mapTitle) { button.append(document.createElement("br")); const mapLabel = document.createElement("small"); const mapName = document.createElement("em"); mapName.textContent = `(${this.mapTitle})`; mapLabel.append(mapName); button.append(mapLabel); } button.title = "Open the concept map containing this connection"; button.addEventListener("click", () => { if (this.onOpenReference) this.onOpenReference(reference); }); layer.append(button); const boundaryX = side === "left" ? x + buttonWidth : x; const boundaryY = y + 15; const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); const startX = reference.sourceInside ? inside.x : boundaryX; const startY = reference.sourceInside ? inside.y : boundaryY; const endX = reference.sourceInside ? boundaryX : inside.x; const endY = reference.sourceInside ? boundaryY : inside.y; path.setAttribute("d", `M ${startX} ${startY} L ${endX} ${endY}`); path.setAttribute("fill", "none"); path.setAttribute("stroke", "#808080"); path.setAttribute("stroke-width", String(reference.connector.lineWidth || 2)); if (reference.connector.hasArrow) path.setAttribute("marker-end", "url(#rw-cmap-boundary-arrow)"); svg.append(path); } } destroy() { this.clear(); } }