UNPKG

devexpress-diagram

Version:

DevExpress Diagram Control

134 lines (122 loc) 5.22 kB
import { IScrollView } from "./ScrollView"; import { svgNS } from "./RenderHelper"; import { DomUtils } from "@devexpress/utils/lib/utils/dom"; import { Size } from "@devexpress/utils/lib/geometry/size"; import { CanvasViewManager } from "./CanvasViewManager"; import { IDOMManipulator } from "./DOMManipulator"; import { EventUtils } from "../Utils"; const SCROLL_EDGE = 40; const SCROLL_RATIO = 5; const SCROLL_MAXOFFSET = 5; const SCROLL_DELAY = 50; export class AutoScrollController { private leftButtonPressed = false; private scrollDragging = false; private scrollTimer: number = -1; private readonly scrollBarWidth: number = DomUtils.getVerticalScrollBarWidth(); constructor( private scroll: IScrollView, private svgElement: SVGElement, private view: CanvasViewManager, private dom: IDOMManipulator ) { } onMouseMove(evt: MouseEvent, raiseMouseMoveFunc: () => void) { this.clearScrollTimer(); if(!EventUtils.isLeftButtonPressed(evt)) this.leftButtonPressed = false; if(this.canAutoScroll()) this.changeScrollPosition(evt, raiseMouseMoveFunc, false); } onMouseDown(evt: MouseEvent) { this.leftButtonPressed = !!EventUtils.isLeftButtonPressed(evt); } onMouseUp(evt: MouseEvent) { this.clearScrollTimer(); this.leftButtonPressed = false; } onMouseEnter(evt: MouseEvent) { if(EventUtils.isLeftButtonPressed(evt)) setTimeout(() => { this.leftButtonPressed = true; }, 500); } onDragScrollStart() { this.scrollDragging = true; } onDragScrollEnd() { this.scrollDragging = false; } private canAutoScroll() { return this.leftButtonPressed && !this.scrollDragging; } private changeScrollPosition(evt: MouseEvent, raiseMouseMoveFunc: () => void, raiseMouseMove: boolean) { let changed = false; if(!this.view.isAutoScrollLocked()) { const scrollContainer = this.scroll.getScrollContainer(); const x = evt.pageX - DomUtils.getAbsolutePositionX(scrollContainer); const y = evt.pageY - DomUtils.getAbsolutePositionY(scrollContainer); const size = this.scroll.getSize(); const scrollSize = new Size(parseFloat(this.svgElement.style.width), parseFloat(this.svgElement.style.height)); let width = size.width; if(size.width < scrollSize.width) width -= this.scrollBarWidth; let height = size.height; if(size.height < scrollSize.height) height -= this.scrollBarWidth; if(x <= SCROLL_EDGE) { this.dom.changeByFunc(null, () => { if(!this.view.isAutoScrollLocked()) this.scroll.offsetScroll(-this.getScrollingOffset(x), 0); }); changed = true; } else if(width - SCROLL_EDGE <= x) { this.dom.changeByFunc(null, () => { if(!this.view.isAutoScrollLocked()) this.scroll.offsetScroll(this.getScrollingOffset(width - x), 0); }); changed = true; } if(y <= SCROLL_EDGE) { this.dom.changeByFunc(null, () => { if(!this.view.isAutoScrollLocked()) this.scroll.offsetScroll(0, -this.getScrollingOffset(y)); }); changed = true; } else if(height - SCROLL_EDGE <= y) { this.dom.changeByFunc(null, () => { if(!this.view.isAutoScrollLocked()) this.scroll.offsetScroll(0, this.getScrollingOffset(height - y)); }); changed = true; } } if(changed || this.view.isAutoScrollLocked()) this.scrollTimer = window.setTimeout(() => this.changeScrollPosition(evt, raiseMouseMoveFunc, changed), SCROLL_DELAY); if(raiseMouseMove) raiseMouseMoveFunc(); } private clearScrollTimer() { if(this.scrollTimer > -1) { window.clearTimeout(this.scrollTimer); this.scrollTimer = -1; } } private getScrollingOffset(edgeOffset: number) { const offset = Math.pow((SCROLL_EDGE - edgeOffset) / SCROLL_RATIO, 2); return Math.round(Math.min(offset, SCROLL_MAXOFFSET)); } static createMainElement(parent: HTMLElement): HTMLDivElement { const element = document.createElement("div"); element.setAttribute("class", "dxdi-control"); parent.appendChild(element); return element; } static createSvgElement(parent: HTMLElement, forExport: boolean = false): SVGSVGElement { const svgElement = document.createElementNS(svgNS, "svg"); svgElement.className.baseVal = "dxdi-canvas" + (forExport ? " export" : ""); parent.appendChild(svgElement); return svgElement; } }