summaryrefslogtreecommitdiffstats
path: root/toolkit/content/aboutwebrtc/graph.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/aboutwebrtc/graph.mjs')
-rw-r--r--toolkit/content/aboutwebrtc/graph.mjs186
1 files changed, 186 insertions, 0 deletions
diff --git a/toolkit/content/aboutwebrtc/graph.mjs b/toolkit/content/aboutwebrtc/graph.mjs
new file mode 100644
index 0000000000..f2c93f0709
--- /dev/null
+++ b/toolkit/content/aboutwebrtc/graph.mjs
@@ -0,0 +1,186 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function compStyle(property) {
+ return getComputedStyle(window.document.body).getPropertyValue(property);
+}
+
+function toHumanReadable(num, fpDecimals) {
+ const prefixes = [..." kMGTPEYZYRQ"];
+ const inner = (curr, remainingPrefixes) => {
+ return Math.abs(curr >= 1000)
+ ? inner(curr / 1000, remainingPrefixes.slice(1, -1))
+ : [curr.toFixed(fpDecimals), remainingPrefixes[0].trimEnd()];
+ };
+ return inner(num, prefixes);
+}
+
+class GraphImpl {
+ constructor(width, height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ // The returns the earliest time to graph
+ startTime = dataSet => (dataSet.earliest() || { time: 0 }).time;
+
+ // Returns the latest time to graph
+ stopTime = dataSet => (dataSet.latest() || { time: 0 }).time;
+
+ // The default background color
+ bgColor = () => compStyle("--in-content-page-background");
+ // The color to use for value graph lines
+ valueLineColor = () => "grey";
+ // The color to use for average graph lines and text
+ averageLineColor = () => "green";
+ // The color to use for the max value
+ maxColor = ({ time, value }) => "grey";
+ // The color to use for the min value
+ minColor = ({ time, value }) => "grey";
+ // Title color
+ titleColor = title => compStyle("--in-content-page-color");
+ // The color to use for a data point at a time.
+ // The destination x coordinate and graph width are also provided.
+ datumColor = ({ time, value, x, width }) => "red";
+
+ // Returns an SVG element that needs to be inserted into the DOM for display
+ drawSparseValues = (dataSet, title, config) => {
+ const { width, height } = this;
+ // Clear the canvas
+ const bgColor = this.bgColor();
+ const mkSvgElem = type =>
+ document.createElementNS("http://www.w3.org/2000/svg", type);
+ const svgText = (x, y, text, color, subclass) => {
+ const txt = mkSvgElem("text");
+ txt.setAttribute("x", x);
+ txt.setAttribute("y", y);
+ txt.setAttribute("stroke", bgColor);
+ txt.setAttribute("fill", color);
+ txt.setAttribute("paint-order", "stroke");
+ txt.textContent = text;
+ txt.classList.add(["graph-text", ...[subclass]].join("-"));
+ return txt;
+ };
+ const svg = mkSvgElem("svg");
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
+ svg.setAttribute("version", "1.1");
+ svg.setAttribute("width", width);
+ svg.setAttribute("height", height);
+ svg.classList.add("svg-graph");
+ const rect = mkSvgElem("rect");
+ rect.setAttribute("fill", bgColor);
+ rect.setAttribute("width", width);
+ rect.setAttribute("height", height);
+ svg.appendChild(rect);
+
+ if (config.toRate) {
+ dataSet = dataSet.toRateDataSet();
+ }
+
+ const startTime = this.startTime(dataSet);
+ const stopTime = this.stopTime(dataSet);
+ let timeFilter = ({ time }) => time >= startTime && time <= stopTime;
+
+ let avgDataSet = { dataPoints: [] };
+ if (!config.noAvg) {
+ avgDataSet = dataSet.toRollingAverageDataSet(config.avgPoints);
+ }
+
+ let filtered = dataSet.filter(timeFilter);
+ if (filtered.dataPoints == []) {
+ return svg;
+ }
+
+ let range = filtered.dataRange();
+ if (range === undefined) {
+ return svg;
+ }
+ let { min: rangeMin, max: rangeMax } = range;
+
+ // Adjust the _display_ range to lift flat lines towards the center
+ if (rangeMin == rangeMax) {
+ rangeMin = rangeMin - 1;
+ rangeMax = rangeMax + 1;
+ }
+ const yFactor = (height - 26) / (1 + rangeMax - rangeMin);
+ const yPos = ({ value }) =>
+ this.height - 1 - (value - rangeMin) * yFactor - 13;
+ const xFactor = width / (1 + stopTime - startTime);
+ const xPos = ({ time }) => (time - startTime) * xFactor;
+
+ const toPathStr = dataPoints =>
+ [...dataPoints]
+ .map(
+ (datum, index) => `${index ? "L" : "M"}${xPos(datum)} ${yPos(datum)}`
+ )
+ .join(" ");
+ const valuePath = mkSvgElem("path");
+ valuePath.setAttribute("d", toPathStr(filtered.dataPoints));
+ valuePath.setAttribute("stroke", this.valueLineColor());
+ valuePath.setAttribute("fill", "none");
+ svg.appendChild(valuePath);
+
+ const avgPath = mkSvgElem("path");
+ avgPath.setAttribute("d", toPathStr(avgDataSet.dataPoints));
+ avgPath.setAttribute("stroke", this.averageLineColor());
+ avgPath.setAttribute("fill", "none");
+ svg.appendChild(avgPath);
+ const fixed = num => num.toFixed(config.fixedPointDecimals);
+ const formatValue = value =>
+ config.toHuman
+ ? toHumanReadable(value, config.fixedPointDecimals).join("")
+ : fixed(value);
+
+ // Draw rolling average text
+ avgDataSet.dataPoints.slice(-1).forEach(({ value }) => {
+ svg.appendChild(
+ svgText(
+ 5,
+ height - 4,
+ `AVG: ${formatValue(value)}`,
+ this.averageLineColor(),
+ "avg"
+ )
+ );
+ });
+
+ // Draw title text
+ if (title) {
+ svg.appendChild(
+ svgText(
+ 5,
+ 12,
+ `${title}${config.toRate ? "/s" : ""}`,
+ this.titleColor(this),
+ "title"
+ )
+ );
+ }
+
+ // Draw max value text
+ const maxText = svgText(
+ width - 5,
+ 12,
+ `Max: ${formatValue(range.max)}`,
+ this.maxColor(range.max),
+ "max"
+ );
+ maxText.setAttribute("text-anchor", "end");
+ svg.appendChild(maxText);
+
+ // Draw min value text
+ const minText = svgText(
+ width - 5,
+ height - 4,
+ `Min: ${formatValue(range.min)}`,
+ this.minColor(range.min),
+ "min"
+ );
+ minText.setAttribute("text-anchor", "end");
+ svg.appendChild(minText);
+ return svg;
+ };
+}
+
+export { GraphImpl };