perf: reduce editor drag lookup overhead

This commit is contained in:
OpenClaw Agent
2026-07-09 20:34:40 +00:00
parent 39af2b0150
commit 50664026a1
2 changed files with 40 additions and 28 deletions

View File

@@ -73,6 +73,14 @@ function findActiveSegmentAtFrame(segments = [], targetFrame, type) {
function segmentMatchesAudioSource(seg, audioFile, blobUrl) { function segmentMatchesAudioSource(seg, audioFile, blobUrl) {
return !!seg && (seg.audioFile === audioFile || seg._blobUrl === blobUrl); return !!seg && (seg.audioFile === audioFile || seg._blobUrl === blobUrl);
} }
function findSegmentIndexById(segments = [], segmentId) {
return (segments || []).findIndex((seg) => seg.id === segmentId);
}
function findSegmentById(segments = [], segmentId) {
return (segments || []).find((seg) => seg.id === segmentId);
}
function hideWidget(w) { function hideWidget(w) {
if (!w) return; if (!w) return;
@@ -8075,7 +8083,8 @@ class TimelineEditor {
const durationFrames = totalFrames; const durationFrames = totalFrames;
let dragDelta = Math.round((mouseX - this._dragStartX) * (totalFrames / logicalWidth)); let dragDelta = Math.round((mouseX - this._dragStartX) * (totalFrames / logicalWidth));
const selectedIds = this.selectedSegmentIds; const selectedIds = this.selectedSegmentIds;
const selectedIdSet = new Set(selectedIds);
// Group Blocking Physics Calculation // Group Blocking Physics Calculation
let maxLeftShift = Infinity; let maxLeftShift = Infinity;
@@ -8084,8 +8093,8 @@ class TimelineEditor {
for (const track of ["image", "motion", "audio"]) { for (const track of ["image", "motion", "audio"]) {
const allTrackSegs = this._multiDragInitialSegments[track]; const allTrackSegs = this._multiDragInitialSegments[track];
if (!allTrackSegs) continue; if (!allTrackSegs) continue;
const selectedOnTrack = allTrackSegs.filter(s => selectedIds.includes(s.id)); const selectedOnTrack = allTrackSegs.filter(s => selectedIdSet.has(s.id));
const nonSelectedOnTrack = allTrackSegs.filter(s => !selectedIds.includes(s.id)); const nonSelectedOnTrack = allTrackSegs.filter(s => !selectedIdSet.has(s.id));
if (selectedOnTrack.length === 0) continue; if (selectedOnTrack.length === 0) continue;
@@ -8130,7 +8139,7 @@ class TimelineEditor {
for (const track of ["image", "motion", "audio"]) { for (const track of ["image", "motion", "audio"]) {
const allTrackSegs = this._multiDragInitialSegments[track]; const allTrackSegs = this._multiDragInitialSegments[track];
if (!allTrackSegs) continue; if (!allTrackSegs) continue;
const nonSelectedOnTrack = allTrackSegs.filter(s => !selectedIds.includes(s.id)); const nonSelectedOnTrack = allTrackSegs.filter(s => !selectedIdSet.has(s.id));
for (const L of nonSelectedOnTrack) { for (const L of nonSelectedOnTrack) {
snapCandidates.push(L.start); snapCandidates.push(L.start);
snapCandidates.push(L.start + L.length); snapCandidates.push(L.start + L.length);
@@ -8141,7 +8150,7 @@ class TimelineEditor {
for (const track of ["image", "motion", "audio"]) { for (const track of ["image", "motion", "audio"]) {
const allTrackSegs = this._multiDragInitialSegments[track]; const allTrackSegs = this._multiDragInitialSegments[track];
if (!allTrackSegs) continue; if (!allTrackSegs) continue;
const selectedOnTrack = allTrackSegs.filter(s => selectedIds.includes(s.id)); const selectedOnTrack = allTrackSegs.filter(s => selectedIdSet.has(s.id));
for (const S of selectedOnTrack) { for (const S of selectedOnTrack) {
const targetStart = S.start + clampedDragDelta; const targetStart = S.start + clampedDragDelta;
const targetEnd = S.start + S.length + clampedDragDelta; const targetEnd = S.start + S.length + clampedDragDelta;
@@ -8896,12 +8905,12 @@ class TimelineEditor {
return ps; return ps;
}); });
} }
if (this._multiDragPreviewTimelines.audio) { if (this._multiDragPreviewTimelines.audio) {
this.timeline.audioSegments = this._multiDragPreviewTimelines.audio.map(ps => { this.timeline.audioSegments = this._multiDragPreviewTimelines.audio.map(ps => {
const orig = this.timeline.audioSegments.find(s => s.id === ps.id); const orig = findSegmentById(this.timeline.audioSegments, ps.id);
if (orig) { if (orig) {
if (orig.imgObj) ps.imgObj = orig.imgObj; if (orig.imgObj) ps.imgObj = orig.imgObj;
if (orig.videoEl) ps.videoEl = orig.videoEl; if (orig.videoEl) ps.videoEl = orig.videoEl;
if (orig.thumbnails) ps.thumbnails = orig.thumbnails; if (orig.thumbnails) ps.thumbnails = orig.thumbnails;
if (orig._extractingThumbs !== undefined) ps._extractingThumbs = orig._extractingThumbs; if (orig._extractingThumbs !== undefined) ps._extractingThumbs = orig._extractingThumbs;
if (orig._uploading !== undefined) ps._uploading = orig._uploading; if (orig._uploading !== undefined) ps._uploading = orig._uploading;
@@ -8914,12 +8923,12 @@ class TimelineEditor {
} }
this._multiDragPreviewTimelines = null; this._multiDragPreviewTimelines = null;
} else if (this._previewSegments) { } else if (this._previewSegments) {
const targetArray = this.getSegmentArray(this.selectionType); const targetArray = this.getSegmentArray(this.selectionType);
const mappedArray = this._previewSegments.map(ps => { const mappedArray = this._previewSegments.map(ps => {
const orig = targetArray.find(s => s.id === ps.id); const orig = findSegmentById(targetArray, ps.id);
let finalStart = ps.resolvedStart !== undefined ? ps.resolvedStart : ps.start; let finalStart = ps.resolvedStart !== undefined ? ps.resolvedStart : ps.start;
let newPs = { ...ps, start: finalStart }; let newPs = { ...ps, start: finalStart };
if (orig) { if (orig) {
if (orig.imgObj) newPs.imgObj = orig.imgObj; if (orig.imgObj) newPs.imgObj = orig.imgObj;
if (orig.videoEl) newPs.videoEl = orig.videoEl; if (orig.videoEl) newPs.videoEl = orig.videoEl;
@@ -8934,17 +8943,17 @@ class TimelineEditor {
return newPs; return newPs;
}); });
if (this.selectionType === "audio") { if (this.selectionType === "audio") {
this.timeline.audioSegments = mappedArray; this.timeline.audioSegments = mappedArray;
if (this._dragTargetId) this.selectedIndex = this.timeline.audioSegments.findIndex(s => s.id === this._dragTargetId); if (this._dragTargetId) this.selectedIndex = findSegmentIndexById(this.timeline.audioSegments, this._dragTargetId);
} else if (this.selectionType === "motion") { } else if (this.selectionType === "motion") {
this.timeline.motionSegments = mappedArray; this.timeline.motionSegments = mappedArray;
if (this._dragTargetId) this.selectedIndex = this.timeline.motionSegments.findIndex(s => s.id === this._dragTargetId); if (this._dragTargetId) this.selectedIndex = findSegmentIndexById(this.timeline.motionSegments, this._dragTargetId);
} else { } else {
this.timeline.segments = mappedArray; this.timeline.segments = mappedArray;
if (this._dragTargetId) this.selectedIndex = this.timeline.segments.findIndex(s => s.id === this._dragTargetId); if (this._dragTargetId) this.selectedIndex = findSegmentIndexById(this.timeline.segments, this._dragTargetId);
} }
} }
if (this._previewSiblingSegments) { if (this._previewSiblingSegments) {
let siblingArray = null; let siblingArray = null;

View File

@@ -288,6 +288,9 @@ def _time_range_to_latent_indices(rel_start_frames: float, rel_length_frames: fl
def _preprocess_prompts_with_characters(global_prompt, local_prompts, char1="", char2="", char3=""): def _preprocess_prompts_with_characters(global_prompt, local_prompts, char1="", char2="", char3=""):
"""Invisibly swaps out @character1/@char1 tags with their high-fidelity VLM descriptions.""" """Invisibly swaps out @character1/@char1 tags with their high-fidelity VLM descriptions."""
if "@" not in (global_prompt or "") and "@" not in (local_prompts or ""):
return global_prompt or "", local_prompts or ""
replacements = {} replacements = {}
for tags, value in zip(CHARACTER_TAG_GROUPS, (char1 or "", char2 or "", char3 or "")): for tags, value in zip(CHARACTER_TAG_GROUPS, (char1 or "", char2 or "", char3 or "")):
for tag in tags: for tag in tags: