Web Inspector: Add a new Scanner TimelineMarker to show up when mousing over Timeline...
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Feb 2019 06:54:21 +0000 (06:54 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Feb 2019 06:54:21 +0000 (06:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195079

Reviewed by Devin Rousso.

* UserInterface/Base/Utilities.js:
(Note.prototype.enclosingNodeOrSelfWithClassInArray):
Helper for a set of classes.

* UserInterface/Models/TimelineMarker.js:
Add a new marker type, "Scanner".

* UserInterface/Views/CPUTimelineView.js:
(WI.CPUTimelineView.prototype.initialLayout):
(WI.CPUTimelineView.prototype._graphPositionForMouseEvent):
(WI.CPUTimelineView.prototype._handleGraphMouseMove):
* UserInterface/Views/MemoryTimelineView.js:
(WI.MemoryTimelineView):
(WI.MemoryTimelineView.prototype._graphPositionForMouseEvent):
(WI.MemoryTimelineView.prototype._handleGraphMouseMove):
Update a scanner time when mousing over various graphs that span the entire time range.
These use the containing graph element because there was a single pixel between
adjacent graphs which would cause the scanner to flicker because the mouse event target
was not an svg element.

* UserInterface/Views/TimelineOverview.js:
(WI.TimelineOverview.prototype.hidden):
(WI.TimelineOverview.prototype.updateScannerTime):
(WI.TimelineOverview.prototype.clearScanner):
* UserInterface/Views/TimelineRecordingContentView.js:
(WI.TimelineRecordingContentView):
(WI.TimelineRecordingContentView.prototype._handleTimelineViewScannerTimeDidChange):
(WI.TimelineRecordingContentView.prototype._handleTimelineViewScannerDidClear):
Update the overview's ruler with scanner changes.

* UserInterface/Views/TimelineRuler.css:
(.timeline-ruler > .markers > .marker.scanner):
* UserInterface/Views/TimelineRuler.js:
(WI.TimelineRuler):
(WI.TimelineRuler.prototype.clearMarkers):
(WI.TimelineRuler.prototype.updateScannerTime):
(WI.TimelineRuler.prototype.clearScanner):
(WI.TimelineRuler.prototype._updateMarkers):
Have a special scanner marker that updates.

* UserInterface/Views/TimelineView.js:
New events that a TimelineView can dispatch to update the overview.

* UserInterface/Views/Variables.css:
(:root):
(@media (prefers-color-scheme: dark)):
Scanner marker colors.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242194 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Models/TimelineMarker.js
Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js
Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ShaderProgramContentView.css
Source/WebInspectorUI/UserInterface/Views/TimelineOverview.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js
Source/WebInspectorUI/UserInterface/Views/TimelineRuler.css
Source/WebInspectorUI/UserInterface/Views/TimelineRuler.js
Source/WebInspectorUI/UserInterface/Views/TimelineView.js
Source/WebInspectorUI/UserInterface/Views/Variables.css

index 5340959..66c15b8 100644 (file)
@@ -1,3 +1,58 @@
+2019-02-27  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Add a new Scanner TimelineMarker to show up when mousing over TimelineView graphs
+        https://bugs.webkit.org/show_bug.cgi?id=195079
+
+        Reviewed by Devin Rousso.
+
+        * UserInterface/Base/Utilities.js:
+        (Note.prototype.enclosingNodeOrSelfWithClassInArray):
+        Helper for a set of classes.
+
+        * UserInterface/Models/TimelineMarker.js:
+        Add a new marker type, "Scanner".
+
+        * UserInterface/Views/CPUTimelineView.js:
+        (WI.CPUTimelineView.prototype.initialLayout):
+        (WI.CPUTimelineView.prototype._graphPositionForMouseEvent):
+        (WI.CPUTimelineView.prototype._handleGraphMouseMove):
+        * UserInterface/Views/MemoryTimelineView.js:
+        (WI.MemoryTimelineView):
+        (WI.MemoryTimelineView.prototype._graphPositionForMouseEvent):
+        (WI.MemoryTimelineView.prototype._handleGraphMouseMove):
+        Update a scanner time when mousing over various graphs that span the entire time range.
+        These use the containing graph element because there was a single pixel between
+        adjacent graphs which would cause the scanner to flicker because the mouse event target
+        was not an svg element.
+
+        * UserInterface/Views/TimelineOverview.js:
+        (WI.TimelineOverview.prototype.hidden):
+        (WI.TimelineOverview.prototype.updateScannerTime):
+        (WI.TimelineOverview.prototype.clearScanner):
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        (WI.TimelineRecordingContentView):
+        (WI.TimelineRecordingContentView.prototype._handleTimelineViewScannerTimeDidChange):
+        (WI.TimelineRecordingContentView.prototype._handleTimelineViewScannerDidClear):
+        Update the overview's ruler with scanner changes.
+
+        * UserInterface/Views/TimelineRuler.css:
+        (.timeline-ruler > .markers > .marker.scanner):
+        * UserInterface/Views/TimelineRuler.js:
+        (WI.TimelineRuler):
+        (WI.TimelineRuler.prototype.clearMarkers):
+        (WI.TimelineRuler.prototype.updateScannerTime):
+        (WI.TimelineRuler.prototype.clearScanner):
+        (WI.TimelineRuler.prototype._updateMarkers):
+        Have a special scanner marker that updates.
+
+        * UserInterface/Views/TimelineView.js:
+        New events that a TimelineView can dispatch to update the overview.
+
+        * UserInterface/Views/Variables.css:
+        (:root):
+        (@media (prefers-color-scheme: dark)):
+        Scanner marker colors.
+
 2019-02-27  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Use Element.closest for internal code
index c797223..de069a7 100644 (file)
@@ -76,5 +76,6 @@ WI.TimelineMarker.Type = {
     CurrentTime: "current-time",
     LoadEvent: "load-event",
     DOMContentEvent: "dom-content-event",
-    TimeStamp: "timestamp"
+    TimeStamp: "timestamp",
+    Scanner: "scanner",
 };
index 8ef54fa..7fdb07d 100644 (file)
@@ -227,6 +227,8 @@ WI.CPUTimelineView = class CPUTimelineView extends WI.TimelineView
         this._detailsContainerElement.appendChild(this._unknownThreadUsageView.element);
 
         this._workerViews = [];
+
+        this.element.addEventListener("mousemove", this._handleGraphMouseMove.bind(this));
     }
 
     layout()
@@ -720,15 +722,15 @@ WI.CPUTimelineView = class CPUTimelineView extends WI.TimelineView
 
     _graphPositionForMouseEvent(event)
     {
-        let svgElement = event.target.closest("svg");
-        if (!svgElement)
+        let chartElement = event.target.closest(".area-chart, .stacked-area-chart, .range-chart");
+        if (!chartElement)
             return NaN;
 
-        let svgRect = svgElement.getBoundingClientRect();
-        let position = event.pageX - svgRect.left;
+        let chartRect = chartElement.getBoundingClientRect();
+        let position = event.pageX - chartRect.left;
 
         if (WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL)
-            return svgRect.width - position;
+            return chartRect.width - position;
         return position;
     }
 
@@ -826,6 +828,20 @@ WI.CPUTimelineView = class CPUTimelineView extends WI.TimelineView
     {
         this.dispatchEventToListeners(WI.TimelineView.Event.RecordWasSelected, {record});
     }
+
+    _handleGraphMouseMove(event)
+    {
+        let mousePosition = this._graphPositionForMouseEvent(event);
+        if (isNaN(mousePosition)) {
+            this.dispatchEventToListeners(WI.TimelineView.Event.ScannerHide);
+            return;
+        }
+
+        let secondsPerPixel = this._timelineRuler.secondsPerPixel;
+        let time = this.startTime + (mousePosition * secondsPerPixel);
+
+        this.dispatchEventToListeners(WI.TimelineView.Event.ScannerShow, {time});
+    }
 };
 
 // NOTE: UI follows this order.
index 9a5b098..866c72c 100644 (file)
@@ -94,6 +94,8 @@ WI.MemoryTimelineView = class MemoryTimelineView extends WI.TimelineView
         this._maxComparisonCurrentSizeElement = null;
 
         timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._memoryTimelineRecordAdded, this);
+
+        this.element.addEventListener("mousemove", this._handleGraphMouseMove.bind(this));
     }
 
     // Static
@@ -278,6 +280,34 @@ WI.MemoryTimelineView = class MemoryTimelineView extends WI.TimelineView
 
     // Private
 
+    _graphPositionForMouseEvent(event)
+    {
+        let chartElement = event.target.closest(".area-chart, .stacked-area-chart, .range-chart");
+        if (!chartElement)
+            return NaN;
+
+        let chartRect = chartElement.getBoundingClientRect();
+        let position = event.pageX - chartRect.left;
+
+        if (WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL)
+            return chartRect.width - position;
+        return position;
+    }
+
+    _handleGraphMouseMove(event)
+    {
+        let mousePosition = this._graphPositionForMouseEvent(event);
+        if (isNaN(mousePosition)) {
+            this.dispatchEventToListeners(WI.TimelineView.Event.ScannerHide);
+            return;
+        }
+
+        let secondsPerPixel = this._timelineRuler.secondsPerPixel;
+        let time = this.startTime + (mousePosition * secondsPerPixel);
+
+        this.dispatchEventToListeners(WI.TimelineView.Event.ScannerShow, {time});
+    }
+
     _clearUsageLegend()
     {
         for (let sizeElement of this._usageLegendSizeElementMap.values())
index 81fcfb6..55ef41f 100644 (file)
@@ -28,7 +28,7 @@
     top: 0;
     bottom: 0;
 
-    --border-start-style: 1px solid lightgrey;;
+    --border-start-style: 1px solid lightgrey;
 }
 
 body[dir=ltr] .content-view.shader-program > .text-editor.shader.vertex,
