@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering.
208 lines (182 loc) • 5.53 kB
text/typescript
import { ModifierKey } from '../types'
import { Dom } from '../util'
import { Base } from './base'
export class PanningManager extends Base {
private panning: boolean
private clientX: number
private clientY: number
private mousewheelHandle: Dom.MouseWheelHandle
protected get widgetOptions() {
return this.options.panning
}
get pannable() {
return this.widgetOptions && this.widgetOptions.enabled === true
}
protected init() {
this.startListening()
this.updateClassName()
}
protected startListening() {
const eventTypes = this.widgetOptions.eventTypes
if (!eventTypes) {
return
}
if (eventTypes.includes('leftMouseDown')) {
this.graph.on('blank:mousedown', this.preparePanning, this)
this.graph.on('node:unhandled:mousedown', this.preparePanning, this)
this.graph.on('edge:unhandled:mousedown', this.preparePanning, this)
}
if (eventTypes.includes('rightMouseDown')) {
this.onRightMouseDown = this.onRightMouseDown.bind(this)
this.view.$(this.graph.container).on('mousedown', this.onRightMouseDown)
}
if (eventTypes.includes('mouseWheel')) {
this.mousewheelHandle = new Dom.MouseWheelHandle(
this.graph.container,
this.onMouseWheel.bind(this),
this.allowMouseWheel.bind(this),
)
this.mousewheelHandle.enable()
}
}
protected stopListening() {
const eventTypes = this.widgetOptions.eventTypes
if (!eventTypes) {
return
}
if (eventTypes.includes('leftMouseDown')) {
this.graph.off('blank:mousedown', this.preparePanning, this)
this.graph.off('node:unhandled:mousedown', this.preparePanning, this)
this.graph.off('edge:unhandled:mousedown', this.preparePanning, this)
}
if (eventTypes.includes('rightMouseDown')) {
this.view.$(this.graph.container).off('mousedown', this.onRightMouseDown)
}
if (eventTypes.includes('mouseWheel')) {
if (this.mousewheelHandle) {
this.mousewheelHandle.disable()
}
}
}
protected preparePanning({ e }: { e: JQuery.MouseDownEvent }) {
if (
this.allowPanning(e, true) ||
(this.allowPanning(e) && !this.graph.selection.allowRubberband(e, true))
) {
this.startPanning(e)
}
}
allowPanning(e: JQuery.MouseDownEvent, strict?: boolean) {
return (
this.pannable &&
ModifierKey.isMatch(e, this.widgetOptions.modifiers, strict) &&
this.graph.hook.allowPanning(e)
)
}
protected startPanning(evt: JQuery.MouseDownEvent) {
const e = this.view.normalizeEvent(evt)
this.clientX = e.clientX
this.clientY = e.clientY
this.panning = true
this.updateClassName()
this.view.$(document.body).on({
'mousemove.panning touchmove.panning': this.pan.bind(this),
'mouseup.panning touchend.panning': this.stopPanning.bind(this),
})
this.view.$(window).on('mouseup.panning', this.stopPanning.bind(this))
}
protected pan(evt: JQuery.MouseMoveEvent) {
const e = this.view.normalizeEvent(evt)
const dx = e.clientX - this.clientX
const dy = e.clientY - this.clientY
this.clientX = e.clientX
this.clientY = e.clientY
this.graph.translateBy(dx, dy)
}
// eslint-disable-next-line
protected stopPanning(e: JQuery.MouseUpEvent) {
this.panning = false
this.updateClassName()
this.view.$(document.body).off('.panning')
this.view.$(window).off('.panning')
}
protected updateClassName() {
const container = this.view.container
const panning = this.view.prefixClassName('graph-panning')
const pannable = this.view.prefixClassName('graph-pannable')
if (this.pannable) {
if (this.panning) {
Dom.addClass(container, panning)
Dom.removeClass(container, pannable)
} else {
Dom.removeClass(container, panning)
Dom.addClass(container, pannable)
}
} else {
Dom.removeClass(container, panning)
Dom.removeClass(container, pannable)
}
}
protected onRightMouseDown(e: JQuery.MouseDownEvent) {
if (e.button === 2 && this.allowPanning(e, true)) {
this.startPanning(e)
}
}
protected allowMouseWheel(e: JQueryMousewheel.JQueryMousewheelEventObject) {
return this.pannable && !e.ctrlKey
}
protected onMouseWheel(
e: JQueryMousewheel.JQueryMousewheelEventObject,
deltaX: number,
deltaY: number,
) {
if (!e.ctrlKey) {
this.graph.translateBy(-deltaX, -deltaY)
}
}
autoPanning(x: number, y: number) {
const buffer = 10
const graphArea = this.graph.getGraphArea()
let dx = 0
let dy = 0
if (x <= graphArea.left + buffer) {
dx = -buffer
}
if (y <= graphArea.top + buffer) {
dy = -buffer
}
if (x >= graphArea.right - buffer) {
dx = buffer
}
if (y >= graphArea.bottom - buffer) {
dy = buffer
}
if (dx !== 0 || dy !== 0) {
this.graph.translateBy(-dx, -dy)
}
}
enablePanning() {
if (!this.pannable) {
this.widgetOptions.enabled = true
this.updateClassName()
}
}
disablePanning() {
if (this.pannable) {
this.widgetOptions.enabled = false
this.updateClassName()
}
}
.dispose()
dispose() {
this.stopListening()
}
}
export namespace PanningManager {
type EventType = 'leftMouseDown' | 'rightMouseDown' | 'mouseWheel'
export interface Options {
enabled?: boolean
modifiers?: string | ModifierKey[] | null
eventTypes?: EventType[]
}
}