Skip to content

Commit

Permalink
network ui: Render metrics using uPlot graph
Browse files Browse the repository at this point in the history
Adds javascript and html files as well as i18n for new metric tab.
Creates polymer object with properties and methods needed for metric
updates and display.

Screenshot: https://screenshot.googleplex.com/42csV4eydRQAXAy

BUG=b:235622519
TEST=rendered graph on chrome://network's new metric tab.

Change-Id: I9ef0f730b6f96b086e885aac26d6ce94caca25f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3816604
Reviewed-by: Jason Zhang <jiajunz@google.com>
Reviewed-by: Steven Bennetts <stevenjb@chromium.org>
Auto-Submit: Geidel Solivan <geidelxavier@google.com>
Commit-Queue: Geidel Solivan <geidelxavier@google.com>
Cr-Commit-Position: refs/heads/main@{#1034742}
  • Loading branch information
Geidel Solivan authored and Chromium LUCI CQ committed Aug 12, 2022
1 parent 2854604 commit 7f1321b
Show file tree
Hide file tree
Showing 16 changed files with 364 additions and 3 deletions.
21 changes: 21 additions & 0 deletions chrome/app/chromeos_strings.grdp
Expand Up @@ -3186,6 +3186,9 @@
<message name="IDS_NETWORK_UI_TAB_NETWORK_SELECT" desc="Network Select tab name">
Network Select
</message>
<message name="IDS_NETWORK_UI_TAB_NETWORK_METRICS" desc="Network metrics tab name">
Network Metrics
</message>
<message name="IDS_NETWORK_UI_TAB_NETWORK_HOTSPOT" desc="Hotspot tab name">
Hotspot
</message>
Expand Down Expand Up @@ -3312,6 +3315,24 @@
<message name="IDS_NETWORK_UI_NETWORK_LOGS_DEBUGGING_UNKNOWN" desc="Text displayed when the Shill debugging mode is unknown.">
Unknown
</message>
<message name="IDS_NETWORK_UI_NETWORK_METRICS_LABEL" desc="Title for the section for displaying WiFi performance metrics.">
WiFi Performance Metrics
</message>
<message name="IDS_NETWORK_UI_NETWORK_METRICS_RENDER_BUTTON" desc="Text displayed on the button for rendering graph.">
Render
</message>
<message name="IDS_NETWORK_UI_NETWORK_METRICS_START_BUTTON" desc="Text displayed on the button for starting plots.">
Start
</message>
<message name="IDS_NETWORK_UI_NETWORK_METRICS_STOP_BUTTON" desc="Text displayed on the button for stopping plots.">
Stop
</message>
<message name="IDS_NETWORK_UI_NETWORK_METRICS_INCREASE_RATE_BUTTON" desc="Text displayed on the button for increasing the sample rate of plots.">
Increase rate
</message>
<message name="IDS_NETWORK_UI_NETWORK_METRICS_DECREASE_RATE_BUTTON" desc="Text displayed on the button for decreasing the sample rate of plots.">
Decrease rate
</message>
<message name="IDS_NETWORK_UI_TETHERING_CAPABILITIES_LABEL" desc="Title for the section for displaying and refreshing tethering capabilities.">
Tethering Capabilities:
</message>
Expand Down
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
@@ -0,0 +1 @@
fd73be38b1eb42a50fbc4875415000e70fe0e452
16 changes: 15 additions & 1 deletion chrome/browser/resources/chromeos/network_ui/BUILD.gn
Expand Up @@ -32,7 +32,11 @@ generate_grd("build_grd") {
preprocess_if_expr("preprocess") {
out_folder = "$target_gen_dir/$preprocess_folder"
out_manifest = "$target_gen_dir/$preprocess_manifest"
in_files = [ "network_ui_browser_proxy.js" ]
in_files = [
"network_ui_browser_proxy.js",
"third_party/uPlot.iife.min.js",
"third_party/uPlot.min.css",
]
}

preprocess_if_expr("preprocess_generated") {
Expand All @@ -44,6 +48,7 @@ preprocess_if_expr("preprocess_generated") {
"network_logs_ui.js",
"network_state_ui.js",
"network_ui.js",
"network_metrics_ui.js",
]
}

Expand All @@ -69,6 +74,7 @@ js_type_check("closure_compile") {
closure_flags = default_closure_args + mojom_js_args
deps = [
":network_logs_ui",
":network_metrics_ui",
":network_state_ui",
":network_ui",
":network_ui_browser_proxy",
Expand All @@ -92,6 +98,13 @@ js_library("network_logs_ui") {
]
}

js_library("network_metrics_ui") {
deps = [
":network_ui_browser_proxy",
"//ui/webui/resources/js:i18n_behavior.m",
]
}

js_library("network_state_ui") {
deps = [
":network_ui_browser_proxy",
Expand All @@ -114,5 +127,6 @@ html_to_js("web_components") {
"network_logs_ui.js",
"network_state_ui.js",
"network_ui.js",
"network_metrics_ui.js",
]
}
@@ -0,0 +1,44 @@
<style include="cr-shared-style">
cr-button,
.flex-parent{
display: flex;
}

.button {
margin-right: 4px;
padding: 12px 60px;
font-size: 14px;
}

.jc-center {
justify-content: center;
}
</style>
<div>
<h2>$i18n{networkMetricsLabel}</h2>
<div class="flex-parent jc-center">
<cr-button class="action-button button"
on-click="renderGraph_">
$i18n{renderGraphButtonText}
</cr-button>
<cr-button class="action-button button"
on-click="start_">
$i18n{startPlotsButtonText}
</cr-button>
<cr-button class="action-button button"
on-click="stop_">
$i18n{stopPlotsButtonText}
</cr-button>
<cr-button class="action-button button"
on-click="decreaseDelay_">
$i18n{increaseRateButtonText}
</cr-button>
<cr-button class="action-button button"
on-click="increaseDelay_">
$i18n{decreaseRateButtonText}
</cr-button>
</div>
<div class="graph" id="metrics-graph">
<link rel="stylesheet" href="third_party/uPlot.min.css" type="text/css">
</div>
</div>
244 changes: 244 additions & 0 deletions chrome/browser/resources/chromeos/network_ui/network_metrics_ui.js
@@ -0,0 +1,244 @@
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
import 'chrome://resources/cr_elements/shared_style_css.m.js';

import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {NetworkUIBrowserProxy, NetworkUIBrowserProxyImpl} from './network_ui_browser_proxy.js';
import {uPlot} from './third_party/uPlot.iife.min.js';

/**
* @fileoverview
* Polymer element for UI controlling the WiFi performance
* metrics and their values.
*/

Polymer({
is: 'network-metrics-ui',

_template: html`{__html_template__}`,

behaviors: [I18nBehavior],

properties: {
/**
* Circular buffer of WiFi.SignalStrengthRssi
* values from shill used for rendering graph.
* @type {!Array<Number>}
* @private
*/
rssiValues_: {
type: Array,
value: [],
},

/** @private */
minRssi_: {
type: Number,
value: -100,
},

/** @private */
maxRssi_: {
type: Number,
value: -25,
},

/**
* Circular buffer of data extraction times used for rendering graph.
* @type {!Array<number>}
* @private
*/
timeValues_: {
type: Array,
value: [],
},

/** @private */
running_: {
type: Boolean,
value: false,
},

/** @private */
graphRendered_: {
type: Boolean,
value: false,
},

/**
* Milliseconds delay between extraction of data.
* @private
*/
delay_: {
type: Number,
value: 500,
},

/**
* Max data points to track in circular buffer.
* @private
*/
dataCap_: {
type: Number,
value: 100,
},
},

/** @type {!NetworkUIBrowserProxy} */
browserProxy_: NetworkUIBrowserProxyImpl.getInstance(),

/** @private */
start_() {
this.running_ = true;
},

/** @private */
stop_() {
this.running_ = false;
},

/** @private */
decreaseDelay_() {
const minDelay = 1000 / 8; //8Hz
if (this.delay_ > minDelay) {
this.delay_ /= 2;
}
},

/** @private */
increaseDelay_() {
this.delay_ *= 2;
},

/**
* Requests first WiFi's properties and updates metric arrays
* when response contains the network information.
* @private
*/
updateMetrics_() {
this.browserProxy_.getFirstWifiNetworkProperties().then((response) => {
if (response.length <= 0) {
return;
}
const properties = response[0];
this.updateRssi_(properties['WiFi.SignalStrengthRssi']);
this.updateTime_();
});
},

/**
* Updates Rssi array with extracted signal value.
* @param {Number} data: The new Rssi data point
* @private
*/
updateRssi_(data) {
if (this.rssiValues_.length >= this.dataCap_) {
this.rssiValues_.shift();
}
this.rssiValues_.push(data);
},

/**
* Updates time array with current time value.
* @private
*/
updateTime_() {
const currDate = new Date();
if (this.timeValues_.length > this.dataCap_) {
this.timeValues_.shift();
}
this.timeValues_.push(currDate.getTime() / 1000);
},

/**
* Updates metrics and creates nested array series required
* as input for the uPlot graph.
* @return {!Array<Array<Number>>} A data nested array.
* @private
*/
getMetrics_() {
this.updateMetrics_();
const data = [];
data.push(this.timeValues_);
data.push(this.rssiValues_);
return data;
},

/**
* Renders uPlot graph and initiates asynchronous loop
* to keep updating with new values.
* @private
*/
renderGraph_() {
if (!this.graphRendered_) {
const self = this;
const graph = this.makeChart_(self, this.getMetrics_());
this.loop_(self, graph);
this.graphRendered_ = true;
}
},

/**
* @param {number} ms: The time in milliseconds for timeout
* @return {!Promise} A promise to wait a set time
* @private
*/
wait_(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
},

/**
* Repeatedly updates the uPlot graph with new data while the
* running state is active. Time between updates is determined by
* the delay property.
* @param {!Object} polymerObj: The polymer parent object
* @param {!Object} graph: The uPlot object
* @private
*/
async loop_(polymerObj, graph) {
while (true) {
if (polymerObj.running_) {
const updatedData = polymerObj.getMetrics_();
graph.setData(updatedData);
}
await this.wait_(polymerObj.delay_);
}
},

/**
* Handles all uPlot functionality.
* @param {!Object} polymerObj: The polymer parent object
* @param {!Array<Array<Number>>} data: The values to be rendered
* @return {!Object} The uPlot object
* @private
*/
makeChart_(polymerObj, data) {
const opts = {
title: 'Rssi vs Time',
width: window.innerWidth * .9,
height: window.innerHeight * .667,
scales: {
x: {time: true},
y: {
auto: false,
range: [polymerObj.minRssi_, polymerObj.maxRssi_],
},
},
series: [
{},
{
label: 'Rssi',
stroke: 'red',
},
],
};
return new uPlot(
opts, data, polymerObj.shadowRoot.getElementById('metrics-graph'));
},
});

0 comments on commit 7f1321b

Please sign in to comment.