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

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

Issue 2623743002: DevTools: extract modules (non-extensions) (Closed)
Patch Set: rebaseline Created 3 years, 11 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 * @unrestricted
6 */
7 UI.ChartViewport = class extends UI.VBox {
8 constructor() {
9 super(true);
10
11 this.viewportElement = this.contentElement.createChild('div', 'fill');
12 this.viewportElement.addEventListener('mousewheel', this._onMouseWheel.bind( this), false);
13 this.viewportElement.addEventListener('keydown', this._handleZoomPanKeys.bin d(this), false);
14
15 UI.installInertialDragHandle(
16 this.viewportElement, this._startDragging.bind(this), this._dragging.bin d(this), this._endDragging.bind(this),
17 '-webkit-grabbing', null);
18 UI.installDragHandle(
19 this.viewportElement, this._startRangeSelection.bind(this), this._rangeS electionDragging.bind(this),
20 this._endRangeSelection.bind(this), 'text', null);
21
22 this._alwaysShowVerticalScroll = false;
23 this._vScrollElement = this.contentElement.createChild('div', 'flame-chart-v -scroll');
24 this._vScrollContent = this._vScrollElement.createChild('div');
25 this._vScrollElement.addEventListener('scroll', this._onScroll.bind(this), f alse);
26
27 this._selectionOverlay = this.contentElement.createChild('div', 'flame-chart -selection-overlay hidden');
28 this._selectedTimeSpanLabel = this._selectionOverlay.createChild('div', 'tim e-span');
29
30 this.reset();
31 }
32
33 alwaysShowVerticalScroll() {
34 this._alwaysShowVerticalScroll = true;
35 this._vScrollElement.classList.add('always-show-scrollbar');
36 }
37
38 /**
39 * @return {boolean}
40 */
41 isDragging() {
42 return this._isDragging;
43 }
44
45 /**
46 * @override
47 * @return {!Array<!Element>}
48 */
49 elementsToRestoreScrollPositionsFor() {
50 return [this._vScrollElement];
51 }
52
53 /**
54 * @private
55 */
56 _updateScrollBar() {
57 const showScroll = this._alwaysShowVerticalScroll || this._totalHeight > thi s._offsetHeight;
58 if (this._vScrollElement.classList.contains('hidden') !== showScroll)
59 return;
60 this._vScrollElement.classList.toggle('hidden', !showScroll);
61 this._updateContentElementSize();
62 }
63
64 /**
65 * @override
66 */
67 onResize() {
68 this._updateScrollBar();
69 this._updateContentElementSize();
70 this.scheduleUpdate();
71 }
72
73 reset() {
74 this._vScrollElement.scrollTop = 0;
75 this._scrollTop = 0;
76 this._rangeSelectionStart = 0;
77 this._rangeSelectionEnd = 0;
78 this._isDragging = false;
79 this._dragStartPointX = 0;
80 this._dragStartPointY = 0;
81 this._dragStartScrollTop = 0;
82 this._timeWindowLeft = 0;
83 this._timeWindowRight = 0;
84 this._offsetWidth = 0;
85 this._offsetHeight = 0;
86 this._totalHeight = 0;
87 this._pendingAnimationTimeLeft = 0;
88 this._pendingAnimationTimeRight = 0;
89 }
90
91 /**
92 * @private
93 */
94 _updateContentElementSize() {
95 var offsetWidth = this._vScrollElement.offsetLeft;
96 if (!offsetWidth)
97 offsetWidth = this.contentElement.offsetWidth;
98 this._offsetWidth = offsetWidth;
99 this._offsetHeight = this.contentElement.offsetHeight;
100 }
101
102 setContentHeight(totalHeight) {
103 this._totalHeight = totalHeight;
104 this._vScrollContent.style.height = totalHeight + 'px';
105 this._updateScrollBar();
106 if (this._scrollTop + this._offsetHeight <= totalHeight)
107 return;
108 this._scrollTop = Math.max(0, totalHeight - this._offsetHeight);
109 this._vScrollElement.scrollTop = this._scrollTop;
110 }
111
112 /**
113 * @param {number} offset
114 * @param {number=} height
115 */
116 setScrollOffset(offset, height) {
117 height = height || 0;
118 if (this._vScrollElement.scrollTop > offset)
119 this._vScrollElement.scrollTop = offset;
120 else if (this._vScrollElement.scrollTop < offset - this._offsetHeight + heig ht)
121 this._vScrollElement.scrollTop = offset - this._offsetHeight + height;
122 }
123
124 /**
125 * @return {number}
126 */
127 getScrollOffset() {
128 return this._vScrollElement.scrollTop;
129 }
130
131 /**
132 * @param {!Event} e
133 * @private
134 */
135 _onMouseWheel(e) {
136 if (!this._enabled())
137 return;
138 // Pan vertically when shift down only.
139 var panVertically = e.shiftKey && (e.wheelDeltaY || Math.abs(e.wheelDeltaX) === 120);
140 var panHorizontally = Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY) && ! e.shiftKey;
141 if (panVertically) {
142 this._vScrollElement.scrollTop -= (e.wheelDeltaY || e.wheelDeltaX) / 120 * this._offsetHeight / 8;
143 } else if (panHorizontally) {
144 var shift = -e.wheelDeltaX * this._pixelToTime;
145 this._muteAnimation = true;
146 this._handlePanGesture(shift);
147 this._muteAnimation = false;
148 } else { // Zoom.
149 const mouseWheelZoomSpeed = 1 / 120;
150 this._handleZoomGesture(Math.pow(1.2, -(e.wheelDeltaY || e.wheelDeltaX) * mouseWheelZoomSpeed) - 1);
151 }
152
153 // Block swipe gesture.
154 e.consume(true);
155 }
156
157 /**
158 * @param {number} x
159 * @param {number} y
160 * @param {!MouseEvent} event
161 * @private
162 * @return {boolean}
163 */
164 _startDragging(x, y, event) {
165 if (event.shiftKey)
166 return false;
167 if (this._windowRight === Infinity)
168 return false;
169 this._isDragging = true;
170 this._initMaxDragOffset(event);
171 this._dragStartPointX = x;
172 this._dragStartPointY = y;
173 this._dragStartScrollTop = this._vScrollElement.scrollTop;
174 this.viewportElement.style.cursor = '';
175 this.hideHighlight();
176 return true;
177 }
178
179 /**
180 * @param {number} x
181 * @param {number} y
182 * @private
183 */
184 _dragging(x, y) {
185 var pixelShift = this._dragStartPointX - x;
186 this._dragStartPointX = x;
187 this._muteAnimation = true;
188 this._handlePanGesture(pixelShift * this._pixelToTime);
189 this._muteAnimation = false;
190
191 var pixelScroll = this._dragStartPointY - y;
192 this._vScrollElement.scrollTop = this._dragStartScrollTop + pixelScroll;
193 this._updateMaxDragOffset(x, y);
194 }
195
196 /**
197 * @private
198 */
199 _endDragging() {
200 this._isDragging = false;
201 this._updateHighlight();
202 }
203
204 /**
205 * @param {!MouseEvent} event
206 * @private
207 */
208 _initMaxDragOffset(event) {
209 this._maxDragOffsetSquared = 0;
210 this._dragStartX = event.pageX;
211 this._dragStartY = event.pageY;
212 }
213
214 /**
215 * @param {number} x
216 * @param {number} y
217 * @private
218 */
219 _updateMaxDragOffset(x, y) {
220 var dx = x - this._dragStartX;
221 var dy = y - this._dragStartY;
222 var dragOffsetSquared = dx * dx + dy * dy;
223 this._maxDragOffsetSquared = Math.max(this._maxDragOffsetSquared, dragOffset Squared);
224 }
225
226 /**
227 * @return {number}
228 */
229 maxDragOffset() {
230 return Math.sqrt(this._maxDragOffsetSquared);
231 }
232
233 /**
234 * @param {!MouseEvent} event
235 * @private
236 * @return {boolean}
237 */
238 _startRangeSelection(event) {
239 if (!event.shiftKey)
240 return false;
241 this._isDragging = true;
242 this._initMaxDragOffset(event);
243 this._selectionOffsetShiftX = event.offsetX - event.pageX;
244 this._selectionOffsetShiftY = event.offsetY - event.pageY;
245 this._selectionStartX = event.offsetX;
246 var style = this._selectionOverlay.style;
247 style.left = this._selectionStartX + 'px';
248 style.width = '1px';
249 this._selectedTimeSpanLabel.textContent = '';
250 this._selectionOverlay.classList.remove('hidden');
251 this.hideHighlight();
252 return true;
253 }
254
255 /**
256 * @private
257 */
258 _endRangeSelection() {
259 this._isDragging = false;
260 this._updateHighlight();
261 }
262
263 hideRangeSelection() {
264 this._selectionOverlay.classList.add('hidden');
265 }
266
267 /**
268 * @param {!MouseEvent} event
269 * @private
270 */
271 _rangeSelectionDragging(event) {
272 this._updateMaxDragOffset(event.pageX, event.pageY);
273 var x = Number.constrain(event.pageX + this._selectionOffsetShiftX, 0, this. _offsetWidth);
274 var start = this._cursorTime(this._selectionStartX);
275 var end = this._cursorTime(x);
276 this._rangeSelectionStart = Math.min(start, end);
277 this._rangeSelectionEnd = Math.max(start, end);
278 this._updateRangeSelectionOverlay();
279 this._flameChartDelegate.updateRangeSelection(this._rangeSelectionStart, thi s._rangeSelectionEnd);
280 }
281
282 /**
283 * @private
284 */
285 _updateRangeSelectionOverlay() {
286 var /** @const */ margin = 100;
287 var left = Number.constrain(this._timeToPosition(this._rangeSelectionStart), -margin, this._offsetWidth + margin);
288 var right = Number.constrain(this._timeToPosition(this._rangeSelectionEnd), -margin, this._offsetWidth + margin);
289 var style = this._selectionOverlay.style;
290 style.left = left + 'px';
291 style.width = (right - left) + 'px';
292 var timeSpan = this._rangeSelectionEnd - this._rangeSelectionStart;
293 this._selectedTimeSpanLabel.textContent = Number.preciseMillisToString(timeS pan, 2);
294 }
295
296 /**
297 * @private
298 */
299 _onScroll() {
300 this._scrollTop = this._vScrollElement.scrollTop;
301 this.scheduleUpdate();
302 }
303
304 /**
305 * @param {!Event} e
306 * @private
307 */
308 _handleZoomPanKeys(e) {
309 if (!UI.KeyboardShortcut.hasNoModifiers(e))
310 return;
311 var zoomMultiplier = e.shiftKey ? 0.8 : 0.3;
312 var panMultiplier = e.shiftKey ? 320 : 80;
313 if (e.code === 'KeyA') {
314 this._handlePanGesture(-panMultiplier * this._pixelToTime);
315 e.consume(true);
316 } else if (e.code === 'KeyD') {
317 this._handlePanGesture(panMultiplier * this._pixelToTime);
318 e.consume(true);
319 } else if (e.code === 'KeyW') {
320 this._handleZoomGesture(-zoomMultiplier);
321 e.consume(true);
322 } else if (e.code === 'KeyS') {
323 this._handleZoomGesture(zoomMultiplier);
324 e.consume(true);
325 }
326 }
327
328 /**
329 * @param {number} zoom
330 * @private
331 */
332 _handleZoomGesture(zoom) {
333 this._cancelAnimation();
334 var bounds = this._windowForGesture();
335 var cursorTime = this._cursorTime(this._lastMouseOffsetX);
336 bounds.left += (bounds.left - cursorTime) * zoom;
337 bounds.right += (bounds.right - cursorTime) * zoom;
338 this._requestWindowTimes(bounds);
339 }
340
341 /**
342 * @param {number} shift
343 * @private
344 */
345 _handlePanGesture(shift) {
346 this._cancelAnimation();
347 var bounds = this._windowForGesture();
348 shift = Number.constrain(
349 shift, this._minimumBoundary - bounds.left, this._totalTime + this._mini mumBoundary - bounds.right);
350 bounds.left += shift;
351 bounds.right += shift;
352 this._requestWindowTimes(bounds);
353 }
354
355 /**
356 * @private
357 * @return {{left: number, right: number}}
358 */
359 _windowForGesture() {
360 var windowLeft = this._timeWindowLeft ? this._timeWindowLeft : this._dataPro vider.minimumBoundary();
361 var windowRight = this._timeWindowRight !== Infinity ?
362 this._timeWindowRight :
363 this._dataProvider.minimumBoundary() + this._dataProvider.totalTime();
364 return {left: windowLeft, right: windowRight};
365 }
366
367 /**
368 * @param {{left: number, right: number}} bounds
369 * @private
370 */
371 _requestWindowTimes(bounds) {
372 bounds.left = Number.constrain(bounds.left, this._minimumBoundary, this._tot alTime + this._minimumBoundary);
373 bounds.right = Number.constrain(bounds.right, this._minimumBoundary, this._t otalTime + this._minimumBoundary);
374 if (bounds.right - bounds.left < UI.FlameChart.MinimalTimeWindowMs)
375 return;
376 this._flameChartDelegate.requestWindowTimes(bounds.left, bounds.right);
377 }
378
379 /**
380 * @param {number} startTime
381 * @param {number} endTime
382 * @private
383 */
384 _animateWindowTimes(startTime, endTime) {
385 this._timeWindowLeft = startTime;
386 this._timeWindowRight = endTime;
387 this._updateHighlight();
388 this.update();
389 }
390
391 /**
392 * @private
393 */
394 _animationCompleted() {
395 delete this._cancelWindowTimesAnimation;
396 this._updateHighlight();
397 }
398
399 /**
400 * @private
401 */
402 _cancelAnimation() {
403 if (!this._cancelWindowTimesAnimation)
404 return;
405 this._timeWindowLeft = this._pendingAnimationTimeLeft;
406 this._timeWindowRight = this._pendingAnimationTimeRight;
407 this._cancelWindowTimesAnimation();
408 delete this._cancelWindowTimesAnimation;
409 }
410
411 scheduleUpdate() {
412 if (this._updateTimerId || this._cancelWindowTimesAnimation)
413 return;
414 this._updateTimerId = this.element.window().requestAnimationFrame(() => {
415 this._updateTimerId = 0;
416 this.update();
417 });
418 }
419
420 update() {
421 }
422
423 /**
424 * @param {number} startTime
425 * @param {number} endTime
426 */
427 setWindowTimes(startTime, endTime) {
428 this.hideRangeSelection();
429 if (this._muteAnimation || this._timeWindowLeft === 0 || this._timeWindowRig ht === Infinity ||
430 (startTime === 0 && endTime === Infinity) || (startTime === Infinity && endTime === Infinity)) {
431 // Initial setup.
432 this._timeWindowLeft = startTime;
433 this._timeWindowRight = endTime;
434 this.scheduleUpdate();
435 return;
436 }
437 this._cancelAnimation();
438 this._cancelWindowTimesAnimation = UI.animateFunction(
439 this.element.window(), this._animateWindowTimes.bind(this),
440 [{from: this._timeWindowLeft, to: startTime}, {from: this._timeWindowRig ht, to: endTime}], 5,
441 this._animationCompleted.bind(this));
442 this._pendingAnimationTimeLeft = startTime;
443 this._pendingAnimationTimeRight = endTime;
444 }
445 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698