index 1c8b705..6f18595 100644 (file)
@@ -360,6 +360,8 @@ WI.TimelineOverview = class TimelineOverview extends WI.View
 
         for (let overviewGraph of this._overviewGraphsByTypeMap.values())
             overviewGraph.hidden();
+
+        this.hideScanner();
     }
 
     closed()
@@ -409,6 +411,16 @@ WI.TimelineOverview = class TimelineOverview extends WI.View
         overviewGraph.selectedRecord = record;
     }
 
+    showScanner(time)
+    {
+        this._timelineRuler.showScanner(time);
+    }
+
+    hideScanner()
+    {
+        this._timelineRuler.hideScanner();
+    }
+
     updateLayoutIfNeeded(layoutReason)
     {
         if (this.layoutPending) {
index 2804b3c..d50be60 100644 (file)
@@ -98,6 +98,8 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
 
         WI.TimelineView.addEventListener(WI.TimelineView.Event.RecordWasFiltered, this._handleTimelineViewRecordFiltered, this);
         WI.TimelineView.addEventListener(WI.TimelineView.Event.RecordWasSelected, this._handleTimelineViewRecordSelected, this);
+        WI.TimelineView.addEventListener(WI.TimelineView.Event.ScannerShow, this._handleTimelineViewScannerShow, this);
+        WI.TimelineView.addEventListener(WI.TimelineView.Event.ScannerHide, this._handleTimelineViewScannerHide, this);
 
         WI.notifications.addEventListener(WI.Notification.VisibilityStateDidChange, this._inspectorVisibilityStateChanged, this);
 
@@ -846,6 +848,23 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
         }
     }
 
