{# Trajectory scatter: colour legend, volume-focus highlight, glyph overlay traces #} function wireTrajScatterLegendInteraction() { if (trajScatterLegendInteractionWired || !trajScatterColorLegendEl) return; trajScatterLegendInteractionWired = true; var drag = null; function onDocMove(ev) { if (!drag && trajScatterLegendPendingDrag) { var dx0 = ev.clientX - trajScatterLegendPendingDrag.startX; var dy0 = ev.clientY - trajScatterLegendPendingDrag.startY; if ((dx0 * dx0 + dy0 * dy0) < 9) return; drag = trajScatterLegendPendingDrag; trajScatterLegendPendingDrag = null; trajScatterColorLegendEl.classList.add("cryo-traj-scatter-color-legend--dragging"); } if (!drag) return; var dx = ev.clientX - drag.startX; var dy = ev.clientY - drag.startY; var clamped = clampTrajScatterLegendBox(drag.origLeft + dx, drag.origTop + dy); trajScatterColorLegendEl.style.left = Math.round(clamped.x) + "px"; trajScatterColorLegendEl.style.top = Math.round(clamped.y) + "px"; trajScatterColorLegendEl.style.right = "auto"; trajScatterColorLegendEl.style.bottom = "auto"; } function onDocUp() { if (drag) { trajScatterColorLegendEl.classList.remove("cryo-traj-scatter-color-legend--dragging"); saveTrajScatterLegendPositionFromDom(); drag = null; } trajScatterLegendPendingDrag = null; } document.addEventListener("mousemove", onDocMove); document.addEventListener("mouseup", onDocUp); trajScatterColorLegendEl.addEventListener("click", function(ev) { var sizeBtn = ev.target.closest("[data-traj-scatter-legend-size-delta]"); if (!sizeBtn || !trajScatterColorLegendEl.contains(sizeBtn)) return; ev.preventDefault(); ev.stopPropagation(); adjustTrajScatterLegendScale(parseFloat(sizeBtn.getAttribute("data-traj-scatter-legend-size-delta"))); }); trajScatterColorLegendEl.addEventListener("dblclick", function(ev) { var t = ev.target; if (!t || !t.classList) return; if (t.classList.contains("cryo-traj-scatter-color-legend__title") || t.classList.contains("cryo-traj-scatter-color-legend__label") || t.classList.contains("cryo-traj-scatter-color-legend__scale-val")) { ev.preventDefault(); ev.stopPropagation(); trajScatterLegendPendingDrag = null; drag = null; trajScatterColorLegendEl.classList.remove("cryo-traj-scatter-color-legend--dragging"); startTrajScatterLegendTextEdit(t); } }); trajScatterColorLegendEl.addEventListener("mousedown", function(ev) { if (ev.button !== 0) return; if (ev.target && ev.target.closest && (ev.target.closest(".cryo-traj-scatter-color-legend__size-control") || ev.target.closest(".cryo-traj-scatter-color-legend__editing"))) { return; } ev.preventDefault(); ev.stopPropagation(); if (!scatterPlotStack) return; var stackRect = scatterPlotStack.getBoundingClientRect(); var legRect = trajScatterColorLegendEl.getBoundingClientRect(); trajScatterLegendPendingDrag = { startX: ev.clientX, startY: ev.clientY, origLeft: legRect.left - stackRect.left, origTop: legRect.top - stackRect.top }; }); } function trajEffectiveColorLegendMeta() { var leg = gd && gd.layout && gd.layout.meta && gd.layout.meta.cdrgn_color_legend; if (!leg) return null; if (leg.type !== "discrete" || !leg.items || !trajDiscreteColorOverridesActive()) { return leg; } var items = []; for (var i = 0; i < leg.items.length; i++) { var it = leg.items[i]; if (!it) continue; var lbl = String(it.label); var ov = trajDiscreteColorOverrides[lbl]; items.push({ label: lbl, color: ov ? String(ov) : String(it.color || "#888888"), count: it.count }); } return { type: "discrete", title: leg.title, items: items }; } function syncTrajScatterColorLegend() { if (!trajScatterColorLegendEl) return; resetTrajScatterLegendUiIfColumnChanged(sc.value); var hasColor = !!(sc.value && sc.value !== "none"); var leg = hasColor ? trajEffectiveColorLegendMeta() : null; if (!leg) { trajScatterColorLegendEl.hidden = true; trajScatterColorLegendEl.setAttribute("aria-hidden", "true"); trajScatterColorLegendEl.innerHTML = ""; trajScatterColorLegendEl.className = "cryo-traj-scatter-color-legend"; return; } var title = trajScatterLegendTitleText(leg); var html = ""; if (leg.type === "continuous") { var pal = selectedTrajPalette(); var grad = trajPaletteLinearGradientCss(pal); trajScatterColorLegendEl.className = "cryo-traj-scatter-color-legend cryo-traj-scatter-color-legend--continuous"; html += '