@quick-game/cli
Version:
Command line interface for rapid qg development
149 lines • 6.83 kB
JavaScript
// Copyright 2023 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as TraceEngine from '../../models/trace/trace.js';
import * as i18n from '../../core/i18n/i18n.js';
import { buildGroupStyle, buildTrackHeader, getFormattedTime } from './AppenderUtils.js';
const UIStrings = {
/**
*@description Text in Timeline Flame Chart Data Provider of the Performance panel
*/
interactions: 'Interactions',
};
const str_ = i18n.i18n.registerUIStrings('panels/timeline/InteractionsTrackAppender.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export class InteractionsTrackAppender {
appenderName = 'Interactions';
#colorGenerator;
#compatibilityBuilder;
#flameChartData;
#traceParsedData;
constructor(compatibilityBuilder, flameChartData, traceParsedData, colorGenerator) {
this.#compatibilityBuilder = compatibilityBuilder;
this.#colorGenerator = colorGenerator;
this.#flameChartData = flameChartData;
this.#traceParsedData = traceParsedData;
}
/**
* Appends into the flame chart data the data corresponding to the
* interactions track.
* @param trackStartLevel the horizontal level of the flame chart events where
* the track's events will start being appended.
* @param expanded wether the track should be rendered expanded.
* @returns the first available level to append more data after having
* appended the track's events.
*/
appendTrackAtLevel(trackStartLevel, expanded) {
if (this.#traceParsedData.UserInteractions.interactionEvents.length === 0) {
return trackStartLevel;
}
this.#appendTrackHeaderAtLevel(trackStartLevel, expanded);
return this.#appendInteractionsAtLevel(trackStartLevel);
}
/**
* Adds into the flame chart data the header corresponding to the
* interactions track. A header is added in the shape of a group in the
* flame chart data. A group has a predefined style and a reference
* to the definition of the legacy track (which should be removed
* in the future).
* @param currentLevel the flame chart level at which the header is
* appended.
*/
#appendTrackHeaderAtLevel(currentLevel, expanded) {
const trackIsCollapsible = this.#traceParsedData.UserInteractions.interactionEvents.length > 0;
const style = buildGroupStyle({ shareHeaderLine: false, collapsible: trackIsCollapsible });
const group = buildTrackHeader(currentLevel, i18nString(UIStrings.interactions), style, /* selectable= */ true, expanded);
this.#compatibilityBuilder.registerTrackForGroup(group, this);
}
/**
* Adds into the flame chart data the trace events dispatched by the
* performance.measure API. These events are taken from the UserInteractions
* handler.
* @param currentLevel the flame chart level from which interactions will
* be appended.
* @returns the next level after the last occupied by the appended
* interactions (the first available level to append more data).
*/
#appendInteractionsAtLevel(trackStartLevel) {
const { interactionEventsWithNoNesting, interactionsOverThreshold } = this.#traceParsedData.UserInteractions;
// Render all top level interactions (see UserInteractionsHandler for an explanation on the nesting) onto the track.
const newLevel = this.#compatibilityBuilder.appendEventsAtLevel(interactionEventsWithNoNesting, trackStartLevel, this);
// Each interaction that we drew that is over the INP threshold needs to be
// candy-striped.
for (const interaction of interactionEventsWithNoNesting) {
const overThreshold = interactionsOverThreshold.has(interaction);
if (!overThreshold) {
continue;
}
const index = this.#compatibilityBuilder.indexForEvent(interaction);
if (index !== undefined) {
this.#addCandyStripingForLongInteraction(index);
}
}
return newLevel;
}
#addCandyStripingForLongInteraction(eventIndex) {
const decorationsForEvent = this.#flameChartData.entryDecorations[eventIndex] || [];
decorationsForEvent.push({
type: 'CANDY',
startAtTime: TraceEngine.Handlers.ModelHandlers.UserInteractions.LONG_INTERACTION_THRESHOLD,
});
this.#flameChartData.entryDecorations[eventIndex] = decorationsForEvent;
}
/*
------------------------------------------------------------------------------------
The following methods are invoked by the flame chart renderer to query features about
events on rendering.
------------------------------------------------------------------------------------
*/
/**
* Gets the color an event added by this appender should be rendered with.
*/
colorForEvent(event) {
let idForColorGeneration = this.titleForEvent(event);
if (TraceEngine.Types.TraceEvents.isSyntheticInteractionEvent(event)) {
// Append the ID so that we vary the colours, ensuring that two events of
// the same type are coloured differently.
idForColorGeneration += event.interactionId;
}
return this.#colorGenerator.colorForID(idForColorGeneration);
}
/**
* Gets the title an event added by this appender should be rendered with.
*/
titleForEvent(event) {
if (TraceEngine.Types.TraceEvents.isSyntheticInteractionEvent(event)) {
return titleForInteractionEvent(event);
}
return event.name;
}
/**
* Returns the info shown when an event added by this appender
* is hovered in the timeline.
*/
highlightedEntryInfo(event) {
const title = this.titleForEvent(event);
return { title, formattedTime: getFormattedTime(event.dur) };
}
}
/**
* Return the title to use for a given interaction event.
* Exported so the title in the DetailsView can re-use the same logic
**/
export function titleForInteractionEvent(event) {
const category = TraceEngine.Handlers.ModelHandlers.UserInteractions.categoryOfInteraction(event);
// Because we hide nested interactions, we do not want to show the
// specific type of the interaction that was not hidden, so instead we
// show just the category of that interaction.
if (category === 'OTHER') {
return 'Other';
}
if (category === 'KEYBOARD') {
return 'Keyboard';
}
if (category === 'POINTER') {
return 'Pointer';
}
return event.type;
}
//# sourceMappingURL=InteractionsTrackAppender.js.map