Add edge editor, generalize selection and edition to both node and edge. Still trying to find a proper tween.

This commit is contained in:
2025-01-14 17:57:57 +01:00
parent 76db788192
commit 348c991c54
6 changed files with 329 additions and 214 deletions

View File

@@ -1,54 +1,70 @@
import { clamp, lerp } from "~/shared/general.utils";
import { clamp } from "~/shared/general.utils";
export const linear = (progress: number): number => progress;
export const ease = (progress: number): number => -(Math.cos(Math.PI * progress) - 1) / 2;
export function useTween(ref: Ref<number>, animation: (progress: number) => number, then: () => void)
{
let initial = ref.value, current = ref.value, end = ref.value, progress = 0, time = 0, animationFrame: number, stop = true, last = 0;
function loop(t: DOMHighResTimeStamp)
{
const elapsed = t - last;
progress = clamp(progress + elapsed, 0, time);
// State variables for animation
let initial = ref.value;
let current = ref.value;
let end = ref.value;
let animationFrame: number;
let stop = true;
let last = 0;
// Velocity tracking with sign preservation
let velocity = 0;
const velocityDecay = 0.92; // Slightly faster decay for more responsive feel
function loop(t: DOMHighResTimeStamp) {
// Cap the elapsed time to prevent jumps during lag or tab switches
const elapsed = Math.min(t - last, 32);
last = t;
// Update velocity considering the sign of the movement
velocity = velocity * velocityDecay + (end - current) * (1 - velocityDecay);
// Apply velocity to current position
// Normalize by elapsed time to maintain consistent speed regardless of frame rate
current = clamp(current + velocity * (elapsed / 16), initial, end);
const step = animation(clamp(progress / time, 0, 1));
current = lerp(initial, end, step);
if(current === end)
stop = true;
// Trigger callback
then();
if(progress < time && !stop)
{
// Continue animation if not stopped
if (!stop) {
animationFrame = requestAnimationFrame(loop);
}
else
{
progress = 0;
stop = true;
}
}
return {
stop: () => {
cancelAnimationFrame(animationFrame);
stop = true;
velocity = 0; // Reset velocity when stopping
},
update: (target: number, duration: number) => {
initial = current;
time = duration + progress;
end = target;
ref.value = target;
if(stop)
{
stop = false;
if (stop) {
// Only reset initial position when starting a new animation
initial = current;
last = performance.now();
}
end = target;
if (stop) {
stop = false;
loop(performance.now());
}
},
refresh: () => { current = ref.value; },
current: () => { return current; },
refresh: () => {
current = ref.value;
velocity = 0; // Reset velocity on refresh
},
current: () => current,
};
}