Skip to content

Commit

Permalink
Refactor viewport change listener integration with Catapult to suppor…
Browse files Browse the repository at this point in the history
…t further viewport change listeners.

PiperOrigin-RevId: 645142097
  • Loading branch information
bmass02 authored and copybara-github committed Jun 20, 2024
1 parent 57dfc6e commit ee997ea
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 46 deletions.
18 changes: 18 additions & 0 deletions plugin/trace_viewer/tf_trace_viewer/tf-trace-viewer-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,22 @@ var tf_component_traceviewer;
};
}
tf_component_traceviewer.intersect = intersect;
/**
* Return a function that will call the given function after the given delay.
* If called again before the delay, the first call will be cancelled, and
* the delay will be reset.
* @param {function(...*): *} func The function to debounce.
* @param {number=} wait The delay in milliseconds.
* @return {function(...*): *} The debounced function.
*/
function debounce(func, wait = 500) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func(...args);
}, wait);
};
}
tf_component_traceviewer.debounce = debounce;
})(tf_component_traceviewer || (tf_component_traceviewer = {})); // namespace tf_component_traceviewer
121 changes: 75 additions & 46 deletions plugin/trace_viewer/tf_trace_viewer/tf-trace-viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,12 @@
// Override the default behavior for find fitler such that pressing find
// previous, find next which cycles through events in the search filter results
// will zoom and focus the event in the timeline.
const boundFindFocusChanged =
const superFindFocusChangedTo =
this._traceViewer.brushingStateController.findFocusChangedTo.bind(
this._traceViewer.brushingStateController);
this._traceViewer.brushingStateController.findFocusChangedTo =
(currentFocus) => {
boundFindFocusChanged(currentFocus);
superFindFocusChangedTo(currentFocus);
this._traceViewer.trackView.zoomToSelection();
};

Expand All @@ -332,6 +332,7 @@
this._resolution = this._resolutionFromViewerWidth(this._traceViewer.clientWidth);
// Retrieve the URL of trace data.
var query = new URL(window.location.href);
this._listenForViewportChanges();
query.searchParams.forEach(function(value, key, searchParams) {
if (key === 'trace_data_url') {
this.traceDataUrl = value;
Expand Down Expand Up @@ -826,14 +827,9 @@
// [----preserve----] - issue loads to keep this full of data
// [---------fetch----------] - fetch this much data with each load
// [-----------full bounds--------] - the whole profile
var viewport = this._trackViewRange(this._traceViewer.trackView);
var PRESERVE_RATIO = tf_component_traceviewer.PRESERVE_RATIO;
var preserve = tf_component_traceviewer.intersect(
tf_component_traceviewer.expand(viewport, PRESERVE_RATIO),
this._fullBounds
);
var FETCH_RATIO = tf_component_traceviewer.FETCH_RATIO;
var fetch = tf_component_traceviewer.expand(viewport, FETCH_RATIO);
var viewport = this._trackViewRange(this._traceViewer.trackView)
var fetch = this._calcFetchRange(viewport);
var preserve = this._calcPreserveRange(viewport);
var zoomFactor =
tf_component_traceviewer.length(this._loadedRange) /
tf_component_traceviewer.length(fetch);
Expand Down Expand Up @@ -1106,38 +1102,10 @@
return;
}
this._dirty = false;
// We can't assign the model until the viewer is attached. This may be
// delayed indefinitely if the tab is backgrounded. This version of polymer
// doesn't provide a direct way to observe the viewer being attached.
// This is a workaround: the browser won't paint until the viewer is attached.
// Promisify this to make the trace loading process synchronized
await new Promise(resolve => window.requestAnimationFrame(
function() {
this._traceViewer.model = this._model;
if (this._traceViewer.trackView != null) {
// Only initialized if data in nonempty!
// Wait 500ms to let an animated zoom/pan operation complete. Ideally,
// we could just explicitly wait for its end.
const debounce = (func, wait = 500) => {
let timer;

return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func(...args);
}, wait);
};
}
const debouncedReload = debounce(this._maybeLoad.bind(this))
this._traceViewer.trackView.viewport.addEventListener(
'change',
debouncedReload
);
}
this._traceViewer.viewTitle = '';
resolve();
}.bind(this)
));
// TraceViewer queues up a model to be built, waits for being attached to the DOM, and then
// builds the model. The builtPromise attribute doesn't resolve until the model is built.
this._traceViewer.model = this._model;
await this._traceViewer.builtPromise;
},

