Title: [242739] trunk/Source/WebInspectorUI
Revision
242739
Author
joep...@webkit.org
Date
2019-03-11 14:26:47 -0700 (Mon, 11 Mar 2019)

Log Message

Web Inspector: CPU Usage Timeline - Add legend and graph hover effects
https://bugs.webkit.org/show_bug.cgi?id=195390

Reviewed by Devin Rousso.

* Localizations/en.lproj/localizedStrings.js:
New strings for the legends.

* UserInterface/Main.html:
Combined files.

* UserInterface/Views/Variables.css:
(:root):
(@media (prefers-color-scheme: dark)):
Tweaked colors, including individual stroke and fill colors for each CPU section.

* UserInterface/Views/CPUTimelineOverviewGraph.css:
(.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.total-usage):
(.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.main-thread-usage):
(.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.worker-thread-usage):
Updated colors.

* UserInterface/Views/CPUUsageCombinedView.css: Renamed from Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.css.
(.cpu-usage-combined-view > .details > .legend-container):
(.cpu-usage-combined-view > .details > .legend-container > .row):
(.cpu-usage-combined-view > .details > .legend-container > .row + .row):
(.cpu-usage-combined-view > .details > .legend-container > .row > .swatch):
* UserInterface/Views/CPUUsageCombinedView.js: Renamed from Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js.
(WI.CPUUsageCombinedView.appendLegendRow):
(WI.CPUUsageCombinedView):
(WI.CPUUsageCombinedView.prototype.get graphElement):
(WI.CPUUsageCombinedView.prototype.get chart):
(WI.CPUUsageCombinedView.prototype.get rangeChart):
(WI.CPUUsageCombinedView.prototype.clear):
(WI.CPUUsageCombinedView.prototype.updateChart):
(WI.CPUUsageCombinedView.prototype.updateMainThreadIndicator):
(WI.CPUUsageCombinedView.prototype.clearLegend):
(WI.CPUUsageCombinedView.prototype.updateLegend):
(WI.CPUUsageCombinedView.prototype._updateDetails):
* UserInterface/Views/CPUUsageIndicatorView.css: Removed.
* UserInterface/Views/CPUUsageIndicatorView.js: Removed.
Combined the Indicator and StackedAreaChart into a single view
that share a left details section.

* UserInterface/Views/CPUUsageView.js:
(WI.CPUUsageView):
(WI.CPUUsageView.prototype.get graphElement):
(WI.CPUUsageView.prototype.clear):
(WI.CPUUsageView.prototype.updateChart):
(WI.CPUUsageView.prototype.clearLegend):
(WI.CPUUsageView.prototype.updateLegend):
(WI.CPUUsageView.prototype._updateDetails):
Include a legend in the left details section.

* UserInterface/Views/AreaChart.js:
(WI.AreaChart):
(WI.AreaChart.prototype.addPointMarker):
(WI.AreaChart.prototype.clearPointMarkers):
(WI.AreaChart.prototype.clear):
(WI.AreaChart.prototype.layout):
* UserInterface/Views/StackedAreaChart.js:
(WI.StackedAreaChart):
(WI.StackedAreaChart.prototype.addPointMarker):
(WI.StackedAreaChart.prototype.clearPointMarkers):
(WI.StackedAreaChart.prototype.clear):
(WI.StackedAreaChart.prototype.layout):
Add point markers for the area charts.

* UserInterface/Views/CPUTimelineView.css:
* UserInterface/Views/CPUTimelineView.js:
(WI.CPUTimelineView):
(WI.CPUTimelineView.prototype.get cpuUsageViewHeight):
(WI.CPUTimelineView.prototype.clear):
(WI.CPUTimelineView.prototype.initialLayout.appendLegendRow):
(WI.CPUTimelineView.prototype.initialLayout):
(WI.CPUTimelineView.prototype.layout):
(WI.CPUTimelineView.prototype._graphPositionForMouseEvent):
(WI.CPUTimelineView.prototype._handleMouseClick):
(WI.CPUTimelineView.prototype._handleGraphMouseMove):
(WI.CPUTimelineView.prototype._showGraphOverlayNearTo):
(WI.CPUTimelineView.prototype._updateGraphOverlay):
(WI.CPUTimelineView.prototype._showGraphOverlay.xScale):
(WI.CPUTimelineView.prototype._showGraphOverlay.yScale):
(WI.CPUTimelineView.prototype._showGraphOverlay.addOverlayPoint):
(WI.CPUTimelineView.prototype._showGraphOverlay):
(WI.CPUTimelineView.prototype._clearOverlayMarkers.clearGraphOverlayElement):
(WI.CPUTimelineView.prototype._clearOverlayMarkers):
(WI.CPUTimelineView.prototype._hideGraphOverlay):
Include graph overlay markers.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (242738 => 242739)


--- trunk/Source/WebInspectorUI/ChangeLog	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/ChangeLog	2019-03-11 21:26:47 UTC (rev 242739)
@@ -1,3 +1,95 @@
+2019-03-11  Joseph Pecoraro  <pecor...@apple.com>
+
+        Web Inspector: CPU Usage Timeline - Add legend and graph hover effects
+        https://bugs.webkit.org/show_bug.cgi?id=195390
+
+        Reviewed by Devin Rousso.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        New strings for the legends.
+
+        * UserInterface/Main.html:
+        Combined files.
+
+        * UserInterface/Views/Variables.css:
+        (:root):
+        (@media (prefers-color-scheme: dark)):
+        Tweaked colors, including individual stroke and fill colors for each CPU section.
+
+        * UserInterface/Views/CPUTimelineOverviewGraph.css:
+        (.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.total-usage):
+        (.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.main-thread-usage):
+        (.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.worker-thread-usage):
+        Updated colors.
+
+        * UserInterface/Views/CPUUsageCombinedView.css: Renamed from Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.css.
+        (.cpu-usage-combined-view > .details > .legend-container):
+        (.cpu-usage-combined-view > .details > .legend-container > .row):
+        (.cpu-usage-combined-view > .details > .legend-container > .row + .row):
+        (.cpu-usage-combined-view > .details > .legend-container > .row > .swatch):
+        * UserInterface/Views/CPUUsageCombinedView.js: Renamed from Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js.
+        (WI.CPUUsageCombinedView.appendLegendRow):
+        (WI.CPUUsageCombinedView):
+        (WI.CPUUsageCombinedView.prototype.get graphElement):
+        (WI.CPUUsageCombinedView.prototype.get chart):
+        (WI.CPUUsageCombinedView.prototype.get rangeChart):
+        (WI.CPUUsageCombinedView.prototype.clear):
+        (WI.CPUUsageCombinedView.prototype.updateChart):
+        (WI.CPUUsageCombinedView.prototype.updateMainThreadIndicator):
+        (WI.CPUUsageCombinedView.prototype.clearLegend):
+        (WI.CPUUsageCombinedView.prototype.updateLegend):
+        (WI.CPUUsageCombinedView.prototype._updateDetails):
+        * UserInterface/Views/CPUUsageIndicatorView.css: Removed.
+        * UserInterface/Views/CPUUsageIndicatorView.js: Removed.
+        Combined the Indicator and StackedAreaChart into a single view
+        that share a left details section.
+
+        * UserInterface/Views/CPUUsageView.js:
+        (WI.CPUUsageView):
+        (WI.CPUUsageView.prototype.get graphElement):
+        (WI.CPUUsageView.prototype.clear):
+        (WI.CPUUsageView.prototype.updateChart):
+        (WI.CPUUsageView.prototype.clearLegend):
+        (WI.CPUUsageView.prototype.updateLegend):
+        (WI.CPUUsageView.prototype._updateDetails):
+        Include a legend in the left details section.
+
+        * UserInterface/Views/AreaChart.js:
+        (WI.AreaChart):
+        (WI.AreaChart.prototype.addPointMarker):
+        (WI.AreaChart.prototype.clearPointMarkers):
+        (WI.AreaChart.prototype.clear):
+        (WI.AreaChart.prototype.layout):
+        * UserInterface/Views/StackedAreaChart.js:
+        (WI.StackedAreaChart):
+        (WI.StackedAreaChart.prototype.addPointMarker):
+        (WI.StackedAreaChart.prototype.clearPointMarkers):
+        (WI.StackedAreaChart.prototype.clear):
+        (WI.StackedAreaChart.prototype.layout):
+        Add point markers for the area charts.
+
+        * UserInterface/Views/CPUTimelineView.css:
+        * UserInterface/Views/CPUTimelineView.js:
+        (WI.CPUTimelineView):
+        (WI.CPUTimelineView.prototype.get cpuUsageViewHeight):
+        (WI.CPUTimelineView.prototype.clear):
+        (WI.CPUTimelineView.prototype.initialLayout.appendLegendRow):
+        (WI.CPUTimelineView.prototype.initialLayout):
+        (WI.CPUTimelineView.prototype.layout):
+        (WI.CPUTimelineView.prototype._graphPositionForMouseEvent):
+        (WI.CPUTimelineView.prototype._handleMouseClick):
+        (WI.CPUTimelineView.prototype._handleGraphMouseMove):
+        (WI.CPUTimelineView.prototype._showGraphOverlayNearTo):
+        (WI.CPUTimelineView.prototype._updateGraphOverlay):
+        (WI.CPUTimelineView.prototype._showGraphOverlay.xScale):
+        (WI.CPUTimelineView.prototype._showGraphOverlay.yScale):
+        (WI.CPUTimelineView.prototype._showGraphOverlay.addOverlayPoint):
+        (WI.CPUTimelineView.prototype._showGraphOverlay):
+        (WI.CPUTimelineView.prototype._clearOverlayMarkers.clearGraphOverlayElement):
+        (WI.CPUTimelineView.prototype._clearOverlayMarkers):
+        (WI.CPUTimelineView.prototype._hideGraphOverlay):
+        Include graph overlay markers.
+
 2019-03-11  Devin Rousso  <drou...@apple.com>
 
         Web Inspector: eliminate manual syncing of numeric constants used by _javascript_ and CSS

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -616,6 +616,7 @@
 localizedStrings["MIME Type:"] = "MIME Type:";
 localizedStrings["MSE Logging:"] = "MSE Logging:";
 localizedStrings["Main Thread"] = "Main Thread";
