UNPKG

11.9 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = function (d, b) {
4 extendStatics = Object.setPrototypeOf ||
5 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7 return extendStatics(d, b);
8 };
9 return function (d, b) {
10 extendStatics(d, b);
11 function __() { this.constructor = d; }
12 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13 };
14})();
15var __importDefault = (this && this.__importDefault) || function (mod) {
16 return (mod && mod.__esModule) ? mod : { "default": mod };
17};
18Object.defineProperty(exports, "__esModule", { value: true });
19/**
20 * Sigma.js Mouse Captor
21 * ======================
22 *
23 * Sigma's captor dealing with the user's mouse.
24 */
25var camera_1 = __importDefault(require("../camera"));
26var captor_1 = __importDefault(require("../captor"));
27var utils_1 = require("./utils");
28/**
29 * Constants.
30 */
31var DRAG_TIMEOUT = 200;
32var MOUSE_INERTIA_DURATION = 200;
33var MOUSE_INERTIA_RATIO = 3;
34var MOUSE_ZOOM_DURATION = 200;
35var ZOOMING_RATIO = 1.7;
36var DOUBLE_CLICK_TIMEOUT = 300;
37var DOUBLE_CLICK_ZOOMING_RATIO = 2.2;
38var DOUBLE_CLICK_ZOOMING_DURATION = 200;
39/**
40 * Mouse captor class.
41 *
42 * @constructor
43 */
44var MouseCaptor = /** @class */ (function (_super) {
45 __extends(MouseCaptor, _super);
46 function MouseCaptor(container, camera) {
47 var _this = _super.call(this, container, camera) || this;
48 // State
49 _this.enabled = true;
50 _this.hasDragged = false;
51 _this.downStartTime = null;
52 _this.lastMouseX = null;
53 _this.lastMouseY = null;
54 _this.isMouseDown = false;
55 _this.isMoving = null;
56 _this.movingTimeout = null;
57 _this.startCameraState = null;
58 _this.lastCameraState = null;
59 _this.clicks = 0;
60 _this.doubleClickTimeout = null;
61 _this.wheelLock = false;
62 // Binding methods
63 _this.handleClick = _this.handleClick.bind(_this);
64 _this.handleRightClick = _this.handleRightClick.bind(_this);
65 _this.handleDown = _this.handleDown.bind(_this);
66 _this.handleUp = _this.handleUp.bind(_this);
67 _this.handleMove = _this.handleMove.bind(_this);
68 _this.handleWheel = _this.handleWheel.bind(_this);
69 _this.handleOut = _this.handleOut.bind(_this);
70 // Binding events
71 container.addEventListener("click", _this.handleClick, false);
72 container.addEventListener("contextmenu", _this.handleRightClick, false);
73 container.addEventListener("mousedown", _this.handleDown, false);
74 container.addEventListener("mousemove", _this.handleMove, false);
75 container.addEventListener("DOMMouseScroll", _this.handleWheel, false);
76 container.addEventListener("mousewheel", _this.handleWheel, false);
77 container.addEventListener("mouseout", _this.handleOut, false);
78 document.addEventListener("mouseup", _this.handleUp, false);
79 return _this;
80 }
81 MouseCaptor.prototype.kill = function () {
82 var container = this.container;
83 container.removeEventListener("click", this.handleClick);
84 container.removeEventListener("contextmenu", this.handleRightClick);
85 container.removeEventListener("mousedown", this.handleDown);
86 container.removeEventListener("mousemove", this.handleMove);
87 container.removeEventListener("DOMMouseScroll", this.handleWheel);
88 container.removeEventListener("mousewheel", this.handleWheel);
89 container.removeEventListener("mouseout", this.handleOut);
90 document.removeEventListener("mouseup", this.handleUp);
91 };
92 MouseCaptor.prototype.handleClick = function (e) {
93 var _this = this;
94 if (!this.enabled)
95 return;
96 this.clicks++;
97 if (this.clicks === 2) {
98 this.clicks = 0;
99 clearTimeout(this.doubleClickTimeout);
100 this.doubleClickTimeout = null;
101 return this.handleDoubleClick(e);
102 }
103 setTimeout(function () {
104 _this.clicks = 0;
105 _this.doubleClickTimeout = null;
106 }, DOUBLE_CLICK_TIMEOUT);
107 // NOTE: this is here to prevent click events on drag
108 if (!this.hasDragged)
109 this.emit("click", utils_1.getMouseCoords(e));
110 };
111 MouseCaptor.prototype.handleRightClick = function (e) {
112 if (!this.enabled)
113 return;
114 this.emit("rightClick", utils_1.getMouseCoords(e));
115 };
116 MouseCaptor.prototype.handleDoubleClick = function (e) {
117 if (!this.enabled)
118 return;
119 var center = utils_1.getCenter(e);
120 var cameraState = this.camera.getState();
121 var newRatio = cameraState.ratio / DOUBLE_CLICK_ZOOMING_RATIO;
122 // TODO: factorize
123 var dimensions = {
124 width: this.container.offsetWidth,
125 height: this.container.offsetHeight,
126 };
127 var clickX = utils_1.getX(e), clickY = utils_1.getY(e);
128 // TODO: baaaad we mustn't mutate the camera, create a Camera.from or #.copy
129 // TODO: factorize pan & zoomTo
130 var cameraWithNewRatio = new camera_1.default();
131 cameraWithNewRatio.ratio = newRatio;
132 cameraWithNewRatio.x = cameraState.x;
133 cameraWithNewRatio.y = cameraState.y;
134 var clickGraph = this.camera.viewportToGraph(dimensions, clickX, clickY), centerGraph = this.camera.viewportToGraph(dimensions, center.x, center.y);
135 var clickGraphNew = cameraWithNewRatio.viewportToGraph(dimensions, clickX, clickY), centerGraphNew = cameraWithNewRatio.viewportToGraph(dimensions, center.x, center.y);
136 var deltaX = clickGraphNew.x - centerGraphNew.x - clickGraph.x + centerGraph.x, deltaY = clickGraphNew.y - centerGraphNew.y - clickGraph.y + centerGraph.y;
137 this.camera.animate({
138 x: cameraState.x - deltaX,
139 y: cameraState.y - deltaY,
140 ratio: newRatio,
141 }, {
142 easing: "quadraticInOut",
143 duration: DOUBLE_CLICK_ZOOMING_DURATION,
144 });
145 if (e.preventDefault)
146 e.preventDefault();
147 else
148 e.returnValue = false;
149 e.stopPropagation();
150 return false;
151 };
152 MouseCaptor.prototype.handleDown = function (e) {
153 if (!this.enabled)
154 return;
155 this.startCameraState = this.camera.getState();
156 this.lastCameraState = this.startCameraState;
157 this.lastMouseX = utils_1.getX(e);
158 this.lastMouseY = utils_1.getY(e);
159 this.hasDragged = false;
160 this.downStartTime = Date.now();
161 // TODO: dispatch events
162 switch (e.which) {
163 default:
164 // Left button pressed
165 this.isMouseDown = true;
166 this.emit("mousedown", utils_1.getMouseCoords(e));
167 }
168 };
169 MouseCaptor.prototype.handleUp = function (e) {
170 var _this = this;
171 if (!this.enabled || !this.isMouseDown)
172 return;
173 this.isMouseDown = false;
174 if (this.movingTimeout) {
175 this.movingTimeout = null;
176 clearTimeout(this.movingTimeout);
177 }
178 var x = utils_1.getX(e), y = utils_1.getY(e);
179 var cameraState = this.camera.getState(), previousCameraState = this.camera.getPreviousState();
180 if (this.isMoving) {
181 this.camera.animate({
182 x: cameraState.x + MOUSE_INERTIA_RATIO * (cameraState.x - previousCameraState.x),
183 y: cameraState.y + MOUSE_INERTIA_RATIO * (cameraState.y - previousCameraState.y),
184 }, {
185 duration: MOUSE_INERTIA_DURATION,
186 easing: "quadraticOut",
187 });
188 }
189 else if (this.lastMouseX !== x || this.lastMouseY !== y) {
190 this.camera.setState({
191 x: cameraState.x,
192 y: cameraState.y,
193 });
194 }
195 this.isMoving = false;
196 setImmediate(function () { return (_this.hasDragged = false); });
197 this.emit("mouseup", utils_1.getMouseCoords(e));
198 };
199 MouseCaptor.prototype.handleMove = function (e) {
200 var _this = this;
201 if (!this.enabled)
202 return;
203 this.emit("mousemove", utils_1.getMouseCoords(e));
204 if (this.isMouseDown) {
205 // TODO: dispatch events
206 this.isMoving = true;
207 this.hasDragged = true;
208 if (this.movingTimeout)
209 clearTimeout(this.movingTimeout);
210 this.movingTimeout = window.setTimeout(function () {
211 _this.movingTimeout = null;
212 _this.isMoving = false;
213 }, DRAG_TIMEOUT);
214 var dimensions = {
215 width: this.container.offsetWidth,
216 height: this.container.offsetHeight,
217 };
218 var eX = utils_1.getX(e), eY = utils_1.getY(e);
219 var lastMouse = this.camera.viewportToGraph(dimensions, this.lastMouseX, this.lastMouseY);
220 var mouse = this.camera.viewportToGraph(dimensions, eX, eY);
221 var offsetX = lastMouse.x - mouse.x, offsetY = lastMouse.y - mouse.y;
222 var cameraState = this.camera.getState();
223 var x = cameraState.x + offsetX, y = cameraState.y + offsetY;
224 this.camera.setState({ x: x, y: y });
225 this.lastMouseX = eX;
226 this.lastMouseY = eY;
227 }
228 if (e.preventDefault)
229 e.preventDefault();
230 else
231 e.returnValue = false;
232 e.stopPropagation();
233 return false;
234 };
235 MouseCaptor.prototype.handleWheel = function (e) {
236 var _this = this;
237 if (e.preventDefault)
238 e.preventDefault();
239 else
240 e.returnValue = false;
241 e.stopPropagation();
242 if (!this.enabled)
243 return false;
244 var delta = utils_1.getWheelDelta(e);
245 if (!delta)
246 return false;
247 if (this.wheelLock)
248 return false;
249 this.wheelLock = true;
250 // TODO: handle max zoom
251 var ratio = delta > 0 ? 1 / ZOOMING_RATIO : ZOOMING_RATIO;
252 var cameraState = this.camera.getState();
253 var newRatio = ratio * cameraState.ratio;
254 var center = utils_1.getCenter(e);
255 var dimensions = {
256 width: this.container.offsetWidth,
257 height: this.container.offsetHeight,
258 };
259 var clickX = utils_1.getX(e), clickY = utils_1.getY(e);
260 // TODO: baaaad we mustn't mutate the camera, create a Camera.from or #.copy
261 // TODO: factorize pan & zoomTo
262 var cameraWithNewRatio = new camera_1.default();
263 cameraWithNewRatio.ratio = newRatio;
264 cameraWithNewRatio.x = cameraState.x;
265 cameraWithNewRatio.y = cameraState.y;
266 var clickGraph = this.camera.viewportToGraph(dimensions, clickX, clickY), centerGraph = this.camera.viewportToGraph(dimensions, center.x, center.y);
267 var clickGraphNew = cameraWithNewRatio.viewportToGraph(dimensions, clickX, clickY), centerGraphNew = cameraWithNewRatio.viewportToGraph(dimensions, center.x, center.y);
268 var deltaX = clickGraphNew.x - centerGraphNew.x - clickGraph.x + centerGraph.x, deltaY = clickGraphNew.y - centerGraphNew.y - clickGraph.y + centerGraph.y;
269 this.camera.animate({
270 x: cameraState.x - deltaX,
271 y: cameraState.y - deltaY,
272 ratio: newRatio,
273 }, {
274 easing: "linear",
275 duration: MOUSE_ZOOM_DURATION,
276 }, function () { return (_this.wheelLock = false); });
277 return false;
278 };
279 MouseCaptor.prototype.handleOut = function () {
280 // TODO: dispatch event
281 };
282 return MouseCaptor;
283}(captor_1.default));
284exports.default = MouseCaptor;