OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
(...skipping 10 matching lines...) Expand all Loading... |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 /** | 31 /** |
32 * @constructor | 32 * @constructor |
33 * @extends {WebInspector.MemoryStatistics} | 33 * @extends {WebInspector.SplitView} |
34 * @implements {WebInspector.TimelineModeView} | |
35 * @param {!WebInspector.TimelineModeViewDelegate} delegate | 34 * @param {!WebInspector.TimelineModeViewDelegate} delegate |
36 * @param {!WebInspector.TimelineModel} model | 35 * @param {!WebInspector.TimelineModel} model |
37 */ | 36 */ |
38 WebInspector.CountersGraph = function(delegate, model) | 37 WebInspector.CountersGraph = function(delegate, model) |
39 { | 38 { |
40 WebInspector.MemoryStatistics.call(this, delegate, model); | 39 WebInspector.SplitView.call(this, true, false); |
| 40 |
| 41 this.element.id = "memory-graphs-container"; |
| 42 |
| 43 this._delegate = delegate; |
| 44 this._model = model; |
| 45 this._calculator = new WebInspector.TimelineCalculator(this._model); |
| 46 |
| 47 this._graphsContainer = this.mainElement(); |
| 48 this._createCurrentValuesBar(); |
| 49 this._canvasView = new WebInspector.VBoxWithResizeCallback(this._resize.bind
(this)); |
| 50 this._canvasView.show(this._graphsContainer); |
| 51 this._canvasContainer = this._canvasView.element; |
| 52 this._canvasContainer.id = "memory-graphs-canvas-container"; |
| 53 this._canvas = this._canvasContainer.createChild("canvas"); |
| 54 this._canvas.id = "memory-counters-graph"; |
| 55 |
| 56 this._canvasContainer.addEventListener("mouseover", this._onMouseMove.bind(t
his), true); |
| 57 this._canvasContainer.addEventListener("mousemove", this._onMouseMove.bind(t
his), true); |
| 58 this._canvasContainer.addEventListener("mouseout", this._onMouseOut.bind(thi
s), true); |
| 59 this._canvasContainer.addEventListener("click", this._onClick.bind(this), tr
ue); |
| 60 // We create extra timeline grid here to reuse its event dividers. |
| 61 this._timelineGrid = new WebInspector.TimelineGrid(); |
| 62 this._canvasContainer.appendChild(this._timelineGrid.dividersElement); |
| 63 |
| 64 // Populate sidebar |
| 65 this.sidebarElement().createChild("div", "sidebar-tree sidebar-tree-section"
).textContent = WebInspector.UIString("COUNTERS"); |
| 66 this._counters = []; |
| 67 this._counterUI = []; |
41 } | 68 } |
42 | 69 |
43 /** | |
44 * @constructor | |
45 * @extends {WebInspector.CounterUIBase} | |
46 * @param {!WebInspector.CountersGraph} memoryCountersPane | |
47 * @param {string} title | |
48 * @param {string} currentValueLabel | |
49 * @param {!string} color | |
50 * @param {!WebInspector.MemoryStatistics.Counter} counter | |
51 */ | |
52 WebInspector.CounterUI = function(memoryCountersPane, title, currentValueLabel,
color, counter) | |
53 { | |
54 WebInspector.CounterUIBase.call(this, memoryCountersPane, title, color, coun
ter) | |
55 this._range = this._swatch.element.createChild("span"); | |
56 | |
57 this._value = memoryCountersPane._currentValuesBar.createChild("span", "memo
ry-counter-value"); | |
58 this._value.style.color = color; | |
59 this._currentValueLabel = currentValueLabel; | |
60 this._marker = memoryCountersPane._canvasContainer.createChild("div", "memor
y-counter-marker"); | |
61 this._marker.style.backgroundColor = color; | |
62 this.clearCurrentValueAndMarker(); | |
63 | |
64 this.graphColor = color; | |
65 this.graphYValues = []; | |
66 } | |
67 | |
68 WebInspector.CounterUI.prototype = { | |
69 reset: function() | |
70 { | |
71 this._range.textContent = ""; | |
72 }, | |
73 | |
74 /** | |
75 * @param {number} minValue | |
76 * @param {number} maxValue | |
77 */ | |
78 setRange: function(minValue, maxValue) | |
79 { | |
80 this._range.textContent = WebInspector.UIString("[%d:%d]", minValue, max
Value); | |
81 }, | |
82 | |
83 __proto__: WebInspector.CounterUIBase.prototype | |
84 } | |
85 | |
86 | |
87 WebInspector.CountersGraph.prototype = { | 70 WebInspector.CountersGraph.prototype = { |
88 _createCurrentValuesBar: function() | 71 _createCurrentValuesBar: function() |
89 { | 72 { |
90 this._currentValuesBar = this._graphsContainer.createChild("div"); | 73 this._currentValuesBar = this._graphsContainer.createChild("div"); |
91 this._currentValuesBar.id = "counter-values-bar"; | 74 this._currentValuesBar.id = "counter-values-bar"; |
92 this._graphsContainer.classList.add("dom-counters"); | |
93 }, | |
94 | |
95 createAllCounters: function() | |
96 { | |
97 this._counters = []; | |
98 this._counterUI = []; | |
99 this._createCounter(WebInspector.UIString("Documents"), WebInspector.UIS
tring("Documents: %d"), "#d00", "documents"); | |
100 this._createCounter(WebInspector.UIString("Nodes"), WebInspector.UIStrin
g("Nodes: %d"), "#0a0", "nodes"); | |
101 this._createCounter(WebInspector.UIString("Listeners"), WebInspector.UIS
tring("Listeners: %d"), "#00d", "jsEventListeners"); | |
102 if (WebInspector.experimentsSettings.gpuTimeline.isEnabled()) | |
103 this._createCounter(WebInspector.UIString("GPU Memory"), WebInspecto
r.UIString("GPU Memory [KB]: %d"), "#c0c", "gpuMemoryUsedKB"); | |
104 }, | 75 }, |
105 | 76 |
106 /** | 77 /** |
107 * @param {string} uiName | 78 * @param {string} uiName |
108 * @param {string} uiValueTemplate | 79 * @param {string} uiValueTemplate |
109 * @param {string} color | 80 * @param {string} color |
110 * @param {string} protocolName | 81 * @return {!WebInspector.CountersGraph.Counter} |
111 */ | 82 */ |
112 _createCounter: function(uiName, uiValueTemplate, color, protocolName) | 83 createCounter: function(uiName, uiValueTemplate, color) |
113 { | 84 { |
114 var counter = new WebInspector.MemoryStatistics.Counter(protocolName); | 85 var counter = new WebInspector.CountersGraph.Counter(); |
115 this._counters.push(counter); | 86 this._counters.push(counter); |
116 this._counterUI.push(new WebInspector.CounterUI(this, uiName, uiValueTem
plate, color, counter)); | 87 this._counterUI.push(new WebInspector.CountersGraph.CounterUI(this, uiNa
me, uiValueTemplate, color, counter)); |
117 }, | 88 return counter; |
118 | 89 }, |
119 /** | 90 |
120 * @param {!WebInspector.TimelineModel.Record} record | 91 reset: function() |
121 */ | 92 { |
122 addRecord: function(record) | 93 for (var i = 0; i < this._counters.length; ++i) { |
123 { | 94 this._counters[i].reset(); |
124 /** | 95 this._counterUI[i].reset(); |
125 * @param {!WebInspector.TimelineModel.Record} record | 96 } |
126 * @this {!WebInspector.CountersGraph} | 97 this.refresh(); |
127 */ | 98 }, |
128 function addStatistics(record) | 99 |
129 { | 100 _resize: function() |
130 var counters = record.counters; | 101 { |
131 if (!counters) | 102 var parentElement = this._canvas.parentElement; |
132 return; | 103 this._canvas.width = parentElement.clientWidth; |
133 var time = record.endTime || record.startTime; | 104 this._canvas.height = parentElement.clientHeight; |
134 for (var i = 0; i < this._counters.length; ++i) | 105 var timelinePaddingLeft = 15; |
135 this._counters[i].appendSample(time, counters); | 106 this._calculator.setDisplayWindow(timelinePaddingLeft, this._canvas.widt
h); |
136 } | 107 this.refresh(); |
137 WebInspector.TimelineModel.forAllRecords([record], null, addStatistics.b
ind(this)); | 108 }, |
| 109 |
| 110 /** |
| 111 * @param {number} startTime |
| 112 * @param {number} endTime |
| 113 */ |
| 114 setWindowTimes: function(startTime, endTime) |
| 115 { |
| 116 this._calculator.setWindow(startTime, endTime); |
138 this.scheduleRefresh(); | 117 this.scheduleRefresh(); |
139 }, | 118 }, |
140 | 119 |
| 120 scheduleRefresh: function() |
| 121 { |
| 122 if (this._refreshTimer) |
| 123 return; |
| 124 this._refreshTimer = setTimeout(this.refresh.bind(this), 300); |
| 125 }, |
| 126 |
141 draw: function() | 127 draw: function() |
142 { | 128 { |
143 WebInspector.MemoryStatistics.prototype.draw.call(this); | 129 for (var i = 0; i < this._counters.length; ++i) { |
| 130 this._counters[i]._calculateVisibleIndexes(this._calculator); |
| 131 this._counters[i]._calculateXValues(this._canvas.width); |
| 132 } |
| 133 this._clear(); |
| 134 this._setVerticalClip(10, this._canvas.height - 20); |
| 135 |
144 for (var i = 0; i < this._counterUI.length; i++) | 136 for (var i = 0; i < this._counterUI.length; i++) |
145 this._drawGraph(this._counterUI[i]); | 137 this._drawGraph(this._counterUI[i]); |
146 }, | 138 }, |
147 | 139 |
148 /** | 140 /** |
149 * @param {!WebInspector.CounterUIBase} counterUI | 141 * @param {?Event} event |
| 142 */ |
| 143 _onClick: function(event) |
| 144 { |
| 145 var x = event.x - this._canvasContainer.totalOffsetLeft(); |
| 146 var minDistance = Infinity; |
| 147 var bestTime; |
| 148 for (var i = 0; i < this._counterUI.length; ++i) { |
| 149 var counterUI = this._counterUI[i]; |
| 150 if (!counterUI.counter.times.length) |
| 151 continue; |
| 152 var index = counterUI._recordIndexAt(x); |
| 153 var distance = Math.abs(x - counterUI.counter.x[index]); |
| 154 if (distance < minDistance) { |
| 155 minDistance = distance; |
| 156 bestTime = counterUI.counter.times[index]; |
| 157 } |
| 158 } |
| 159 if (bestTime !== undefined) |
| 160 this._revealRecordAt(bestTime); |
| 161 }, |
| 162 |
| 163 /** |
| 164 * @param {number} time |
| 165 */ |
| 166 _revealRecordAt: function(time) |
| 167 { |
| 168 var recordToReveal; |
| 169 function findRecordToReveal(record) |
| 170 { |
| 171 if (record.startTime <= time && time <= record.endTime) { |
| 172 recordToReveal = record; |
| 173 return true; |
| 174 } |
| 175 // If there is no record containing the time than use the latest one
before that time. |
| 176 if (!recordToReveal || record.endTime < time && recordToReveal.endTi
me < record.endTime) |
| 177 recordToReveal = record; |
| 178 return false; |
| 179 } |
| 180 this._model.forAllRecords(null, findRecordToReveal); |
| 181 this._delegate.selectRecord(recordToReveal); |
| 182 }, |
| 183 |
| 184 /** |
| 185 * @param {?Event} event |
| 186 */ |
| 187 _onMouseOut: function(event) |
| 188 { |
| 189 delete this._markerXPosition; |
| 190 this._clearCurrentValueAndMarker(); |
| 191 }, |
| 192 |
| 193 _clearCurrentValueAndMarker: function() |
| 194 { |
| 195 for (var i = 0; i < this._counterUI.length; i++) |
| 196 this._counterUI[i]._clearCurrentValueAndMarker(); |
| 197 }, |
| 198 |
| 199 /** |
| 200 * @param {?Event} event |
| 201 */ |
| 202 _onMouseMove: function(event) |
| 203 { |
| 204 var x = event.x - this._canvasContainer.totalOffsetLeft(); |
| 205 this._markerXPosition = x; |
| 206 this._refreshCurrentValues(); |
| 207 }, |
| 208 |
| 209 _refreshCurrentValues: function() |
| 210 { |
| 211 if (this._markerXPosition === undefined) |
| 212 return; |
| 213 for (var i = 0; i < this._counterUI.length; ++i) |
| 214 this._counterUI[i].updateCurrentValue(this._markerXPosition); |
| 215 }, |
| 216 |
| 217 refresh: function() |
| 218 { |
| 219 delete this._refreshTimer; |
| 220 this._timelineGrid.updateDividers(this._calculator); |
| 221 this.draw(); |
| 222 this._refreshCurrentValues(); |
| 223 }, |
| 224 |
| 225 refreshRecords: function() |
| 226 { |
| 227 this.reset(); |
| 228 var records = this._model.records(); |
| 229 for (var i = 0; i < records.length; ++i) |
| 230 this.addRecord(records[i]); |
| 231 }, |
| 232 |
| 233 /** |
| 234 * @param {number} originY |
| 235 * @param {number} height |
| 236 */ |
| 237 _setVerticalClip: function(originY, height) |
| 238 { |
| 239 this._originY = originY; |
| 240 this._clippedHeight = height; |
| 241 }, |
| 242 |
| 243 _clear: function() |
| 244 { |
| 245 var ctx = this._canvas.getContext("2d"); |
| 246 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
| 247 }, |
| 248 |
| 249 /** |
| 250 * @param {?WebInspector.TimelineModel.Record} record |
| 251 * @param {string=} regex |
| 252 * @param {boolean=} selectRecord |
| 253 */ |
| 254 highlightSearchResult: function(record, regex, selectRecord) |
| 255 { |
| 256 }, |
| 257 |
| 258 /** |
| 259 * @param {?WebInspector.TimelineModel.Record} record |
| 260 */ |
| 261 setSelectedRecord: function(record) |
| 262 { |
| 263 }, |
| 264 |
| 265 /** |
| 266 * @param {!WebInspector.CountersGraph.CounterUI} counterUI |
150 */ | 267 */ |
151 _drawGraph: function(counterUI) | 268 _drawGraph: function(counterUI) |
152 { | 269 { |
153 var canvas = this._canvas; | 270 var canvas = this._canvas; |
154 var ctx = canvas.getContext("2d"); | 271 var ctx = canvas.getContext("2d"); |
155 var width = canvas.width; | 272 var width = canvas.width; |
156 var height = this._clippedHeight; | 273 var height = this._clippedHeight; |
157 var originY = this._originY; | 274 var originY = this._originY; |
158 var counter = counterUI.counter; | 275 var counter = counterUI.counter; |
159 var values = counter.values; | 276 var values = counter.values; |
160 | 277 |
161 if (!values.length) | 278 if (!values.length) |
162 return; | 279 return; |
163 | 280 |
164 var maxValue; | 281 var maxValue; |
165 var minValue; | 282 var minValue; |
166 for (var i = counter._minimumIndex; i <= counter._maximumIndex; i++) { | 283 for (var i = counter._minimumIndex; i <= counter._maximumIndex; i++) { |
167 var value = values[i]; | 284 var value = values[i]; |
168 if (minValue === undefined || value < minValue) | 285 if (minValue === undefined || value < minValue) |
169 minValue = value; | 286 minValue = value; |
170 if (maxValue === undefined || value > maxValue) | 287 if (maxValue === undefined || value > maxValue) |
171 maxValue = value; | 288 maxValue = value; |
172 } | 289 } |
173 minValue = minValue || 0; | 290 minValue = minValue || 0; |
174 maxValue = maxValue || 1; | 291 maxValue = maxValue || 1; |
175 | 292 |
176 counterUI.setRange(minValue, maxValue); | 293 counterUI.setRange(minValue, maxValue); |
177 | 294 |
178 if (!counterUI.visible) | 295 if (!counterUI.visible()) |
179 return; | 296 return; |
180 | 297 |
181 var yValues = counterUI.graphYValues; | 298 var yValues = counterUI.graphYValues; |
182 yValues.length = this._counters.length; | 299 yValues.length = this._counters.length; |
183 | 300 |
184 var maxYRange = maxValue - minValue; | 301 var maxYRange = maxValue - minValue; |
185 var yFactor = maxYRange ? height / (maxYRange) : 1; | 302 var yFactor = maxYRange ? height / (maxYRange) : 1; |
186 | 303 |
187 ctx.save(); | 304 ctx.save(); |
188 ctx.translate(0.5, 0.5); | 305 ctx.translate(0.5, 0.5); |
(...skipping 12 matching lines...) Expand all Loading... |
201 yValues[i] = currentY; | 318 yValues[i] = currentY; |
202 } | 319 } |
203 ctx.lineTo(width, currentY); | 320 ctx.lineTo(width, currentY); |
204 ctx.lineWidth = 1; | 321 ctx.lineWidth = 1; |
205 ctx.strokeStyle = counterUI.graphColor; | 322 ctx.strokeStyle = counterUI.graphColor; |
206 ctx.stroke(); | 323 ctx.stroke(); |
207 ctx.closePath(); | 324 ctx.closePath(); |
208 ctx.restore(); | 325 ctx.restore(); |
209 }, | 326 }, |
210 | 327 |
211 __proto__: WebInspector.MemoryStatistics.prototype | 328 __proto__: WebInspector.SplitView.prototype |
212 } | 329 } |
213 | 330 |
| 331 /** |
| 332 * @constructor |
| 333 */ |
| 334 WebInspector.CountersGraph.Counter = function() |
| 335 { |
| 336 this.times = []; |
| 337 this.values = []; |
| 338 } |
| 339 |
| 340 WebInspector.CountersGraph.Counter.prototype = { |
| 341 /** |
| 342 * @param {number} time |
| 343 * @param {number} value |
| 344 */ |
| 345 appendSample: function(time, value) |
| 346 { |
| 347 if (this.values.length && this.values.peekLast() === value) |
| 348 return; |
| 349 this.times.push(time); |
| 350 this.values.push(value); |
| 351 }, |
| 352 |
| 353 reset: function() |
| 354 { |
| 355 this.times = []; |
| 356 this.values = []; |
| 357 }, |
| 358 |
| 359 /** |
| 360 * @param {!WebInspector.TimelineCalculator} calculator |
| 361 */ |
| 362 _calculateVisibleIndexes: function(calculator) |
| 363 { |
| 364 var start = calculator.minimumBoundary(); |
| 365 var end = calculator.maximumBoundary(); |
| 366 |
| 367 // Maximum index of element whose time <= start. |
| 368 this._minimumIndex = Number.constrain(this.times.upperBound(start) - 1,
0, this.times.length - 1); |
| 369 |
| 370 // Minimum index of element whose time >= end. |
| 371 this._maximumIndex = Number.constrain(this.times.lowerBound(end), 0, thi
s.times.length - 1); |
| 372 |
| 373 // Current window bounds. |
| 374 this._minTime = start; |
| 375 this._maxTime = end; |
| 376 }, |
| 377 |
| 378 /** |
| 379 * @param {number} width |
| 380 */ |
| 381 _calculateXValues: function(width) |
| 382 { |
| 383 if (!this.values.length) |
| 384 return; |
| 385 |
| 386 var xFactor = width / (this._maxTime - this._minTime); |
| 387 |
| 388 this.x = new Array(this.values.length); |
| 389 this.x[this._minimumIndex] = 0; |
| 390 for (var i = this._minimumIndex + 1; i < this._maximumIndex; i++) |
| 391 this.x[i] = xFactor * (this.times[i] - this._minTime); |
| 392 this.x[this._maximumIndex] = width; |
| 393 } |
| 394 } |
| 395 |
| 396 /** |
| 397 * @constructor |
| 398 * @param {!WebInspector.CountersGraph} memoryCountersPane |
| 399 * @param {string} title |
| 400 * @param {string} currentValueLabel |
| 401 * @param {string} graphColor |
| 402 * @param {!WebInspector.CountersGraph.Counter} counter |
| 403 */ |
| 404 WebInspector.CountersGraph.CounterUI = function(memoryCountersPane, title, curre
ntValueLabel, graphColor, counter) |
| 405 { |
| 406 this._memoryCountersPane = memoryCountersPane; |
| 407 this.counter = counter; |
| 408 var container = memoryCountersPane.sidebarElement().createChild("div", "memo
ry-counter-sidebar-info"); |
| 409 var swatchColor = graphColor; |
| 410 this._swatch = new WebInspector.SwatchCheckbox(WebInspector.UIString(title),
swatchColor); |
| 411 this._swatch.addEventListener(WebInspector.SwatchCheckbox.Events.Changed, th
is._toggleCounterGraph.bind(this)); |
| 412 container.appendChild(this._swatch.element); |
| 413 this._range = this._swatch.element.createChild("span"); |
| 414 |
| 415 this._value = memoryCountersPane._currentValuesBar.createChild("span", "memo
ry-counter-value"); |
| 416 this._value.style.color = graphColor; |
| 417 this.graphColor = graphColor; |
| 418 this.strokeColor = graphColor; |
| 419 this.graphYValues = []; |
| 420 |
| 421 this._currentValueLabel = currentValueLabel; |
| 422 this._marker = memoryCountersPane._canvasContainer.createChild("div", "memor
y-counter-marker"); |
| 423 this._marker.style.backgroundColor = graphColor; |
| 424 this._clearCurrentValueAndMarker(); |
| 425 } |
| 426 |
| 427 WebInspector.CountersGraph.CounterUI.prototype = { |
| 428 reset: function() |
| 429 { |
| 430 this._range.textContent = ""; |
| 431 }, |
| 432 |
| 433 /** |
| 434 * @param {number} minValue |
| 435 * @param {number} maxValue |
| 436 */ |
| 437 setRange: function(minValue, maxValue) |
| 438 { |
| 439 this._range.textContent = WebInspector.UIString("[%d:%d]", minValue, max
Value); |
| 440 }, |
| 441 |
| 442 _toggleCounterGraph: function(event) |
| 443 { |
| 444 this._value.classList.toggle("hidden", !this._swatch.checked); |
| 445 this._memoryCountersPane.refresh(); |
| 446 }, |
| 447 |
| 448 /** |
| 449 * @param {number} x |
| 450 * @return {number} |
| 451 */ |
| 452 _recordIndexAt: function(x) |
| 453 { |
| 454 return this.counter.x.upperBound(x, null, this.counter._minimumIndex + 1
, this.counter._maximumIndex + 1) - 1; |
| 455 }, |
| 456 |
| 457 /** |
| 458 * @param {number} x |
| 459 */ |
| 460 updateCurrentValue: function(x) |
| 461 { |
| 462 if (!this.visible() || !this.counter.values.length) |
| 463 return; |
| 464 var index = this._recordIndexAt(x); |
| 465 this._value.textContent = WebInspector.UIString(this._currentValueLabel,
this.counter.values[index]); |
| 466 var y = this.graphYValues[index]; |
| 467 this._marker.style.left = x + "px"; |
| 468 this._marker.style.top = y + "px"; |
| 469 this._marker.classList.remove("hidden"); |
| 470 }, |
| 471 |
| 472 _clearCurrentValueAndMarker: function() |
| 473 { |
| 474 this._value.textContent = ""; |
| 475 this._marker.classList.add("hidden"); |
| 476 }, |
| 477 |
| 478 /** |
| 479 * @return {boolean} |
| 480 */ |
| 481 visible: function() |
| 482 { |
| 483 return this._swatch.checked; |
| 484 } |
| 485 } |
| 486 |
| 487 |
| 488 /** |
| 489 * @constructor |
| 490 * @extends {WebInspector.Object} |
| 491 */ |
| 492 WebInspector.SwatchCheckbox = function(title, color) |
| 493 { |
| 494 this.element = document.createElement("div"); |
| 495 this._swatch = this.element.createChild("div", "swatch"); |
| 496 this.element.createChild("span", "title").textContent = title; |
| 497 this._color = color; |
| 498 this.checked = true; |
| 499 |
| 500 this.element.addEventListener("click", this._toggleCheckbox.bind(this), true
); |
| 501 } |
| 502 |
| 503 WebInspector.SwatchCheckbox.Events = { |
| 504 Changed: "Changed" |
| 505 } |
| 506 |
| 507 WebInspector.SwatchCheckbox.prototype = { |
| 508 get checked() |
| 509 { |
| 510 return this._checked; |
| 511 }, |
| 512 |
| 513 set checked(v) |
| 514 { |
| 515 this._checked = v; |
| 516 if (this._checked) |
| 517 this._swatch.style.backgroundColor = this._color; |
| 518 else |
| 519 this._swatch.style.backgroundColor = ""; |
| 520 }, |
| 521 |
| 522 _toggleCheckbox: function(event) |
| 523 { |
| 524 this.checked = !this.checked; |
| 525 this.dispatchEventToListeners(WebInspector.SwatchCheckbox.Events.Changed
); |
| 526 }, |
| 527 |
| 528 __proto__: WebInspector.Object.prototype |
| 529 } |
OLD | NEW |