visualfries 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +213 -0
- package/dist/DIContainer.d.ts +4 -0
- package/dist/DIContainer.js +145 -0
- package/dist/SceneBuilder.svelte.d.ts +8574 -0
- package/dist/SceneBuilder.svelte.js +409 -0
- package/dist/adapters/subtitleHelpers.d.ts +2 -0
- package/dist/adapters/subtitleHelpers.js +187 -0
- package/dist/animations/AnimationContext.d.ts +17 -0
- package/dist/animations/AnimationContext.js +72 -0
- package/dist/animations/AnimationPresetsRegister.d.ts +362 -0
- package/dist/animations/AnimationPresetsRegister.js +20 -0
- package/dist/animations/AnimationSetup.d.ts +8 -0
- package/dist/animations/AnimationSetup.js +30 -0
- package/dist/animations/SplitTextCache.d.ts +28 -0
- package/dist/animations/SplitTextCache.js +68 -0
- package/dist/animations/animationBuilder.d.ts +31 -0
- package/dist/animations/animationBuilder.js +255 -0
- package/dist/animations/animationPreset.d.ts +7 -0
- package/dist/animations/animationPreset.js +31 -0
- package/dist/animations/builders/AnimationPresetFactory.d.ts +43 -0
- package/dist/animations/builders/AnimationPresetFactory.js +139 -0
- package/dist/animations/builders/LineHighlighterAnimationBuilder.d.ts +16 -0
- package/dist/animations/builders/LineHighlighterAnimationBuilder.js +183 -0
- package/dist/animations/builders/WordHighlighterAnimationBuilder.d.ts +15 -0
- package/dist/animations/builders/WordHighlighterAnimationBuilder.js +180 -0
- package/dist/animations/engines/AnimationEngineAdaptor.d.ts +107 -0
- package/dist/animations/engines/AnimationEngineAdaptor.js +1 -0
- package/dist/animations/engines/GSAPEngineAdaptor.d.ts +21 -0
- package/dist/animations/engines/GSAPEngineAdaptor.js +145 -0
- package/dist/animations/presets/index.d.ts +2 -0
- package/dist/animations/presets/index.js +3 -0
- package/dist/animations/presets/lines.d.ts +52 -0
- package/dist/animations/presets/lines.js +547 -0
- package/dist/animations/presets/words.d.ts +31 -0
- package/dist/animations/presets/words.js +268 -0
- package/dist/animations/transformers/AnimationReferenceTransformer.d.ts +9 -0
- package/dist/animations/transformers/AnimationReferenceTransformer.js +114 -0
- package/dist/builders/PixiComponentBuilder.d.ts +63 -0
- package/dist/builders/PixiComponentBuilder.js +112 -0
- package/dist/builders/_ComponentState.svelte.d.ts +795 -0
- package/dist/builders/_ComponentState.svelte.js +203 -0
- package/dist/builders/html/HtmlBuilder.d.ts +66 -0
- package/dist/builders/html/HtmlBuilder.js +171 -0
- package/dist/builders/html/HtmlBuilderFactory.d.ts +27 -0
- package/dist/builders/html/HtmlBuilderFactory.js +30 -0
- package/dist/builders/html/StyleBuilder.d.ts +13 -0
- package/dist/builders/html/StyleBuilder.js +133 -0
- package/dist/builders/html/StyleProcessor.d.ts +9 -0
- package/dist/builders/html/StyleProcessor.js +1 -0
- package/dist/builders/html/TextComponentHtmlBuilder.d.ts +16 -0
- package/dist/builders/html/TextComponentHtmlBuilder.js +93 -0
- package/dist/builders/html/TextShadowBuilder.d.ts +60 -0
- package/dist/builders/html/TextShadowBuilder.js +227 -0
- package/dist/builders/html/processors/AppearanceStyleProcessor.d.ts +5 -0
- package/dist/builders/html/processors/AppearanceStyleProcessor.js +57 -0
- package/dist/builders/html/processors/TextAppearanceStyleProcessor.d.ts +5 -0
- package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +37 -0
- package/dist/builders/html/processors/TextEffectsStyleProcessor.d.ts +6 -0
- package/dist/builders/html/processors/TextEffectsStyleProcessor.js +68 -0
- package/dist/commands/Command.d.ts +6 -0
- package/dist/commands/Command.js +1 -0
- package/dist/commands/CommandRunner.d.ts +28 -0
- package/dist/commands/CommandRunner.js +81 -0
- package/dist/commands/CommandTypes.d.ts +11 -0
- package/dist/commands/CommandTypes.js +13 -0
- package/dist/commands/PauseCommand.d.ts +4 -0
- package/dist/commands/PauseCommand.js +5 -0
- package/dist/commands/PlayCommand.d.ts +4 -0
- package/dist/commands/PlayCommand.js +6 -0
- package/dist/commands/RenderCommand.d.ts +15 -0
- package/dist/commands/RenderCommand.js +18 -0
- package/dist/commands/RenderFrameCommand.d.ts +17 -0
- package/dist/commands/RenderFrameCommand.js +93 -0
- package/dist/commands/ReplaceSourceOnTimeCommand.d.ts +4 -0
- package/dist/commands/ReplaceSourceOnTimeCommand.js +22 -0
- package/dist/commands/SeekCommand.d.ts +15 -0
- package/dist/commands/SeekCommand.js +39 -0
- package/dist/commands/UpdateComponentCommand.d.ts +4 -0
- package/dist/commands/UpdateComponentCommand.js +17 -0
- package/dist/components/AnimatedGIF.d.ts +201 -0
- package/dist/components/AnimatedGIF.js +391 -0
- package/dist/components/Component.svelte.d.ts +33 -0
- package/dist/components/Component.svelte.js +152 -0
- package/dist/components/ComponentContext.svelte.d.ts +33 -0
- package/dist/components/ComponentContext.svelte.js +105 -0
- package/dist/components/hooks/AnimationHook.d.ts +25 -0
- package/dist/components/hooks/AnimationHook.js +180 -0
- package/dist/components/hooks/CanvasShapeHook.d.ts +12 -0
- package/dist/components/hooks/CanvasShapeHook.js +229 -0
- package/dist/components/hooks/HtmlAnimationHook.d.ts +8 -0
- package/dist/components/hooks/HtmlAnimationHook.js +70 -0
- package/dist/components/hooks/HtmlTextHook.d.ts +16 -0
- package/dist/components/hooks/HtmlTextHook.js +102 -0
- package/dist/components/hooks/HtmlToCanvasHook.d.ts +16 -0
- package/dist/components/hooks/HtmlToCanvasHook.js +148 -0
- package/dist/components/hooks/ImageHook.d.ts +10 -0
- package/dist/components/hooks/ImageHook.js +45 -0
- package/dist/components/hooks/MediaHook.d.ts +15 -0
- package/dist/components/hooks/MediaHook.js +252 -0
- package/dist/components/hooks/MediaSeekingHook.d.ts +12 -0
- package/dist/components/hooks/MediaSeekingHook.js +204 -0
- package/dist/components/hooks/PixiDisplayObjectHook.d.ts +15 -0
- package/dist/components/hooks/PixiDisplayObjectHook.js +77 -0
- package/dist/components/hooks/PixiGifHook.d.ts +15 -0
- package/dist/components/hooks/PixiGifHook.js +97 -0
- package/dist/components/hooks/PixiProgressShapeHook.d.ts +12 -0
- package/dist/components/hooks/PixiProgressShapeHook.js +128 -0
- package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.d.ts +21 -0
- package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +210 -0
- package/dist/components/hooks/PixiTextureHook.d.ts +7 -0
- package/dist/components/hooks/PixiTextureHook.js +29 -0
- package/dist/components/hooks/PixiVideoTextureHook.d.ts +10 -0
- package/dist/components/hooks/PixiVideoTextureHook.js +35 -0
- package/dist/components/hooks/SubtitlesHook.d.ts +88 -0
- package/dist/components/hooks/SubtitlesHook.js +199 -0
- package/dist/components/hooks/VerifyGifHook.d.ts +7 -0
- package/dist/components/hooks/VerifyGifHook.js +27 -0
- package/dist/components/hooks/VerifyImageHook.d.ts +7 -0
- package/dist/components/hooks/VerifyImageHook.js +27 -0
- package/dist/components/hooks/VerifyMediaHook.d.ts +7 -0
- package/dist/components/hooks/VerifyMediaHook.js +21 -0
- package/dist/components/hooks/shapes/progress/CustomProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/CustomProgressRenderer.js +53 -0
- package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.js +69 -0
- package/dist/components/hooks/shapes/progress/LinearProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/LinearProgressRenderer.js +60 -0
- package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.d.ts +9 -0
- package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.js +213 -0
- package/dist/components/hooks/shapes/progress/ProgressRenderer.d.ts +17 -0
- package/dist/components/hooks/shapes/progress/ProgressRenderer.js +75 -0
- package/dist/components/hooks/shapes/progress/RadialProgressRenderer.d.ts +8 -0
- package/dist/components/hooks/shapes/progress/RadialProgressRenderer.js +50 -0
- package/dist/components/hooks/shapes/progress/index.d.ts +6 -0
- package/dist/components/hooks/shapes/progress/index.js +6 -0
- package/dist/composers/componentComposer.d.ts +55 -0
- package/dist/composers/componentComposer.js +118 -0
- package/dist/composers/layerComposer.d.ts +46 -0
- package/dist/composers/layerComposer.js +79 -0
- package/dist/composers/sceneComposer.d.ts +48 -0
- package/dist/composers/sceneComposer.js +92 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +14 -0
- package/dist/directors/ComponentDirector.d.ts +20 -0
- package/dist/directors/ComponentDirector.js +86 -0
- package/dist/factories/SceneBuilderFactory.d.ts +15 -0
- package/dist/factories/SceneBuilderFactory.js +51 -0
- package/dist/fonts/GoogleFontsProvider.d.ts +12 -0
- package/dist/fonts/GoogleFontsProvider.js +125 -0
- package/dist/fonts/fontLoader.d.ts +15 -0
- package/dist/fonts/fontLoader.js +41 -0
- package/dist/fonts/types.d.ts +1 -0
- package/dist/fonts/types.js +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +14 -0
- package/dist/layers/Layer.svelte.d.ts +8492 -0
- package/dist/layers/Layer.svelte.js +125 -0
- package/dist/managers/AppManager.svelte.d.ts +23 -0
- package/dist/managers/AppManager.svelte.js +89 -0
- package/dist/managers/ComponentsManager.svelte.d.ts +49 -0
- package/dist/managers/ComponentsManager.svelte.js +247 -0
- package/dist/managers/DomManager.d.ts +18 -0
- package/dist/managers/DomManager.js +73 -0
- package/dist/managers/EventManager.d.ts +7 -0
- package/dist/managers/EventManager.js +22 -0
- package/dist/managers/LayersManager.svelte.d.ts +8499 -0
- package/dist/managers/LayersManager.svelte.js +176 -0
- package/dist/managers/MediaManager.d.ts +32 -0
- package/dist/managers/MediaManager.js +243 -0
- package/dist/managers/RenderManager.d.ts +23 -0
- package/dist/managers/RenderManager.js +59 -0
- package/dist/managers/StateManager.svelte.d.ts +8746 -0
- package/dist/managers/StateManager.svelte.js +272 -0
- package/dist/managers/SubtitlesManager.svelte.d.ts +261 -0
- package/dist/managers/SubtitlesManager.svelte.js +1385 -0
- package/dist/managers/TimeManager.svelte.d.ts +6 -0
- package/dist/managers/TimeManager.svelte.js +18 -0
- package/dist/managers/TimelineManager.svelte.d.ts +25 -0
- package/dist/managers/TimelineManager.svelte.js +152 -0
- package/dist/registers.d.ts +12 -0
- package/dist/registers.js +29 -0
- package/dist/schemas/runtime/index.d.ts +3 -0
- package/dist/schemas/runtime/index.js +4 -0
- package/dist/schemas/runtime/types.d.ts +323 -0
- package/dist/schemas/runtime/types.js +12 -0
- package/dist/schemas/scene/animations.d.ts +89738 -0
- package/dist/schemas/scene/animations.js +211 -0
- package/dist/schemas/scene/components.js +515 -0
- package/dist/schemas/scene/core.js +160 -0
- package/dist/schemas/scene/index.d.ts +22 -0
- package/dist/schemas/scene/index.js +10 -0
- package/dist/schemas/scene/properties.d.ts +914 -0
- package/dist/schemas/scene/properties.js +398 -0
- package/dist/schemas/scene/subtitles.d.ts +1141 -0
- package/dist/schemas/scene/subtitles.js +111 -0
- package/dist/schemas/scene/utils.d.ts +1 -0
- package/dist/schemas/scene/utils.js +5 -0
- package/dist/seeds/SeedFactory.d.ts +59 -0
- package/dist/seeds/SeedFactory.js +99 -0
- package/dist/seeds/index.d.ts +8 -0
- package/dist/seeds/index.js +8 -0
- package/dist/transformers/ColorTransformer.d.ts +5 -0
- package/dist/transformers/ColorTransformer.js +67 -0
- package/dist/transformers/PixiColorTransformer.d.ts +22 -0
- package/dist/transformers/PixiColorTransformer.js +104 -0
- package/dist/utils/canvas.d.ts +6 -0
- package/dist/utils/canvas.js +18 -0
- package/dist/utils/document.d.ts +2 -0
- package/dist/utils/document.js +36 -0
- package/dist/utils/emoji.d.ts +10 -0
- package/dist/utils/emoji.js +51 -0
- package/dist/utils/html.d.ts +4 -0
- package/dist/utils/html.js +45 -0
- package/dist/utils/svgGenerator.d.ts +20 -0
- package/dist/utils/svgGenerator.js +103 -0
- package/dist/utils/utils.d.ts +5 -0
- package/dist/utils/utils.js +125 -0
- package/package.json +96 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { AnimationSetup } from './AnimationSetup.js';
|
|
2
|
+
import { get } from 'lodash-es';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
export class AnimationBuilder {
|
|
5
|
+
animationContext;
|
|
6
|
+
engineAdaptor;
|
|
7
|
+
mainTimeline;
|
|
8
|
+
labels = new Set();
|
|
9
|
+
constructor(animationContext, engineAdaptor) {
|
|
10
|
+
this.animationContext = animationContext;
|
|
11
|
+
this.engineAdaptor = engineAdaptor;
|
|
12
|
+
const revertAfterComplete = get(this.animationContext.preset.preset, 'revertAfterComplete', false);
|
|
13
|
+
this.mainTimeline = this.engineAdaptor.createTimeline({
|
|
14
|
+
// duration: this.animationContext.preset.duration,
|
|
15
|
+
revertAfterComplete
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
build() {
|
|
19
|
+
this.processSetupSteps();
|
|
20
|
+
const hasItems = this.buildTimelineItems();
|
|
21
|
+
// No more repositionOutLabelsIfNeeded() since we position correctly from the start
|
|
22
|
+
return hasItems ? this.mainTimeline : null;
|
|
23
|
+
}
|
|
24
|
+
processSetupSteps() {
|
|
25
|
+
const setupProcessor = new AnimationSetup(this.animationContext, this.engineAdaptor);
|
|
26
|
+
setupProcessor.process();
|
|
27
|
+
}
|
|
28
|
+
ensureItemHasId(item) {
|
|
29
|
+
if (!item.id) {
|
|
30
|
+
item.id = uuidv4();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
buildTimelineItems() {
|
|
34
|
+
const timelineItems = this.animationContext.preset.getTimelineItems();
|
|
35
|
+
let hasSequenceItems = false;
|
|
36
|
+
for (let i = 0; i < timelineItems.length; i++) {
|
|
37
|
+
const item = timelineItems[i];
|
|
38
|
+
this.ensureItemHasId(item);
|
|
39
|
+
const targets = this.resolveTargets(item.target);
|
|
40
|
+
if (!this.isValidTargets(targets)) {
|
|
41
|
+
console.warn(`AnimationBuilder: No targets found for query "${item.target}" in item ID "${item.id || 'untitled'}". Skipping.`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
this.addSequenceItemToTimeline(item, i === 0, targets);
|
|
45
|
+
hasSequenceItems = true;
|
|
46
|
+
}
|
|
47
|
+
return hasSequenceItems;
|
|
48
|
+
}
|
|
49
|
+
isValidTargets(targets) {
|
|
50
|
+
return targets !== null && !(Array.isArray(targets) && targets.length === 0);
|
|
51
|
+
}
|
|
52
|
+
addSequenceItemToTimeline(item, isFirstItem, targets) {
|
|
53
|
+
// Always build the child timeline first to get real duration
|
|
54
|
+
const childTimeline = this.processTweens(item, targets);
|
|
55
|
+
const duration = this.engineAdaptor.totalDuration(childTimeline);
|
|
56
|
+
// Now calculate position with duration information available
|
|
57
|
+
const resolvedPosition = this.calculatePosition(item.position, item.id, isFirstItem, duration);
|
|
58
|
+
// Add label if needed
|
|
59
|
+
this.addItemLabelIfNeeded(item, resolvedPosition);
|
|
60
|
+
// Add child timeline at calculated position
|
|
61
|
+
this.mainTimeline.add(childTimeline, resolvedPosition.value);
|
|
62
|
+
}
|
|
63
|
+
addItemLabelIfNeeded(item, resolvedPosition) {
|
|
64
|
+
if (item.id && resolvedPosition.value !== undefined && !this.labels.has(item.id)) {
|
|
65
|
+
this.engineAdaptor.addLabel(this.mainTimeline, item.id, resolvedPosition.value);
|
|
66
|
+
this.labels.add(item.id);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
processTweens(item, targets) {
|
|
70
|
+
const tweenTL = this.engineAdaptor.createTimeline();
|
|
71
|
+
item.tweens.forEach((tweenDef, tweenIndex) => {
|
|
72
|
+
const resolvedVars = this.resolveTweenVars(tweenDef.vars);
|
|
73
|
+
const tweenPosition = tweenIndex === 0 ? 0 : '>'; // Always start first tween at 0
|
|
74
|
+
const tweenFinalPosition = tweenDef.position || tweenPosition;
|
|
75
|
+
const resolvedPosition = this.calculatePosition(tweenFinalPosition, undefined, tweenIndex === 0, 0);
|
|
76
|
+
this.engineAdaptor.addTween(tweenTL, targets, tweenDef.method, resolvedVars, resolvedPosition.value);
|
|
77
|
+
});
|
|
78
|
+
return tweenTL;
|
|
79
|
+
}
|
|
80
|
+
resolveTargets(targetQuery) {
|
|
81
|
+
return targetQuery
|
|
82
|
+
? this.animationContext.getElement(targetQuery)
|
|
83
|
+
: this.animationContext.rootElement;
|
|
84
|
+
}
|
|
85
|
+
resolveTweenVars(vars) {
|
|
86
|
+
const resolved = {};
|
|
87
|
+
for (const [key, valueDefinition] of Object.entries(vars)) {
|
|
88
|
+
if (key === 'from' && this.isObject(valueDefinition)) {
|
|
89
|
+
resolved.from = this.resolveTweenVars(valueDefinition);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (key === 'stagger' && valueDefinition) {
|
|
93
|
+
resolved.stagger = this.engineAdaptor.resolveStagger(valueDefinition, this.animationContext, typeof resolved.duration === 'number' ? resolved.duration : undefined);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
// merge textShadow with animation shadow to preserve effects as expected
|
|
97
|
+
if (key === 'textShadow') {
|
|
98
|
+
const hasOriginalShadow = this.animationContext.getData('textShadow') &&
|
|
99
|
+
this.animationContext.getData('textShadow') !== 'none' &&
|
|
100
|
+
this.animationContext.getData('textShadow') !== '';
|
|
101
|
+
const hasAnimationShadow = valueDefinition && valueDefinition !== 'none' && valueDefinition !== '';
|
|
102
|
+
if (hasOriginalShadow && hasAnimationShadow) {
|
|
103
|
+
// merge shadows
|
|
104
|
+
resolved.textShadow = `${this.animationContext.getData('textShadow')}, ${valueDefinition}`;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
resolved.textShadow = valueDefinition;
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
resolved[key] = this.resolveValue(valueDefinition, key);
|
|
112
|
+
}
|
|
113
|
+
return resolved;
|
|
114
|
+
}
|
|
115
|
+
isObject(value) {
|
|
116
|
+
return typeof value === 'object' && value !== null;
|
|
117
|
+
}
|
|
118
|
+
resolveValue(valueDefinition, key) {
|
|
119
|
+
if (!this.isObject(valueDefinition)) {
|
|
120
|
+
return valueDefinition;
|
|
121
|
+
}
|
|
122
|
+
if (this.isFromDataValue(valueDefinition)) {
|
|
123
|
+
return this.resolveFromDataValue(valueDefinition, key);
|
|
124
|
+
}
|
|
125
|
+
if (this.isByIndexValue(valueDefinition)) {
|
|
126
|
+
return this.resolveByIndexValue(valueDefinition, key);
|
|
127
|
+
}
|
|
128
|
+
return valueDefinition;
|
|
129
|
+
}
|
|
130
|
+
isFromDataValue(value) {
|
|
131
|
+
return 'fromData' in value && !('type' in value && value.type === 'byIndex');
|
|
132
|
+
}
|
|
133
|
+
isByIndexValue(value) {
|
|
134
|
+
return value.type === 'byIndex' && 'expression' in value;
|
|
135
|
+
}
|
|
136
|
+
resolveFromDataValue(dataDef, key) {
|
|
137
|
+
const referencedData = this.animationContext.getData(dataDef.fromData);
|
|
138
|
+
if (referencedData === undefined) {
|
|
139
|
+
console.warn(`AnimationBuilder: dataKey "${dataDef.fromData}" for property "${key}" not found. Using fallbackValue if provided.`);
|
|
140
|
+
return dataDef.fallbackValue;
|
|
141
|
+
}
|
|
142
|
+
if (Array.isArray(referencedData)) {
|
|
143
|
+
return this.createArrayAccessFunction(referencedData, dataDef);
|
|
144
|
+
}
|
|
145
|
+
return referencedData;
|
|
146
|
+
}
|
|
147
|
+
createArrayAccessFunction(valuesArray, dataDef) {
|
|
148
|
+
const mode = dataDef.mode || 'cycle';
|
|
149
|
+
const fallback = dataDef.fallbackValue;
|
|
150
|
+
const arrayClone = [...valuesArray];
|
|
151
|
+
return (i) => {
|
|
152
|
+
if (arrayClone.length === 0)
|
|
153
|
+
return fallback;
|
|
154
|
+
if (i < arrayClone.length)
|
|
155
|
+
return arrayClone[i];
|
|
156
|
+
switch (mode) {
|
|
157
|
+
case 'cycle':
|
|
158
|
+
return arrayClone[i % arrayClone.length];
|
|
159
|
+
case 'clamp':
|
|
160
|
+
return arrayClone[arrayClone.length - 1];
|
|
161
|
+
default:
|
|
162
|
+
return fallback;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
resolveByIndexValue(dynamicValueDef, key) {
|
|
167
|
+
const expr = dynamicValueDef.expression;
|
|
168
|
+
const dataContext = this.animationContext.getAllData();
|
|
169
|
+
try {
|
|
170
|
+
const boundExpressionFunc = new Function('index', 'data', `return (${expr})`);
|
|
171
|
+
return (i) => {
|
|
172
|
+
try {
|
|
173
|
+
return boundExpressionFunc(i, dataContext);
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
console.warn(`AnimationBuilder: Error executing byIndex expression for '${key}': ${expr}. Index: ${i}. Using fallback.`, e);
|
|
177
|
+
return dynamicValueDef.fallbackValue;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
console.warn(`AnimationBuilder: Error creating function for byIndex expression '${expr}' for '${key}'. Using fallback.`, e);
|
|
183
|
+
return () => dynamicValueDef.fallbackValue;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
calculatePosition(positionDef, itemId, isFirstItem, duration) {
|
|
187
|
+
if (positionDef === undefined) {
|
|
188
|
+
return { value: isFirstItem ? 0 : '>' };
|
|
189
|
+
}
|
|
190
|
+
if (typeof positionDef === 'string') {
|
|
191
|
+
return this.resolveStringPosition(positionDef, duration);
|
|
192
|
+
}
|
|
193
|
+
if (typeof positionDef === 'object') {
|
|
194
|
+
return this.resolveObjectPosition(positionDef);
|
|
195
|
+
}
|
|
196
|
+
if (typeof positionDef === 'number') {
|
|
197
|
+
return { value: positionDef };
|
|
198
|
+
}
|
|
199
|
+
return { value: 0 };
|
|
200
|
+
}
|
|
201
|
+
resolveStringPosition(positionDef, duration) {
|
|
202
|
+
switch (positionDef) {
|
|
203
|
+
case 'in':
|
|
204
|
+
return { value: 0 };
|
|
205
|
+
case 'out': {
|
|
206
|
+
const componentDuration = this.animationContext.getAnimationTargetDuration();
|
|
207
|
+
if (componentDuration !== undefined) {
|
|
208
|
+
const correctOutPosition = Math.max(0, componentDuration - duration);
|
|
209
|
+
return { value: correctOutPosition };
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
console.warn('AnimationBuilder: Cannot position "out" animation - no component duration available');
|
|
213
|
+
return { value: '>' };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
default:
|
|
217
|
+
return { value: positionDef };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
resolveObjectPosition(positionDef) {
|
|
221
|
+
const { anchor, anchorPoint, alignTween = 'start', offset = '0s' } = positionDef;
|
|
222
|
+
const baseTime = this.resolveAnchor(anchor, anchorPoint);
|
|
223
|
+
if (baseTime === undefined) {
|
|
224
|
+
console.warn(`AnimationBuilder: Could not resolve anchor "${anchor}" for position.`);
|
|
225
|
+
return { value: 0 };
|
|
226
|
+
}
|
|
227
|
+
if (alignTween === 'end' || alignTween === 'center') {
|
|
228
|
+
console.warn(`AnimationBuilder: alignTween "${alignTween}" requires knowing the duration of the current animation block. This is advanced and may not be fully supported.`);
|
|
229
|
+
}
|
|
230
|
+
return { value: this.buildPositionString(baseTime, offset) };
|
|
231
|
+
}
|
|
232
|
+
resolveAnchor(anchor, anchorPoint) {
|
|
233
|
+
switch (anchor) {
|
|
234
|
+
case 'componentStart':
|
|
235
|
+
return 0;
|
|
236
|
+
case 'componentCenter': {
|
|
237
|
+
const cd = this.animationContext.getDuration();
|
|
238
|
+
return cd !== undefined ? cd / 2 : undefined;
|
|
239
|
+
}
|
|
240
|
+
case 'componentEnd':
|
|
241
|
+
return this.animationContext.endAnchor;
|
|
242
|
+
default:
|
|
243
|
+
return anchorPoint === 'end' ? `${anchor}.end` : anchor;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
buildPositionString(baseTime, offset) {
|
|
247
|
+
if (offset === '0s' || offset === '0') {
|
|
248
|
+
return `${baseTime}`;
|
|
249
|
+
}
|
|
250
|
+
if (offset.startsWith('+') || offset.startsWith('-')) {
|
|
251
|
+
return `${baseTime}${offset}`;
|
|
252
|
+
}
|
|
253
|
+
return `${baseTime}+=${offset}`;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AnimationPreset as AnimationPresetData, type AnimationPresetInput, type AnimationSequenceItem } from '..';
|
|
2
|
+
export declare class AnimationPreset {
|
|
3
|
+
preset: AnimationPresetData;
|
|
4
|
+
constructor(presetJson: AnimationPresetInput);
|
|
5
|
+
get duration(): number;
|
|
6
|
+
getTimelineItems(): AnimationSequenceItem[];
|
|
7
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AnimationPresetShape } from '..';
|
|
2
|
+
import { get } from 'lodash-es';
|
|
3
|
+
export class AnimationPreset {
|
|
4
|
+
preset;
|
|
5
|
+
constructor(presetJson) {
|
|
6
|
+
const parsedPreset = AnimationPresetShape.safeParse(presetJson);
|
|
7
|
+
if (!parsedPreset.success) {
|
|
8
|
+
console.error('Invalid preset JSON', presetJson);
|
|
9
|
+
throw new Error('Invalid preset JSON');
|
|
10
|
+
}
|
|
11
|
+
this.preset = parsedPreset.data;
|
|
12
|
+
}
|
|
13
|
+
get duration() {
|
|
14
|
+
if (this.preset.duration) {
|
|
15
|
+
return Math.max(0.5, this.preset.duration);
|
|
16
|
+
}
|
|
17
|
+
const offset = Math.min(0.5, get(this.preset, 'startAt', 0.5));
|
|
18
|
+
const timeline = this.getTimelineItems();
|
|
19
|
+
let durations = 0;
|
|
20
|
+
if (timeline.length > 0) {
|
|
21
|
+
durations = timeline
|
|
22
|
+
.map((item) => item.tweens.map((tween) => typeof tween.vars.duration === 'number' ? tween.vars.duration : 0.5))
|
|
23
|
+
.reduce((acc, curr) => acc + curr.map((d) => d || 0.5).reduce((acc, curr) => acc + curr, 0), 0);
|
|
24
|
+
}
|
|
25
|
+
durations = parseFloat(durations.toFixed(2));
|
|
26
|
+
return durations + offset;
|
|
27
|
+
}
|
|
28
|
+
getTimelineItems() {
|
|
29
|
+
return this.preset.timeline;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AnimationPreset, AnimationSequenceItem, SetupStep, TweenVars } from '../..';
|
|
2
|
+
export declare class AnimationPresetFactory {
|
|
3
|
+
static create(id: string): PresetComposer;
|
|
4
|
+
static from(preset: AnimationPreset): PresetComposer;
|
|
5
|
+
}
|
|
6
|
+
declare class PresetComposer {
|
|
7
|
+
private _id;
|
|
8
|
+
private _data;
|
|
9
|
+
private _setup;
|
|
10
|
+
private _timeline;
|
|
11
|
+
private _description?;
|
|
12
|
+
constructor(id: string);
|
|
13
|
+
withData(data: Record<string, any>): PresetComposer;
|
|
14
|
+
withSetup(setup: SetupStep[]): PresetComposer;
|
|
15
|
+
withTimeline(timeline: AnimationSequenceItem[]): PresetComposer;
|
|
16
|
+
withDescription(description: string): PresetComposer;
|
|
17
|
+
resetTimeline(): PresetComposer;
|
|
18
|
+
timeline(): TimelineComposer;
|
|
19
|
+
build(): AnimationPreset;
|
|
20
|
+
}
|
|
21
|
+
declare class TimelineComposer {
|
|
22
|
+
private _presetComposer;
|
|
23
|
+
private _timeline;
|
|
24
|
+
constructor(presetComposer: PresetComposer, existingTimeline?: any[]);
|
|
25
|
+
target(targetQuery: string): TargetComposer;
|
|
26
|
+
get timeline(): any[];
|
|
27
|
+
updateTimeline(): PresetComposer;
|
|
28
|
+
build(): AnimationPreset;
|
|
29
|
+
}
|
|
30
|
+
declare class TargetComposer {
|
|
31
|
+
private _timelineComposer;
|
|
32
|
+
private _timelineIndex;
|
|
33
|
+
private _timeline;
|
|
34
|
+
constructor(timelineComposer: TimelineComposer, timelineIndex: number);
|
|
35
|
+
to(vars: TweenVars, position?: string | number): TargetComposer;
|
|
36
|
+
from(vars: TweenVars, position?: string | number): TargetComposer;
|
|
37
|
+
fromTo(vars: TweenVars, position?: string | number): TargetComposer;
|
|
38
|
+
set(vars: TweenVars, position?: string | number): TargetComposer;
|
|
39
|
+
position(pos: string | number): TargetComposer;
|
|
40
|
+
timeline(): TimelineComposer;
|
|
41
|
+
build(): AnimationPreset;
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export class AnimationPresetFactory {
|
|
2
|
+
static create(id) {
|
|
3
|
+
return new PresetComposer(id);
|
|
4
|
+
}
|
|
5
|
+
static from(preset) {
|
|
6
|
+
// Create a new composer initialized with all properties from the existing preset
|
|
7
|
+
const composer = new PresetComposer(preset.id).withData(preset.data || {});
|
|
8
|
+
// Copy the setup steps if they exist
|
|
9
|
+
if (preset.setup && preset.setup.length > 0) {
|
|
10
|
+
composer.withSetup([...preset.setup]);
|
|
11
|
+
}
|
|
12
|
+
// Copy the timeline if it exists
|
|
13
|
+
if (preset.timeline && preset.timeline.length > 0) {
|
|
14
|
+
composer.withTimeline([...preset.timeline]);
|
|
15
|
+
}
|
|
16
|
+
// Copy any other properties we might want to preserve
|
|
17
|
+
if (preset.description) {
|
|
18
|
+
composer.withDescription(preset.description);
|
|
19
|
+
}
|
|
20
|
+
return composer;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class PresetComposer {
|
|
24
|
+
_id;
|
|
25
|
+
_data = {};
|
|
26
|
+
_setup = [];
|
|
27
|
+
_timeline = [];
|
|
28
|
+
_description;
|
|
29
|
+
constructor(id) {
|
|
30
|
+
this._id = id;
|
|
31
|
+
// Initialize with default preset or empty structure
|
|
32
|
+
}
|
|
33
|
+
withData(data) {
|
|
34
|
+
this._data = { ...this._data, ...data };
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
withSetup(setup) {
|
|
38
|
+
this._setup = [...setup];
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
withTimeline(timeline) {
|
|
42
|
+
this._timeline = [...timeline];
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
withDescription(description) {
|
|
46
|
+
this._description = description;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
// Reset the timeline to start fresh
|
|
50
|
+
resetTimeline() {
|
|
51
|
+
this._timeline = [];
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
timeline() {
|
|
55
|
+
return new TimelineComposer(this, this._timeline);
|
|
56
|
+
}
|
|
57
|
+
build() {
|
|
58
|
+
// Construct and return the final animation preset
|
|
59
|
+
return {
|
|
60
|
+
id: this._id,
|
|
61
|
+
...(this._description ? { description: this._description } : {}),
|
|
62
|
+
data: this._data,
|
|
63
|
+
setup: this._setup,
|
|
64
|
+
timeline: this._timeline
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class TimelineComposer {
|
|
69
|
+
_presetComposer;
|
|
70
|
+
_timeline = [];
|
|
71
|
+
constructor(presetComposer, existingTimeline = []) {
|
|
72
|
+
this._presetComposer = presetComposer;
|
|
73
|
+
this._timeline = [...existingTimeline];
|
|
74
|
+
}
|
|
75
|
+
target(targetQuery) {
|
|
76
|
+
// Create a new sequence item for this target
|
|
77
|
+
const sequenceItem = {
|
|
78
|
+
target: targetQuery,
|
|
79
|
+
tweens: []
|
|
80
|
+
};
|
|
81
|
+
// Add it to the timeline
|
|
82
|
+
this._timeline.push(sequenceItem);
|
|
83
|
+
return new TargetComposer(this, this._timeline.length - 1);
|
|
84
|
+
}
|
|
85
|
+
// Public getter for timeline access
|
|
86
|
+
get timeline() {
|
|
87
|
+
return this._timeline;
|
|
88
|
+
}
|
|
89
|
+
// Allow updating the preset composer with the current timeline
|
|
90
|
+
updateTimeline() {
|
|
91
|
+
return this._presetComposer.withTimeline(this._timeline);
|
|
92
|
+
}
|
|
93
|
+
build() {
|
|
94
|
+
// Update the timeline before building
|
|
95
|
+
return this.updateTimeline().build();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
class TargetComposer {
|
|
99
|
+
_timelineComposer;
|
|
100
|
+
_timelineIndex;
|
|
101
|
+
_timeline;
|
|
102
|
+
constructor(timelineComposer, timelineIndex) {
|
|
103
|
+
this._timelineComposer = timelineComposer;
|
|
104
|
+
this._timelineIndex = timelineIndex;
|
|
105
|
+
this._timeline = timelineComposer.timeline;
|
|
106
|
+
}
|
|
107
|
+
to(vars, position) {
|
|
108
|
+
this._timeline[this._timelineIndex].tweens.push({ method: 'to', vars, position });
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
from(vars, position) {
|
|
112
|
+
this._timeline[this._timelineIndex].tweens.push({ method: 'from', vars, position });
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
fromTo(vars, position) {
|
|
116
|
+
if (!vars.from) {
|
|
117
|
+
throw new Error('from is required for fromTo');
|
|
118
|
+
}
|
|
119
|
+
this._timeline[this._timelineIndex].tweens.push({ method: 'fromTo', vars, position });
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
set(vars, position) {
|
|
123
|
+
this._timeline[this._timelineIndex].tweens.push({ method: 'set', vars, position });
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
// Set the position of this timeline item
|
|
127
|
+
position(pos) {
|
|
128
|
+
this._timeline[this._timelineIndex].position = pos;
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
// Return to timeline context
|
|
132
|
+
timeline() {
|
|
133
|
+
return this._timelineComposer;
|
|
134
|
+
}
|
|
135
|
+
// Build the final preset
|
|
136
|
+
build() {
|
|
137
|
+
return this.timeline().build();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Animation } from '../..';
|
|
2
|
+
import type { ComponentData } from '../..';
|
|
3
|
+
import type { SplitTextCache } from '../SplitTextCache.js';
|
|
4
|
+
export declare class LineHighlighterAnimationBuilder {
|
|
5
|
+
static build(data: ComponentData, target: HTMLElement, animationData: Record<string, any>, splitTextCache: SplitTextCache): Animation[];
|
|
6
|
+
private static createLineHighlightAnimations;
|
|
7
|
+
private static prepareHighlightStyles;
|
|
8
|
+
private static createHighlightAnimation;
|
|
9
|
+
private static createUnhighlightAnimation;
|
|
10
|
+
private static createBackgroundHighlightAnimation;
|
|
11
|
+
private static generateBackgroundElementId;
|
|
12
|
+
private static createBackgroundElement;
|
|
13
|
+
private static getBackgroundConfig;
|
|
14
|
+
private static initializeBackgroundElement;
|
|
15
|
+
private static buildBackgroundAnimation;
|
|
16
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { get } from 'lodash-es';
|
|
2
|
+
import { linesHighlighter } from '../presets/lines.js'; // Assuming this exists
|
|
3
|
+
import { AnimationPresetFactory } from './AnimationPresetFactory.js';
|
|
4
|
+
import { ColorTransformer } from '../../transformers/ColorTransformer.js';
|
|
5
|
+
export class LineHighlighterAnimationBuilder {
|
|
6
|
+
static build(data, target, animationData, splitTextCache) {
|
|
7
|
+
if (data.type !== 'TEXT') {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const activeLine = get(data, 'appearance.text.activeLine', null);
|
|
11
|
+
if (!activeLine || !activeLine.enabled) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const config = {
|
|
15
|
+
activeLine,
|
|
16
|
+
data,
|
|
17
|
+
animationData,
|
|
18
|
+
target,
|
|
19
|
+
splitTextCache
|
|
20
|
+
};
|
|
21
|
+
return this.createLineHighlightAnimations(config);
|
|
22
|
+
}
|
|
23
|
+
static createLineHighlightAnimations(config) {
|
|
24
|
+
const animations = [];
|
|
25
|
+
const styles = this.prepareHighlightStyles(config);
|
|
26
|
+
// Create main highlight animation
|
|
27
|
+
const highlightAnimation = this.createHighlightAnimation(config.data.id, styles.highlight, config.animationData);
|
|
28
|
+
animations.push(highlightAnimation);
|
|
29
|
+
// Create unhighlight animation if needed
|
|
30
|
+
const unhighlightAnimation = this.createUnhighlightAnimation(config.data.id, styles.original, config.animationData);
|
|
31
|
+
if (unhighlightAnimation) {
|
|
32
|
+
animations.push(unhighlightAnimation);
|
|
33
|
+
}
|
|
34
|
+
// Create background highlight animation if needed
|
|
35
|
+
const backgroundAnimation = this.createBackgroundHighlightAnimation(config);
|
|
36
|
+
if (backgroundAnimation) {
|
|
37
|
+
animations.push(backgroundAnimation);
|
|
38
|
+
}
|
|
39
|
+
return animations;
|
|
40
|
+
}
|
|
41
|
+
static prepareHighlightStyles(config) {
|
|
42
|
+
const { activeLine, data } = config;
|
|
43
|
+
const highlightStyles = ColorTransformer.transform(activeLine.color, 'background');
|
|
44
|
+
const originalStyles = ColorTransformer.transform(data.appearance.text?.color, 'background');
|
|
45
|
+
// Handle font weight if specified
|
|
46
|
+
if (get(activeLine, 'fontWeight', undefined)) {
|
|
47
|
+
highlightStyles.fontWeight = activeLine.fontWeight;
|
|
48
|
+
originalStyles.fontWeight = data.appearance.text?.fontWeight ?? 'normal';
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
highlight: highlightStyles,
|
|
52
|
+
original: originalStyles
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
static createHighlightAnimation(componentId, styles, animationData) {
|
|
56
|
+
const animation = AnimationPresetFactory.from(linesHighlighter)
|
|
57
|
+
.resetTimeline()
|
|
58
|
+
.timeline()
|
|
59
|
+
.target('lines')
|
|
60
|
+
.to({
|
|
61
|
+
...styles,
|
|
62
|
+
stagger: { type: 'fromData', dataKey: 'lineStartTimes' } // Use line timing data
|
|
63
|
+
})
|
|
64
|
+
.build();
|
|
65
|
+
return {
|
|
66
|
+
id: `lines-highlight-${componentId}`,
|
|
67
|
+
name: 'Lines Highlight',
|
|
68
|
+
animation,
|
|
69
|
+
startAt: 0
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
static createUnhighlightAnimation(componentId, originalStyles, animationData) {
|
|
73
|
+
if (!animationData.lineUnhighlightTimes) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const animation = AnimationPresetFactory.from(linesHighlighter)
|
|
77
|
+
.resetTimeline()
|
|
78
|
+
.timeline()
|
|
79
|
+
.target('lines')
|
|
80
|
+
.to({
|
|
81
|
+
...originalStyles,
|
|
82
|
+
stagger: { type: 'fromData', dataKey: 'lineUnhighlightTimes' }
|
|
83
|
+
})
|
|
84
|
+
.build();
|
|
85
|
+
return {
|
|
86
|
+
id: `lines-highlight-${componentId}-unhighlight`,
|
|
87
|
+
name: 'Lines Unhighlight',
|
|
88
|
+
animation,
|
|
89
|
+
startAt: 0
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
static createBackgroundHighlightAnimation(config) {
|
|
93
|
+
const { activeLine, target, splitTextCache, data, animationData } = config;
|
|
94
|
+
if (!activeLine.backgroundColor) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const lines = splitTextCache.getSplitText(target, 'lines');
|
|
98
|
+
if (!lines?.length) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const bgHighlighter = this.createBackgroundElement(target, data.id);
|
|
102
|
+
const backgroundConfig = this.getBackgroundConfig(activeLine);
|
|
103
|
+
const bgStyles = ColorTransformer.transform(activeLine.backgroundColor, 'background');
|
|
104
|
+
this.initializeBackgroundElement(bgHighlighter, lines[0], backgroundConfig, bgStyles);
|
|
105
|
+
const animation = this.buildBackgroundAnimation(data.id, bgHighlighter.id, lines, animationData, backgroundConfig, bgStyles);
|
|
106
|
+
return {
|
|
107
|
+
id: `lines-background-highlight-${data.id}`,
|
|
108
|
+
name: 'Lines Background Highlight',
|
|
109
|
+
animation,
|
|
110
|
+
startAt: 0
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
static generateBackgroundElementId(componentId) {
|
|
114
|
+
return `highlighter-bg-lines-${componentId}`;
|
|
115
|
+
}
|
|
116
|
+
static createBackgroundElement(target, componentId) {
|
|
117
|
+
const bgHighlighter = document.createElement('div');
|
|
118
|
+
bgHighlighter.id = this.generateBackgroundElementId(componentId);
|
|
119
|
+
bgHighlighter.style.position = 'absolute';
|
|
120
|
+
bgHighlighter.style.pointerEvents = 'none';
|
|
121
|
+
target.prepend(bgHighlighter);
|
|
122
|
+
return bgHighlighter;
|
|
123
|
+
}
|
|
124
|
+
static getBackgroundConfig(activeLine) {
|
|
125
|
+
return {
|
|
126
|
+
paddingX: get(activeLine, 'backgroundPaddingX', 25),
|
|
127
|
+
paddingY: get(activeLine, 'backgroundPaddingY', 10),
|
|
128
|
+
borderRadius: get(activeLine, 'backgroundBorderRadius', 10)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
static initializeBackgroundElement(bgHighlighter, firstLine, config, bgStyles) {
|
|
132
|
+
const { paddingX, paddingY, borderRadius } = config;
|
|
133
|
+
bgHighlighter.style.left = `${firstLine.offsetLeft - paddingX}px`;
|
|
134
|
+
bgHighlighter.style.top = `${firstLine.offsetTop - paddingY}px`;
|
|
135
|
+
bgHighlighter.style.width = `${firstLine.clientWidth + 2 * paddingX}px`;
|
|
136
|
+
bgHighlighter.style.height = `${firstLine.clientHeight + 2 * paddingY}px`;
|
|
137
|
+
bgHighlighter.style.borderRadius = `${borderRadius}px`;
|
|
138
|
+
bgHighlighter.style.opacity = '1';
|
|
139
|
+
if (bgStyles) {
|
|
140
|
+
Object.entries(bgStyles).forEach(([key, value]) => {
|
|
141
|
+
// Check if key is a valid writable style property
|
|
142
|
+
if (key in bgHighlighter.style) {
|
|
143
|
+
bgHighlighter.style[key] = String(value);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// For custom properties or CSS variables, use setProperty
|
|
147
|
+
bgHighlighter.style.setProperty(key, String(value));
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
static buildBackgroundAnimation(componentId, backgroundElementId, lines, animationData, backgroundConfig, bgStyles) {
|
|
153
|
+
const presetComposer = AnimationPresetFactory.create(`lines-bg-highlight-anim-${componentId}`);
|
|
154
|
+
const timelineComposer = presetComposer.timeline();
|
|
155
|
+
const targetComposer = timelineComposer.target(`#${backgroundElementId}`);
|
|
156
|
+
const lineStartTimes = animationData.lineStartTimes ?? []; // Use line timing data
|
|
157
|
+
if (lineStartTimes.length <= 1) {
|
|
158
|
+
return timelineComposer.build();
|
|
159
|
+
}
|
|
160
|
+
const { paddingX, paddingY, borderRadius } = backgroundConfig;
|
|
161
|
+
for (let i = 0; i < lineStartTimes.length; i++) {
|
|
162
|
+
const currentLine = lines[i];
|
|
163
|
+
if (!currentLine) {
|
|
164
|
+
console.warn(`LineHighlighter: Line element at index ${i} is missing.`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const startTime = parseFloat(lineStartTimes[i].toFixed(3));
|
|
168
|
+
targetComposer
|
|
169
|
+
.to({
|
|
170
|
+
borderRadius: `${borderRadius}px`,
|
|
171
|
+
left: currentLine.offsetLeft - paddingX,
|
|
172
|
+
top: currentLine.offsetTop - paddingY,
|
|
173
|
+
width: currentLine.clientWidth + 2 * paddingX,
|
|
174
|
+
height: currentLine.clientHeight + 2 * paddingY,
|
|
175
|
+
duration: 0.15,
|
|
176
|
+
ease: 'power1.out',
|
|
177
|
+
...bgStyles
|
|
178
|
+
}, startTime)
|
|
179
|
+
.position(0);
|
|
180
|
+
}
|
|
181
|
+
return timelineComposer.build();
|
|
182
|
+
}
|
|
183
|
+
}
|