2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @param {string} prefix
35 WebInspector
.OverviewGrid = function(prefix
)
37 this.element
= createElement("div");
38 this.element
.id
= prefix
+ "-overview-container";
40 this._grid
= new WebInspector
.TimelineGrid();
41 this._grid
.element
.id
= prefix
+ "-overview-grid";
42 this._grid
.setScrollTop(0);
44 this.element
.appendChild(this._grid
.element
);
46 this._window
= new WebInspector
.OverviewGrid
.Window(this.element
, this._grid
.dividersLabelBarElement
);
49 WebInspector
.OverviewGrid
.prototype = {
53 clientWidth: function()
55 return this.element
.clientWidth
;
59 * @param {!WebInspector.TimelineGrid.Calculator} calculator
61 updateDividers: function(calculator
)
63 this._grid
.updateDividers(calculator
);
67 * @param {!Array.<!Element>} dividers
69 addEventDividers: function(dividers
)
71 this._grid
.addEventDividers(dividers
);
74 removeEventDividers: function()
76 this._grid
.removeEventDividers();
87 windowLeft: function()
89 return this._window
.windowLeft
;
95 windowRight: function()
97 return this._window
.windowRight
;
101 * @param {number} left
102 * @param {number} right
104 setWindow: function(left
, right
)
106 this._window
._setWindow(left
, right
);
110 * @param {string} eventType
111 * @param {function(!WebInspector.Event)} listener
112 * @param {!Object=} thisObject
114 addEventListener: function(eventType
, listener
, thisObject
)
116 this._window
.addEventListener(eventType
, listener
, thisObject
);
120 * @param {number} zoomFactor
121 * @param {number} referencePoint
123 zoom: function(zoomFactor
, referencePoint
)
125 this._window
._zoom(zoomFactor
, referencePoint
);
129 * @param {boolean} enabled
131 setResizeEnabled: function(enabled
)
133 this._window
.setEnabled(enabled
);
138 WebInspector
.OverviewGrid
.MinSelectableSize
= 14;
140 WebInspector
.OverviewGrid
.WindowScrollSpeedFactor
= .3;
142 WebInspector
.OverviewGrid
.ResizerOffset
= 3.5; // half pixel because offset values are not rounded but ceiled
146 * @extends {WebInspector.Object}
147 * @param {!Element} parentElement
148 * @param {!Element=} dividersLabelBarElement
150 WebInspector
.OverviewGrid
.Window = function(parentElement
, dividersLabelBarElement
)
152 this._parentElement
= parentElement
;
154 WebInspector
.installDragHandle(this._parentElement
, this._startWindowSelectorDragging
.bind(this), this._windowSelectorDragging
.bind(this), this._endWindowSelectorDragging
.bind(this), "text", null);
155 if (dividersLabelBarElement
)
156 WebInspector
.installDragHandle(dividersLabelBarElement
, this._startWindowDragging
.bind(this), this._windowDragging
.bind(this), null, "-webkit-grabbing", "-webkit-grab");
158 this.windowLeft
= 0.0;
159 this.windowRight
= 1.0;
161 this._parentElement
.addEventListener("mousewheel", this._onMouseWheel
.bind(this), true);
162 this._parentElement
.addEventListener("dblclick", this._resizeWindowMaximum
.bind(this), true);
164 this._overviewWindowElement
= parentElement
.createChild("div", "overview-grid-window");
165 this._overviewWindowElement
.appendChild(WebInspector
.Widget
.createStyleElement("ui_lazy/overviewGrid.css"));
166 this._overviewWindowBordersElement
= parentElement
.createChild("div", "overview-grid-window-rulers");
167 parentElement
.createChild("div", "overview-grid-dividers-background");
169 this._leftResizeElement
= parentElement
.createChild("div", "overview-grid-window-resizer");
170 this._leftResizeElement
.style
.left
= 0;
171 WebInspector
.installDragHandle(this._leftResizeElement
, this._resizerElementStartDragging
.bind(this), this._leftResizeElementDragging
.bind(this), null, "ew-resize");
173 this._rightResizeElement
= parentElement
.createChild("div", "overview-grid-window-resizer overview-grid-window-resizer-right");
174 this._rightResizeElement
.style
.right
= 0;
175 WebInspector
.installDragHandle(this._rightResizeElement
, this._resizerElementStartDragging
.bind(this), this._rightResizeElementDragging
.bind(this), null, "ew-resize");
176 this.setEnabled(true);
179 WebInspector
.OverviewGrid
.Events
= {
180 WindowChanged
: "WindowChanged",
184 WebInspector
.OverviewGrid
.Window
.prototype = {
187 this.windowLeft
= 0.0;
188 this.windowRight
= 1.0;
190 this._overviewWindowElement
.style
.left
= "0%";
191 this._overviewWindowElement
.style
.width
= "100%";
192 this._overviewWindowBordersElement
.style
.left
= "0%";
193 this._overviewWindowBordersElement
.style
.right
= "0%";
194 this._leftResizeElement
.style
.left
= "0%";
195 this._rightResizeElement
.style
.left
= "100%";
196 this.setEnabled(true);
200 * @param {boolean} enabled
202 setEnabled: function(enabled
)
204 this._enabled
= enabled
;
208 * @param {!Event} event
210 _resizerElementStartDragging: function(event
)
214 this._resizerParentOffsetLeft
= event
.pageX
- event
.offsetX
- event
.target
.offsetLeft
;
215 event
.preventDefault();
220 * @param {!Event} event
222 _leftResizeElementDragging: function(event
)
224 this._resizeWindowLeft(event
.pageX
- this._resizerParentOffsetLeft
);
225 event
.preventDefault();
229 * @param {!Event} event
231 _rightResizeElementDragging: function(event
)
233 this._resizeWindowRight(event
.pageX
- this._resizerParentOffsetLeft
);
234 event
.preventDefault();
238 * @param {!Event} event
241 _startWindowSelectorDragging: function(event
)
245 this._offsetLeft
= this._parentElement
.totalOffsetLeft();
246 var position
= event
.x
- this._offsetLeft
;
247 this._overviewWindowSelector
= new WebInspector
.OverviewGrid
.WindowSelector(this._parentElement
, position
);
252 * @param {!Event} event
254 _windowSelectorDragging: function(event
)
256 this._overviewWindowSelector
._updatePosition(event
.x
- this._offsetLeft
);
257 event
.preventDefault();
261 * @param {!Event} event
263 _endWindowSelectorDragging: function(event
)
265 var window
= this._overviewWindowSelector
._close(event
.x
- this._offsetLeft
);
266 delete this._overviewWindowSelector
;
267 var clickThreshold
= 3;
268 if (window
.end
- window
.start
< clickThreshold
) {
269 if (this.dispatchEventToListeners(WebInspector
.OverviewGrid
.Events
.Click
, event
))
271 var middle
= window
.end
;
272 window
.start
= Math
.max(0, middle
- WebInspector
.OverviewGrid
.MinSelectableSize
/ 2);
273 window
.end
= Math
.min(this._parentElement
.clientWidth
, middle
+ WebInspector
.OverviewGrid
.MinSelectableSize
/ 2);
274 } else if (window
.end
- window
.start
< WebInspector
.OverviewGrid
.MinSelectableSize
) {
275 if (this._parentElement
.clientWidth
- window
.end
> WebInspector
.OverviewGrid
.MinSelectableSize
)
276 window
.end
= window
.start
+ WebInspector
.OverviewGrid
.MinSelectableSize
;
278 window
.start
= window
.end
- WebInspector
.OverviewGrid
.MinSelectableSize
;
280 this._setWindowPosition(window
.start
, window
.end
);
284 * @param {!Event} event
287 _startWindowDragging: function(event
)
289 this._dragStartPoint
= event
.pageX
;
290 this._dragStartLeft
= this.windowLeft
;
291 this._dragStartRight
= this.windowRight
;
296 * @param {!Event} event
298 _windowDragging: function(event
)
300 event
.preventDefault();
301 var delta
= (event
.pageX
- this._dragStartPoint
) / this._parentElement
.clientWidth
;
302 if (this._dragStartLeft
+ delta
< 0)
303 delta
= -this._dragStartLeft
;
305 if (this._dragStartRight
+ delta
> 1)
306 delta
= 1 - this._dragStartRight
;
308 this._setWindow(this._dragStartLeft
+ delta
, this._dragStartRight
+ delta
);
312 * @param {number} start
314 _resizeWindowLeft: function(start
)
319 else if (start
> this._rightResizeElement
.offsetLeft
- 4)
320 start
= this._rightResizeElement
.offsetLeft
- 4;
321 this._setWindowPosition(start
, null);
325 * @param {number} end
327 _resizeWindowRight: function(end
)
330 if (end
> this._parentElement
.clientWidth
- 10)
331 end
= this._parentElement
.clientWidth
;
332 else if (end
< this._leftResizeElement
.offsetLeft
+ WebInspector
.OverviewGrid
.MinSelectableSize
)
333 end
= this._leftResizeElement
.offsetLeft
+ WebInspector
.OverviewGrid
.MinSelectableSize
;
334 this._setWindowPosition(null, end
);
337 _resizeWindowMaximum: function()
339 this._setWindowPosition(0, this._parentElement
.clientWidth
);
343 * @param {number} windowLeft
344 * @param {number} windowRight
346 _setWindow: function(windowLeft
, windowRight
)
348 var left
= windowLeft
;
349 var right
= windowRight
;
350 var width
= windowRight
- windowLeft
;
352 // We allow actual time window to be arbitrarily small but don't want the UI window to be too small.
353 var widthInPixels
= width
* this._parentElement
.clientWidth
;
354 var minWidthInPixels
= WebInspector
.OverviewGrid
.MinSelectableSize
/ 2;
355 if (widthInPixels
< minWidthInPixels
) {
356 var factor
= minWidthInPixels
/ widthInPixels
;
357 left
= ((windowRight
+ windowLeft
) - width
* factor
) / 2;
358 right
= ((windowRight
+ windowLeft
) + width
* factor
) / 2;
361 this.windowLeft
= windowLeft
;
362 this._leftResizeElement
.style
.left
= left
* 100 + "%";
363 this.windowRight
= windowRight
;
364 this._rightResizeElement
.style
.left
= right
* 100 + "%";
366 this._overviewWindowElement
.style
.left
= left
* 100 + "%";
367 this._overviewWindowBordersElement
.style
.left
= left
* 100 + "%";
368 this._overviewWindowElement
.style
.width
= (right
- left
) * 100 + "%";
369 this._overviewWindowBordersElement
.style
.right
= (1 - right
) * 100 + "%";
371 this.dispatchEventToListeners(WebInspector
.OverviewGrid
.Events
.WindowChanged
);
375 * @param {?number} start
376 * @param {?number} end
378 _setWindowPosition: function(start
, end
)
380 var clientWidth
= this._parentElement
.clientWidth
;
381 var windowLeft
= typeof start
=== "number" ? start
/ clientWidth
: this.windowLeft
;
382 var windowRight
= typeof end
=== "number" ? end
/ clientWidth
: this.windowRight
;
383 this._setWindow(windowLeft
, windowRight
);
387 * @param {!Event} event
389 _onMouseWheel: function(event
)
393 if (typeof event
.wheelDeltaY
=== "number" && event
.wheelDeltaY
) {
394 const zoomFactor
= 1.1;
395 const mouseWheelZoomSpeed
= 1 / 120;
397 var reference
= event
.offsetX
/ event
.target
.clientWidth
;
398 this._zoom(Math
.pow(zoomFactor
, -event
.wheelDeltaY
* mouseWheelZoomSpeed
), reference
);
400 if (typeof event
.wheelDeltaX
=== "number" && event
.wheelDeltaX
) {
401 var offset
= Math
.round(event
.wheelDeltaX
* WebInspector
.OverviewGrid
.WindowScrollSpeedFactor
);
402 var windowLeft
= this._leftResizeElement
.offsetLeft
+ WebInspector
.OverviewGrid
.ResizerOffset
;
403 var windowRight
= this._rightResizeElement
.offsetLeft
+ WebInspector
.OverviewGrid
.ResizerOffset
;
405 if (windowLeft
- offset
< 0)
408 if (windowRight
- offset
> this._parentElement
.clientWidth
)
409 offset
= windowRight
- this._parentElement
.clientWidth
;
411 this._setWindowPosition(windowLeft
- offset
, windowRight
- offset
);
413 event
.preventDefault();
418 * @param {number} factor
419 * @param {number} reference
421 _zoom: function(factor
, reference
)
423 var left
= this.windowLeft
;
424 var right
= this.windowRight
;
425 var windowSize
= right
- left
;
426 var newWindowSize
= factor
* windowSize
;
427 if (newWindowSize
> 1) {
429 factor
= newWindowSize
/ windowSize
;
431 left
= reference
+ (left
- reference
) * factor
;
432 left
= Number
.constrain(left
, 0, 1 - newWindowSize
);
434 right
= reference
+ (right
- reference
) * factor
;
435 right
= Number
.constrain(right
, newWindowSize
, 1);
436 this._setWindow(left
, right
);
439 __proto__
: WebInspector
.Object
.prototype
445 WebInspector
.OverviewGrid
.WindowSelector = function(parent
, position
)
447 this._startPosition
= position
;
448 this._width
= parent
.offsetWidth
;
449 this._windowSelector
= createElement("div");
450 this._windowSelector
.className
= "overview-grid-window-selector";
451 this._windowSelector
.style
.left
= this._startPosition
+ "px";
452 this._windowSelector
.style
.right
= this._width
- this._startPosition
+ "px";
453 parent
.appendChild(this._windowSelector
);
456 WebInspector
.OverviewGrid
.WindowSelector
.prototype = {
457 _close: function(position
)
459 position
= Math
.max(0, Math
.min(position
, this._width
));
460 this._windowSelector
.remove();
461 return this._startPosition
< position
? {start
: this._startPosition
, end
: position
} : {start
: position
, end
: this._startPosition
};
464 _updatePosition: function(position
)
466 position
= Math
.max(0, Math
.min(position
, this._width
));
467 if (position
< this._startPosition
) {
468 this._windowSelector
.style
.left
= position
+ "px";
469 this._windowSelector
.style
.right
= this._width
- this._startPosition
+ "px";
471 this._windowSelector
.style
.left
= this._startPosition
+ "px";
472 this._windowSelector
.style
.right
= this._width
- position
+ "px";