Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/ui_lazy/ChartViewport.js

Issue 2423283002: DevTools: Extract ChartViewport out of FlameChart. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @constructor
7 * @extends {WebInspector.VBox}
8 */
9 WebInspector.ChartViewport = function()
10 {
11 WebInspector.VBox.call(this, true);
12
13 this.contentElement.addEventListener("mousewheel", this._onMouseWheel.bind(t his), false);
14 this.contentElement.addEventListener("keydown", this._handleZoomPanKeys.bind (this), false);
15
16 WebInspector.installInertialDragHandle(this.contentElement, this._startDragg ing.bind(this), this._dragging.bind(this), this._endDragging.bind(this), "-webki t-grabbing", null);
17 WebInspector.installDragHandle(this.contentElement, this._startRangeSelectio n.bind(this), this._rangeSelectionDragging.bind(this), this._endRangeSelection.b ind(this), "text", null);
18
19 /** @private */
20 this._vScrollElement = this.contentElement.createChild("div", "flame-chart-v -scroll");
21 this._vScrollContent = this._vScrollElement.createChild("div");
22 this._vScrollElement.addEventListener("scroll", this._onScroll.bind(this), f alse);
23
24 /** @private */
25 this._selectionOverlay = this.contentElement.createChild("div", "flame-chart -selection-overlay hidden");
26 /** @private */
27 this._selectedTimeSpanLabel = this._selectionOverlay.createChild("div", "tim e-span");
28
29 this.reset();
30 }
31
32 WebInspector.ChartViewport.prototype = {
33 /**
34 * @return {boolean}
35 */
36 isDragging: function()
37 {
38 return this._isDragging;
39 },
40
41 /**
42 * @override
43 * @return {!Array<!Element>}
44 */
45 elementsToRestoreScrollPositionsFor: function()
46 {
47 return [this._vScrollElement];
48 },
49
50 /**
51 * @private
52 */
53 _updateScrollBar: function()
54 {
55 var showScroll = this._totalHeight > this._offsetHeight;
56 if (this._vScrollElement.classList.contains("hidden") === showScroll) {
57 this._vScrollElement.classList.toggle("hidden", !showScroll);
58 this._updateContentElementSize();
59 }
60 },
61
62 /**
63 * @override
64 */
65 onResize: function()
66 {
67 this._updateScrollBar();
68 this._updateContentElementSize();
69 this.scheduleUpdate();
70 },
71
72 reset: function()
73 {
74 this._vScrollElement.scrollTop = 0;
75 /** @private */
76 this._scrollTop = 0;
77 /** @private */
78 this._rangeSelectionStart = 0;
79 /** @private */
80 this._rangeSelectionEnd = 0;
81 /** @private */
82 this._scrollTop = 0;
83 /** @private */
84 this._isDragging = false;
85 /** @private */
86 this._dragStartPointX = 0;
87 /** @private */
88 this._dragStartPointY = 0;
89 /** @private */
90 this._dragStartScrollTop = 0;
91 /** @private */
92 this._timeWindowLeft = 0;
93 /** @private */
94 this._timeWindowRight = 0;
95 /** @private */
96 this._offsetWidth = 0;
97 /** @private */
98 this._offsetHeight = 0;
99 /** @private */
100 this._totalHeight = 0;
101 /** @private */
102 this._pendingAnimationTimeLeft = 0;
103 /** @private */
104 this._pendingAnimationTimeRight = 0;
105 },
106
107 /**
108 * @private
109 */
110 _updateContentElementSize: function()
111 {
112 var offsetWidth = this._vScrollElement.offsetLeft;
113 if (!offsetWidth)
114 offsetWidth = this.contentElement.offsetWidth;
115 this._offsetWidth = offsetWidth;
116 this._offsetHeight = this.contentElement.offsetHeight;
117 },
118
119 setContentHeight: function(totalHeight)
120 {
121 this._totalHeight = totalHeight;
122 this._vScrollContent.style.height = totalHeight + "px";
123 if (this._scrollTop + this._offsetHeight <= totalHeight)
124 return;
125 this._scrollTop = Math.max(0, totalHeight - this._offsetHeight);
126 this._vScrollElement.scrollTop = this._scrollTop;
127 },
128
129 /**
130 * @param {number} offset
131 * @param {number=} height
132 */
133 setScrollOffset: function(offset, height)
134 {
135 height = height || 0;
136 if (this._vScrollElement.scrollTop > offset)
137 this._vScrollElement.scrollTop = offset;
138 else if (this._vScrollElement.scrollTop < offset - this._offsetHeight + height)
139 this._vScrollElement.scrollTop = offset - this._offsetHeight + heigh t;
140 },
141
142 /**
143 * @return {number}
144 */
145 scrollOffset: function()
146 {
147 return this._vScrollElement.scrollTop;
148 },
149
150 /**
151 * @param {!Event} e
152 * @private
153 */
154 _onMouseWheel: function(e)
155 {
156 if (!this._enabled())
157 return;
158 // Pan vertically when shift down only.
159 var panVertically = e.shiftKey && (e.wheelDeltaY || Math.abs(e.wheelDelt aX) === 120);
160 var panHorizontally = Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY) && !e.shiftKey;
161 if (panVertically) {
162 this._vScrollElement.scrollTop -= (e.wheelDeltaY || e.wheelDeltaX) / 120 * this._offsetHeight / 8;
163 } else if (panHorizontally) {
164 var shift = -e.wheelDeltaX * this._pixelToTime;
165 this._muteAnimation = true;
166 this._handlePanGesture(shift);
167 this._muteAnimation = false;
168 } else { // Zoom.
169 const mouseWheelZoomSpeed = 1 / 120;
170 this._handleZoomGesture(Math.pow(1.2, -(e.wheelDeltaY || e.wheelDelt aX) * mouseWheelZoomSpeed) - 1);
171 }
172
173 // Block swipe gesture.
174 e.consume(true);
175 },
176
177 /**
178 * @param {number} x
179 * @param {number} y
180 * @param {!MouseEvent} event
181 * @private
182 * @return {boolean}
183 */
184 _startDragging: function(x, y, event)
185 {
186 if (event.shiftKey)
187 return false;
188 if (this._windowRight === Infinity)
189 return false;
190 this._isDragging = true;
191 this._initMaxDragOffset(event);
192 this._dragStartPointX = x;
193 this._dragStartPointY = y;
194 this._dragStartScrollTop = this._vScrollElement.scrollTop;
195 this.contentElement.style.cursor = "";
196 this.hideHighlight();
197 return true;
198 },
199
200 /**
201 * @param {number} x
202 * @param {number} y
203 * @private
204 */
205 _dragging: function(x, y)
206 {
207 var pixelShift = this._dragStartPointX - x;
208 this._dragStartPointX = x;
209 this._muteAnimation = true;
210 this._handlePanGesture(pixelShift * this._pixelToTime);
211 this._muteAnimation = false;
212
213 var pixelScroll = this._dragStartPointY - y;
214 this._vScrollElement.scrollTop = this._dragStartScrollTop + pixelScroll;
215 this._updateMaxDragOffset(x, y);
216 },
217
218 /**
219 * @private
220 */
221 _endDragging: function()
222 {
223 this._isDragging = false;
224 this._updateHighlight();
225 },
226
227 /**
228 * @param {!MouseEvent} event
229 * @private
230 */
231 _initMaxDragOffset: function(event)
232 {
233 this._maxDragOffsetSquared = 0;
234 this._dragStartX = event.pageX;
235 this._dragStartY = event.pageY;
236 },
237
238 /**
239 * @param {number} x
240 * @param {number} y
241 * @private
242 */
243 _updateMaxDragOffset: function(x, y)
244 {
245 var dx = x - this._dragStartX;
246 var dy = y - this._dragStartY;
247 var dragOffsetSquared = dx * dx + dy * dy;
248 this._maxDragOffsetSquared = Math.max(this._maxDragOffsetSquared, dragOf fsetSquared);
249 },
250
251 /**
252 * @return {number}
253 */
254 maxDragOffset: function()
255 {
256 return Math.sqrt(this._maxDragOffsetSquared);
257 },
258
259 /**
260 * @param {!MouseEvent} event
261 * @private
262 * @return {boolean}
263 */
264 _startRangeSelection: function(event)
265 {
266 if (!event.shiftKey)
267 return false;
268 this._isDragging = true;
269 this._initMaxDragOffset(event);
270 this._selectionOffsetShiftX = event.offsetX - event.pageX;
271 this._selectionOffsetShiftY = event.offsetY - event.pageY;
272 this._selectionStartX = event.offsetX;
273 var style = this._selectionOverlay.style;
274 style.left = this._selectionStartX + "px";
275 style.width = "1px";
276 this._selectedTimeSpanLabel.textContent = "";
277 this._selectionOverlay.classList.remove("hidden");
278 this.hideHighlight();
279 return true;
280 },
281
282 /**
283 * @private
284 */
285 _endRangeSelection: function()
286 {
287 this._isDragging = false;
288 this._updateHighlight();
289 },
290
291 hideRangeSelection: function()
292 {
293 this._selectionOverlay.classList.add("hidden");
294 },
295
296 /**
297 * @param {!MouseEvent} event
298 * @private
299 */
300 _rangeSelectionDragging: function(event)
301 {
302 this._updateMaxDragOffset(event.pageX, event.pageY);
303 var x = Number.constrain(event.pageX + this._selectionOffsetShiftX, 0, t his._offsetWidth);
304 var start = this._cursorTime(this._selectionStartX);
305 var end = this._cursorTime(x);
306 this._rangeSelectionStart = Math.min(start, end);
307 this._rangeSelectionEnd = Math.max(start, end);
308 this._updateRangeSelectionOverlay();
309 this._flameChartDelegate.updateRangeSelection(this._rangeSelectionStart, this._rangeSelectionEnd);
310 },
311
312 /**
313 * @private
314 */
315 _updateRangeSelectionOverlay: function()
316 {
317 var /** @const */ margin = 100;
318 var left = Number.constrain(this._timeToPosition(this._rangeSelectionSta rt), -margin, this._offsetWidth + margin);
319 var right = Number.constrain(this._timeToPosition(this._rangeSelectionEn d), -margin, this._offsetWidth + margin);
320 var style = this._selectionOverlay.style;
321 style.left = left + "px";
322 style.width = (right - left) + "px";
323 var timeSpan = this._rangeSelectionEnd - this._rangeSelectionStart;
324 this._selectedTimeSpanLabel.textContent = Number.preciseMillisToString(t imeSpan, 2);
325 },
326
327 /**
328 * @private
329 */
330 _onScroll: function()
331 {
332 this._scrollTop = this._vScrollElement.scrollTop;
333 this.scheduleUpdate();
334 },
335
336 /**
337 * @param {!Event} e
338 * @private
339 */
340 _handleZoomPanKeys: function(e)
341 {
342 if (!WebInspector.KeyboardShortcut.hasNoModifiers(e))
343 return;
344 var zoomMultiplier = e.shiftKey ? 0.8 : 0.3;
345 var panMultiplier = e.shiftKey ? 320 : 80;
346 if (e.keyCode === "A".charCodeAt(0)) {
347 this._handlePanGesture(-panMultiplier * this._pixelToTime);
348 e.consume(true);
349 } else if (e.keyCode === "D".charCodeAt(0)) {
350 this._handlePanGesture(panMultiplier * this._pixelToTime);
351 e.consume(true);
352 } else if (e.keyCode === "W".charCodeAt(0)) {
353 this._handleZoomGesture(-zoomMultiplier);
354 e.consume(true);
355 } else if (e.keyCode === "S".charCodeAt(0)) {
356 this._handleZoomGesture(zoomMultiplier);
357 e.consume(true);
358 }
359 },
360
361 /**
362 * @param {number} zoom
363 * @private
364 */
365 _handleZoomGesture: function(zoom)
366 {
367 this._cancelAnimation();
368 var bounds = this._windowForGesture();
369 var cursorTime = this._cursorTime(this._lastMouseOffsetX);
370 bounds.left += (bounds.left - cursorTime) * zoom;
371 bounds.right += (bounds.right - cursorTime) * zoom;
372 this._requestWindowTimes(bounds);
373 },
374
375 /**
376 * @param {number} shift
377 * @private
378 */
379 _handlePanGesture: function(shift)
380 {
381 this._cancelAnimation();
382 var bounds = this._windowForGesture();
383 shift = Number.constrain(shift, this._minimumBoundary - bounds.left, thi s._totalTime + this._minimumBoundary - bounds.right);
384 bounds.left += shift;
385 bounds.right += shift;
386 this._requestWindowTimes(bounds);
387 },
388
389 /**
390 * @private
391 * @return {{left: number, right: number}}
392 */
393 _windowForGesture: function()
394 {
395 var windowLeft = this._timeWindowLeft ? this._timeWindowLeft : this._dat aProvider.minimumBoundary();
396 var windowRight = this._timeWindowRight !== Infinity ? this._timeWindowR ight : this._dataProvider.minimumBoundary() + this._dataProvider.totalTime();
397 return {left: windowLeft, right: windowRight};
398 },
399
400 /**
401 * @param {{left: number, right: number}} bounds
402 * @private
403 */
404 _requestWindowTimes: function(bounds)
405 {
406 bounds.left = Number.constrain(bounds.left, this._minimumBoundary, this. _totalTime + this._minimumBoundary);
407 bounds.right = Number.constrain(bounds.right, this._minimumBoundary, thi s._totalTime + this._minimumBoundary);
408 if (bounds.right - bounds.left < WebInspector.FlameChart.MinimalTimeWind owMs)
409 return;
410 this._flameChartDelegate.requestWindowTimes(bounds.left, bounds.right);
411 },
412
413 /**
414 * @param {number} startTime
415 * @param {number} endTime
416 * @private
417 */
418 _animateWindowTimes: function(startTime, endTime)
419 {
420 this._timeWindowLeft = startTime;
421 this._timeWindowRight = endTime;
422 this._updateHighlight();
423 this.update();
424 },
425
426 /**
427 * @private
428 */
429 _animationCompleted: function()
430 {
431 delete this._cancelWindowTimesAnimation;
432 this._updateHighlight();
433 },
434
435 /**
436 * @private
437 */
438 _cancelAnimation: function()
439 {
440 if (this._cancelWindowTimesAnimation) {
441 this._timeWindowLeft = this._pendingAnimationTimeLeft;
442 this._timeWindowRight = this._pendingAnimationTimeRight;
443 this._cancelWindowTimesAnimation();
444 delete this._cancelWindowTimesAnimation;
445 }
446 },
447
448 scheduleUpdate: function()
449 {
450 if (this._updateTimerId || this._cancelWindowTimesAnimation)
451 return;
452 this._updateTimerId = this.element.window().requestAnimationFrame(() => {
453 this._updateTimerId = 0;
454 this.update();
455 });
456 },
457
458 update: function() {},
459
460 /**
461 * @param {number} startTime
462 * @param {number} endTime
463 */
464 setWindowTimes: function(startTime, endTime)
465 {
466 if (this._muteAnimation || this._timeWindowLeft === 0 || this._timeWindo wRight === Infinity || (startTime === 0 && endTime === Infinity) || (startTime = == Infinity && endTime === Infinity)) {
467 // Initial setup.
468 this._timeWindowLeft = startTime;
469 this._timeWindowRight = endTime;
470 this.scheduleUpdate();
471 return;
472 }
473 this._cancelAnimation();
474 this._cancelWindowTimesAnimation = WebInspector.animateFunction(this.ele ment.window(), this._animateWindowTimes.bind(this),
475 [{from: this._timeWindowLeft, to: startTime}, {from: this._timeWindo wRight, to: endTime}], 5,
476 this._animationCompleted.bind(this));
477 this._pendingAnimationTimeLeft = startTime;
478 this._pendingAnimationTimeRight = endTime;
479 },
480
481 __proto__: WebInspector.VBox.prototype
482 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698