sprotty
Version:
A next-gen framework for graphical views
238 lines • 11.1 kB
JavaScript
"use strict";
/********************************************************************************
* Copyright (c) 2017-2018 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.findViewportScrollbar = exports.ScrollMouseListener = void 0;
const inversify_1 = require("inversify");
const actions_1 = require("sprotty-protocol/lib/actions");
const geometry_1 = require("sprotty-protocol/lib/utils/geometry");
const smodel_1 = require("../../base/model/smodel");
const mouse_tool_1 = require("../../base/views/mouse-tool");
const smodel_utils_1 = require("../../base/model/smodel-utils");
const model_1 = require("./model");
const model_2 = require("../move/model");
const model_3 = require("../routing/model");
const model_4 = require("../projection/model");
const browser_1 = require("../../utils/browser");
const types_1 = require("../../base/types");
class ScrollMouseListener extends mouse_tool_1.MouseListener {
constructor() {
super(...arguments);
this.scrollbarMouseDownDelay = 200;
}
mouseDown(target, event) {
const moveable = (0, smodel_utils_1.findParentByFeature)(target, model_2.isMoveable);
if (moveable === undefined && !(target instanceof model_3.SRoutingHandleImpl)) {
const viewport = (0, smodel_utils_1.findParentByFeature)(target, model_1.isViewport);
if (viewport) {
this.lastScrollPosition = { x: event.pageX, y: event.pageY };
this.scrollbar = this.getScrollbar(event);
if (this.scrollbar) {
window.clearTimeout(this.scrollbarMouseDownTimeout);
return this.moveScrollBar(viewport, event, this.scrollbar, true)
.map(action => new Promise(resolve => {
this.scrollbarMouseDownTimeout = window.setTimeout(() => resolve(action), this.scrollbarMouseDownDelay);
}));
}
}
else {
this.lastScrollPosition = undefined;
this.scrollbar = undefined;
}
}
return [];
}
mouseMove(target, event) {
if (event.buttons === 0) {
return this.mouseUp(target, event);
}
if (this.scrollbar) {
window.clearTimeout(this.scrollbarMouseDownTimeout);
const viewport = (0, smodel_utils_1.findParentByFeature)(target, model_1.isViewport);
if (viewport) {
return this.moveScrollBar(viewport, event, this.scrollbar);
}
}
if (this.lastScrollPosition) {
const viewport = (0, smodel_utils_1.findParentByFeature)(target, model_1.isViewport);
if (viewport) {
return this.dragCanvas(viewport, event, this.lastScrollPosition);
}
}
return [];
}
mouseEnter(target, event) {
if (target instanceof smodel_1.SModelRootImpl && event.buttons === 0) {
this.mouseUp(target, event);
}
return [];
}
mouseUp(target, event) {
this.lastScrollPosition = undefined;
this.scrollbar = undefined;
return [];
}
doubleClick(target, event) {
const viewport = (0, smodel_utils_1.findParentByFeature)(target, model_1.isViewport);
if (viewport) {
const scrollbar = this.getScrollbar(event);
if (scrollbar) {
window.clearTimeout(this.scrollbarMouseDownTimeout);
const targetElement = this.findClickTarget(scrollbar, event);
let elementId;
if (targetElement && targetElement.id.startsWith('horizontal-projection:')) {
elementId = targetElement.id.substring('horizontal-projection:'.length);
}
else if (targetElement && targetElement.id.startsWith('vertical-projection:')) {
elementId = targetElement.id.substring('vertical-projection:'.length);
}
if (elementId) {
return [actions_1.CenterAction.create([elementId], { animate: true, retainZoom: true })];
}
}
}
return [];
}
dragCanvas(model, event, lastScrollPosition) {
let dx = (event.pageX - lastScrollPosition.x) / model.zoom;
if (dx > 0 && (0, geometry_1.almostEquals)(model.scroll.x, this.viewerOptions.horizontalScrollLimits.min)
|| dx < 0 && (0, geometry_1.almostEquals)(model.scroll.x, this.viewerOptions.horizontalScrollLimits.max - model.canvasBounds.width / model.zoom)) {
dx = 0;
}
let dy = (event.pageY - lastScrollPosition.y) / model.zoom;
if (dy > 0 && (0, geometry_1.almostEquals)(model.scroll.y, this.viewerOptions.verticalScrollLimits.min)
|| dy < 0 && (0, geometry_1.almostEquals)(model.scroll.y, this.viewerOptions.verticalScrollLimits.max - model.canvasBounds.height / model.zoom)) {
dy = 0;
}
if (dx === 0 && dy === 0) {
return [];
}
const newViewport = {
scroll: {
x: model.scroll.x - dx,
y: model.scroll.y - dy,
},
zoom: model.zoom
};
this.lastScrollPosition = { x: event.pageX, y: event.pageY };
return [actions_1.SetViewportAction.create(model.id, newViewport, { animate: false })];
}
moveScrollBar(model, event, scrollbar, animate = false) {
const modelBounds = (0, model_4.getModelBounds)(model);
if (!modelBounds || model.zoom <= 0) {
return [];
}
const scrollbarRect = scrollbar.getBoundingClientRect();
let newScroll;
if (this.getScrollbarOrientation(scrollbar) === 'horizontal') {
if (scrollbarRect.width <= 0) {
return [];
}
const viewportSize = (model.canvasBounds.width / (model.zoom * modelBounds.width)) * scrollbarRect.width;
let position = event.clientX - scrollbarRect.x - viewportSize / 2;
if (position < 0) {
position = 0;
}
else if (position > scrollbarRect.width - viewportSize) {
position = scrollbarRect.width - viewportSize;
}
newScroll = {
x: modelBounds.x + (position / scrollbarRect.width) * modelBounds.width,
y: model.scroll.y
};
if (newScroll.x < this.viewerOptions.horizontalScrollLimits.min) {
newScroll.x = this.viewerOptions.horizontalScrollLimits.min;
}
else if (newScroll.x > this.viewerOptions.horizontalScrollLimits.max - model.canvasBounds.width / model.zoom) {
newScroll.x = this.viewerOptions.horizontalScrollLimits.max - model.canvasBounds.width / model.zoom;
}
if ((0, geometry_1.almostEquals)(newScroll.x, model.scroll.x)) {
return [];
}
}
else {
if (scrollbarRect.height <= 0) {
return [];
}
const viewportSize = (model.canvasBounds.height / (model.zoom * modelBounds.height)) * scrollbarRect.height;
let position = event.clientY - scrollbarRect.y - viewportSize / 2;
if (position < 0) {
position = 0;
}
else if (position > scrollbarRect.height - viewportSize) {
position = scrollbarRect.height - viewportSize;
}
newScroll = {
x: model.scroll.x,
y: modelBounds.y + (position / scrollbarRect.height) * modelBounds.height
};
if (newScroll.y < this.viewerOptions.verticalScrollLimits.min) {
newScroll.y = this.viewerOptions.verticalScrollLimits.min;
}
else if (newScroll.y > this.viewerOptions.verticalScrollLimits.max - model.canvasBounds.height / model.zoom) {
newScroll.y = this.viewerOptions.verticalScrollLimits.max - model.canvasBounds.height / model.zoom;
}
if ((0, geometry_1.almostEquals)(newScroll.y, model.scroll.y)) {
return [];
}
}
return [actions_1.SetViewportAction.create(model.id, { scroll: newScroll, zoom: model.zoom }, { animate })];
}
getScrollbar(event) {
return findViewportScrollbar(event);
}
getScrollbarOrientation(scrollbar) {
if (scrollbar.classList.contains('horizontal')) {
return 'horizontal';
}
else {
return 'vertical';
}
}
findClickTarget(scrollbar, event) {
const matching = Array.from(scrollbar.children).filter(child => child.id && child.classList.contains('sprotty-projection') && (0, browser_1.hitsMouseEvent)(child, event));
if (matching.length > 0) {
return matching[matching.length - 1];
}
return undefined;
}
}
exports.ScrollMouseListener = ScrollMouseListener;
__decorate([
(0, inversify_1.inject)(types_1.TYPES.ViewerOptions),
__metadata("design:type", Object)
], ScrollMouseListener.prototype, "viewerOptions", void 0);
function findViewportScrollbar(event) {
let element = event.target;
while (element) {
if (element.classList && element.classList.contains('sprotty-projection-bar')) {
return element;
}
element = element.parentElement;
}
return undefined;
}
exports.findViewportScrollbar = findViewportScrollbar;
//# sourceMappingURL=scroll.js.map