UNPKG

6.02 kBJavaScriptView Raw
1import { ClickMode, DivMode, DivType, HoverMode } from "../../Enums";
2import { Circle, Constants, NumberUtils, Rectangle, Utils } from "../../Utils";
3import { Vector } from "../../Core/Particle/Vector";
4export class Repulser {
5 constructor(container) {
6 this.container = container;
7 }
8 isEnabled() {
9 const container = this.container;
10 const options = container.actualOptions;
11 const mouse = container.interactivity.mouse;
12 const events = options.interactivity.events;
13 const divs = events.onDiv;
14 const divRepulse = Utils.isDivModeEnabled(DivMode.repulse, divs);
15 if (!(divRepulse || (events.onHover.enable && mouse.position) || (events.onClick.enable && mouse.clickPosition))) {
16 return false;
17 }
18 const hoverMode = events.onHover.mode;
19 const clickMode = events.onClick.mode;
20 return (Utils.isInArray(HoverMode.repulse, hoverMode) || Utils.isInArray(ClickMode.repulse, clickMode) || divRepulse);
21 }
22 reset() {
23 }
24 interact() {
25 const container = this.container;
26 const options = container.actualOptions;
27 const mouseMoveStatus = container.interactivity.status === Constants.mouseMoveEvent;
28 const events = options.interactivity.events;
29 const hoverEnabled = events.onHover.enable;
30 const hoverMode = events.onHover.mode;
31 const clickEnabled = events.onClick.enable;
32 const clickMode = events.onClick.mode;
33 const divs = events.onDiv;
34 if (mouseMoveStatus && hoverEnabled && Utils.isInArray(HoverMode.repulse, hoverMode)) {
35 this.hoverRepulse();
36 }
37 else if (clickEnabled && Utils.isInArray(ClickMode.repulse, clickMode)) {
38 this.clickRepulse();
39 }
40 else {
41 Utils.divModeExecute(DivMode.repulse, divs, (selector, div) => this.singleSelectorRepulse(selector, div));
42 }
43 }
44 singleSelectorRepulse(selector, div) {
45 const container = this.container;
46 const query = document.querySelectorAll(selector);
47 if (!query.length) {
48 return;
49 }
50 query.forEach((item) => {
51 const elem = item;
52 const pxRatio = container.retina.pixelRatio;
53 const pos = {
54 x: (elem.offsetLeft + elem.offsetWidth / 2) * pxRatio,
55 y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
56 };
57 const repulseRadius = (elem.offsetWidth / 2) * pxRatio;
58 const area = div.type === DivType.circle
59 ? new Circle(pos.x, pos.y, repulseRadius)
60 : new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio);
61 const divs = container.actualOptions.interactivity.modes.repulse.divs;
62 const divRepulse = Utils.divMode(divs, elem);
63 this.processRepulse(pos, repulseRadius, area, divRepulse);
64 });
65 }
66 hoverRepulse() {
67 const container = this.container;
68 const mousePos = container.interactivity.mouse.position;
69 if (!mousePos) {
70 return;
71 }
72 const repulseRadius = container.retina.repulseModeDistance;
73 this.processRepulse(mousePos, repulseRadius, new Circle(mousePos.x, mousePos.y, repulseRadius));
74 }
75 processRepulse(position, repulseRadius, area, divRepulse) {
76 var _a;
77 const container = this.container;
78 const query = container.particles.quadTree.query(area);
79 for (const particle of query) {
80 const { dx, dy, distance } = NumberUtils.getDistances(particle.position, position);
81 const normVec = {
82 x: dx / distance,
83 y: dy / distance,
84 };
85 const velocity = ((_a = divRepulse === null || divRepulse === void 0 ? void 0 : divRepulse.speed) !== null && _a !== void 0 ? _a : container.actualOptions.interactivity.modes.repulse.speed) * 100;
86 const repulseFactor = NumberUtils.clamp((1 - Math.pow(distance / repulseRadius, 2)) * velocity, 0, 50);
87 particle.position.x += normVec.x * repulseFactor;
88 particle.position.y += normVec.y * repulseFactor;
89 }
90 }
91 clickRepulse() {
92 const container = this.container;
93 if (!container.repulse.finish) {
94 if (!container.repulse.count) {
95 container.repulse.count = 0;
96 }
97 container.repulse.count++;
98 if (container.repulse.count === container.particles.count) {
99 container.repulse.finish = true;
100 }
101 }
102 if (container.repulse.clicking) {
103 const repulseDistance = container.retina.repulseModeDistance;
104 const repulseRadius = Math.pow(repulseDistance / 6, 3);
105 const mouseClickPos = container.interactivity.mouse.clickPosition;
106 if (mouseClickPos === undefined) {
107 return;
108 }
109 const range = new Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius);
110 const query = container.particles.quadTree.query(range);
111 for (const particle of query) {
112 const { dx, dy, distance } = NumberUtils.getDistances(mouseClickPos, particle.position);
113 const d = distance * distance;
114 if (d <= repulseRadius) {
115 container.repulse.particles.push(particle);
116 const velocity = container.actualOptions.interactivity.modes.repulse.speed;
117 const v = Vector.create(dx, dy);
118 v.length = (-repulseRadius * velocity) / d;
119 particle.velocity.setTo(v);
120 }
121 }
122 }
123 else if (container.repulse.clicking === false) {
124 for (const particle of container.repulse.particles) {
125 particle.velocity.setTo(particle.initialVelocity);
126 }
127 container.repulse.particles = [];
128 }
129 }
130}