Skip to content

Commit

Permalink
* MS the transition-period for timeline-driven map-scrolling/node-mov…
Browse files Browse the repository at this point in the history
…ing can be customized, using a new step-effect. (setTransitionPeriod)

* FIxed that MapUI was applying "willChange:transform" to the wrong container. (with this fix, scrolling is a bit smoother when tons of nodes are loaded, eg. 1000+)
  • Loading branch information
Venryx committed Feb 28, 2024
1 parent 3eba1b8 commit 2df7065
Show file tree
Hide file tree
Showing 10 changed files with 36 additions and 17 deletions.
12 changes: 7 additions & 5 deletions Packages/client/Source/UI/@Shared/Maps/MapGraph.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {GetMap, GetTimelineStepTimesFromStart, GetTimelineSteps, GetTimelineStepsReachedByTimeX, NodeType, TimelineStep} from "dm_common";
import {GetMap, GetTimelineStepTimesFromStart, GetTimelineSteps, GetTimelineStepsReachedByTimeX, NodeType, TimelineStep, TimelineStepEffect_defaultTransitionPeriod} from "dm_common";
import {useMemo} from "react";
import {Graph, KeyframeInfo} from "tree-grapher";
import {GetMapState} from "Store/main/maps/mapStates/$mapState";
Expand All @@ -22,8 +22,7 @@ export class NodeDataForTreeGrapher {
aboveToolbar_hasLeftButton?: boolean;
}

