| OLD | NEW |
| (Empty) |
| 1 /* | |
| 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. | |
| 5 */ | |
| 6 | |
| 7 /** | |
| 8 * @constructor | |
| 9 * @extends {WebInspector.Object} | |
| 10 * @param {!Element} element | |
| 11 * @param {boolean=} disableRotate | |
| 12 */ | |
| 13 WebInspector.TransformController = function(element, disableRotate) | |
| 14 { | |
| 15 this._shortcuts = {}; | |
| 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._minScale = 0; | |
| 25 this._maxScale = Infinity; | |
| 26 | |
| 27 this._controlPanelToolbar = new WebInspector.Toolbar("transform-control-pane
l"); | |
| 28 | |
| 29 /** @type {!Object<string, !WebInspector.ToolbarToggle>} */ | |
| 30 this._modeButtons = {}; | |
| 31 if (!disableRotate) { | |
| 32 var panModeButton = new WebInspector.ToolbarToggle(WebInspector.UIString
("Pan mode (X)"), "pan-toolbar-item"); | |
| 33 panModeButton.addEventListener("click", this._setMode.bind(this, WebInsp
ector.TransformController.Modes.Pan)); | |
| 34 this._modeButtons[WebInspector.TransformController.Modes.Pan] = panModeB
utton; | |
| 35 this._controlPanelToolbar.appendToolbarItem(panModeButton); | |
| 36 var rotateModeButton = new WebInspector.ToolbarToggle(WebInspector.UIStr
ing("Rotate mode (V)"), "rotate-toolbar-item"); | |
| 37 rotateModeButton.addEventListener("click", this._setMode.bind(this, WebI
nspector.TransformController.Modes.Rotate)); | |
| 38 this._modeButtons[WebInspector.TransformController.Modes.Rotate] = rotat
eModeButton; | |
| 39 this._controlPanelToolbar.appendToolbarItem(rotateModeButton); | |
| 40 } | |
| 41 this._setMode(WebInspector.TransformController.Modes.Pan); | |
| 42 | |
| 43 var resetButton = new WebInspector.ToolbarButton(WebInspector.UIString("Rese
t transform (0)"), "center-toolbar-item"); | |
| 44 resetButton.addEventListener("click", this.resetAndNotify.bind(this, undefin
ed)); | |
| 45 this._controlPanelToolbar.appendToolbarItem(resetButton); | |
| 46 | |
| 47 this._reset(); | |
| 48 } | |
| 49 | |
| 50 /** @enum {symbol} */ | |
| 51 WebInspector.TransformController.Events = { | |
| 52 TransformChanged: Symbol("TransformChanged") | |
| 53 } | |
| 54 | |
| 55 /** | |
| 56 * @enum {string} | |
| 57 */ | |
| 58 WebInspector.TransformController.Modes = { | |
| 59 Pan: "Pan", | |
| 60 Rotate: "Rotate", | |
| 61 } | |
| 62 | |
| 63 WebInspector.TransformController.prototype = { | |
| 64 /** | |
| 65 * @return {!WebInspector.Toolbar} | |
| 66 */ | |
| 67 toolbar: function() | |
| 68 { | |
| 69 return this._controlPanelToolbar; | |
| 70 }, | |
| 71 | |
| 72 _onKeyDown: function(event) | |
| 73 { | |
| 74 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Shift.code) { | |
| 75 this._toggleMode(); | |
| 76 return; | |
| 77 } | |
| 78 | |
| 79 var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEventIgnoring
Modifiers(event); | |
| 80 var handler = this._shortcuts[shortcutKey]; | |
| 81 if (handler && handler(event)) | |
| 82 event.consume(); | |
| 83 }, | |
| 84 | |
| 85 _onKeyUp: function(event) | |
| 86 { | |
| 87 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Shift.code) | |
| 88 this._toggleMode(); | |
| 89 }, | |
| 90 | |
| 91 _addShortcuts: function(keys, handler) | |
| 92 { | |
| 93 for (var i = 0; i < keys.length; ++i) | |
| 94 this._shortcuts[keys[i].key] = handler; | |
| 95 }, | |
| 96 | |
| 97 _registerShortcuts: function() | |
| 98 { | |
| 99 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Res
etView, this.resetAndNotify.bind(this)); | |
| 100 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Pan
Mode, this._setMode.bind(this, WebInspector.TransformController.Modes.Pan)); | |
| 101 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Rot
ateMode, this._setMode.bind(this, WebInspector.TransformController.Modes.Rotate)
); | |
| 102 var zoomFactor = 1.1; | |
| 103 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Zoo
mIn, this._onKeyboardZoom.bind(this, zoomFactor)); | |
| 104 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Zoo
mOut, this._onKeyboardZoom.bind(this, 1 / zoomFactor)); | |
| 105 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Up,
this._onKeyboardPanOrRotate.bind(this, 0, -1)); | |
| 106 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Dow
n, this._onKeyboardPanOrRotate.bind(this, 0, 1)); | |
| 107 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Lef
t, this._onKeyboardPanOrRotate.bind(this, -1, 0)); | |
| 108 this._addShortcuts(WebInspector.ShortcutsScreen.LayersPanelShortcuts.Rig
ht, this._onKeyboardPanOrRotate.bind(this, 1, 0)); | |
| 109 }, | |
| 110 | |
| 111 _postChangeEvent: function() | |
| 112 { | |
| 113 this.dispatchEventToListeners(WebInspector.TransformController.Events.Tr
ansformChanged); | |
| 114 }, | |
| 115 | |
| 116 _reset: function() | |
| 117 { | |
| 118 this._scale = 1; | |
| 119 this._offsetX = 0; | |
| 120 this._offsetY = 0; | |
| 121 this._rotateX = 0; | |
| 122 this._rotateY = 0; | |
| 123 }, | |
| 124 | |
| 125 _toggleMode: function() | |
| 126 { | |
| 127 this._setMode(this._mode === WebInspector.TransformController.Modes.Pan
? WebInspector.TransformController.Modes.Rotate : WebInspector.TransformControll
er.Modes.Pan); | |
| 128 }, | |
| 129 | |
| 130 /** | |
| 131 * @param {!WebInspector.TransformController.Modes} mode | |
| 132 */ | |
| 133 _setMode: function(mode) | |
| 134 { | |
| 135 if (this._mode === mode) | |
| 136 return; | |
| 137 this._mode = mode; | |
| 138 this._updateModeButtons(); | |
| 139 this.element.focus(); | |
| 140 }, | |
| 141 | |
| 142 _updateModeButtons: function() | |
| 143 { | |
| 144 for (var mode in this._modeButtons) | |
| 145 this._modeButtons[mode].setToggled(mode === this._mode); | |
| 146 }, | |
| 147 | |
| 148 /** | |
| 149 * @param {!Event=} event | |
| 150 */ | |
| 151 resetAndNotify: function(event) | |
| 152 { | |
| 153 this._reset(); | |
| 154 this._postChangeEvent(); | |
| 155 if (event) | |
| 156 event.preventDefault(); | |
| 157 this.element.focus(); | |
| 158 }, | |
| 159 | |
| 160 /** | |
| 161 * @param {number} minScale | |
| 162 * @param {number} maxScale | |
| 163 */ | |
| 164 setScaleConstraints: function(minScale, maxScale) | |
| 165 { | |
| 166 this._minScale = minScale; | |
| 167 this._maxScale = maxScale; | |
| 168 this._scale = Number.constrain(this._scale, minScale, maxScale); | |
| 169 }, | |
| 170 | |
| 171 /** | |
| 172 * @param {number} minX | |
| 173 * @param {number} maxX | |
| 174 * @param {number} minY | |
| 175 * @param {number} maxY | |
| 176 */ | |
| 177 clampOffsets: function(minX, maxX, minY, maxY) | |
| 178 { | |
| 179 this._offsetX = Number.constrain(this._offsetX, minX, maxX); | |
| 180 this._offsetY = Number.constrain(this._offsetY, minY, maxY); | |
| 181 }, | |
| 182 | |
| 183 /** | |
| 184 * @return {number} | |
| 185 */ | |
| 186 scale: function() | |
| 187 { | |
| 188 return this._scale; | |
| 189 }, | |
| 190 | |
| 191 /** | |
| 192 * @return {number} | |
| 193 */ | |
| 194 offsetX: function() | |
| 195 { | |
| 196 return this._offsetX; | |
| 197 }, | |
| 198 | |
| 199 /** | |
| 200 * @return {number} | |
| 201 */ | |
| 202 offsetY: function() | |
| 203 { | |
| 204 return this._offsetY; | |
| 205 }, | |
| 206 | |
| 207 /** | |
| 208 * @return {number} | |
| 209 */ | |
| 210 rotateX: function() | |
| 211 { | |
| 212 return this._rotateX; | |
| 213 }, | |
| 214 | |
| 215 /** | |
| 216 * @return {number} | |
| 217 */ | |
| 218 rotateY: function() | |
| 219 { | |
| 220 return this._rotateY; | |
| 221 }, | |
| 222 | |
| 223 /** | |
| 224 * @param {number} scaleFactor | |
| 225 * @param {number} x | |
| 226 * @param {number} y | |
| 227 */ | |
| 228 _onScale: function(scaleFactor, x, y) | |
| 229 { | |
| 230 scaleFactor = Number.constrain(this._scale * scaleFactor, this._minScale
, this._maxScale) / this._scale; | |
| 231 this._scale *= scaleFactor; | |
| 232 this._offsetX -= (x - this._offsetX) * (scaleFactor - 1); | |
| 233 this._offsetY -= (y - this._offsetY) * (scaleFactor - 1); | |
| 234 this._postChangeEvent(); | |
| 235 }, | |
| 236 | |
| 237 /** | |
| 238 * @param {number} offsetX | |
| 239 * @param {number} offsetY | |
| 240 */ | |
| 241 _onPan: function(offsetX, offsetY) | |
| 242 { | |
| 243 this._offsetX += offsetX; | |
| 244 this._offsetY += offsetY; | |
| 245 this._postChangeEvent(); | |
| 246 }, | |
| 247 | |
| 248 /** | |
| 249 * @param {number} rotateX | |
| 250 * @param {number} rotateY | |
| 251 */ | |
| 252 _onRotate: function(rotateX, rotateY) | |
| 253 { | |
| 254 this._rotateX = rotateX; | |
| 255 this._rotateY = rotateY; | |
| 256 this._postChangeEvent(); | |
| 257 }, | |
| 258 | |
| 259 /** | |
| 260 * @param {number} zoomFactor | |
| 261 */ | |
| 262 _onKeyboardZoom: function(zoomFactor) | |
| 263 { | |
| 264 this._onScale(zoomFactor, this.element.clientWidth / 2, this.element.cli
entHeight / 2); | |
| 265 }, | |
| 266 | |
| 267 /** | |
| 268 * @param {number} xMultiplier | |
| 269 * @param {number} yMultiplier | |
| 270 */ | |
| 271 _onKeyboardPanOrRotate: function(xMultiplier, yMultiplier) | |
| 272 { | |
| 273 var panStepInPixels = 6; | |
| 274 var rotateStepInDegrees = 5; | |
| 275 | |
| 276 if (this._mode === WebInspector.TransformController.Modes.Rotate) { | |
| 277 // Sic! _onRotate treats X and Y as "rotate around X" and "rotate ar
ound Y", so swap X/Y multiplers. | |
| 278 this._onRotate(this._rotateX + yMultiplier * rotateStepInDegrees, th
is._rotateY + xMultiplier * rotateStepInDegrees); | |
| 279 } else { | |
| 280 this._onPan(xMultiplier * panStepInPixels, yMultiplier * panStepInPi
xels); | |
| 281 } | |
| 282 }, | |
| 283 | |
| 284 /** | |
| 285 * @param {!Event} event | |
| 286 */ | |
| 287 _onMouseWheel: function(event) | |
| 288 { | |
| 289 /** @const */ | |
| 290 var zoomFactor = 1.1; | |
| 291 /** @const */ | |
| 292 var mouseWheelZoomSpeed = 1 / 120; | |
| 293 var scaleFactor = Math.pow(zoomFactor, event.wheelDeltaY * mouseWheelZoo
mSpeed); | |
| 294 this._onScale(scaleFactor, event.clientX - this.element.totalOffsetLeft(
), event.clientY - this.element.totalOffsetTop()); | |
| 295 }, | |
| 296 | |
| 297 /** | |
| 298 * @param {!Event} event | |
| 299 */ | |
| 300 _onDrag: function(event) | |
| 301 { | |
| 302 if (this._mode === WebInspector.TransformController.Modes.Rotate) { | |
| 303 this._onRotate(this._oldRotateX + (this._originY - event.clientY) /
this.element.clientHeight * 180, this._oldRotateY - (this._originX - event.clien
tX) / this.element.clientWidth * 180); | |
| 304 } else { | |
| 305 this._onPan(event.clientX - this._originX, event.clientY - this._ori
ginY); | |
| 306 this._originX = event.clientX; | |
| 307 this._originY = event.clientY; | |
| 308 } | |
| 309 }, | |
| 310 | |
| 311 /** | |
| 312 * @param {!MouseEvent} event | |
| 313 */ | |
| 314 _onDragStart: function(event) | |
| 315 { | |
| 316 this.element.focus(); | |
| 317 this._originX = event.clientX; | |
| 318 this._originY = event.clientY; | |
| 319 this._oldRotateX = this._rotateX; | |
| 320 this._oldRotateY = this._rotateY; | |
| 321 return true; | |
| 322 }, | |
| 323 | |
| 324 _onDragEnd: function() | |
| 325 { | |
| 326 delete this._originX; | |
| 327 delete this._originY; | |
| 328 delete this._oldRotateX; | |
| 329 delete this._oldRotateY; | |
| 330 }, | |
| 331 | |
| 332 __proto__: WebInspector.Object.prototype | |
| 333 } | |
| OLD | NEW |