ui: Crop incomplete slices
For incomplete slices, use fixed pixel width (20px) instead of
|visibleWindowTime.end|. The default is disabled.
Change-Id: I6f3ef6a47ef98233d8116595968fccb04b6593e7
diff --git a/ui/src/common/canvas_utils.ts b/ui/src/common/canvas_utils.ts
index 2d09617..ad78f96 100644
--- a/ui/src/common/canvas_utils.ts
+++ b/ui/src/common/canvas_utils.ts
@@ -75,7 +75,11 @@
x: number,
y: number,
width: number,
- height: number) {
+ height: number,
+ showGradient: boolean = true) {
+ if (width <= 0 || height <= 0) {
+ return;
+ }
ctx.beginPath();
const triangleSize = height / 4;
ctx.moveTo(x, y);
@@ -92,10 +96,12 @@
const fillStyle = ctx.fillStyle;
if (isString(fillStyle)) {
- const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
- gradient.addColorStop(0.66, fillStyle);
- gradient.addColorStop(1, '#FFFFFF');
- ctx.fillStyle = gradient;
+ if (showGradient) {
+ const gradient = ctx.createLinearGradient(x, y, x + width, y + height);
+ gradient.addColorStop(0.66, fillStyle);
+ gradient.addColorStop(1, '#FFFFFF');
+ ctx.fillStyle = gradient;
+ }
} else {
throw new Error(
`drawIncompleteSlice() expects fillStyle to be a simple color not ${
diff --git a/ui/src/frontend/base_slice_track.ts b/ui/src/frontend/base_slice_track.ts
index c0c637e..0995ff2 100644
--- a/ui/src/frontend/base_slice_track.ts
+++ b/ui/src/frontend/base_slice_track.ts
@@ -41,6 +41,7 @@
import {PxSpan, TimeScale} from './time_scale';
import {NewTrackArgs, TrackBase} from './track';
import {BUCKETS_PER_PIXEL, CacheKey, TrackCache} from './track_cache';
+import {featureFlags} from '../core/feature_flags';
// The common class that underpins all tracks drawing slices.
@@ -52,6 +53,14 @@
const SLICE_MIN_WIDTH_PX = 1 / BUCKETS_PER_PIXEL;
const CHEVRON_WIDTH_PX = 10;
const DEFAULT_SLICE_COLOR = UNEXPECTED_PINK;
+const INCOMPLETE_SLICE_WIDTH_PX = 20;
+
+export const CROP_INCOMPLETE_SLICE_FLAG = featureFlags.register({
+ id: 'cropIncompleteSlice',
+ name: 'Crop incomplete Slice',
+ description: 'Display incomplete slice in short form',
+ defaultValue: false,
+});
// Exposed and standalone to allow for testing without making this
// visible to subclasses.
@@ -391,8 +400,16 @@
slice.x -= CHEVRON_WIDTH_PX / 2;
slice.w = CHEVRON_WIDTH_PX;
} else if (slice.flags & SLICE_FLAGS_INCOMPLETE) {
- slice.x = Math.max(slice.x, 0);
- slice.w = pxEnd - slice.x;
+ let widthPx;
+ if (CROP_INCOMPLETE_SLICE_FLAG.get()) {
+ widthPx = slice.x > 0 ? Math.min(pxEnd, INCOMPLETE_SLICE_WIDTH_PX) :
+ Math.max(0, INCOMPLETE_SLICE_WIDTH_PX + slice.x);
+ slice.x = Math.max(slice.x, 0);
+ } else {
+ slice.x = Math.max(slice.x, 0);
+ widthPx = pxEnd - slice.x;
+ }
+ slice.w = widthPx;
} else {
// If the slice is an actual slice, intersect the slice geometry with
// the visible viewport (this affects only the first and last slice).
@@ -429,8 +446,8 @@
if (slice.flags & SLICE_FLAGS_INSTANT) {
this.drawChevron(ctx, slice.x, y, sliceHeight);
} else if (slice.flags & SLICE_FLAGS_INCOMPLETE) {
- const w = Math.max(slice.w - 2, 2);
- drawIncompleteSlice(ctx, slice.x, y, w, sliceHeight);
+ const w = CROP_INCOMPLETE_SLICE_FLAG.get() ? slice.w : Math.max(slice.w - 2, 2);
+ drawIncompleteSlice(ctx, slice.x, y, w, sliceHeight, !CROP_INCOMPLETE_SLICE_FLAG.get());
} else {
const w = Math.max(slice.w, SLICE_MIN_WIDTH_PX);
ctx.fillRect(slice.x, y, w, sliceHeight);
@@ -798,7 +815,12 @@
}
for (const slice of this.incomplete) {
- if (slice.depth === depth && slice.x <= x) {
+ const startPx = CROP_INCOMPLETE_SLICE_FLAG.get() ?
+ globals.frontendLocalState.visibleTimeScale.timeToPx(slice.startNsQ) : slice.x;
+ const cropUnfinishedSlicesCondition = CROP_INCOMPLETE_SLICE_FLAG.get() ?
+ startPx + INCOMPLETE_SLICE_WIDTH_PX >= x : true;
+
+ if (slice.depth === depth && startPx <= x && cropUnfinishedSlicesCondition) {
return slice;
}
}
diff --git a/ui/src/frontend/slice_track_base.ts b/ui/src/frontend/slice_track_base.ts
index bf66782..ddf8874 100644
--- a/ui/src/frontend/slice_track_base.ts
+++ b/ui/src/frontend/slice_track_base.ts
@@ -24,12 +24,14 @@
import {checkerboardExcept} from './checkerboard';
import {globals} from './globals';
import {PxSpan, TimeScale} from './time_scale';
+import {CROP_INCOMPLETE_SLICE_FLAG} from './base_slice_track';
export const SLICE_TRACK_KIND = 'ChromeSliceTrack';
const SLICE_HEIGHT = 18;
const TRACK_PADDING = 2;
const CHEVRON_WIDTH_PX = 10;
const HALF_CHEVRON_WIDTH_PX = CHEVRON_WIDTH_PX / 2;
+const INCOMPLETE_SLICE_WIDTH_PX = 20;
export interface SliceData extends TrackData {
// Slices are stored in a columnar fashion.
@@ -115,7 +117,7 @@
if (isIncomplete) { // incomplete slice
// TODO(stevegolton): This isn't exactly equivalent, ideally we should
// choose tEnd once we've converted to screen space coords.
- tEnd = visibleWindowTime.end.toTime('ceil');
+ tEnd = this.getEndTimeIfInComplete(tStart);
}
if (!visibleTimeSpan.intersects(tStart, tEnd)) {
@@ -187,7 +189,8 @@
}
if (isIncomplete && rect.width > SLICE_HEIGHT / 4) {
- drawIncompleteSlice(ctx, rect.left, rect.top, rect.width, SLICE_HEIGHT);
+ drawIncompleteSlice(ctx, rect.left, rect.top, rect.width,
+ SLICE_HEIGHT, !CROP_INCOMPLETE_SLICE_FLAG.get());
} else if (
data.cpuTimeRatio !== undefined && data.cpuTimeRatio[i] < 1 - 1e-9) {
// We draw two rectangles, representing the ratio between wall time and
@@ -248,7 +251,6 @@
if (data === undefined) return;
const {
visibleTimeScale: timeScale,
- visibleWindowTime: visibleHPTimeSpan,
} = globals.frontendLocalState;
if (y < TRACK_PADDING) return;
const instantWidthTime = timeScale.pxDeltaToDuration(HALF_CHEVRON_WIDTH_PX);
@@ -269,7 +271,8 @@
const end = Time.fromRaw(data.ends[i]);
let tEnd = HighPrecisionTime.fromTime(end);
if (data.isIncomplete[i]) {
- tEnd = visibleHPTimeSpan.end;
+ const endTime = this.getEndTimeIfInComplete(start);
+ tEnd = HighPrecisionTime.fromTime(endTime);
}
if (tStart.lte(t) && t.lte(tEnd)) {
return i;
@@ -278,6 +281,18 @@
}
}
+ getEndTimeIfInComplete(start: time) : time {
+ const {visibleTimeScale, visibleWindowTime} = globals.frontendLocalState;
+
+ let end = visibleWindowTime.end.toTime('ceil');
+ if (CROP_INCOMPLETE_SLICE_FLAG.get()) {
+ const widthTime = visibleTimeScale.pxDeltaToDuration(INCOMPLETE_SLICE_WIDTH_PX).toTime();
+ end = Time.add(start, widthTime);
+ }
+
+ return end;
+ }
+
onMouseMove({x, y}: {x: number, y: number}) {
this.hoveredTitleId = -1;
globals.dispatch(Actions.setHighlightedSliceId({sliceId: -1}));