[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 /** 2 * @requires javelin-install 3 * javelin-event 4 * @provides javelin-vector 5 * 6 * @javelin-installs JX.$V 7 * 8 * @javelin 9 */ 10 11 12 /** 13 * Convenience function that returns a @{class:JX.Vector} instance. This allows 14 * you to concisely write things like: 15 * 16 * JX.$V(x, y).add(10, 10); // Explicit coordinates. 17 * JX.$V(node).add(50, 50).setDim(node); // Position of a node. 18 * 19 * @param number|Node If a node, returns the node's position vector. 20 * If numeric, the x-coordinate for the new vector. 21 * @param number? The y-coordinate for the new vector. 22 * @return @{class:JX.Vector} New vector. 23 */ 24 JX.$V = function(x, y) { 25 return new JX.Vector(x, y); 26 }; 27 28 29 /** 30 * Query and update positions and dimensions of nodes (and other things) within 31 * within a document. Each vector has two elements, 'x' and 'y', which usually 32 * represent width/height ('dimension vector') or left/top ('position vector'). 33 * 34 * Vectors are used to manage the sizes and positions of elements, events, 35 * the document, and the viewport (the visible section of the document, i.e. 36 * how much of the page the user can actually see in their browser window). 37 * Unlike most Javelin classes, @{class:JX.Vector} exposes two bare properties, 38 * 'x' and 'y'. You can read and manipulate these directly: 39 * 40 * // Give the user information about elements when they click on them. 41 * JX.Stratcom.listen( 42 * 'click', 43 * null, 44 * function(e) { 45 * var p = new JX.Vector(e); 46 * var d = JX.Vector.getDim(e.getTarget()); 47 * 48 * alert('You clicked at <' + p.x + ',' + p.y + '> and the element ' + 49 * 'you clicked is ' + d.x + 'px wide and ' + d.y + 'px high.'); 50 * }); 51 * 52 * You can also update positions and dimensions using vectors: 53 * 54 * // When the user clicks on something, make it 10px wider and 10px taller. 55 * JX.Stratcom.listen( 56 * 'click', 57 * null, 58 * function(e) { 59 * var target = e.getTarget(); 60 * JX.$V(target).add(10, 10).setDim(target); 61 * }); 62 * 63 * Additionally, vectors can be used to query document and viewport information: 64 * 65 * var v = JX.Vector.getViewport(); // Viewport (window) width and height. 66 * var d = JX.Vector.getDocument(); // Document width and height. 67 * var visible_area = parseInt(100 * (v.x * v.y) / (d.x * d.y), 10); 68 * alert('You can currently see ' + visible_area + ' % of the document.'); 69 * 70 * The function @{function:JX.$V} provides convenience construction of common 71 * vectors. 72 * 73 * @task query Querying Positions and Dimensions 74 * @task update Changing Positions and Dimensions 75 * @task manip Manipulating Vectors 76 */ 77 JX.install('Vector', { 78 79 /** 80 * Construct a vector, either from explicit coordinates or from a node 81 * or event. You can pass two Numbers to construct an explicit vector: 82 * 83 * var p = new JX.Vector(35, 42); 84 * 85 * Otherwise, you can pass a @{class:JX.Event} or a Node to implicitly 86 * construct a vector: 87 * 88 * var q = new JX.Vector(some_event); 89 * var r = new JX.Vector(some_node); 90 * 91 * These are just like calling JX.Vector.getPos() on the @{class:JX.Event} or 92 * Node. 93 * 94 * For convenience, @{function:JX.$V} constructs a new vector so you don't 95 * need to use the 'new' keyword. That is, these are equivalent: 96 * 97 * var s = new JX.Vector(x, y); 98 * var t = JX.$V(x, y); 99 * 100 * Methods like @{method:getScroll}, @{method:getViewport} and 101 * @{method:getDocument} also create new vectors. 102 * 103 * Once you have a vector, you can manipulate it with add(): 104 * 105 * var u = JX.$V(35, 42); 106 * var v = u.add(5, -12); // v = <40, 30> 107 * 108 * @param wild 'x' component of the vector, or a @{class:JX.Event}, or a 109 * Node. 110 * @param Number? If providing an 'x' component, the 'y' component of the 111 * vector. 112 * @return @{class:JX.Vector} Specified vector. 113 * @task query 114 */ 115 construct : function(x, y) { 116 if (typeof y == 'undefined') { 117 return JX.Vector.getPos(x); 118 } 119 120 this.x = (x === null) ? null : parseFloat(x); 121 this.y = (y === null) ? null : parseFloat(y); 122 }, 123 124 members : { 125 x : null, 126 y : null, 127 128 /** 129 * Move a node around by setting the position of a Node to the vector's 130 * coordinates. For instance, if you want to move an element to the top left 131 * corner of the document, you could do this (assuming it has 'position: 132 * absolute'): 133 * 134 * JX.$V(0, 0).setPos(node); 135 * 136 * @param Node Node to move. 137 * @return this 138 * @task update 139 */ 140 setPos : function(node) { 141 node.style.left = (this.x === null) ? '' : (parseInt(this.x, 10) + 'px'); 142 node.style.top = (this.y === null) ? '' : (parseInt(this.y, 10) + 'px'); 143 return this; 144 }, 145 146 /** 147 * Change the size of a node by setting its dimensions to the vector's 148 * coordinates. For instance, if you want to change an element to be 100px 149 * by 100px: 150 * 151 * JX.$V(100, 100).setDim(node); 152 * 153 * Or if you want to expand a node's dimensions by 50px: 154 * 155 * JX.$V(node).add(50, 50).setDim(node); 156 * 157 * @param Node Node to resize. 158 * @return this 159 * @task update 160 */ 161 setDim : function(node) { 162 node.style.width = 163 (this.x === null) ? '' : (parseInt(this.x, 10) + 'px'); 164 node.style.height = 165 (this.y === null) ? '' : (parseInt(this.y, 10) + 'px'); 166 return this; 167 }, 168 169 /** 170 * Change a vector's x and y coordinates by adding numbers to them, or 171 * adding the coordinates of another vector. For example: 172 * 173 * var u = JX.$V(3, 4).add(100, 200); // u = <103, 204> 174 * 175 * You can also add another vector: 176 * 177 * var q = JX.$V(777, 999); 178 * var r = JX.$V(1000, 2000); 179 * var s = q.add(r); // s = <1777, 2999> 180 * 181 * Note that this method returns a new vector. It does not modify the 182 * 'this' vector. 183 * 184 * @param wild Value to add to the vector's x component, or another 185 * vector. 186 * @param Number? Value to add to the vector's y component. 187 * @return @{class:JX.Vector} New vector, with summed components. 188 * @task manip 189 */ 190 add : function(x, y) { 191 if (x instanceof JX.Vector) { 192 y = x.y; 193 x = x.x; 194 } 195 return new JX.Vector(this.x + parseFloat(x), this.y + parseFloat(y)); 196 } 197 }, 198 199 statics : { 200 _viewport: null, 201 202 /** 203 * Determine where in a document an element is (or where an event, like 204 * a click, occurred) by building a new vector containing the position of a 205 * Node or @{class:JX.Event}. The 'x' component of the vector will 206 * correspond to the pixel offset of the argument relative to the left edge 207 * of the document, and the 'y' component will correspond to the pixel 208 * offset of the argument relative to the top edge of the document. Note 209 * that all vectors are generated in document coordinates, so the scroll 210 * position does not affect them. 211 * 212 * See also @{method:getDim}, used to determine an element's dimensions. 213 * 214 * @param Node|@{class:JX.Event} Node or event to determine the position 215 * of. 216 * @return @{class:JX.Vector} New vector with the argument's position. 217 * @task query 218 */ 219 getPos : function(node) { 220 JX.Event && (node instanceof JX.Event) && (node = node.getRawEvent()); 221 222 if (node.getBoundingClientRect) { 223 var rect; 224 try { 225 rect = node.getBoundingClientRect(); 226 } catch (e) { 227 rect = { top : 0, left : 0 }; 228 } 229 return new JX.Vector( 230 rect.left + window.pageXOffset, 231 rect.top + window.pageYOffset); 232 } 233 234 if (('pageX' in node) || ('clientX' in node)) { 235 var c = JX.Vector._viewport; 236 return new JX.Vector( 237 node.pageX || (node.clientX + c.scrollLeft), 238 node.pageY || (node.clientY + c.scrollTop) 239 ); 240 } 241 242 var x = 0; 243 var y = 0; 244 do { 245 var offsetParent = node.offsetParent; 246 var scrollLeft = 0; 247 var scrollTop = 0; 248 if (offsetParent && offsetParent != document.body) { 249 scrollLeft = offsetParent.scrollLeft; 250 scrollTop = offsetParent.scrollTop; 251 } 252 x += (node.offsetLeft - scrollLeft); 253 y += (node.offsetTop - scrollTop); 254 node = offsetParent; 255 } while (node && node != document.body); 256 257 return new JX.Vector(x, y); 258 }, 259 260 /** 261 * Determine the width and height of a node by building a new vector with 262 * dimension information. The 'x' component of the vector will correspond 263 * to the element's width in pixels, and the 'y' component will correspond 264 * to its height in pixels. 265 * 266 * See also @{method:getPos}, used to determine an element's position. 267 * 268 * @param Node Node to determine the display size of. 269 * @return @{JX.$V} New vector with the node's dimensions. 270 * @task query 271 */ 272 getDim : function(node) { 273 return new JX.Vector(node.offsetWidth, node.offsetHeight); 274 }, 275 276 /** 277 * Determine the current scroll position by building a new vector where 278 * the 'x' component corresponds to how many pixels the user has scrolled 279 * from the left edge of the document, and the 'y' component corresponds to 280 * how many pixels the user has scrolled from the top edge of the document. 281 * 282 * See also @{method:getViewport}, used to determine the size of the 283 * viewport. 284 * 285 * @return @{JX.$V} New vector with the document scroll position. 286 * @task query 287 */ 288 getScroll : function() { 289 // We can't use JX.Vector._viewport here because there's diversity between 290 // browsers with respect to where position/dimension and scroll position 291 // information is stored. 292 var b = document.body; 293 var e = document.documentElement; 294 return new JX.Vector( 295 window.pageXOffset || b.scrollLeft || e.scrollLeft, 296 window.pageYOffset || b.scrollTop || e.scrollTop 297 ); 298 }, 299 300 301 /** 302 * Get the aggregate scroll offsets for a node and all of its parents. 303 * 304 * Note that this excludes scroll at the document level, because it does 305 * not normally impact operations in document coordinates, which everything 306 * on this class returns. Use @{method:getScroll} to get the document scroll 307 * position. 308 * 309 * @param Node Node to determine offsets for. 310 * @return JX.Vector New vector with aggregate scroll offsets. 311 */ 312 getAggregateScrollForNode: function(node) { 313 var x = 0; 314 var y = 0; 315 316 do { 317 if (node == document.body || node == document.documentElement) { 318 break; 319 } 320 321 x += node.scrollLeft || 0; 322 y += node.scrollTop || 0; 323 node = node.parentNode; 324 } while (node); 325 326 return new JX.$V(x, y); 327 }, 328 329 /** 330 * Determine the size of the viewport (basically, the browser window) by 331 * building a new vector where the 'x' component corresponds to the width 332 * of the viewport in pixels and the 'y' component corresponds to the height 333 * of the viewport in pixels. 334 * 335 * See also @{method:getScroll}, used to determine the position of the 336 * viewport, and @{method:getDocument}, used to determine the size of the 337 * entire document. 338 * 339 * @return @{class:JX.Vector} New vector with the viewport dimensions. 340 * @task query 341 */ 342 getViewport : function() { 343 var c = JX.Vector._viewport; 344 return new JX.Vector( 345 window.innerWidth || c.clientWidth || 0, 346 window.innerHeight || c.clientHeight || 0 347 ); 348 }, 349 350 /** 351 * Determine the size of the document, including any area outside the 352 * current viewport which the user would need to scroll in order to see, by 353 * building a new vector where the 'x' component corresponds to the document 354 * width in pixels and the 'y' component corresponds to the document height 355 * in pixels. 356 * 357 * @return @{class:JX.Vector} New vector with the document dimensions. 358 * @task query 359 */ 360 getDocument : function() { 361 var c = JX.Vector._viewport; 362 return new JX.Vector(c.scrollWidth || 0, c.scrollHeight || 0); 363 } 364 }, 365 366 /** 367 * On initialization, the browser-dependent viewport root is determined and 368 * stored. 369 * 370 * In ##__DEV__##, @{class:JX.Vector} installs a toString() method so 371 * vectors print in a debuggable way: 372 * 373 * <23, 92> 374 * 375 * This string representation of vectors is not available in a production 376 * context. 377 * 378 * @return void 379 */ 380 initialize : function() { 381 JX.Vector._viewport = document.documentElement || document.body; 382 383 if (__DEV__) { 384 JX.Vector.prototype.toString = function() { 385 return '<' + this.x + ', ' + this.y + '>'; 386 }; 387 } 388 } 389 390 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |