Remove old dead perf dashboard pages and js
The below pages have historically been served on
build.chromium.org/f/chromium/perf/dashboard/ui/*. This was poorly known,
and even more poorly maintained. I sent out a survey[1] asking which pages
under that path were still used. The ones being removed here are no longer
used, and mostly broken to boot.
[1] https://docs.google.com/a/chromium.org/forms/d/1f1yx-_WmMfjVqtsPylzHUWn8Q8k6e7UWAVEz8KrvKKA/viewanalytics
R=qyearsley@chromium.org
Review URL: https://codereview.chromium.org/1654813003
git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/perf@298507 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/dashboard/ui/chrome_report.html b/dashboard/ui/chrome_report.html
deleted file mode 100644
index db81d1f..0000000
--- a/dashboard/ui/chrome_report.html
+++ /dev/null
@@ -1,202 +0,0 @@
-<html>
-
-<!--
- Copyright (c) 2012 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.
--->
-
-<!--
- A brief note on terminology as used here: a "graph" is a plotted screenful
- of data, showing the results of one type of test: for example, the
- page-load-time graph. A "trace" is a single line on a graph, showing one
- one for the test: for example, the reference build trace on the
- page-load-time graph.
-
- This page plots arbitrary numerical data loaded from files in a specific
- format. It uses two or more data files, all JSON-encoded:
-
- graphs.dat: a list of objects, each with these properties: name (the name
- of a graph) and units (the units for the data to be read by humans).
- Schematically:
- [{'name': graph_name, 'important': important,
- 'units': units},
- ...,]
-
- <graphname>-summary.dat: for each of the graphs listed in graphs.dat, the
- corresponding summary file holds rows of data. Each row of data is an
- object with several properties:
- "rev": the revision number for this row of data
- "traces": an object with several properties of its own. The name of
- the property corresponds to a trace name, used only as an
- internal identifier, and the property's value is an array of
- its measurement and that measurement's standard deviation (or
- other measurement error).
- Schematically:
- {"traces": {<trace_name1>: [<value1>, <stddev1>],
- <trace_name2>: [<value2>, <stddev2>], ...},
- "rev": <rev>,
- "ver": <ver>,
- "chan": <chan>,
- }
--->
-<head>
-
-<style type="text/css">
-body {
- font-family: sans-serif;
-}
-div.plot {
- cursor: pointer;
-}
-div.switcher * {
- border: 1px solid black;
- border-radius: 4px 4px 0 0;
- padding-left: 0.5em;
- padding-right: 0.5em;
-}
-div.switcher .select {
- background: #ddd;
- cursor: pointer;
-}
-canvas.plot {
- border: 1px solid black;
- cursor: pointer;
-}
-div.plot-coordinates {
- font-family: monospace;
-}
-iframe.detail {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
-}
-div.selector {
- border: solid 1px black;
- cursor: pointer;
- padding-left: 0.3em;
- background-color: white;
-}
-div.selector:hover {
- background-color: rgb(200,200,250);
-}
-div.selected {
- border-left: none;
-}
-div.selectors {
- width: 80px;
- display: none;
-}
-#explain {
- font-size: 0.75em;
- font-style: italic;
- color: rgb(100,100,100);
-}
-</style>
-
-<script src="js/common.js"></script>
-<script src="js/plotter.js"></script>
-<script src="js/coordinates.js"></script>
-<script src="config.js"></script>
-<script src="js/graph.js"></script>
-
-<script>
-document.title = Config.title + ' - ' + Config.buildslave;
-var params = ParseParams();
-var CHANNELS = ['canary', 'dev', 'beta', 'stable'];
-
-function init() {
- Fetch('graphs.dat', onGraphListReceived);
-}
-
-function onGraphListReceived(data, error) {
- if (error) {
- reportError(error);
- return;
- }
-
- var graphList = JsonToJs(data);
-
- // Add a graph for defined params.
- if (params['channel'] != undefined && params['graph'] != undefined) {
- var channels = params['channel'].split(',');
- for (var i = 0; i < graphList.length; i++) {
- if (graphList[i].name == params['graph']) {
- graphList[i].loc = graphList[i].name + '-summary.dat';
- var options = {
- width: window.innerWidth - 56,
- showDetail: false,
- channels: channels,
- history: params['history'],
- enableMouseScroll: true,
- };
- var graph = new Graph('output', [graphList[i]], options);
- graph.setTitle('<h3>' + params['channel'] + '</h3>');
- graph.graph();
- return;
- }
- }
- } else {
- // Set summary path.
- for (var j = 0; j < graphList.length; j++) {
- graphList[j].loc = graphList[j].name + '-summary.dat';
- }
-
- // Add channel comparison graph.
- var options = {
- width: window.innerWidth - 56,
- showDetail: false,
- channels: CHANNELS,
- enableMouseScroll: true,
- showTabs: true,
- };
- var graph = new Graph('output', graphList, options);
- graph.setTitle('<h3>Channel Comparison</h3>');
- graph.graph();
-
- // Add graph for each channel.
- for (var i = 0; i < CHANNELS.length; i++) {
- var channel = CHANNELS[i];
- var options = {
- width: window.innerWidth - 56,
- showDetail: false,
- channels: [channel],
- enableMouseScroll: true,
- showTabs: true,
- };
- var graph = new Graph('output', graphList, options)
- graph.setTitle('<h3>' + channel + '</h3>');
- graph.graph();
- }
- }
-}
-
-function reportError(error) {
- document.getElementById('output').innerHTML = "<p>" + error + "</p>";
-}
-
-window.addEventListener('load', init, false);
-
-</script>
-</head>
-
-<body>
-<div id="header_text">
-Builds generated by the <a href="#">Chrome Buildbot</a>
-are run through <b>
-<script>
-document.write(Config.title);
-</script>
-</b>and the results of that test are charted here.
-</div>
-<div id="explain">
-The vertical axis is measured values, and the horizontal
-axis is the version number for the build being tested.
-Shift-click to place baseline. Shift-scroll to zoom slowly.
-</div>
-<p></p>
-<div id="output"></div>
-<pre id="log"></pre>
-</body>
-</html>
diff --git a/dashboard/ui/details.html b/dashboard/ui/details.html
deleted file mode 100644
index 1ccbdae..0000000
--- a/dashboard/ui/details.html
+++ /dev/null
@@ -1,175 +0,0 @@
-<html>
-
-<!--
- Copyright (c) 2006-2009 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.
--->
-
-<head>
-<style>
-table {
- font-family: monospace;
- border-collapse: collapse;
-}
-thead {
- border-top: solid 1px gray;
- border-left: solid 1px gray;
-}
-tbody {
- border-top: solid 1px gray;
- border-bottom: solid 1px gray;
- border-left: solid 1px gray;
-}
-th {
- text-align: center;
- border-right: solid 1px gray;
-}
-td {
- text-align: right;
- padding-left: 2em;
- padding-right: 0.5em;
- border-right: solid 1px gray;
-}
-tr.sep {
- border-top: solid 1px gray;
- border-bottom: solid 1px gray;
-}
-td.max-value {
- color: red;
-}
-</style>
-<script src="js/common.js"></script>
-<script>
-function get_index_of_max(ary) {
- var max = ary[0];
- var result = 0;
- for (var i = 1; i < ary.length; ++i) {
- if (ary[i] > max) {
- max = ary[i];
- result = i;
- }
- }
- return result;
-}
-
-function append_column(tr, value, sums, index) {
- td = document.createElement("TD");
- td.appendChild(document.createTextNode(value));
- tr.appendChild(td);
-
- if (index >= 0) {
- if (!sums[index])
- sums[index] = 0;
- sums[index] += parseFloat(value);
- }
-}
-
-function received_data(data) {
- var tbody = document.getElementById("tbody");
- data.replace('\r', '');
-
- var col_sums = [];
- var rows = data.split('\n');
- var num_rows = 0;
-
- for (var i = 0; i < rows.length; ++i) {
- var tr = document.createElement("TR");
- var cols = rows[i].split(' ');
-
- // cols[0] = page name
- // cols[1] = (mean+/-standard deviation):
- // cols[2...] = individual runs
- // Require at least the page name and statistics.
- if (cols.length < 2)
- continue;
-
- var page = cols[0];
- var values = cols[1].split('+/-');
- append_column(tr, page, col_sums, -1);
- append_column(tr, values[0].slice(1), col_sums, 0);
- append_column(tr, values[1].slice(0,-2), col_sums, 1);
-
- for (var j = 2; j < cols.length; ++j)
- append_column(tr, cols[j], col_sums, j);
-
- tbody.appendChild(tr);
- num_rows++;
- }
-
- // print out the column totals (highlight the max value)
- var index_of_max = get_index_of_max(col_sums);
-
- var tr = document.createElement("TR");
- tr.setAttribute("class", "sep");
-
- var td = document.createElement("TD");
- td.appendChild(document.createTextNode("column totals"));
- tr.appendChild(td);
-
- for (var j = 0; j < col_sums.length; ++j) {
- td = document.createElement("TD");
- // don't display the summation of the stddev column since it is bogus
- if (j != 1) {
- if (j == index_of_max)
- td.setAttribute("class", "max-value");
- var precision = j == 0 ? 2 : 0;
- td.appendChild(document.createTextNode(col_sums[j].toFixed(precision)));
- }
- tr.appendChild(td);
- }
-
- tbody.appendChild(tr);
-
- // print out the column averages
- var tr = document.createElement("TR");
- tr.setAttribute("class", "sep");
-
- var td = document.createElement("TD");
- td.appendChild(document.createTextNode("column averages"));
- tr.appendChild(td);
-
- for (var j = 0; j < col_sums.length; ++j) {
- td = document.createElement("TD");
- // don't display the average of the stddev column since it is bogus
- if (j != 1) {
- var precision = 2;
- td.appendChild(document.createTextNode(
- (col_sums[j]/num_rows).toFixed(precision)));
- }
- tr.appendChild(td);
- }
-
- tbody.appendChild(tr);
-}
-
-function init() {
- var params = ParseParams();
- var graph = params.graph ? params.graph + "_" : "";
- var cl = params.cl;
- var traces = [];
- for (var trace in params.trace) {
- // Try to fetch both files, because page cycler and frame rate have
- // have different output files (this should be fixed).
- Fetch(cl + "_" + trace + ".dat", received_data);
- Fetch(cl + "_" + graph + trace + ".dat", received_data);
- traces.push(trace);
- }
- if (traces.length > 0)
- document.getElementById("description").innerText = traces + " in r" + cl;
-}
-
-window.addEventListener("load", init, false);
-</script>
-</head>
-<body>
-<div id="description"></div>
-<table>
- <thead>
- <tr><th>Data</th><th>Mean</th><th>StdDev</th><th colspan="10">Runs...</th></tr>
- </thead>
- <tbody id="tbody">
- </tbody>
-</table>
-</body>
-</html>
diff --git a/dashboard/ui/endure_js/common.js b/dashboard/ui/endure_js/common.js
deleted file mode 100644
index 88136b3..0000000
--- a/dashboard/ui/endure_js/common.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Common methods for performance-plotting Javascript.
- */
-
-/**
- * Fetches a URL asynchronously and invokes a callback when complete.
- *
- * @param {string} url URL to fetch.
- * @param {Function(string, ?string)} callback The function to invoke when the
- * results of the URL fetch are complete. The function should accept two
- * strings representing the URL data, and any errors, respectively.
- */
-function Fetch(url, callback) {
- var r = new XMLHttpRequest();
- r.open('GET', url, true);
- r.setRequestHeader('pragma', 'no-cache');
- r.setRequestHeader('cache-control', 'no-cache');
-
- r.onreadystatechange = function() {
- if (r.readyState == 4) {
- var text = r.responseText;
- var error = null;
- if (r.status != 200)
- error = url + ': ' + r.status + ': ' + r.statusText;
- else if (!text)
- error = url + ': null response';
- callback(text, error);
- }
- }
-
- r.send(null);
-}
-
-/**
- * Parses the parameters of the current page's URL.
- *
- * @return {Object.<string, (string|number)>} An object with properties given
- * by the parameters specified in the URL's query string.
- */
-function ParseParams() {
- var result = {};
-
- var query = window.location.search.substring(1);
- if (query.slice(-1) == '/') {
- query = query.slice(0, -1); // Strip trailing slash.
- }
- var s = query.split('&');
-
- for (i = 0; i < s.length; ++i) {
- var v = s[i].split('=');
- var key = v[0];
- var value = unescape(v[1]);
- result[key] = value;
- }
-
- if ('history' in result) {
- result['history'] = parseInt(result['history']);
- result['history'] = Math.max(result['history'], 2);
- }
- if ('rev' in result) {
- result['rev'] = parseInt(result['rev']);
- }
-
- return result;
-}
-
-/**
- * Creates the URL constructed from the current pathname and the given params.
- *
- * @param {Object.<string, (string|number)>} params An object containing
- * parameters for a URL query string.
- * @return {string} The URL constructed from the given params.
- */
-function MakeURL(params) {
- var key_values = [];
- for (key in params) {
- // better to sanitize key here.
- key_values.push(key + '=' + encodeURIComponent(params[key]));
- }
- return window.location.pathname + '?' + key_values.join('&');
-}
diff --git a/dashboard/ui/endure_js/coordinates.js b/dashboard/ui/endure_js/coordinates.js
deleted file mode 100644
index 29aa473..0000000
--- a/dashboard/ui/endure_js/coordinates.js
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Class and functions to handle positioning of plot data points.
- */
-
-/**
- * Class that handles plot data positioning.
- * @constructor
- * @param {Array.<Array.<Array.<number>>>>} plotData Data that will be plotted.
- * It is an array of lines, where each line is an array of points, and each
- * point is a length-2 array representing an (x, y) pair.
- */
-function Coordinates(plotData) {
- this.plotData = plotData;
-
- height = window.innerHeight - 16;
- width = window.innerWidth - 16;
-
- this.widthMax = width;
- this.heightMax = Math.min(400, height - 85);
-
- this.processValues_('x');
- this.processValues_('y');
-}
-
-/**
- * Determines the min/max x or y values in the plot, accounting for some extra
- * buffer space.
- * @param {string} type The type of value to process, either 'x' or 'y'.
- */
-Coordinates.prototype.processValues_ = function (type) {
- var merged = [];
- for (var i = 0; i < this.plotData.length; i++)
- for (var j = 0; j < this.plotData[i].length; j++) {
- if (type == 'x')
- merged.push(parseFloat(this.plotData[i][j][0])); // Index 0 is x value.
- else
- merged.push(parseFloat(this.plotData[i][j][1])); // Index 1 is y value.
- }
-
- min = merged[0];
- max = merged[0];
- for (var i = 1; i < merged.length; ++i) {
- if (isNaN(min) || merged[i] < min)
- min = merged[i];
- if (isNaN(max) || merged[i] > max)
- max = merged[i];
- }
-
- var bufferSpace = 0.02 * (max - min);
-
- if (type == 'x') {
- this.xBufferSpace_ = bufferSpace;
- this.xMinValue_ = min;
- this.xMaxValue_ = max;
- } else {
- this.yBufferSpace_ = bufferSpace;
- this.yMinValue_ = min;
- this.yMaxValue_ = max;
- }
-};
-
-/**
- * Difference between horizontal upper and lower limit values.
- * @return {number} The x value range.
- */
-Coordinates.prototype.xValueRange = function() {
- return this.xUpperLimitValue() - this.xLowerLimitValue();
-};
-
-/**
- * Difference between vertical upper and lower limit values.
- * @return {number} The y value range.
- */
-Coordinates.prototype.yValueRange = function() {
- return this.yUpperLimitValue() - this.yLowerLimitValue();
-};
-
-/**
- * Converts horizontal data value to pixel value on canvas.
- * @param {number} value The x data value.
- * @return {number} The corresponding x pixel value on the canvas.
- */
-Coordinates.prototype.xPixel = function(value) {
- return this.widthMax *
- ((value - this.xLowerLimitValue()) / this.xValueRange());
-};
-
-/**
- * Converts vertical data value to pixel value on canvas.
- * @param {number} value The y data value.
- * @return {number} The corresponding y pixel value on the canvas.
- */
-Coordinates.prototype.yPixel = function(value) {
- if (this.yValueRange() == 0) {
- // Completely horizontal lines should be centered horizontally.
- return this.heightMax / 2;
- } else {
- return this.heightMax -
- (this.heightMax *
- (value - this.yLowerLimitValue()) / this.yValueRange());
- }
-};
-
-/**
- * Converts x point on canvas to data value it represents.
- * @param {number} position The x pixel value on the canvas.
- * @return {number} The corresponding x data value.
- */
-Coordinates.prototype.xValue = function(position) {
- return this.xLowerLimitValue() +
- (position / this.widthMax * this.xValueRange());
-};
-
-/**
- * Converts y point on canvas to data value it represents.
- * @param {number} position The y pixel value on the canvas.
- * @return {number} The corresponding y data value.
- */
-Coordinates.prototype.yValue = function(position) {
- var ratio = this.heightMax / (this.heightMax - position);
- return this.yLowerLimitValue() + (this.yValueRange() / ratio);
-};
-
-/**
- * Returns the minimum x value of all the data points.
- * @return {number} The minimum x value of all the data points.
- */
-Coordinates.prototype.xMinValue = function() {
- return this.xMinValue_;
-};
-
-/**
- * Returns the maximum x value of all the data points.
- * @return {number} The maximum x value of all the data points.
- */
-Coordinates.prototype.xMaxValue = function() {
- return this.xMaxValue_;
-};
-
-/**
- * Returns the minimum y value of all the data points.
- * @return {number} The minimum y value of all the data points.
- */
-Coordinates.prototype.yMinValue = function() {
- return this.yMinValue_;
-};
-
-/**
- * Returns the maximum y value of all the data points.
- * @return {number} The maximum y value of all the data points.
- */
-Coordinates.prototype.yMaxValue = function() {
- return this.yMaxValue_;
-};
-
-/**
- * Returns the x value at the lower limit of the bounding box of the canvas.
- * @return {number} The x value at the lower limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.xLowerLimitValue = function() {
- return this.xMinValue_ - this.xBufferSpace_;
-};
-
-/**
- * Returns the x value at the upper limit of the bounding box of the canvas.
- * @return {number} The x value at the upper limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.xUpperLimitValue = function() {
- return this.xMaxValue_ + this.xBufferSpace_;
-};
-
-/**
- * Returns the y value at the lower limit of the bounding box of the canvas.
- * @return {number} The y value at the lower limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.yLowerLimitValue = function() {
- return this.yMinValue_ - this.yBufferSpace_;
-};
-
-/**
- * Returns the y value at the upper limit of the bounding box of the canvas.
- * @return {number} The y value at the upper limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.yUpperLimitValue = function() {
- return this.yMaxValue_ + this.yBufferSpace_;
-};
diff --git a/dashboard/ui/endure_js/dom_utils.js b/dashboard/ui/endure_js/dom_utils.js
deleted file mode 100644
index 09158c3..0000000
--- a/dashboard/ui/endure_js/dom_utils.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Collection of functions which operate on DOM.
- */
-
-var domUtils = window['domUtils'] || {};
-
-/**
- * Returns pageX and pageY of the given element.
- *
- * @param {Element} element An element of which the top-left position is to be
- * returned in the coordinate system of the document page.
- * @return {Object} A point object which has {@code x} and {@code y} fields.
- */
-domUtils.pageXY = function(element) {
- var x = 0, y = 0;
- for (; element; element = element.offsetParent) {
- x += element.offsetLeft;
- y += element.offsetTop;
- }
- return {'x': x, 'y': y};
-};
-
-/**
- * Returns pageX and pageY of the given event.
- *
- * @param {Event} event An event of which the position is to be returned in
- * the coordinate system of the document page.
- * @return {Object} A point object which has {@code x} and {@code y} fields.
- */
-domUtils.pageXYOfEvent = function(event) {
- return (event.pageX != null && event.pageY != null) ?
- {'x': event.pageX, 'y': event.pageY} :
- {'x': event.clientX + document.body.scrollLeft +
- document.documentElement.scrollLeft,
- 'y': event.clientY + document.body.scrollTop +
- document.documentElement.scrollTop};
-};
diff --git a/dashboard/ui/endure_js/endure_plotter.js b/dashboard/ui/endure_js/endure_plotter.js
deleted file mode 100644
index bd9e044..0000000
--- a/dashboard/ui/endure_js/endure_plotter.js
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Handles drawing a general Chrome Endure graph.
- */
-
-document.title = Config.title + ' - ' + Config.buildslave;
-
-var unitsX = 'unitsX';
-var unitsY = 'unitsY';
-var unitsYOther = null;
-var graphList = [];
-var revisionNumbers = [];
-var graphDataOtherRows = null;
-
-var eventRows = null;
-var eventTypes = [];
-var eventInfo = null;
-
-var params = ParseParams();
-
-/**
- * Encapsulates a *-summary.dat file.
- * @constructor
- *
- * @param {string} data Raw data from a *-summary.dat file.
- */
-function Rows(data) {
- this.rows = data.split('\n');
- this.length = this.rows.length;
-}
-
-/**
- * Returns the row at the given index.
- *
- * @param {number} i The index of a row of data from the *-summary.dat file.
- * @return {Object} An object representing a row of data from the input file.
- */
-Rows.prototype.get = function(i) {
- if (!this.rows[i].length) return null;
- var row = jsonToJs(this.rows[i]);
- row.revision = isNaN(row['rev']) ? row['rev'] : parseInt(row['rev']);
- return row;
-};
-
-/**
- * Gets the current URL, but without the 'lookout' parameter.
- *
- * @return {string} The current URL, but without the 'lookout' parameter.
- */
-function get_url() {
- new_url = window.location.href;
- new_url = new_url.replace(/\&lookout=1/, '');
- return new_url;
-}
-
-/**
- * Reports an error message on the webpage.
- *
- * @param {string} error An error message to display on the page.
- */
-function reportError(error) {
- document.getElementById('output').innerHTML = '<p>' + error + '</p>';
-}
-
-/**
- * Converts a JSON string into a Javascript object.
- *
- * @param {string} data A string in JSON format.
- * @return {Object} A Javascript object computed from the JSON string.
- */
-function jsonToJs(data) {
- return JSON.parse(data)
-}
-
-/**
- * Causes the page to navigate to another graph.
- *
- * @param {string} graph The name of the graph to which to navigate.
- */
-function goTo(graph) {
- params.graph = graph;
- window.location.href = MakeURL(params);
-}
-
-/**
- * Returns a function that will navigate the page to another graph.
- *
- * @param {string} graph The name of the graph to which to navigate.
- * @return {Function} A function that will navigate the page to another graph.
- */
-function goToClosure(graph) {
- return function(){goTo(graph)};
-}
-
-/**
- * Changes the event being overlayed on the graph.
- *
- * @param {string} eventName The name of the event to overlay on the graph.
- */
-function changeEventCompare(eventName) {
- delete params.revisionOther;
- delete params.graphOther;
- if (eventName == 'None') {
- delete params.event;
- window.location.href = MakeURL(params);
- } else {
- params.event = eventName;
- window.location.href = MakeURL(params);
- }
-}
-
-/**
- * Changes the other measurement being overlayed on top of an original line on
- * the graph.
- *
- * @param {string} graphName The name of the other graph to overlay on top of
- * the existing graph.
- */
-function changeMeasurementCompare(graphName) {
- delete params.revisionOther;
- delete params.event;
- if (graphName == 'None') {
- delete params.graphOther;
- window.location.href = MakeURL(params);
- } else {
- params.graphOther = graphName;
- window.location.href = MakeURL(params);
- }
-}
-
-/**
- * Changes the number of the other revision to compare against on the graph.
- *
- * @param {string} revision The revision number of the other line to plot on
- * the graph.
- */
-function changeRevisionCompare(revision) {
- delete params.graphOther;
- delete params.event;
- if (revision == 'None') {
- delete params.revisionOther;
- window.location.href = MakeURL(params);
- } else {
- params.revisionOther = revision;
- window.location.href = MakeURL(params);
- }
-}
-
-/**
- * Changes the displayed revision number of the graph line.
- *
- * @param {string} revision The revision number of the graph to display.
- */
-function changeRevision(revision) {
- delete params.revisionOther;
- delete params.graphOther;
- delete params.event;
- params.revision = revision;
- window.location.href = MakeURL(params);
-}
-
-/**
- * Initializes the UI for changing the revision number of the displayed graph.
- */
-function initRevisionOptions() {
- var html = '<table cellpadding=5><tr><td>';
- html += '<b>Chrome revision:</b> ';
- html += '<select onchange=\"changeRevision(this.value)\">';
- for (var i = 0; i < revisionNumbers.length; ++i) {
- html += '<option id=\"r' + revisionNumbers[i] + '\"';
- if (revisionNumbers[i] == params.revision)
- html += 'selected=\"true\"';
- html += '>' + revisionNumbers[i] + '</option>';
- }
- html += '</select></td></tr></table>';
-
- document.getElementById('revisions').innerHTML = html;
-}
-
-/**
- * Initializes the UI for changing what is compared against the current line
- * on the displayed graph.
- */
-function initComparisonOptions() {
- var html = '<table cellpadding=5>';
- html += '<tr><td><b>Compare with (select one):</b></td></tr>';
-
- html += '<tr><td> Another run: ';
- html += '<select onchange=\"changeRevisionCompare(this.value)\">';
- html += '<option selected=\"true\">None</option>';
- for (var i = 0; i < revisionNumbers.length; ++i) {
- html += '<option id=\"r' + revisionNumbers[i] + '\"';
- if (revisionNumbers[i] == params.revisionOther)
- html += 'selected=\"true\"';
- html += '>' + revisionNumbers[i] + '</option>';
- }
- html += '</select></td></tr>'
-
- html += '<tr><td> Another measurement of same run: ';
- html += '<select onchange=\"changeMeasurementCompare(this.value)\">';
- html += '<option selected=\"true\">None</option>';
- for (var i = 0; i < graphList.length; ++i) {
- var graph = graphList[i];
- html += '<option id=\"r' + graph.name + '\"';
- if (graph.name == params.graphOther)
- html += 'selected=\"true\"';
- html += '>' + graph.name + '</option>';
- }
- html += '</select></td></tr>';
-
- html += '<tr><td> Event overlay: ';
- if (eventTypes.length >= 1) {
- html += '<select onchange=\"changeEventCompare(this.value)\">';
- html += '<option selected=\"true\">None</option>';
- for (var i = 0; i < eventTypes.length; ++i) {
- var eventType = eventTypes[i];
- html += '<option id=\"' + eventType + '\"';
- if (eventType == params.event)
- html += 'selected=\"true\"';
- html += '>' + eventType + '</option>';
- }
- html += '</select>';
- } else {
- html += ' <i><font size=-1>No events for this revision</font></i>';
- }
- html += '</td></tr></table>';
-
- document.getElementById('comparisons').innerHTML = html;
-}
-
-/**
- * Initializes the UI for the tabs at the top of a graph to change the displayed
- * line.
- */
-function initPlotSwitcher(tabs) {
- var switcher = document.getElementById('switcher');
- for (var i = 0; i < tabs.length; ++i) {
- var is_selected = tabs[i] == params.graph;
- var tab = document.createElement(is_selected ? 'span' : 'a');
- tab.appendChild(document.createTextNode(tabs[i] + ' '));
- if (!is_selected)
- tab.addEventListener('click', goToClosure(tabs[i]), false);
- switcher.appendChild(tab);
- }
-}
-
-/**
- * Adds data to existing arrays indicating what data should be plotted.
- *
- * @param {number} revisionNum The revision number of the data to plot.
- * @param {Rows} dataRows The |Rows| object containing the plot data.
- * @param {Array} plotData A list of data lines to plot, to which new data will
- * be appended.
- * @param {Array} dataDescriptions A list of string descriptions corresponding
- * to data lines in |plotData|, to which new data will be appended.
- * @return {Object} A row object specified by {@code revisionNum} on success,
- * otherwise returns null.
- */
-function addToPlotData(revisionNum, dataRows, plotData, dataDescriptions) {
- // Get data for the revision number(s) to plot.
- var found = false;
- for (var i = 0; i < dataRows.length; ++i) {
- var row = dataRows.get(i);
- if (row && row.revision == revisionNum) {
- found = true;
- break;
- }
- }
- if (!found) {
- return null;
- }
-
- if (row.stack) {
- if (!row.stack_order) {
- reportError('No stack order was specified.');
- return null;
- }
- var traceList = row.stack_order;
- } else {
- // Identify the (single) trace name associated with this revision.
- var traceName = null;
- for (var t in row.traces) {
- if (traceName) {
- reportError('Only one trace per revision is supported for ' +
- 'non-stacked graphs.');
- return null;
- }
- traceName = t;
- }
- var traceList = [traceName];
- }
-
- var lines = [];
- for (var i = 0, traceName; traceName = traceList[i]; ++i) {
- var trace = row.traces[traceName];
- if (!trace) {
- reportError('No specified trace was found.');
- return null;
- }
-
- var points = [];
- for (var j = 0, point; point = trace[j]; ++j) {
- points.push([parseFloat(point[0]), parseFloat(point[1])]);
- }
- lines.push(points);
- dataDescriptions.push(traceName + ' [r' + row.revision + ']');
- }
-
- if (row.stack) {
- lines = graphUtils.stackFrontToBack(graphUtils.interpolate(lines));
- }
-
- for (var i = 0, line; line = lines[i]; ++i) {
- plotData.push(line);
- }
-
- return row;
-}
-
-/**
- * Callback for when a *-summary.dat data file has been read.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedSummary(data, error) {
- if (error) {
- reportError(error);
- return;
- }
-
- var errorMessages = '';
- var rows = new Rows(data);
-
- // Build and order a list of revision numbers.
- revisionNumbers = [];
- for (var i = 0; i < rows.length; ++i) {
- var row = rows.get(i);
- if (!row)
- continue;
- revisionNumbers.push(row.revision);
- }
- revisionNumbers.sort(
- function(a, b) { return parseInt(a, 10) - parseInt(b, 10) });
-
- // Get the revision number to plot.
- if (!('revision' in params) || params.revision == '') {
- if (revisionNumbers.length >= 2 && 'lookout' in params) {
- // Since the last graph (test run) might still be in progress, get the
- // second-to-last graph to display on the summary page. That one
- // is assumed to have finished running to completion.
- params.revision = revisionNumbers[revisionNumbers.length-2];
- } else {
- if (revisionNumbers.length >= 1) {
- params.revision = revisionNumbers[revisionNumbers.length-1];
- } else {
- reportError('No revision information to plot.');
- return;
- }
- }
- }
-
- var plotData = []; // plotData is a list of graph lines; each graph line is
- // a list of points; each point is a list of 2 values,
- // representing the (x, y) pair.
- var dataDescriptions = [];
-
- var row = addToPlotData(params.revision, rows, plotData, dataDescriptions);
- if (!row) {
- errorMessages += 'No data for the specified revision.<br>';
- }
- // From index {@code plotData.length} onwards, any graph lines in
- // {@code plotData} are considered to be part of a second set of graphs.
- var graphsOtherStartIndex = plotData.length;
-
- var rowOther = null;
- if ('revisionOther' in params) {
- rowOther = addToPlotData(params.revisionOther, rows, plotData,
- dataDescriptions);
- if (!rowOther)
- errorMessages += 'No data for the revision to compare against.<br>';
- }
-
- if ('graphOther' in params) {
- rowOther = addToPlotData(params.revision, graphDataOtherRows, plotData,
- dataDescriptions);
- if (rowOther) {
- for (var i = 0; i < graphList.length; ++i) {
- if (graphList[i].name == params.graphOther) {
- unitsYOther = graphList[i].units;
- break;
- }
- }
- } else {
- errorMessages += 'No data for the measurement to compare against.<br>';
- }
- }
-
- // Identify the events for the current revision.
- if (eventRows) {
- for (var index = 0; index < eventRows.length; ++index) {
- var info = eventRows.get(index);
- if (params.revision == info['rev']) {
- eventInfo = info;
- break;
- }
- }
- if (eventInfo != null) {
- for (var key in eventInfo['events']) {
- eventTypes.push(key);
- }
- }
- }
-
- // Get data for the events to display, if one was requested in the params.
- var eventNameToPlot = null;
- var eventInfoToPlot = null;
- if ('event' in params && eventInfo != null) {
- for (var key in eventInfo['events']) {
- if (key == params['event']) {
- eventInfoToPlot = eventInfo['events'][key];
- eventNameToPlot = key;
- }
- }
- }
-
- // Draw everything.
- if (errorMessages == '') {
- var plotter = new Plotter(
- plotData,
- dataDescriptions,
- eventNameToPlot, eventInfoToPlot,
- unitsX, unitsY, unitsYOther, graphsOtherStartIndex,
- document.getElementById('output'),
- 'lookout' in params,
- !!row.stack,
- rowOther && !!rowOther.stack);
-
- plotter.plot();
- } else {
- errorMessages = '<br><br><br><table border=2 cellpadding=5><tr><td>' +
- errorMessages + '</td></tr></table><br><br>';
- document.getElementById('output').innerHTML = errorMessages;
- }
-
- if (!('lookout' in params)) {
- initRevisionOptions();
- initComparisonOptions();
- }
-}
-
-/**
- * Callback for when a second *-summary.dat data file has been read, in the
- * event that a second graph line is being overlayed on top of an existing
- * graph line.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedSummaryGraphOther(data, error) {
- if (error) {
- reportError(error);
- return;
- }
-
- graphDataOtherRows = new Rows(data);
- Fetch(escape(params.graph) + '-summary.dat', receivedSummary);
-}
-
-/**
- * Callback for when an event info file has been read.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedEvents(data, error) {
- if (!error)
- eventRows = new Rows(data);
- fetchSummary();
-}
-
-/**
- * Callback for when a graphs.dat data file has been read.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedGraphList(data, error) {
- if (error) {
- reportError(error);
- return;
- }
- graphList = jsonToJs(data);
-
- if (!('graph' in params) || params.graph == '')
- if (graphList.length > 0)
- params.graph = graphList[0].name
-
- // Add a selection tab for each graph, and find the units for the selected
- // one while we're at it.
- tabs = [];
- for (var index = 0; index < graphList.length; ++index) {
- var graph = graphList[index];
- tabs.push(graph.name);
- if (graph.name == params.graph) {
- unitsX = graph.units_x;
- unitsY = graph.units;
- }
- }
- initPlotSwitcher(tabs);
-
- fetchEvents();
-}
-
-/**
- * Starts fetching a *-summary.dat file.
- */
-function fetchSummary() {
- if ('graphOther' in params) {
- // We need to overlay a second graph over the first one, so we need to
- // fetch that summary data too. Do it first.
- Fetch(escape(params.graphOther) + '-summary.dat',
- receivedSummaryGraphOther);
- } else {
- Fetch(escape(params.graph) + '-summary.dat',
- receivedSummary);
- }
-}
-
-/**
- * Starts fetching an event info file.
- */
-function fetchEvents() {
- Fetch('_EVENT_-summary.dat', receivedEvents);
-}
-
-/**
- * Starts fetching a graphs.dat file.
- */
-function fetchGraphList() {
- Fetch('graphs.dat', receivedGraphList);
-}
-
-window.addEventListener('load', fetchGraphList, false);
diff --git a/dashboard/ui/endure_js/graph_utils.js b/dashboard/ui/endure_js/graph_utils.js
deleted file mode 100644
index ad5c83d..0000000
--- a/dashboard/ui/endure_js/graph_utils.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Collection of functions which operate on graph data.
- */
-
-var graphUtils = window['graphUtils'] || {};
-
-/**
- * Interpolate given multiple lines of graphs, and returns the lines of
- * the graphs where each line has the same number of points and x coordinates.
- *
- * For example,
- * <pre>
- * [[[0, 1], [2, 3]], // 1st line
- * [[1, 3]]] // 2nd line
- * </pre>
- * will be converted to
- * <pre>
- * [[[0, 1], [1, 2], [2, 3]], // [1, 2] is interpolated.
- * [[0, 0], [1, 3], [2, 0]]] // [0, 0] and [2, 0] are interpolated.
- * </pre>
- * where every line has points at x=0, 1 and 2.
- * Interpolated data points are marked with a property
- * {@code point.interpolated == true}.
- *
- * @param {Array.<Array.<Array.<number>>>} plotData List of arrays that
- * represent individual lines. The line itself is an Array of points.
- * @return {Array.<Array.<Array.<number>>>} An interpolated {@code plotData}.
- * The original {@code plotData} is not affected.
- */
-graphUtils.interpolate = function(plotData) {
- var interpolated = []; // resulting interpolated {@code plotData}
- var unconsumed = []; // indices to unconsumed points in {@code plotData}
- for (var i = 0; i < plotData.length; ++i) {
- interpolated.push([]);
- unconsumed.push(0);
- }
-
- // Returns the next x-coordinate to interpolate if any, or null.
- function nextX() {
- var index = null;
- for (var i = 0; i < unconsumed.length; ++i) {
- if (0 <= unconsumed[i] && unconsumed[i] < plotData[i].length &&
- (index == null ||
- plotData[i][unconsumed[i]][0] <
- plotData[index][unconsumed[index]][0])) {
- index = i;
- }
- }
- return index == null ? null : plotData[index][unconsumed[index]][0];
- }
-
- for (var x = nextX(); x != null; x = nextX()) { // for all x
- for (var i = 0; i < plotData.length; ++i) { // for all lines
- var y = 0;
- var hasPoint = false;
- if (0 <= unconsumed[i] && unconsumed[i] < plotData[i].length) {
- var p = plotData[i][unconsumed[i]];
- if (p[0] <= x) {
- y = p[1]; // The original line has a point at x.
- hasPoint = true;
- } else if (unconsumed[i] == 0) {
- y = 0; // y = 0 before the first point
- } else {
- // Interpolate a point.
- var p0 = plotData[i][unconsumed[i] - 1];
- y = (x - p0[0]) / (p[0] - p0[0]) * (p[1] - p0[1]) + p0[1];
- }
- } // else y = 0 because it's out of range.
-
- var point = [x, y];
- if (!hasPoint) {
- point.interpolated = true;
- }
- interpolated[i].push(point);
- }
-
- // Consume {@code plotData} by incrementing indices in {@code unconsumed}.
- for (var i = 0; i < unconsumed.length; ++i) {
- if (0 <= unconsumed[i] && unconsumed[i] < plotData[i].length &&
- plotData[i][unconsumed[i]][0] <= x) {
- ++unconsumed[i];
- }
- }
- }
-
- return interpolated;
-};
-
-/**
- * Creates and returns a set of stacked graphs, assuming the given
- * {@code plotData} is interpolated by {@code graphUtils.interpolate}.
- *
- * For example,
- * <pre>
- * [[[0, 1], [1, 2]], // 1st line
- * [[0, 1], [1, 3]], // 2nd line
- * [[0, 2], [1, 1]]] // 3rd line
- * </pre>
- * will be converted to
- * <pre>
- * [[[0, 1], [1, 2]], // 1st
- * [[0, 2], [1, 5]], // 1st + 2nd
- * [[0, 4], [1, 6]]] // 1st + 2nd + 3rd
- * </pre>
- *
- * @param {Array.<Array.<Array.<number>>>} plotData List of arrays that
- * represent individual lines. The line itself is an Array of points.
- * @return {Array.<Array.<Array.<number>>>} A stacked {@code plotData}.
- * The original {@code plotData} is not affected.
- */
-graphUtils.stackFrontToBack = function(plotData) {
- if (!(plotData && plotData[0] && plotData[0].length > 0)) {
- return [];
- }
-
- var stacked = [];
- for (var i = 0; i < plotData.length; ++i) {
- stacked.push([]);
- }
-
- for (var j = 0; j < plotData[0].length; ++j) {
- for (var i = 0; i < plotData.length; ++i) {
- var point = [
- plotData[i][j][0],
- plotData[i][j][1] +
- (i == 0 ? 0 : stacked[i - 1][j][1])];
- if (plotData[i][j].interpolated) {
- point.interpolated = true;
- }
- stacked[i].push(point);
- }
- }
-
- return stacked;
-};
diff --git a/dashboard/ui/endure_js/plotter.js b/dashboard/ui/endure_js/plotter.js
deleted file mode 100644
index edbbf11..0000000
--- a/dashboard/ui/endure_js/plotter.js
+++ /dev/null
@@ -1,1199 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Collection of functions and classes used to plot data in a
- * <canvas>. Create a Plotter() to generate a plot.
- */
-
-/**
- * Adds commas to a given number.
- *
- * Examples:
- * 1234.56 => "1,234.56"
- * 99999 => "99,999"
- *
- * @param {string|number} number The number to format.
- * @return {string} String representation of |number| with commas for every
- * three digits to the left of a decimal point.
- */
-function addCommas(number) {
- number += ''; // Convert number to string if not already a string.
- var numberParts = number.split('.');
- var integralPart = numberParts[0];
- var fractionalPart = numberParts.length > 1 ? '.' + numberParts[1] : '';
- var reThreeDigits = /(\d+)(\d{3})/;
- while (reThreeDigits.test(integralPart))
- integralPart = integralPart.replace(reThreeDigits, '$1' + ',' + '$2');
- return integralPart + fractionalPart;
-}
-
-/**
- * Vertical marker to highlight data points that are being hovered over by the
- * mouse.
- *
- * @param {string} color The color to make the marker, e.g., 'rgb(100,80,240)'.
- * @return {Element} A div Element object representing the vertical marker.
- */
-function VerticalMarker(color) {
- var m = document.createElement('div');
- m.style.backgroundColor = color;
- m.style.opacity = '0.3';
- m.style.position = 'absolute';
- m.style.left = '-2px';
- m.style.top = '-2px';
- m.style.width = '0px';
- m.style.height = '0px';
- return m;
-}
-
-/**
- * Class representing a horizontal marker at the indicated mouse location.
- * @constructor
- *
- * @param {Element} canvasElement The canvas bounds.
- * @param {Number} yValue The data value corresponding to the vertical click
- * location.
- * @param {Number} yOtherValue If the plot is overlaying two coordinate systems,
- * this is the data value corresponding to the vertical click location in
- * the second coordinate system. Can be null.
- */
-function HorizontalMarker(canvasElement, yValue, yOtherValue) {
- var m = document.createElement('div');
- m.style.backgroundColor = HorizontalMarker.COLOR;
- m.style.opacity = '0.3';
- m.style.position = 'absolute';
- m.style.width = canvasElement.offsetWidth + 'px';
- m.style.height = HorizontalMarker.HEIGHT + 'px';
-
- this.markerDiv = m;
- this.value = yValue;
- this.otherValue = yOtherValue;
-}
-
-HorizontalMarker.HEIGHT = 5;
-HorizontalMarker.COLOR = 'rgb(0,100,100)';
-
-/**
- * Locates this element at a specified position.
- *
- * @param {Element} canvasElement The canvas element at which this element is
- * to be placed.
- * @param {number} y Y position relative to the canvas element.
- */
-HorizontalMarker.prototype.locateAt = function(canvasElement, y) {
- var div = this.markerDiv;
- div.style.left = domUtils.pageXY(canvasElement).x -
- domUtils.pageXY(div.offsetParent) + 'px';
- div.style.top = (y + domUtils.pageXY(canvasElement).y
- - domUtils.pageXY(div.offsetParent).y
- - (HorizontalMarker.HEIGHT / 2)) + 'px';
-};
-
-/**
- * Removes the horizontal marker from the graph.
- */
-HorizontalMarker.prototype.remove = function() {
- this.markerDiv.parentNode.removeChild(this.markerDiv);
-};
-
-/**
- * An information indicator hovering around the mouse cursor on the graph.
- * This class is used to show a legend near the mouse cursor.
- *
- * A set of legends under the graph is managed separately in
- * {@code Plotter.createLegendsSummaryElement_}.
- *
- * @constructor
- */
-function HoveringInfo() {
- this.containerDiv_ = document.createElement('div');
- this.containerDiv_.style.display = 'none';
- this.containerDiv_.style.position = 'absolute';
- this.containerDiv_.style.border = '1px solid #000';
- this.containerDiv_.style.padding = '0.12em';
- this.containerDiv_.style.backgroundColor = '#ddd';
- this.colorIndicator_ = document.createElement('div');
- this.colorIndicator_.style.display = 'inline-block';
- this.colorIndicator_.style.width = '1em';
- this.colorIndicator_.style.height = '1em';
- this.colorIndicator_.style.verticalAlign = 'text-bottom';
- this.colorIndicator_.style.margin = '0 0.24em 0 0';
- this.colorIndicator_.style.border = '1px solid #000';
- this.legendText_ = document.createElement('span');
- this.itemValueText_ = document.createElement('span');
-
- this.containerDiv_.appendChild(this.colorIndicator_);
- this.containerDiv_.appendChild(this.legendText_);
- var div = document.createElement('div');
- div.appendChild(this.itemValueText_);
- this.containerDiv_.appendChild(div);
-}
-
-/**
- * Returns the container element;
- *
- * @return {Element} The container element.
- */
-HoveringInfo.prototype.getElement = function() {
- return this.containerDiv_;
-};
-
-/**
- * Shows or hides the element.
- *
- * @param {boolean} show Shows the element if true, or hides it.
- */
-HoveringInfo.prototype.show = function(show) {
- this.containerDiv_.style.display = show ? 'block' : 'none';
-};
-
-/**
- * Returns the position of the container element in the page coordinate.
- *
- * @return {Object} A point object which has {@code x} and {@code y} fields.
- */
-HoveringInfo.prototype.pageXY = function() {
- return domUtils.pageXY(this.containerDiv_);
-};
-
-/**
- * Locates the element at the specified position.
- *
- * @param {number} x X position in the page coordinate.
- * @param {number} y Y position in the page coordinate.
- */
-HoveringInfo.prototype.locateAtPageXY = function(x, y) {
- var parentXY = domUtils.pageXY(this.containerDiv_.offsetParent);
- this.containerDiv_.style.left = x - parentXY.x + 'px';
- this.containerDiv_.style.top = y - parentXY.y + 'px';
-};
-
-/**
- * Returns the legend text.
- *
- * @return {?string} The legend text.
- */
-HoveringInfo.prototype.getLegendText = function() {
- return this.legendText_.textContent;
-};
-
-/**
- * Changes the legend text.
- *
- * @param {string} text The new text to be set.
- */
-HoveringInfo.prototype.setLegendText = function(text) {
- this.legendText_.textContent = text;
-};
-
-/**
- * Changes the item value.
- *
- * @param {number} value The new value to be shown.
- */
-HoveringInfo.prototype.setItemValue = function(value) {
- this.itemValueText_.textContent = 'Item value = ' + addCommas(value);
-};
-
-/**
- * Changes the color of the color indicator.
- *
- * @param {string} color The new color to be set.
- */
-HoveringInfo.prototype.setColorIndicator = function(color) {
- this.colorIndicator_.style.backgroundColor = color;
-};
-
-/**
- * Main class that does the actual plotting.
- *
- * Draws a chart using a canvas element. Takes an array of lines to draw.
- * @constructor
- *
- * @param {Array} plotData list of arrays that represent individual lines. The
- * line itself is an Array of points.
- * @param {Array} dataDescriptions list of data descriptions for each line in
- * |plotData|.
- * @param {string} eventName The string name of an event to overlay on the
- * graph. Should be 'null' if there are no events to overlay.
- * @param {Object} eventInfo If |eventName| is specified, an array of event
- * points to overlay on the graph. Each event point in the array is itself
- * a 2-element array, where the first element is the x-axis value at which
- * the event occurred during the test, and the second element is a
- * dictionary of kay/value pairs representing metadata associated with the
- * event.
- * @param {string} unitsX The x-axis units of the data being plotted.
- * @param {string} unitsY The y-axis units of the data being plotted.
- * @param {string} unitsYOther If another graph (with different y-axis units) is
- * being overlayed over the first graph, this represents the units of the
- * other graph. Otherwise, this should be 'null'.
- * @param {?number} graphsOtherStartIndex Specifies the starting index of
- * the second set of lines. {@code plotData} in the range of
- * [0, {@code graphsOtherStartIndex}) are treated as the first set of lines,
- * and ones in the range of
- * [{@code graphsOtherStartIndex}, {@code plotData.length}) are as
- * the second set. 0, {@code plotData.length} and {@code null} mean
- * no second set, i.e. all the data in {@code plotData} represent the single
- * set of lines.
- * @param {Element} resultNode A DOM Element object representing the DOM node to
- * which the plot should be attached.
- * @param {boolean} is_lookout Whether or not the graph should be drawn
- * in 'lookout' mode, which is a summarized view that is made for overview
- * pages when the graph is drawn in a more confined space.
- * @param {boolean} stackedGraph Whether or not the first set of lines is
- * a stacked graph.
- * @param {boolean} stackedGraphOther Whether or not the second set of lines is
- * a stacked graph.
- *
- * Example of the |plotData|:
- * [
- * [line 1 data],
- * [line 2 data]
- * ].
- * Line data looks like [[point one], [point two]].
- * And individual points are [x value, y value]
- */
-function Plotter(plotData, dataDescriptions, eventName, eventInfo, unitsX,
- unitsY, unitsYOther, graphsOtherStartIndex, resultNode,
- is_lookout, stackedGraph, stackedGraphOther) {
- this.plotData_ = plotData;
- this.dataDescriptions_ = dataDescriptions;
- this.eventName_ = eventName;
- this.eventInfo_ = eventInfo;
- this.unitsX_ = unitsX;
- this.unitsY_ = unitsY;
- this.unitsYOther_ = unitsYOther;
- this.graphsOtherStartIndex_ =
- (0 < graphsOtherStartIndex && graphsOtherStartIndex < plotData.length) ?
- graphsOtherStartIndex : null;
- this.resultNode_ = resultNode;
- this.is_lookout_ = is_lookout;
- this.stackedGraph_ = stackedGraph;
- this.stackedGraphOther_ = stackedGraphOther;
-
- this.dataColors_ = [];
-
- this.coordinates = null;
- this.coordinatesOther = null;
- if (this.unitsYOther_ && this.graphsOtherStartIndex_) {
- // Need two different coordinate systems to overlay on the same graph.
- this.coordinates = new Coordinates(
- this.plotData_.slice(0, this.graphsOtherStartIndex_));
- this.coordinatesOther = new Coordinates(
- this.plotData_.slice(this.graphsOtherStartIndex_));
- } else {
- this.coordinates = new Coordinates(this.plotData_);
- }
-
- // A color palette that's unambigous for normal and color-deficient viewers.
- // Values are (red, green, blue) on a scale of 255.
- // Taken from http://jfly.iam.u-tokyo.ac.jp/html/manuals/pdf/color_blind.pdf.
- this.colors = [[0, 114, 178], // Blue.
- [230, 159, 0], // Orange.
- [0, 158, 115], // Green.
- [204, 121, 167], // Purplish pink.
- [86, 180, 233], // Sky blue.
- [213, 94, 0], // Dark orange.
- [0, 0, 0], // Black.
- [240, 228, 66] // Yellow.
- ];
-
- for (var i = 0, colorIndex = 0; i < this.dataDescriptions_.length; ++i)
- this.dataColors_[i] = this.makeColor(colorIndex++);
-}
-
-/**
- * Generates a string representing a color corresponding to the given index
- * in a color array. Handles wrapping around the color array if necessary.
- *
- * @param {number} i An index into the |this.colors| array.
- * @return {string} A string representing a color in 'rgb(X,Y,Z)' format.
- */
-Plotter.prototype.makeColor = function(i) {
- var index = i % this.colors.length;
- return 'rgb(' + this.colors[index][0] + ',' +
- this.colors[index][1] + ',' +
- this.colors[index][2] + ')';
-};
-
-/**
- * Same as function makeColor above, but also takes a transparency value
- * indicating how transparent to make the color appear.
- *
- * @param {number} i An index into the |this.colors| array.
- * @param {number} transparencyPercent Percentage transparency to make the
- * color, e.g., 0.75.
- * @return {string} A string representing a color in 'rgb(X,Y,Z,A)' format,
- * where A is the percentage transparency.
- */
-Plotter.prototype.makeColorTransparent = function(i, transparencyPercent) {
- var index = i % this.colors.length;
- return 'rgba(' + this.colors[index][0] + ',' +
- this.colors[index][1] + ',' +
- this.colors[index][2] + ',' + transparencyPercent + ')';
-};
-
-/**
- * Gets the data color value associated with a specified color index.
- *
- * @param {number} i An index into the |this.colors| array.
- * @return {string} A string representing a color in 'rgb(X,Y,Z,A)' format,
- * where A is the percentage transparency.
- */
-Plotter.prototype.getDataColor = function(i) {
- if (this.dataColors_[i])
- return this.dataColors_[i];
- else
- return this.makeColor(i);
-};
-
-/**
- * Gets the fill color value associated with a specified color index.
- *
- * @param {number} i An index into the |this.colors| array.
- * @return {string} A string representing a color in 'rgba(R,G,B,A)' format,
- * where A is the percentage transparency.
- */
-Plotter.prototype.getFillColor = function(i) {
- return this.makeColorTransparent(i, 0.4);
-};
-
-/**
- * Does the actual plotting.
- */
-Plotter.prototype.plot = function() {
- var self = this;
-
- this.canvasElement_ = this.canvas_();
- this.rulerDiv_ = this.ruler_();
-
- // Markers for the result point(s)/events that the mouse is currently
- // hovering over.
- this.cursorDiv_ = new VerticalMarker('rgb(100,80,240)');
- this.cursorDivOther_ = new VerticalMarker('rgb(50,50,50)');
- this.eventDiv_ = new VerticalMarker('rgb(255, 0, 0)');
- this.hoveringInfo_ = new HoveringInfo();
-
- this.resultNode_.appendChild(this.canvasElement_);
- this.resultNode_.appendChild(this.coordinates_());
- this.resultNode_.appendChild(this.rulerDiv_);
- this.resultNode_.appendChild(this.cursorDiv_);
- this.resultNode_.appendChild(this.cursorDivOther_);
- this.resultNode_.appendChild(this.eventDiv_);
- this.resultNode_.appendChild(this.hoveringInfo_.getElement());
- this.attachEventListeners_();
-
- // Now draw the canvas.
- var ctx = this.canvasElement_.getContext('2d');
-
- // Clear it with white: otherwise canvas will draw on top of existing data.
- ctx.clearRect(0, 0, this.canvasElement_.width, this.canvasElement_.height);
-
- // Draw all data lines in the reverse order so the last graph appears on
- // the backmost and the first graph appears on the frontmost.
- function draw(plotData, coordinates, colorOffset, stack) {
- for (var i = plotData.length - 1; i >= 0; --i) {
- if (stack) {
- self.plotAreaUnderLine_(ctx, self.getFillColor(colorOffset + i),
- plotData[i], coordinates);
- }
- self.plotLine_(ctx, self.getDataColor(colorOffset + i),
- plotData[i], coordinates);
- }
- }
- draw(this.plotData_.slice(0,
- this.graphsOtherStartIndex_ ?
- this.graphsOtherStartIndex_ :
- this.plotData_.length),
- this.coordinates, 0, this.stackedGraph_);
- if (this.graphsOtherStartIndex_) {
- draw(this.plotData_.slice(this.graphsOtherStartIndex_),
- this.unitsYOther_ ? this.coordinatesOther : this.coordinates,
- this.graphsOtherStartIndex_, this.stackedGraphOther_);
- }
-
- // Draw events overlayed on graph if needed.
- if (this.eventName_ && this.eventInfo_)
- this.plotEvents_(ctx, 'rgb(255, 150, 150)', this.coordinates);
-
- this.graduation_divs_ = this.graduations_(this.coordinates, 0, false);
- if (this.unitsYOther_) {
- this.graduation_divs_ = this.graduation_divs_.concat(
- this.graduations_(this.coordinatesOther, 1, true));
- }
- for (var i = 0; i < this.graduation_divs_.length; ++i)
- this.resultNode_.appendChild(this.graduation_divs_[i]);
-};
-
-/**
- * Draws events overlayed on top of an existing graph.
- *
- * @param {Object} ctx A canvas element object for drawing.
- * @param {string} strokeStyles A string representing the drawing style.
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- */
-Plotter.prototype.plotEvents_ = function(ctx, strokeStyles, coordinateSystem) {
- ctx.strokeStyle = strokeStyles;
- ctx.fillStyle = strokeStyles;
- ctx.lineWidth = 1.0;
-
- ctx.beginPath();
- var data = this.eventInfo_;
- for (var index = 0; index < data.length; ++index) {
- var event_time = data[index][0];
- var x = coordinateSystem.xPixel(event_time);
- ctx.moveTo(x, 0);
- ctx.lineTo(x, this.canvasElement_.offsetHeight);
- }
- ctx.closePath();
- ctx.stroke();
-};
-
-/**
- * Draws a line on the graph.
- *
- * @param {Object} ctx A canvas element object for drawing.
- * @param {string} strokeStyles A string representing the drawing style.
- * @param {Array} data A list of [x, y] values representing the line to plot.
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- */
-Plotter.prototype.plotLine_ = function(ctx, strokeStyles, data,
- coordinateSystem) {
- ctx.strokeStyle = strokeStyles;
- ctx.fillStyle = strokeStyles;
- ctx.lineWidth = 2.0;
-
- ctx.beginPath();
- var initial = true;
- var allPoints = [];
- for (var i = 0; i < data.length; ++i) {
- var pointX = parseFloat(data[i][0]);
- var pointY = parseFloat(data[i][1]);
- var x = coordinateSystem.xPixel(pointX);
- var y = coordinateSystem.yPixel(0);
- if (isNaN(pointY)) {
- // Re-set 'initial' if we're at a gap in the data.
- initial = true;
- } else {
- y = coordinateSystem.yPixel(pointY);
- if (initial)
- initial = false;
- else
- ctx.lineTo(x, y);
- }
-
- ctx.moveTo(x, y);
- if (!data[i].interpolated) {
- allPoints.push([x, y]);
- }
- }
- ctx.closePath();
- ctx.stroke();
-
- if (!this.is_lookout_) {
- // Draw a small dot at each point.
- for (var i = 0; i < allPoints.length; ++i) {
- ctx.beginPath();
- ctx.arc(allPoints[i][0], allPoints[i][1], 3, 0, Math.PI*2, true);
- ctx.fill();
- }
- }
-};
-
-/**
- * Fills an area under the given line on the graph.
- *
- * @param {Object} ctx A canvas element object for drawing.
- * @param {string} fillStyle A string representing the drawing style.
- * @param {Array} data A list of [x, y] values representing the line to plot.
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- */
-Plotter.prototype.plotAreaUnderLine_ = function(ctx, fillStyle, data,
- coordinateSystem) {
- if (!data[0]) {
- return; // nothing to draw
- }
-
- ctx.beginPath();
- var x = coordinateSystem.xPixel(parseFloat(data[0][0]) || 0);
- var y = coordinateSystem.yPixel(parseFloat(data[0][1]) || 0);
- var y0 = coordinateSystem.yPixel(coordinateSystem.yMinValue());
- ctx.moveTo(x, y0);
- for (var point, i = 0; point = data[i]; ++i) {
- var pointX = parseFloat(point[0]);
- var pointY = parseFloat(point[1]);
- if (isNaN(pointX)) { continue; } // Skip an invalid point.
- if (isNaN(pointY)) {
- ctx.lineTo(x, y0);
- var yWasNaN = true;
- } else {
- x = coordinateSystem.xPixel(pointX);
- y = coordinateSystem.yPixel(pointY);
- if (yWasNaN) {
- ctx.lineTo(x, y0);
- yWasNaN = false;
- }
- ctx.lineTo(x, y);
- }
- }
- ctx.lineTo(x, y0);
-
- ctx.lineWidth = 0;
- // Clear the area with white color first.
- var COLOR_WHITE = 'rgb(255,255,255)';
- ctx.strokeStyle = COLOR_WHITE;
- ctx.fillStyle = COLOR_WHITE;
- ctx.fill();
- // Then, fill the area with the specified color.
- ctx.strokeStyle = fillStyle;
- ctx.fillStyle = fillStyle;
- ctx.fill();
-};
-
-/**
- * Attaches event listeners to DOM nodes.
- */
-Plotter.prototype.attachEventListeners_ = function() {
- var self = this;
- this.canvasElement_.parentNode.addEventListener(
- 'mousemove', function(evt) { self.onMouseMove_(evt); }, false);
- this.canvasElement_.parentNode.addEventListener(
- 'mouseover', function(evt) { self.onMouseOver_(evt); }, false);
- this.canvasElement_.parentNode.addEventListener(
- 'mouseout', function(evt) { self.onMouseOut_(evt); }, false);
- this.cursorDiv_.addEventListener(
- 'click', function(evt) { self.onMouseClick_(evt); }, false);
- this.cursorDivOther_.addEventListener(
- 'click', function(evt) { self.onMouseClick_(evt); }, false);
- this.eventDiv_.addEventListener(
- 'click', function(evt) { self.onMouseClick_(evt); }, false);
-};
-
-/**
- * Update the horizontal line that is following where the mouse is hovering.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.updateRuler_ = function(evt) {
- var r = this.rulerDiv_;
- r.style.left = this.canvasElement_.offsetLeft + 'px';
- r.style.top = this.canvasElement_.offsetTop + 'px';
- r.style.width = this.canvasElement_.offsetWidth + 'px';
- var h = domUtils.pageXYOfEvent(evt).y -
- domUtils.pageXY(this.canvasElement_).y;
- if (h > this.canvasElement_.offsetHeight)
- h = this.canvasElement_.offsetHeight;
- r.style.height = h + 'px';
-};
-
-/**
- * Update the highlighted data point at the x value that the mouse is hovering
- * over.
- *
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- * @param {number} currentIndex The index into the |this.plotData| array of the
- * data point being hovered over, for a given line.
- * @param {Object} cursorDiv A DOM element div object representing the highlight
- * itself.
- * @param {number} dataIndex The index into the |this.plotData| array of the
- * line being hovered over.
- */
-Plotter.prototype.updateCursor_ = function(coordinateSystem, currentIndex,
- cursorDiv, dataIndex) {
- var c = cursorDiv;
- c.style.top = this.canvasElement_.offsetTop + 'px';
- c.style.height = this.canvasElement_.offsetHeight + 'px';
-
- // Left point is half-way to the previous x value, unless it's the first
- // point, in which case it's the x value of the current point.
- var leftPoint = null;
- if (currentIndex == 0) {
- leftPoint = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][0][0]);
- }
- else {
- var left_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex - 1][0]);
- var curr_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex][0]);
- leftPoint = (left_x + curr_x) / 2;
- }
- c.style.left = leftPoint;
-
- // Width is half-way to the next x value minus the left point, unless it's
- // the last point, in which case it's the x value of the current point minus
- // the left point.
- if (currentIndex == this.plotData_[dataIndex].length - 1) {
- var curr_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex][0]);
- c.style.width = curr_x - leftPoint;
- }
- else {
- var next_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex + 1][0]);
- var curr_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex][0]);
- c.style.width = ((next_x + curr_x) / 2) - leftPoint;
- }
-};
-
-/**
- * Update the highlighted event at the x value that the mouse is hovering over.
- *
- * @param {number} x The x-value (pixel) at which to draw the event highlight
- * div.
- * @param {boolean} show Whether or not to show the highlight div.
- */
-Plotter.prototype.updateEventDiv_ = function(x, show) {
- var c = this.eventDiv_;
- c.style.top = this.canvasElement_.offsetTop + 'px';
- c.style.height = this.canvasElement_.offsetHeight + 'px';
-
- if (show) {
- c.style.left = this.canvasElement_.offsetLeft + (x - 2);
- c.style.width = 8;
- } else {
- c.style.width = 0;
- }
-};
-
-/**
- * Updates the hovering information.
- *
- * @param {Event} evt An event object, which specifies the position of the mouse
- * cursor.
- * @param {boolean} show Whether or not to show the hovering info. Even if it's
- * true, if the cursor position is out of the appropriate area, nothing will
- * be shown.
- */
-Plotter.prototype.updateHoveringInfo_ = function(evt, show) {
- var evtPageXY = domUtils.pageXYOfEvent(evt);
- var hoveringInfoPageXY = this.hoveringInfo_.pageXY();
- var canvasPageXY = domUtils.pageXY(this.canvasElement_);
-
- var coord = this.coordinates;
- // p = the mouse cursor position in value coordinates.
- var p = {'x': coord.xValue(evtPageXY.x - canvasPageXY.x),
- 'y': coord.yValue(evtPageXY.y - canvasPageXY.y)};
- if (!show ||
- !(this.stackedGraph_ || this.stackedGraphOther_) ||
- p.x < coord.xMinValue() || coord.xMaxValue() < p.x ||
- p.y < coord.yMinValue() || coord.yMaxValue() < p.y) {
- this.hoveringInfo_.show(false);
- return;
- } else {
- this.hoveringInfo_.show(true);
- }
-
- /**
- * Finds the closest lines (upside and downside of the cursor position).
- * Returns a set of upside/downside line indices and point index on success
- * or null.
- */
- function findClosestLines(lines, opt_startIndex, opt_endIndex) {
- var offsetIndex = opt_startIndex || 0;
- lines =
- opt_endIndex != null ? lines.slice(offsetIndex, opt_endIndex) :
- opt_startIndex != null ? lines.slice(offsetIndex) :
- lines;
-
- var upsideClosestLineIndex = null;
- var upsideClosestYDistance = coord.yValueRange();
- var downsideClosestLineIndex = null;
- var downsideClosestYDistance = coord.yValueRange();
- var upsideClosestPointIndex = null;
-
- for (var lineIndex = 0, line; line = lines[lineIndex]; ++lineIndex) {
- for (var i = 1; line[i]; ++i) {
- var p0 = line[i - 1], p1 = line[i];
- if (p0[0] <= p.x && p.x < p1[0]) {
- // Calculate y-value of the line at p.x, which is the cursor point.
- var y = (p.x - p0[0]) / (p1[0] - p0[0]) * (p1[1] - p0[1]) + p0[1];
- if (p.y < y && y - p.y < upsideClosestYDistance) {
- upsideClosestLineIndex = lineIndex;
- upsideClosestYDistance = y - p.y;
-
- if (p.x - p0[0] < p1[0] - p.x) {
- upsideClosestPointIndex = i - 1;
- } else {
- upsideClosestPointIndex = i;
- }
- } else if (y <= p.y && p.y - y < downsideClosestYDistance) {
- downsideClosestLineIndex = lineIndex;
- downsideClosestYDistance = p.y - y;
- }
- break;
- }
- }
- }
-
- return (upsideClosestLineIndex != null &&
- upsideClosestPointIndex != null) ?
- {'upsideLineIndex': offsetIndex + upsideClosestLineIndex,
- 'downsideLineIndex': downsideClosestYDistance == null ? null :
- offsetIndex + downsideClosestLineIndex,
- 'upsidePointIndex': offsetIndex + upsideClosestPointIndex} :
- null;
- }
-
- // Find the closest lines above and below the mouse cursor.
- var closest = null;
- // Since the other set of graphs are drawn over the first set, try to find
- // the closest lines from the other set of graphs first.
- if (this.graphsOtherStartIndex_ && this.stackedGraphOther_) {
- closest = findClosestLines(this.plotData_, this.graphsOtherStartIndex_);
- }
- if (!closest && this.stackedGraph_) {
- closest = this.graphsOtherStartIndex_ ?
- findClosestLines(this.plotData_, 0, this.graphsOtherStartIndex_) :
- findClosestLines(this.plotData_);
- }
- if (!closest) {
- this.hoveringInfo_.show(false);
- return;
- }
-
- // Update the contents of the hovering info box.
- // Color indicator, description and the value of the item.
- this.hoveringInfo_.setColorIndicator(
- this.getDataColor(closest.upsideLineIndex));
- this.hoveringInfo_.setLegendText(
- this.dataDescriptions_[closest.upsideLineIndex]);
- var y1 = this.plotData_[closest.upsideLineIndex][closest.upsidePointIndex][1];
- var y0 = closest.downsideLineIndex == null ?
- 0 :
- this.plotData_[closest.downsideLineIndex][closest.upsidePointIndex][1];
- this.hoveringInfo_.setItemValue(y1 - y0);
-
- // Locate the hovering info box near the mouse cursor.
- var DIV_X_OFFSET = 10, DIV_Y_OFFSET = -20;
- if (evtPageXY.x + this.hoveringInfo_.getElement().offsetWidth <
- canvasPageXY.x + this.canvasElement_.offsetWidth) {
- this.hoveringInfo_.locateAtPageXY(evtPageXY.x + DIV_X_OFFSET,
- evtPageXY.y + DIV_Y_OFFSET);
- } else { // If lacking space at the right side, locate it at the left side.
- this.hoveringInfo_.locateAtPageXY(
- evtPageXY.x - this.hoveringInfo_.getElement().offsetWidth - DIV_X_OFFSET,
- evtPageXY.y + DIV_Y_OFFSET);
- }
-};
-
-/**
- * Handle a mouse move event.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.onMouseMove_ = function(evt) {
- var self = this;
-
- var canvas = evt.currentTarget.firstChild;
- var evtPageXY = domUtils.pageXYOfEvent(evt);
- var canvasPageXY = domUtils.pageXY(this.canvasElement_);
- var positionX = evtPageXY.x - canvasPageXY.x;
- var positionY = evtPageXY.y - canvasPageXY.y;
-
- // Identify the index of the x value that is closest to the mouse x value.
- var xValue = this.coordinates.xValue(positionX);
- var lineIndex = !this.stackedGraph_ ? 0 :
- this.graphsOtherStartIndex_ ? this.graphsOtherStartIndex_ - 1 :
- this.plotData_.length - 1;
- var line = this.plotData_[lineIndex];
- var min_diff = Math.abs(line[0][0] - xValue);
- indexValueX = 0;
- for (var i = 1; i < line.length; ++i) {
- var diff = Math.abs(line[i][0] - xValue);
- if (diff < min_diff) {
- min_diff = diff;
- indexValueX = i;
- }
- }
-
- // Identify the index of the x value closest to the mouse x value for the
- // other graph being overlayed on top of the original graph, if one exists.
- if (this.unitsYOther_) {
- var xValue = this.coordinatesOther.xValue(positionX);
- var lineIndexOther = !this.stackedGraphOther_ ?
- this.graphsOtherStartIndex_ : this.plotData_.length - 1;
- var lineOther = this.plotData_[lineIndexOther];
- var min_diff = Math.abs(lineOther[0][0] - xValue);
- var indexValueXOther = 0;
- for (var i = 1; i < lineOther.length; ++i) {
- var diff = Math.abs(lineOther[i][0] - xValue);
- if (diff < min_diff) {
- min_diff = diff;
- indexValueXOther = i;
- }
- }
- }
-
- // Update coordinate information displayed directly underneath the graph.
- function legendLabel(lineIndex, opt_labelText) {
- return '<span style="color:' + self.getDataColor(lineIndex) + '">' +
- (opt_labelText || self.dataDescriptions_[lineIndex]) +
- '</span>: ';
- }
- function valuesAtCursor(lineIndex, pointIndex, unitsY, yValue) {
- return '<span style="color:' + self.getDataColor(lineIndex) + '">' +
- self.plotData_[lineIndex][pointIndex][0] + ' ' + self.unitsX_ + ': ' +
- addCommas(self.plotData_[lineIndex][pointIndex][1].toFixed(2)) + ' ' +
- unitsY + '</span> [hovering at ' + addCommas(yValue.toFixed(2)) +
- ' ' + unitsY + ']';
- }
-
- this.infoBox_.rows[0].label.innerHTML = legendLabel(lineIndex);
- this.infoBox_.rows[0].content.innerHTML = valuesAtCursor(
- lineIndex, indexValueX, this.unitsY_, this.coordinates.yValue(positionY));
- var row = this.infoBox_.rows[1];
- if (this.unitsYOther_) {
- row.label.innerHTML = legendLabel(lineIndexOther);
- row.content.innerHTML = valuesAtCursor(
- lineIndexOther, indexValueXOther, this.unitsYOther_,
- this.coordinatesOther.yValue(positionY));
- } else if (this.graphsOtherStartIndex_) {
- row.label.innerHTML = legendLabel(
- this.stackedGraphOther_ ?
- this.plotData_.length - 1 : this.graphsOtherStartIndex_);
- row.content.innerHTML = valuesAtCursor(
- this.stackedGraphOther_ ?
- this.plotData_.length - 1 : this.graphsOtherStartIndex_,
- indexValueX, this.unitsY_, this.coordinates.yValue(positionY));
- } else if (!this.stackedGraph_ && this.dataDescriptions_.length > 1) {
- row.label.innerHTML = legendLabel(1);
- row.content.innerHTML = valuesAtCursor(
- 1, indexValueX, this.unitsY_, this.coordinates.yValue(positionY));
- } else if (row) {
- row.label.innerHTML = '';
- row.content.innerHTML = '';
- }
-
- // If there is a horizontal marker, also display deltas relative to it.
- if (this.horizontal_marker_) {
- var baseline = this.horizontal_marker_.value;
- var delta = this.coordinates.yValue(positionY) - baseline;
- var fraction = delta / baseline; // Allow division by 0.
-
- var deltaStr = (delta >= 0 ? '+' : '') + delta.toFixed(0) + ' ' +
- this.unitsY_;
- var percentStr = (fraction >= 0 ? '+' : '') + (fraction * 100).toFixed(3) +
- '%';
-
- this.baselineDeltasTd_.innerHTML = deltaStr + ': ' + percentStr;
-
- if (this.unitsYOther_) {
- var baseline = this.horizontal_marker_.otherValue;
- var yValue2 = this.coordinatesOther.yValue(positionY);
- var delta = yValue2 - baseline;
- var fraction = delta / baseline; // Allow division by 0.
-
- var deltaStr = (delta >= 0 ? '+' : '') + delta.toFixed(0) + ' ' +
- this.unitsYOther_;
- var percentStr = (fraction >= 0 ? '+' : '') +
- (fraction * 100).toFixed(3) + '%';
- this.baselineDeltasTd_.innerHTML += '<br>' + deltaStr + ': ' + percentStr;
- }
- }
-
- this.updateRuler_(evt);
- this.updateCursor_(this.coordinates, indexValueX, this.cursorDiv_, 0);
- if (this.unitsYOther_ && this.graphsOtherStartIndex_) {
- this.updateCursor_(this.coordinatesOther, indexValueXOther,
- this.cursorDivOther_, this.graphsOtherStartIndex_);
- }
-
- // If there are events displayed, see if we're hovering close to an existing
- // event on the graph, and if so, display the metadata associated with it.
- if (this.eventName_ != null && this.eventInfo_ != null) {
- this.infoBox_.rows[1].label.innerHTML = 'Event "' + this.eventName_ +
- '": ';
- var data = this.eventInfo_;
- var showed_event = false;
- var x = 0;
- for (var index = 0; index < data.length; ++index) {
- var event_time = data[index][0];
- x = this.coordinates.xPixel(event_time);
- if (positionX >= x - 10 && positionX <= x + 10) {
- var metadata = data[index][1];
- var metadata_str = "";
- for (var meta_key in metadata)
- metadata_str += meta_key + ': ' + metadata[meta_key] + ', ';
- metadata_str = metadata_str.substring(0, metadata_str.length - 2);
- this.infoBox_.rows[1].content.innerHTML = event_time + ' ' +
- this.unitsX_ + ': {' + metadata_str + '}';
- showed_event = true;
- this.updateEventDiv_(x, true);
- break;
- }
- }
- if (!showed_event) {
- this.coordinatesTdOther_.innerHTML =
- 'move mouse close to vertical event marker';
- this.updateEventDiv_(x, false);
- }
- }
-
- this.updateHoveringInfo_(evt, true);
-};
-
-/**
- * Handle a mouse over event.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.onMouseOver_ = function(evt) {
- this.updateHoveringInfo_(evt, true);
-};
-
-/**
- * Handle a mouse out event.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.onMouseOut_ = function(evt) {
- this.updateHoveringInfo_(evt, false);
-};
-
-/**
- * Handle a mouse click event.
- *
- * @param {Object} evt A mouse event object representing a mouse click event.
- */
-Plotter.prototype.onMouseClick_ = function(evt) {
- // Shift-click controls the horizontal reference line.
- if (evt.shiftKey) {
- if (this.horizontal_marker_)
- this.horizontal_marker_.remove();
-
- var canvasY = domUtils.pageXYOfEvent(evt).y -
- domUtils.pageXY(this.canvasElement_).y;
- this.horizontal_marker_ = new HorizontalMarker(
- this.canvasElement_,
- this.coordinates.yValue(canvasY),
- (this.coordinatesOther ? this.coordinatesOther.yValue(canvasY) : null));
- // Insert before cursor node, otherwise it catches clicks.
- this.cursorDiv_.parentNode.insertBefore(
- this.horizontal_marker_.markerDiv, this.cursorDiv_);
- this.horizontal_marker_.locateAt(this.canvasElement_, canvasY);
- }
-};
-
-/**
- * Generates and returns a list of div objects representing horizontal lines in
- * the graph that indicate y-axis values at a computed interval.
- *
- * @param {Object} coordinateSystem a Coordinates object representing the
- * coordinate system for which the graduations should be created.
- * @param {number} colorIndex An index into the |this.colors| array representing
- * the color to make the graduations in the event that two graphs with
- * different coordinate systems are being overlayed on the same plot.
- * @param {boolean} isRightSide Whether or not the graduations should have
- * right-aligned text (used when the graduations are for a second graph
- * that is being overlayed on top of another graph).
- * @return {Array} An array of DOM Element objects representing the divs.
- */
-Plotter.prototype.graduations_ = function(coordinateSystem, colorIndex,
- isRightSide) {
- // Don't allow a graduation in the bottom 5% of the chart or the number label
- // would overflow the chart bounds.
- var yMin = coordinateSystem.yLowerLimitValue() +
- .05 * coordinateSystem.yValueRange();
- var yRange = coordinateSystem.yUpperLimitValue() - yMin;
-
- // Use the largest scale that fits 3 or more graduations.
- // We allow scales of [...,500, 250, 100, 50, 25, 10,...].
- var scale = 5000000000;
- while (scale) {
- if (Math.floor(yRange / scale) > 2) break; // 5s.
- scale /= 2;
- if (Math.floor(yRange / scale) > 2) break; // 2.5s.
- scale /= 2.5;
- if (Math.floor(yRange / scale) > 2) break; // 1s.
- scale /= 2;
- }
-
- var graduationPosition = yMin + (scale - yMin % scale);
- var graduationDivs = [];
- while (graduationPosition < coordinateSystem.yUpperLimitValue() ||
- yRange == 0) {
- var graduation = document.createElement('div');
- var canvasPosition;
- if (yRange == 0) {
- // Center the graduation vertically.
- canvasPosition = this.canvasElement_.offsetHeight / 2;
- } else {
- canvasPosition = coordinateSystem.yPixel(graduationPosition);
- }
- if (this.unitsYOther_) {
- graduation.style.borderTop = '1px dashed ' +
- this.makeColorTransparent(colorIndex, 0.4)
- } else {
- graduation.style.borderTop = '1px dashed rgba(0,0,0,.08)';
- }
- graduation.style.position = 'absolute';
- graduation.style.left = this.canvasElement_.offsetLeft + 'px';
- graduation.style.top = canvasPosition + this.canvasElement_.offsetTop +
- 'px';
- graduation.style.width = this.canvasElement_.offsetWidth -
- this.canvasElement_.offsetLeft + 'px';
- graduation.style.paddingLeft = '4px';
- if (this.unitsYOther_)
- graduation.style.color = this.makeColorTransparent(colorIndex, 0.9)
- else
- graduation.style.color = 'rgba(0,0,0,.4)';
- graduation.style.fontSize = '9px';
- graduation.style.paddingTop = '0';
- graduation.style.zIndex = '-1';
- if (isRightSide)
- graduation.style.textAlign = 'right';
- if (yRange == 0)
- graduation.innerHTML = addCommas(yMin);
- else
- graduation.innerHTML = addCommas(graduationPosition);
- graduationDivs.push(graduation);
- if (yRange == 0)
- break;
- graduationPosition += scale;
- }
- return graduationDivs;
-};
-
-/**
- * Generates and returns a div object representing the horizontal line that
- * follows the mouse pointer around the plot.
- *
- * @return {Object} A DOM Element object representing the div.
- */
-Plotter.prototype.ruler_ = function() {
- var ruler = document.createElement('div');
- ruler.setAttribute('class', 'plot-ruler');
- ruler.style.borderBottom = '1px dotted black';
- ruler.style.position = 'absolute';
- ruler.style.left = '-2px';
- ruler.style.top = '-2px';
- ruler.style.width = '0px';
- ruler.style.height = '0px';
- return ruler;
-};
-
-/**
- * Generates and returns a canvas object representing the plot itself.
- *
- * @return {Object} A DOM Element object representing the canvas.
- */
-Plotter.prototype.canvas_ = function() {
- var canvas = document.createElement('canvas');
- canvas.setAttribute('id', '_canvas');
- canvas.setAttribute('class', 'plot');
- canvas.setAttribute('width', this.coordinates.widthMax);
- canvas.setAttribute('height', this.coordinates.heightMax);
- canvas.plotter = this;
- return canvas;
-};
-
-/**
- * Generates and returns a div object representing the coordinate information
- * displayed directly underneath a graph.
- *
- * @return {Object} A DOM Element object representing the div.
- */
-Plotter.prototype.coordinates_ = function() {
- var coordinatesDiv = document.createElement('div');
- var table_html = '<table border=0 width="100%"';
- if (this.is_lookout_) {
- table_html += ' style="font-size:0.8em"';
- }
- table_html += '><tbody><tr>';
- table_html += '<td><span class="legend_item"></span>' +
- '<span class="plot-coordinates"><i>move mouse over graph</i></span></td>';
- table_html += '<td align="right">x-axis is ' + this.unitsX_ + '</td>';
- table_html += '</tr><tr>';
- table_html += '<td><span class="legend_item"></span>' +
- '<span class="plot-coordinates"></span></td>';
-
- if (!this.is_lookout_) {
- table_html += '<td align="right" style="color: ' + HorizontalMarker.COLOR +
- '"><i>Shift-click to place baseline.</i></td>';
- }
- table_html += '</tr></tbody></table>';
- coordinatesDiv.innerHTML = table_html;
-
- var trs = coordinatesDiv.querySelectorAll('tr');
- this.infoBox_ = {rows: []};
- this.infoBox_.rows.push({
- label: trs[0].querySelector('span.legend_item'),
- content: trs[0].querySelector('span.plot-coordinates')});
- if (this.dataDescriptions_.length > 1 || this.eventName_) {
- this.infoBox_.rows.push({
- label: trs[1].querySelector('span.legend_item'),
- content: trs[1].querySelector('span.plot-coordinates')});
- }
-
- this.baselineDeltasTd_ = trs[1].childNodes[1];
-
- // Add a summary of legends in case of stacked graphs.
- if (this.stackedGraph_ || this.stackedGraphOther_) {
- var legendPane = document.createElement('div');
- legendPane.style.fontSize = '80%';
- coordinatesDiv.appendChild(legendPane);
-
- if (this.graphsOtherStartIndex_) {
- legendPane.appendChild(
- this.createLegendsSummaryElement_(
- this.dataDescriptions_.slice(0, this.graphsOtherStartIndex_),
- 0));
- legendPane.appendChild(
- this.createLegendsSummaryElement_(
- this.dataDescriptions_.slice(this.graphsOtherStartIndex_),
- this.graphsOtherStartIndex_));
- } else {
- legendPane.appendChild(
- this.createLegendsSummaryElement_(this.dataDescriptions_, 0));
- }
- }
-
- return coordinatesDiv;
-};
-
-/**
- * Creates and returns a DOM element which shows a summary of legends.
- *
- * @param {!Array.<string>} legendTexts An array of legend texts.
- * @param {number} colorIndexOffset Offset index for color. i-th legend text
- * has an indicator in {@code (colorIndexOffset + i)}-th color
- * @return {!Element} An element which shows a summary of legends.
- */
-Plotter.prototype.createLegendsSummaryElement_ = function(legendTexts,
- colorIndexOffset) {
- var containerElem = document.createElement('div');
-
- for (var i = 0, text; text = legendTexts[i]; ++i) {
- var colorIndicatorElem = document.createElement('div');
- colorIndicatorElem.style.display = 'inline-block';
- colorIndicatorElem.style.width = '1em';
- colorIndicatorElem.style.height = '1em';
- colorIndicatorElem.style.verticalAlign = 'text-bottom';
- colorIndicatorElem.style.margin = '0 0.24em 0 0';
- colorIndicatorElem.style.border = '1px solid #000';
- colorIndicatorElem.style.backgroundColor =
- this.getDataColor(colorIndexOffset + i);
- var legendTextElem = document.createElement('span');
- legendTextElem.textContent = text;
- var legendElem = document.createElement('span');
- legendElem.style.whiteSpace = 'nowrap';
- legendElem.appendChild(colorIndicatorElem);
- legendElem.appendChild(legendTextElem);
- legendElem.style.margin = '0 0.8em 0 0';
- containerElem.appendChild(legendElem);
- // Add a space to break lines if necessary.
- containerElem.appendChild(document.createTextNode(' '));
- }
-
- return containerElem;
-};
diff --git a/dashboard/ui/endure_plotter.html b/dashboard/ui/endure_plotter.html
deleted file mode 100644
index df89935..0000000
--- a/dashboard/ui/endure_plotter.html
+++ /dev/null
@@ -1,116 +0,0 @@
-<!--
- Copyright (c) 2012 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.
--->
-
-<!--
- HTML for a general Chrome Endure graph.
--->
-
-<html>
- <head>
- <style>
- body {
- font-family: sans-serif;
- }
- div#output {
- cursor: pointer;
- }
- div#switcher * {
- border: 1px solid black;
- border-radius: 4px 4px 0 0;
- padding-left: 0.5em;
- padding-right: 0.5em;
- }
- div#switcher a {
- background: #ddd;
- cursor: pointer;
- }
- canvas.plot {
- border: 1px solid black;
- }
- div.plot-coordinates {
- font-family: monospace;
- }
- iframe {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
- }
- div.selected {
- border-left: none;
- }
- #explain {
- font-size: 0.75em;
- font-style: italic;
- color: rgb(100,100,100);
- }
- </style>
-
- <script src="js/common.js"></script>
- <script src="js/coordinates.js"></script>
- <script src="js/dom_utils.js"></script>
- <script src="js/graph_utils.js"></script>
- <script src="js/plotter.js"></script>
- <script src="config.js"></script>
-
- <script src="js/endure_plotter.js"></script>
- </head>
-
- <body>
- <div id="header_lookout" align="center">
- <font style='color: #0066FF; font-family: Arial, serif;
- font-size: 12pt; font-weight: bold;'>
- <script>
- document.write("<a target=\"_blank\" href=\"");
- document.write(get_url());
- document.write("\">");
- if ('graph' in params && params.graph != '')
- document.write(escape(params.graph));
- else if ('header' in params && params.header != '')
- document.write(escape(params.header));
- else
- document.write(Config.title);
- document.write("</a>");
- </script>
- </font>
- </div>
-
- <div id="header_text">
- Builds generated by the <i>
- <script>
- document.write(Config.buildslave);
- </script>
- </i> are run through <b>
- <script>
- document.write(Config.title);
- </script>
- </b> and the results of that test are charted here.
- </div>
-
- <div id="explain">
- More information about Chrome Endure can be found here:
- <a href="http://www.chromium.org/developers/testing/pyauto/perf/endure">
- http://www.chromium.org/developers/testing/pyauto/perf/endure</a>
- </div>
-
- <p></p>
-
- <div id="switcher"></div>
- <div id="output"></div> <br>
- <div id="revisions"></div> <br>
- <div id="comparisons"></div> <br>
- <div id="events"></div>
- <script>
- if ('lookout' in params) {
- document.getElementById("switcher").style.display = "none";
- document.getElementById("header_text").style.display = "none";
- document.getElementById("explain").style.display = "none";
- } else {
- document.getElementById("header_lookout").style.display = "none";
- }
- </script>
- </body>
-</html>
diff --git a/dashboard/ui/generic_plotter.html b/dashboard/ui/generic_plotter.html
deleted file mode 100644
index 0d1591d..0000000
--- a/dashboard/ui/generic_plotter.html
+++ /dev/null
@@ -1,533 +0,0 @@
-<html>
-
-<!--
- Copyright (c) 2012 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.
--->
-
-<!--
- For testing this file locally, start a localhost server at the root of the
- perf directory (e.g. with "python -m SimpleHTTPServer") and pass in a
- baseUrl as a query parameter, e.g.
- http://localhost:8000/dashboard/ui/generic_plotter.html?history=150&rev=-1&graph=dom&baseUrl=http://localhost:8000/data/linux-release-webkit-latest/dromaeo_domcore/.
-
- You need a localhost server to get around Chromium's restrictions on loading
- file urls in XMLHttpRequests.
-
- A brief note on terminology as used here: a "graph" is a plotted screenful
- of data, showing the results of one type of test: for example, the
- page-load-time graph. A "trace" is a single line on a graph, showing one
- one for the test: for example, the reference build trace on the
- page-load-time graph.
-
- This page plots arbitrary numerical data loaded from files in a specific
- format. It uses two or more data files, all JSON-encoded:
-
- graphs.dat: a list of objects, each with these properties: name (the name
- of a graph) and units (the units for the data to be read by humans).
- Schematically:
- [{"name": <graph_name>, "units": <units>}, ...]
-
- <graphname>-summary.dat: for each of the graphs listed in graphs.dat, the
- corresponding summary file holds rows of data. Each row of data is an
- object with several properties:
- "rev": the revision number for this row of data
- "traces": an object with several properties of its own. The name of
- the property corresponds to a trace name, used only as an
- internal identifier, and the property's value is an array of
- its measurement and that measurement's standard deviation (or
- other measurement error).
- Schematically:
- {"rev": <rev>,
- "traces": {<trace_name1>: [<value1>, <stddev1>],
- <trace_name2>: [<value2>, <stddev2>], ...}
- }
--->
-<head>
-<style>
-body {
- font-family: sans-serif;
-}
-div#output {
- cursor: pointer;
-}
-div#switcher * {
- border: 1px solid black;
- border-radius: 4px 4px 0 0;
- padding-left: 0.5em;
- padding-right: 0.5em;
-}
-div#switcher a {
- background: #ddd;
- cursor: pointer;
-}
-canvas.plot {
- border: 1px solid black;
-}
-div.plot-coordinates {
- font-family: monospace;
-}
-iframe {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
-}
-.selector {
- border: solid 1px black;
- cursor: pointer;
- padding-left: 0.3em;
- background-color: white;
- width: 80px;
- display: inline-block;
-}
-.selector:hover {
- background-color: rgb(200,200,250);
-}
-div#selectors {
- display: none;
- right: 6px;
- position: absolute;
-}
-#explain {
- font-size: 0.75em;
- font-style: italic;
- color: rgb(100,100,100);
-}
-#views {
- border: 1px solid black;
- width: 100%;
- display: none;
-}
-#webkit-tab {
- border-left: none;
- display: none;
-}
-</style>
-
-<script src="js/common.js"></script>
-<script src="js/plotter.js"></script>
-<script src="js/coordinates.js"></script>
-<script src="config.js"></script>
-<script>
-document.title = Config.title + ' - ' + Config.buildslave;
-
-var did_position_details = false;
-var units = 'thing-a-ma-bobs';
-var graph_list = [];
-var first_trace = '';
-
-var refresh_params = false;
-var params = ParseParams();
-if (!('history' in params)) {
- params.history = 150;
- refresh_params = true;
-}
-if (!('rev' in params)) {
- params.rev = -1; // -1 specifies the latest revision.
- refresh_params = true;
-}
-if (refresh_params)
- window.location.href = MakeURL(params);
-
-if (!Config.detailTabs)
- Config.detailTabs = {'view-change': 'CL'};
-
-/**
- * Encapsulates a *-summary.dat file.
- * @constructor
- */
-function Rows(data) {
- this.rows = data.split('\n');
- this.length = this.rows.length;
-}
-
-/**
- * Returns the row at the given index.
- */
-Rows.prototype.get = function(i) {
- if (!i in this.rows || this.rows[i] === undefined) return null;
- if (!this.rows[i].length) return null;
- var row = JSON.parse(this.rows[i]);
- row.revision = isNaN(row['rev']) ? row['rev'] : parseInt(row['rev']);
- row.webkitRevision = isNaN(row['webkit_rev']) ?
- row['webkit_rev'] : parseInt(row['webkit_rev']);
- return row;
-};
-
-function report_error(error) {
- document.getElementById("output").innerHTML = "<p>" + error + "</p>";
-}
-
-function received_graph_list(data, error) {
- if (error) {
- report_error(error);
- return;
- }
- graph_list = JSON.parse(data);
-
- if (!('graph' in params) || params.graph == '') {
- if (graph_list.length > 0)
- params.graph = graph_list[0].name
- }
-
- // Add a selection tab for each graph, and find the units for the selected
- // one while we're at it.
- tabs = [];
- for (var index = 0; index < graph_list.length; ++index) {
- var graph = graph_list[index];
- tabs.push(graph.name);
- if (graph.name == params.graph)
- units = graph.units;
- }
- initPlotSwitcher(tabs);
-
- // Fetch the data for the selected graph.
- fetch_summary();
-
-}
-
-function go_to(graph) {
- params.graph = graph;
- if (params.graph == '')
- delete params.graph;
- window.location.href = MakeURL(params);
-}
-
-function get_url() {
- var new_url = encodeURI(window.location.href);
- new_url = new_url.replace(/'/g, '%27');
- new_url = new_url.replace(/\&lookout=1/, '');
- if (new_url.indexOf('http://') == 0 || new_url.indexOf('https://') == 0)
- return new_url;
- return '';
-}
-
-function on_clicked_plot(prev_entry, current_entry) {
- if ('lookout' in params) {
- window.open(get_url());
- return;
- }
-
- // Define sources for detail tabs
- if ('view-change' in Config.detailTabs) {
- // If the changeLinkPrefix has {PREV_CL}/{CL} markers, replace them.
- // Otherwise, append to the URL.
- var url = Config.changeLinkPrefix;
- if (url.indexOf('{PREV_CL}') >= 0 || url.indexOf('{CL}') >= 0) {
- url = url.replace('{PREV_CL}', prev_entry.chromium);
- url = url.replace('{CL}', current_entry.chromium);
- } else {
- url += prev_entry.chromium + ':' + current_entry.chromium;
- }
- document.getElementById('view-change').setAttribute('src', url);
- }
- if ('view-pages' in Config.detailTabs) {
- document.getElementById('view-pages').src = 'details.html?cl=' +
- current_entry.chromium + '&graph=' + params.graph + '&trace=' +
- first_trace;
- }
- if ('view-coverage' in Config.detailTabs) {
- document.getElementById('view-coverage').src =
- Config.coverageLinkPrefix + current_entry.chromium;
- }
- if (!isNaN(prev_entry.webkit) && !isNaN(current_entry.webkit) &&
- prev_entry.webkit <= current_entry.webkit) {
- Config.detailTabs['view-webkit-change'] = 'Webkit';
- document.getElementById('webkit-tab').style.display = 'inline-block';
- var url = 'http://trac.webkit.org/log/?verbose=on&rev=' +
- current_entry.webkit + '&stop_rev=' + prev_entry.webkit;
- document.getElementById('view-webkit-change').src = url;
- } else {
- var webkitView = document.getElementById('view-webkit-change');
- if (webkitView.style.display == 'block')
- show_first_view();
- delete Config.detailTabs['view-webkit-change'];
- document.getElementById('webkit-tab').style.display = 'none';
- }
-
- if (!did_position_details) {
- show_first_view();
- position_details();
- did_position_details = true;
- }
-}
-
-function show_first_view() {
- for (var tab in Config.detailTabs) {
- change_view(tab);
- break;
- }
-}
-
-function received_summary(data, error) {
- if (error) {
- report_error(error);
- return;
- }
- // Parse the summary data file.
- var rows = new Rows(data);
- var max_rows = rows.length;
- if (max_rows > params.history)
- max_rows = params.history;
-
- var allTraces = {};
-
- // Find the start and end of the data slice we will focus on.
- var start_row = 0;
- if (params.rev > 0) {
- var i = 0;
- while (i < rows.length) {
- var row = rows.get(i);
-
- // If the current row's revision is higher than the desired revision,
- // continue searching.
- if (row.revision > params.rev) {
- i++;
- continue;
- }
-
- // We're either just under or at the desired revision.
- start_row = i;
-
- // If the desired revision does not exist, use the row before it.
- if (row.revision < params.rev && start_row > 0)
- start_row -= 1;
-
- break;
- }
- }
-
- // Some summary files contain data not listed in rev-descending order. For
- // those cases, it is possible we will find a start row in the middle of the
- // data whose neighboring data is not nearby. See xp-release-dual-core
- // moz rev 265 => no graph.
- var end_row = start_row + max_rows;
-
- // Build and order a list of revision numbers.
- var revisionNumbers = [];
- var hasNumericRevisions = true;
- // graphData[rev] = {trace1:[value, stddev], trace2:[value, stddev], ...}
- var graphData = {};
- for (var i = start_row; i < end_row; ++i) {
- var row = rows.get(i);
- if (!row)
- continue;
- var traces = row['traces'];
- for (var j = 0; j < traces.length; ++j)
- traces[j] = parseFloat(traces[j]);
-
- if (!(row.revision in graphData)) {
- graphData[row.revision] = {};
- }
- graphData[row.revision][row.webkitRevision] = traces;
- if (isNaN(row.revision) || isNaN(row.webkitRevision)) {
- hasNumericRevisions = false;
- }
- revisionNumbers.push(
- { chromium: row.revision, webkit: row.webkitRevision });
-
- // Collect unique trace names. If traces are explicitly specified in
- // params, delete unspecified trace data.
- for (var traceName in traces) {
- if (typeof(params['trace']) != 'undefined' &&
- params['trace'][traceName] != 1) {
- delete(traces[traceName]);
- }
- allTraces[traceName] = 1;
- }
- }
-
- // Build a list of all the trace names we've seen, in the order in which
- // they appear in the data file. Although JS objects are not required by
- // the spec to iterate their properties in order, in practice they do,
- // because it causes compatibility problems otherwise.
- var traceNames = [];
- for (var traceName in allTraces)
- traceNames.push(traceName);
-
- first_trace = traceNames[0];
-
- // If the revisions are numeric (svn), sort them numerically to ensure they
- // are in ascending order. Otherwise, if the revisions aren't numeric (git),
- // reverse them under the assumption the rows were prepended to the file.
- if (hasNumericRevisions) {
- revisionNumbers.sort(function(a, b) {
- var revdiff = parseInt(a.chromium, 10) - parseInt(b.chromium, 10);
- if (revdiff != 0) {
- return revdiff;
- }
- return parseInt(a.webkit, 10) - parseInt(b.webkit, 10);
- });
- } else {
- revisionNumbers.reverse();
- }
-
- // Build separate ordered lists of trace data.
- var traceData = {};
- for (var revIndex = 0; revIndex < revisionNumbers.length; ++revIndex) {
- var rev = revisionNumbers[revIndex].chromium;
- var webkitrev = revisionNumbers[revIndex].webkit;
- var revisionData = graphData[rev][webkitrev];
- for (var nameIndex = 0; nameIndex < traceNames.length; ++nameIndex) {
- var traceName = traceNames[nameIndex];
- if (!traceData[traceName])
- traceData[traceName] = [];
- if (!revisionData[traceName])
- traceData[traceName].push([NaN, NaN]);
- else
- traceData[traceName].push([parseFloat(revisionData[traceName][0]),
- parseFloat(revisionData[traceName][1])]);
- }
- }
- var plotData = [];
- for (var traceName in traceData)
- plotData.push(traceData[traceName]);
- var plotter = new Plotter(revisionNumbers, plotData, traceNames, units,
- document.getElementById("output"));
- plotter.onclick = on_clicked_plot;
- plotter.plot();
-}
-
-function fetch_summary() {
- if ('graph' in params)
- file = escape(params.graph) + "-summary.dat"
- else
- file = "summary.dat"
- var baseUrl = params.baseUrl || '';
- Fetch(baseUrl + file, received_summary);
-}
-
-function fetch_graph_list() {
- var baseUrl = params.baseUrl || '';
- Fetch(baseUrl + "graphs.dat", received_graph_list);
-}
-
-function initPlotSwitcher(tabs) {
- var switcher = document.getElementById("switcher");
- for (var i = 0; i < tabs.length; i++) {
- var is_selected = tabs[i] == params.graph;
- var tab = document.createElement(is_selected ? "span" : "a");
- tab.appendChild(document.createTextNode(tabs[i] + " "));
- if (!is_selected)
- tab.addEventListener("click", goToClosure(tabs[i]), false);
- switcher.appendChild(tab);
- }
-}
-
-function goToClosure(graph) {
- return function(){go_to(graph)};
-}
-
-function position_details() {
- var views = document.getElementById("views");
- views.style.display = "block";
- var selectors = document.getElementById("selectors");
- selectors.style.display = "block";
-
- var output = document.getElementById("output");
- var views_width = output.offsetWidth - selectors.offsetWidth;
-
- views.style.height = (window.innerHeight - output.offsetHeight -
- output.offsetTop - 16) + "px";
- selectors.style.top = (views.offsetTop - selectors.offsetHeight + 1) + "px";
-}
-
-function change_view(target) {
- for (var tab in Config.detailTabs) {
- document.getElementById(tab).style.display =
- (tab == target ? "block" : "none");
- }
-}
-
-function init() {
- // We need to fill the graph list before parsing the params or fetching the
- // data, so we have a default graph in case none was specified.
- fetch_graph_list();
-}
-
-window.addEventListener("resize", position_details, false);
-window.addEventListener("load", init, false);
-</script>
-</head>
-
-
-<body>
-<div id="header_lookout" align="center">
- <font style='color: #0066FF; font-family: Arial, serif;
- font-size: 20pt; font-weight: bold;'>
- <script>
- document.write("<a target=\"_blank\" href=\"");
- document.write(get_url());
- document.write("\">");
- if ('header' in params && params.header != '') {
- document.write(escape(params.header));
- } else {
- document.write(Config.title);
- }
- document.write("</a>");
- </script>
- </font>
-</div>
-
-<div id="header_text">
-Builds generated by the <a href="http://build.chromium.org/">Chromium Buildbot</a>
-are run through <b>
-<script>
-document.write(Config.title);
-</script>
-</b>and the results of that test are charted here.
-</div>
-
-<div id="explain">
-The vertical axis is measured values, and the horizontal
-axis is the revision number for the build being tested.
-</div>
-<p></p>
-<div id="switcher">
-
-</div>
-<div id="output"></div>
-<div id="details">
- <div id="views">
- <script>
- for (var tab in Config.detailTabs) {
- document.write("<iframe id=\"" + tab + "\"></iframe>");
- }
- </script>
- <iframe id='view-webkit-change'></iframe>
- </div>
- <div id="selectors">
- <script>
- var firstTab = true;
- for (var tab in Config.detailTabs) {
- document.write("<div ");
- if (firstTab) {
- firstTab = false;
- } else {
- document.write("style=\"border-left: none\" ");
- }
- document.write("class=\"selector\" onclick=\"change_view('"
- + tab + "')\">" + Config.detailTabs[tab] + "</div>");
- }
- </script><div id="webkit-tab" class="selector"
- onclick="change_view('view-webkit-change')">Webkit</div>
- </div>
-</div>
-<pre id="log"></pre>
-<script>
-if ('lookout' in params) {
- document.getElementById("switcher").style.display = "none";
- document.getElementById("details").style.display = "none";
- document.getElementById("header_text").style.display = "none";
- document.getElementById("explain").style.display = "none";
- if ('thumbnail' in params) {
- document.getElementById("header_lookout").style.display = "none";
- }
-} else {
- document.getElementById("header_lookout").style.display = "none";
-}
-</script>
-</body>
-</html>
diff --git a/dashboard/ui/js/coordinates.js b/dashboard/ui/js/coordinates.js
deleted file mode 100644
index 7304cf1..0000000
--- a/dashboard/ui/js/coordinates.js
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * 'Understands' plot data positioning.
- * @constructor
- *
- * @param {Array} plotData data that will be displayed
- */
-function Coordinates(plotData, width, height) {
- this.plotData = plotData;
-
- if (!height)
- height = window.innerHeight - 16;
- if (!width)
- width = window.innerWidth - 16;
-
- this.widthMax = width;
- this.heightMax = Math.min(400, height - 85);
-
- this.xMinValue = -0.5;
- this.xMaxValue = (this.plotData[0].length - 1) + 0.5;
- this.processYValues_();
-}
-
-Coordinates.prototype.processYValues_ = function () {
- var merged = [];
- var mergedErr = [];
- for (var i = 0; i < this.plotData.length; i++)
- for (var j = 0; j < this.plotData[i].length; j++) {
- merged.push(parseFloat(this.plotData[i][j][0]));
- mergedErr.push(parseFloat(this.plotData[i][j][1]));
- }
- var max = Math.max.apply( Math, merged );
- var min = Math.min.apply( Math, merged );
- var maxErr = Math.max.apply( Math, mergedErr );
-
- // If we have a missing value, find the real max and min the hard way.
- if (isNaN(min)) {
- for (var i = 0; i < merged.length; ++i) {
- if (isNaN(min) || merged[i] < min)
- min = merged[i];
- if (isNaN(max) || merged[i] > max)
- max = merged[i];
- if (isNaN(maxErr) || mergedErr[i] > maxErr)
- maxErr = mergedErr[i];
- }
- }
-
- this.yMinValue = min - maxErr;
- this.yMaxValue = max + maxErr;
-};
-
-/**
- * Difference between horizontal max min values.
- */
-Coordinates.prototype.xValueRange = function() {
- return this.xMaxValue - this.xMinValue;
-};
-
-/**
- * Difference between vertical max min values.
- */
-Coordinates.prototype.yValueRange = function() {
- return this.yMaxValue - this.yMinValue
-};
-
-/**
- * Converts horizontal data value to pixel value on canvas.
- * @param {number} value horizontal data value
- */
-Coordinates.prototype.xPoints = function(value) {
- return this.widthMax * ((value - this.xMinValue) / this.xValueRange());
-};
-
-/**
- * Converts vertical data value to pixel value on canvas.
- * @param {number} value vertical data value
- */
-Coordinates.prototype.yPoints = function(value) {
- // yValueRange() can be 0. If it is, place |value| in the middle of
- // the region.
- if (this.yValueRange() == 0)
- return this.heightMax / 2;
-
- // Converts value to canvas Y position in pixels.
- return this.heightMax - this.heightMax * (value - this.yMinValue) /
- this.yValueRange();
-};
-
-/**
- * Converts X point on canvas to value it represents.
- * @param {number} position horizontal point on canvas.
- */
-Coordinates.prototype.xValue = function(position) {
- /* Converts canvas X pixels to value. */
- return position / this.widthMax * (this.xValueRange()) + this.xMinValue;
-};
-
-/**
- * Converts Y point on canvas to value it represents.
- * @param {number} position vertical point on canvas.
- */
-Coordinates.prototype.yValue = function(position) {
- /* Converts canvas Y pixels to value.
- position is point value is from top.
- */
- var position = this.heightMax - position;
- var ratio = parseFloat(this.heightMax / position);
- return this.yMinValue + this.yValueRange() / ratio;
-};
-
-/**
- * Converts canvas X pixel to data index.
- * @param {number} xPosition horizontal point on canvas
- */
-Coordinates.prototype.dataSampleIndex = function(xPosition) {
- var xValue = this.xValue(xPosition);
- var index;
- if (xValue < 0) {
- index = 0;
- } else if (xValue > this.plotData[0].length - 1) {
- index = this.plotData[0].length - 1;
- } else {
- index = xValue.toFixed(0);
- }
- return index;
-};
-
-Coordinates.prototype.log = function(val) {
- document.getElementById('log').appendChild(
- document.createTextNode(val + '\n'));
-};
diff --git a/dashboard/ui/js/graph.js b/dashboard/ui/js/graph.js
deleted file mode 100644
index f224e69..0000000
--- a/dashboard/ui/js/graph.js
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/*
- Fetch all graph data files, prepare the data, and create Plotter() to
- generate a graph.
-
- To use:
- var graph = new Graph('output_div', graphList)
- graph.setTitle('Title');
- graph.graph();
-*/
-
-function JsonToJs(data) {
- return eval('(' + data + ')');
-}
-
-/**
- * Insert element a after element b.
- */
-function AppendChild(a, b) {
- var elementA = (typeof(a) == 'object') ? a : document.getElementById(a);
- var elementB = (typeof(b) == 'object') ? b : document.getElementById(b);
- elementB.appendChild(elementA);
-}
-
-/**
- * Insert element a before element b.
- */
-function InsertBefore(a, b) {
- var elementA = (typeof(a) == 'object') ? a : document.getElementById(a);
- var elementB = (typeof(b) == 'object') ? b : document.getElementById(b);
- elementB.insertBefore(elementA);
-}
-
-
-/**
- * Graph class.
- * @constructor
- *
- * Fetch each graph in |graphList| and create Plotter(). Create Graph()
- * and call graph() to display graph.
- *
- * @param div {String|DOMElement} The container that the graph should be
- * rendered to.
- * @param graphList {Array} List of graphs to be plotted.
- * @param options {Object} Options to configure graph.
- * - width {int} Width of graph.
- * - height {int} Height of graph.
- * - history {int} Number of row to show.
- * - showDetail {Boolean} Specifies whether or not to display detail.
- * Default false.
- * - showTabs {Boolean} Specifies whether or not to show tabs.
- * Default false.
- * - enableMouseScroll {Boolean} Specifies whether or not to enable
- * mouse wheel zooming. Default false.
- * - channels {Array} Display graph by channels.
- * - orderDataByVersion {Boolean} Order plot data by version number.
- * Default false.
- *
- * Example of the graphList:
- * [
- * {"units": "ms", "important": false, "name": "SunSpider-individual",
- * "SunSpider-individual-summary.dat"},
- * ]
- */
-function Graph(div, graphList, opt_options) {
- this.graphList_ = graphList;
- this.options_ = (opt_options) ? opt_options : {};
- this.history_ = (this.options_.history) ? this.options_.history : 150;
- this.rev_ = (this.options_.rev) ? this.options_.rev : -1;
- this.channels_ = (this.options_.channels) ? this.options_.channels : [];
- this.firstTrace_ = '';
- this.rows_ = [];
- this.isDetailViewAdded_ = false;
- this.selectedGraph_ = null;
- this.plotterDiv_ = null;
- this.tabs_ = [];
- this.width = this.options_.width;
- this.height = this.options_.height;
-
- this.graphContainer = document.createElement('div');
- this.graphContainer.setAttribute(
- 'style', 'display: block; overflow: hidden; ' +
- 'margin: 5px; padding: 5px; width:' + this.width);
- AppendChild(this.graphContainer, div);
-
- this.title = document.createElement('div');
- this.title.setAttribute('style', 'text-align: center');
- AppendChild(this.title, this.graphContainer);
-}
-
-/**
- * Start fetching graph data.
- */
-Graph.prototype.graph = function() {
- this.fetchSummary_();
-
- if (this.options_.showTabs)
- this.addTabs_();
-}
-
-/**
- * Set graph title.
- */
-Graph.prototype.setTitle = function(title) {
- this.title.innerHTML = title;
-}
-
-/**
- * Display tabs for each graph.
- */
-Graph.prototype.addTabs_ = function() {
- this.tabs_ = [];
- var tabPane = document.createElement('div');
- tabPane.setAttribute('class', 'switcher');
- AppendChild(tabPane, this.graphContainer);
-
- var graphNames = []
- var inserted = {};
- for (var i = 0; i < this.graphList_.length; i++) {
- if (!inserted[this.graphList_[i].name]) {
- graphNames.push(this.graphList_[i].name);
- inserted[this.graphList_[i].name] = 1;
- }
- }
-
- var obj = this;
- for (var i = 0; i < graphNames.length; i++) {
- var name = graphNames[i];
- var tab = document.createElement('span');
- if (name != this.selectedGraph_.name) {
- tab.setAttribute('class', 'select');
- }
- tab.addEventListener(
- "click",
- (function(){
- var cur = name; return function() {obj.switchGraph_(cur)}
- })(),
- false);
- tab.appendChild(document.createTextNode(name + " "));
- AppendChild(tab, tabPane);
- this.tabs_.push(tab);
- }
-}
-
-/**
- * Fetch graph summary data files.
- */
-Graph.prototype.fetchSummary_ = function() {
- this.rows_ = [];
- if (!this.selectedGraph_) {
- this.selectedGraph_ = this.graphList_[0];
- }
- var graphFiles = [];
- this.selectedGraphList_ = [];
- for (var i = 0; i < this.graphList_.length; i++) {
- if (this.graphList_[i].name == this.selectedGraph_.name) {
- graphFiles.push(this.graphList_[i].loc);
- this.selectedGraphList_.push(this.graphList_[i]);
- }
- }
- var obj = this;
- new FetchList(graphFiles, function(data) {obj.onSummaryReceived_(data)});
-}
-
-/**
- * Call addPlot_ once all graph summary data are received.
- */
-Graph.prototype.onSummaryReceived_ = function(data) {
- // Parse the summary data file.
- for (var i = 0; i < data.length; i++) {
- if (data[i]) {
- var rows = new Rows(data[i]);
- this.rows_[i] = rows;
- }
- }
- this.addPlot_();
-}
-
-/**
- * Merge all data rows by channel and version. This is use in platform
- * comparison graph.
- *
- * Example:
- * Two rows:
- * {"traces": {"score": ["777", "0.0"]}, "rev": "9",
- * "ver": "17.1.963.19", "chan": "stable"}
- * {"traces": {"score": ["888", "0.0"]}, "rev": "10",
- * "ver": "17.1.963.19", "chan": "stable"}
- * Become:
- * {"traces": {"score_windows": ["777", "0.0"],
- * "score_linux": ["888", "0.0"]},
- * "rev": "9", "ver": "17.1.963.19", "chan": "stable"}
- *
- * @return {Array} Array of rows.
- */
-Graph.prototype.getMergedRowsByVersion_ = function() {
- var channels = {};
- for (var i = 0; i < this.channels_.length; i++)
- channels[this.channels_[i]] = 1;
- var allRows = [];
- // Combind all rows to one list.
- for (var i = 0; i < this.rows_.length; i++) {
- if (this.rows_[i]) {
- for (var j = 0; j < this.rows_[i].length; j++) {
- var row = this.rows_[i].get(j);
- if (row && row.chan in channels) {
- row.machine = this.selectedGraphList_[i].machine;
- allRows.push(row);
- }
- }
- }
- }
-
- // Sort by version number.
- allRows.sort(
- function(a, b) {
- var a_arr = a.version.split('.');
- var b_arr = b.version.split('.');
- var len = Math.min(b_arr.length, b_arr.length);
- for (var i = 0; i < len; i++) {
- if (parseInt(a_arr[i], 10) > parseInt(b_arr[i], 10))
- return 1;
- else if (parseInt(a_arr[i], 10) < parseInt(b_arr[i], 10))
- return -1;
- }
- return a_arr.length - b_arr.length;
- });
-
- // Merge all rows by version number.
- var combindedRows = [];
- var index = 0;
- while (index < allRows.length) {
- var currentRow = allRows[index];
- var traces = currentRow['traces'];
- for (var traceName in traces) {
- var traceRenamed = traceName + '_' + currentRow.machine.toLowerCase();
- traces[traceRenamed] = traces[traceName];
- delete(traces[traceName]);
- }
- while (index < allRows.length - 1 &&
- allRows[index + 1].version == currentRow.version) {
- var row = allRows[index + 1];
- var traces = row['traces'];
- for (var traceName in traces) {
- var traceRenamed = traceName + '_' + row.machine.toLowerCase();
- currentRow['traces'][traceRenamed] = traces[traceName];
- }
- index++;
- }
- combindedRows.push(currentRow);
- index++;
- }
- return combindedRows;
-}
-
-/**
- * Merge all channel data by their index in file. This is use in channel
- * comparison graph.
- *
- * @return {Array} Array of rows.
- */
-Graph.prototype.getMergedRowByIndex_ = function() {
- var rowByChannel = {};
- for (var i = 0; i < this.channels_.length; i++)
- rowByChannel[this.channels_[i]] = [];
-
- // Order by channel.
- for (var i = 0; i < this.rows_.length; i++) {
- if (this.rows_[i]) {
- for (var j = 0; j < this.rows_[i].length; j++) {
- var row = this.rows_[i].get(j);
- if (row && row.chan in rowByChannel) {
- rowByChannel[row.chan].push(row);
- }
- }
- }
- }
-
- var max = 0;
- for (var channel in rowByChannel)
- max = Math.max(rowByChannel[channel].length, max);
-
- // Merge data.
- var combindedRows = [];
- for (var i = 0; i < max; i++) {
- var currentRow = null;
- for (var channel in rowByChannel) {
- if (rowByChannel[channel].length > i) {
- var row = rowByChannel[channel][i];
- var traces = row['traces'];
- for (var traceName in traces) {
- traces[traceName + '_' + channel] = traces[traceName];
- delete(traces[traceName]);
- }
- if (!currentRow) {
- currentRow = row;
- } else {
- for (var traceName in traces)
- currentRow['traces'][traceName] = traces[traceName];
- currentRow.version += ', ' + row.version;
- }
- }
- }
- combindedRows.push(currentRow);
- }
- return combindedRows;
-}
-
-/**
- * Get rows for a specific channel.
- *
- * @return {Array} Array of rows.
- */
-Graph.prototype.getRowByChannel_ = function() {
- // Combind channel data.
- var rows = [];
- for (var i = 0; i < this.rows_.length; i++) {
- if (this.rows_[i]) {
- for (var j = 0; j < this.rows_[i].length; j++) {
- var row = this.rows_[i].get(j);
- if (row && row.chan == this.channels_[0])
- rows.push(row);
- }
- }
- }
- return rows;
-}
-
-/**
- * Prepare the data and create Plotter() to generate a graph.
- */
-Graph.prototype.addPlot_ = function() {
- var rows = [];
- if (this.options_.orderDataByVersion)
- rows = this.getMergedRowsByVersion_();
- else if (this.channels_.length > 1)
- rows = this.getMergedRowByIndex_();
- else
- rows = this.getRowByChannel_();
-
- var maxRows = rows.length;
- if (maxRows > this.history_)
- maxRows = this.history_;
-
- // Find the start and end of the data slice we will focus on.
- var startRow = 0;
- if (this.rev_ > 0) {
- var i = 0;
- while (i < rows.length) {
- var row = rows[i];
- // If the current row's revision is higher than the desired revision,
- // continue searching.
- if (row.revision > this.rev_) {
- i++;
- continue;
- }
- // We're either just under or at the desired revision.
- startRow = i;
- // If the desired revision does not exist, use the row before it.
- if (row.revision < this.rev_ && startRow > 0)
- startRow -= 1;
- break;
- }
- }
-
- // Some summary files contain data not listed in rev-descending order. For
- // those cases, it is possible we will find a start row in the middle of the
- // data whose neighboring data is not nearby. See xp-release-dual-core
- // moz rev 265 => no graph.
- var endRow = startRow + maxRows;
-
- // Build and order a list of revision numbers.
- var allTraces = {};
- var revisionNumbers = [];
- var versionMap = {};
- var hasNumericRevisions = true;
- // graphData[rev] = {trace1:[value, stddev], trace2:[value, stddev], ...}
- var graphData = {};
- for (var i = startRow; i < endRow; ++i) {
- var row = rows[i];
- if (!row)
- continue;
- var traces = row['traces'];
- for (var j = 0; j < traces.length; ++j)
- traces[j] = parseFloat(traces[j]);
-
- graphData[row.revision] = traces;
- if (isNaN(row.revision)) {
- hasNumericRevisions = false;
- }
- revisionNumbers.push(row.revision);
-
- versionMap[row.revision] = row.version;
-
- // Collect unique trace names. If traces are explicitly specified in
- // params, delete unspecified trace data.
- for (var traceName in traces) {
- if (typeof(params['trace']) != 'undefined' &&
- params['trace'][traceName] != 1) {
- delete(traces[traceName]);
- }
- allTraces[traceName] = 1;
- }
- }
-
- // Build a list of all the trace names we've seen, in the order in which
- // they appear in the data file. Although JS objects are not required by
- // the spec to iterate their properties in order, in practice they do,
- // because it causes compatibility problems otherwise.
- var traceNames = [];
- for (var traceName in allTraces)
- traceNames.push(traceName);
- this.firstTrace_ = traceNames[0];
-
- // If the revisions are numeric (svn), sort them numerically to ensure they
- // are in ascending order. Otherwise, if the revisions aren't numeric (git),
- // reverse them under the assumption the rows were prepended to the file.
- if (hasNumericRevisions) {
- revisionNumbers.sort(
- function(a, b) { return parseInt(a, 10) - parseInt(b, 10) });
- } else {
- revisionNumbers.reverse();
- }
-
- // Build separate ordered lists of trace data.
- var traceData = {};
- var versionList = [];
- for (var revIndex = 0; revIndex < revisionNumbers.length; ++revIndex) {
- var rev = revisionNumbers[revIndex];
- var revisionData = graphData[rev];
- for (var nameIndex = 0; nameIndex < traceNames.length; ++nameIndex) {
- var traceName = traceNames[nameIndex];
- if (!traceData[traceName])
- traceData[traceName] = [];
- if (!revisionData[traceName])
- traceData[traceName].push([NaN, NaN]);
- else
- traceData[traceName].push([parseFloat(revisionData[traceName][0]),
- parseFloat(revisionData[traceName][1])]);
- }
- versionList.push(versionMap[rev]);
- }
-
- var plotData = [];
- for (var traceName in traceData)
- plotData.push(traceData[traceName]);
-
- var plotterDiv = document.createElement('div');
- if (!this.plotterDiv_)
- AppendChild(plotterDiv, this.graphContainer)
- else
- this.graphContainer.replaceChild(plotterDiv, this.plotterDiv_);
- this.plotterDiv_ = plotterDiv;
-
- var plotter = new Plotter(
- versionList, plotData, traceNames, this.selectedGraph_.units,
- this.plotterDiv_, this.width, this.height);
-
- var obj = this;
- plotter.onclick = function(){obj.onPlotClicked.apply(obj, arguments)};
- plotter.enableMouseScroll = this.options_.enableMouseScroll;
- plotter.plot();
-}
-
-/**
- * Handle switching graph when tab is clicked.
- */
-Graph.prototype.switchGraph_ = function(graphName) {
- if (graphName == this.selectedGraph_.name)
- return;
-
- for (var i = 0; i < this.tabs_.length; i++) {
- var name = this.tabs_[i].innerHTML;
- if (graphName + ' ' == name) {
- this.tabs_[i].removeAttribute('class');
- } else {
- this.tabs_[i].setAttribute('class', 'select');
- }
- }
-
- for (var i = 0; i < this.graphList_.length; i++) {
- if (this.graphList_[i].name == graphName) {
- this.selectedGraph_ = this.graphList_[i];
- break;
- }
- }
-
- this.fetchSummary_();
-}
-
-/**
- * On plot clicked, display detail view.
- */
-Graph.prototype.onPlotClicked = function(prev_cl, cl) {
- if (!this.options_.showDetail)
- return;
- this.addDetailView_();
-
- var getChildByName = function(div, name) {
- var children = div.childNodes;
- for (var i = 0; i < children.length; i++)
- if (children[i].getAttribute('name') == name)
- return children[i];
- }
- // Define sources for detail tabs
- if ('view-change' in Config.detailTabs) {
- // If the changeLinkPrefix has {PREV_CL}/{CL} markers, replace them.
- // Otherwise, append to the URL.
- var url = Config.changeLinkPrefix;
- if (url.indexOf('{PREV_CL}') >= 0 || url.indexOf('{CL}') >= 0) {
- url = url.replace('{PREV_CL}', prev_cl);
- url = url.replace('{CL}', cl);
- } else {
- url += prev_cl + ':' + cl;
- }
- getChildByName(this.detailPane, 'view-change').setAttribute('src', url);
- }
-
- if ('view-pages' in Config.detailTabs) {
- getChildByName(this.detailPane, 'view-pages').
- setAttribute('src', 'details.html?cl=' + cl +
- '&graph=' + this.milestone + '-' + this.selectedGraph_.name +
- '&trace=' + this.firstTrace_);
- }
- if ('view-coverage' in Config.detailTabs) {
- getChildByName(this.detailPane, 'view-coverage').setAttribute(
- 'src',Config.coverageLinkPrefix + cl);
- }
-
- if (!this.didPositionDetail) {
- this.positionDetails_();
- this.didPositionDetail = true;
- }
-}
-
-/**
- * Display detail view.
- */
-Graph.prototype.addDetailView_ = function() {
- if (this.isDetailViewAdded_)
- return;
- this.isDetailViewAdded_ = true;
- // Add detail page.
- this.detailPane = document.createElement('div');
- AppendChild(this.detailPane, this.graphContainer);
-
- for (var tab in Config.detailTabs) {
- var detail = document.createElement('iframe');
- detail.setAttribute('class', 'detail');
- detail.setAttribute('name', tab);
- AppendChild(detail, this.detailPane);
- }
-
- this.selectorPane = document.createElement('div');
- this.selectorPane.setAttribute('class', 'selectors');
- this.selectorPane.setAttribute(
- 'style', 'display: block; 1px solid black; position: absolute;');
- AppendChild(this.selectorPane, this.graphContainer);
-
- var firstTab = true;
- for (var tab in Config.detailTabs) {
- var selector = document.createElement('div');
- selector.setAttribute('class', 'selector');
- var obj = this;
- selector.onclick = (
- function(){
- var cur = tab; return function() {obj.changeDetailTab(cur)}})();
- if (firstTab)
- firstTab = false;
- else
- selector.setAttribute('style', 'border-top: none');
- selector.innerHTML = Config.detailTabs[tab];
- AppendChild(selector, this.selectorPane);
- }
-}
-
-Graph.prototype.positionDetails_ = function() {
- var win_height = window.innerHeight;
-
- var views_width = this.graphContainer.offsetWidth -
- this.selectorPane.offsetWidth;
-
- this.detailPane.style.width = views_width + "px";
- this.detailPane.style.height = (
- win_height - this.graphContainer.offsetHeight -
- this.graphContainer.offsetTop - 30) + "px";
-
- this.selectorPane.style.left = (
- this.detailPane.offsetLeft + views_width + 1) + "px";
- this.selectorPane.style.top = this.detailPane.offsetTop + "px";
-
- // Change to the first detail tab
- for (var tab in Config.detailTabs) {
- this.changeDetailTab_(tab);
- break;
- }
-}
-
-Graph.prototype.changeDetailTab_ = function(target) {
- var detailArr = this.detailPane.getElementsByTagName('iframe');
- var i = 0;
- for (var tab in Config.detailTabs) {
- detailArr[i++].style.display = (tab == target ? 'block' : 'none');
- }
-}
-
-Graph.prototype.goTo = function(graph) {
- params.graph = graph;
- if (params.graph == '')
- delete params.graph;
- window.location.href = MakeURL(params);
-}
-
-Graph.prototype.getURL = function() {
- new_url = window.location.href;
- new_url = new_url.replace(/50/, "150");
- new_url = new_url.replace(/\&lookout=1/, "");
- return new_url;
-}
-
-
-/**
- * Encapsulates a *-summary.dat file.
- * @constructor
- */
-function Rows(data) {
- this.rows_ = (data) ? data.split('\n') : [];
- this.length = this.rows_.length;
-}
-
-/**
- * Returns the row at the given index.
- */
-Rows.prototype.get = function(i) {
- if (!this.rows_[i].length) return null;
- var row = JsonToJs(this.rows_[i]);
- row.revision = isNaN(row['rev']) ? row['rev'] : parseInt(row['rev']);
- row.version = row['ver'];
- return row;
-};
diff --git a/dashboard/ui/js/plotter.js b/dashboard/ui/js/plotter.js
deleted file mode 100644
index 21efc2d..0000000
--- a/dashboard/ui/js/plotter.js
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-// Collection of classes used to plot data in a <canvas>. Create a Plotter()
-// to generate a plot.
-
-// Vertical marker for columns.
-function Marker(color) {
- var m = document.createElement("DIV");
- m.setAttribute("class", "plot-cursor");
- m.style.backgroundColor = color;
- m.style.opacity = "0.3";
- m.style.position = "absolute";
- m.style.left = "-2px";
- m.style.top = "-2px";
- m.style.width = "0px";
- m.style.height = "0px";
- return m;
-}
-
-/**
- * Adds commas to |number|.
- *
- * Examples:
- * 1234.56 => "1,234.56"
- * "99999" => "99,999"
- *
- * @param number {string|number} The number to format.
- * @return {string} String representation of |number| with commas every
- * three places.
- */
-function addCommas(number) {
- number += ''; // Convert number to string if not already.
- var numberParts = number.split('.');
- var integralPart = numberParts[0];
- var fractionalPart = numberParts.length > 1 ? '.' + numberParts[1] : '';
- var reThreeDigits = /(\d+)(\d{3})/;
- while (reThreeDigits.test(integralPart)) {
- integralPart = integralPart.replace(reThreeDigits, '$1' + ',' + '$2');
- }
- return integralPart + fractionalPart;
-}
-
-/**
- * HorizontalMarker class
- * Create a horizontal marker at the indicated mouse location.
- * @constructor
- *
- * @param canvasRect {Object} The canvas bounds (in client coords).
- * @param clientY {Number} The vertical mouse click location that spawned
- * the marker, in the client coordinate space.
- * @param yValue {Number} The plotted value corresponding to the clientY
- * click location.
- */
-function HorizontalMarker(canvasRect, clientY, yValue) {
- // Add a horizontal line to the graph.
- var m = document.createElement("DIV");
- m.setAttribute("class", "plot-baseline");
- m.style.backgroundColor = HorizontalMarker.COLOR;
- m.style.opacity = "0.3";
- m.style.position = "absolute";
- m.style.left = canvasRect.offsetLeft;
- var h = HorizontalMarker.HEIGHT;
- m.style.top = (clientY - h/2).toFixed(0) + "px";
- m.style.width = canvasRect.offsetWidth + "px";
- m.style.height = h + "px";
- this.markerDiv_ = m;
-
- this.value = yValue;
-}
-
-HorizontalMarker.HEIGHT = 5;
-HorizontalMarker.COLOR = "rgb(0,100,100)";
-
-// Remove the horizontal line from the graph.
-HorizontalMarker.prototype.remove_ = function() {
- this.markerDiv_.parentNode.removeChild(this.markerDiv_);
-};
-
-
-/**
- * Plotter class
- * @constructor
- *
- * Draws a chart using CANVAS element. Takes array of lines to draw with
- * deviations values for each data sample.
- *
- * @param {Array} clNumbers list of clNumbers for each data sample.
- * @param {Array} plotData list of arrays that represent individual lines.
- * The line itself is an Array of value and stdd.
- * @param {Array} dataDescription list of data description for each line
- * in plotData.
- * @param {string} units name of measurement used to describe plotted data.
- *
- * Example of the plotData:
- * [
- * [line 1 data],
- * [line 2 data]
- * ].
- * Line data looks like [[point one], [point two]].
- * And individual points are [value, deviation value]
- */
-function Plotter(clNumbers, plotData, dataDescription, units, resultNode,
- width, height) {
- this.clNumbers_ = clNumbers;
- this.plotData_ = plotData;
- this.dataDescription_ = dataDescription;
- this.dataColors_ = [];
- this.dataIndexByName_ = {};
- this.resultNode_ = resultNode;
- this.units_ = units;
- this.selectedTraces_ = [];
- this.imageCache_ = null;
- this.enableMouseScroll = true;
- this.coordinates = new Coordinates(plotData, width, height);
- if (isNaN(width))
- this.width = this.coordinates.widthMax;
- else
- this.width = width;
-
- this.plotPane_ = null;
-
- // A color palette that's unambigous for normal and color-deficient viewers.
- // Values are (red, green, blue) on a scale of 255.
- // Taken from http://jfly.iam.u-tokyo.ac.jp/html/manuals/pdf/color_blind.pdf
- this.colors = [[0, 114, 178], // blue
- [230, 159, 0], // orange
- [0, 158, 115], // green
- [204, 121, 167], // purplish pink
- [86, 180, 233], // sky blue
- [213, 94, 0], // dark orange
- [0, 0, 0], // black
- [240, 228, 66] // yellow
- ];
-
- var categoryColors = {};
- var colorIndex = 0;
- for (var i = 0; i < this.dataDescription_.length; i++) {
- this.dataIndexByName_[this.dataDescription_[i]] = i;
- var category = this.dataDescription_[i].replace(/-.*/, "");
- if (this.dataDescription_[i].indexOf("ref") == -1) {
- category += "-ref";
- }
- if (!categoryColors[category]) {
- categoryColors[category] = this.makeColor(colorIndex++);
- }
- this.dataColors_[i] = categoryColors[category];
- }
-}
-
-/**
- * Does the actual plotting.
- */
-Plotter.prototype.plot = function() {
- this.canvas_elt_ = this.canvas();
- this.coordinates_div_ = this.coordinates_();
- this.ruler_div_ = this.ruler();
- // marker for the result-point that the mouse is currently over
- this.cursor_div_ = new Marker("rgb(100,80,240)");
- // marker for the result-point for which details are shown
- this.marker_div_ = new Marker("rgb(100,100,100)");
-
- this.plotPane_ = document.createElement('div');
- this.plotPane_.setAttribute('class', 'plot');
- this.plotPane_.setAttribute('style', 'position: relative');
- this.resultNode_.appendChild(this.plotPane_);
- this.plotPane_.appendChild(this.canvas_elt_);
- this.plotPane_.appendChild(this.ruler_div_);
- this.plotPane_.appendChild(this.cursor_div_);
- this.plotPane_.appendChild(this.marker_div_);
-
- this.resultNode_.appendChild(this.coordinates_div_);
- this.attachEventListeners(this.canvas_elt_);
-
- this.redraw();
-
- this.graduation_divs_ = this.graduations();
- for (var i = 0; i < this.graduation_divs_.length; i++)
- this.plotPane_.appendChild(this.graduation_divs_[i]);
-};
-
-/**
- * Redraws the canvas with selected traces highlighted.
- */
-Plotter.prototype.redraw = function() {
- var ctx = this.canvas_elt_.getContext("2d");
- var doDrawImage = this.selectedTraces_.length || this.imageCache_;
- // Drawing all lines can take a few seconds on large graphs, so use a cache.
- // After the initial render, the cache draws quickly on Firefox and Chrome.
- if (!this.imageCache_) {
- // Clear it with white: otherwise canvas will draw on top of existing data.
- ctx.clearRect(0, 0, this.canvas_elt_.width, this.canvas_elt_.height);
- // Draw all data lines.
- for (var i = 0; i < this.plotData_.length; i++)
- this.plotLine_(ctx, this.getDataColor(i), this.plotData_[i]);
- // Here we convert the canvas to an image by making a new Image with
- // src set to the canvas's Data URL.
- var imageDataURL = this.canvas_elt_.toDataURL();
- this.imageCache_ = new Image;
- this.imageCache_.src = imageDataURL;
- }
- if (doDrawImage) {
- // Clear it again so we don't draw on top of the old line.
- ctx.clearRect(0, 0, this.canvas_elt_.width, this.canvas_elt_.height);
- // If we have selections, dim the other traces by first setting low alpha.
- if (this.selectedTraces_.length)
- ctx.globalAlpha = 0.2;
- // Draw the cached image.
- ctx.drawImage(this.imageCache_, 0, 0);
- // Restore the alpha so we can draw selected lines in full opacity.
- ctx.globalAlpha = 1;
- }
- // Now draw all selected traces in order of selection.
- for (var i = 0; i < this.selectedTraces_.length; i++) {
- var index = this.selectedTraces_[i];
- this.plotLine_(ctx, this.getDataColor(index), this.plotData_[index]);
- }
-};
-
-/**
- * Sets the selected state of a given trace.
- * @param {number} trace_index
- * @return {boolean} true if the trace has been selected, false if deselected.
- */
-Plotter.prototype.toggleSelection = function(trace_index) {
- var i = this.selectedTraces_.indexOf(trace_index);
- var ret = (i == -1);
- if (ret)
- this.selectedTraces_.push(trace_index);
- else
- this.selectedTraces_.splice(i, 1);
- this.redraw();
- return ret;
-};
-
-Plotter.prototype.drawDeviationBar_ = function(context, strokeStyles, x,
- y_errLow, y_errHigh) {
- context.strokeStyle = strokeStyles;
- context.lineWidth = 1.0;
- context.beginPath();
- context.moveTo(x, y_errHigh);
- context.lineTo(x, y_errLow);
- context.closePath();
- context.stroke();
-};
-
-Plotter.prototype.plotLine_ = function(ctx, strokeStyles, data) {
- ctx.strokeStyle = strokeStyles;
- ctx.lineWidth = 2.0;
- ctx.beginPath();
- var initial = true;
- var deviationData = [];
- for (var i = 0; i < data.length; i++) {
- var x = this.coordinates.xPoints(i);
- var value = parseFloat(data[i][0]);
- var stdd = parseFloat(data[i][1]);
- var y = 0.0;
- var y_errLow = 0.0;
- var y_errHigh = 0.0;
- if (isNaN(value)) {
- // Re-set 'initial' if we're at a gap in the data.
- initial = true;
- } else {
- y = this.coordinates.yPoints(value);
- // We assume that the stdd will only be NaN (missing) when the value is.
- if (value != 0.0) {
- y_errLow = this.coordinates.yPoints(value - stdd);
- y_errHigh = this.coordinates.yPoints(value + stdd);
- }
- if (initial)
- initial = false;
- else
- ctx.lineTo(x, y);
- }
-
- ctx.moveTo(x, y);
- deviationData.push([x, y_errLow, y_errHigh]);
- }
- ctx.closePath();
- ctx.stroke();
-
- for (var i = 0; i < deviationData.length; i++) {
- this.drawDeviationBar_(ctx, strokeStyles, deviationData[i][0],
- deviationData[i][1], deviationData[i][2]);
- }
-};
-
-Plotter.prototype.attachEventListeners = function(canvas) {
- var self = this;
- if (this.enableMouseScroll) {
- canvas.parentNode.addEventListener(
- "mousewheel", function(evt) { self.onMouseScroll_(evt); }, false);
- canvas.parentNode.addEventListener(
- "DOMMouseScroll", function(evt) { self.onMouseScroll_(evt); }, false);
- }
- canvas.parentNode.addEventListener(
- "mousemove", function(evt) { self.onMouseMove_(evt); }, false);
- this.cursor_div_.addEventListener(
- "click", function(evt) { self.onMouseClick_(evt); }, false);
-};
-
-Plotter.prototype.onMouseScroll_ = function(evt) {
- // Chrome uses wheelDelta and Mozilla uses detail with opposite sign values.
- var zoom = evt.wheelDelta ? evt.wheelDelta : -evt.detail;
- zoom = zoom < 0 ? -1 : 1;
- // Zoom less if the shift key is held.
- if (evt.shiftKey)
- zoom /= 10;
-
- var obj = this.canvas_elt_;
- var offsetTop = 0;
- do {
- offsetTop += obj.offsetTop;
- } while (obj = obj.offsetParent);
- var positionY = evt.clientY + document.body.scrollTop - offsetTop;
- var yValue = this.coordinates.yValue(positionY);
- var yTopToMouse = this.coordinates.yMaxValue - (this.coordinates.yMaxValue +
- yValue) / 2;
- var yBottomToMouse = (yValue + this.coordinates.yMinValue) / 2 -
- this.coordinates.yMinValue;
-
- this.coordinates.yMinValue += yBottomToMouse * zoom;
- this.coordinates.yMaxValue -= yTopToMouse * zoom;
- this.imageCache_ = null;
- if(this.horizontal_marker_) {
- this.horizontal_marker_.remove_();
- this.horizontal_marker_ = null;
- }
- for (var i = 0; i < this.graduation_divs_.length; i++)
- this.plotPane_.removeChild(this.graduation_divs_[i]);
- this.graduation_divs_ = this.graduations();
- for (var i = 0; i < this.graduation_divs_.length; i++)
- this.plotPane_.appendChild(this.graduation_divs_[i]);
- this.redraw();
-};
-
-Plotter.prototype.updateRuler_ = function(evt) {
- var r = this.ruler_div_;
- var obj = this.canvas_elt_;
- var offsetTop = 0;
- do {
- offsetTop += obj.offsetTop;
- } while (obj = obj.offsetParent);
- r.style.left = this.canvas_elt_.offsetLeft + "px";
- r.style.top = this.canvas_elt_.offsetTop + "px";
- r.style.width = this.canvas_elt_.offsetWidth + "px";
- var h = evt.clientY + document.body.scrollTop - offsetTop;
- if (h > this.canvas_elt_.offsetHeight)
- h = this.canvas_elt_.offsetHeight;
- r.style.height = h + "px";
-};
-
-Plotter.prototype.updateCursor_ = function() {
- var c = this.cursor_div_;
- c.style.top = this.canvas_elt_.offsetTop + "px";
- c.style.height = this.canvas_elt_.offsetHeight + "px";
- var w = this.canvas_elt_.offsetWidth / this.clNumbers_.length;
- var x = (this.canvas_elt_.offsetLeft + w * this.current_index_).toFixed(0);
- c.style.left = x + "px";
- c.style.width = w + "px";
-};
-
-Plotter.prototype.chromiumCLNumber_ = function(index) {
- // CL number entries are either revisions or objects of the form
- // {chromium: revision, webkit: revision}
- return this.clNumbers_[index].chromium || this.clNumbers_[index];
-};
-
-Plotter.prototype.onMouseMove_ = function(evt) {
- var obj = this.canvas_elt_;
- var offsetTop = 0;
- var offsetLeft = 0;
- do {
- offsetTop += obj.offsetTop;
- offsetLeft += obj.offsetLeft;
- } while (obj = obj.offsetParent);
-
- var canvas = evt.currentTarget.firstChild;
- var positionX = evt.clientX + document.body.scrollLeft - offsetLeft;
- var positionY = evt.clientY + document.body.scrollTop - offsetTop;
-
- this.current_index_ = this.coordinates.dataSampleIndex(positionX);
- var yValue = this.coordinates.yValue(positionY);
-
- var html = "";
- if (!isNaN(this.chromiumCLNumber_(0)))
- html = "r";
- html += this.chromiumCLNumber_(this.current_index_);
- var webkitCLNumber = this.clNumbers_[this.current_index_].webkit;
- if (webkitCLNumber) {
- html += ", webkit ";
- if (!isNaN(webkitCLNumber))
- html += "r";
- html += webkitCLNumber;
- }
-
- html += ": " +
- addCommas(this.plotData_[0][this.current_index_][0].toFixed(2)) +
- " " + this.units_ + " +/- " +
- addCommas(this.plotData_[0][this.current_index_][1].toFixed(2)) +
- " " + addCommas(yValue.toFixed(2)) + " " + this.units_;
-
- this.coordinates_td_.innerHTML = html;
-
- // If there is a horizontal marker, also display deltas relative to it.
- if (this.horizontal_marker_) {
- var baseline = this.horizontal_marker_.value;
- var delta = yValue - baseline;
- var fraction = delta / baseline; // allow division by 0
-
- var deltaStr = (delta >= 0 ? "+" : "") + delta.toFixed(0) + " " +
- this.units_;
- var percentStr = (fraction >= 0 ? "+" : "") +
- (fraction * 100).toFixed(3) + "%";
-
- this.baseline_deltas_td_.innerHTML = deltaStr + ": " + percentStr;
- }
-
- this.updateRuler_(evt);
- this.updateCursor_();
-};
-
-Plotter.incrementNumericCLNumber = function(value) {
- if (isNaN(value))
- return value;
- return value + 1;
-};
-
-Plotter.prototype.onMouseClick_ = function(evt) {
- // Shift-click controls the horizontal reference line.
- if (evt.shiftKey) {
- if (this.horizontal_marker_) {
- this.horizontal_marker_.remove_();
- }
- var obj = this.canvas_elt_;
- var offsetTop = 0;
- do {
- offsetTop += obj.offsetTop;
- } while (obj = obj.offsetParent);
- var canvasY = evt.clientY + document.body.scrollTop - offsetTop;
- this.horizontal_marker_ = new HorizontalMarker(
- this.canvas_elt_, evt.clientY + document.body.scrollTop - offsetTop,
- this.coordinates.yValue(canvasY));
-
- // Insert before cursor node, otherwise it catches clicks.
- this.cursor_div_.parentNode.insertBefore(
- this.horizontal_marker_.markerDiv_, this.cursor_div_);
- } else {
- var index = this.current_index_;
- var m = this.marker_div_;
- var c = this.cursor_div_;
- m.style.top = c.style.top;
- m.style.left = c.style.left;
- m.style.width = c.style.width;
- m.style.height = c.style.height;
- if ("onclick" in this) {
- var this_x = this.clNumbers_[index];
- // TODO(tonyg): When the clNumber is not numeric, the range includes one
- // too many revisions on the starting side.
- var prev_x = this_x;
- if (index > 0) {
- prev_x_source = this.clNumbers_[index-1];
- if (typeof prev_x_source == 'object') {
- prev_x = {};
- for (var key in prev_x_source) {
- prev_x[key] = Plotter.incrementNumericCLNumber(prev_x_source[key]);
- }
- } else {
- prev_x = Plotter.incrementNumericCLNumber(prev_x_source);
- }
- }
- this.onclick(prev_x, this_x);
- }
- }
-};
-
-Plotter.prototype.canvas = function() {
- var canvas = document.createElement("CANVAS");
- canvas.setAttribute("class", "plot");
- canvas.setAttribute("width", this.coordinates.widthMax);
- canvas.setAttribute("height", this.coordinates.heightMax);
- canvas.plotter = this;
- return canvas;
-};
-
-Plotter.prototype.ruler = function() {
- var ruler = document.createElement("DIV");
- ruler.setAttribute("class", "plot-ruler");
- ruler.style.borderBottom = "1px dotted black";
- ruler.style.position = "absolute";
- ruler.style.left = "-2px";
- ruler.style.top = "-2px";
- ruler.style.width = "0px";
- ruler.style.height = "0px";
- return ruler;
-};
-
-Plotter.prototype.graduations = function() {
- // Don't allow a graduation in the bottom 5% of the chart
- // or the number label would overflow the chart bounds.
- var yMin = this.coordinates.yMinValue + .05 * this.coordinates.yValueRange();
- var yRange = this.coordinates.yMaxValue - yMin;
-
- // Use the largest scale that fits 3 or more graduations.
- // We allow scales of [...,500, 250, 100, 50, 25, 10,...].
- var scale = 5000000000;
- while (scale) {
- if (Math.floor(yRange / scale) > 2) break; // 5s
- scale /= 2;
- if (Math.floor(yRange / scale) > 2) break; // 2.5s
- scale /= 2.5;
- if (Math.floor(yRange / scale) > 2) break; // 1s
- scale /= 2;
- }
-
- var graduationPosition = yMin + (scale - yMin % scale);
- var graduationDivs = [];
- while (graduationPosition < this.coordinates.yMaxValue) {
- var graduation = document.createElement("DIV");
- var canvasPosition = this.coordinates.yPoints(graduationPosition);
- graduation.style.borderTop = "1px dashed rgba(0,0,0,.08)";
- graduation.style.position = "absolute";
- graduation.style.left = this.canvas_elt_.offsetLeft + "px";
- graduation.style.top = canvasPosition + this.canvas_elt_.offsetTop + "px";
- graduation.style.width =
- this.canvas_elt_.offsetWidth - 4 + "px";
- graduation.style.paddingLeft = "4px";
- graduation.style.color = "rgba(0,0,0,.4)";
- graduation.style.fontSize = "9px";
- graduation.style.paddingTop = "0";
- graduation.style.zIndex = "-1";
- graduation.innerHTML = addCommas(graduationPosition);
- graduationDivs.push(graduation);
- graduationPosition += scale;
- }
- return graduationDivs;
-};
-
-Plotter.prototype.coordinates_ = function() {
- var coordinatesDiv = document.createElement("DIV");
- var fontSize = Math.max(0.8, this.width / 400 * 0.75);
- fontSize = Math.min(1.0, fontSize);
-
- var table = document.createElement("table");
- coordinatesDiv.appendChild(table);
- table.style.cssText = "border=0; width=100%; font-size:" + fontSize + "em;";
- var tr = document.createElement("tr");
- table.appendChild(tr);
- var td = document.createElement("td");
- tr.appendChild(td);
- td.className = "legend";
- td.innerHTML = "Legend: ";
-
- for (var i = 0; i < this.dataDescription_.length; i++) {
- if (i > 0)
- td.appendChild(document.createTextNode(", "));
- var legendItem = document.createElement("a");
- td.appendChild(legendItem);
- legendItem.className = "legend_item";
- legendItem.href = "#";
- legendItem.style.cssText = "text-decoration: none; color: " +
- this.getDataColor(i);
- var obj = this;
- legendItem.onclick = (
- function(){
- var index = i;
- return function() {
- this.style.fontWeight = (obj.toggleSelection(index)) ?
- "bold" : "normal";
- return false;
- };
- })();
- legendItem.innerHTML = this.dataDescription_[i];
- }
-
- this.coordinates_td_ = document.createElement("td");
- this.coordinates_td_.innerHTML = "<i>move mouse over graph</i>";
- tr.appendChild(this.coordinates_td_);
-
- this.baseline_deltas_td_ = document.createElement("td");
- this.baseline_deltas_td_.style.color = HorizontalMarker.COLOR;
- tr.appendChild(this.baseline_deltas_td_);
-
- return coordinatesDiv;
-};
-
-Plotter.prototype.makeColor = function(i) {
- var index = i % this.colors.length;
- return "rgb(" + this.colors[index][0] + "," +
- this.colors[index][1] + "," +
- this.colors[index][2] + ")";
-};
-
-Plotter.prototype.getDataColor = function(i) {
- if (this.dataColors_[i]) {
- return this.dataColors_[i];
- } else {
- return this.makeColor(i);
- }
-};
-
-Plotter.prototype.log = function(val) {
- document.getElementById('log').appendChild(
- document.createTextNode(val + '\n'));
-};
diff --git a/dashboard/ui/pagecycler_report.html b/dashboard/ui/pagecycler_report.html
deleted file mode 100644
index 04f543d..0000000
--- a/dashboard/ui/pagecycler_report.html
+++ /dev/null
@@ -1,260 +0,0 @@
-<html>
-<head>
-<style>
-body {
- font-family: sans-serif;
-}
-div#output {
- cursor: pointer;
-}
-div#switcher {
- cursor: pointer;
-}
-div#switcher a {
- border-top: 1px solid black;
- border-left: 1px solid black;
- padding-left: 0.5em;
- padding-right: 0.5em;
-}
-canvas.plot {
- border: 1px solid black;
-}
-div.plot-coordinates {
- font-family: monospace;
-}
-iframe {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
-}
-div.selector {
- border: solid 1px black;
- cursor: pointer;
- padding-left: 0.3em;
- background-color: white;
-}
-div.selector:hover {
- background-color: rgb(200,200,250);
-}
-div.selected {
- border-left: none;
-}
-div#selectors {
- width: 80px;
- display: none;
-}
-</style>
-<script src="js/common.js"></script>
-<script src="js/plotter.js"></script>
-<script src="js/coordinates.js"></script>
-<script src="config.js"></script>
-<script>
-document.title = Config.title;
-
-var params = ParseParams();
-if (!('history' in params)) {
- params.history = 150;
- // make this option somewhat user discoverable :-/
- window.location.href = MakeURL(params);
-}
-
-var did_position_details = false;
-
-function units_for_trace() {
- if ('trace' in params && params.trace.indexOf('vm-') == 0) {
- return 'bytes'
- } else if ('trace' in params && params.trace.indexOf('io-op') == 0) {
- return 'times'
- } else if ('trace' in params && params.trace.indexOf('io-byte') == 0) {
- return 'KB'
- } else {
- return 'msec'
- }
-}
-
-function go_to(trace) {
- params.trace = trace;
- if (params.trace == '')
- delete params.trace;
- window.location.href = MakeURL(params);
-}
-
-function on_clicked_plot(cl, value, fuzz, e) {
- document.getElementById('view-change').
- setAttribute('src', Config.changeLinkPrefix + cl);
-
- document.getElementById('view-pages').
- setAttribute('src', 'details.html?cl=' + cl);
-
- if (!did_position_details) {
- position_details();
- did_position_details = true;
- }
-}
-
-function received_summary(data) {
- var dataGrid = [[],[]];
- var clNumbers = [];
- var rows = data.split('\n');
- var max_rows = rows.length;
- if (max_rows > params.history)
- max_rows = params.history
- var index = 0;
- for (var i = 0; i < max_rows; ++i) {
- // ignore ill-formatted data
- if (rows[i].match(/[\d\.]+ [\d\.]+ [\d\.]+/) == null)
- continue;
- var cols = rows[i].split(' ');
-
- clNumbers.push(cols[0])
- if (cols.length == 3) {
- dataGrid[0].push( [parseFloat(cols[1]), 0] );
- dataGrid[1].push( [parseFloat(cols[2]), 0] );
- } else {
- dataGrid[0].push( [parseFloat(cols[1]), parseFloat(cols[2])] );
- dataGrid[1].push( [parseFloat(cols[3]), 0] );
- }
-
- index++;
- }
-
-
- dataGrid[0].reverse();
- dataGrid[1].reverse();
- clNumbers.reverse();
-
- var output = document.getElementById("output");
- var plotter = new Plotter(clNumbers, dataGrid, [], units_for_trace(),
- document.getElementById("output"));
- plotter.onclick = on_clicked_plot;
- plotter.plot();
-}
-
-function fetch_summary() {
- if ('trace' in params)
- file = "summary-" + escape(params.trace) + ".dat"
- else
- file = "summary.dat"
- Fetch(file, received_summary);
-}
-
-function position_details() {
- var output = document.getElementById("output");
-
- var win_height = window.innerHeight;
-
- var details = document.getElementById("views");
-
- var views = document.getElementById("views");
- var selectors = document.getElementById("selectors");
- selectors.style.display = "block";
-
- var views_width = output.offsetWidth - selectors.offsetWidth;
-
- views.style.border = "1px solid black";
- views.style.width = views_width + "px";
- views.style.height = (win_height - output.offsetHeight - output.offsetTop - 30) + "px";
-
- selectors.style.position = "absolute";
- selectors.style.left = (views.offsetLeft + views_width + 1) + "px";
- selectors.style.top = views.offsetTop + "px";
-
- change_view("view-change");
-}
-
-function change_view(target) {
- if (target == "view-change") {
- document.getElementById("view-pages").style.display = "none";
- document.getElementById("view-change").style.display = "block";
- } else {
- document.getElementById("view-change").style.display = "none";
- document.getElementById("view-pages").style.display = "block";
- }
-}
-
-function init() {
- fetch_summary();
-}
-
-window.addEventListener("load", init, false);
-</script>
-</head>
-<body>
-<p>
-<div id="header_lookout" align="center">
- <font style='color: #0066FF; font-family: Arial, serif;font-size: 20pt; font-weight: bold;'>
- <script>document.write(Config.title);</script>
- </font>
-</div>
-<div id="header_text">
-Builds generated by the <a href="http://build.chromium.org/">BUILD TYPE</a> build
-slave are run through the
-<script>
-document.write('<a href="' + Config.sourceLink + '">' + Config.title + '</a>');
-</script>
-and the results of that test are charted here.
-</div>
-</p>
-<p style="font-size: 0.75em; font-style: italic; color: rgb(100,100,100)">
-<div id="explain">
-<script>
-if ('trace' in params && params.trace == 'vm-peak-renderer') {
- document.write(
- "The vertical axis is the peak vm usage for the renderer process, and the " +
- "horizontal axis is the change-list for the build being tested. The pink " +
- "trace shows the results for the reference build.")
-} else if ('trace' in params && params.trace == 'vm-peak-browser') {
- document.write(
- "The vertical axis is the peak vm usage for the browser process, and the " +
- "horizontal axis is the change-list for the build being tested. The pink " +
- "trace shows the results for the reference build.")
-} else if ('trace' in params && params.trace == 'io-op-browser') {
- document.write(
- "This is an experimental page to track IO performance.")
-} else if ('trace' in params && params.trace == 'io-byte-browser') {
- document.write(
- "This is an experimental page to track IO performance.")
-} else {
- document.write(
- "The vertical axis is the time in milliseconds for the build to complete the " +
- "test, and the horizontal axis is the change-list for the build being " +
- "tested. Vertical error bars correspond to standard deviation. The pink " +
- "trace shows the results for the reference build.")
-}
-</script>
-</div>
-</p>
-<div id="switcher">
- <a onclick="go_to('')">page-load-time</a>
- <a onclick="go_to('vm-peak-browser')">vm-peak-browser</a>
- <a onclick="go_to('vm-peak-renderer')">vm-peak-renderer</a>
- <a onclick="go_to('io-op-browser')">io-op-browser</a>
- <a onclick="go_to('io-byte-browser')">io-byte-browser</a>
-</div>
-<div id="output"></div>
-<div id="details">
- <div id="views">
- <iframe id="view-change"></iframe>
- <iframe id="view-pages"></iframe>
- </div>
- <div id="selectors">
- <div class="selector" onclick="change_view('view-change')">CL</div>
- <div style="border-top: none" class="selector" onclick="change_view('view-pages')">Pages</div>
- </div>
-</div>
-<pre id="log"></pre>
-
-<script>
-if ('lookout' in params) {
- switcher.style.display = "none";
- details.style.display = "none";
- header_text.style.display = "none";
- explain.style.display = "none";
- selection.style.display = "none";
-} else {
- document.getElementById("header_lookout").style.display = "none";
-}
-</script>
-</body>
-</html>
diff --git a/dashboard/ui/playback_report.html b/dashboard/ui/playback_report.html
deleted file mode 100644
index a683b00..0000000
--- a/dashboard/ui/playback_report.html
+++ /dev/null
@@ -1,341 +0,0 @@
-<html>
-<head>
-<style>
-body {
- font-family: sans-serif;
-}
-div#output {
- cursor: pointer;
-}
-div#switcher {
- cursor: pointer;
-}
-div#switcher a {
- border-top: 1px solid black;
- border-left: 1px solid black;
- padding-left: 0.5em;
- padding-right: 0.5em;
-}
-canvas.plot {
- border: 1px solid black;
-}
-div.plot-coordinates {
- font-family: monospace;
-}
-iframe {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
-}
-div.selector {
- border: solid 1px black;
- cursor: pointer;
- padding-left: 0.3em;
- background-color: white;
-}
-div.selector:hover {
- background-color: rgb(200,200,250);
-}
-div.selected {
- border-left: none;
-}
-div#selectors {
- width: 80px;
- display: none;
-}
-.latest {
- font-weight: bold;
- color: rgb(60, 0, 240);
-}
-.reference {
- font-weight: bold;
- color: rgb(110, 50, 35);
-}
-</style>
-<script src="js/common.js"></script>
-<script src="js/coordinates.js"></script>
-<script src="js/plotter.js"></script>
-<script src="config.js"></script>
-<script>
-// TODO(pjohnson): Much of this code is common to all of the performance
-// reports. It would be nice to refactor the shared code into a common place.
-
-document.title = Config.title;
-
-String.prototype.startsWith = function(s) {
- return this.indexOf(s) == 0;
-}
-
-function strcmp(a, b) {
- return a < b ? -1 : (a > b ? 1 : 0);
-}
-
-// Hard-coded default trace to show if none are specified.
-var defaultTrace = 'c:V8.OsMemoryAllocated';
-
-var params = ParseParams();
-if (!('history' in params)) {
- params.history = 150;
-}
-if (!('trace' in params)) {
- params.trace = defaultTrace;
-}
-
-function goTo(trace) {
- params.trace = trace;
- if (params.trace == '' && params.trace != '0') {
- params.trace = defaultTrace;
- }
- window.location.href = MakeURL(params);
-}
-
-function goToFromEvent(e) {
- var trace = e.target.value;
- return goTo(trace);
-}
-
-var didUpdatePositionDetails = false;
-
-function unitsForTrace() {
- if ('trace' in params) {
- if (params.trace.startsWith("t:")) {
- return 'msec';
- }
- }
- return 'thing-a-ma-bobs';
-}
-
-function timing(dict) {
- return parseFloat(dict['time']);
-}
-
-function jsonToJs(data) {
- return eval('(' + data + ')')
-}
-
-function addSelectionTabs(rows) {
- if (rows.length > 0 && rows[0].length > 0) {
- data = jsonToJs(rows[0]);
- tabs = [];
-
- for (var clNumber in data) {
- for (var testName in data[clNumber]['latest']) {
- tabs.push(testName);
- }
- }
-
- tabs.sort(sortTraces);
-
- initPlotSwitcher(tabs);
- }
-}
-
-function appendTestResult(dataRows, currentData, testType, testName) {
- if (!dataRows[testType]) {
- dataRows[testType] = [];
- }
-
- mean = parseFloat(currentData[testName]['mean']);
- stdd = parseFloat(currentData[testName]['stdd']);
- dataRows[testType].push([mean, stdd]);
-}
-
-function onSummaryReceived(data) {
- var rows = data.split('\n');
- addSelectionTabs(rows);
- var clNumbers = [];
- var dataRows = {};
-
- for (var i = 0; i < rows.length; i++) {
- if (rows[i].length < 1) {
- break;
- }
- if (i > params.history) { // limit by history
- break;
- }
-
- clData = jsonToJs(rows[i]);
-
- for (var clNumber in clData) {
- clNumbers.push(clNumber);
-
- for (var testType in clData[clNumber]) {
- var currentData = clData[clNumber][testType];
- // Specific selection that is defined in params.trace.
- if (currentData[params.trace]) {
- appendTestResult(dataRows, currentData, testType, params.trace);
- }
- }
- }
- }
-
- // Don't depend on any special for-in order.
- var keys = [];
- for (var key in dataRows) {
- keys.push(key);
- }
- keys.sort();
-
- var dataGrid = [];
- for (var i = 0; i < keys.length; i++) {
- var key = keys[i];
- dataGrid.push(dataRows[key].reverse());
- }
- clNumbers.reverse();
- var plotter = new Plotter(clNumbers, dataGrid, Config.dataDescription,
- unitsForTrace(), document.getElementById("output"));
- plotter.onclick = handlePlotClicked;
- plotter.plot();
-
- return;
-}
-
-function handlePlotClicked(cl, value, fuzz, e) {
- document.getElementById('view-change').
- setAttribute('src', Config.changeLinkPrefix + cl);
-
- if (!didUpdatePositionDetails) {
- updatePositionDetails();
- didUpdatePositionDetails = true;
- }
-}
-
-function updatePositionDetails() {
- var output = document.getElementById("output");
- var win_height = window.innerHeight;
- var details = document.getElementById("views");
- var views = document.getElementById("views");
- var selectors = document.getElementById("selectors");
- selectors.style.display = "block";
-
- var views_width = output.offsetWidth - selectors.offsetWidth;
-
- views.style.border = "1px solid black";
- views.style.width = views_width + "px";
- views.style.height = (win_height - output.offsetHeight -
- output.offsetTop - 30) + "px";
-
- selectors.style.position = "absolute";
- selectors.style.left = (views.offsetLeft + views_width + 1) + "px";
- selectors.style.top = views.offsetTop + "px";
-
- viewCl();
-}
-
-function viewCl(target) {
- document.getElementById("view-change").style.display = "block";
-}
-
-function addOption(selectBox, text, value) {
- var option = document.createElement("option");
- option.text = text;
- option.value = value;
- selectBox.add(option);
-}
-
-function initPlotSwitcher(tabs) {
- var selectBox = document.getElementById("switcher");
-
- if (selectBox.attachEvent) {
- selectBox.attachEvent("onchange", goToFromEvent);
- } else {
- selectBox.addEventListener("change", goToFromEvent, false);
- }
-
- var selectedIndex = 0;
- for (var i = 0; i < tabs.length; i++) {
- if (tabs[i] == params.trace) {
- selectedIndex = i;
- }
- addOption(selectBox, tabs[i], tabs[i]);
- }
- selectBox.selectedIndex = selectedIndex;
-
- if ('lookout' in params) {
- switcher.style.display = "none";
- details.style.display = "none";
- header_text.style.display = "none";
- explain.style.display = "none";
- selection.style.display = "none";
- } else {
- document.getElementById("header_lookout").style.display = "none";
- }
-}
-
-function log(data) {
- document.getElementById('log').appendChild(
- document.createTextNode(data + '\n'));
-}
-
-function init() {
- Fetch("summary.dat", onSummaryReceived);
-}
-
-// Used to sort by trace name, ignoring the "c:" and "t:" prefixes.
-// This allows related traces (such as a timer and a counter for the same
-// thing) to appear next to each other in the drop-down box.
-function sortTraces(a, b) {
- function getMeat(trace) {
- if (trace.startsWith("c:") || trace.startsWith("t:")) {
- trace = trace.substring(2);
- }
- return trace;
- }
-
- var aMeat = getMeat(a);
- var bMeat = getMeat(b);
- var meatCmp = strcmp(aMeat, bMeat);
-
- if (meatCmp != 0) {
- return meatCmp;
- }
- return strcmp(a, b);
-}
-
-window.addEventListener("load", init, false);
-</script>
-</head>
-<body>
-<p>
-<div id="header_lookout" align="center">
- <font style='color: #0066FF; font-family: Arial, serif;font-size: 20pt; font-weight: bold;'>
- <script>document.write(Config.title);</script>
- </font>
-</div>
-<div id="header_text">
-Builds generated by the
-<script>
-document.write('<a href="' + Config.builderLink + '">' + Config.builder + '</a>');
-</script>
-build slave are run through the
-<script>
-document.write('<b>' + Config.title + '</b>');
-</script>
-and the results of that test are charted here.
-</div>
-</p>
-<p style="font-size: 0.75em; font-style: italic; color: rgb(100,100,100)">
-<div id="explain">
-The vertical axis is the count or time and the horizontal axis is the
-change-list for the build being tested.<br /><br />
-<span class="latest">This color</span> is for the latest build, and
-<span class="reference">this color</span> is for the reference build.
-</div>
-</p>
-<select id="switcher">
-
-</select>
-<div id="output"></div>
-<div id="details">
- <div id="views">
- <iframe id="view-change"></iframe>
- <iframe id="view-pages"></iframe>
- </div>
- <div id="selectors">
- <div class="selector" onclick="viewCl()">CL</div>
- </div>
-</div>
-<pre id="log"></pre>
-</body>
-</html>
diff --git a/dashboard/ui/sunspider_report.html b/dashboard/ui/sunspider_report.html
deleted file mode 100644
index 2af203c..0000000
--- a/dashboard/ui/sunspider_report.html
+++ /dev/null
@@ -1,279 +0,0 @@
-<html>
-<head>
-<style>
-body {
- font-family: sans-serif;
-}
-div#output {
- cursor: pointer;
-}
-div#switcher {
- cursor: pointer;
-}
-div#switcher a {
- border-top: 1px solid black;
- border-left: 1px solid black;
- padding-left: 0.5em;
- padding-right: 0.5em;
-}
-canvas.plot {
- border: 1px solid black;
-}
-div.plot-coordinates {
- font-family: monospace;
-}
-iframe {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
-}
-div.selector {
- border: solid 1px black;
- cursor: pointer;
- padding-left: 0.3em;
- background-color: white;
-}
-div.selector:hover {
- background-color: rgb(200,200,250);
-}
-div.selected {
- border-left: none;
-}
-div#selectors {
- width: 80px;
- display: none;
-}
-</style>
-<script src="js/common.js"></script>
-<script src="js/coordinates.js"></script>
-<script src="js/plotter.js"></script>
-<script src="config.js"></script>
-<script>
-document.title = Config.title;
-
-var params = ParseParams();
-if (!('history' in params)) {
- params.history = 150;
- window.location.href = MakeURL(params);
-}
-if (!('trace' in params)) {
- params.trace = 'summary';
- window.location.href = MakeURL(params);
-}
-
-function goTo(trace) {
- params.trace = trace;
- if (params.trace == '' && params.trace != '0')
- params.trace = 'summary';
- window.location.href = MakeURL(params);
-}
-
-function goToClosure(trace) {
- return function(){goTo(trace)};
-}
-
-var didUpdatePositionDetails = false;
-
-function unitsForTrace() {
- return 'msec';
-}
-
-function timing(dict) {
- return parseFloat(dict['time']);
-}
-
-function deviation(absoluteValue, dict) {
- deviationPercentage = parseFloat(dict['stdd']);
- return absoluteValue / 100 * deviationPercentage;
-}
-
-function testCategoryDetails(dict) {
- return dict['details'];
-}
-
-function jsonToJs(data) {
- return eval('(' + data + ')')
-}
-
-function addSelectionTabs(rows) {
- if (rows.length > 0 && rows[0].length > 0) {
- data = jsonToJs(rows[0]);
- tabs = ['summary'];
- for (var clNumber in data)
- for (var testType in data[clNumber])
- for (test_name in testCategoryDetails(data[clNumber][testType]))
- tabs.push(test_name);
-
- initPlotSwitcher(tabs);
- }
-}
-
-function onSummaryReceived(data) {
- var rows = data.split('\n');
- addSelectionTabs(rows);
- clNumbers = [];
- dataRows = {};
-
- for(var i = 0; i < rows.length; i++) {
- if (rows[i].length < 1)
- break;
- if (i > params.history) // limit by history
- break;
-
- clData = jsonToJs(rows[i]);
-
- if (params.trace == 'summary') {
- for (var clNumber in clData) {
- clNumbers.push(clNumber)
-
- for(testType in clData[clNumber]){
- if(!dataRows[testType])
- dataRows[testType] = []
-
- time = timing(clData[clNumber][testType]);
- stdd = deviation(time, clData[clNumber][testType]);
- dataRows[testType].push([time, stdd])
- }
- }
- } else {
- // specific selection that is defined in params.trace
- for (var clNumber in clData) {
- clNumbers.push(clNumber)
- currentData = clData[clNumber]
- for(testType in currentData){
- if(!dataRows[params.trace])
- dataRows[params.trace] = []
-
- details = testCategoryDetails(currentData[testType]);
- if (details[params.trace]) {
- testData = details[params.trace];
- time = timing(testData);
- stdd = deviation(time, testData);
- dataRows[params.trace].push([time, stdd])
- break;
- }
- }
- }
- }
- }
-
- dataGrid = []
- for(key in dataRows) {
- dataGrid.push(dataRows[key].reverse())
- }
- clNumbers.reverse();
- var plotter = new Plotter(clNumbers, dataGrid, Config.dataDescription,
- unitsForTrace(), document.getElementById("output"));
- plotter.onclick = handlePlotClicked;
- plotter.plot();
-
- return;
-}
-
-function handlePlotClicked(cl, value, fuzz, e) {
- document.getElementById('view-change').
- setAttribute('src', Config.changeLinkPrefix + cl);
-
- if (!didUpdatePositionDetails) {
- updatePositionDetails();
- didUpdatePositionDetails = true;
- }
-}
-
-function updatePositionDetails() {
- var output = document.getElementById("output");
- var win_height = window.innerHeight;
- var details = document.getElementById("views");
- var views = document.getElementById("views");
- var selectors = document.getElementById("selectors");
- selectors.style.display = "block";
-
- var views_width = output.offsetWidth - selectors.offsetWidth;
-
- views.style.border = "1px solid black";
- views.style.width = views_width + "px";
- views.style.height = (win_height - output.offsetHeight -
- output.offsetTop - 30) + "px";
-
- selectors.style.position = "absolute";
- selectors.style.left = (views.offsetLeft + views_width + 1) + "px";
- selectors.style.top = views.offsetTop + "px";
-
- viewCl();
-}
-
-function viewCl(target) {
- document.getElementById("view-change").style.display = "block";
-}
-
-function initPlotSwitcher(tabs) {
- for(var i = 0; i < tabs.length; i++) {
- var anchor = document.createElement("a");
- anchor.appendChild(document.createTextNode(tabs[i]));
- anchor.addEventListener("click", goToClosure(tabs[i]), false);
- document.getElementById("switcher").appendChild(anchor);
- }
-
- if ('lookout' in params) {
- switcher.style.display = "none";
- details.style.display = "none";
- header_text.style.display = "none";
- explain.style.display = "none";
- selection.style.display = "none";
- } else {
- document.getElementById("header_lookout").style.display = "none";
- }
-}
-
-function log(data) {
- document.getElementById('log').appendChild(
- document.createTextNode(data + '\n'));
-}
-
-function init() {
- Fetch("summary.dat", onSummaryReceived);
-}
-
-window.addEventListener("load", init, false);
-</script>
-</head>
-<body>
-<p>
-<div id="header_lookout" align="center">
- <font style='color: #0066FF; font-family: Arial, serif;font-size: 20pt; font-weight: bold;'>
- <script>document.write(Config.title);</script>
- </font>
-</div>
-<div id="header_text">
-Builds generated by the <a href="http://build.chromium.org/">BUILD TYPE</a> build
-slave are run through the
-<script>
-document.write('<a href="' + Config.sourceLink + '">' + Config.title + '</a>');
-</script>
-and the results of that test are charted here.
-</div>
-</p>
-<p style="font-size: 0.75em; font-style: italic; color: rgb(100,100,100)">
-<div id="explain">
-The vertical axis is the time in milliseconds for the build to complete the
-test, and the horizontal axis is the change-list for the build being
-tested
-</div>
-</p>
-<div id="switcher">
-
-</div>
-<div id="output"></div>
-<div id="details">
- <div id="views">
- <iframe id="view-change"></iframe>
- <iframe id="view-pages"></iframe>
- </div>
- <div id="selectors">
- <div class="selector" onclick="viewCl()">CL</div>
- </div>
-</div>
-<pre id="log"></pre>
-</body>
-</html>