| Index: chrome/browser/resources/performance_monitor/chart.js
|
| diff --git a/chrome/browser/resources/performance_monitor/chart.js b/chrome/browser/resources/performance_monitor/chart.js
|
| index 1f0f4ef3804c6d9604596d59f8089d53ab747b3a..acc2102fc6b78513515b58cf310497a1e38c95d5 100644
|
| --- a/chrome/browser/resources/performance_monitor/chart.js
|
| +++ b/chrome/browser/resources/performance_monitor/chart.js
|
| @@ -2,135 +2,172 @@
|
| * Use of this source code is governed by a BSD-style license that can be
|
| * found in the LICENSE file. */
|
|
|
| -'use strict';
|
|
|
| -/* convert to cr.define('PerformanceMonitor', function() {...
|
| - * when integrating into webui */
|
| +cr.define('performance_monitor', function() {
|
| + 'use strict';
|
|
|
| -var Installer = function() {
|
| /**
|
| * Enum for time ranges, giving a descriptive name, time span prior to |now|,
|
| * data point resolution, and time-label frequency and format for each.
|
| * @enum {{
|
| - * value: !number,
|
| - * name: !string,
|
| - * timeSpan: !number,
|
| - * resolution: !number,
|
| - * labelEvery: !number,
|
| - * format: !string
|
| + * value: number,
|
| + * name: string,
|
| + * timeSpan: number,
|
| + * resolution: number,
|
| + * labelEvery: number,
|
| + * format: string
|
| * }}
|
| * @private
|
| */
|
| var TimeRange_ = {
|
| + // Prior 12 min, resolution of 1s, at most 720 points.
|
| + // Labels at 60 point (1 min) intervals.
|
| + minutes: {value: 0, name: 'Last 12 min', timeSpan: 720 * 1000,
|
| + resolution: 1000, labelEvery: 60, format: 'MM-dd'},
|
| +
|
| + // Prior hour, resolution of 5s, at most 720 points.
|
| + // Labels at 60 point (5 min) intervals.
|
| + hour: {value: 1, name: 'Last Hour', timeSpan: 3600 * 1000,
|
| + resolution: 1000 * 5, labelEvery: 60, format: 'MM-dd'},
|
| +
|
| // Prior day, resolution of 2 min, at most 720 points.
|
| // Labels at 90 point (3 hour) intervals.
|
| - day: {value: 0, name: 'Last Day', timeSpan: 24 * 3600 * 1000,
|
| + day: {value: 2, name: 'Last Day', timeSpan: 24 * 3600 * 1000,
|
| resolution: 1000 * 60 * 2, labelEvery: 90, format: 'MM-dd'},
|
|
|
| // Prior week, resolution of 15 min -- at most 672 data points.
|
| // Labels at 96 point (daily) intervals.
|
| - week: {value: 1, name: 'Last Week', timeSpan: 7 * 24 * 3600 * 1000,
|
| + week: {value: 3, name: 'Last Week', timeSpan: 7 * 24 * 3600 * 1000,
|
| resolution: 1000 * 60 * 15, labelEvery: 96, format: 'M/d'},
|
|
|
| // Prior month (30 days), resolution of 1 hr -- at most 720 data points.
|
| // Labels at 168 point (weekly) intervals.
|
| - month: {value: 2, name: 'Last Month', timeSpan: 30 * 24 * 3600 * 1000,
|
| + month: {value: 4, name: 'Last Month', timeSpan: 30 * 24 * 3600 * 1000,
|
| resolution: 1000 * 3600, labelEvery: 168, format: 'M/d'},
|
|
|
| // Prior quarter (90 days), resolution of 3 hr -- at most 720 data points.
|
| // Labels at 112 point (fortnightly) intervals.
|
| - quarter: {value: 3, name: 'Last Quarter', timeSpan: 90 * 24 * 3600 * 1000,
|
| + quarter: {value: 5, name: 'Last Quarter', timeSpan: 90 * 24 * 3600 * 1000,
|
| resolution: 1000 * 3600 * 3, labelEvery: 112, format: 'M/yy'},
|
| };
|
|
|
| + /*
|
| + * Offset, in ms, by which to subtract to convert GMT to local time
|
| + * @type {number}
|
| + */
|
| + var timezoneOffset = new Date().getTimezoneOffset() * 60000;
|
| +
|
| /** @constructor */
|
| function PerformanceMonitor() {
|
| this.__proto__ = PerformanceMonitor.prototype;
|
| /**
|
| * All metrics have entries, but those not displayed have an empty div list.
|
| * If a div list is not empty, the associated data will be non-null, or
|
| - * null but about to be filled by webui response. Thus, any metric with
|
| - * non-empty div list but null data is awaiting a data response from the
|
| - * webui.
|
| + * null but about to be filled by webui handler response. Thus, any metric
|
| + * with non-empty div list but null data is awaiting a data response
|
| + * from the webui handler. The webui handler uses numbers to uniquely
|
| + * identify metric and event types, so we use the same numbers (in
|
| + * string form) for the map key, repeating the id number in the |id|
|
| + * field, as a number.
|
| * @type {Object.<string, {
|
| + * id: number,
|
| + * description: string,
|
| + * units: string,
|
| + * yAxis: !{max: number, color: string},
|
| * divs: !Array.<HTMLDivElement>,
|
| - * yAxis: !{max: !number, color: !string},
|
| - * data: ?Array.<{time: !number, value: !number}>,
|
| - * description: !string,
|
| - * units: !string
|
| + * data: ?Array.<{time: number, value: number}>
|
| * }>}
|
| * @private
|
| */
|
| - this.metricMap_ = {
|
| - jankiness: {
|
| - divs: [],
|
| - yAxis: {max: 100, color: 'rgb(255, 128, 128)'},
|
| - data: null,
|
| - description: 'Jankiness',
|
| - units: 'milliJanks'
|
| - },
|
| - oddness: {
|
| - divs: [],
|
| - yAxis: {max: 20, color: 'rgb(0, 192, 0)'},
|
| - data: null,
|
| - description: 'Oddness',
|
| - units: 'kOdds'
|
| - }
|
| - };
|
| + this.metricMap_ = {};
|
|
|
| /*
|
| * Similar data for events, though no yAxis info is needed since events
|
| * are simply labelled markers at X locations. Rules regarding null data
|
| * with non-empty div list apply here as for metricMap_ above.
|
| - * @type {Object.<string, {
|
| + * @type {Object.<number, {
|
| + * id: number,
|
| + * description: string,
|
| + * color: string,
|
| * divs: !Array.<HTMLDivElement>,
|
| - * description: !string,
|
| - * color: !string,
|
| - * data: ?Array.<{time: !number, longDescription: !string}>
|
| + * data: ?Array.<{time: number, longDescription: string}>
|
| * }>}
|
| * @private
|
| */
|
| - this.eventMap_ = {
|
| - wampusAttacks: {
|
| - divs: [],
|
| - description: 'Wampus Attack',
|
| - color: 'rgb(0, 0, 255)',
|
| - data: null
|
| - },
|
| - solarEclipses: {
|
| - divs: [],
|
| - description: 'Solar Eclipse',
|
| - color: 'rgb(255, 0, 255)',
|
| - data: null
|
| - }
|
| - };
|
| + this.eventMap_ = {};
|
|
|
| /**
|
| - * Time periods in which the browser was active and collecting metrics.
|
| + * Time periods in which the browser was active and collecting metrics
|
| * and events.
|
| - * @type {!Array.<{start: !number, end: !number}>}
|
| + * @type {!Array.<{start: number, end: number}>}
|
| * @private
|
| */
|
| this.intervals_ = [];
|
|
|
| - this.setupCheckboxes_(
|
| - '#chooseMetrics', this.metricMap_, this.addMetric, this.dropMetric);
|
| - this.setupCheckboxes_(
|
| - '#chooseEvents', this.eventMap_, this.addEventType, this.dropEventType);
|
| this.setupTimeRangeChooser_();
|
| + chrome.send('getAllEventTypes');
|
| + chrome.send('getAllMetricTypes');
|
| this.setupMainChart_();
|
| - TimeRange_.day.element.click().call(this);
|
| + TimeRange_.day.element.click();
|
| }
|
|
|
| PerformanceMonitor.prototype = {
|
| /**
|
| - * Set up the radio button set to choose time range. Use div#radioTemplate
|
| + * Receive a list of all metrics, and populate |this.metricMap_| to
|
| + * reflect said list. Reconfigure the checkbox set for metric selection.
|
| + * @param {Array.<{metricType: string, shortDescription: string}>}
|
| + * allMetrics All metrics from which to select.
|
| + */
|
| + getAllMetricTypesCallback: function(allMetrics) {
|
| + for (var i = 0; i < allMetrics.length; i++) {
|
| + var metric = allMetrics[i];
|
| +
|
| + this.metricMap_[metric.metricType] = {
|
| + id: metric.metricType,
|
| + description: metric.shortDescription,
|
| + units: metric.units,
|
| + yAxis: {min: 0, max: metric.maxValue,
|
| + color: jQuery.color.parse('blue')},
|
| + divs: [],
|
| + data: null
|
| + };
|
| + }
|
| +
|
| + this.setupCheckboxes_($('#choose-metrics')[0],
|
| + this.metricMap_, this.addMetric, this.dropMetric);
|
| + },
|
| +
|
| + /**
|
| + * Receive a list of all event types, and populate |this.eventMap_| to
|
| + * reflect said list. Reconfigure the checkbox set for event selection.
|
| + * @param {Array.<{eventType: string, shortDescription: string}>}
|
| + * allEvents All events from which to select.
|
| + */
|
| + getAllEventTypesCallback: function(allEvents) {
|
| + for (var i = 0; i < allEvents.length; i++) {
|
| + var eventInfo = allEvents[i];
|
| +
|
| + this.eventMap_[eventInfo.eventType] = {
|
| + id: eventInfo.eventType,
|
| + color: jQuery.color.parse('red'),
|
| + data: null,
|
| + description: eventInfo.shortDescription,
|
| + divs: []
|
| + };
|
| + }
|
| +
|
| + this.setupCheckboxes_($('#choose-events')[0],
|
| + this.eventMap_, this.addEventType, this.dropEventType);
|
| + },
|
| +
|
| + /**
|
| + * Set up the radio button set to choose time range. Use div#radio-template
|
| * as a template.
|
| * @private
|
| */
|
| setupTimeRangeChooser_: function() {
|
| - var timeDiv = $('#chooseTimeRange')[0];
|
| - var radioTemplate = $('#radioTemplate')[0];
|
| + var timeDiv = $('#choose-time-range')[0];
|
| + var radioTemplate = $('#radio-template')[0];
|
|
|
| for (var time in TimeRange_) {
|
| var timeRange = TimeRange_[time];
|
| @@ -154,37 +191,33 @@ var Installer = function() {
|
|
|
| /**
|
| * Generalized function for setting up checkbox blocks for either events
|
| - * or metrics. Take a div ID |divId| into which to place the checkboxes,
|
| + * or metrics. Take a div |div| into which to place the checkboxes,
|
| * and a map |optionMap| with values that each include a property
|
| * |description|. Set up one checkbox for each entry in |optionMap|
|
| * labelled with that description. Arrange callbacks to function |check|
|
| * or |uncheck|, passing them the key of the checked or unchecked option,
|
| * when the relevant checkbox state changes.
|
| - * @param {!string} divId Id of division into which to put checkboxes
|
| - * @param {!Object} optionMap map of metric/event entries
|
| + * @param {!HTMLDivElement} div A <div> into which to put checkboxes.
|
| + * @param {!Object} optionMap A map of metric/event entries.
|
| * @param {!function(this:Controller, Object)} check
|
| - * function to select an entry (metric or event)
|
| + * The function to select an entry (metric or event).
|
| * @param {!function(this:Controller, Object)} uncheck
|
| - * function to deselect an entry (metric or event)
|
| + * The function to deselect an entry (metric or event).
|
| * @private
|
| */
|
| - setupCheckboxes_: function(divId, optionMap, check, uncheck) {
|
| - var checkboxTemplate = $('#checkboxTemplate')[0];
|
| - var chooseMetricsDiv = $(divId)[0];
|
| + setupCheckboxes_: function(div, optionMap, check, uncheck) {
|
| + var checkboxTemplate = $('#checkbox-template')[0];
|
|
|
| for (var option in optionMap) {
|
| var checkbox = checkboxTemplate.cloneNode(true);
|
| checkbox.querySelector('span').innerText = 'Show ' +
|
| optionMap[option].description;
|
| - chooseMetricsDiv.appendChild(checkbox);
|
| + div.appendChild(checkbox);
|
|
|
| var input = checkbox.querySelector('input');
|
| - input.option = option;
|
| + input.option = optionMap[option].id;
|
| input.addEventListener('change', function(e) {
|
| - if (e.target.checked)
|
| - check.call(this, e.target.option);
|
| - else
|
| - uncheck.call(this, e.target.option);
|
| + (e.target.checked ? check : uncheck).call(this, e.target.option);
|
| }.bind(this));
|
| }
|
| },
|
| @@ -206,52 +239,33 @@ var Installer = function() {
|
| * Set the time range for which to display metrics and events. For
|
| * now, the time range always ends at "now", but future implementations
|
| * may allow time ranges not so anchored.
|
| - * @param {!{start: !number, end: !number, resolution: !number}} range
|
| + * @param {!{start: number, end: number, resolution: number}} range
|
| + * The time range for which to get display data.
|
| */
|
| setTimeRange: function(range) {
|
| this.range = range;
|
| this.end = Math.floor(Date.now() / range.resolution) *
|
| range.resolution;
|
|
|
| - // Take the GMT value of this.end ("now") and subtract from it the
|
| - // number of minutes by which we lag GMT in the present timezone,
|
| - // X mS/minute. This will show time in the present timezone.
|
| - this.end -= new Date().getTimezoneOffset() * 60000;
|
| this.start = this.end - range.timeSpan;
|
| this.requestIntervals();
|
| },
|
|
|
| /**
|
| - * Return mock interval set for testing.
|
| - * @return {!Array.<{start: !number, end: !number}>} intervals
|
| - */
|
| - getMockIntervals: function() {
|
| - var interval = this.end - this.start;
|
| -
|
| - return [
|
| - {start: this.start + interval * .1,
|
| - end: this.start + interval * .2},
|
| - {start: this.start + interval * .7,
|
| - end: this.start + interval}
|
| - ];
|
| - },
|
| -
|
| - /**
|
| * Request activity intervals in the current time range.
|
| */
|
| requestIntervals: function() {
|
| - this.onReceiveIntervals(this.getMockIntervals());
|
| - // Replace with: chrome.send('getIntervals', this.start, this.end,
|
| - // this.onReceiveIntervals);
|
| + chrome.send('getActiveIntervals', [this.start, this.end]);
|
| },
|
|
|
| /**
|
| * Webui callback delivering response from requestIntervals call. Assumes
|
| * this is a new time range choice, which results in complete refresh of
|
| * all metrics and event types that are currently selected.
|
| - * @param {!Array.<{start: !number, end: !number}>} intervals new intervals
|
| + * @param {!Array.<{start: number, end: number}>} intervals
|
| + * The new intervals.
|
| */
|
| - onReceiveIntervals: function(intervals) {
|
| + getActiveIntervalsCallback: function(intervals) {
|
| this.intervals_ = intervals;
|
|
|
| for (var metric in this.metricMap_) {
|
| @@ -263,13 +277,13 @@ var Installer = function() {
|
| for (var eventType in this.eventMap_) {
|
| var eventValue = this.eventMap_[eventType];
|
| if (eventValue.divs.length > 0)
|
| - this.refreshEventType(eventType);
|
| + this.refreshEventType(eventValue.id);
|
| }
|
| },
|
|
|
| /**
|
| * Add a new metric to the main (currently only) chart.
|
| - * @param {!string} metric Metric to start displaying
|
| + * @param {string} metric The metric to start displaying.
|
| */
|
| addMetric: function(metric) {
|
| this.metricMap_[metric].divs.push(this.charts[0]);
|
| @@ -278,7 +292,7 @@ var Installer = function() {
|
|
|
| /**
|
| * Remove a metric from the chart(s).
|
| - * @param {!string} metric Metric to stop displaying
|
| + * @param {string} metric The metric to stop displaying.
|
| */
|
| dropMetric: function(metric) {
|
| var metricValue = this.metricMap_[metric];
|
| @@ -289,61 +303,35 @@ var Installer = function() {
|
| },
|
|
|
| /**
|
| - * Return mock metric data points for testing. Give values ranging from
|
| - * offset to max-offset. (This lets us avoid direct overlap of
|
| - * different mock data sets in an ugly way that will die in the next
|
| - * version anyway.)
|
| - * @param {!number} max Max data value to return, less offset
|
| - * @param {!number} offset Adjustment factor
|
| - * @return {!Array.<{time: !number, value: !number}>}
|
| - */
|
| - getMockDataPoints: function(max, offset) {
|
| - var dataPoints = [];
|
| -
|
| - for (var i = 0; i < this.intervals_.length; i++) {
|
| - // Rise from low offset to high max-offset in 100 point steps.
|
| - for (var time = this.intervals_[i].start;
|
| - time <= this.intervals_[i].end; time += this.range.resolution) {
|
| - var numPoints = time / this.range.resolution;
|
| - dataPoints.push({time: time, value: offset + (numPoints % 100) *
|
| - (max - 2 * offset) / 100});
|
| - }
|
| - }
|
| - return dataPoints;
|
| - },
|
| -
|
| - /**
|
| * Request new metric data, assuming the metric table and chart already
|
| * exist.
|
| - * @param {!string} metric Metric for which to get data
|
| + * @param {string} metric The metric for which to get data.
|
| */
|
| refreshMetric: function(metric) {
|
| var metricValue = this.metricMap_[metric];
|
|
|
| metricValue.data = null; // Mark metric as awaiting response.
|
| - this.onReceiveMetric(metric,
|
| - this.getMockDataPoints(metricValue.yAxis.max, 5));
|
| - // Replace with:
|
| - // chrome.send("getMetric", this.range.start, this.range.end,
|
| - // this.range.resolution, this.onReceiveMetric);
|
| + chrome.send('getMetric', [metricValue.id,
|
| + this.start, this.end, this.range.resolution]);
|
| },
|
|
|
| /**
|
| - * Receive new datapoints for |metric|, convert the data to Flot-usable
|
| + * Receive new datapoints for a metric, convert the data to Flot-usable
|
| * form, and redraw all affected charts.
|
| - * @param {!string} metric Metric to which |points| applies
|
| - * @param {!Array.<{time: !number, value: !number}>} points
|
| - * new data points
|
| + * @param {!{
|
| + * type: number,
|
| + * points: !Array.<{time: number, value: number}>
|
| + * }} result An object giving metric ID, and time/value point pairs for
|
| + * that id.
|
| */
|
| - onReceiveMetric: function(metric, points) {
|
| - var metricValue = this.metricMap_[metric];
|
| -
|
| + getMetricCallback: function(result) {
|
| + var metricValue = this.metricMap_[result.metricType];
|
| // Might have been dropped while waiting for data.
|
| if (metricValue.divs.length == 0)
|
| return;
|
|
|
| var series = [];
|
| - metricValue.data = [series];
|
| + metricValue.data = [series]; // Data ends with current open series.
|
|
|
| // Traverse the points, and the intervals, in parallel. Both are in
|
| // ascending time order. Create a sequence of data "series" (per Flot)
|
| @@ -351,28 +339,28 @@ var Installer = function() {
|
| var interval = this.intervals_[0];
|
| var intervalIndex = 0;
|
| var pointIndex = 0;
|
| - while (pointIndex < points.length &&
|
| + while (pointIndex < result.points.length &&
|
| intervalIndex < this.intervals_.length) {
|
| - var point = points[pointIndex++];
|
| + var point = result.points[pointIndex++];
|
| while (intervalIndex < this.intervals_.length &&
|
| point.time > interval.end) {
|
| - interval = this.intervals_[++intervalIndex]; // Jump to new interval.
|
| + interval = this.intervals_[++intervalIndex]; // Jump to new interval.
|
| if (series.length > 0) {
|
| - series = []; // Start a new series.
|
| - metricValue.data.push(series); // Put it on the end of the data.
|
| + series = []; // Start a new series.
|
| + metricValue.data.push(series); // Put it on the end of the data.
|
| }
|
| }
|
| if (intervalIndex < this.intervals_.length &&
|
| - point.time > interval.start)
|
| - series.push([point.time, point.value]);
|
| + point.time > interval.start) {
|
| + series.push([point.time - timezoneOffset, point.value]);
|
| + }
|
| }
|
| -
|
| metricValue.divs.forEach(this.drawChart, this);
|
| },
|
|
|
| /**
|
| * Add a new event to the chart(s).
|
| - * @param {!string} eventType type of event to start displaying
|
| + * @param {string} eventType The type of event to start displaying.
|
| */
|
| addEventType: function(eventType) {
|
| // Events show on all charts.
|
| @@ -382,7 +370,7 @@ var Installer = function() {
|
|
|
| /*
|
| * Remove an event from the chart(s).
|
| - * @param {!string} eventType type of event to stop displaying
|
| + * @param {string} eventType The type of event to stop displaying.
|
| */
|
| dropEventType: function(eventType) {
|
| var eventValue = this.eventMap_[eventType];
|
| @@ -393,66 +381,45 @@ var Installer = function() {
|
| },
|
|
|
| /**
|
| - * Return mock event points for testing.
|
| - * @param {!string} eventType type of event to generate mock data for
|
| - * @return {!Array.<{time: !number, longDescription: !string}>}
|
| - */
|
| - getMockEventValues: function(eventType) {
|
| - var mockValues = [];
|
| - for (var i = 0; i < this.intervals_.length; i++) {
|
| - var interval = this.intervals_[i];
|
| -
|
| - mockValues.push({
|
| - time: interval.start,
|
| - longDescription: eventType + ' at ' +
|
| - new Date(interval.start) + ' blah, blah blah'});
|
| - mockValues.push({
|
| - time: (interval.start + interval.end) / 2,
|
| - longDescription: eventType + ' at ' +
|
| - new Date((interval.start + interval.end) / 2) + ' blah, blah'});
|
| - mockValues.push({
|
| - time: interval.end,
|
| - longDescription: eventType + ' at ' + new Date(interval.end) +
|
| - ' blah, blah blah'});
|
| - }
|
| - return mockValues;
|
| - },
|
| -
|
| - /**
|
| * Request new data for |eventType|, for times in the current range.
|
| - * @param {!string} eventType type of event to get new data for
|
| + * @param {string} eventType The type of event to get new data for.
|
| */
|
| refreshEventType: function(eventType) {
|
| // Mark eventType as awaiting response.
|
| this.eventMap_[eventType].data = null;
|
| - this.onReceiveEventType(eventType, this.getMockEventValues(eventType));
|
| - // Replace with:
|
| - // chrome.send("getEvents", eventType, this.range.start, this.range.end);
|
| +
|
| + chrome.send('getEvents', [eventType, this.start, this.end]);
|
| },
|
|
|
| /**
|
| - * Receive new data for |eventType|. If the event has been deselected while
|
| - * awaiting webui response, do nothing. Otherwise, save the data directly,
|
| - * since events are handled differently than metrics when drawing
|
| - * (no "series"), and redraw all the affected charts.
|
| - * @param {!string} eventType type of event the new data applies to
|
| - * @param {!Array.<{time: !number, longDescription: !string}>} values
|
| - * new event values
|
| + * Receive new events for |eventType|. If |eventType| has been deselected
|
| + * while awaiting webui handler response, do nothing. Otherwise, save the
|
| + * data directly, since events are handled differently than metrics
|
| + * when drawing (no "series"), and redraw all the affected charts.
|
| + * @param {!{
|
| + * type: number,
|
| + * points: !Array.<{time: number, longDescription: string}>
|
| + * }} result An object giving eventType ID, and time/description pairs for
|
| + * each event of that type in the range requested.
|
| */
|
| - onReceiveEventType: function(eventType, values) {
|
| - var eventValue = this.eventMap_[eventType];
|
| + getEventsCallback: function(result) {
|
| + var eventValue = this.eventMap_[result.eventType];
|
|
|
| if (eventValue.divs.length == 0)
|
| return;
|
|
|
| - eventValue.data = values;
|
| + result.points.forEach(function(element) {
|
| + element.time -= timezoneOffset;
|
| + });
|
| +
|
| + eventValue.data = result.points;
|
| eventValue.divs.forEach(this.drawChart, this);
|
| },
|
|
|
| /**
|
| * Return an object containing an array of metrics and another of events
|
| * that include |chart| as one of the divs into which they display.
|
| - * @param {HTMLDivElement} chart div for which to get relevant items
|
| + * @param {HTMLDivElement} chart The <div> for which to get relevant items.
|
| * @return {!{metrics: !Array,<Object>, events: !Array.<Object>}}
|
| * @private
|
| */
|
| @@ -480,10 +447,11 @@ var Installer = function() {
|
| /**
|
| * Check all entries in an object of the type returned from getChartData,
|
| * above, to see if all events and metrics have completed data (none is
|
| - * awaiting an asynchronous webui response to get their current data).
|
| + * awaiting an asynchronous webui handler response to get their current
|
| + * data).
|
| * @param {!{metrics: !Array,<Object>, events: !Array.<Object>}} chartData
|
| - * event/metric data to check for readiness
|
| - * @return {boolean} is data ready?
|
| + * The event/metric data to check for readiness.
|
| + * @return {boolean} Whether data is ready.
|
| * @private
|
| */
|
| isDataReady_: function(chartData) {
|
| @@ -506,15 +474,15 @@ var Installer = function() {
|
| * (not per Flot) a |description| property to each, to be used for hand
|
| * creating description boxes.
|
| * @param {!Array.<{
|
| - * description: !string,
|
| - * color: !string,
|
| - * data: !Array.<{time: !number}>
|
| - * }>} eventValues events to make markings for
|
| + * description: string,
|
| + * color: string,
|
| + * data: !Array.<{time: number}>
|
| + * }>} eventValues The events to make markings for.
|
| * @return {!Array.<{
|
| - * color: !string,
|
| - * description: !string,
|
| - * xaxis: {from: !number, to: !number}
|
| - * }>} mark data structure for Flot to use
|
| + * color: string,
|
| + * description: string,
|
| + * xaxis: {from: number, to: number}
|
| + * }>} A marks data structure for Flot to use.
|
| * @private
|
| */
|
| getEventMarks_: function(eventValues) {
|
| @@ -524,11 +492,17 @@ var Installer = function() {
|
| var eventValue = eventValues[i];
|
| for (var d = 0; d < eventValue.data.length; d++) {
|
| var point = eventValue.data[d];
|
| - markings.push({
|
| - color: eventValue.color,
|
| - description: eventValue.description,
|
| - xaxis: {from: point.time, to: point.time}
|
| - });
|
| + if (point.time >= this.start - timezoneOffset &&
|
| + point.time <= this.end - timezoneOffset) {
|
| + markings.push({
|
| + color: eventValue.color,
|
| + description: eventValue.description,
|
| + xaxis: {from: point.time, to: point.time}
|
| + });
|
| + } else {
|
| + console.log('Event out of time range ' + this.start + ' -> ' +
|
| + this.end + ' at: ' + point.time);
|
| + }
|
| }
|
| }
|
|
|
| @@ -539,7 +513,7 @@ var Installer = function() {
|
| * Redraw the chart in div |chart|, *if* all its dependent data is present.
|
| * Otherwise simply return, and await another call when all data is
|
| * available.
|
| - * @param {HTMLDivElement} chart div to redraw
|
| + * @param {HTMLDivElement} chart The <div> to redraw.
|
| */
|
| drawChart: function(chart) {
|
| var chartData = this.getChartData_(chart);
|
| @@ -561,19 +535,29 @@ var Installer = function() {
|
| }
|
| });
|
|
|
| + // Ensure at least one y axis, as a reference for event placement.
|
| + if (yAxes.length == 0)
|
| + yAxes.push({max: 1.0});
|
| +
|
| var markings = this.getEventMarks_(chartData.events);
|
| var chart = this.charts[0];
|
| var plot = $.plot(chart, seriesSeq, {
|
| yaxes: yAxes,
|
| - xaxis: {mode: 'time'},
|
| + xaxis: {
|
| + mode: 'time',
|
| + min: this.start - timezoneOffset,
|
| + max: this.end - timezoneOffset
|
| + },
|
| + points: {show: true, radius: 1},
|
| + lines: {show: true},
|
| grid: {markings: markings}
|
| });
|
|
|
| // For each event in |markings|, create also a label div, with left
|
| - // edge colinear with the event vertical-line. Top of label is
|
| + // edge colinear with the event vertical line. Top of label is
|
| // presently a hack-in, putting labels in three tiers of 25px height
|
| // each to avoid overlap. Will need something better.
|
| - var labelTemplate = $('#labelTemplate')[0];
|
| + var labelTemplate = $('#label-template')[0];
|
| for (var i = 0; i < markings.length; i++) {
|
| var mark = markings[i];
|
| var point =
|
| @@ -582,6 +566,7 @@ var Installer = function() {
|
| labelDiv.innerText = mark.description;
|
| labelDiv.style.left = point.left + 'px';
|
| labelDiv.style.top = (point.top + 25 * (i % 3)) + 'px';
|
| +
|
| chart.appendChild(labelDiv);
|
| }
|
| }
|
| @@ -589,6 +574,6 @@ var Installer = function() {
|
| return {
|
| PerformanceMonitor: PerformanceMonitor
|
| };
|
| -}();
|
| +});
|
|
|
| -var performanceMonitor = new Installer.PerformanceMonitor();
|
| +var PerformanceMonitor = new performance_monitor.PerformanceMonitor();
|
|
|