UNPKG

15.7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.EventListeners = void 0;
4const Enums_1 = require("../Enums");
5const Constants_1 = require("./Constants");
6const Utils_1 = require("./Utils");
7function manageListener(element, event, handler, add, options) {
8 if (add) {
9 let addOptions = { passive: true };
10 if (typeof options === "boolean") {
11 addOptions.capture = options;
12 }
13 else if (options !== undefined) {
14 addOptions = options;
15 }
16 element.addEventListener(event, handler, addOptions);
17 }
18 else {
19 const removeOptions = options;
20 element.removeEventListener(event, handler, removeOptions);
21 }
22}
23class EventListeners {
24 constructor(container) {
25 this.container = container;
26 this.canPush = true;
27 this.mouseMoveHandler = (e) => this.mouseTouchMove(e);
28 this.touchStartHandler = (e) => this.mouseTouchMove(e);
29 this.touchMoveHandler = (e) => this.mouseTouchMove(e);
30 this.touchEndHandler = () => this.mouseTouchFinish();
31 this.mouseLeaveHandler = () => this.mouseTouchFinish();
32 this.touchCancelHandler = () => this.mouseTouchFinish();
33 this.touchEndClickHandler = (e) => this.mouseTouchClick(e);
34 this.mouseUpHandler = (e) => this.mouseTouchClick(e);
35 this.mouseDownHandler = () => this.mouseDown();
36 this.visibilityChangeHandler = () => this.handleVisibilityChange();
37 this.themeChangeHandler = (e) => this.handleThemeChange(e);
38 this.resizeHandler = () => this.handleWindowResize();
39 }
40 addListeners() {
41 this.manageListeners(true);
42 }
43 removeListeners() {
44 this.manageListeners(false);
45 }
46 manageListeners(add) {
47 var _a;
48 const container = this.container;
49 const options = container.actualOptions;
50 const detectType = options.interactivity.detectsOn;
51 let mouseLeaveEvent = Constants_1.Constants.mouseLeaveEvent;
52 if (detectType === Enums_1.InteractivityDetect.window) {
53 container.interactivity.element = window;
54 mouseLeaveEvent = Constants_1.Constants.mouseOutEvent;
55 }
56 else if (detectType === Enums_1.InteractivityDetect.parent && container.canvas.element) {
57 const canvasEl = container.canvas.element;
58 container.interactivity.element = (_a = canvasEl.parentElement) !== null && _a !== void 0 ? _a : canvasEl.parentNode;
59 }
60 else {
61 container.interactivity.element = container.canvas.element;
62 }
63 const mediaMatch = typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)");
64 if (mediaMatch) {
65 manageListener(mediaMatch, "change", this.themeChangeHandler, add);
66 }
67 const interactivityEl = container.interactivity.element;
68 if (!interactivityEl) {
69 return;
70 }
71 const html = interactivityEl;
72 if (options.interactivity.events.onHover.enable || options.interactivity.events.onClick.enable) {
73 manageListener(interactivityEl, Constants_1.Constants.mouseMoveEvent, this.mouseMoveHandler, add);
74 manageListener(interactivityEl, Constants_1.Constants.touchStartEvent, this.touchStartHandler, add);
75 manageListener(interactivityEl, Constants_1.Constants.touchMoveEvent, this.touchMoveHandler, add);
76 if (!options.interactivity.events.onClick.enable) {
77 manageListener(interactivityEl, Constants_1.Constants.touchEndEvent, this.touchEndHandler, add);
78 }
79 else {
80 manageListener(interactivityEl, Constants_1.Constants.touchEndEvent, this.touchEndClickHandler, add);
81 manageListener(interactivityEl, Constants_1.Constants.mouseUpEvent, this.mouseUpHandler, add);
82 manageListener(interactivityEl, Constants_1.Constants.mouseDownEvent, this.mouseDownHandler, add);
83 }
84 manageListener(interactivityEl, mouseLeaveEvent, this.mouseLeaveHandler, add);
85 manageListener(interactivityEl, Constants_1.Constants.touchCancelEvent, this.touchCancelHandler, add);
86 }
87 if (container.canvas.element) {
88 container.canvas.element.style.pointerEvents = html === container.canvas.element ? "initial" : "none";
89 }
90 if (options.interactivity.events.resize) {
91 if (typeof ResizeObserver !== "undefined") {
92 if (this.resizeObserver && !add) {
93 if (container.canvas.element) {
94 this.resizeObserver.unobserve(container.canvas.element);
95 }
96 this.resizeObserver.disconnect();
97 delete this.resizeObserver;
98 }
99 else if (!this.resizeObserver && add && container.canvas.element) {
100 this.resizeObserver = new ResizeObserver((entries) => {
101 const entry = entries.find((e) => e.target === container.canvas.element);
102 if (!entry) {
103 return;
104 }
105 this.handleWindowResize();
106 });
107 this.resizeObserver.observe(container.canvas.element);
108 }
109 }
110 else {
111 manageListener(window, Constants_1.Constants.resizeEvent, this.resizeHandler, add);
112 }
113 }
114 if (document) {
115 manageListener(document, Constants_1.Constants.visibilityChangeEvent, this.visibilityChangeHandler, add, false);
116 }
117 }
118 handleWindowResize() {
119 if (this.resizeTimeout) {
120 clearTimeout(this.resizeTimeout);
121 delete this.resizeTimeout;
122 }
123 this.resizeTimeout = setTimeout(() => { var _a; return (_a = this.container.canvas) === null || _a === void 0 ? void 0 : _a.windowResize(); }, 500);
124 }
125 handleVisibilityChange() {
126 const container = this.container;
127 const options = container.actualOptions;
128 this.mouseTouchFinish();
129 if (!options.pauseOnBlur) {
130 return;
131 }
132 if (document === null || document === void 0 ? void 0 : document.hidden) {
133 container.pageHidden = true;
134 container.pause();
135 }
136 else {
137 container.pageHidden = false;
138 if (container.getAnimationStatus()) {
139 container.play(true);
140 }
141 else {
142 container.draw(true);
143 }
144 }
145 }
146 mouseDown() {
147 const interactivity = this.container.interactivity;
148 if (interactivity) {
149 const mouse = interactivity.mouse;
150 mouse.clicking = true;
151 mouse.downPosition = mouse.position;
152 }
153 }
154 mouseTouchMove(e) {
155 var _a, _b, _c, _d, _e, _f, _g;
156 const container = this.container;
157 const options = container.actualOptions;
158 if (((_a = container.interactivity) === null || _a === void 0 ? void 0 : _a.element) === undefined) {
159 return;
160 }
161 container.interactivity.mouse.inside = true;
162 let pos;
163 const canvas = container.canvas.element;
164 if (e.type.startsWith("mouse")) {
165 this.canPush = true;
166 const mouseEvent = e;
167 if (container.interactivity.element === window) {
168 if (canvas) {
169 const clientRect = canvas.getBoundingClientRect();
170 pos = {
171 x: mouseEvent.clientX - clientRect.left,
172 y: mouseEvent.clientY - clientRect.top,
173 };
174 }
175 }
176 else if (options.interactivity.detectsOn === Enums_1.InteractivityDetect.parent) {
177 const source = mouseEvent.target;
178 const target = mouseEvent.currentTarget;
179 const canvasEl = container.canvas.element;
180 if (source && target && canvasEl) {
181 const sourceRect = source.getBoundingClientRect();
182 const targetRect = target.getBoundingClientRect();
183 const canvasRect = canvasEl.getBoundingClientRect();
184 pos = {
185 x: mouseEvent.offsetX + 2 * sourceRect.left - (targetRect.left + canvasRect.left),
186 y: mouseEvent.offsetY + 2 * sourceRect.top - (targetRect.top + canvasRect.top),
187 };
188 }
189 else {
190 pos = {
191 x: (_b = mouseEvent.offsetX) !== null && _b !== void 0 ? _b : mouseEvent.clientX,
192 y: (_c = mouseEvent.offsetY) !== null && _c !== void 0 ? _c : mouseEvent.clientY,
193 };
194 }
195 }
196 else {
197 if (mouseEvent.target === container.canvas.element) {
198 pos = {
199 x: (_d = mouseEvent.offsetX) !== null && _d !== void 0 ? _d : mouseEvent.clientX,
200 y: (_e = mouseEvent.offsetY) !== null && _e !== void 0 ? _e : mouseEvent.clientY,
201 };
202 }
203 }
204 }
205 else {
206 this.canPush = e.type !== "touchmove";
207 const touchEvent = e;
208 const lastTouch = touchEvent.touches[touchEvent.touches.length - 1];
209 const canvasRect = canvas === null || canvas === void 0 ? void 0 : canvas.getBoundingClientRect();
210 pos = {
211 x: lastTouch.clientX - ((_f = canvasRect === null || canvasRect === void 0 ? void 0 : canvasRect.left) !== null && _f !== void 0 ? _f : 0),
212 y: lastTouch.clientY - ((_g = canvasRect === null || canvasRect === void 0 ? void 0 : canvasRect.top) !== null && _g !== void 0 ? _g : 0),
213 };
214 }
215 const pxRatio = container.retina.pixelRatio;
216 if (pos) {
217 pos.x *= pxRatio;
218 pos.y *= pxRatio;
219 }
220 container.interactivity.mouse.position = pos;
221 container.interactivity.status = Constants_1.Constants.mouseMoveEvent;
222 }
223 mouseTouchFinish() {
224 const interactivity = this.container.interactivity;
225 if (interactivity === undefined) {
226 return;
227 }
228 const mouse = interactivity.mouse;
229 delete mouse.position;
230 delete mouse.clickPosition;
231 delete mouse.downPosition;
232 interactivity.status = Constants_1.Constants.mouseLeaveEvent;
233 mouse.inside = false;
234 mouse.clicking = false;
235 }
236 mouseTouchClick(e) {
237 const container = this.container;
238 const options = container.actualOptions;
239 const mouse = container.interactivity.mouse;
240 mouse.inside = true;
241 let handled = false;
242 const mousePosition = mouse.position;
243 if (mousePosition === undefined || !options.interactivity.events.onClick.enable) {
244 return;
245 }
246 for (const [, plugin] of container.plugins) {
247 if (plugin.clickPositionValid !== undefined) {
248 handled = plugin.clickPositionValid(mousePosition);
249 if (handled) {
250 break;
251 }
252 }
253 }
254 if (!handled) {
255 this.doMouseTouchClick(e);
256 }
257 mouse.clicking = false;
258 }
259 doMouseTouchClick(e) {
260 const container = this.container;
261 const options = container.actualOptions;
262 if (this.canPush) {
263 const mousePos = container.interactivity.mouse.position;
264 if (mousePos) {
265 container.interactivity.mouse.clickPosition = {
266 x: mousePos.x,
267 y: mousePos.y,
268 };
269 }
270 else {
271 return;
272 }
273 container.interactivity.mouse.clickTime = new Date().getTime();
274 const onClick = options.interactivity.events.onClick;
275 if (onClick.mode instanceof Array) {
276 for (const mode of onClick.mode) {
277 this.handleClickMode(mode);
278 }
279 }
280 else {
281 this.handleClickMode(onClick.mode);
282 }
283 }
284 if (e.type === "touchend") {
285 setTimeout(() => this.mouseTouchFinish(), 500);
286 }
287 }
288 handleThemeChange(e) {
289 const mediaEvent = e;
290 const themeName = mediaEvent.matches
291 ? this.container.options.defaultDarkTheme
292 : this.container.options.defaultLightTheme;
293 const theme = this.container.options.themes.find((theme) => theme.name === themeName);
294 if (theme && theme.default.auto) {
295 this.container.loadTheme(themeName);
296 }
297 }
298 handleClickMode(mode) {
299 const container = this.container;
300 const options = container.actualOptions;
301 const pushNb = options.interactivity.modes.push.quantity;
302 const removeNb = options.interactivity.modes.remove.quantity;
303 switch (mode) {
304 case Enums_1.ClickMode.push: {
305 if (pushNb > 0) {
306 const pushOptions = options.interactivity.modes.push;
307 const group = (0, Utils_1.itemFromArray)([undefined, ...pushOptions.groups]);
308 const groupOptions = group !== undefined ? container.actualOptions.particles.groups[group] : undefined;
309 container.particles.push(pushNb, container.interactivity.mouse, groupOptions, group);
310 }
311 break;
312 }
313 case Enums_1.ClickMode.remove:
314 container.particles.removeQuantity(removeNb);
315 break;
316 case Enums_1.ClickMode.bubble:
317 container.bubble.clicking = true;
318 break;
319 case Enums_1.ClickMode.repulse:
320 container.repulse.clicking = true;
321 container.repulse.count = 0;
322 for (const particle of container.repulse.particles) {
323 particle.velocity.setTo(particle.initialVelocity);
324 }
325 container.repulse.particles = [];
326 container.repulse.finish = false;
327 setTimeout(() => {
328 if (!container.destroyed) {
329 container.repulse.clicking = false;
330 }
331 }, options.interactivity.modes.repulse.duration * 1000);
332 break;
333 case Enums_1.ClickMode.attract:
334 container.attract.clicking = true;
335 container.attract.count = 0;
336 for (const particle of container.attract.particles) {
337 particle.velocity.setTo(particle.initialVelocity);
338 }
339 container.attract.particles = [];
340 container.attract.finish = false;
341 setTimeout(() => {
342 if (!container.destroyed) {
343 container.attract.clicking = false;
344 }
345 }, options.interactivity.modes.attract.duration * 1000);
346 break;
347 case Enums_1.ClickMode.pause:
348 if (container.getAnimationStatus()) {
349 container.pause();
350 }
351 else {
352 container.play();
353 }
354 break;
355 }
356 for (const [, plugin] of container.plugins) {
357 if (plugin.handleClickMode) {
358 plugin.handleClickMode(mode);
359 }
360 }
361 }
362}
363exports.EventListeners = EventListeners;