Skip to content

Commit 6eac602

Browse files
committed
Improve RAF implementation
1 parent 9123f42 commit 6eac602

1 file changed

Lines changed: 123 additions & 42 deletions

File tree

src/js/ui.js

Lines changed: 123 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -559,28 +559,27 @@ export function showCrashDetails(crashIndex) {
559559
});
560560
}
561561

562+
// Marker highlighting RAF management
563+
let highlightRafId = null;
564+
let pendingHighlight = null;
565+
562566
/**
563567
* Highlight marker from table row hover
564568
* @param {number} crashIndex - Index of crash in filtered data
565569
*/
566570
export function highlightMarkerFromTable(crashIndex) {
571+
// Skip if already highlighting this marker
572+
if (uiState.dtHoveredRow === crashIndex) return;
573+
567574
const crash = dataState.filteredData[crashIndex];
568575
if (!crash || !crash._marker) return;
569576

570-
updateUiState({ dtHoveredRow: crashIndex });
577+
// Store pending operation
578+
pendingHighlight = { crashIndex, highlight: true };
571579

572-
// Highlight on map
573-
if (crash._marker) {
574-
crash._marker.setZIndexOffset(1000);
575-
const icon = crash._marker.getIcon();
576-
if (icon && icon.options) {
577-
const originalClass = icon.options.className || '';
578-
crash._marker._originalIconClass = originalClass;
579-
crash._marker.setIcon(L.divIcon({
580-
...icon.options,
581-
className: originalClass + ' marker-highlighted'
582-
}));
583-
}
580+
// Schedule highlight update if not already scheduled
581+
if (!highlightRafId) {
582+
highlightRafId = requestAnimationFrame(performMarkerHighlight);
584583
}
585584
}
586585

@@ -592,20 +591,57 @@ export function unhighlightMarkerFromTable(crashIndex) {
592591
const crash = dataState.filteredData[crashIndex];
593592
if (!crash || !crash._marker) return;
594593

595-
updateUiState({ dtHoveredRow: null });
594+
// Store pending operation
595+
pendingHighlight = { crashIndex, highlight: false };
596596

597-
// Remove highlight
598-
if (crash._marker && crash._marker._originalIconClass) {
597+
// Schedule highlight update if not already scheduled
598+
if (!highlightRafId) {
599+
highlightRafId = requestAnimationFrame(performMarkerHighlight);
600+
}
601+
}
602+
603+
/**
604+
* Perform the actual marker highlight/unhighlight operation
605+
*/
606+
function performMarkerHighlight() {
607+
highlightRafId = null;
608+
609+
if (!pendingHighlight) return;
610+
611+
const { crashIndex, highlight } = pendingHighlight;
612+
pendingHighlight = null;
613+
614+
const crash = dataState.filteredData[crashIndex];
615+
if (!crash || !crash._marker) return;
616+
617+
if (highlight) {
618+
updateUiState({ dtHoveredRow: crashIndex });
619+
620+
// Highlight on map
621+
crash._marker.setZIndexOffset(1000);
599622
const icon = crash._marker.getIcon();
600623
if (icon && icon.options) {
624+
const originalClass = icon.options.className || '';
625+
crash._marker._originalIconClass = originalClass;
601626
crash._marker.setIcon(L.divIcon({
602627
...icon.options,
603-
className: crash._marker._originalIconClass
628+
className: originalClass + ' marker-highlighted'
604629
}));
605630
}
606-
delete crash._marker._originalIconClass;
607-
}
608-
if (crash._marker) {
631+
} else {
632+
updateUiState({ dtHoveredRow: null });
633+
634+
// Remove highlight
635+
if (crash._marker._originalIconClass) {
636+
const icon = crash._marker.getIcon();
637+
if (icon && icon.options) {
638+
crash._marker.setIcon(L.divIcon({
639+
...icon.options,
640+
className: crash._marker._originalIconClass
641+
}));
642+
}
643+
delete crash._marker._originalIconClass;
644+
}
609645
crash._marker.setZIndexOffset(0);
610646
}
611647
}
@@ -654,6 +690,13 @@ export function getDtSorted() {
654690
/**
655691
* Render data table with current page and sort
656692
*/
693+
// Cache for tracking render state to avoid unnecessary updates
694+
let lastRenderState = {
695+
sortField: null,
696+
sortAsc: null,
697+
visibleColumns: null
698+
};
699+
657700
export function renderDataTable() {
658701
const tbody = document.getElementById('dataTableBody');
659702
const info = document.getElementById('dataTableInfo');
@@ -686,26 +729,43 @@ export function renderDataTable() {
686729
jumpInput.max = maxPage + 1;
687730
}
688731

689-
// Update sort icons and column visibility in header
690-
DATA_TABLE.COLUMNS.forEach(function(col) {
691-
const th = document.getElementById('dt-th-' + col.key.replace(/\s+/g, '_'));
692-
if (!th) return;
693-
694-
// Update visibility
695-
th.style.display = uiState.dtVisibleColumns[col.key] ? '' : 'none';
732+
// Only update headers if sort or visibility changed
733+
const sortChanged = lastRenderState.sortField !== uiState.dtSortField ||
734+
lastRenderState.sortAsc !== uiState.dtSortAsc;
735+
const visibilityChanged = JSON.stringify(lastRenderState.visibleColumns) !==
736+
JSON.stringify(uiState.dtVisibleColumns);
737+
738+
if (sortChanged || visibilityChanged) {
739+
// Update sort icons and column visibility in header
740+
DATA_TABLE.COLUMNS.forEach(function(col) {
741+
const th = document.getElementById('dt-th-' + col.key.replace(/\s+/g, '_'));
742+
if (!th) return;
743+
744+
// Update visibility only if changed
745+
if (visibilityChanged) {
746+
th.style.display = uiState.dtVisibleColumns[col.key] ? '' : 'none';
747+
}
696748

697-
// Update sort icons
698-
const icon = th.querySelector('.dt-sort-icon');
699-
if (!icon) return;
749+
// Update sort icons only if changed
750+
if (sortChanged) {
751+
const icon = th.querySelector('.dt-sort-icon');
752+
if (!icon) return;
753+
754+
if (uiState.dtSortField === col.key) {
755+
icon.textContent = uiState.dtSortAsc ? ' ↑' : ' ↓';
756+
th.classList.add('dt-active-sort');
757+
} else {
758+
icon.textContent = ' ↕';
759+
th.classList.remove('dt-active-sort');
760+
}
761+
}
762+
});
700763

701-
if (uiState.dtSortField === col.key) {
702-
icon.textContent = uiState.dtSortAsc ? ' ↑' : ' ↓';
703-
th.classList.add('dt-active-sort');
704-
} else {
705-
icon.textContent = ' ↕';
706-
th.classList.remove('dt-active-sort');
707-
}
708-
});
764+
// Update cache
765+
lastRenderState.sortField = uiState.dtSortField;
766+
lastRenderState.sortAsc = uiState.dtSortAsc;
767+
lastRenderState.visibleColumns = { ...uiState.dtVisibleColumns };
768+
}
709769

710770
// Severity label map
711771
const sevMap = {
@@ -908,24 +968,39 @@ export function initColumnResizing() {
908968
let startX = 0;
909969
let startWidth = 0;
910970
let th = null;
971+
let currentX = 0;
972+
let rafId = null;
911973

912974
resizer.addEventListener('mousedown', (e) => {
913975
e.stopPropagation(); // Prevent sort trigger
914976
isResizing = true;
915977
th = resizer.parentElement;
916978
startX = e.pageX;
979+
currentX = e.pageX;
917980
startWidth = th.offsetWidth;
918981

919-
document.addEventListener('mousemove', doResize);
982+
document.addEventListener('mousemove', onMouseMove);
920983
document.addEventListener('mouseup', stopResize);
921984

922985
// Add resizing class to table
923986
table.classList.add('dt-resizing');
924987
});
925988

926-
function doResize(e) {
989+
function onMouseMove(e) {
990+
if (!isResizing) return;
991+
currentX = e.pageX;
992+
993+
// Schedule resize update if not already scheduled
994+
if (!rafId) {
995+
rafId = requestAnimationFrame(doResize);
996+
}
997+
}
998+
999+
function doResize() {
1000+
rafId = null;
9271001
if (!isResizing || !th) return;
928-
const width = startWidth + (e.pageX - startX);
1002+
1003+
const width = startWidth + (currentX - startX);
9291004
if (width > 50) { // Minimum width
9301005
th.style.width = width + 'px';
9311006
th.style.minWidth = width + 'px';
@@ -934,9 +1009,15 @@ export function initColumnResizing() {
9341009

9351010
function stopResize() {
9361011
isResizing = false;
937-
document.removeEventListener('mousemove', doResize);
1012+
document.removeEventListener('mousemove', onMouseMove);
9381013
document.removeEventListener('mouseup', stopResize);
9391014
table.classList.remove('dt-resizing');
1015+
1016+
// Cancel any pending animation frame
1017+
if (rafId) {
1018+
cancelAnimationFrame(rafId);
1019+
rafId = null;
1020+
}
9401021
}
9411022
});
9421023
}

0 commit comments

Comments
 (0)