2 * Copyright 2014 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
9 * @extends {WebInspector.Object}
10 * @param {!Element} element
11 * @param {boolean=} disableRotate
13 WebInspector.TransformController = function(element, disableRotate)
16 this.element = element;
17 if (this.element.tabIndex < 0)
18 this.element.tabIndex = 0;
19 this._registerShortcuts();
20 WebInspector.installDragHandle(element, this._onDragStart.bind(this), this._onDrag.bind(this), this._onDragEnd.bind(this), "move", null);
21 element.addEventListener("keydown", this._onKeyDown.bind(this), false);
22 element.addEventListener("keyup", this._onKeyUp.bind(this), false);
23 element.addEventListener("mousewheel", this._onMouseWheel.bind(this), false);
24 this._disableRotate = disableRotate;
26 this._maxScale = Infinity;
28 this._controlPanelElement = createElement("div");
29 this._controlPanelElement.classList.add("transform-control-panel");
31 this._modeButtons = {};
33 var panModeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pan mode (X)"), "transform-mode-pan");
34 panModeButton.addEventListener("click", this._setMode.bind(this, WebInspector.TransformController.Modes.Pan));
35 this._modeButtons[WebInspector.TransformController.Modes.Pan] = panModeButton;
36 this._controlPanelElement.appendChild(panModeButton.element);
37 var rotateModeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Rotate mode (V)"), "transform-mode-rotate");
38 rotateModeButton.addEventListener("click", this._setMode.bind(this, WebInspector.TransformController.Modes.Rotate));
39 this._modeButtons[WebInspector.TransformController.Modes.Rotate] = rotateModeButton;
40 this._controlPanelElement.appendChild(rotateModeButton.element);
42 this._setMode(WebInspector.TransformController.Modes.Pan);
44 var resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Reset transform (0)"), "transform-reset");
45 resetButton.addEventListener("click", this.resetAndNotify.bind(this, undefined));
46 this._controlPanelElement.appendChild(resetButton.element);
54 WebInspector.TransformController.Events = {
55 TransformChanged: "TransformChanged"
61 WebInspector.TransformController.Modes = {
66 WebInspector.TransformController.prototype = {
70 controlPanelElement: function()
72 return this._controlPanelElement;
75 _onKeyDown: function(event)
77 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Shift.code) {
82 var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEventIgnoringModifiers(event);
83 var handler = this._shortcuts[shortcutKey];
84 if (handler && handler(event))
88 _onKeyUp: function(event)
90 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Shift.code)
94 _addShortcuts: function(keys, handler)
96 for (var i = 0; i < keys.length; ++i)
97 this._shortcuts[keys[i].key] = handler;
100 _registerShortcuts: function()
102 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.ResetView, this.resetAndNotify.bind(this));
103 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.PanMode, this._setMode.bind(this, WebInspector.TransformController.Modes.Pan));
104 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.RotateMode, this._setMode.bind(this, WebInspector.TransformController.Modes.Rotate));
105 var zoomFactor = 1.1;
106 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.ZoomIn, this._onKeyboardZoom.bind(this, zoomFactor));
107 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.ZoomOut, this._onKeyboardZoom.bind(this, 1 / zoomFactor));
108 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Up, this._onKeyboardPanOrRotate.bind(this, 0, -1));
109 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Down, this._onKeyboardPanOrRotate.bind(this, 0, 1));
110 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Left, this._onKeyboardPanOrRotate.bind(this, -1, 0));
111 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Right, this._onKeyboardPanOrRotate.bind(this, 1, 0));
114 _postChangeEvent: function()
116 this.dispatchEventToListeners(WebInspector.TransformController.Events.TransformChanged);
128 _toggleMode: function()
130 this._setMode(this._mode === WebInspector.TransformController.Modes.Pan ? WebInspector.TransformController.Modes.Rotate : WebInspector.TransformController.Modes.Pan);
134 * @param {!WebInspector.TransformController.Modes} mode
136 _setMode: function(mode)
138 if (this._mode === mode)
141 this._updateModeButtons();
142 this.element.focus();
145 _updateModeButtons: function()
147 for (var mode in this._modeButtons)
148 this._modeButtons[mode].toggled = (mode === this._mode);
152 * @param {!Event=} event
154 resetAndNotify: function(event)
157 this._postChangeEvent();
159 event.preventDefault();
160 this.element.focus();
164 * @param {number} minScale
165 * @param {number} maxScale
167 setScaleConstraints: function(minScale, maxScale)
169 this._minScale = minScale;
170 this._maxScale = maxScale;
171 this._scale = Number.constrain(this._scale, minScale, maxScale);
175 * @param {number} minX
176 * @param {number} maxX
177 * @param {number} minY
178 * @param {number} maxY
180 clampOffsets: function(minX, maxX, minY, maxY)
182 this._offsetX = Number.constrain(this._offsetX, minX, maxX);
183 this._offsetY = Number.constrain(this._offsetY, minY, maxY);
199 return this._offsetX;
207 return this._offsetY;
215 return this._rotateX;
223 return this._rotateY;
227 * @param {number} scaleFactor
231 _onScale: function(scaleFactor, x, y)
233 scaleFactor = Number.constrain(this._scale * scaleFactor, this._minScale, this._maxScale) / this._scale;
234 this._scale *= scaleFactor;
235 this._offsetX -= (x - this._offsetX) * (scaleFactor - 1);
236 this._offsetY -= (y - this._offsetY) * (scaleFactor - 1);
237 this._postChangeEvent();
241 * @param {number} offsetX
242 * @param {number} offsetY
244 _onPan: function(offsetX, offsetY)
246 this._offsetX += offsetX;
247 this._offsetY += offsetY;
248 this._postChangeEvent();
252 * @param {number} rotateX
253 * @param {number} rotateY
255 _onRotate: function(rotateX, rotateY)
257 this._rotateX = rotateX;
258 this._rotateY = rotateY;
259 this._postChangeEvent();
263 * @param {number} zoomFactor
265 _onKeyboardZoom: function(zoomFactor)
267 this._onScale(zoomFactor, this.element.clientWidth / 2, this.element.clientHeight / 2);
271 * @param {number} xMultiplier
272 * @param {number} yMultiplier
274 _onKeyboardPanOrRotate: function(xMultiplier, yMultiplier)
276 var panStepInPixels = 6;
277 var rotateStepInDegrees = 5;
279 if (this._mode === WebInspector.TransformController.Modes.Rotate) {
280 // Sic! _onRotate treats X and Y as "rotate around X" and "rotate around Y", so swap X/Y multiplers.
281 this._onRotate(this._rotateX + yMultiplier * rotateStepInDegrees, this._rotateY + xMultiplier * rotateStepInDegrees);
283 this._onPan(xMultiplier * panStepInPixels, yMultiplier * panStepInPixels);
288 * @param {!Event} event
290 _onMouseWheel: function(event)
293 var zoomFactor = 1.1;
295 var mouseWheelZoomSpeed = 1 / 120;
296 var scaleFactor = Math.pow(zoomFactor, event.wheelDeltaY * mouseWheelZoomSpeed);
297 this._onScale(scaleFactor, event.clientX - this.element.totalOffsetLeft(), event.clientY - this.element.totalOffsetTop());
301 * @param {!Event} event
303 _onDrag: function(event)
305 if (this._mode === WebInspector.TransformController.Modes.Rotate) {
306 this._onRotate(this._oldRotateX + (this._originY - event.clientY) / this.element.clientHeight * 180, this._oldRotateY - (this._originX - event.clientX) / this.element.clientWidth * 180);
308 this._onPan(event.clientX - this._originX, event.clientY - this._originY);
309 this._originX = event.clientX;
310 this._originY = event.clientY;
315 * @param {!MouseEvent} event
317 _onDragStart: function(event)
319 this.element.focus();
320 this._originX = event.clientX;
321 this._originY = event.clientY;
322 this._oldRotateX = this._rotateX;
323 this._oldRotateY = this._rotateY;
327 _onDragEnd: function()
329 delete this._originX;
330 delete this._originY;
331 delete this._oldRotateX;
332 delete this._oldRotateY;
335 __proto__: WebInspector.Object.prototype