aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Truong <terry06890@gmail.com>2023-01-07 19:48:36 +1100
committerTerry Truong <terry06890@gmail.com>2023-01-07 19:50:09 +1100
commit5d25f637119f1560ce8f8171cd46123c0bba56b4 (patch)
tree9e846f7ad1a677ae0f268ed3a927e1c4f15120ec
parent4b323024f51a8de755e4fb6cab301c36d52132a3 (diff)
Throttle relayouting of eventsthrottle-relayout
Reduces CPU drain, but adds noticeable gap between panning and event movement.
-rw-r--r--src/components/TimeLine.vue96
1 files changed, 55 insertions, 41 deletions
diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue
index 9e0a48c..2f58328 100644
--- a/src/components/TimeLine.vue
+++ b/src/components/TimeLine.vue
@@ -435,7 +435,14 @@ function dateToOffset(date: HistDate){ // Assumes 'date' is >=firstDate and <=la
return tick.offset + getUnitDiff(tick.date, date, minorScale.value) / getNumSubUnits(tick.date, scaleIdx.value);
}
}
-const idToEvent = computed(() => { // Maps visible event IDs to HistEvents
+const idToEvent: Ref<Map<number, HistEvent>> = ref(new Map()); // Maps visible event IDs to HistEvents
+const idToPos: Ref<Map<number, [number, number, number, number]>> = ref(new Map()); // Maps event IDs to x/y/w/h
+const idsToSkipTransition: Ref<Set<number>> = ref(new Set()); // Used to prevent events moving across mainline
+type LineCoords = [number, number, number, number]; // x, y, length, angle
+const eventLines: Ref<Map<number, LineCoords>> = ref(new Map()); // Maps event ID to event line data
+const UPDATE_TIMEOUT = 100; // Used to throttle relayouting
+let layoutUpdateHdlr = 0;
+function updateIdToEvent(){
let map: Map<number, HistEvent> = new Map();
// Find events to display
let itr = props.eventTree.lowerBound(new HistEvent(0, '', firstDate.value));
@@ -450,17 +457,8 @@ const idToEvent = computed(() => { // Maps visible event IDs to HistEvents
}
map.set(event.id, event);
}
- return map;
-});
-watch(idToEvent, () => { // Remove highlighting of search results that have become out of range
- if (searchEvent.value != null && !idToEvent.value.has(searchEvent.value.id)){
- searchEvent.value = null;
- }
-});
-const idToPos: Ref<Map<number, [number, number, number, number]>> = ref(new Map()); // Maps event IDs to x/y/w/h
-const idsToSkipTransition: Ref<Set<number>> = ref(new Set()); // Used to prevent events moving across mainline
-type LineCoords = [number, number, number, number]; // x, y, length, angle
-const eventLines: Ref<Map<number, LineCoords>> = ref(new Map()); // Maps event ID to event line data
+ idToEvent.value = map;
+}
function getEventLayout(): Map<number, [number, number, number, number]> {
let map: Map<number, [number, number, number, number]> = new Map();
if (!mounted.value){
@@ -633,36 +631,10 @@ function getEventLayout(): Map<number, [number, number, number, number]> {
}
return map;
}
-watch(idToEvent, () => { // Updates idToPos and eventLines
- let map = getEventLayout();
- // Check for events that cross mainline
- idsToSkipTransition.value.clear();
- for (let [eventId, [x, y, , ]] of map.entries()){
- if (idToPos.value.has(eventId)){
- let [oldX, oldY, , ] = idToPos.value.get(eventId)!;
- if (props.vert && (oldX - mainlineOffset.value) * (x - mainlineOffset.value) < 0
- || !props.vert && (oldY - mainlineOffset.value) * (y - mainlineOffset.value) < 0){
- idsToSkipTransition.value.add(eventId);
- }
- }
- }
- // Update idToPos // Note: For some reason, if the map is assigned directly, events won't consistently transition
- let toDelete = [];
- for (let eventId of idToPos.value.keys()){
- if (!map.has(eventId)){
- toDelete.push(eventId);
- }
- }
- for (let eventId of toDelete){
- idToPos.value.delete(eventId);
- }
- for (let [eventId, pos] of map.entries()){
- idToPos.value.set(eventId, pos);
- }
- // Update event lines
+function updateEventLines(){
let newEventLines: Map<number, LineCoords> = new Map();
let numUnits = getNumDisplayUnits();
- for (let [id, [eventX, eventY, eventW, eventH]] of map){
+ for (let [id, [eventX, eventY, eventW, eventH]] of idToPos.value.entries()){
let x: number; // For line end on mainline
let y: number;
let x2: number; // For line end at event
@@ -700,9 +672,51 @@ watch(idToEvent, () => { // Updates idToPos and eventLines
newEventLines.set(id, [x, y, l, a]);
}
eventLines.value = newEventLines;
+}
+function updateLayoutData(){ // Updates idToEvent, idToPos, idsToSkipTransition, and eventLines
+ // Update idToEvent
+ updateIdToEvent()
+ // Remove highlighting of search results that have become out of range
+ if (searchEvent.value != null && !idToEvent.value.has(searchEvent.value.id)){
+ searchEvent.value = null;
+ }
+ // Get layout
+ let map = getEventLayout();
+ // Check for events that cross mainline
+ idsToSkipTransition.value.clear();
+ for (let [eventId, [x, y, , ]] of map.entries()){
+ if (idToPos.value.has(eventId)){
+ let [oldX, oldY, , ] = idToPos.value.get(eventId)!;
+ if (props.vert && (oldX - mainlineOffset.value) * (x - mainlineOffset.value) < 0
+ || !props.vert && (oldY - mainlineOffset.value) * (y - mainlineOffset.value) < 0){
+ idsToSkipTransition.value.add(eventId);
+ }
+ }
+ }
+ // Update idToPos // Note: For some reason, if the map is assigned directly, events won't consistently transition
+ let toDelete = [];
+ for (let eventId of idToPos.value.keys()){
+ if (!map.has(eventId)){
+ toDelete.push(eventId);
+ }
+ }
+ for (let eventId of toDelete){
+ idToPos.value.delete(eventId);
+ }
+ for (let [eventId, pos] of map.entries()){
+ idToPos.value.set(eventId, pos);
+ }
+ // Update event lines
+ updateEventLines();
// Notify parent
emit('event-display', ID, [...map.keys()], firstDate.value, lastDate.value, minorScaleIdx.value);
-});
+}
+function updateLayoutDataThrottled(){
+ clearTimeout(layoutUpdateHdlr);
+ layoutUpdateHdlr = window.setTimeout(updateLayoutData, UPDATE_TIMEOUT);
+}
+watch(firstDate, updateLayoutDataThrottled);
+watch(() => props.eventTree, updateLayoutDataThrottled);
// For event-count indicators
const tickToCount = computed((): Map<number, number> => {