devexpress-diagram
Version:
DevExpress Diagram Control
134 lines (122 loc) • 5.22 kB
text/typescript
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;
}
}