From b0b7a5bb849c386ec9b7629c2c67f2db7bbf8566 Mon Sep 17 00:00:00 2001 From: yonava Date: Sun, 17 Aug 2025 00:55:02 +0200 Subject: [PATCH 1/2] animation sync --- .../products/src/markov-chains/MainView.vue | 50 +++++++++++++++++++ packages/shapes/src/animation/index.ts | 6 +-- .../shapes/src/animation/timeline/define.ts | 7 ++- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/packages/products/src/markov-chains/MainView.vue b/packages/products/src/markov-chains/MainView.vue index 02242586..adb52889 100644 --- a/packages/products/src/markov-chains/MainView.vue +++ b/packages/products/src/markov-chains/MainView.vue @@ -7,18 +7,68 @@ import MarkovChainInfo from "./ui/MarkovChainInfo.vue"; import MarkovChainInfoLabels from "./ui/MarkovChainInfoLabels.vue"; import { useMarkovColorizer } from "./ui/useMarkovColorizer"; + import tinycolor from "tinycolor2"; + import { watch, watchEffect } from "vue"; + import GButton from "@magic/ui/graph/button/GButton.vue"; + import gsap from "gsap"; + import colors from "@magic/utils/colors"; const graphWithCanvas = useGraphWithCanvas(MARKOV_CHAIN_GRAPH_SETTINGS); const { graph } = graphWithCanvas; const markov = useMarkovChain(graph); useMarkovColorizer(graph, markov).colorize(); + + const int = gsap.utils.interpolate(colors.RED_500, colors.RED_800); + + const { play, stop } = graph.defineTimeline({ + forShapes: ["circle"], + durationMs: 2000, + customInterpolations: { + stroke: { + value: (progress, schema) => ({ + color: progress < 0.5 ? int(progress * 2) : int(2 - progress * 2), + lineWidth: schema.stroke?.lineWidth ?? 10, + }), + easing: "in-out", + }, + }, + synchronize: true, + }); + + graph.subscribe("onFocusChange", (newIds, oldIds) => { + const newNodeIds = Array.from(newIds).filter(graph.getNode); + const oldNodeIds = Array.from(oldIds).filter(graph.getNode); + newNodeIds.forEach((nodeId) => { + stop({ shapeId: nodeId }); + }); + const noLongerFocused = Array.from(oldNodeIds).filter( + (nodeId) => !newNodeIds.includes(nodeId) + ); + for (const nodeId of noLongerFocused) { + if (markov.invalidStates.value.has(nodeId)) play({ shapeId: nodeId }); + } + }); + + watch(markov.invalidStates, () => { + for (const node of graph.nodes.value) { + stop({ shapeId: node.id }); + if (markov.invalidStates.value.has(node.id)) play({ shapeId: node.id }); + } + }); + + const test = () => { + for (const nodeId of markov.invalidStates.value) { + play({ shapeId: nodeId }); + } + };