+    _handleTimelineViewScannerShow(event)
+    {
+        if (!this.visible)
+            return;
+
+        let {time} = event.data;
+        this._timelineOverview.showScanner(time);
+    }
+
+    _handleTimelineViewScannerHide(event)
+    {
+        if (!this.visible)
+            return;
+
+        this._timelineOverview.hideScanner();
+    }
+
     _updateProgressView()
     {
         let isCapturing = WI.timelineManager.isCapturing();
index fb3d736..2e64e96 100644 (file)
@@ -197,6 +197,10 @@ body[dir=rtl] .timeline-ruler > .markers > .marker::after {
     color: hsl(119, 100%, 21%);
 }
 
+.timeline-ruler > .markers > .marker.scanner {
+    color: var(--timeline-scanner-color);
+}
+
 .timeline-ruler > .selection-drag {
     position: absolute;
     top: 0;
index 1090fc7..b3ba45d 100644 (file)
@@ -55,6 +55,7 @@ WI.TimelineRuler = class TimelineRuler extends WI.View
         this._timeRangeSelectionChanged = false;
         this._enabled = true;
 
+        this._scannerMarker = null;
         this._markerElementMap = new Map;
         this._cachedClientWidth = 0;
     }
@@ -374,6 +375,8 @@ WI.TimelineRuler = class TimelineRuler extends WI.View
         }
 
         this._markerElementMap.clear();
+
+        this._scannerMarker = null;
     }
 
     elementForMarker(marker)
@@ -381,6 +384,22 @@ WI.TimelineRuler = class TimelineRuler extends WI.View
         return this._markerElementMap.get(marker) || null;
     }
 
+    showScanner(time)
+    {
+        if (!this._scannerMarker) {
+            this._scannerMarker = new WI.TimelineMarker(time, WI.TimelineMarker.Type.Scanner);
+            this.addMarker(this._scannerMarker);
+        }
+
+        this._scannerMarker.time = time;
+    }
+
+    hideScanner()
+    {
+        if (this._scannerMarker)
+            this._scannerMarker.time = -1;
+    }
+
     updateLayoutIfNeeded(layoutReason)
     {
         // If a layout is pending we can let the base class handle it and return, since that will update
@@ -624,6 +643,11 @@ WI.TimelineRuler = class TimelineRuler extends WI.View
         }
 
         for (let [marker, markerElement] of this._markerElementMap) {
+            if (marker.time < 0) {
+                markerElement.remove();
+                continue;
+            }
+
             let newPosition = (marker.time - this._startTime) / duration;
             let property = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? "right" : "left";
             this._updatePositionOfElement(markerElement, newPosition, visibleWidth, property);
index e3c763c..85e7afd 100644 (file)
@@ -337,4 +337,6 @@ WI.TimelineView = class TimelineView extends WI.ContentView
 WI.TimelineView.Event = {
     RecordWasFiltered: "timeline-view-record-was-filtered",
     RecordWasSelected: "timeline-view-record-was-selected",
+    ScannerShow: "timeline-view-scanner-show",
+    ScannerHide: "timeline-view-scanner-hide",
 };
index 2c8f8ac..1efb520 100644 (file)
     --timeline-odd-background-color: var(--background-color-content);
     --timeline-even-background-color: hsl(0, 0%, 96%);
 
+    --timeline-scanner-color: hsl(0, 0%, 35%);
+
     --memory-javascript-fill-color: hsl(269, 65%, 75%);
     --memory-javascript-stroke-color: hsl(269, 33%, 50%);
     --memory-images-fill-color: hsl(0, 65%, 75%);
@@ -291,6 +293,8 @@ body.window-inactive * {
 
         --timeline-even-background-color: hsl(0, 0%, 25%);
 
+        --timeline-scanner-color: hsl(0, 0%, 80%);
+
         /* Invert colors yet preserve the hue */
         --filter-invert: invert(100%) hue-rotate(180deg);