UNPKG

6.82 kBJavaScriptView Raw
1"use strict";
2
3// prevent springy scrolling on ios
4document.ontouchmove = function(e) {
5 e.preventDefault();
6};
7
8// prevent right-click on desktop
9window.oncontextmenu = function() {
10 return false;
11};
12
13var relMouseCoords = function(canvas, event) {
14 var x = event.pageX - canvas.offsetLeft + document.body.scrollLeft;
15 var y = event.pageY - canvas.offsetTop + document.body.scrollTop;
16
17 // scale based on ratio of canvas internal dimentions to css dimensions
18 if (canvas.style.width.length) {
19 x *= canvas.width / canvas.style.width.substring(0, canvas.style.width.indexOf("p"));
20 }
21 if (canvas.style.height.length) {
22 y *= canvas.height / canvas.style.height.substring(0, canvas.style.height.indexOf("p"));
23 }
24
25 return {x:x, y:y};
26};
27
28function relMouseCoordsEjecta() {
29 var event = arguments[1];
30 var x = event.pageX * window.devicePixelRatio;
31 var y = event.pageY * window.devicePixelRatio;
32 return {x:x, y:y};
33}
34
35if (window.ejecta) {
36 relMouseCoords = relMouseCoordsEjecta;
37}
38
39/**
40 * Mouse and touch input handling. An instance of Mouse is available as {@link Splat.Game#mouse}.
41 *
42 * The first touch will emulates a mouse press with button 0.
43 * This means you can use the mouse ({@link Mouse#isPressed}/{@link Mouse#consumePressed}) APIs and your game will work on touch screens (as long as you only need the left button.
44 *
45 * A mouse press will emulate a touch if the device does not support touch.
46 * This means you can use {@link Mouse#touches}, and your game will still work on a PC with a mouse.
47 * Also, if you call {@link Mouse#consumePressed} with button 0, it will add a `consumed:true` field to all current touches. This will help you prevent processing a touch multiple times.
48 *
49 * @constructor
50 * @param {external:canvas} canvas The canvas to listen for events on.
51 */
52function Mouse(canvas) {
53 /**
54 * The x coordinate of the cursor relative to the left side of the canvas.
55 * @member {number}
56 */
57 this.x = 0;
58 /**
59 * The y coordinate of the cursor relative to the top of the canvas.
60 * @member {number}
61 */
62 this.y = 0;
63 /**
64 * The current button states.
65 * @member {Array}
66 * @private
67 */
68 this.buttons = [0, 0, 0];
69
70 /**
71 * An array of the current touches on a touch screen device. Each touch has a `x`, `y`, and `id` field.
72 * @member {Array}
73 */
74 this.touches = [];
75
76 var self = this;
77 canvas.addEventListener("mousedown", function(event) {
78 var m = relMouseCoords(canvas, event);
79 self.x = m.x;
80 self.y = m.y;
81 self.buttons[event.button] = 2;
82 updateTouchFromMouse();
83 });
84 canvas.addEventListener("mouseup", function(event) {
85 var m = relMouseCoords(canvas, event);
86 self.x = m.x;
87 self.y = m.y;
88 self.buttons[event.button] = 0;
89 updateTouchFromMouse();
90 });
91 canvas.addEventListener("mousemove", function(event) {
92 var m = relMouseCoords(canvas, event);
93 self.x = m.x;
94 self.y = m.y;
95 updateTouchFromMouse();
96 });
97
98 function updateTouchFromMouse() {
99 if (self.supportsTouch()) {
100 return;
101 }
102 var idx = touchIndexById("mouse");
103 if (self.isPressed(0)) {
104 if (idx !== undefined) {
105 var touch = self.touches[idx];
106 touch.x = self.x;
107 touch.y = self.y;
108 } else {
109 self.touches.push({
110 id: "mouse",
111 x: self.x,
112 y: self.y
113 });
114 }
115 } else if (idx !== undefined) {
116 self.touches.splice(idx, 1);
117 }
118 }
119 function updateMouseFromTouch(touch) {
120 self.x = touch.x;
121 self.y = touch.y;
122 if (self.buttons[0] === 0) {
123 self.buttons[0] = 2;
124 }
125 }
126 function touchIndexById(id) {
127 for (var i = 0; i < self.touches.length; i++) {
128 if (self.touches[i].id === id) {
129 return i;
130 }
131 }
132 return undefined;
133 }
134 function eachChangedTouch(event, onChangeFunc) {
135 var touches = event.changedTouches;
136 for (var i = 0; i < touches.length; i++) {
137 onChangeFunc(touches[i]);
138 }
139 }
140 canvas.addEventListener("touchstart", function(event) {
141 eachChangedTouch(event, function(touch) {
142 var t = relMouseCoords(canvas, touch);
143 t.id = touch.identifier;
144 if (self.touches.length === 0) {
145 t.isMouse = true;
146 updateMouseFromTouch(t);
147 }
148 self.touches.push(t);
149 });
150 });
151 canvas.addEventListener("touchmove", function(event) {
152 eachChangedTouch(event, function(touch) {
153 var idx = touchIndexById(touch.identifier);
154 var t = self.touches[idx];
155 var coords = relMouseCoords(canvas, touch);
156 t.x = coords.x;
157 t.y = coords.y;
158 if (t.isMouse) {
159 updateMouseFromTouch(t);
160 }
161 });
162 });
163 canvas.addEventListener("touchend", function(event) {
164 eachChangedTouch(event, function(touch) {
165 var idx = touchIndexById(touch.identifier);
166 var t = self.touches.splice(idx, 1)[0];
167 if (t.isMouse) {
168 if (self.touches.length === 0) {
169 self.buttons[0] = 0;
170 } else {
171 self.touches[0].isMouse = true;
172 updateMouseFromTouch(self.touches[0]);
173 }
174 }
175 });
176 });
177}
178/**
179 * Test whether the device supports touch events. This is useful to customize messages to say either "click" or "tap".
180 * @returns {boolean}
181 */
182Mouse.prototype.supportsTouch = function() {
183 return "ontouchstart" in window || navigator.msMaxTouchPoints;
184};
185/**
186 * Test if a mouse button is currently pressed.
187 * @param {number} button The button number to test. Button 0 is typically the left mouse button, as well as the first touch location.
188 * @returns {boolean}
189 */
190Mouse.prototype.isPressed = function(button) {
191 return this.buttons[button] >= 1;
192};
193/**
194 * Test if a mouse button is currently pressed, and was newly pressed down since the last call to consumePressed.
195 * If you call this with button 0, it will add a `consumed:true` field to all current touches. This will help you prevent processing a touch multiple times.
196 * @param {number} button The button number to test.
197 * @param {number} [x] The left edge of a rectangle to restrict the test to. If the mouse position is outside of this rectangle, the button will not be considered pressed.
198 * @param {number} [y] The top edge of a rectangle to restrict the test to. If the mouse position is outside of this rectangle, the button will not be considered pressed.
199 * @param {number} [width] The width of a rectangle to restrict the test to. If the mouse position is outside of this rectangle, the button will not be considered pressed.
200 * @param {number} [height] The height of a rectangle to restrict the test to. If the mouse position is outside of this rectangle, the button will not be considered pressed.
201 * @returns {boolean}
202 */
203Mouse.prototype.consumePressed = function(button, x, y, width, height) {
204 var b = this.buttons[button] === 2;
205 if (arguments.length > 1 && (this.x < x || this.x > x + width || this.y < y || this.y > y + height)) {
206 b = false;
207 }
208 if (b) {
209 this.buttons[button] = 1;
210 if (button === 0) {
211 for (var i = 0; i < this.touches.length; i++) {
212 this.touches[i].consumed = true;
213 }
214 }
215 }
216 return b;
217};
218
219module.exports = Mouse;