-
Notifications
You must be signed in to change notification settings - Fork 0
/
lerp.js
233 lines (192 loc) · 7.43 KB
/
lerp.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
class Vector2 {
constructor(x = 0, y = 0) {
this.x = x;
this.y = y;
}
// Add another vector to this vector
add(vector) {
return new Vector2(this.x + vector.x, this.y + vector.y);
}
// Multiply the vector by a scalar value
multiply(scalar) {
return new Vector2(this.x * scalar, this.y * scalar);
}
// Calculate the magnitude (length) of the vector
magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
// Normalize the vector (make its length equal to 1)
normalize() {
let mag = this.magnitude();
if (mag === 0) {
return new Vector2(0, 0); // Return zero vector if magnitude is zero
}
return new Vector2(this.x / mag, this.y / mag);
}
}
// Set up the initial vector position for the circle
const circle = document.getElementById('circle');
let current = new Vector2(window.innerWidth / 2, window.innerHeight / 2); // Start at the center
let target = new Vector2(window.innerWidth / 2, window.innerHeight / 2);
// Setup current mode
const currentFunctionSelection = document.getElementById('current-function');
currentFunctionSelection.addEventListener("change", updateFunction);
// Setup variable setting
const variableSliders = document.getElementsByClassName('slider');
for (const slider of variableSliders) {
slider.addEventListener('input', updateVariable, false);
// get parents parent and then id ignoring the appended -slider
slider.variable = (slider.parentElement.parentElement.id).replace('-slider', '');
slider.label = slider.parentElement.parentElement.children[0];
}
const resetButton = document.getElementById('reset');
resetButton.addEventListener('click', resetSimulation);
let positionFunction = positionSetter;
let deltaTime = 0;
let lastTimestamp = Date.now();
let inertia = new Vector2(0, 0);
// Variable to be set by the user
let baseVelocity = 300;
let referenceDistance = 300;
let baseAcceleration = 50;
let dragCoefficient = 0.5;
function updateFunction() {
switch (currentFunctionSelection.value) {
case 'positionSetter':
positionFunction = positionSetter;
setSliderVisibility(['baseVelocity', 'referenceDistance', 'baseAcceleration', 'dragCoefficient'], false);
break;
case 'staticVelocity':
positionFunction = staticVelocity;
setSliderVisibility(['baseVelocity'], true);
setSliderVisibility(['referenceDistance', 'baseAcceleration', 'dragCoefficient'], false);
break;
case 'distanceVelocity':
positionFunction = distanceVelocity;
setSliderVisibility(['baseVelocity', 'referenceDistance'], true);
setSliderVisibility(['baseAcceleration', 'dragCoefficient'], false);
break;
case 'proximityVelocity':
positionFunction = proximityVelocity;
setSliderVisibility(['baseVelocity', 'referenceDistance'], true);
setSliderVisibility(['baseAcceleration', 'dragCoefficient'], false);
break;
case 'staticAcceleration':
positionFunction = staticAcceleration;
setSliderVisibility(['baseAcceleration', 'dragCoefficient'], true);
setSliderVisibility(['baseVelocity', 'referenceDistance'], false);
break;
}
}
function updateVariable() {
this.label.textContent = (this.label.textContent).split(' - ')[0] + ' - ' + this.value;
switch (this.variable) {
case 'baseVelocity':
baseVelocity = this.value;
break;
case 'referenceDistance':
referenceDistance = this.value;
break;
case 'baseAcceleration':
baseAcceleration = this.value;
break;
case 'dragCoefficient':
dragCoefficient = this.value;
break;
}
}
function setSliderVisibility(sliderNames, isVisible) {
for (const sliderName of sliderNames) {
const settingsContainer = document.getElementById(`${sliderName}-slider`)
if (!isVisible) {
settingsContainer.classList.add('is-hidden');
} else {
settingsContainer.classList.remove('is-hidden');
}
}
}
function resetSimulation() {
current = new Vector2(window.innerWidth / 2, window.innerHeight / 2);
target = new Vector2(window.innerWidth / 2, window.innerHeight / 2);
inertia = new Vector2(0, 0);
positionFunction();
}
// Update the circle position based on the vector2 values
function updateCirclePlacement(pos) {
circle.style.transform = `translate(${pos.x - 25}px, ${pos.y - 25}px)`; // Centering the circle
current = new Vector2(pos.x, pos.y);
}
function positionSetter() {
updateCirclePlacement(target);
}
function staticVelocity() {
let directionRaw = target.add(current.multiply(-1));
let velocity = baseVelocity * deltaTime;
if (directionRaw.magnitude() < velocity) {
updateCirclePlacement(target);
return;
}
let directionNormalized = directionRaw.normalize();
let newPosition = current.add(directionNormalized.multiply(velocity));
updateCirclePlacement(newPosition);
}
function distanceVelocity() {
// Increased distance leads to increased velocity
const minVelocity = 5 * deltaTime;
let directionRaw = target.add(current.multiply(-1));
let velocity = baseVelocity * (directionRaw.magnitude() / referenceDistance) * deltaTime;
velocity = Math.max(velocity, minVelocity);
if (directionRaw.magnitude() < velocity) {
updateCirclePlacement(target);
return;
}
let directionNormalized = directionRaw.normalize();
let newPosition = current.add(directionNormalized.multiply(velocity));
updateCirclePlacement(newPosition);
}
function proximityVelocity() {
// Decreased distance leads to increased velocity
const minVelocity = 5 * deltaTime;
let directionRaw = target.add(current.multiply(-1));
let velocity = baseVelocity * (referenceDistance / directionRaw.magnitude()) * deltaTime;
velocity = Math.max(velocity, minVelocity);
if (directionRaw.magnitude() < velocity) {
updateCirclePlacement(target);
return;
}
let directionNormalized = directionRaw.normalize();
let newPosition = current.add(directionNormalized.multiply(velocity));
updateCirclePlacement(newPosition);
}
function staticAcceleration() {
let directionRaw = target.add(current.multiply(-1));
let directionNormalized = directionRaw.normalize();
let force = directionNormalized.multiply(baseAcceleration * deltaTime);
if (isNaN(inertia.x)) {
return;
}
inertia = inertia.add(force);
inertia = inertia.multiply((1 - dragCoefficient) ** deltaTime);
if (directionRaw.magnitude() < 20) {
inertia = inertia.multiply((1 - 0.99) ** deltaTime);
if (inertia.magnitude() < 0.1) {
updateCirclePlacement(target);
return;
}
}
let newPosition = current.add(inertia);
updateCirclePlacement(newPosition);
}
function updateCirclePosition() {
deltaTime = (Date.now() - lastTimestamp) / 1000;
lastTimestamp = Date.now();
positionFunction();
requestAnimationFrame(updateCirclePosition);
}
// Event listener for mouse movement
document.addEventListener('mousemove', function(event) {
// Update the target as a Vector2 object with the mouse coordinates
target = new Vector2(event.clientX, event.clientY);
});
// Initial position update
updateCirclePosition();