| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 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. | |
| 29 */ | |
| 30 | |
| 31 /** | |
| 32 * @constructor | |
| 33 * @extends {WebInspector.VBox} | |
| 34 */ | |
| 35 WebInspector.TimelineOverviewPane = function() | |
| 36 { | |
| 37 WebInspector.VBox.call(this); | |
| 38 this.element.id = "timeline-overview-pane"; | |
| 39 | |
| 40 this._overviewCalculator = new WebInspector.TimelineOverviewCalculator(); | |
| 41 this._overviewCalculator._setWindow(0, 1000); | |
| 42 | |
| 43 this._overviewGrid = new WebInspector.OverviewGrid("timeline"); | |
| 44 this.element.appendChild(this._overviewGrid.element); | |
| 45 | |
| 46 this._overviewGrid.setResizeEnabled(false); | |
| 47 this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowC
hanged, this._onWindowChanged, this); | |
| 48 this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.Click,
this._onClick, this); | |
| 49 this._overviewControls = []; | |
| 50 this._markers = new Map(); | |
| 51 } | |
| 52 | |
| 53 WebInspector.TimelineOverviewPane.Events = { | |
| 54 WindowChanged: "WindowChanged", | |
| 55 SelectionChanged: "SelectionChanged" | |
| 56 }; | |
| 57 | |
| 58 WebInspector.TimelineOverviewPane.prototype = { | |
| 59 /** | |
| 60 * @override | |
| 61 */ | |
| 62 wasShown: function() | |
| 63 { | |
| 64 this.update(); | |
| 65 }, | |
| 66 | |
| 67 /** | |
| 68 * @override | |
| 69 */ | |
| 70 onResize: function() | |
| 71 { | |
| 72 this.update(); | |
| 73 }, | |
| 74 | |
| 75 /** | |
| 76 * @param {!Array.<!WebInspector.TimelineOverview>} overviewControls | |
| 77 */ | |
| 78 setOverviewControls: function(overviewControls) | |
| 79 { | |
| 80 for (var i = 0; i < this._overviewControls.length; ++i) | |
| 81 this._overviewControls[i].dispose(); | |
| 82 | |
| 83 for (var i = 0; i < overviewControls.length; ++i) { | |
| 84 overviewControls[i].show(this._overviewGrid.element); | |
| 85 if (this._currentSelection) | |
| 86 overviewControls[i].select(this._currentSelection); | |
| 87 } | |
| 88 this._overviewControls = overviewControls; | |
| 89 this.update(); | |
| 90 }, | |
| 91 | |
| 92 /** | |
| 93 * @param {number} minimumBoundary | |
| 94 * @param {number} maximumBoundary | |
| 95 */ | |
| 96 setBounds: function(minimumBoundary, maximumBoundary) | |
| 97 { | |
| 98 this._overviewCalculator._setWindow(minimumBoundary, maximumBoundary); | |
| 99 this._overviewGrid.setResizeEnabled(true); | |
| 100 }, | |
| 101 | |
| 102 update: function() | |
| 103 { | |
| 104 if (!this.isShowing()) | |
| 105 return; | |
| 106 this._overviewCalculator._setDisplayWindow(0, this._overviewGrid.clientW
idth()); | |
| 107 for (var i = 0; i < this._overviewControls.length; ++i) | |
| 108 this._overviewControls[i].update(); | |
| 109 this._overviewGrid.updateDividers(this._overviewCalculator); | |
| 110 this._updateMarkers(); | |
| 111 this._updateWindow(); | |
| 112 }, | |
| 113 | |
| 114 /** | |
| 115 * @param {?WebInspector.TimelineSelection} selection | |
| 116 */ | |
| 117 select: function(selection) | |
| 118 { | |
| 119 this._currentSelection = selection; | |
| 120 for (var overviewControl of this._overviewControls) | |
| 121 overviewControl.select(selection); | |
| 122 }, | |
| 123 | |
| 124 /** | |
| 125 * @param {!Map<number, !Element>} markers | |
| 126 */ | |
| 127 setMarkers: function(markers) | |
| 128 { | |
| 129 this._markers = markers; | |
| 130 this._updateMarkers(); | |
| 131 }, | |
| 132 | |
| 133 _updateMarkers: function() | |
| 134 { | |
| 135 var filteredMarkers = new Map(); | |
| 136 for (var time of this._markers.keys()) { | |
| 137 var marker = this._markers.get(time); | |
| 138 var position = Math.round(this._overviewCalculator.computePosition(t
ime)); | |
| 139 // Limit the number of markers to one per pixel. | |
| 140 if (filteredMarkers.has(position)) | |
| 141 continue; | |
| 142 filteredMarkers.set(position, marker); | |
| 143 marker.style.left = position + "px"; | |
| 144 } | |
| 145 this._overviewGrid.removeEventDividers(); | |
| 146 this._overviewGrid.addEventDividers(filteredMarkers.valuesArray()); | |
| 147 }, | |
| 148 | |
| 149 reset: function() | |
| 150 { | |
| 151 this._overviewCalculator.reset(); | |
| 152 this._overviewGrid.reset(); | |
| 153 this._overviewGrid.setResizeEnabled(false); | |
| 154 this._overviewGrid.updateDividers(this._overviewCalculator); | |
| 155 this._markers = new Map(); | |
| 156 for (var i = 0; i < this._overviewControls.length; ++i) | |
| 157 this._overviewControls[i].reset(); | |
| 158 this.update(); | |
| 159 }, | |
| 160 | |
| 161 /** | |
| 162 * @param {!WebInspector.Event} event | |
| 163 */ | |
| 164 _onClick: function(event) | |
| 165 { | |
| 166 var domEvent = /** @type {!Event} */ (event.data); | |
| 167 var selection; | |
| 168 for (var overviewControl of this._overviewControls) { | |
| 169 selection = overviewControl.selectionFromEvent(domEvent); | |
| 170 if (selection) | |
| 171 break; | |
| 172 } | |
| 173 if (typeof selection !== "object") | |
| 174 return; | |
| 175 event.preventDefault(); | |
| 176 this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.S
electionChanged, selection); | |
| 177 }, | |
| 178 | |
| 179 /** | |
| 180 * @param {!WebInspector.Event} event | |
| 181 */ | |
| 182 _onWindowChanged: function(event) | |
| 183 { | |
| 184 if (this._muteOnWindowChanged) | |
| 185 return; | |
| 186 // Always use first control as a time converter. | |
| 187 if (!this._overviewControls.length) | |
| 188 return; | |
| 189 var windowTimes = this._overviewControls[0].windowTimes(this._overviewGr
id.windowLeft(), this._overviewGrid.windowRight()); | |
| 190 this._windowStartTime = windowTimes.startTime; | |
| 191 this._windowEndTime = windowTimes.endTime; | |
| 192 this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.W
indowChanged, windowTimes); | |
| 193 }, | |
| 194 | |
| 195 /** | |
| 196 * @param {number} startTime | |
| 197 * @param {number} endTime | |
| 198 */ | |
| 199 requestWindowTimes: function(startTime, endTime) | |
| 200 { | |
| 201 if (startTime === this._windowStartTime && endTime === this._windowEndTi
me) | |
| 202 return; | |
| 203 this._windowStartTime = startTime; | |
| 204 this._windowEndTime = endTime; | |
| 205 this._updateWindow(); | |
| 206 this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.W
indowChanged, { startTime: startTime, endTime: endTime }); | |
| 207 }, | |
| 208 | |
| 209 _updateWindow: function() | |
| 210 { | |
| 211 if (!this._overviewControls.length) | |
| 212 return; | |
| 213 var windowBoundaries = this._overviewControls[0].windowBoundaries(this._
windowStartTime, this._windowEndTime); | |
| 214 this._muteOnWindowChanged = true; | |
| 215 this._overviewGrid.setWindow(windowBoundaries.left, windowBoundaries.rig
ht); | |
| 216 this._muteOnWindowChanged = false; | |
| 217 }, | |
| 218 | |
| 219 __proto__: WebInspector.VBox.prototype | |
| 220 } | |
| 221 | |
| 222 /** | |
| 223 * @constructor | |
| 224 * @implements {WebInspector.TimelineGrid.Calculator} | |
| 225 */ | |
| 226 WebInspector.TimelineOverviewCalculator = function() | |
| 227 { | |
| 228 } | |
| 229 | |
| 230 WebInspector.TimelineOverviewCalculator.prototype = { | |
| 231 /** | |
| 232 * @override | |
| 233 * @return {number} | |
| 234 */ | |
| 235 paddingLeft: function() | |
| 236 { | |
| 237 return this._paddingLeft; | |
| 238 }, | |
| 239 | |
| 240 /** | |
| 241 * @override | |
| 242 * @param {number} time | |
| 243 * @return {number} | |
| 244 */ | |
| 245 computePosition: function(time) | |
| 246 { | |
| 247 return (time - this._minimumBoundary) / this.boundarySpan() * this._work
ingArea + this._paddingLeft; | |
| 248 }, | |
| 249 | |
| 250 /** | |
| 251 * @param {number=} minimumRecordTime | |
| 252 * @param {number=} maximumRecordTime | |
| 253 */ | |
| 254 _setWindow: function(minimumRecordTime, maximumRecordTime) | |
| 255 { | |
| 256 this._minimumBoundary = minimumRecordTime; | |
| 257 this._maximumBoundary = maximumRecordTime; | |
| 258 }, | |
| 259 | |
| 260 /** | |
| 261 * @param {number} paddingLeft | |
| 262 * @param {number} clientWidth | |
| 263 */ | |
| 264 _setDisplayWindow: function(paddingLeft, clientWidth) | |
| 265 { | |
| 266 this._workingArea = clientWidth - paddingLeft; | |
| 267 this._paddingLeft = paddingLeft; | |
| 268 }, | |
| 269 | |
| 270 reset: function() | |
| 271 { | |
| 272 this._setWindow(0, 1000); | |
| 273 }, | |
| 274 | |
| 275 /** | |
| 276 * @override | |
| 277 * @param {number} value | |
| 278 * @param {number=} precision | |
| 279 * @return {string} | |
| 280 */ | |
| 281 formatTime: function(value, precision) | |
| 282 { | |
| 283 return Number.preciseMillisToString(value - this.zeroTime(), precision); | |
| 284 }, | |
| 285 | |
| 286 /** | |
| 287 * @override | |
| 288 * @return {number} | |
| 289 */ | |
| 290 maximumBoundary: function() | |
| 291 { | |
| 292 return this._maximumBoundary; | |
| 293 }, | |
| 294 | |
| 295 /** | |
| 296 * @override | |
| 297 * @return {number} | |
| 298 */ | |
| 299 minimumBoundary: function() | |
| 300 { | |
| 301 return this._minimumBoundary; | |
| 302 }, | |
| 303 | |
| 304 /** | |
| 305 * @override | |
| 306 * @return {number} | |
| 307 */ | |
| 308 zeroTime: function() | |
| 309 { | |
| 310 return this._minimumBoundary; | |
| 311 }, | |
| 312 | |
| 313 /** | |
| 314 * @override | |
| 315 * @return {number} | |
| 316 */ | |
| 317 boundarySpan: function() | |
| 318 { | |
| 319 return this._maximumBoundary - this._minimumBoundary; | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 /** | |
| 324 * @interface | |
| 325 */ | |
| 326 WebInspector.TimelineOverview = function(model) | |
| 327 { | |
| 328 } | |
| 329 | |
| 330 WebInspector.TimelineOverview.prototype = { | |
| 331 /** | |
| 332 * @param {?Element} parentElement | |
| 333 * @param {!Element=} insertBefore | |
| 334 */ | |
| 335 show: function(parentElement, insertBefore) { }, | |
| 336 | |
| 337 update: function() { }, | |
| 338 | |
| 339 dispose: function() { }, | |
| 340 | |
| 341 reset: function() { }, | |
| 342 | |
| 343 /** | |
| 344 * @param {!WebInspector.TimelineSelection} selection | |
| 345 */ | |
| 346 select: function(selection) { }, | |
| 347 | |
| 348 /** | |
| 349 * @param {!Event} event | |
| 350 * @return {?WebInspector.TimelineSelection|undefined} | |
| 351 */ | |
| 352 selectionFromEvent: function(event) { }, | |
| 353 | |
| 354 /** | |
| 355 * @param {number} windowLeft | |
| 356 * @param {number} windowRight | |
| 357 * @return {!{startTime: number, endTime: number}} | |
| 358 */ | |
| 359 windowTimes: function(windowLeft, windowRight) { }, | |
| 360 | |
| 361 /** | |
| 362 * @param {number} startTime | |
| 363 * @param {number} endTime | |
| 364 * @return {!{left: number, right: number}} | |
| 365 */ | |
| 366 windowBoundaries: function(startTime, endTime) { }, | |
| 367 | |
| 368 timelineStarted: function() { }, | |
| 369 | |
| 370 timelineStopped: function() { }, | |
| 371 } | |
| 372 | |
| 373 /** | |
| 374 * @constructor | |
| 375 * @extends {WebInspector.VBox} | |
| 376 * @implements {WebInspector.TimelineOverview} | |
| 377 * @param {!WebInspector.TimelineModel} model | |
| 378 */ | |
| 379 WebInspector.TimelineOverviewBase = function(model) | |
| 380 { | |
| 381 WebInspector.VBox.call(this); | |
| 382 | |
| 383 this._model = model; | |
| 384 this._canvas = this.element.createChild("canvas", "fill"); | |
| 385 this._context = this._canvas.getContext("2d"); | |
| 386 } | |
| 387 | |
| 388 WebInspector.TimelineOverviewBase.prototype = { | |
| 389 /** | |
| 390 * @override | |
| 391 */ | |
| 392 update: function() | |
| 393 { | |
| 394 this.resetCanvas(); | |
| 395 }, | |
| 396 | |
| 397 /** | |
| 398 * @override | |
| 399 */ | |
| 400 dispose: function() | |
| 401 { | |
| 402 this.detach(); | |
| 403 }, | |
| 404 | |
| 405 /** | |
| 406 * @override | |
| 407 */ | |
| 408 reset: function() | |
| 409 { | |
| 410 }, | |
| 411 | |
| 412 /** | |
| 413 * @override | |
| 414 */ | |
| 415 timelineStarted: function() | |
| 416 { | |
| 417 }, | |
| 418 | |
| 419 /** | |
| 420 * @override | |
| 421 */ | |
| 422 timelineStopped: function() | |
| 423 { | |
| 424 }, | |
| 425 | |
| 426 /** | |
| 427 * @override | |
| 428 * @param {!WebInspector.TimelineSelection} selection | |
| 429 */ | |
| 430 select: function(selection) { }, | |
| 431 | |
| 432 /** | |
| 433 * @override | |
| 434 * @param {!Event} event | |
| 435 * @return {?WebInspector.TimelineSelection|undefined} | |
| 436 */ | |
| 437 selectionFromEvent: function(event) | |
| 438 { | |
| 439 return undefined; | |
| 440 }, | |
| 441 | |
| 442 /** | |
| 443 * @override | |
| 444 * @param {number} windowLeft | |
| 445 * @param {number} windowRight | |
| 446 * @return {!{startTime: number, endTime: number}} | |
| 447 */ | |
| 448 windowTimes: function(windowLeft, windowRight) | |
| 449 { | |
| 450 var absoluteMin = this._model.minimumRecordTime(); | |
| 451 var timeSpan = this._model.maximumRecordTime() - absoluteMin; | |
| 452 return { | |
| 453 startTime: absoluteMin + timeSpan * windowLeft, | |
| 454 endTime: absoluteMin + timeSpan * windowRight | |
| 455 }; | |
| 456 }, | |
| 457 | |
| 458 /** | |
| 459 * @override | |
| 460 * @param {number} startTime | |
| 461 * @param {number} endTime | |
| 462 * @return {!{left: number, right: number}} | |
| 463 */ | |
| 464 windowBoundaries: function(startTime, endTime) | |
| 465 { | |
| 466 var absoluteMin = this._model.minimumRecordTime(); | |
| 467 var timeSpan = this._model.maximumRecordTime() - absoluteMin; | |
| 468 var haveRecords = absoluteMin > 0; | |
| 469 return { | |
| 470 left: haveRecords && startTime ? Math.min((startTime - absoluteMin)
/ timeSpan, 1) : 0, | |
| 471 right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) /
timeSpan : 1 | |
| 472 }; | |
| 473 }, | |
| 474 | |
| 475 resetCanvas: function() | |
| 476 { | |
| 477 this._canvas.width = this.element.clientWidth * window.devicePixelRatio; | |
| 478 this._canvas.height = this.element.clientHeight * window.devicePixelRati
o; | |
| 479 }, | |
| 480 | |
| 481 __proto__: WebInspector.VBox.prototype | |
| 482 } | |
| OLD | NEW |