+localizedStrings["Main: %s"] = "Main: %s";
 localizedStrings["Manifest URL"] = "Manifest URL";
 localizedStrings["Mass"] = "Mass";
 localizedStrings["Matching"] = "Matching";
@@ -710,6 +711,7 @@
 localizedStrings["Other"] = "Other";
 localizedStrings["Other Issue"] = "Other Issue";
 localizedStrings["Other Threads"] = "Other Threads";
+localizedStrings["Other: %s"] = "Other: %s";
 localizedStrings["Other\u2026"] = "Other\u2026";
 localizedStrings["Outgoing message"] = "Outgoing message";
 localizedStrings["Output: "] = "Output: ";
@@ -1056,6 +1058,7 @@
 localizedStrings["Total Time"] = "Total Time";
 localizedStrings["Total memory size at the end of the selected time range"] = "Total memory size at the end of the selected time range";
 localizedStrings["Total time"] = "Total time";
+localizedStrings["Total: %s"] = "Total: %s";
 localizedStrings["Totals:"] = "Totals:";
 localizedStrings["Trace"] = "Trace";
 localizedStrings["Trace: %s"] = "Trace: %s";
@@ -1082,6 +1085,7 @@
 localizedStrings["Unsupported property name"] = "Unsupported property name";
 localizedStrings["Unsupported property value"] = "Unsupported property value";
 localizedStrings["Untitled"] = "Untitled";
+localizedStrings["Usage: %s"] = "Usage: %s";
 localizedStrings["Use Default Appearance"] = "Use Default Appearance";
 localizedStrings["Use Default Media Styles"] = "Use Default Media Styles";
 localizedStrings["Use Mock Capture Devices"] = "Use Mock Capture Devices";
@@ -1121,7 +1125,9 @@
 localizedStrings["With Object Properties"] = "With Object Properties";
 localizedStrings["Worker"] = "Worker";
 localizedStrings["Worker Thread"] = "Worker Thread";
+localizedStrings["Worker Threads"] = "Worker Threads";
 localizedStrings["Worker \u2014 %s"] = "Worker \u2014 %s";
+localizedStrings["Worker: %s"] = "Worker: %s";
 localizedStrings["Working Copy"] = "Working Copy";
 localizedStrings["Wrap lines to editor width"] = "Wrap lines to editor width";
 localizedStrings["XHR"] = "XHR";

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2019-03-11 21:26:47 UTC (rev 242739)
@@ -45,8 +45,7 @@
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
-    <link rel="stylesheet" href=""
-    <link rel="stylesheet" href=""
+    <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
     <link rel="stylesheet" href=""
@@ -596,8 +595,7 @@
     <script src=""
     <script src=""
     <script src=""
-    <script src=""
-    <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/AreaChart.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/AreaChart.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/AreaChart.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -26,7 +26,8 @@
 // AreaChart creates a single filled area chart.
 //
 // Initialize the chart with a size. You can then include a new point
-// in the area chart by providing an (x, y) point via `addPoint`.
+// in the area chart by providing an (x, y) point via `addPoint`. You
+// can add point markers (<circle>) with an (x, y) as well.
 //
 // SVG:
 //
@@ -50,8 +51,10 @@
         this._chartElement.setAttribute("preserveAspectRatio", "none");
 
         this._pathElement = this._chartElement.appendChild(createSVGElement("path"));
+        this._circleElements = [];
 
         this._points = [];
+        this._markers = [];
         this._size = null;
     }
 
@@ -79,11 +82,27 @@
         this._points.push({x, y});
     }
 
-    clear()
+    clearPoints()
     {
         this._points = [];
     }
 
+    addPointMarker(x, y)
+    {
+        this._markers.push({x, y});
+    }
+
+    clearPointMarkers()
+    {
+        this._markers = [];
+    }
+
+    clear()
+    {
+        this.clearPoints();
+        this.clearPointMarkers();
+    }
+
     // Protected
 
     layout()
@@ -107,5 +126,20 @@
 
         let pathString = pathComponents.join(" ");
         this._pathElement.setAttribute("d", pathString);
+
+        if (this._circleElements.length) {
+            for (let circle of this._circleElements)
+                circle.remove();
+            this._circleElements = [];
+        }
+
+        if (this._markers.length) {
+            for (let {x, y} of this._markers) {
+                let circle = this._chartElement.appendChild(createSVGElement("circle"));
+                this._circleElements.push(circle);
+                circle.setAttribute("cx", x);
+                circle.setAttribute("cy", y);
+            }
+        }
     }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css	2019-03-11 21:26:47 UTC (rev 242739)
@@ -61,17 +61,19 @@
     transform: scaleX(-1);
 }
 
