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(); |