const animation_transitionPeriod = .5;
export const GetPercentThroughTransition = (lastKeyframe_time: number|n, nextKeyframe_time: number|n, currentTime: number|n)=>{
export const GetPercentThroughTransition = (lastKeyframe_time: number|n, nextKeyframe_time: number|n, currentTime: number|n, animation_transitionPeriod: number)=>{
//AssertWarn(lastKeyframe_time != null, "lastKeyframe_time must be non-null.");
//AssertWarn(nextKeyframe_time != null, "nextKeyframe_time must be non-null.");
if (lastKeyframe_time == null || nextKeyframe_time == null || currentTime == null) return null;
Expand Down Expand Up @@ -56,6 +55,8 @@ export const GetTimelineApplyEssentials = CreateAccessor({cache_comparer: compar

const effectsReached = currentEffect_time != null ? effects.filter(a=>a.time_absolute <= currentEffect_time) : [];
const effectsReachedAtNext = nextEffect_time != null ? effects.filter(a=>a.time_absolute <= nextEffect_time) : [];

const currentTransitionPeriod = effectsReached.LastOrX(a=>a.setTransitionPeriod != null)?.setTransitionPeriod ?? TimelineStepEffect_defaultTransitionPeriod;
return {
playback,
effects,
Expand All @@ -65,6 +66,7 @@ export const GetTimelineApplyEssentials = CreateAccessor({cache_comparer: compar
nextEffect_time: nextEffect_time as number|n, // needs to be redeclared as nullable fsr
effectsReached,
effectsReachedAtNext,
currentTransitionPeriod,
};
});

Expand All @@ -74,13 +76,13 @@ export function useGraph(forLayoutHelper: boolean, layoutHelperGraph: Graph|null
const mainGraph_getNextKeyframeInfo_base = (): KeyframeInfo|null=>{
const data = GetTimelineApplyEssentials();
if (data == null) return null;
const {playback, currentEffect_time, nextEffect_time, effectsReachedAtNext} = data;
const {playback, currentEffect_time, nextEffect_time, effectsReachedAtNext, currentTransitionPeriod} = data;
const currentTime = playback.mapState.playingTimeline_time ?? 0;

//const finalKeyframe_time = stepTimes.Last();
const nodePathsVisibleAtNextKeyframe = GetVisiblePathsAfterEffects([playback.map.rootNode], effectsReachedAtNext);
const layout = layoutHelperGraph!.GetLayout(undefined, group=>RevealPathsIncludesNode(nodePathsVisibleAtNextKeyframe, group.leftColumn_userData?.["nodePath"] as string))!;
const percentThroughTransition = GetPercentThroughTransition(currentEffect_time, nextEffect_time, currentTime) ?? 0;
const percentThroughTransition = GetPercentThroughTransition(currentEffect_time, nextEffect_time, currentTime, currentTransitionPeriod) ?? 0;
return {layout, percentThroughTransition};
};
const mainGraph_getNextKeyframeInfo = ()=>CatchBail(null, mainGraph_getNextKeyframeInfo_base);
Expand Down
2 changes: 1 addition & 1 deletion Packages/client/Source/UI/@Shared/Maps/MapUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class MapUI extends BaseComponent<Props, {}> {
backgroundDrag={true} backgroundDragMatchFunc={a=>a == GetDOM(this.scrollView!.contentOuter) || a == this.scrollView!.content || a == this.mapUIEl}
style={ES({width: "100%", height: "100%"}, withinPage && {overflow: "visible"})}
scrollHBarStyle={E({height: 10}, withinPage && {display: "none"})} scrollVBarStyle={E({width: 10}, withinPage && {display: "none"})}
contentStyle={E(
contentOuterStyle={E(
{willChange: "transform"}, // keeping willChange:transform can normally make text blurry after zooming, but we're good, since we have the zoom button trigger a re-rasterization
withinPage && {position: "relative", marginBottom: -300, paddingBottom: 300},
withinPage && inFirefox && {overflow: "hidden"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const TimelineEffectApplier_Smooth = observer_mgl((props: {map: Map, mapS
const data = GetTimelineApplyEssentials();
if (data == null) return null;
if (data.playback.mapID != map.id) return null;
const {currentEffect_time, nextEffect_time, effectsReached, effectsReachedAtNext} = data;
const {currentEffect_time, nextEffect_time, effectsReached, effectsReachedAtNext, currentTransitionPeriod} = data;
//if (currentEffect_time == null || nextEffect_time == null) return null;
const currentTime = mapState.playingTimeline_time ?? 0;

Expand Down Expand Up @@ -57,7 +57,7 @@ export const TimelineEffectApplier_Smooth = observer_mgl((props: {map: Map, mapS
const lastFocusNodeRectsMerged = MergeNodeRects(lastFocusNodePaths, lastKeyframe_groupRects);
const nextFocusNodeRectsMerged = MergeNodeRects(nextFocusNodePaths, nextKeyframe_groupRects);
if (lastFocusNodeRectsMerged == null || nextFocusNodeRectsMerged == null) return null;
const percentFromLastToNext = GetPercentThroughTransition(currentEffect_time, nextEffect_time, mapState.playingTimeline_time) ?? 0;
const percentFromLastToNext = GetPercentThroughTransition(currentEffect_time, nextEffect_time, mapState.playingTimeline_time, currentTransitionPeriod) ?? 0;
const focusNodeRects_interpolated = InterpolateRect(lastFocusNodeRectsMerged, nextFocusNodeRectsMerged, percentFromLastToNext);
//console.log("percentFromLastToNext:", percentFromLastToNext);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class NodeUI_ForBots extends BaseComponentPlus({} as Props, {}) {
return (
<ScrollView
// backgroundDrag={true} backgroundDragMatchFunc={a=>a == GetDOM(this.refs.scrollView.contentOuter) || a == this.refs.mapUI}
scrollVBarStyle={{width: 10}} /* contentStyle={{willChange: "transform"}} */>
scrollVBarStyle={{width: 10}} /*contentOuterStyle={{willChange: "transform"}}*/>
<Row>
<Pre>Parents: </Pre>{nodeParents.map((parent, index)=>{
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {OPFS_Map} from "Utils/OPFS/OPFS_Map";
import {liveSkin} from "Utils/Styles/SkinManager";
import {DraggableInfo, DroppableInfo} from "Utils/UI/DNDStructures.js";
import {zIndexes} from "Utils/UI/ZIndexes.js";
import {GetNodeEffects, GetTimelineSteps, IsUserCreatorOrMod, Map, MeID, OrderKey, Timeline, TimelineStep, TimelineStepEffect} from "dm_common";
import {GetNodeEffects, GetTimelineSteps, IsUserCreatorOrMod, Map, MeID, OrderKey, Timeline, TimelineStep, TimelineStepEffect, TimelineStepEffect_defaultTransitionPeriod} from "dm_common";
import {DragInfo, MakeDraggable, Observer, RunInAction_Set} from "web-vcore";
import {Clone, E, GetEntries, ModifyString, ToJSON, VRect, Vector2, WaitXThenRun} from "web-vcore/nm/js-vextensions.js";
import {RunInAction} from "web-vcore/nm/mobx-graphlink.js";
Expand Down Expand Up @@ -215,6 +215,13 @@ export class StepEditorUI extends BaseComponentPlus({} as StepEditorUIProps, {pl
];
RunCommand_UpdateTimelineStep({id: step.id, updates: {extras: {...step.extras, effects: newEffects}}});
}}/>
<VMenuItem text="Set transition period" style={liveSkin.Style_VMenuItem()} onClick={()=>{
const newEffects = [
...(step.extras?.effects ?? []),
new TimelineStepEffect({setTransitionPeriod: TimelineStepEffect_defaultTransitionPeriod}),
];
RunCommand_UpdateTimelineStep({id: step.id, updates: {extras: {...step.extras, effects: newEffects}}});
}}/>
</>,
);
}}/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ export class StepEffectUI extends BaseComponentPlus({} as {map: Map, step: Timel

const nodeInfo = effect.nodeEffect ? GetNodeInfoForStepEffectUI(effect.nodeEffect) : null;

let displayText: string = "[unknown effect type]";
let displayText: string|JSX.Element = "[unknown effect type]";
if (effect.nodeEffect) displayText = nodeInfo && nodeInfo.node && nodeInfo.nodeL3 ? GetNodeDisplayText(nodeInfo.node, nodeInfo.path) : `(Node no longer exists: ${GetNodeID(nodeInfo?.path)})`;
else if (effect.setTimeTrackerState != null) displayText = `Set time-tracker state: ${effect.setTimeTrackerState ? "visible" : "hidden"}`;
else if (effect.setTransitionPeriod != null) {
displayText = <Row>
<Text>Set transition period:</Text>
<Spinner ml={5} step="any" value={effect.setTransitionPeriod} onChange={val=>UpdateStepEffect(step, index, effect, a=>a.setTransitionPeriod = val)}/>
<Text>s</Text>
</Row>;
}

let backgroundColor: chroma.Color;
if (effect.nodeEffect) backgroundColor = GetNodeColor(nodeInfo?.nodeL3 || {type: NodeType.category} as any).desaturate(0.5).alpha(0.8);
Expand All @@ -64,7 +71,7 @@ export class StepEffectUI extends BaseComponentPlus({} as {map: Map, step: Timel
{/*<Pre>{effect.time_relative.toFixed(1)}</Pre>*/}
<span style={{position: "relative", paddingTop: 2, fontSize: 12, color: "rgba(20,20,20,1)"}}>
<span style={{
position: "absolute", left: -5, top: -8, lineHeight: "11px", fontSize: 10, color: "yellow",
position: "absolute", left: -5, top: -8, lineHeight: "11px", fontSize: 10, whiteSpace: "pre", color: "yellow",
background: "rgba(50,50,50,1)", borderRadius: 5, padding: "0 3px",
}}>
{[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class StepAudio_TakeUI extends BaseComponent<{map: Map, step: TimelineSte
}</Text>
<AudioFileMiniPlayer file={origAudioFile} buttonProps={{style: {marginLeft: 5}, title: "Play the original recorded audio-contents"}}/>
{/*<Select ml={5} options={voiceChangerBridge.GetVoiceOptionsForSelect()} style={{flex: 1, minWidth: 0}} value={selectedVoice?.slotIndex} onChange={val=>this.SetState({selectedVoiceIndex: val?.slot})}/>*/}
<Button ml={5} mdIcon="account-voice" enabled={origAudioFile != null && voiceChangerBridge.activeSlotIndex > -1} title="Send to voice-converter, using selected voice" onClick={async()=>{
<Button ml={5} mdIcon="account-voice" enabled={origAudioFile != null && voiceChangerBridge.activeSlotIndex != null} title="Send to voice-converter, using selected voice" onClick={async()=>{
const audioFileBuffer = await origAudioFile!.arrayBuffer();
const outputFileBuffer = await ConvertAudioFileUsingVoiceChanger(audioFileBuffer);
const outputFile = new File([outputFileBuffer], origAudioFile!.name.replace(/_Orig\..+$/, "_Converted.wav"), {type: "audio/wav"});
Expand Down
2 changes: 1 addition & 1 deletion Packages/client/Source/Utils/Bridge/Bridge_VoiceChanger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class VoiceChangerBridge {

// stored info
@O voices: Voice[] = [];
@O activeSlotIndex = -1;
@O activeSlotIndex: number|n;

// getters
@computed get Voices() {
Expand Down
4 changes: 2 additions & 2 deletions Packages/js-common/Source/DB/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ export const GetNodeChildren = CreateAccessor((nodeID: string, includeMirrorChil
if (c.catchItemBails) return GetNode.CatchBail(c.catchItemBails_asX, link.child);
return GetNode(link.child);
});*/
//let result = MapWithBailHandling(childLinks, link=>GetNode.BIN(link.child)); // BIN: we know link exists, so child-node should as well (so null must mean change loading)
let result = MapWithBailHandling(childLinks, link=>GetNode(link.child) as NodeL1);
let result = MapWithBailHandling(childLinks, link=>GetNode.BIN(link.child)); // BIN: we know link exists, so child-node should as well (so null must mean change loading)
//let result = MapWithBailHandling(childLinks, link=>GetNode(link.child) as NodeL1);
if (includeMirrorChildren) {
//let tags = GetNodeTags(nodeID);
const tagComps = GetNodeTagComps(nodeID, true, tagsToIgnore);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
export const TimelineStepEffect_defaultTransitionPeriod = 0.5; // in seconds

export class TimelineStepEffect {
constructor(data?: Partial<TimelineStepEffect>) { Object.assign(this, data); }
/** Time that effect takes place, as seconds since start of step. */
time_relative = 0;

nodeEffect?: NodeEffect;
setTimeTrackerState?: boolean;
setTransitionPeriod?: number;
}

export function IsStepEffectEmpty(stepEffect: TimelineStepEffect) {
return IsNodeEffectEmpty(stepEffect.nodeEffect) && stepEffect.setTimeTrackerState == null;
return IsNodeEffectEmpty(stepEffect.nodeEffect) && stepEffect.setTimeTrackerState == null && stepEffect.setTransitionPeriod == null;
}

export class NodeEffect {
Expand Down

0 comments on commit 2df7065

Please sign in to comment.