Merge d1dd7dcfb2 into 2afde23a5d
commit
4f56d844fa
|
|
@ -85,6 +85,15 @@
|
|||
let shiftKeyIsDown = $state(false);
|
||||
let lastAssetMouseEvent: TimelineAsset | null = $state(null);
|
||||
let scrollTop = $state(0);
|
||||
|
||||
// Asset ID index lookup map for O(1) range computation
|
||||
let assetIndexMap = $derived.by(() => {
|
||||
const map = new Map<string, number>();
|
||||
for (let i = 0; i < assets.length; i++) {
|
||||
map.set(assets[i].id, i);
|
||||
}
|
||||
return map;
|
||||
});
|
||||
let slidingWindow = $derived.by(() => {
|
||||
const top = (scrollTop || 0) - slidingWindowOffset;
|
||||
const bottom = top + viewport.height + slidingWindowOffset;
|
||||
|
|
@ -175,8 +184,12 @@
|
|||
return;
|
||||
}
|
||||
|
||||
let start = assets.findIndex((a) => a.id === startAsset.id);
|
||||
let end = assets.findIndex((a) => a.id === endAsset.id);
|
||||
let start = assetIndexMap.get(startAsset.id);
|
||||
let end = assetIndexMap.get(endAsset.id);
|
||||
|
||||
if (start === undefined || end === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start > end) {
|
||||
[start, end] = [end, start];
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export type AssetMultiSelectOptions = {
|
|||
};
|
||||
export class AssetMultiSelectManager {
|
||||
#selectedMap = new SvelteMap<string, TimelineAsset>();
|
||||
#candidateSet = new SvelteSet<string>();
|
||||
|
||||
selectAll = $state(false);
|
||||
startAsset = $state<TimelineAsset | null>(null);
|
||||
|
|
@ -55,7 +56,7 @@ export class AssetMultiSelectManager {
|
|||
}
|
||||
|
||||
hasSelectionCandidate(assetId: string) {
|
||||
return this.candidates.some((asset) => asset.id === assetId);
|
||||
return this.#candidateSet.has(assetId);
|
||||
}
|
||||
|
||||
selectAsset(asset: TimelineAsset) {
|
||||
|
|
@ -64,7 +65,7 @@ export class AssetMultiSelectManager {
|
|||
|
||||
selectAssets(assets: TimelineAsset[]) {
|
||||
for (const asset of assets) {
|
||||
this.selectAsset(asset);
|
||||
this.#selectedMap.set(asset.id, asset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,10 +87,15 @@ export class AssetMultiSelectManager {
|
|||
|
||||
setAssetSelectionCandidates(assets: TimelineAsset[]) {
|
||||
this.candidates = assets;
|
||||
this.#candidateSet.clear();
|
||||
for (const asset of assets) {
|
||||
this.#candidateSet.add(asset.id);
|
||||
}
|
||||
}
|
||||
|
||||
clearCandidates() {
|
||||
this.candidates = [];
|
||||
this.#candidateSet.clear();
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
|
@ -101,6 +107,7 @@ export class AssetMultiSelectManager {
|
|||
|
||||
// Range selection
|
||||
this.candidates = [];
|
||||
this.#candidateSet.clear();
|
||||
this.startAsset = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,24 @@ export async function retrieveRange(timelineManager: TimelineManager, start: Ass
|
|||
[startTimelineMonth, endTimelineMonth] = [endTimelineMonth, startTimelineMonth];
|
||||
}
|
||||
|
||||
// Fast path: both assets in the same loaded month — collect synchronously
|
||||
if (startTimelineMonth === endTimelineMonth && startTimelineMonth.isLoaded) {
|
||||
const range: TimelineAsset[] = [];
|
||||
let collecting = false;
|
||||
for (const asset of startTimelineMonth.assetsIterator()) {
|
||||
if (!collecting && asset.id === startAsset.id) {
|
||||
collecting = true;
|
||||
}
|
||||
if (collecting) {
|
||||
range.push(asset);
|
||||
}
|
||||
if (asset.id === endAsset.id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
const range: TimelineAsset[] = [];
|
||||
const startTimelineDay = startTimelineMonth.findTimelineDayForAsset(startAsset);
|
||||
for await (const targetAsset of timelineManager.assetsIterator({
|
||||
|
|
|
|||
Loading…
Reference in New Issue