this.zoomOutBtn = null;
this.zoomResetBtn = null;
+ // Bind event handlers for proper addition and removal
this.boundMouseMoveHandler = this.handleMouseMove.bind(this);
this.boundMouseUpHandler = this.handleMouseUp.bind(this);
+ this.boundToggleInteraction = this.toggleInteraction.bind(this);
+ this.boundCopyCode = this.copyCode.bind(this);
+ this.boundZoomIn = () => {
+ const { clientX, clientY } = this._getViewportCenterClientCoords();
+ this.zoom(1, clientX, clientY);
+ };
+ this.boundZoomOut = () => {
+ const { clientX, clientY } = this._getViewportCenterClientCoords();
+ this.zoom(-1, clientX, clientY);
+ };
+ this.boundResetZoom = this.resetZoom.bind(this);
+ this.boundHandleWheel = this.handleWheel.bind(this);
+ this.boundHandleMouseDown = this.handleMouseDown.bind(this);
+ this.boundPreventDefault = e => e.preventDefault();
+ this.boundPreventSelect = e => { if (this.isDragging || this.interactionEnabled) e.preventDefault(); };
+
this.setupViewer();
this.setupEventListeners();
}
}
setupEventListeners() {
- this.toggleInteractionBtn.addEventListener('click', () => this.toggleInteraction());
- this.copyCodeBtn.addEventListener('click', () => this.copyCode());
- this.zoomInBtn.addEventListener('click', () => {
- const { clientX, clientY } = this._getViewportCenterClientCoords();
- this.zoom(1, clientX, clientY);
- });
- this.zoomOutBtn.addEventListener('click', () => {
- const { clientX, clientY } = this._getViewportCenterClientCoords();
- this.zoom(-1, clientX, clientY);
- });
- this.zoomResetBtn.addEventListener('click', () => this.resetZoom());
-
- this.viewport.addEventListener('wheel', (e) => {
- if (!this.interactionEnabled) return;
- // Prevent default browser scroll/zoom behavior when wheeling over the diagram
- e.preventDefault();
- this.content.classList.add(CSS_CLASSES.ZOOMING);
- const clientX = e.clientX;
- const clientY = e.clientY;
- if (e.deltaY > 0) this.zoom(-1, clientX, clientY);
- else this.zoom(1, clientX, clientY);
- setTimeout(() => this.content.classList.remove(CSS_CLASSES.ZOOMING), ZOOM_ANIMATION_CLASS_TIMEOUT_MS);
- }, { passive: false });
+ this.toggleInteractionBtn.addEventListener('click', this.boundToggleInteraction);
+ this.copyCodeBtn.addEventListener('click', this.boundCopyCode);
+ this.zoomInBtn.addEventListener('click', this.boundZoomIn);
+ this.zoomOutBtn.addEventListener('click', this.boundZoomOut);
+ this.zoomResetBtn.addEventListener('click', this.boundResetZoom);
- this.viewport.addEventListener('mousedown', (e) => {
- if (!this.interactionEnabled || e.button !== 0) return;
- e.preventDefault();
- this.isDragging = true;
- this.dragStarted = false;
- this.startX = e.clientX;
- this.startY = e.clientY;
- this.dragBaseTranslateX = this.translateX;
- this.dragBaseTranslateY = this.translateY;
- this.viewport.classList.add(CSS_CLASSES.DRAGGING);
- this.viewport.classList.remove(CSS_CLASSES.INTERACTIVE_HOVER);
- this.viewport.classList.add(CSS_CLASSES.INTERACTIVE_PAN);
- this.content.classList.remove(CSS_CLASSES.ZOOMING);
- });
+ this.viewport.addEventListener('wheel', this.boundHandleWheel, { passive: false });
+ this.viewport.addEventListener('mousedown', this.boundHandleMouseDown);
// Listen on document for mousemove to handle dragging outside viewport
document.addEventListener('mousemove', this.boundMouseMoveHandler);
// Listen on window for mouseup to ensure drag ends even if mouse is released outside
window.addEventListener('mouseup', this.boundMouseUpHandler, true); // Use capture phase
- this.viewport.addEventListener('contextmenu', (e) => e.preventDefault());
- this.viewport.addEventListener('selectstart', (e) => { if (this.isDragging || this.interactionEnabled) e.preventDefault(); });
+ this.viewport.addEventListener('contextmenu', this.boundPreventDefault);
+ this.viewport.addEventListener('selectstart', this.boundPreventSelect);
}
toggleInteraction() {
this.content.style.transform = `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`;
}
+ handleWheel(e) {
+ if (!this.interactionEnabled) return;
+ // Prevent default browser scroll/zoom behavior when wheeling over the diagram
+ e.preventDefault();
+ this.content.classList.add(CSS_CLASSES.ZOOMING);
+ const clientX = e.clientX;
+ const clientY = e.clientY;
+ if (e.deltaY > 0) this.zoom(-1, clientX, clientY);
+ else this.zoom(1, clientX, clientY);
+ setTimeout(() => this.content.classList.remove(CSS_CLASSES.ZOOMING), ZOOM_ANIMATION_CLASS_TIMEOUT_MS);
+ }
+
+ handleMouseDown(e) {
+ if (!this.interactionEnabled || e.button !== 0) return;
+ e.preventDefault();
+ this.isDragging = true;
+ this.dragStarted = false;
+ this.startX = e.clientX;
+ this.startY = e.clientY;
+ this.dragBaseTranslateX = this.translateX;
+ this.dragBaseTranslateY = this.translateY;
+ this.viewport.classList.add(CSS_CLASSES.DRAGGING);
+ this.viewport.classList.remove(CSS_CLASSES.INTERACTIVE_HOVER);
+ this.viewport.classList.add(CSS_CLASSES.INTERACTIVE_PAN);
+ this.content.classList.remove(CSS_CLASSES.ZOOMING);
+ }
+
handleMouseMove(e) {
if (!this.isDragging) return;
// e.preventDefault() is called only after dragStarted is true to allow clicks if threshold isn't met.
destroy() {
// Remove event listeners specific to this instance
- this.toggleInteractionBtn.removeEventListener('click', this.toggleInteraction); // Need to ensure this is the same function reference
- this.copyCodeBtn.removeEventListener('click', this.copyCode);
- this.zoomInBtn.removeEventListener('click', this.zoom); // These would need bound versions or careful handling
- this.zoomOutBtn.removeEventListener('click', this.zoom);
- this.zoomResetBtn.removeEventListener('click', this.resetZoom);
+ this.toggleInteractionBtn.removeEventListener('click', this.boundToggleInteraction);
+ this.copyCodeBtn.removeEventListener('click', this.boundCopyCode);
+ this.zoomInBtn.removeEventListener('click', this.boundZoomIn);
+ this.zoomOutBtn.removeEventListener('click', this.boundZoomOut);
+ this.zoomResetBtn.removeEventListener('click', this.boundResetZoom);
- this.viewport.removeEventListener('wheel', this.handleWheel); // Assuming handleWheel is the actual handler
- this.viewport.removeEventListener('mousedown', this.handleMouseDown); // Assuming handleMouseDown
- this.viewport.removeEventListener('contextmenu', this.handleContextMenu);
- this.viewport.removeEventListener('selectstart', this.handleSelectStart);
+ this.viewport.removeEventListener('wheel', this.boundHandleWheel, { passive: false });
+ this.viewport.removeEventListener('mousedown', this.boundHandleMouseDown);
+ this.viewport.removeEventListener('contextmenu', this.boundPreventDefault);
+ this.viewport.removeEventListener('selectstart', this.boundPreventSelect);
document.removeEventListener('mousemove', this.boundMouseMoveHandler);
window.removeEventListener('mouseup', this.boundMouseUpHandler, true);
border-radius: 6px;
transform: translateX(400px);
transition: transform 0.3s ease;
- z-index: 1000;
+ z-index: 10000;
+ /* Increased z-index to appear above site header */
}
.mermaid-notification.show {