Improvements to the cool graph
This commit is contained in:
parent
8a38d407c4
commit
842fb23275
@ -4,6 +4,7 @@
|
|||||||
import type { PrevType } from './types';
|
import type { PrevType } from './types';
|
||||||
import { type EventsStat } from '../utils';
|
import { type EventsStat } from '../utils';
|
||||||
import CoolGraphNode from './CoolGraphNode.svelte';
|
import CoolGraphNode from './CoolGraphNode.svelte';
|
||||||
|
import type { Node } from '../../flow/types';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
events
|
events
|
||||||
@ -30,9 +31,6 @@
|
|||||||
return Object.values(appState);
|
return Object.values(appState);
|
||||||
});
|
});
|
||||||
|
|
||||||
let figHeight = $state(0);
|
|
||||||
let figWidth = $state(0);
|
|
||||||
|
|
||||||
type Pos = {
|
type Pos = {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
@ -163,7 +161,7 @@
|
|||||||
return levels;
|
return levels;
|
||||||
});
|
});
|
||||||
|
|
||||||
const levelSize = $derived(Math.floor(figWidth / posByDepth.length));
|
let hovering: Node | undefined = $state();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if statusStore.nodesR && posByDepth.length > 0}
|
{#if statusStore.nodesR && posByDepth.length > 0}
|
||||||
@ -184,9 +182,16 @@
|
|||||||
{#snippet children(canvasX, canvasY)}
|
{#snippet children(canvasX, canvasY)}
|
||||||
{#each Object.keys(posByDepth[depth]) as nodeId}
|
{#each Object.keys(posByDepth[depth]) as nodeId}
|
||||||
{@const cur = posByDepth[depth][nodeId]}
|
{@const cur = posByDepth[depth][nodeId]}
|
||||||
{@const node = statusStore.nodesR[nodeId === 'null' ? (null as any) : nodeId]}
|
{@const node = statusStore.nodesR[nodeId]}
|
||||||
{#if node}
|
{#if node}
|
||||||
<CoolGraphNode {canvasX} {canvasY} {node} from={cur.from} count={cur.count} />
|
<CoolGraphNode
|
||||||
|
bind:hovering
|
||||||
|
{canvasX}
|
||||||
|
{canvasY}
|
||||||
|
{node}
|
||||||
|
from={cur.from}
|
||||||
|
count={cur.count}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
@ -10,13 +10,15 @@
|
|||||||
canvasX,
|
canvasX,
|
||||||
canvasY,
|
canvasY,
|
||||||
count,
|
count,
|
||||||
from
|
from,
|
||||||
|
hovering = $bindable()
|
||||||
}: {
|
}: {
|
||||||
node: Node;
|
node: Node;
|
||||||
canvasX: FuncBase;
|
canvasX: FuncBase;
|
||||||
canvasY: FuncBase;
|
canvasY: FuncBase;
|
||||||
from: PrevType;
|
from: PrevType;
|
||||||
count: number;
|
count: number;
|
||||||
|
hovering: Node | undefined;
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
let fromText = $derived(
|
let fromText = $derived(
|
||||||
@ -31,37 +33,42 @@
|
|||||||
to: string;
|
to: string;
|
||||||
percentage: number;
|
percentage: number;
|
||||||
rand: number;
|
rand: number;
|
||||||
randX: number;
|
randXStart: number;
|
||||||
randY: number;
|
randXEnd: number;
|
||||||
color: string;
|
color: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let particles: Particle[] = $state([]);
|
let particlesState: Record<string, Particle[]> = $state({});
|
||||||
let particlesState: Record<string, number> = $state({});
|
let particleCount = 0;
|
||||||
|
|
||||||
let MAX_PARTICLES = 200;
|
let MAX_PARTICLES = 400;
|
||||||
|
|
||||||
function spwanParticle(key: string) {
|
function spwanParticle(key: string) {
|
||||||
if (particles.length > MAX_PARTICLES) return;
|
if (particleCount > MAX_PARTICLES) return;
|
||||||
if (from.cur[key] <= particlesState[key]) {
|
if (from.cur[key] <= (particlesState[key] ?? []).length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
particles.push({
|
const toAdd: Particle = {
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
to: key,
|
to: key,
|
||||||
rand: Math.random(),
|
rand: Math.random(),
|
||||||
randX: Math.random(),
|
randXStart: Math.floor(Math.random() * 100),
|
||||||
randY: Math.random(),
|
randXEnd: Math.floor(Math.random() * 100),
|
||||||
color: [
|
color: [
|
||||||
'oklch(68.5% 0.169 237.323)',
|
'oklch(68.5% 0.169 237.323)',
|
||||||
'oklch(62.3% 0.214 259.815)',
|
'oklch(62.3% 0.214 259.815)',
|
||||||
'oklch(62.7% 0.265 303.9)'
|
'oklch(62.7% 0.265 303.9)'
|
||||||
][Math.floor(Math.random() * 3)]
|
][Math.floor(Math.random() * 3)]
|
||||||
});
|
};
|
||||||
particlesState[key] = (particlesState[key] ?? 0) + 1;
|
if (particlesState[key]) {
|
||||||
|
particlesState[key].push(toAdd);
|
||||||
|
} else {
|
||||||
|
particlesState[key] = [toAdd];
|
||||||
|
}
|
||||||
|
particleCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_ROUNDS = 40;
|
const MAX_ROUNDS = 200;
|
||||||
let timeout: number | undefined = undefined;
|
let timeout: number | undefined = undefined;
|
||||||
|
|
||||||
function t(k: number) {
|
function t(k: number) {
|
||||||
@ -72,39 +79,64 @@
|
|||||||
for (const key of Object.keys(from.cur)) {
|
for (const key of Object.keys(from.cur)) {
|
||||||
spwanParticle(key);
|
spwanParticle(key);
|
||||||
}
|
}
|
||||||
timeout = setTimeout(() => t(k + 1), Math.random() * 1500) as unknown as number;
|
timeout = setTimeout(() => t(k + 1), Math.random() * 1000) as unknown as number;
|
||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (timeout !== undefined) clearTimeout(timeout);
|
if (timeout !== undefined) clearTimeout(timeout);
|
||||||
|
// this is used for making this effect block dependednt on form
|
||||||
|
// eslint-disable-next-line
|
||||||
const _ = from;
|
const _ = from;
|
||||||
particles = [];
|
particlesState = {};
|
||||||
timeout = setTimeout(() => t(0), 10) as unknown as number;
|
timeout = setTimeout(() => t(0), 10) as unknown as number;
|
||||||
return () => {
|
return () => {
|
||||||
if (timeout !== undefined) clearTimeout(timeout);
|
if (timeout !== undefined) clearTimeout(timeout);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let showColor = $derived(hovering === undefined || hovering === node);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="shadow-sm shadow-violet-500 border rounded-full min-w-[50px] min-h-[50px] grid place-items-center bg-white z-40 absolute"
|
class="shadow-sm shadow-violet-500 border rounded-full min-w-[50px] min-h-[50px] grid place-items-center bg-white z-40 absolute"
|
||||||
style="left: {canvasX(node.x + node.width / 2)}px; top: {canvasY(node.y - node.height / 2)}px;"
|
style="left: {canvasX(node.x + node.width / 2)}px; top: {canvasY(node.y - node.height / 2)}px;"
|
||||||
title={`${node?.name ?? ''}: ${count}\n${fromText}`}
|
title={`${node?.name ?? ''}: ${count}\n${fromText}`}
|
||||||
|
onmouseenter={() => {
|
||||||
|
hovering = node;
|
||||||
|
}}
|
||||||
|
onmouseleave={() => {
|
||||||
|
hovering = undefined;
|
||||||
|
}}
|
||||||
|
role="figure"
|
||||||
>
|
>
|
||||||
<span class={`bi bi-${node?.icon ?? ''}`}> </span>
|
<span class={`bi bi-${node?.icon ?? ''}`}> </span>
|
||||||
</div>
|
</div>
|
||||||
{#each particles as particle}
|
|
||||||
{@const to = statusStore.nodesR[particle.to]}
|
{#each Object.keys(particlesState) as key}
|
||||||
{@const f_x = to.x + to.width / 2 + particle.randX}
|
{@const size = 20}
|
||||||
{@const f_y = to.y - to.height / 2 + particle.randY}
|
{@const to = statusStore.nodesR[key]}
|
||||||
{@const x = (p: number) => f_x + (node.x + node.width / 2 - f_x) * p}
|
{@const f_x = node.x + node.width / 2}
|
||||||
{@const y = (p: number) => f_y + (node.y - node.height / 2 - f_y) * p}
|
{@const f_y = node.y - node.height / 2}
|
||||||
|
{@const t_x = to.x + to.width / 2}
|
||||||
|
{@const t_y = to.y - to.height / 2}
|
||||||
|
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
||||||
|
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
||||||
<div
|
<div
|
||||||
class="animateMove absolute w-2 h-2 text-black rounded-full shadow-lg z-20"
|
class="absolute z-30"
|
||||||
style="--start-x: {canvasX(x(0)) + 25}px; --start-y: {canvasY(y(0)) + 25}px; --end-x: {canvasX(
|
style="height: {(25 / 2) *
|
||||||
x(1)
|
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
||||||
) + 25}px; --end-y: {canvasY(y(1)) + 25}px; background: {particle.color};"
|
25 -
|
||||||
></div>
|
size / 2}px, {canvasY(f_y) + 25 + size / 8}px) rotate({theta}rad);"
|
||||||
|
>
|
||||||
|
{#each particlesState[key] as particle}
|
||||||
|
<div
|
||||||
|
class="animateMove absolute w-2 h-2 text-black rounded-full shadow-lg"
|
||||||
|
style="--start-x: {particle.randXStart}%; --end-x: {particle.randXEnd}%; background: {!showColor
|
||||||
|
? '#18181818'
|
||||||
|
: particle.color};"
|
||||||
|
></div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#each Object.keys(from.cur) as link}
|
{#each Object.keys(from.cur) as link}
|
||||||
@ -117,9 +149,11 @@
|
|||||||
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
||||||
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
||||||
<div
|
<div
|
||||||
class="absolute bg-gradient-to-t from-blue-400/70 to-blue-200/70 z-10"
|
class="absolute {showColor
|
||||||
style="height: {(25 / 2) *
|
? 'bg-gradient-to-t from-blue-400/70 to-blue-200/70'
|
||||||
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
: 'bg-gray-800/20'} z-10"
|
||||||
|
style="height: {(25 / 2) * diff}px;
|
||||||
|
width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
||||||
25 -
|
25 -
|
||||||
size / 2}px, {canvasY(f_y) + 25 + size / 8}px) rotate({theta}rad);"
|
size / 2}px, {canvasY(f_y) + 25 + size / 8}px) rotate({theta}rad);"
|
||||||
></div>
|
></div>
|
||||||
@ -136,7 +170,9 @@
|
|||||||
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
||||||
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
||||||
<div
|
<div
|
||||||
class="absolute bg-gradient-to-t from-violet-400/70 to-violet-200/70"
|
class="absolute {showColor
|
||||||
|
? 'bg-gradient-to-t from-violet-400/70 to-violet-200/70'
|
||||||
|
: 'bg-gray-600/20'}"
|
||||||
style="height: {(25 / 2) *
|
style="height: {(25 / 2) *
|
||||||
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
||||||
25 -
|
25 -
|
||||||
@ -156,7 +192,31 @@
|
|||||||
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
||||||
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
||||||
<div
|
<div
|
||||||
class="absolute bg-gradient-to-t from-violet-400/50 to-violet-200/50"
|
class="absolute {showColor
|
||||||
|
? 'bg-gradient-to-t from-violet-400/50 to-violet-200/50'
|
||||||
|
: 'bg-gray-400/20'}"
|
||||||
|
style="height: {(25 / 2) *
|
||||||
|
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
||||||
|
25 -
|
||||||
|
size / 2}px, {canvasY(f_y) + 25 - size / 4}px) rotate({theta}rad); z-index: 2"
|
||||||
|
></div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if from.prev && from.prev.prev && from.prev.prev.prev}
|
||||||
|
{#each Object.keys(from.prev.prev.prev.cur) as link}
|
||||||
|
{@const size = 2.5}
|
||||||
|
{@const to = statusStore.nodesR[link]}
|
||||||
|
{@const f_x = node.x + node.width / 2}
|
||||||
|
{@const f_y = node.y - node.height / 2}
|
||||||
|
{@const t_x = to.x + to.width / 2}
|
||||||
|
{@const t_y = to.y - to.height / 2}
|
||||||
|
{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
|
||||||
|
{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
|
||||||
|
<div
|
||||||
|
class="absolute {showColor
|
||||||
|
? 'bg-gradient-to-t from-violet-200/50 to-violet-100/50'
|
||||||
|
: 'bg-gray-400/20'}"
|
||||||
style="height: {(25 / 2) *
|
style="height: {(25 / 2) *
|
||||||
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
|
||||||
25 -
|
25 -
|
||||||
@ -167,15 +227,15 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.animateMove {
|
.animateMove {
|
||||||
animation: animateMoves 5s ease-in-out infinite;
|
animation: animateMoves 5s ease-in infinite;
|
||||||
}
|
}
|
||||||
@keyframes animateMoves {
|
@keyframes animateMoves {
|
||||||
0% {
|
0% {
|
||||||
top: var(--start-y);
|
top: 100%;
|
||||||
left: var(--start-x);
|
left: var(--start-x);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
top: var(--end-y);
|
top: 0%;
|
||||||
left: var(--end-x);
|
left: var(--end-x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user