js-draw
Version:
Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.
81 lines (80 loc) • 3.92 kB
JavaScript
import { Rect2 } from '@js-draw/math';
import { EditorEventType } from '../types.mjs';
import BaseTool from './BaseTool.mjs';
/**
* This tool, when enabled, renders scrollbars reflecting the current position
* of the view relative to the import/export area of the image.
*
* **Note**: These scrollbars are currently not draggable. This may change in
* a future release.
*/
export default class ScrollbarTool extends BaseTool {
constructor(editor) {
super(editor.notifier, 'scrollbar');
this.editor = editor;
this.fadeOutTimeout = null;
this.scrollbarOverlay = document.createElement('div');
this.scrollbarOverlay.classList.add('ScrollbarTool-overlay');
this.verticalScrollbar = document.createElement('div');
this.verticalScrollbar.classList.add('vertical-scrollbar');
this.horizontalScrollbar = document.createElement('div');
this.horizontalScrollbar.classList.add('horizontal-scrollbar');
this.scrollbarOverlay.replaceChildren(this.verticalScrollbar, this.horizontalScrollbar);
let overlay = null;
let viewportListener = null;
this.enabledValue().onUpdateAndNow((enabled) => {
overlay?.remove();
viewportListener?.remove();
viewportListener = null;
overlay = null;
if (enabled) {
viewportListener = editor.notifier.on(EditorEventType.ViewportChanged, (_event) => {
this.updateScrollbars();
});
this.updateScrollbars();
overlay = editor.createHTMLOverlay(this.scrollbarOverlay);
}
});
}
updateScrollbars() {
const viewport = this.editor.viewport;
const screenSize = viewport.getScreenRectSize();
const screenRect = new Rect2(0, 0, screenSize.x, screenSize.y);
const imageRect = this.editor
.getImportExportRect()
// The scrollbars are positioned in screen coordinates, so the exportRect also needs
// to be in screen coordinates
.transformedBoundingBox(viewport.canvasToScreenTransform)
// If the screenRect is outside of the exportRect, expand the image rectangle
.union(screenRect);
const scrollbarWidth = (screenRect.width / imageRect.width) * screenSize.x;
const scrollbarHeight = (screenRect.height / imageRect.height) * screenSize.y;
const scrollbarX = ((screenRect.x - imageRect.x) / imageRect.width) * screenSize.x;
const scrollbarY = ((screenRect.y - imageRect.y) / imageRect.height) * screenSize.y;
this.horizontalScrollbar.style.width = `${scrollbarWidth}px`;
this.verticalScrollbar.style.height = `${scrollbarHeight}px`;
this.horizontalScrollbar.style.marginLeft = `${scrollbarX}px`;
this.verticalScrollbar.style.marginTop = `${scrollbarY}px`;
// Style the scrollbars differently when there's no scroll (all content visible)
const handleNoScrollStyling = (scrollbar, size, fillSize) => {
const fillsWindowClass = 'represents-no-scroll';
if (Math.abs(size - fillSize) < 1e-8) {
scrollbar.classList.add(fillsWindowClass);
}
else {
scrollbar.classList.remove(fillsWindowClass);
}
};
handleNoScrollStyling(this.horizontalScrollbar, scrollbarWidth, screenSize.x);
handleNoScrollStyling(this.verticalScrollbar, scrollbarHeight, screenSize.y);
// Fade out after a delay.
if (this.fadeOutTimeout !== null) {
clearTimeout(this.fadeOutTimeout);
}
const fadeOutDelay = 3000;
this.fadeOutTimeout = setTimeout(() => {
this.scrollbarOverlay.classList.remove('just-updated');
}, fadeOutDelay);
this.scrollbarOverlay.classList.add('just-updated');
}
}