OLD | NEW |
(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 var vrShellUi = (function() { |
| 6 'use strict'; |
| 7 |
| 8 /** |
| 9 * Enumeration of valid Anchroing for X axis. |
| 10 * A mesh can either be anchored to the left, right, or center of the main |
| 11 * content rect (or it can be absolutely positioned using NONE). Any |
| 12 * translations applied will be relative to this anchoring. |
| 13 * @enum {number} |
| 14 * @const |
| 15 */ |
| 16 var XAnchoring = Object.freeze({ |
| 17 'XLEFT': 0, |
| 18 'XRIGHT': 1, |
| 19 'XCENTER': 2, |
| 20 'XNONE': 3 |
| 21 }); |
| 22 |
| 23 /** |
| 24 * Enumeration of valid Anchroing for Y axis. |
| 25 * @enum {number} |
| 26 * @const |
| 27 */ |
| 28 var YAnchoring = Object.freeze({ |
| 29 'YTOP': 0, |
| 30 'YBOTTOM': 1, |
| 31 'YCENTER': 2, |
| 32 'YNONE': 3 |
| 33 }); |
| 34 |
| 35 /** |
| 36 * Enumeration of animatable properties. |
| 37 * @enum {number} |
| 38 * @const |
| 39 */ |
| 40 var Property = Object.freeze({ |
| 41 'COPYRECT': 0, |
| 42 'SIZE': 1, |
| 43 'TRANSLATION': 2, |
| 44 'ORIENTATION': 3, |
| 45 'ROTATION': 4 |
| 46 }); |
| 47 |
| 48 /** |
| 49 * Enumeration of easing type. |
| 50 * @enum {number} |
| 51 * @const |
| 52 */ |
| 53 var Easing = Object.freeze({ |
| 54 'LINEAR': 0, |
| 55 'CUBICBEZIER': 1, |
| 56 'EASEIN': 2, |
| 57 'EASEOUT': 3 |
| 58 }); |
| 59 |
| 60 /** |
| 61 * @type {number} Id generator. |
| 62 */ |
| 63 var idIndex = 1; |
| 64 |
| 65 class UiElement { |
| 66 /** |
| 67 * Constructor of UiElement. |
| 68 * pixelX and pixelY values indicate the left upper corner; pixelWidth and |
| 69 * pixelHeight is width and height of the texture to be copied from the web |
| 70 * contents. metersX and metersY indicate the size of the rectangle onto |
| 71 * which the pixel region will be mapped. |
| 72 */ |
| 73 constructor(pixelX, pixelY, pixelWidth, pixelHeight, metersX, metersY) { |
| 74 this.copyRect = { |
| 75 x: pixelX, |
| 76 y: pixelY, |
| 77 width: pixelWidth, |
| 78 height: pixelHeight |
| 79 }; |
| 80 this.size = { x: metersX, y: metersY }; |
| 81 this.xAnchoring = XAnchoring.XNONE; |
| 82 this.yAnchoring = YAnchoring.YNONE; |
| 83 this.anchorZ = false; |
| 84 this.translation = { x: 0, y: 0, z: 0 }; |
| 85 this.orientationAxisAngle = { x: 0, y: 0, z: 0, a: 0 }; |
| 86 this.rotationAxisAngle = { x: 0, y: 0, z: 0, a: 0 }; |
| 87 } |
| 88 |
| 89 /** |
| 90 * The rotation for the mesh in 3D, applied before translation. The |
| 91 * rotation is axis-angle representation (rotated around unit vector [x, y, |
| 92 * z] by 'a' radians). |
| 93 */ |
| 94 setRotation(x, y, z, a) { |
| 95 this.rotationAxisAngle = { x: x, y: y, z: z, a: a }; |
| 96 } |
| 97 |
| 98 /** |
| 99 * The offset for the mesh in 3D. If anchoring is specified, the offset is |
| 100 * applied to the anchoring position rather than the origin. |
| 101 */ |
| 102 setTranslation(x, y, z) { |
| 103 this.translation = { x: x, y: y, z: z }; |
| 104 } |
| 105 |
| 106 /** |
| 107 * Anchoring allows a rectangle to be positioned relative to the content |
| 108 * window. X and Y values should be XAnchoring and YAnchoring elements. |
| 109 * anchorZ is a boolean. |
| 110 * Example: rect.setAnchoring(XAnchoring.XCENTER, YAnchoring.YBOTTOM, true); |
| 111 */ |
| 112 setAnchoring(x, y, z) { |
| 113 this.xAnchoring = x; |
| 114 this.yAnchoring = y; |
| 115 this.anchorZ = z; |
| 116 } |
| 117 }; |
| 118 |
| 119 class Animation { |
| 120 constructor(meshId, durationMs) { |
| 121 this.meshId = meshId; |
| 122 this.easing = {}; |
| 123 this.from = {}; |
| 124 this.to = {}; |
| 125 this.easing.type = Easing.LINEAR; |
| 126 |
| 127 // How many milliseconds in the future to start the animation. |
| 128 this.startInMillis = 0.0; |
| 129 // Duration of the animation (milliseconds). |
| 130 this.durationMillis = durationMs; |
| 131 } |
| 132 |
| 133 setRotateTo(x, y, z, a) { |
| 134 this.property = Property.ROTATION; |
| 135 this.to.x = x; |
| 136 this.to.y = y; |
| 137 this.to.z = z; |
| 138 this.to.a = a; |
| 139 } |
| 140 |
| 141 setResizeTo(newWidth, newHeight) { |
| 142 this.property = Property.SIZE; |
| 143 this.to.x = newWidth; |
| 144 this.to.y = newHeight; |
| 145 } |
| 146 }; |
| 147 |
| 148 function initialize() { |
| 149 domLoaded(); |
| 150 |
| 151 // Change the body background so that the transparency applies. |
| 152 window.setTimeout(function() { |
| 153 document.body.parentNode.style.backgroundColor = 'rgba(255,255,255,0)'; |
| 154 }, 100); |
| 155 |
| 156 addControlButtons(); |
| 157 } |
| 158 |
| 159 // Build a row of control buttons. |
| 160 function addControlButtons() { |
| 161 var buttons = [ |
| 162 // Button text, UI action passed down to native. |
| 163 ['<', 'HISTORY_BACK'], |
| 164 ['>', 'HISTORY_FORWARD'], |
| 165 ['R', 'RELOAD'], |
| 166 ['-', 'ZOOM_OUT'], |
| 167 ['+', 'ZOOM_IN'] |
| 168 ]; |
| 169 |
| 170 var buttonWidth = 0.3; |
| 171 var buttonHeight = 0.2; |
| 172 var buttonSpacing = 0.5; |
| 173 var buttonStartPosition = -buttonSpacing * (buttons.length / 2.0 - 0.5); |
| 174 |
| 175 for (var i = 0; i < buttons.length; i++) { |
| 176 var b = document.createElement('div'); |
| 177 b.position = 'absolute'; |
| 178 b.style.top = '200px'; |
| 179 b.style.left = 50 * i + 'px'; |
| 180 b.style.width = '50px'; |
| 181 b.style.height = '50px'; |
| 182 b.className = 'ui-button'; |
| 183 b.textContent = buttons[i][0]; |
| 184 |
| 185 // Add click behaviour. |
| 186 b.addEventListener('click', function(action, e) { |
| 187 chrome.send('doAction', [action]); |
| 188 }.bind(undefined, buttons[i][1])); |
| 189 |
| 190 document.body.appendChild(b); |
| 191 |
| 192 // Add a UI rectangle for the button. |
| 193 var el = new UiElement(50 * i, 200, 50, 50, buttonWidth, buttonHeight); |
| 194 el.setAnchoring(XAnchoring.XCENTER, YAnchoring.YBOTTOM, true); |
| 195 el.setTranslation(buttonStartPosition + buttonSpacing * i, -0.3, 0.0); |
| 196 var id = idIndex++; |
| 197 addMesh(id, el); |
| 198 |
| 199 // Add transitions when the mouse hovers over (and leaves) the button. |
| 200 b.addEventListener('mouseenter', function(buttonId, width, height, e) { |
| 201 var resize = new Animation(buttonId, 250); |
| 202 resize.id = idIndex++; |
| 203 resize.setResizeTo(width, height); |
| 204 chrome.send('addAnimations', [resize]); |
| 205 }.bind(undefined, id, buttonWidth * 1.5, buttonHeight * 1.5)); |
| 206 b.addEventListener('mouseleave', function(buttonId, width, height) { |
| 207 var resize = new Animation(buttonId, 250); |
| 208 resize.id = idIndex++; |
| 209 resize.setResizeTo(width, height); |
| 210 chrome.send('addAnimations', [resize]); |
| 211 }.bind(undefined, id, buttonWidth, buttonHeight)); |
| 212 } |
| 213 } |
| 214 |
| 215 function domLoaded() { |
| 216 chrome.send('domLoaded', [window.innerWidth, window.innerHeight]); |
| 217 } |
| 218 |
| 219 function addAnimations(animations) { |
| 220 chrome.send('addAnimations', animations); |
| 221 } |
| 222 |
| 223 function addMesh(id, mesh) { |
| 224 chrome.send('addMesh', [id, mesh]); |
| 225 } |
| 226 |
| 227 return { |
| 228 initialize: initialize, |
| 229 }; |
| 230 })(); |
| 231 |
| 232 document.addEventListener('DOMContentLoaded', vrShellUi.initialize); |
OLD | NEW |