-.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect {
-    stroke: var(--cpu-stroke-color);
-    fill: var(--cpu-fill-color);
+.timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.total-usage {
+    fill: var(--cpu-other-thread-fill-color);
+    stroke: var(--cpu-other-thread-stroke-color);
 }
 
 .timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.main-thread-usage {
     fill: var(--cpu-main-thread-fill-color);
+    stroke: var(--cpu-main-thread-stroke-color);
 }
 
 .timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.worker-thread-usage {
     fill: var(--cpu-worker-thread-fill-color);
+    stroke: var(--cpu-worker-thread-stroke-color);
 }
 
 .timeline-overview-graph.cpu > .stacked-column-chart > svg > rect.selected {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css	2019-03-11 21:26:47 UTC (rev 242739)
@@ -126,20 +126,20 @@
     color: var(--text-color-secondary);
 }
 
-.timeline-view.cpu .legend {
+.timeline-view.cpu > .content > .overview .legend {
     -webkit-padding-start: 20px;
     text-align: start;
 }
 
-.timeline-view.cpu .legend .row {
+.timeline-view.cpu > .content > .overview .legend .row {
     display: flex;
 }
 
-.timeline-view.cpu .legend .row + .row {
+.timeline-view.cpu > .content > .overview .legend .row + .row {
     margin-top: 4px;
 }
 
-.timeline-view.cpu .legend .swatch {
+.timeline-view.cpu > .content > .overview .legend .swatch {
     width: 1em;
     height: 1em;
     margin-top: 1px;
@@ -146,27 +146,22 @@
     -webkit-margin-end: 8px;
 }
 
-.timeline-view.cpu .legend > .row > .swatch.sample-type-idle {
-    border: 1px solid var(--cpu-idle-stroke-color);
-    background-color: var(--cpu-idle-fill-color);
-}
-
-.timeline-view.cpu .legend > .row > .swatch.sample-type-script {
+.timeline-view.cpu > .content > .overview .legend > .row > .swatch.sample-type-script {
     border: 1px solid var(--cpu-script-stroke-color);
     background-color: var(--cpu-script-fill-color);
 }
 
-.timeline-view.cpu .legend > .row > .swatch.sample-type-style {
+.timeline-view.cpu > .content > .overview .legend > .row > .swatch.sample-type-style {
     border: 1px solid var(--cpu-style-stroke-color);
     background-color: var(--cpu-style-fill-color);
 }
 
-.timeline-view.cpu .legend > .row > .swatch.sample-type-layout {
+.timeline-view.cpu > .content > .overview .legend > .row > .swatch.sample-type-layout {
     border: 1px solid var(--cpu-layout-stroke-color);
     background-color: var(--cpu-layout-fill-color);
 }
 
-.timeline-view.cpu .legend > .row > .swatch.sample-type-paint {
+.timeline-view.cpu > .content > .overview .legend > .row > .swatch.sample-type-paint {
     border: 1px solid var(--cpu-paint-stroke-color);
     background-color: var(--cpu-paint-fill-color);
 }
@@ -197,24 +192,22 @@
 }
 
 .timeline-view.cpu :matches(.area-chart, .stacked-area-chart) svg > path {
-    stroke: var(--cpu-stroke-color);
-    fill: var(--cpu-fill-color);
+    fill: var(--cpu-other-thread-fill-color);
+    stroke: var(--cpu-other-thread-stroke-color);
 }
 
 .timeline-view.cpu .main-thread svg > path,
 .timeline-view.cpu svg > path.main-thread-usage {
     fill: var(--cpu-main-thread-fill-color);
+    stroke: var(--cpu-main-thread-stroke-color);
 }
 
 .timeline-view.cpu .worker-thread svg > path,
 .timeline-view.cpu svg > path.worker-thread-usage {
     fill: var(--cpu-worker-thread-fill-color);
+    stroke: var(--cpu-worker-thread-stroke-color);
 }
 
-.timeline-view.cpu .cpu-usage-view.empty {
-    display: none;
-}
-
 .timeline-view.cpu :matches(.area-chart, .stacked-area-chart) .markers {
     position: absolute;
     top: 0;
@@ -247,30 +240,21 @@
     background-color: var(--background-color-content);
 }
 
-.timeline-view.cpu .cpu-usage-indicator-view > .graph > .range-chart rect {
-    stroke-opacity: 0.25;
+.timeline-view.cpu :matches(.area-chart, .stacked-area-chart) circle {
+    r: 3;
+    fill: var(--cpu-overlay-color);
 }
 
-.timeline-view.cpu .cpu-usage-indicator-view > .graph > .range-chart .sample-type-script {
-    stroke: var(--cpu-script-stroke-color);
-    fill: var(--cpu-script-fill-color);
+.timeline-view.cpu .timeline-ruler > .markers > .marker.timestamp {
+    color: var(--cpu-overlay-color);
+    opacity: 0.8;
+    pointer-events: none;
 }
 
-.timeline-view.cpu .cpu-usage-indicator-view > .graph > .range-chart .sample-type-style {
-    stroke: var(--cpu-style-stroke-color);
-    fill: var(--cpu-style-fill-color);
+.timeline-view.cpu .timeline-ruler > .markers > .marker.timestamp::after {
+    display: none;
 }
 
-.timeline-view.cpu .cpu-usage-indicator-view > .graph > .range-chart .sample-type-layout {
-    stroke: var(--cpu-layout-stroke-color);
-    fill: var(--cpu-layout-fill-color);
-}
-
-.timeline-view.cpu .cpu-usage-indicator-view > .graph > .range-chart .sample-type-paint {
-    stroke: var(--cpu-paint-stroke-color);
-    fill: var(--cpu-paint-fill-color);
-}
-
 .timeline-view.cpu .gauge-chart .low {
     --gauge-chart-path-fill-color: var(--cpu-low-color);
     --gauge-chart-path-stroke-color: var(--cpu-low-color);

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -35,9 +35,17 @@
 
         this.element.classList.add("cpu");
 
-        this._statisticsData = null;
         this._sectionLimit = CPUTimelineView.defaultSectionLimit;
 
+        this._statisticsData = null;
+        this._secondsPerPixelInLayout = undefined;
+        this._visibleRecordsInLayout = [];
+        this._discontinuitiesInLayout = [];
+
+        this._stickingOverlay = false;
+        this._overlayRecord = null;
+        this._overlayTime = NaN;
+
         timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._cpuTimelineRecordAdded, this);
     }
 
@@ -58,7 +66,7 @@
         console.error("Unknown sample type", type);
     }
 
-    static get cpuUsageViewHeight() { return 150; }
+    static get cpuUsageViewHeight() { return 135; }
     static get threadCPUUsageViewHeight() { return 65; }
     static get indicatorViewHeight() { return 15; }
 
@@ -124,10 +132,15 @@
 
         this._removeWorkerThreadViews();
 
-        this._mainThreadWorkIndicatorView.clear();
+        this._sectionLimit = CPUTimelineView.defaultSectionLimit;
 
         this._statisticsData = null;
-        this._sectionLimit = CPUTimelineView.defaultSectionLimit;
+        this._secondsPerPixelInLayout = undefined;
+        this._visibleRecordsInLayout = [];
+        this._discontinuitiesInLayout = [];
+
+        this._stickingOverlay = false;
+        this._hideGraphOverlay();
     }
 
     // Protected
@@ -141,7 +154,7 @@
 
     initialLayout()
     {
-        this.element.style.setProperty("--cpu-usage-stacked-view-height", CPUTimelineView.cpuUsageViewHeight + "px");
+        this.element.style.setProperty("--cpu-usage-combined-view-height", CPUTimelineView.cpuUsageViewHeight + "px");
         this.element.style.setProperty("--cpu-usage-view-height", CPUTimelineView.threadCPUUsageViewHeight + "px");
         this.element.style.setProperty("--cpu-usage-indicator-view-height", CPUTimelineView.indicatorViewHeight + "px");
 
@@ -174,7 +187,6 @@
             swatchElement.classList.add("swatch", sampleType);
 
             let valueContainer = rowElement.appendChild(document.createElement("div"));
-            valueContainer.classList.add("value");
 
             let labelElement = valueContainer.appendChild(document.createElement("div"));
             labelElement.classList.add("label");
@@ -287,16 +299,12 @@
         detailsSubtitleElement.classList.add("subtitle");
         detailsSubtitleElement.textContent = WI.UIString("CPU Usage");
 
-        this._cpuUsageView = new WI.CPUUsageStackedView(WI.UIString("Total"));
+        this._cpuUsageView = new WI.CPUUsageCombinedView(WI.UIString("Total"));
         this.addSubview(this._cpuUsageView);
         detailsContainerElement.appendChild(this._cpuUsageView.element);
 
-        this._mainThreadWorkIndicatorView = new WI.CPUUsageIndicatorView;
-        this.addSubview(this._mainThreadWorkIndicatorView);
-        detailsContainerElement.appendChild(this._mainThreadWorkIndicatorView.element);
+        this._cpuUsageView.rangeChart.element.addEventListener("click", this._handleIndicatorClick.bind(this));
 
-        this._mainThreadWorkIndicatorView.chart.element.addEventListener("click", this._handleIndicatorClick.bind(this));
-
         this._threadsDetailsElement = detailsContainerElement.appendChild(document.createElement("details"));
         this._threadsDetailsElement.open = WI.settings.cpuTimelineThreadDetailsExpanded.value;
         this._threadsDetailsElement.addEventListener("toggle", (event) => {
@@ -315,12 +323,10 @@
         this._threadsDetailsElement.appendChild(this._mainThreadUsageView.element);
 
         this._webkitThreadUsageView = new WI.CPUUsageView(WI.UIString("WebKit Threads"));
-        this._webkitThreadUsageView.element.classList.add("non-main-thread");
         this.addSubview(this._webkitThreadUsageView);
         this._threadsDetailsElement.appendChild(this._webkitThreadUsageView.element);
 
         this._unknownThreadUsageView = new WI.CPUUsageView(WI.UIString("Other Threads"));
-        this._unknownThreadUsageView.element.classList.add("non-main-thread");
         this.addSubview(this._unknownThreadUsageView);
         this._threadsDetailsElement.appendChild(this._unknownThreadUsageView.element);
 
@@ -398,7 +404,11 @@
 
         this._clearSources();
 
+        this.element.addEventListener("click", this._handleGraphClick.bind(this));
         this.element.addEventListener("mousemove", this._handleGraphMouseMove.bind(this));
+
+        this._overlayMarker = new WI.TimelineMarker(-1, WI.TimelineMarker.Type.TimeStamp);
+        this._timelineRuler.addMarker(this._overlayMarker);
     }
 
     layout()
@@ -434,6 +444,10 @@
             return;
         }
 
+        this._secondsPerPixelInLayout = secondsPerPixel;
+        this._visibleRecordsInLayout = visibleRecords;
+        this._discontinuitiesInLayout = discontinuities.slice();
+
         this._statisticsData = this._computeStatisticsData(graphStartTime, visibleEndTime);
         this._layoutBreakdownChart();
         this._layoutStatisticsAndSources();
@@ -610,6 +624,7 @@
         // Layout all graphs to the same time scale. The maximum value is
         // the maximum total CPU usage across all threads.
         let layoutMax = max;
+        this._layoutMax = max;
 
         function layoutView(view, property, graphHeight, {dataPoints, min, max, average}) {
             if (min === Infinity)
@@ -684,6 +699,7 @@
                 let displayName = worker ? worker.displayName : WI.UIString("Worker Thread");
                 let workerView = new WI.CPUUsageView(displayName);
                 workerView.element.classList.add("worker-thread");
+                workerView.__workerId = workerId;
                 this.addSubview(workerView);
                 this._threadsDetailsElement.insertBefore(workerView.element, this._webkitThreadUsageView.element);
                 this._workerViews.push(workerView);
@@ -698,9 +714,11 @@
 
         let graphWidth = (graphEndTime - graphStartTime) / secondsPerPixel;
         let size = new WI.Size(graphWidth, CPUTimelineView.indicatorViewHeight);
-        this._mainThreadWorkIndicatorView.updateChart(this._statisticsData.samples, size, visibleEndTime, xScaleIndicatorRange);
+        this._cpuUsageView.updateMainThreadIndicator(this._statisticsData.samples, size, visibleEndTime, xScaleIndicatorRange);
 
         this._layoutEnergyChart(average, visibleDuration);
+
+        this._updateGraphOverlay();
     }
 
     // Private
@@ -1488,11 +1506,11 @@
         if (!chartElement)
             return NaN;
 
-        let chartRect = chartElement.getBoundingClientRect();
-        let position = event.pageX - chartRect.left;
+        let rect = chartElement.getBoundingClientRect();
+        let position = event.pageX - rect.left;
 
         if (WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL)
-            return chartRect.width - position;
+            return rect.width - position;
         return position;
     }
 
@@ -1591,10 +1609,23 @@
         this.dispatchEventToListeners(WI.TimelineView.Event.RecordWasSelected, {record});
     }
 
+    _handleGraphClick(event)
+    {
+        let mousePosition = this._graphPositionForMouseEvent(event);
+        if (isNaN(mousePosition))
+            return;
+
+        this._stickingOverlay = !this._stickingOverlay;
+
+        if (!this._stickingOverlay)
+            this._handleGraphMouseMove(event);
+    }
+
     _handleGraphMouseMove(event)
     {
         let mousePosition = this._graphPositionForMouseEvent(event);
         if (isNaN(mousePosition)) {
+            this._hideGraphOverlay();
             this.dispatchEventToListeners(WI.TimelineView.Event.ScannerHide);
             return;
         }
@@ -1602,8 +1633,162 @@
         let secondsPerPixel = this._timelineRuler.secondsPerPixel;
         let time = this.startTime + (mousePosition * secondsPerPixel);
 
+        if (!this._stickingOverlay)
+            this._showGraphOverlayNearTo(time);
+
         this.dispatchEventToListeners(WI.TimelineView.Event.ScannerShow, {time});
     }
+
+    _showGraphOverlayNearTo(time)
+    {
+        let nearestRecord = null;
+        let nearestDistance = Infinity;
+
+        // Find the nearest record to the time.
+        for (let record of this._visibleRecordsInLayout) {
+            let distance = Math.abs(time - record.timestamp);
+            if (distance < nearestDistance) {
+                nearestRecord = record;
+                nearestDistance = distance;
+            }
+        }
+
+        if (!nearestRecord) {
+            this._hideGraphOverlay();
+            return;
+        }
+
+        let bestTime = nearestRecord.timestamp;
+
+        // Snap to a discontinuity if closer.
+        for (let {startTime, endTime} of this._discontinuitiesInLayout) {
+            let distance = Math.abs(time - startTime);
+            if (distance < nearestDistance) {
+                nearestDistance = distance;
+                bestTime = startTime;
+            }
+            distance = Math.abs(time - endTime);
+            if (distance < nearestDistance) {
+                nearestDistance = distance;
+                bestTime = endTime;
+            }
+        }
+
+        // Snap to end time if closer.
+        let visibleEndTime = Math.min(this.endTime, this.currentTime);
+        let distance = Math.abs(time - visibleEndTime);
+        if (distance < nearestDistance) {
+            nearestDistance = distance;
+            bestTime = visibleEndTime;
+        }
+
+        let graphStartTime = this.startTime;
+        let adjustedTime = Number.constrain(bestTime, graphStartTime, visibleEndTime);
+        this._showGraphOverlay(nearestRecord, adjustedTime);
+    }
+
+    _updateGraphOverlay()
+    {
+        if (!this._overlayRecord)
+            return;
+
+        this._showGraphOverlay(this._overlayRecord, this._overlayTime, true);
+    }
+
+    _showGraphOverlay(record, time, force)
+    {
+        if (!force && record === this._overlayRecord && time === this._overlayTime)
+            return;
+
+        this._overlayRecord = record;
+        this._overlayTime = time;
+
+        let layoutMax = this._layoutMax;
+        let secondsPerPixel = this._secondsPerPixelInLayout;
+        let graphMax = layoutMax * 1.05;
+        let graphStartTime = this.startTime;
+
+        this._overlayMarker.time = time + (secondsPerPixel / 2);
+
+        function xScale(time) {
+            return (time - graphStartTime) / secondsPerPixel;
+        }
+
+        let x = xScale(time);
+
+        let {mainThreadUsage, workerThreadUsage, webkitThreadUsage, unknownThreadUsage, workersData} = record;
+
+        function addOverlayPoint(view, graphHeight, value) {
+            if (!value)
+                return;
+
+            function yScale(value) {
+                return graphHeight - ((value / graphMax) * graphHeight);
+            }
+
+            view.chart.addPointMarker(x, yScale(value));
+            view.chart.needsLayout();
+        }
+
+        this._clearOverlayMarkers();
+
+        this._cpuUsageView.updateLegend(record);
+        addOverlayPoint(this._cpuUsageView, CPUTimelineView.cpuUsageViewHeight, mainThreadUsage);
+        addOverlayPoint(this._cpuUsageView, CPUTimelineView.cpuUsageViewHeight, mainThreadUsage + workerThreadUsage);
+        addOverlayPoint(this._cpuUsageView, CPUTimelineView.cpuUsageViewHeight, mainThreadUsage + workerThreadUsage + webkitThreadUsage + unknownThreadUsage);
+
+        if (this._threadsDetailsElement.open) {
+            this._mainThreadUsageView.updateLegend(mainThreadUsage);
+            addOverlayPoint(this._mainThreadUsageView, CPUTimelineView.threadCPUUsageViewHeight, mainThreadUsage);
+
+            this._webkitThreadUsageView.updateLegend(webkitThreadUsage);
+            addOverlayPoint(this._webkitThreadUsageView, CPUTimelineView.threadCPUUsageViewHeight, webkitThreadUsage);
+
+            this._unknownThreadUsageView.updateLegend(unknownThreadUsage);
+            addOverlayPoint(this._unknownThreadUsageView, CPUTimelineView.threadCPUUsageViewHeight, unknownThreadUsage);
+
+            for (let workerView of this._workerViews)
+                workerView.updateLegend(NaN);
+
+            if (workersData) {
+                for (let {targetId, usage} of workersData) {
+                    let workerView = this._workerViews.find((x) => x.__workerId === targetId);
+                    if (workerView) {
+                        workerView.updateLegend(usage);
+                        addOverlayPoint(workerView, CPUTimelineView.threadCPUUsageViewHeight, usage);
+                    }
+                }
+            }
+        }
+    }
+
+    _clearOverlayMarkers()
+    {
+        function clearGraphOverlayElement(view) {
+            view.clearLegend();
+            view.chart.clearPointMarkers();
+            view.chart.needsLayout();
+        }
+
+        clearGraphOverlayElement(this._cpuUsageView);
+        clearGraphOverlayElement(this._mainThreadUsageView);
+        clearGraphOverlayElement(this._webkitThreadUsageView);
+        clearGraphOverlayElement(this._unknownThreadUsageView);
+
+        for (let workerView of this._workerViews)
+            clearGraphOverlayElement(workerView);
+    }
+
+    _hideGraphOverlay()
+    {
+        if (this._stickingOverlay)
+            return;
+
+        this._overlayRecord = null;
+        this._overlayTime = NaN;
+        this._overlayMarker.time = -1;
+        this._clearOverlayMarkers();
+    }
 };
 
 WI.CPUTimelineView.LayoutReason = {

Added: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageCombinedView.css (0 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageCombinedView.css	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageCombinedView.css	2019-03-11 21:26:47 UTC (rev 242739)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.cpu-usage-combined-view {
+    display: flex;
+    width: 100%;
+    height: calc(var(--cpu-usage-combined-view-height) + var(--cpu-usage-indicator-view-height) + 2px); /* +2 for borders */
+    border-bottom: 1px solid var(--border-color);
+}
+
+.cpu-usage-combined-view > .graph,
+.cpu-usage-combined-view > .graph > :matches(.stacked-area-chart, .range-chart),
+.cpu-usage-combined-view > .graph > :matches(.stacked-area-chart, .range-chart) > svg {
+    width: 100%;
+    height: 100%;
+}
+
+.cpu-usage-combined-view > .graph > .stacked-area-chart {
+    height: calc(var(--cpu-usage-combined-view-height));
+}
+
+.cpu-usage-combined-view > .graph > .range-chart {
+    position: relative;
+    z-index: calc(var(--timeline-marker-z-index) + 1);
+    height: calc(var(--cpu-usage-indicator-view-height) + 2px); /* +2 for borders */
+    background-color: var(--background-color-content);
+    border-top: 1px solid var(--border-color);
+    border-bottom: 1px solid var(--border-color);
+}
+
+.cpu-usage-combined-view > .details {
+    flex-shrink: 0;
+    width: 150px;
+    padding-top: 10px;
+    -webkit-padding-start: 15px;
+    font-size: 12px;
+    color: var(--text-color-secondary);
+    overflow: hidden;
+    text-overflow: ellipsis;
+
+    --cpu-usage-combined-view-details-border-end: 1px solid var(--border-color);
+}
+
+body[dir=ltr] .cpu-usage-combined-view > .details {
+    border-right: var(--cpu-usage-combined-view-details-border-end);
+}
+
+body[dir=rtl] .cpu-usage-combined-view > .details {
+    border-left: var(--cpu-usage-combined-view-details-border-end);
+}
+
+.cpu-usage-combined-view > :matches(.details, .legend) > .name {
+    color: var(--text-color);
+    white-space: nowrap;
+}
+
+.cpu-usage-combined-view > .graph {
+    position: relative;
+}
+
+body[dir=rtl] .cpu-usage-combined-view > .graph {
+    transform: scaleX(-1);
+}
+
+.cpu-usage-combined-view > .details > .legend-container {
+    font-size: 11px;
+}
+
+.cpu-usage-combined-view > .details > .legend-container > .row {
+    display: flex;
+}
+
+.cpu-usage-combined-view > .details > .legend-container > .row + .row {
+    margin-top: 4px;
+}
+
+.cpu-usage-combined-view > .details > .legend-container > .row > .swatch {
+    width: 1em;
+    height: 1em;
+    margin-top: 1px;
+    -webkit-margin-end: 4px;
+}
+
+.cpu-usage-combined-view > .details > .legend-container .swatch.total {
+    background-color: none;
+    border: none;
+}
+
+.cpu-usage-combined-view > .details > .legend-container .swatch.other-threads {
+    background-color: var(--cpu-other-thread-fill-color);
+    border: 1px solid var(--cpu-other-thread-stroke-color);
+}
+
+.cpu-usage-combined-view > .details > .legend-container .swatch.main-thread {
+    background-color: var(--cpu-main-thread-fill-color);
+    border: 1px solid var(--cpu-main-thread-stroke-color);
+}
+
+.cpu-usage-combined-view > .details > .legend-container .swatch.worker-threads {
+    background-color: var(--cpu-worker-thread-fill-color);
+    border: 1px solid var(--cpu-worker-thread-stroke-color);
+}
+
+.cpu-usage-combined-view > .graph > .range-chart rect {
+    stroke-opacity: 0.25;
+}
+
+.cpu-usage-combined-view > .graph > .range-chart .sample-type-script {
+    stroke: var(--cpu-script-stroke-color);
+    fill: var(--cpu-script-fill-color);
+}
+
+.cpu-usage-combined-view > .graph > .range-chart .sample-type-style {
+    stroke: var(--cpu-style-stroke-color);
+    fill: var(--cpu-style-fill-color);
+}
+
+.cpu-usage-combined-view > .graph > .range-chart .sample-type-layout {
+    stroke: var(--cpu-layout-stroke-color);
+    fill: var(--cpu-layout-fill-color);
+}
+
+.cpu-usage-combined-view > .graph > .range-chart .sample-type-paint {
+    stroke: var(--cpu-paint-stroke-color);
+    fill: var(--cpu-paint-fill-color);
+}

Copied: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageCombinedView.js (from rev 242738, trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js) (0 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageCombinedView.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageCombinedView.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.CPUUsageCombinedView = class CPUUsageCombinedView extends WI.View
+{
+    constructor(displayName)
+    {
+        super();
+
+        this.element.classList.add("cpu-usage-combined-view");
+
+        this._detailsElement = this.element.appendChild(document.createElement("div"));
+        this._detailsElement.classList.add("details");
+
+        let detailsNameElement = this._detailsElement.appendChild(document.createElement("span"));
+        detailsNameElement.classList.add("name");
+        detailsNameElement.textContent = displayName;
+
+        this._detailsElement.appendChild(document.createElement("br"));
+        this._detailsAverageElement = this._detailsElement.appendChild(document.createElement("span"));
+        this._detailsElement.appendChild(document.createElement("br"));
+        this._detailsMaxElement = this._detailsElement.appendChild(document.createElement("span"));
+        this._detailsElement.appendChild(document.createElement("br"));
+        this._detailsElement.appendChild(document.createElement("br"));
+        this._updateDetails(NaN, NaN);
+
+        this._graphElement = this.element.appendChild(document.createElement("div"));
+        this._graphElement.classList.add("graph");
+
+        // Combined thread usage area chart.
+        this._chart = new WI.StackedAreaChart;
+        this._chart.initializeSections(["main-thread-usage", "worker-thread-usage", "total-usage"]);
+        this.addSubview(this._chart);
+        this._graphElement.appendChild(this._chart.element);
+
+        // Main thread indicator strip.
+        this._rangeChart = new WI.RangeChart;
+        this.addSubview(this._rangeChart);
+        this._graphElement.appendChild(this._rangeChart.element);
+
+        function appendLegendRow(legendElement, className) {
+            let rowElement = legendElement.appendChild(document.createElement("div"));
+            rowElement.classList.add("row");
+
+            let swatchElement = rowElement.appendChild(document.createElement("div"));
+            swatchElement.classList.add("swatch", className);
+
+            let labelElement = rowElement.appendChild(document.createElement("div"));
+            labelElement.classList.add("label");
+
+            return labelElement;
+        }
+
+        this._legendElement = this._detailsElement.appendChild(document.createElement("div"));
+        this._legendElement.classList.add("legend-container");
+
+        this._legendMainThreadElement = appendLegendRow(this._legendElement, "main-thread");
+        this._legendWorkerThreadsElement = appendLegendRow(this._legendElement, "worker-threads");
+        this._legendOtherThreadsElement = appendLegendRow(this._legendElement, "other-threads");
+        this._legendTotalThreadsElement = appendLegendRow(this._legendElement, "total");
+
+        this.clearLegend();
+    }
+
+    // Public
+
+    get graphElement() { return this._graphElement; }
+    get chart() { return this._chart; }
+    get rangeChart() { return this._rangeChart; }
+
+    clear()
+    {
+        this._cachedAverageSize = undefined;
+        this._cachedMaxSize = undefined;
+        this._updateDetails(NaN, NaN);
+
+        this.clearLegend();
+
+        this._chart.clear();
+        this._chart.needsLayout();
+
+        this._rangeChart.clear();
+        this._rangeChart.needsLayout();
+    }
+
+    updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale)
+    {
+        console.assert(size instanceof WI.Size);
+        console.assert(min >= 0);
+        console.assert(max >= 0);
+        console.assert(min <= max);
+        console.assert(min <= average && average <= max);
+
+        this._updateDetails(max, average);
+
+        this._chart.clearPoints();
+        this._chart.size = size;
+        this._chart.needsLayout();
+
+        if (!dataPoints.length)
+            return;
+
+        // Ensure an empty graph is empty.
+        if (!max)
+            return;
+
+        // Extend the first data point to the start so it doesn't look like we originate at zero size.
+        let firstX = 0;
+        let firstY1 = yScale(dataPoints[0].mainThreadUsage);
+        let firstY2 = yScale(dataPoints[0].mainThreadUsage + dataPoints[0].workerThreadUsage);
+        let firstY3 = yScale(dataPoints[0].usage);
+        this._chart.addPointSet(firstX, [firstY1, firstY2, firstY3]);
+
+        // Points for data points.
+        for (let dataPoint of dataPoints) {
+            let x = xScale(dataPoint.time);
+            let y1 = yScale(dataPoint.mainThreadUsage);
+            let y2 = yScale(dataPoint.mainThreadUsage + dataPoint.workerThreadUsage);
+            let y3 = yScale(dataPoint.usage)
+            this._chart.addPointSet(x, [y1, y2, y3]);
+        }
+
+        // Extend the last data point to the end time.
+        let lastDataPoint = dataPoints.lastValue;
+        let lastX = Math.floor(xScale(visibleEndTime));
+        let lastY1 = yScale(lastDataPoint.mainThreadUsage);
+        let lastY2 = yScale(lastDataPoint.mainThreadUsage + lastDataPoint.workerThreadUsage);
+        let lastY3 = yScale(lastDataPoint.usage);
+        this._chart.addPointSet(lastX, [lastY1, lastY2, lastY3]);
+    }
+
+    updateMainThreadIndicator(samples, size, visibleEndTime, xScale)
+    {
+        console.assert(size instanceof WI.Size);
+
+        this._rangeChart.clear();
+        this._rangeChart.size = size;
+        this._rangeChart.needsLayout();
+
+        if (!samples.length)
+            return;
+
+        // Coalesce ranges of samples.
+        let ranges = [];
+        let currentRange = null;
+        let currentSampleType = undefined;
+        for (let i = 0; i < samples.length; ++i) {
+            // Back to idle, close any current chunk.
+            let type = samples[i];
+            if (!type) {
+                if (currentRange) {
+                    ranges.push(currentRange);
+                    currentRange = null;
+                    currentSampleType = undefined;
+                }
+                continue;
+            }
+
+            // Expand existing chunk.
+            if (type === currentSampleType) {
+                currentRange.endIndex = i;
+                continue;
+            }
+
+            // If type changed, close current chunk.
+            if (currentSampleType) {
+                ranges.push(currentRange);
+                currentRange = null;
+                currentSampleType = undefined;
+            }
+
+            // Start a new chunk.
+            console.assert(!currentRange);
+            console.assert(!currentSampleType);
+            currentRange = {type, startIndex: i, endIndex: i};
+            currentSampleType = type;
+        }
+
+        for (let {type, startIndex, endIndex} of ranges) {
+            let startX = xScale(startIndex);
+            let endX = xScale(endIndex + 1);
+            let width = endX - startX;
+            this._rangeChart.addRange(startX, width, type);
+        }
+    }
+
+    clearLegend()
+    {
+        this._legendMainThreadElement.textContent = WI.UIString("Main Thread");
+        this._legendWorkerThreadsElement.textContent = WI.UIString("Worker Threads");
+        this._legendOtherThreadsElement.textContent = WI.UIString("Other Threads");
+        this._legendTotalThreadsElement.textContent = "";
+    }
+
+    updateLegend(record)
+    {
+        if (!record) {
+            this.clearLegend();
+            return;
+        }
+
+        let {usage, mainThreadUsage, workerThreadUsage, webkitThreadUsage, unknownThreadUsage} = record;
+
+        this._legendMainThreadElement.textContent = WI.UIString("Main: %s").format(Number.percentageString(mainThreadUsage / 100));
+        this._legendWorkerThreadsElement.textContent = WI.UIString("Worker: %s").format(Number.percentageString(workerThreadUsage / 100));
+        this._legendOtherThreadsElement.textContent = WI.UIString("Other: %s").format(Number.percentageString((webkitThreadUsage + unknownThreadUsage) / 100));
+        this._legendTotalThreadsElement.textContent = WI.UIString("Total: %s").format(Number.percentageString(usage / 100));
+    }
+
+    // Private
+
+    _updateDetails(maxSize, averageSize)
+    {
+        if (this._cachedMaxSize === maxSize && this._cachedAverageSize === averageSize)
+            return;
+
+        this._cachedAverageSize = averageSize;
+        this._cachedMaxSize = maxSize;
+
+        this._detailsAverageElement.textContent = WI.UIString("Average: %s").format(Number.isFinite(maxSize) ? Number.percentageString(averageSize / 100) : emDash);
+        this._detailsMaxElement.textContent = WI.UIString("Highest: %s").format(Number.isFinite(maxSize) ? Number.percentageString(maxSize / 100) : emDash);
+    }
+};
+
+WI.CPUUsageCombinedView._cachedMainThreadIndicatorFillColor = null;
+WI.CPUUsageCombinedView._cachedMainThreadIndicatorStrokeColor = null;

Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageIndicatorView.css (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageIndicatorView.css	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageIndicatorView.css	2019-03-11 21:26:47 UTC (rev 242739)
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-.cpu-usage-indicator-view {
-    display: flex;
-    width: 100%;
-    height: calc(var(--cpu-usage-indicator-view-height) + 1px); /* 1 for border-bottom */
-    border-bottom: 1px solid var(--border-color);
-}
-
-.cpu-usage-indicator-view > .details {
-    flex-shrink: 0;
-    width: 150px;
-    -webkit-padding-start: 15px;
-    
-    --cpu-usage-indicator-view-details-border-end: 1px solid var(--border-color);
-}
-
-body[dir=ltr] .cpu-usage-indicator-view > .details {
-    border-right: var(--cpu-usage-indicator-view-details-border-end);
-}
-
-body[dir=rtl] .cpu-usage-indicator-view > .details {
-    border-left: var(--cpu-usage-indicator-view-details-border-end);
-}
-
-body[dir=rtl] .cpu-usage-indicator-view > .graph {
-    transform: scaleX(-1);
-}
-
-.cpu-usage-indicator-view > .graph {
-    position: relative;
-    z-index: calc(var(--timeline-marker-z-index) + 1);
-    background-color: var(--background-color-content);
-}
-
-.cpu-usage-indicator-view > .graph,
-.cpu-usage-indicator-view > .graph > .range-chart,
-.cpu-usage-indicator-view > .graph > .range-chart > svg {
-    width: 100%;
-    height: 100%;
-}

Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageIndicatorView.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageIndicatorView.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageIndicatorView.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WI.CPUUsageIndicatorView = class CPUUsageIndicatorView extends WI.View
-{
-    constructor(delegate)
-    {
-        super();
-
-        this.element.classList.add("cpu-usage-indicator-view");
-
-        this._detailsElement = this.element.appendChild(document.createElement("div"));
-        this._detailsElement.classList.add("details");
-
-        this._graphElement = this.element.appendChild(document.createElement("div"));
-        this._graphElement.classList.add("graph");
-
-        this._chart = new WI.RangeChart;
-        this.addSubview(this._chart);
-        this._graphElement.appendChild(this._chart.element);
-    }
-
-    // Public
-
-    get chart() { return this._chart; }
-
-    clear()
-    {
-        this._chart.clear();
-        this._chart.needsLayout();
-    }
-
-    updateChart(samples, size, visibleEndTime, xScale)
-    {
-        console.assert(size instanceof WI.Size);
-
-        this._chart.clear();
-        this._chart.size = size;
-        this._chart.needsLayout();
-
-        if (!samples.length)
-            return;
-
-        // Coalesce ranges of samples.
-        let ranges = [];
-        let currentRange = null;
-        let currentSampleType = undefined;
-        for (let i = 0; i < samples.length; ++i) {
-            // Back to idle, close any current chunk.
-            let type = samples[i];
-            if (!type) {
-                if (currentRange) {
-                    ranges.push(currentRange);
-                    currentRange = null;
-                    currentSampleType = undefined;
-                }
-                continue;
-            }
-
-            // Expand existing chunk.
-            if (type === currentSampleType) {
-                currentRange.endIndex = i;
-                continue;
-            }
-
-            // If type changed, close current chunk.
-            if (currentSampleType) {
-                ranges.push(currentRange);
-                currentRange = null;
-                currentSampleType = undefined;
-            }
-
-            // Start a new chunk.
-            console.assert(!currentRange);
-            console.assert(!currentSampleType);
-            currentRange = {type, startIndex: i, endIndex: i};
-            currentSampleType = type;
-        }
-
-        for (let {type, startIndex, endIndex} of ranges) {
-            let startX = xScale(startIndex);
-            let endX = xScale(endIndex + 1);
-            let width = endX - startX;
-            this._chart.addRange(startX, width, type);
-        }
-    }
-};

Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.css (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.css	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.css	2019-03-11 21:26:47 UTC (rev 242739)
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-.cpu-usage-stacked-view {
-    display: flex;
-    width: 100%;
-    height: calc(var(--cpu-usage-stacked-view-height) + 1px); /* +1 for border-bottom */
-    border-bottom: 1px solid var(--border-color);
-}
-
-.cpu-usage-stacked-view > .details {
-    flex-shrink: 0;
-    width: 150px;
-    padding-top: 10px;
-    -webkit-padding-start: 15px;
-    font-family: -webkit-system-font, sans-serif;
-    font-size: 12px;
-    color: var(--text-color-secondary);
-    overflow: hidden;
-    text-overflow: ellipsis;
-
-    --cpu-usage-stacked-view-details-border-end: 1px solid var(--border-color);
-}
-
-body[dir=ltr] .cpu-usage-stacked-view > .details {
-    border-right: var(--cpu-usage-stacked-view-details-border-end);
-}
-
-body[dir=rtl] .cpu-usage-stacked-view > .details {
-    border-left: var(--cpu-usage-stacked-view-details-border-end);
-}
-
-.cpu-usage-stacked-view > .details > .name {
-    color: var(--text-color);
-    white-space: nowrap;
-}
-
-body[dir=rtl] .cpu-usage-stacked-view > .graph {
-    transform: scaleX(-1);
-}
-
-.cpu-usage-stacked-view > .graph {
-    position: relative;
-}
-
-.cpu-usage-stacked-view > .graph,
-.cpu-usage-stacked-view > .graph > .stacked-area-chart,
-.cpu-usage-stacked-view > .graph > .stacked-area-chart > svg {
-    width: 100%;
-    height: 100%;
-}

Deleted: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageStackedView.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WI.CPUUsageStackedView = class CPUUsageStackedView extends WI.View
-{
-    constructor(displayName)
-    {
-        super();
-
-        this.element.classList.add("cpu-usage-stacked-view");
-
-        this._detailsElement = this.element.appendChild(document.createElement("div"));
-        this._detailsElement.classList.add("details");
-
-        let detailsNameElement = this._detailsElement.appendChild(document.createElement("span"));
-        detailsNameElement.classList.add("name");
-        detailsNameElement.textContent = displayName;
-
-        this._detailsElement.appendChild(document.createElement("br"));
-        this._detailsAverageElement = this._detailsElement.appendChild(document.createElement("span"));
-        this._detailsElement.appendChild(document.createElement("br"));
-        this._detailsMaxElement = this._detailsElement.appendChild(document.createElement("span"));
-        this._detailsElement.appendChild(document.createElement("br"));
-        this._detailsMinElement = this._detailsElement.appendChild(document.createElement("span"));
-        this._updateDetails(NaN, NaN);
-
-        this._graphElement = this.element.appendChild(document.createElement("div"));
-        this._graphElement.classList.add("graph");
-
-        this._chart = new WI.StackedAreaChart;
-        this._chart.initializeSections(["main-thread-usage", "worker-thread-usage", "total-usage"]);
-        this.addSubview(this._chart);
-        this._graphElement.appendChild(this._chart.element);
-    }
-
-    // Public
-
-    get chart() { return this._chart; }
-
-    clear()
-    {
-        this._cachedAverageSize = undefined;
-        this._cachedMinSize = undefined;
-        this._cachedMaxSize = undefined;
-        this._updateDetails(NaN, NaN);
-
-        this._chart.clear();
-        this._chart.needsLayout();
-    }
-
-    updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale)
-    {
-        console.assert(size instanceof WI.Size);
-        console.assert(min >= 0);
-        console.assert(max >= 0);
-        console.assert(min <= max);
-        console.assert(min <= average && average <= max);
-
-        this._updateDetails(min, max, average);
-
-        this._chart.clear();
-        this._chart.size = size;
-        this._chart.needsLayout();
-
-        if (!dataPoints.length)
-            return;
-
-        // Ensure an empty graph is empty.
-        if (!max)
-            return;
-
-        // Extend the first data point to the start so it doesn't look like we originate at zero size.
-        let firstX = 0;
-        let firstY1 = yScale(dataPoints[0].mainThreadUsage);
-        let firstY2 = yScale(dataPoints[0].mainThreadUsage + dataPoints[0].workerThreadUsage);
-        let firstY3 = yScale(dataPoints[0].usage);
-        this._chart.addPointSet(firstX, [firstY1, firstY2, firstY3]);
-
-        // Points for data points.
-        for (let dataPoint of dataPoints) {
-            let x = xScale(dataPoint.time);
-            let y1 = yScale(dataPoint.mainThreadUsage);
-            let y2 = yScale(dataPoint.mainThreadUsage + dataPoint.workerThreadUsage);
-            let y3 = yScale(dataPoint.usage)
-            this._chart.addPointSet(x, [y1, y2, y3]);
-        }
-
-        // Extend the last data point to the end time.
-        let lastDataPoint = dataPoints.lastValue;
-        let lastX = Math.floor(xScale(visibleEndTime));
-        let lastY1 = yScale(lastDataPoint.mainThreadUsage);
-        let lastY2 = yScale(lastDataPoint.mainThreadUsage + lastDataPoint.workerThreadUsage);
-        let lastY3 = yScale(lastDataPoint.usage);
-        this._chart.addPointSet(lastX, [lastY1, lastY2, lastY3]);
-    }
-
-    // Private
-
-    _updateDetails(minSize, maxSize, averageSize)
-    {
-        if (this._cachedMinSize === minSize && this._cachedMaxSize === maxSize && this._cachedAverageSize === averageSize)
-            return;
-
-        this._cachedAverageSize = averageSize;
-        this._cachedMinSize = minSize;
-        this._cachedMaxSize = maxSize;
-
-        this._detailsAverageElement.textContent = WI.UIString("Average: %s").format(Number.isFinite(maxSize) ? Number.percentageString(averageSize / 100) : emDash);
-        this._detailsMaxElement.textContent = WI.UIString("Highest: %s").format(Number.isFinite(maxSize) ? Number.percentageString(maxSize / 100) : emDash);
-        this._detailsMinElement.textContent = WI.UIString("Lowest: %s").format(Number.isFinite(minSize) ? Number.percentageString(minSize / 100) : emDash);
-    }
-};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -43,9 +43,11 @@
 
         this._detailsAverageElement = this._detailsElement.appendChild(document.createElement("span"));
         this._detailsElement.appendChild(document.createElement("br"));
-        this._detailsMaxElement = this._detailsElement.appendChild(document.createElement("span"));
-        this._updateDetails(NaN, NaN);
+        this._detailsUsageElement = this._detailsElement.appendChild(document.createElement("span"));
 
+        this.clearLegend();
+        this._updateDetails(NaN);
+
         this._graphElement = this.element.appendChild(document.createElement("div"));
         this._graphElement.classList.add("graph");
 
@@ -56,15 +58,18 @@
 
     // Public
 
+    get graphElement() { return this._graphElement; }
     get chart() { return this._chart; }
 
     clear()
     {
         this._cachedAverageSize = undefined;
-        this._cachedMaxSize = undefined;
-        this._updateDetails(NaN, NaN);
+        this._updateDetails(NaN);
 
+        this.clearLegend();
+
         this._chart.clear();
+        this._chart.needsLayout();
     }
 
     updateChart(dataPoints, size, visibleEndTime, min, max, average, xScale, yScale, property)
@@ -76,9 +81,9 @@
         console.assert(min <= average && average <= max);
         console.assert(property, "CPUUsageView needs a property of the dataPoints to graph");
 
-        this._updateDetails(min, max, average);
+        this._updateDetails(average);
 
-        this._chart.clear();
+        this._chart.clearPoints();
         this._chart.size = size;
         this._chart.needsLayout();
 
@@ -108,20 +113,30 @@
         this._chart.addPoint(lastX, lastY);
     }
 
+    clearLegend()
+    {
+        this._detailsUsageElement.hidden = true;
+        this._detailsUsageElement.textContent = emDash;
+    }
+
+    updateLegend(value)
+    {
+        let usage = Number.isFinite(value) ? Number.percentageString(value / 100) : emDash;
+
+        this._detailsUsageElement.hidden = false;
+        this._detailsUsageElement.textContent = WI.UIString("Usage: %s").format(usage);
+    }
+
     // Private
 
-    _updateDetails(minSize, maxSize, averageSize)
+    _updateDetails(averageSize)
     {
-        if (this._cachedMaxSize === maxSize && this._cachedAverageSize === averageSize)
+        if (this._cachedAverageSize === averageSize)
             return;
 
         this._cachedAverageSize = averageSize;
-        this._cachedMaxSize = maxSize;
 
         this._detailsAverageElement.hidden = !Number.isFinite(averageSize);
-        this._detailsMaxElement.hidden = !Number.isFinite(maxSize);
-
         this._detailsAverageElement.textContent = WI.UIString("Average: %s").format(Number.isFinite(averageSize) ? Number.percentageString(averageSize / 100) : emDash);
-        this._detailsMaxElement.textContent = WI.UIString("Highest: %s").format(Number.isFinite(maxSize) ? Number.percentageString(maxSize / 100) : emDash);
     }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/StackedAreaChart.js (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/StackedAreaChart.js	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/StackedAreaChart.js	2019-03-11 21:26:47 UTC (rev 242739)
@@ -29,7 +29,9 @@
 // To populate with data, first initialize the sections. The class names you
 // provide for the segments will allow you to style them. You can then include
 // a new set of (x, [y1, y2, y3]) points in the chart via `addPointSet`. The
-// order of `y` values must be in the same order as the sections.
+// order of `y` values must be in the same order as the sections. You can add
+// point markers (<circle>) with an (x, y) as well, note these are individual
+// instead of a set.
 //
 // SVG:
 //
@@ -56,8 +58,10 @@
         this._chartElement.setAttribute("preserveAspectRatio", "none");
 
         this._pathElements = [];
+        this._circleElements = [];
 
         this._points = [];
+        this._markers = [];
         this._size = null;
     }
 
@@ -101,11 +105,27 @@
         this._points.push({x, ys});
     }
 
-    clear()
+    clearPoints()
     {
         this._points = [];
     }
 
+    addPointMarker(x, y)
+    {
+        this._markers.push({x, y});
+    }
+
+    clearPointMarkers()
+    {
+        this._markers = [];
+    }
+
+    clear()
+    {
+        this.clearPoints();
+        this.clearPointMarkers();
+    }
+
     // Protected
 
     layout()
@@ -136,5 +156,21 @@
             let pathString = pathComponents[i].join(" ");
             this._pathElements[i].setAttribute("d", pathString);
         }
+
+        if (this._circleElements.length) {
+            for (let circle of this._circleElements)
+                circle.remove();
+            this._circleElements = [];
+        }
+
+        if (this._markers.length) {
+            for (let {x, y} of this._markers) {
+                let circle = this._chartElement.appendChild(createSVGElement("circle"));
+                this._circleElements.push(circle);
+                circle.setAttribute("cx", x);
+                circle.setAttribute("cy", y);
+                circle.setAttribute("r", 3);
+            }
+        }
     }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css (242738 => 242739)


--- trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css	2019-03-11 21:19:11 UTC (rev 242738)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/Variables.css	2019-03-11 21:26:47 UTC (rev 242739)
@@ -132,13 +132,18 @@
     --memory-max-comparison-fill-color: hsl(220, 10%, 75%);
     --memory-max-comparison-stroke-color: hsl(220, 10%, 55%);
 
+    /* LegacyCPUTimeline */
+    --cpu-fill-color: hsl(81, 80%, 50%);
     --cpu-stroke-color: hsl(118, 33%, 42%);
-    --cpu-fill-color: hsl(81, 80%, 50%);
+
+    --cpu-other-thread-fill-color: hsl(81, 80%, 50%);
+    --cpu-other-thread-stroke-color: hsl(81, 80%, 30%);
     --cpu-main-thread-fill-color: hsl(118, 43%, 55%);
-    --cpu-worker-thread-fill-color: hsl(45, 94.75%, 55%);
+    --cpu-main-thread-stroke-color: hsl(118, 33%, 42%);
+    --cpu-worker-thread-fill-color: hsl(59, 79%, 62%);
+    --cpu-worker-thread-stroke-color: hsl(59, 79%, 37%);
+    --cpu-overlay-color: var(--cpu-main-thread-stroke-color);
 
-    --cpu-idle-fill-color: hsl(220, 10%, 75%);
-    --cpu-idle-stroke-color: hsl(220, 10%, 55%);
     --cpu-script-fill-color: hsl(269, 65%, 75%);
     --cpu-script-stroke-color: hsl(269, 33%, 50%);
     --cpu-style-fill-color: hsl(22, 60%, 70%);
@@ -299,6 +304,8 @@
         --network-pseudo-header-color: hsl(312, 55%, 61%);
         --network-error-color: hsl(0, 54%, 55%);
 
+        --cpu-overlay-color: hsl(36, 98%, 50%);
+
         --cpu-low-color: hsl(110, 52%, 56%);
         --cpu-medium-color: hsl(46, 91%, 62%);
         --cpu-high-color: hsl(6, 79%, 57%);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to