// Dummy node inserted to enable webdriver detect render complete signal
Expand Down Expand Up @@ -1174,15 +1142,47 @@

// Access the {min, max} range of a trackView.
_trackViewRange: function(trackView) {
var xfm = trackView.viewport.currentDisplayTransform;
return this._calcViewportRange(trackView.viewport.currentDisplayTransform, trackView.viewWidth_);
},

_calcViewportRange: function(displayTransform, viewWidth) {
const pixelRatio = window.devicePixelRatio || 1;
const devicePixelWidth = pixelRatio * trackView.viewWidth_;
const devicePixelWidth = pixelRatio * viewWidth;
return {
min: xfm.xViewToWorld(0),
max: xfm.xViewToWorld(devicePixelWidth),
min: displayTransform.xViewToWorld(0),
max: displayTransform.xViewToWorld(devicePixelWidth),
};
},

_calcFetchRange: function(viewportRange) {
var FETCH_RATIO = tf_component_traceviewer.FETCH_RATIO;
var fetch = tf_component_traceviewer.expand(viewportRange, FETCH_RATIO);
fetch = tf_component_traceviewer.intersect(fetch, this._getFilterRange());
return fetch;
},

_calcPreserveRange: function(viewportRange) {
var PRESERVE_RATIO = tf_component_traceviewer.PRESERVE_RATIO;
var preserve = tf_component_traceviewer.expand(viewportRange, PRESERVE_RATIO);
preserve = tf_component_traceviewer.intersect(preserve, this._getFilterRange());
return preserve;
},

_getFilterRange: function() {
const range = {min: Number.MIN_VALUE, max: Number.MAX_VALUE};
if (this.traceDataUrl) {
const url = new URL(this.traceDataUrl, window.location.origin);
const sp = url.searchParams;
if (sp.has('start_time_ms')) {
range.min = Number(sp.get('start_time_ms'));
}
if (sp.has('end_time_ms')) {
range.max = Number(sp.get('end_time_ms'));
}
}
return range;
},

// Returns the resolution (in number of events) given the width of the
// trace viewer (in pixels).
_resolutionFromViewerWidth(viewerWidth) {
Expand Down Expand Up @@ -1277,5 +1277,34 @@
overlay.title = title;
overlay.visible = true;
},

_onViewportChanged: function() {
if (this._isStreaming) {
this._maybeLoad();
}
},

/**
* Listen for viewport changes and debounce the onViewportChanged callback.
* This is to avoid the onViewportChanged callback being called unnecessarily when the user
* navigating the traces.
* NOTE: this does not currently listen for scroll events.
*/
_listenForViewportChanges: function() {
const _debouncedOnViewportChanged = tf_component_traceviewer.debounce(this._onViewportChanged.bind(this));
const superOnViewportChanged_ = this._traceViewer.onViewportChanged_.bind(this._traceViewer);
this._traceViewer.onViewportChanged_ = (...args) => {
superOnViewportChanged_(...args);

if (this._traceViewer.trackView != undefined) {
_debouncedOnViewportChanged();
}
};
// if called after trackView already created, then reset listener
if (this._traceViewer.trackView != undefined) {
this._traceViewer.trackView.viewport.removeEventListener('change', superOnViewportChanged_);
this._traceViewer.trackView.viewport.addEventListener('change', this._traceViewer.onViewportChanged_);
}
},
});
</script>

0 comments on commit ee997ea

Please sign in to comment.