Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @constructor | 6 * @constructor |
| 7 * @extends {WebInspector.HBox} | 7 * @extends {WebInspector.HBox} |
| 8 */ | 8 */ |
| 9 WebInspector.FilmStripView = function() | 9 WebInspector.FilmStripView = function() |
| 10 { | 10 { |
| 11 WebInspector.HBox.call(this, true); | 11 WebInspector.HBox.call(this, true); |
| 12 this.registerRequiredCSS("components_lazy/filmStripView.css"); | 12 this.registerRequiredCSS("components_lazy/filmStripView.css"); |
| 13 this.contentElement.classList.add("film-strip-view"); | 13 this.contentElement.classList.add("film-strip-view"); |
| 14 this._mode = WebInspector.FilmStripView.Modes.TimeBased; | 14 this._framesContainer = this.contentElement.createChild("div", "frames-conta iner"); |
| 15 this.reset(); | 15 this.reset(); |
| 16 this.setMode(WebInspector.FilmStripView.Modes.TimeBased); | |
| 16 } | 17 } |
| 17 | 18 |
| 18 WebInspector.FilmStripView.Events = { | 19 WebInspector.FilmStripView.Events = { |
| 19 FrameSelected: "FrameSelected", | 20 FrameSelected: "FrameSelected", |
| 20 FrameEnter: "FrameEnter", | 21 FrameEnter: "FrameEnter", |
| 21 FrameExit: "FrameExit", | 22 FrameExit: "FrameExit", |
| 22 } | 23 } |
| 23 | 24 |
| 24 WebInspector.FilmStripView.Modes = { | 25 WebInspector.FilmStripView.Modes = { |
| 25 TimeBased: "TimeBased", | 26 TimeBased: "TimeBased", |
| 26 FrameBased: "FrameBased" | 27 FrameBased: "FrameBased" |
| 27 } | 28 } |
| 28 | 29 |
| 29 WebInspector.FilmStripView.prototype = { | 30 WebInspector.FilmStripView.prototype = { |
| 30 /** | 31 /** |
| 31 * @param {string} mode | 32 * @param {string} mode |
| 32 */ | 33 */ |
| 33 setMode: function(mode) | 34 setMode: function(mode) |
| 34 { | 35 { |
| 35 this._mode = mode; | 36 this._mode = mode; |
| 37 this.contentElement.classList.toggle("time-based", mode === WebInspector .FilmStripView.Modes.TimeBased); | |
| 36 this.update(); | 38 this.update(); |
| 37 }, | 39 }, |
| 38 | 40 |
| 39 /** | 41 /** |
| 40 * @param {!WebInspector.FilmStripModel} filmStripModel | 42 * @param {!WebInspector.FilmStripModel} filmStripModel |
| 41 * @param {number} zeroTime | 43 * @param {number} zeroTime |
| 42 * @param {number} spanTime | 44 * @param {number} spanTime |
| 43 */ | 45 */ |
| 44 setModel: function(filmStripModel, zeroTime, spanTime) | 46 setModel: function(filmStripModel, zeroTime, spanTime) |
| 45 { | 47 { |
| 46 this._model = filmStripModel; | 48 this._model = filmStripModel; |
| 47 this._zeroTime = zeroTime; | 49 this._zeroTime = zeroTime; |
| 48 this._spanTime = spanTime; | 50 this._spanTime = spanTime; |
| 49 var frames = filmStripModel.frames(); | 51 var frames = filmStripModel.frames(); |
| 50 if (!frames.length) { | 52 if (!frames.length) { |
| 51 this.reset(); | 53 this.reset(); |
| 52 return; | 54 return; |
| 53 } | 55 } |
| 54 this.update(); | 56 this.update(); |
| 55 }, | 57 }, |
| 56 | 58 |
| 57 update: function() | 59 /** |
| 60 * @param {number} index | |
| 61 * @return {!Element} | |
| 62 */ | |
| 63 frameElementByIndex: function(index) | |
| 58 { | 64 { |
| 59 if (!this._model) | 65 var element = this._elementsCache[index]; |
| 60 return; | 66 if (!element) { |
| 61 var frames = this._model.frames(); | 67 var frame = this._model.frames()[index]; |
|
caseq
2015/06/16 14:14:49
Is this method guaranteed to always be called afte
alph
2015/06/17 09:17:08
Yes. I can cover it with assert if you want.
| |
| 62 if (!frames.length) | |
| 63 return; | |
| 64 this.contentElement.removeChildren(); | |
| 65 this._label.remove(); | |
| 66 var zeroTime = this._zeroTime; | |
| 67 | |
| 68 /** | |
| 69 * @param {!WebInspector.FilmStripModel.Frame} frame | |
| 70 * @param {boolean=} skipTimeLabel | |
| 71 * @return {!Element} | |
| 72 * @this {WebInspector.FilmStripView} | |
| 73 */ | |
| 74 function createElementForFrame(frame, skipTimeLabel) | |
| 75 { | |
| 76 var time = frame.timestamp; | 68 var time = frame.timestamp; |
| 77 var element = createElementWithClass("div", "frame"); | 69 element = createElementWithClass("div", "frame"); |
| 78 element.createChild("div", "thumbnail").createChild("img").src = "da ta:image/jpg;base64," + frame.imageData; | 70 element.createChild("div", "thumbnail").createChild("img").src = "da ta:image/jpg;base64," + frame.imageData; |
| 79 if (!skipTimeLabel) | 71 element.createChild("div", "time").textContent = Number.millisToStri ng(time - this._zeroTime); |
| 80 element.createChild("div", "time").textContent = Number.millisTo String(time - zeroTime); | |
| 81 element.addEventListener("mousedown", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameSelected, time), false); | 72 element.addEventListener("mousedown", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameSelected, time), false); |
| 82 element.addEventListener("mouseenter", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameEnter, time), false); | 73 element.addEventListener("mouseenter", this._onMouseEvent.bind(this, WebInspector.FilmStripView.Events.FrameEnter, time), false); |
| 83 element.addEventListener("mouseout", this._onMouseEvent.bind(this, W ebInspector.FilmStripView.Events.FrameExit, time), false); | 74 element.addEventListener("mouseout", this._onMouseEvent.bind(this, W ebInspector.FilmStripView.Events.FrameExit, time), false); |
| 84 element.addEventListener("dblclick", this._onDoubleClick.bind(this, frame), false); | 75 element.addEventListener("dblclick", this._onDoubleClick.bind(this, frame), false); |
| 85 this.contentElement.appendChild(element); | 76 this._elementsCache[index] = element; |
| 86 return element; | |
| 87 } | 77 } |
| 78 return element; | |
| 79 }, | |
| 88 | 80 |
| 89 if (this._mode === WebInspector.FilmStripView.Modes.FrameBased) { | 81 /** |
| 90 for (var frame of frames) | 82 * @param {number} time |
| 91 createElementForFrame.call(this, frame); | 83 * @return {number} |
| 92 return; | 84 */ |
| 93 } | 85 frameIndexByTime: function(time) |
| 94 | 86 { |
| 95 /** | |
| 96 * @return {!Element} | |
| 97 * @this {WebInspector.FilmStripView} | |
| 98 */ | |
| 99 function createEmptyElement() | |
| 100 { | |
| 101 var element = createElementWithClass("div", "frame"); | |
| 102 this.contentElement.appendChild(element); | |
| 103 return element; | |
| 104 } | |
| 105 | |
| 106 /** | 87 /** |
| 107 * @param {number} time | 88 * @param {number} time |
| 108 * @param {!WebInspector.FilmStripModel.Frame} frame | 89 * @param {!WebInspector.FilmStripModel.Frame} frame |
| 109 * @return {number} | 90 * @return {number} |
| 110 */ | 91 */ |
| 111 function comparator(time, frame) | 92 function comparator(time, frame) |
| 112 { | 93 { |
| 113 return time - frame.timestamp; | 94 return time - frame.timestamp; |
| 114 } | 95 } |
| 96 // Using the first frame to fill the interval between recording start | |
| 97 // and a moment the frame is taken. | |
| 98 return Math.max(this._model.frames().upperBound(time, comparator) - 1, 0 ); | |
|
caseq
2015/06/16 14:14:49
ditto.
alph
2015/06/17 09:17:08
ditto.
| |
| 99 }, | |
| 115 | 100 |
| 116 var width = this.contentElement.clientWidth; | 101 update: function() |
| 102 { | |
| 103 if (!this._model) | |
| 104 return; | |
| 105 var frames = this._model.frames(); | |
| 106 if (!frames.length) | |
| 107 return; | |
| 108 this._framesContainer.removeChildren(); | |
| 109 this._label.remove(); | |
|
caseq
2015/06/16 14:14:49
nit: please remove label into something more descr
alph
2015/06/17 09:17:08
I actually didn't introduce this name, but ok rena
| |
| 110 | |
| 111 if (this._mode === WebInspector.FilmStripView.Modes.FrameBased) { | |
| 112 for (var i = 0; i < frames.length; ++i) | |
| 113 this._framesContainer.appendChild(this.frameElementByIndex(i).cl oneNode(true)); | |
|
caseq
2015/06/16 14:14:49
So what's the purpose of the cache if we're clonin
alph
2015/06/17 09:17:08
Popover uses cached versions directly.
| |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 var width = this._framesContainer.clientWidth; | |
| 117 var scale = this._spanTime / width; | 118 var scale = this._spanTime / width; |
| 118 | 119 var element0 = this.frameElementByIndex(0); // Calculate frame width ba sing on the first frame. |
| 119 // Calculate frame width basing on the first frame. | 120 var frameWidth = Math.ceil(WebInspector.measurePreferredSize(element0, t his.contentElement).width); |
| 120 var tempElement = createElementWithClass("div", "frame"); | |
| 121 tempElement.createChild("div", "thumbnail").createChild("img").src = "da ta:image/jpg;base64," + frames[0].imageData; | |
| 122 var frameWidth = Math.ceil(WebInspector.measurePreferredSize(tempElement , this.contentElement).width); | |
| 123 if (!frameWidth) | 121 if (!frameWidth) |
| 124 return; | 122 return; |
| 125 | 123 |
| 126 for (var pos = frameWidth; pos < width; pos += frameWidth) { | 124 for (var pos = frameWidth; pos < width; pos += frameWidth) { |
| 127 var time = pos * scale + zeroTime; | 125 var time = pos * scale + this._zeroTime; |
| 128 var index = frames.upperBound(time, comparator) - 1; | 126 var index = this.frameIndexByTime(time); |
| 129 var element = index >= 0 ? createElementForFrame.call(this, frames[i ndex], true) : createEmptyElement.call(this); | 127 var element = this._framesContainer.appendChild(this.frameElementByI ndex(index).cloneNode(true)); |
|
caseq
2015/06/16 14:14:49
ditto.
alph
2015/06/17 09:17:08
ditto.
| |
| 130 element.style.width = frameWidth + "px"; | 128 element.style.width = frameWidth + "px"; |
| 131 } | 129 } |
| 132 }, | 130 }, |
| 133 | 131 |
| 134 /** | 132 /** |
| 135 * @override | 133 * @override |
| 136 */ | 134 */ |
| 137 onResize: function() | 135 onResize: function() |
| 138 { | 136 { |
| 139 if (this._mode === WebInspector.FilmStripView.Modes.FrameBased) | 137 if (this._mode === WebInspector.FilmStripView.Modes.FrameBased) |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 154 * @param {!WebInspector.FilmStripModel.Frame} filmStripFrame | 152 * @param {!WebInspector.FilmStripModel.Frame} filmStripFrame |
| 155 */ | 153 */ |
| 156 _onDoubleClick: function(filmStripFrame) | 154 _onDoubleClick: function(filmStripFrame) |
| 157 { | 155 { |
| 158 WebInspector.Dialog.show(null, new WebInspector.FilmStripView.DialogDele gate(filmStripFrame, this._zeroTime)); | 156 WebInspector.Dialog.show(null, new WebInspector.FilmStripView.DialogDele gate(filmStripFrame, this._zeroTime)); |
| 159 }, | 157 }, |
| 160 | 158 |
| 161 reset: function() | 159 reset: function() |
| 162 { | 160 { |
| 163 this._zeroTime = 0; | 161 this._zeroTime = 0; |
| 164 this.contentElement.removeChildren(); | 162 this._elementsCache = []; |
| 165 this._label = this.contentElement.createChild("div", "label"); | 163 this._framesContainer.removeChildren(); |
| 164 this._label = this._framesContainer.createChild("div", "label"); | |
| 166 this._label.textContent = WebInspector.UIString("No frames recorded. Rel oad page to start recording."); | 165 this._label.textContent = WebInspector.UIString("No frames recorded. Rel oad page to start recording."); |
| 167 }, | 166 }, |
| 168 | 167 |
| 169 setRecording: function() | 168 setRecording: function() |
| 170 { | 169 { |
| 171 this.reset(); | 170 this.reset(); |
| 172 this._label.textContent = WebInspector.UIString("Recording frames..."); | 171 this._label.textContent = WebInspector.UIString("Recording frames..."); |
| 173 }, | 172 }, |
| 174 | 173 |
| 175 setFetching: function() | 174 setFetching: function() |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 | 278 |
| 280 _render: function() | 279 _render: function() |
| 281 { | 280 { |
| 282 var frame = this._frames[this._index]; | 281 var frame = this._frames[this._index]; |
| 283 this._imageElement.src = "data:image/jpg;base64," + frame.imageData; | 282 this._imageElement.src = "data:image/jpg;base64," + frame.imageData; |
| 284 this._timeLabel.textContent = Number.millisToString(frame.timestamp - th is._zeroTime); | 283 this._timeLabel.textContent = Number.millisToString(frame.timestamp - th is._zeroTime); |
| 285 }, | 284 }, |
| 286 | 285 |
| 287 __proto__: WebInspector.DialogDelegate.prototype | 286 __proto__: WebInspector.DialogDelegate.prototype |
| 288 } | 287 } |
| OLD | NEW |