Commit eaa4feb3 authored by pfeldman@chromium.org's avatar pfeldman@chromium.org

DevTools: merge MemoryStatistics.js and CountersGraph.js, extract DOMCountersGraph.js

Review URL: https://codereview.chromium.org/210053002

git-svn-id: svn://svn.chromium.org/blink/trunk@169857 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 2d0fb0f4
......@@ -50,7 +50,6 @@
'front_end/CookieItemsView.js',
'front_end/CookieParser.js',
'front_end/CookiesTable.js',
'front_end/CountersGraph.js',
'front_end/CPUProfilerModel.js',
'front_end/CSSMetadata.js',
'front_end/CSSParser.js',
......@@ -308,7 +307,8 @@
'front_end/ThreadsToolbar.js',
],
'devtools_timeline_js_files': [
'front_end/MemoryStatistics.js',
'front_end/CountersGraph.js',
'front_end/DOMCountersGraph.js',
'front_end/PieChart.js',
'front_end/TimelineFrameModel.js',
'front_end/TimelineModel.js',
......
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
......@@ -30,123 +30,240 @@
/**
* @constructor
* @extends {WebInspector.MemoryStatistics}
* @implements {WebInspector.TimelineModeView}
* @extends {WebInspector.SplitView}
* @param {!WebInspector.TimelineModeViewDelegate} delegate
* @param {!WebInspector.TimelineModel} model
*/
WebInspector.CountersGraph = function(delegate, model)
{
WebInspector.MemoryStatistics.call(this, delegate, model);
}
WebInspector.SplitView.call(this, true, false);
/**
* @constructor
* @extends {WebInspector.CounterUIBase}
* @param {!WebInspector.CountersGraph} memoryCountersPane
* @param {string} title
* @param {string} currentValueLabel
* @param {!string} color
* @param {!WebInspector.MemoryStatistics.Counter} counter
*/
WebInspector.CounterUI = function(memoryCountersPane, title, currentValueLabel, color, counter)
{
WebInspector.CounterUIBase.call(this, memoryCountersPane, title, color, counter)
this._range = this._swatch.element.createChild("span");
this.element.id = "memory-graphs-container";
this._value = memoryCountersPane._currentValuesBar.createChild("span", "memory-counter-value");
this._value.style.color = color;
this._currentValueLabel = currentValueLabel;
this._marker = memoryCountersPane._canvasContainer.createChild("div", "memory-counter-marker");
this._marker.style.backgroundColor = color;
this.clearCurrentValueAndMarker();
this._delegate = delegate;
this._model = model;
this._calculator = new WebInspector.TimelineCalculator(this._model);
this.graphColor = color;
this.graphYValues = [];
this._graphsContainer = this.mainElement();
this._createCurrentValuesBar();
this._canvasView = new WebInspector.VBoxWithResizeCallback(this._resize.bind(this));
this._canvasView.show(this._graphsContainer);
this._canvasContainer = this._canvasView.element;
this._canvasContainer.id = "memory-graphs-canvas-container";
this._canvas = this._canvasContainer.createChild("canvas");
this._canvas.id = "memory-counters-graph";
this._canvasContainer.addEventListener("mouseover", this._onMouseMove.bind(this), true);
this._canvasContainer.addEventListener("mousemove", this._onMouseMove.bind(this), true);
this._canvasContainer.addEventListener("mouseout", this._onMouseOut.bind(this), true);
this._canvasContainer.addEventListener("click", this._onClick.bind(this), true);
// We create extra timeline grid here to reuse its event dividers.
this._timelineGrid = new WebInspector.TimelineGrid();
this._canvasContainer.appendChild(this._timelineGrid.dividersElement);
// Populate sidebar
this.sidebarElement().createChild("div", "sidebar-tree sidebar-tree-section").textContent = WebInspector.UIString("COUNTERS");
this._counters = [];
this._counterUI = [];
}
WebInspector.CounterUI.prototype = {
reset: function()
WebInspector.CountersGraph.prototype = {
_createCurrentValuesBar: function()
{
this._range.textContent = "";
this._currentValuesBar = this._graphsContainer.createChild("div");
this._currentValuesBar.id = "counter-values-bar";
},
/**
* @param {number} minValue
* @param {number} maxValue
* @param {string} uiName
* @param {string} uiValueTemplate
* @param {string} color
* @return {!WebInspector.CountersGraph.Counter}
*/
setRange: function(minValue, maxValue)
createCounter: function(uiName, uiValueTemplate, color)
{
this._range.textContent = WebInspector.UIString("[%d:%d]", minValue, maxValue);
var counter = new WebInspector.CountersGraph.Counter();
this._counters.push(counter);
this._counterUI.push(new WebInspector.CountersGraph.CounterUI(this, uiName, uiValueTemplate, color, counter));
return counter;
},
__proto__: WebInspector.CounterUIBase.prototype
}
reset: function()
{
for (var i = 0; i < this._counters.length; ++i) {
this._counters[i].reset();
this._counterUI[i].reset();
}
this.refresh();
},
_resize: function()
{
var parentElement = this._canvas.parentElement;
this._canvas.width = parentElement.clientWidth;
this._canvas.height = parentElement.clientHeight;
var timelinePaddingLeft = 15;
this._calculator.setDisplayWindow(timelinePaddingLeft, this._canvas.width);
this.refresh();
},
WebInspector.CountersGraph.prototype = {
_createCurrentValuesBar: function()
/**
* @param {number} startTime
* @param {number} endTime
*/
setWindowTimes: function(startTime, endTime)
{
this._currentValuesBar = this._graphsContainer.createChild("div");
this._currentValuesBar.id = "counter-values-bar";
this._graphsContainer.classList.add("dom-counters");
this._calculator.setWindow(startTime, endTime);
this.scheduleRefresh();
},
createAllCounters: function()
scheduleRefresh: function()
{
this._counters = [];
this._counterUI = [];
this._createCounter(WebInspector.UIString("Documents"), WebInspector.UIString("Documents: %d"), "#d00", "documents");
this._createCounter(WebInspector.UIString("Nodes"), WebInspector.UIString("Nodes: %d"), "#0a0", "nodes");
this._createCounter(WebInspector.UIString("Listeners"), WebInspector.UIString("Listeners: %d"), "#00d", "jsEventListeners");
if (WebInspector.experimentsSettings.gpuTimeline.isEnabled())
this._createCounter(WebInspector.UIString("GPU Memory"), WebInspector.UIString("GPU Memory [KB]: %d"), "#c0c", "gpuMemoryUsedKB");
if (this._refreshTimer)
return;
this._refreshTimer = setTimeout(this.refresh.bind(this), 300);
},
draw: function()
{
for (var i = 0; i < this._counters.length; ++i) {
this._counters[i]._calculateVisibleIndexes(this._calculator);
this._counters[i]._calculateXValues(this._canvas.width);
}
this._clear();
this._setVerticalClip(10, this._canvas.height - 20);
for (var i = 0; i < this._counterUI.length; i++)
this._drawGraph(this._counterUI[i]);
},
/**
* @param {string} uiName
* @param {string} uiValueTemplate
* @param {string} color
* @param {string} protocolName
* @param {?Event} event
*/
_createCounter: function(uiName, uiValueTemplate, color, protocolName)
_onClick: function(event)
{
var counter = new WebInspector.MemoryStatistics.Counter(protocolName);
this._counters.push(counter);
this._counterUI.push(new WebInspector.CounterUI(this, uiName, uiValueTemplate, color, counter));
var x = event.x - this._canvasContainer.totalOffsetLeft();
var minDistance = Infinity;
var bestTime;
for (var i = 0; i < this._counterUI.length; ++i) {
var counterUI = this._counterUI[i];
if (!counterUI.counter.times.length)
continue;
var index = counterUI._recordIndexAt(x);
var distance = Math.abs(x - counterUI.counter.x[index]);
if (distance < minDistance) {
minDistance = distance;
bestTime = counterUI.counter.times[index];
}
}
if (bestTime !== undefined)
this._revealRecordAt(bestTime);
},
/**
* @param {!WebInspector.TimelineModel.Record} record
* @param {number} time
*/
addRecord: function(record)
_revealRecordAt: function(time)
{
/**
* @param {!WebInspector.TimelineModel.Record} record
* @this {!WebInspector.CountersGraph}
*/
function addStatistics(record)
var recordToReveal;
function findRecordToReveal(record)
{
var counters = record.counters;
if (!counters)
return;
var time = record.endTime || record.startTime;
for (var i = 0; i < this._counters.length; ++i)
this._counters[i].appendSample(time, counters);
if (record.startTime <= time && time <= record.endTime) {
recordToReveal = record;
return true;
}
// If there is no record containing the time than use the latest one before that time.
if (!recordToReveal || record.endTime < time && recordToReveal.endTime < record.endTime)
recordToReveal = record;
return false;
}
WebInspector.TimelineModel.forAllRecords([record], null, addStatistics.bind(this));
this.scheduleRefresh();
this._model.forAllRecords(null, findRecordToReveal);
this._delegate.selectRecord(recordToReveal);
},
draw: function()
/**
* @param {?Event} event
*/
_onMouseOut: function(event)
{
delete this._markerXPosition;
this._clearCurrentValueAndMarker();
},
_clearCurrentValueAndMarker: function()
{
WebInspector.MemoryStatistics.prototype.draw.call(this);
for (var i = 0; i < this._counterUI.length; i++)
this._drawGraph(this._counterUI[i]);
this._counterUI[i]._clearCurrentValueAndMarker();
},
/**
* @param {?Event} event
*/
_onMouseMove: function(event)
{
var x = event.x - this._canvasContainer.totalOffsetLeft();
this._markerXPosition = x;
this._refreshCurrentValues();
},
_refreshCurrentValues: function()
{
if (this._markerXPosition === undefined)
return;
for (var i = 0; i < this._counterUI.length; ++i)
this._counterUI[i].updateCurrentValue(this._markerXPosition);
},
refresh: function()
{
delete this._refreshTimer;
this._timelineGrid.updateDividers(this._calculator);
this.draw();
this._refreshCurrentValues();
},
refreshRecords: function()
{
this.reset();
var records = this._model.records();
for (var i = 0; i < records.length; ++i)
this.addRecord(records[i]);
},
/**
* @param {!WebInspector.CounterUIBase} counterUI
* @param {number} originY
* @param {number} height
*/
_setVerticalClip: function(originY, height)
{
this._originY = originY;
this._clippedHeight = height;
},
_clear: function()
{
var ctx = this._canvas.getContext("2d");
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
},
/**
* @param {?WebInspector.TimelineModel.Record} record
* @param {string=} regex
* @param {boolean=} selectRecord
*/
highlightSearchResult: function(record, regex, selectRecord)
{
},
/**
* @param {?WebInspector.TimelineModel.Record} record
*/
setSelectedRecord: function(record)
{
},
/**
* @param {!WebInspector.CountersGraph.CounterUI} counterUI
*/
_drawGraph: function(counterUI)
{
......@@ -175,7 +292,7 @@ WebInspector.CountersGraph.prototype = {
counterUI.setRange(minValue, maxValue);
if (!counterUI.visible)
if (!counterUI.visible())
return;
var yValues = counterUI.graphYValues;
......@@ -208,6 +325,205 @@ WebInspector.CountersGraph.prototype = {
ctx.restore();
},
__proto__: WebInspector.MemoryStatistics.prototype
__proto__: WebInspector.SplitView.prototype
}
/**
* @constructor
*/
WebInspector.CountersGraph.Counter = function()
{
this.times = [];
this.values = [];
}
WebInspector.CountersGraph.Counter.prototype = {
/**
* @param {number} time
* @param {number} value
*/
appendSample: function(time, value)
{
if (this.values.length && this.values.peekLast() === value)
return;
this.times.push(time);
this.values.push(value);
},
reset: function()
{
this.times = [];
this.values = [];
},
/**
* @param {!WebInspector.TimelineCalculator} calculator
*/
_calculateVisibleIndexes: function(calculator)
{
var start = calculator.minimumBoundary();
var end = calculator.maximumBoundary();
// Maximum index of element whose time <= start.
this._minimumIndex = Number.constrain(this.times.upperBound(start) - 1, 0, this.times.length - 1);
// Minimum index of element whose time >= end.
this._maximumIndex = Number.constrain(this.times.lowerBound(end), 0, this.times.length - 1);
// Current window bounds.
this._minTime = start;
this._maxTime = end;
},
/**
* @param {number} width
*/
_calculateXValues: function(width)
{
if (!this.values.length)
return;
var xFactor = width / (this._maxTime - this._minTime);
this.x = new Array(this.values.length);
this.x[this._minimumIndex] = 0;
for (var i = this._minimumIndex + 1; i < this._maximumIndex; i++)
this.x[i] = xFactor * (this.times[i] - this._minTime);
this.x[this._maximumIndex] = width;
}
}
/**
* @constructor
* @param {!WebInspector.CountersGraph} memoryCountersPane
* @param {string} title
* @param {string} currentValueLabel
* @param {string} graphColor
* @param {!WebInspector.CountersGraph.Counter} counter
*/
WebInspector.CountersGraph.CounterUI = function(memoryCountersPane, title, currentValueLabel, graphColor, counter)
{
this._memoryCountersPane = memoryCountersPane;
this.counter = counter;
var container = memoryCountersPane.sidebarElement().createChild("div", "memory-counter-sidebar-info");
var swatchColor = graphColor;
this._swatch = new WebInspector.SwatchCheckbox(WebInspector.UIString(title), swatchColor);
this._swatch.addEventListener(WebInspector.SwatchCheckbox.Events.Changed, this._toggleCounterGraph.bind(this));
container.appendChild(this._swatch.element);
this._range = this._swatch.element.createChild("span");
this._value = memoryCountersPane._currentValuesBar.createChild("span", "memory-counter-value");
this._value.style.color = graphColor;
this.graphColor = graphColor;
this.strokeColor = graphColor;
this.graphYValues = [];
this._currentValueLabel = currentValueLabel;
this._marker = memoryCountersPane._canvasContainer.createChild("div", "memory-counter-marker");
this._marker.style.backgroundColor = graphColor;
this._clearCurrentValueAndMarker();
}
WebInspector.CountersGraph.CounterUI.prototype = {
reset: function()
{
this._range.textContent = "";
},
/**
* @param {number} minValue
* @param {number} maxValue
*/
setRange: function(minValue, maxValue)
{
this._range.textContent = WebInspector.UIString("[%d:%d]", minValue, maxValue);
},
_toggleCounterGraph: function(event)
{
this._value.classList.toggle("hidden", !this._swatch.checked);
this._memoryCountersPane.refresh();
},
/**
* @param {number} x
* @return {number}
*/
_recordIndexAt: function(x)
{
return this.counter.x.upperBound(x, null, this.counter._minimumIndex + 1, this.counter._maximumIndex + 1) - 1;
},
/**
* @param {number} x
*/
updateCurrentValue: function(x)
{
if (!this.visible() || !this.counter.values.length)
return;
var index = this._recordIndexAt(x);
this._value.textContent = WebInspector.UIString(this._currentValueLabel, this.counter.values[index]);
var y = this.graphYValues[index];
this._marker.style.left = x + "px";
this._marker.style.top = y + "px";
this._marker.classList.remove("hidden");
},
_clearCurrentValueAndMarker: function()
{
this._value.textContent = "";
this._marker.classList.add("hidden");
},
/**
* @return {boolean}
*/
visible: function()
{
return this._swatch.checked;
}
}
/**
* @constructor
* @extends {WebInspector.Object}
*/
WebInspector.SwatchCheckbox = function(title, color)
{
this.element = document.createElement("div");
this._swatch = this.element.createChild("div", "swatch");
this.element.createChild("span", "title").textContent = title;
this._color = color;
this.checked = true;
this.element.addEventListener("click", this._toggleCheckbox.bind(this), true);
}
WebInspector.SwatchCheckbox.Events = {
Changed: "Changed"
}
WebInspector.SwatchCheckbox.prototype = {
get checked()
{
return this._checked;
},
set checked(v)
{
this._checked = v;
if (this._checked)
this._swatch.style.backgroundColor = this._color;
else
this._swatch.style.backgroundColor = "";
},
_toggleCheckbox: function(event)
{
this.checked = !this.checked;
this.dispatchEventToListeners(WebInspector.SwatchCheckbox.Events.Changed);
},
__proto__: WebInspector.Object.prototype
}
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @constructor
* @extends {WebInspector.CountersGraph}
* @implements {WebInspector.TimelineModeView}
* @param {!WebInspector.TimelineModeViewDelegate} delegate
* @param {!WebInspector.TimelineModel} model
*/
WebInspector.DOMCountersGraph = function(delegate, model)
{
WebInspector.CountersGraph.call(this, delegate, model);
this._countersByName = {};
this._countersByName["documents"] = this.createCounter(WebInspector.UIString("Documents"), WebInspector.UIString("Documents: %d"), "#d00");
this._countersByName["nodes"] = this.createCounter(WebInspector.UIString("Nodes"), WebInspector.UIString("Nodes: %d"), "#0a0");
this._countersByName["jsEventListeners"] = this.createCounter(WebInspector.UIString("Listeners"), WebInspector.UIString("Listeners: %d"), "#00d");
if (WebInspector.experimentsSettings.gpuTimeline.isEnabled())
this._countersByName["gpuMemoryUsedKB"] = this.createCounter(WebInspector.UIString("GPU Memory"), WebInspector.UIString("GPU Memory [KB]: %d"), "#c0c");
}
WebInspector.DOMCountersGraph.prototype = {
/**
* @param {!WebInspector.TimelineModel.Record} record
*/
addRecord: function(record)
{
/**
* @param {!WebInspector.TimelineModel.Record} record
* @this {!WebInspector.DOMCountersGraph}
*/
function addStatistics(record)
{
var counters = record.counters;
if (!counters)
return;
for (var name in counters) {
var counter = this._countersByName[name];
if (counter)
counter.appendSample(record.endTime || record.startTime, counters[name]);
}
}
WebInspector.TimelineModel.forAllRecords([record], null, addStatistics.bind(this));
this.scheduleRefresh();
},
__proto__: WebInspector.CountersGraph.prototype
}
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @constructor
* @extends {WebInspector.SplitView}
* @param {!WebInspector.TimelineModeViewDelegate} delegate
* @param {!WebInspector.TimelineModel} model
*/
WebInspector.MemoryStatistics = function(delegate, model)
{
WebInspector.SplitView.call(this, true, false);
this.element.id = "memory-graphs-container";
this._delegate = delegate;
this._model = model;
this._calculator = new WebInspector.TimelineCalculator(this._model);
this._graphsContainer = this.mainElement();
this._createCurrentValuesBar();
this._canvasView = new WebInspector.VBoxWithResizeCallback(this._resize.bind(this));
this._canvasView.show(this._graphsContainer);
this._canvasContainer = this._canvasView.element;
this._canvasContainer.id = "memory-graphs-canvas-container";
this._canvas = this._canvasContainer.createChild("canvas");
this._canvas.id = "memory-counters-graph";
this._canvasContainer.addEventListener("mouseover", this._onMouseMove.bind(this), true);
this._canvasContainer.addEventListener("mousemove", this._onMouseMove.bind(this), true);
this._canvasContainer.addEventListener("mouseout", this._onMouseOut.bind(this), true);
this._canvasContainer.addEventListener("click", this._onClick.bind(this), true);
// We create extra timeline grid here to reuse its event dividers.
this._timelineGrid = new WebInspector.TimelineGrid();
this._canvasContainer.appendChild(this._timelineGrid.dividersElement);
// Populate sidebar
this.sidebarElement().createChild("div", "sidebar-tree sidebar-tree-section").textContent = WebInspector.UIString("COUNTERS");
this.createAllCounters();
}
/**
* @constructor
* @param {string} counterName
*/
WebInspector.MemoryStatistics.Counter = function(counterName)
{
this.counterName = counterName;
this.times = [];
this.values = [];
}
WebInspector.MemoryStatistics.Counter.prototype = {
/**
* @param {number} time
* @param {!TimelineAgent.Counters} counters
*/
appendSample: function(time, counters)
{
var value = counters[this.counterName];
if (value === undefined)
return;
if (this.values.length && this.values.peekLast() === value)
return;
this.times.push(time);
this.values.push(value);
},
reset: function()
{
this.times = [];
this.values = [];
},
/**
* @param {!WebInspector.TimelineCalculator} calculator
*/
_calculateVisibleIndexes: function(calculator)
{
var start = calculator.minimumBoundary();
var end = calculator.maximumBoundary();
// Maximum index of element whose time <= start.
this._minimumIndex = Number.constrain(this.times.upperBound(start) - 1, 0, this.times.length - 1);
// Minimum index of element whose time >= end.
this._maximumIndex = Number.constrain(this.times.lowerBound(end), 0, this.times.length - 1);
// Current window bounds.
this._minTime = start;
this._maxTime = end;
},
/**
* @param {number} width
*/
_calculateXValues: function(width)
{
if (!this.values.length)
return;
var xFactor = width / (this._maxTime - this._minTime);
this.x = new Array(this.values.length);
this.x[this._minimumIndex] = 0;
for (var i = this._minimumIndex + 1; i < this._maximumIndex; i++)
this.x[i] = xFactor * (this.times[i] - this._minTime);
this.x[this._maximumIndex] = width;
}
}
/**
* @constructor
* @extends {WebInspector.Object}
*/
WebInspector.SwatchCheckbox = function(title, color)
{
this.element = document.createElement("div");
this._swatch = this.element.createChild("div", "swatch");
this.element.createChild("span", "title").textContent = title;
this._color = color;
this.checked = true;
this.element.addEventListener("click", this._toggleCheckbox.bind(this), true);
}
WebInspector.SwatchCheckbox.Events = {
Changed: "Changed"
}
WebInspector.SwatchCheckbox.prototype = {
get checked()
{
return this._checked;
},
set checked(v)
{
this._checked = v;
if (this._checked)
this._swatch.style.backgroundColor = this._color;
else
this._swatch.style.backgroundColor = "";
},
_toggleCheckbox: function(event)
{
this.checked = !this.checked;
this.dispatchEventToListeners(WebInspector.SwatchCheckbox.Events.Changed);
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @param {!WebInspector.MemoryStatistics} memoryCountersPane
* @param {string} title
* @param {string} graphColor
* @param {!WebInspector.MemoryStatistics.Counter} counter
*/
WebInspector.CounterUIBase = function(memoryCountersPane, title, graphColor, counter)
{
this._memoryCountersPane = memoryCountersPane;
this.counter = counter;
var container = memoryCountersPane.sidebarElement().createChild("div", "memory-counter-sidebar-info");
var swatchColor = graphColor;
this._swatch = new WebInspector.SwatchCheckbox(WebInspector.UIString(title), swatchColor);
this._swatch.addEventListener(WebInspector.SwatchCheckbox.Events.Changed, this._toggleCounterGraph.bind(this));
container.appendChild(this._swatch.element);
this._value = null;
this.graphColor = graphColor;
this.strokeColor = graphColor;
this.graphYValues = [];
}
WebInspector.CounterUIBase.prototype = {
_toggleCounterGraph: function(event)
{
this._value.classList.toggle("hidden", !this._swatch.checked);
this._memoryCountersPane.refresh();
},
/**
* @param {number} x
* @return {number}
*/
_recordIndexAt: function(x)
{
return this.counter.x.upperBound(x, null, this.counter._minimumIndex + 1, this.counter._maximumIndex + 1) - 1;
},
/**
* @param {number} x
*/
updateCurrentValue: function(x)
{
if (!this.visible || !this.counter.values.length)
return;
var index = this._recordIndexAt(x);
this._value.textContent = WebInspector.UIString(this._currentValueLabel, this.counter.values[index]);
var y = this.graphYValues[index];
this._marker.style.left = x + "px";
this._marker.style.top = y + "px";
this._marker.classList.remove("hidden");
},
clearCurrentValueAndMarker: function()
{
this._value.textContent = "";
this._marker.classList.add("hidden");
},
get visible()
{
return this._swatch.checked;
},
}
WebInspector.MemoryStatistics.prototype = {
_createCurrentValuesBar: function()
{
throw new Error("Not implemented");
},
createAllCounters: function()
{
throw new Error("Not implemented");
},
/**
* @param {!WebInspector.TimelineModel.Record} record
*/
addRecord: function(record)
{
throw new Error("Not implemented");
},
reset: function()
{
for (var i = 0; i < this._counters.length; ++i)
this._counters[i].reset();
for (var i = 0; i < this._counterUI.length; ++i)
this._counterUI[i].reset();
this.refresh();
},
_resize: function()
{
var parentElement = this._canvas.parentElement;
this._canvas.width = parentElement.clientWidth;
this._canvas.height = parentElement.clientHeight;
var timelinePaddingLeft = 15;
this._calculator.setDisplayWindow(timelinePaddingLeft, this._canvas.width);
this.refresh();
},
/**
* @param {number} startTime
* @param {number} endTime
*/
setWindowTimes: function(startTime, endTime)
{
this._calculator.setWindow(startTime, endTime);
this.scheduleRefresh();
},
scheduleRefresh: function()
{
if (this._refreshTimer)
return;
this._refreshTimer = setTimeout(this.refresh.bind(this), 300);
},
draw: function()
{
for (var i = 0; i < this._counters.length; ++i) {
this._counters[i]._calculateVisibleIndexes(this._calculator);
this._counters[i]._calculateXValues(this._canvas.width);
}
this._clear();
this._setVerticalClip(10, this._canvas.height - 20);
},
/**
* @param {?Event} event
*/
_onClick: function(event)
{
var x = event.x - this._canvasContainer.totalOffsetLeft();
var minDistance = Infinity;
var bestTime;
for (var i = 0; i < this._counterUI.length; ++i) {
var counterUI = this._counterUI[i];
if (!counterUI.counter.times.length)
continue;
var index = counterUI._recordIndexAt(x);
var distance = Math.abs(x - counterUI.counter.x[index]);
if (distance < minDistance) {
minDistance = distance;
bestTime = counterUI.counter.times[index];
}
}
if (bestTime !== undefined)
this._revealRecordAt(bestTime);
},
/**
* @param {number} time
*/
_revealRecordAt: function(time)
{
var recordToReveal;
function findRecordToReveal(record)
{
if (record.startTime <= time && time <= record.endTime) {
recordToReveal = record;
return true;
}
// If there is no record containing the time than use the latest one before that time.
if (!recordToReveal || record.endTime < time && recordToReveal.endTime < record.endTime)
recordToReveal = record;
return false;
}
this._model.forAllRecords(null, findRecordToReveal);
this._delegate.selectRecord(recordToReveal);
},
/**
* @param {?Event} event
*/
_onMouseOut: function(event)
{
delete this._markerXPosition;
this._clearCurrentValueAndMarker();
},
_clearCurrentValueAndMarker: function()
{
for (var i = 0; i < this._counterUI.length; i++)
this._counterUI[i].clearCurrentValueAndMarker();
},
/**
* @param {?Event} event
*/
_onMouseMove: function(event)
{
var x = event.x - this._canvasContainer.totalOffsetLeft();
this._markerXPosition = x;
this._refreshCurrentValues();
},
_refreshCurrentValues: function()
{
if (this._markerXPosition === undefined)
return;
for (var i = 0; i < this._counterUI.length; ++i)
this._counterUI[i].updateCurrentValue(this._markerXPosition);
},
refresh: function()
{
delete this._refreshTimer;
this._timelineGrid.updateDividers(this._calculator);
this.draw();
this._refreshCurrentValues();
},
refreshRecords: function()
{
this.reset();
var records = this._model.records();
for (var i = 0; i < records.length; ++i)
this.addRecord(records[i]);
},
/**
* @param {number} originY
* @param {number} height
*/
_setVerticalClip: function(originY, height)
{
this._originY = originY;
this._clippedHeight = height;
},
_clear: function()
{
var ctx = this._canvas.getContext("2d");
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
},
/**
* @param {?WebInspector.TimelineModel.Record} record
* @param {string=} regex
* @param {boolean=} selectRecord
*/
highlightSearchResult: function(record, regex, selectRecord)
{
},
/**
* @param {?WebInspector.TimelineModel.Record} record
*/
setSelectedRecord: function(record)
{
},
__proto__: WebInspector.SplitView.prototype
}
......@@ -67,7 +67,7 @@ WebInspector.TimelineOverviewPane.prototype = {
},
/**
* @param {!WebInspector.TimelineOverviewBase} overviewControl
* @param {!WebInspector.TimelineOverview} overviewControl
*/
setOverviewControl: function(overviewControl)
{
......@@ -297,9 +297,43 @@ WebInspector.TimelineOverviewCalculator.prototype = {
}
}
/**
* @interface
*/
WebInspector.TimelineOverview = function(model)
{
}
WebInspector.TimelineOverview.prototype = {
/**
* @param {?Element} parentElement
* @param {!Element=} insertBefore
*/
show: function(parentElement, insertBefore) { },
update: function() { },
reset: function() { },
/**
* @param {number} windowLeft
* @param {number} windowRight
* @return {!{startTime: number, endTime: number}}
*/
windowTimes: function(windowLeft, windowRight) { },
/**
* @param {number} startTime
* @param {number} endTime
* @return {!{left: number, right: number}}
*/
windowBoundaries: function(startTime, endTime) { }
}
/**
* @constructor
* @extends {WebInspector.VBox}
* @implements {WebInspector.TimelineOverview}
* @param {!WebInspector.TimelineModel} model
*/
WebInspector.TimelineOverviewBase = function(model)
......@@ -312,8 +346,14 @@ WebInspector.TimelineOverviewBase = function(model)
}
WebInspector.TimelineOverviewBase.prototype = {
update: function() { },
reset: function() { },
update: function()
{
this.resetCanvas();
},
reset: function()
{
},
/**
* @param {number} windowLeft
......
......@@ -29,8 +29,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
importScript("MemoryStatistics.js");
importScript("CountersGraph.js");
importScript("DOMCountersGraph.js");
importScript("PieChart.js");
importScript("TimelineModel.js");
importScript("TimelineOverviewPane.js");
......@@ -240,6 +240,7 @@ WebInspector.TimelinePanel.prototype = {
/**
* @param {string} mode
* @return {!{overviewView: !WebInspector.TimelineOverview, mainViews: !Array.<!WebInspector.TimelineView>}}
*/
_viewsForMode: function(mode)
{
......@@ -257,7 +258,7 @@ WebInspector.TimelinePanel.prototype = {
break;
case WebInspector.TimelinePanel.Mode.Memory:
views.overviewView = new WebInspector.TimelineMemoryOverview(this._model);
views.mainViews = [this._timelineView(), new WebInspector.CountersGraph(this, this._model)];
views.mainViews = [this._timelineView(), new WebInspector.DOMCountersGraph(this, this._model)];
break;
case WebInspector.TimelinePanel.Mode.FlameChart:
views.overviewView = new WebInspector.TimelineFrameOverview(this._model, this._frameModel());
......
......@@ -298,7 +298,7 @@
"dependencies": ["components"],
"sources": [
"CountersGraph.js",
"MemoryStatistics.js",
"DOMCountersGraph.js",
"TimelineEventOverview.js",
"TimelineFrameModel.js",
"TimelineFrameOverview.js",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment