[shell-perf-web] Add tooltips for skipped events
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [shell-perf-web] Add tooltips for skipped events
- Date: Wed, 26 May 2010 14:35:51 +0000 (UTC)
commit fc9623d08e2ebb0202eca1feafd0849c6a2c9628
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Wed May 26 10:34:00 2010 -0400
Add tooltips for skipped events
* Change the algorithm for drawing <...> so that each <...> is clearly
associated with a set of events
* Store skipped events with the region that the corresponding <...>
takes on the screen.
* Show tooltips on mouse-over of a <...>
static/log_viewer.js | 154 +++++++++++++++++++++++++++++++++++++++++-------
static/shell-perf.css | 10 +++
2 files changed, 141 insertions(+), 23 deletions(-)
---
diff --git a/static/log_viewer.js b/static/log_viewer.js
index 815c2e8..4c3a985 100644
--- a/static/log_viewer.js
+++ b/static/log_viewer.js
@@ -30,9 +30,11 @@ EventPainter.prototype = {
this.nextI = -1;
this.pos = null;
this.lastPos = null;
- this.lastLabelPos = null;
this.nextPos = null;
+ this.skippedEvents = [];
+ this.skipDrawPos = null;
+
this.advance();
this.advance();
},
@@ -50,6 +52,17 @@ EventPainter.prototype = {
var e = this.log[this.nextI];
if (this.predicate(e)) {
this.nextPos = this.getPos(e[0]);
+ if (this.nextPos - this.pos <= LABEL_SPACE &&
+ this.lastPos == null || this.pos - this.lastPos > LABEL_SPACE) {
+ // Within a consecutive run of events that are too close together to
+ // draw labels, we draw '<...>' indicators at a regular grid starting
+ // at a position based on the first event position; whatever method
+ // we use, we need to make sure that the position where we draw the
+ // indicators doesn't depend on the scroll position
+ if (this.skippedEvents.length > 0)
+ this._flushSkip();
+ this.skipDrawPos = this.pos;
+ }
return;
}
@@ -60,21 +73,27 @@ EventPainter.prototype = {
this.nextPos = null;
},
+ _flushSkip: function() {
+ this.paintLabel(this.skipDrawPos + LABEL_SPACE / 2, '<...>', this.skippedEvents);
+ this.skippedEvents = [];
+ },
+
paint: function() {
- var label;
- if ((this.lastPos == null || this.pos - this.lastPos > LABEL_SPACE) &&
- (this.nextPos == null || this.nextPos - this.pos > LABEL_SPACE)) {
- label = this.log[this.i][1];
- } else {
- if (this.lastLabelPos == null || this.pos - this.lastLabelPos > LABEL_SPACE)
- label = '<...>';
- else
- label = null;
+ if (this.skippedEvents.length > 0) {
+ if (this.pos >= this.skipDrawPos + LABEL_SPACE * 2) {
+ this._flushSkip();
+ this.skipDrawPos += 2 * LABEL_SPACE;
+ }
}
- if (label != null) {
+ var label = this.log[this.i][1];
+ if ((this.lastPos == null || this.pos - this.lastPos > LABEL_SPACE) &&
+ (this.nextPos == null || this.nextPos - this.pos > LABEL_SPACE)) {
this.paintLabel(this.pos, label);
- this.lastLabelPos = this.pos;
+ } else {
+ this.skippedEvents.push(label);
+ if (this.nextI == null)
+ this._flushSkip();
}
this.paintLine(this.pos);
@@ -193,6 +212,9 @@ LogViewer.prototype = {
this.canvas.addEventListener('mousedown',
bind(this, this._onMouseDown),
false);
+ this.canvas.addEventListener('mousemove',
+ bind(this, this._onMouseMove),
+ false);
this.canvas.addEventListener('DOMMouseScroll',
bind(this, this._onMouseScroll),
true);
@@ -281,19 +303,30 @@ LogViewer.prototype = {
this.redraw();
},
- // Translate the coordinates from an event to be stage relative
- _eventCoords: function(e) {
- var x = e.clientX + window.scrollX;
- var y = e.clientY + window.scrollY;
+ // Coordinates of canvas with respect to page
+ _pageCoords: function(e) {
+ var x = 0;
+ var y = 0;
var el = this.canvas;
do {
- x -= el.offsetLeft;
- y -= el.offsetTop;
+ x += el.offsetLeft;
+ y += el.offsetTop;
el = el.offsetParent;
} while (el);
- return {x: x, y: y};
+ return { x: x, y: y };
+ },
+
+ // Translate the coordinates from an event to be stage relative
+ _eventCoords: function(e) {
+ var coords = this._pageCoords();
+
+ // efficiency hack to avoid creating a new object
+ coords.x = e.clientX + window.scrollX - coords.x;
+ coords.y = e.clientY + window.scrollY - coords.y;
+
+ return coords;
},
_onMouseDown: function(e) {
@@ -392,6 +425,67 @@ LogViewer.prototype = {
grabDiv.addEventListener('mouseup', onMouseUp, false);
},
+ _showTooltip: function(tooltip) {
+ if (this._tooltip == tooltip)
+ return;
+
+ if (this._tooltip != null)
+ this._hideTooltip();
+
+ this._tooltipDiv = document.createElement("div");
+ this._tooltipDiv.className = "event-tooltip";
+ document.body.appendChild(this._tooltipDiv);
+ var textNode = document.createTextNode(tooltip.events.join("\n"));
+ this._tooltipDiv.appendChild(textNode);
+
+ var pageCoords = this._pageCoords();
+
+ var x = pageCoords.x + tooltip.x2 + 5;
+ var y = pageCoords.y + tooltip.y1;
+
+ // The + 2 is for the two pixel border
+ if (y + this._tooltipDiv.clientHeight + 2 > window.innerHeight)
+ y = window.innerHeight - this._tooltipDiv.clientHeight - 2;
+ if (y < 0)
+ y = 0;
+
+ this._tooltipDiv.style.left = x + 'px';
+ this._tooltipDiv.style.top = y + 'px';
+
+ this._tooltip = tooltip;
+ },
+
+ _hideTooltip: function() {
+ if (this._tooltip == null)
+ return;
+
+ document.body.removeChild(this._tooltipDiv);
+ this._tooltipDiv = null;
+ this._tooltip = null;
+ },
+
+ _onMouseMove: function(e) {
+ if (!this.eventTooltips)
+ return;
+
+ var coords = this._eventCoords(e);
+ var i;
+
+ var x = coords.x;
+ var y = coords.y;
+
+ for (i = 0; i < this.eventTooltips.length; i++) {
+ var tooltip = this.eventTooltips[i];
+ if (x >= tooltip.x1 && x < tooltip.x2 &&
+ y >= tooltip.y1 && y < tooltip.y2) {
+ this._showTooltip(tooltip);
+ return;
+ }
+ }
+
+ this._hideTooltip();
+ },
+
_onMouseScroll: function(e) {
e.preventDefault();
e.stopPropagation();
@@ -459,6 +553,20 @@ LogViewer.prototype = {
return Math.floor(height * (t - me.zoomStart) / (me.zoomEnd - me.zoomStart));
}
+ this.eventTooltips = [];
+
+ function paintLabel(x, y, rightAlign, label, skippedEvents) {
+ context.fillText(label, x, y);
+ if (skippedEvents) {
+ var textWidth = context.measureText(label).width;
+ me.eventTooltips.push({ x1: rightAlign ? x - textWidth : x,
+ y1: y - LABEL_SPACE / 2,
+ x2: rightAlign ? x : x + textWidth,
+ y2: y + LABEL_SPACE / 2,
+ events: skippedEvents });
+ }
+ }
+
var scriptPainter = new EventPainter({
log: this.run.log,
getPos: getY,
@@ -472,11 +580,11 @@ LogViewer.prototype = {
context.restore();
lastY = pos;
},
- paintLabel: function(pos, label) {
+ paintLabel: function(pos, label, skippedEvents) {
context.save();
context.textAlign = 'right';
context.fillStyle = '#0000ff';
- context.fillText(label, width / 4 - 5, pos);
+ paintLabel(width / 4 - 5, pos, true, label, skippedEvents);
context.restore();
}
});
@@ -493,8 +601,8 @@ LogViewer.prototype = {
lastY = pos;
},
- paintLabel: function(pos, label) {
- context.fillText(label, 2 * width / 4 + 5, pos);
+ paintLabel: function(pos, label, skippedEvents) {
+ paintLabel(2 * width / 4 + 5, pos, false, label, skippedEvents);
}
});
diff --git a/static/shell-perf.css b/static/shell-perf.css
index 002e649..c08e421 100644
--- a/static/shell-perf.css
+++ b/static/shell-perf.css
@@ -323,3 +323,13 @@ body.report_view .metric-table {
#eventLogCanvas {
border: 1px solid #888888;
}
+
+.event-tooltip {
+ position: absolute;
+ border: 1px solid gray;
+ font-size: 70%;
+ white-space: pre-wrap;
+ background: #ddeeff;
+ opacity: 0.90;
+ padding: 0.5em;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]