vendor: 4,288 bytes, lines 1-142
1var VanillaTilt = (function () { 2'use strict'; 3 4/** 5 * Created by Sergiu Èandor (micku7zu) on 1/27/2017. 6 * Original idea: https://github.com/gijsroge/tilt.js 7 * MIT License. 8 * Version 1.8.0 9 */ 10 11class VanillaTilt { 12 constructor(element, settings = {}) { 13 if (!(element instanceof Node)) { 14 throw ("Can't initialize VanillaTilt because " + element + " is not a Node."); 15 } 16 17 this.width = null; 18 this.height = null; 19 this.clientWidth = null; 20 this.clientHeight = null; 21 this.left = null; 22 this.top = null; 23 24 // for Gyroscope sampling 25 this.gammazero = null; 26 this.betazero = null; 27 this.lastgammazero = null; 28 this.lastbetazero = null; 29 30 this.transitionTimeout = null; 31 this.updateCall = null; 32 this.event = null; 33 34 this.updateBind = this.update.bind(this); 35 this.resetBind = this.reset.bind(this); 36 37 this.element = element; 38 this.settings = this.extendSettings(settings); 39 40 this.reverse = this.settings.reverse ? -1 : 1; 41 this.resetToStart = VanillaTilt.isSettingTrue(this.settings["reset-to-start"]); 42 this.glare = VanillaTilt.isSettingTrue(this.settings.glare); 43 this.glarePrerender = VanillaTilt.isSettingTrue(this.settings["glare-prerender"]); 44 this.fullPageListening = VanillaTilt.isSettingTrue(this.settings["full-page-listening"]); 45 this.gyroscope = VanillaTilt.isSettingTrue(this.settings.gyroscope); 46 this.gyroscopeSamples = this.settings.gyroscopeSamples; 47 48 this.elementListener = this.getElementListener(); 49 50 if (this.glare) { 51 this.prepareGlare(); 52 } 53 54 if (this.fullPageListening) { 55 this.updateClientSize(); 56 } 57 58 this.addEventListeners(); 59 this.reset(); 60 61 if (this.resetToStart === false) { 62 this.settings.startX = 0; 63 this.settings.startY = 0; 64 } 65 } 66 67 static isSettingTrue(setting) { 68 return setting === "" || setting === true || setting === 1; 69 } 70 71 /** 72 * Method returns element what will be listen mouse events 73 * @return {Node} 74 */ 75 getElementListener() { 76 if (this.fullPageListening) { 77 return window.document; 78 } 79 80 if (typeof this.settings["mouse-event-element"] === "string") { 81 const mouseEventElement = document.querySelector(this.settings["mouse-event-element"]); 82 83 if (mouseEventElement) { 84 return mouseEventElement; 85 } 86 } 87 88 if (this.settings["mouse-event-element"] instanceof Node) { 89 return this.settings["mouse-event-element"]; 90 } 91 92 return this.element; 93 } 94 95 /** 96 * Method set listen methods for this.elementListener 97 * @return {Node} 98 */ 99 addEventListeners() { 100 this.onMouseEnterBind = this.onMouseEnter.bind(this); 101 this.onMouseMoveBind = this.onMouseMove.bind(this); 102 this.onMouseLeaveBind = this.onMouseLeave.bind(this); 103 this.onWindowResizeBind = this.onWindowResize.bind(this); 104 this.onDeviceOrientationBind = this.onDeviceOrientation.bind(this); 105 106 this.elementListener.addEventListener("mouseenter", this.onMouseEnterBind); 107 this.elementListener.addEventListener("mouseleave", this.onMouseLeaveBind); 108 this.elementListener.addEventListener("mousemove", this.onMouseMoveBind); 109 110 if (this.glare || this.fullPageListening) { 111 window.addEventListener("resize", this.onWindowResizeBind); 112 } 113 114 if (this.gyroscope) { 115 window.addEventListener("deviceorientation", this.onDeviceOrientationBind); 116 } 117 } 118 119 /** 120 * Method remove event listeners from current this.elementListener 121 */ 122 removeEventListeners() { 123 this.elementListener.removeEventListener("mouseenter", this.onMouseEnterBind); 124 this.elementListener.removeEventListener("mouseleave", this.onMouseLeaveBind); 125 this.elementListener.removeEventListener("mousemove", this.onMouseMoveBind); 126 127 if (this.gyroscope) { 128 window.removeEventListener("deviceorientation", this.onDeviceOrientationBind); 129 } 130 131 if (this.glare || this.fullPageListening) { 132 window.removeEventListener("resize", this.onWindowResizeBind); 133 } 134 } 135 136 destroy() { 137 clearTimeout(this.transitionTimeout); 138 if (this.updateCall !== null) { 139 cancelAnimationFrame(this.updateCall); 140 } 141 142 this.reset
vendor: 11,638 bytes, lines 142-494
142(); 143 144 this.removeEventListeners(); 145 this.element.vanillaTilt = null; 146 delete this.element.vanillaTilt; 147 148 this.element = null; 149 } 150 151 onDeviceOrientation(event) { 152 if (event.gamma === null || event.beta === null) { 153 return; 154 } 155 156 this.updateElementPosition(); 157 158 if (this.gyroscopeSamples > 0) { 159 this.lastgammazero = this.gammazero; 160 this.lastbetazero = this.betazero; 161 162 if (this.gammazero === null) { 163 this.gammazero = event.gamma; 164 this.betazero = event.beta; 165 } else { 166 this.gammazero = (event.gamma + this.lastgammazero) / 2; 167 this.betazero = (event.beta + this.lastbetazero) / 2; 168 } 169 170 this.gyroscopeSamples -= 1; 171 } 172 173 const totalAngleX = this.settings.gyroscopeMaxAngleX - this.settings.gyroscopeMinAngleX; 174 const totalAngleY = this.settings.gyroscopeMaxAngleY - this.settings.gyroscopeMinAngleY; 175 176 const degreesPerPixelX = totalAngleX / this.width; 177 const degreesPerPixelY = totalAngleY / this.height; 178 179 const angleX = event.gamma - (this.settings.gyroscopeMinAngleX + this.gammazero); 180 const angleY = event.beta - (this.settings.gyroscopeMinAngleY + this.betazero); 181 182 const posX = angleX / degreesPerPixelX; 183 const posY = angleY / degreesPerPixelY; 184 185 if (this.updateCall !== null) { 186 cancelAnimationFrame(this.updateCall); 187 } 188 189 this.event = { 190 clientX: posX + this.left, 191 clientY: posY + this.top, 192 }; 193 194 this.updateCall = requestAnimationFrame(this.updateBind); 195 } 196 197 onMouseEnter() { 198 this.updateElementPosition(); 199 this.element.style.willChange = "transform"; 200 this.setTransition(); 201 } 202 203 onMouseMove(event) { 204 if (this.updateCall !== null) { 205 cancelAnimationFrame(this.updateCall); 206 } 207 208 this.event = event; 209 this.updateCall = requestAnimationFrame(this.updateBind); 210 } 211 212 onMouseLeave() { 213 this.setTransition(); 214 215 if (this.settings.reset) { 216 requestAnimationFrame(this.resetBind); 217 } 218 } 219 220 reset() { 221 this.onMouseEnter(); 222 223 if (this.fullPageListening) { 224 this.event = { 225 clientX: (this.settings.startX + this.settings.max) / (2 * this.settings.max) * this.clientWidth, 226 clientY: (this.settings.startY + this.settings.max) / (2 * this.settings.max) * this.clientHeight 227 }; 228 } else { 229 this.event = { 230 clientX: this.left + ((this.settings.startX + this.settings.max) / (2 * this.settings.max) * this.width), 231 clientY: this.top + ((this.settings.startY + this.settings.max) / (2 * this.settings.max) * this.height) 232 }; 233 } 234 235 let backupScale = this.settings.scale; 236 this.settings.scale = 1; 237 this.update(); 238 this.settings.scale = backupScale; 239 this.resetGlare(); 240 } 241 242 resetGlare() { 243 if (this.glare) { 244 this.glareElement.style.transform = "rotate(180deg) translate(-50%, -50%)"; 245 this.glareElement.style.opacity = "0"; 246 } 247 } 248 249 getValues() { 250 let x, y; 251 252 if (this.fullPageListening) { 253 x = this.event.clientX / this.clientWidth; 254 y = this.event.clientY / this.clientHeight; 255 } else { 256 x = (this.event.clientX - this.left) / this.width; 257 y = (this.event.clientY - this.top) / this.height; 258 } 259 260 x = Math.min(Math.max(x, 0), 1); 261 y = Math.min(Math.max(y, 0), 1); 262 263 let tiltX = (this.reverse * (this.settings.max - x * this.settings.max * 2)).toFixed(2); 264 let tiltY = (this.reverse * (y * this.settings.max * 2 - this.settings.max)).toFixed(2); 265 let angle = Math.atan2(this.event.clientX - (this.left + this.width / 2), -(this.event.clientY - (this.top + this.height / 2))) * (180 / Math.PI); 266 267 return { 268 tiltX: tiltX, 269 tiltY: tiltY, 270 percentageX: x * 100, 271 percentageY: y * 100, 272 angle: angle 273 }; 274 } 275 276 updateElementPosition() { 277 let rect = this.element.getBoundingClientRect(); 278 279 this.width = this.element.offsetWidth; 280 this.height = this.element.offsetHeight; 281 this.left = rect.left; 282 this.top = rect.top; 283 } 284 285 update() { 286 let values = this.getValues(); 287 288 this.element.style.transform = "perspective(" + this.settings.perspective + "px) " + 289 "rotateX(" + (this.settings.axis === "x" ? 0 : values.tiltY) + "deg) " + 290 "rotateY(" + (this.settings.axis === "y" ? 0 : values.tiltX) + "deg) " + 291 "scale3d(" + this.settings.scale + ", " + this.settings.scale + ", " + this.settings.scale + ")"; 292 293 if (this.glare) { 294 this.glareElement.style.transform = `rotate(${values.angle}deg) translate(-50%, -50%)`; 295 this.glareElement.style.opacity = `${values.percentageY * this.settings["max-glare"] / 100}`; 296 } 297 298 this.element.dispatchEvent(new CustomEvent("tiltChange", { 299 "detail": values 300 })); 301 302 this.updateCall = null; 303 } 304 305 /** 306 * Appends the glare element (if glarePrerender equals false) 307 * and sets the default style 308 */ 309 prepareGlare() { 310 // If option pre-render is enabled we assume all html/css is present for an optimal glare effect. 311 if (!this.glarePrerender) { 312 // Create glare element 313 const jsTiltGlare = document.createElement("div"); 314 jsTiltGlare.classList.add("js-tilt-glare"); 315 316 const jsTiltGlareInner = document.createElement("div"); 317 jsTiltGlareInner.classList.add("js-tilt-glare-inner"); 318 319 jsTiltGlare.appendChild(jsTiltGlareInner); 320 this.element.appendChild(jsTiltGlare); 321 } 322 323 this.glareElementWrapper = this.element.querySelector(".js-tilt-glare"); 324 this.glareElement = this.element.querySelector(".js-tilt-glare-inner"); 325 326 if (this.glarePrerender) { 327 return; 328 } 329 330 Object.assign(this.glareElementWrapper.style, { 331 "position": "absolute", 332 "top": "0", 333 "left": "0", 334 "width": "100%", 335 "height": "100%", 336 "overflow": "hidden", 337 "pointer-events": "none", 338 "border-radius": "inherit" 339 }); 340 341 Object.assign(this.glareElement.style, { 342 "position": "absolute", 343 "top": "50%", 344 "left": "50%", 345 "pointer-events": "none", 346 "background-image": `linear-gradient(0deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%)`, 347 "transform": "rotate(180deg) translate(-50%, -50%)", 348 "transform-origin": "0% 0%", 349 "opacity": "0" 350 }); 351 352 this.updateGlareSize(); 353 } 354 355 updateGlareSize() { 356 if (this.glare) { 357 const glareSize = (this.element.offsetWidth > this.element.offsetHeight ? this.element.offsetWidth : this.element.offsetHeight) * 2; 358 359 Object.assign(this.glareElement.style, { 360 "width": `${glareSize}px`, 361 "height": `${glareSize}px`, 362 }); 363 } 364 } 365 366 updateClientSize() { 367 this.clientWidth = window.innerWidth 368 || document.documentElement.clientWidth 369 || document.body.clientWidth; 370 371 this.clientHeight = window.innerHeight 372 || document.documentElement.clientHeight 373 || document.body.clientHeight; 374 } 375 376 onWindowResize() { 377 this.updateGlareSize(); 378 this.updateClientSize(); 379 } 380 381 setTransition() { 382 clearTimeout(this.transitionTimeout); 383 this.element.style.transition = this.settings.speed + "ms " + this.settings.easing; 384 if (this.glare) this.glareElement.style.transition = `opacity ${this.settings.speed}ms ${this.settings.easing}`; 385 386 this.transitionTimeout = setTimeout(() => { 387 this.element.style.transition = ""; 388 if (this.glare) { 389 this.glareElement.style.transition = ""; 390 } 391 }, this.settings.speed); 392 393 } 394 395 /** 396 * Method return patched settings of instance 397 * @param {boolean} settings.reverse - reverse the tilt direction 398 * @param {number} settings.max - max tilt rotation (degrees) 399 * @param {startX} settings.startX - the starting tilt on the X axis, in degrees. Default: 0 400 * @param {startY} settings.startY - the starting tilt on the Y axis, in degrees. Default: 0 401 * @param {number} settings.perspective - Transform perspective, the lower the more extreme the tilt gets 402 * @param {string} settings.easing - Easing on enter/exit 403 * @param {number} settings.scale - 2 = 200%, 1.5 = 150%, etc.. 404 * @param {number} settings.speed - Speed of the enter/exit transition 405 * @param {boolean} settings.transition - Set a transition on enter/exit 406 * @param {string|null} settings.axis - What axis should be enabled. Can be "x" or "y" 407 * @param {boolean} settings.glare - if it should have a "glare" effect 408 * @param {number} settings.max-glare - the maximum "glare" opacity (1 = 100%, 0.5 = 50%) 409 * @param {boolean} settings.glare-prerender - false = VanillaTilt creates the glare elements for you, otherwise 410 * @param {boolean} settings.full-page-listening - If true, parallax effect will listen to mouse move events on the whole document, not only the selected element 411 * @param {string|object} settings.mouse-event-element - String selector or link to HTML-element what will be listen mouse events 412 * @param {boolean} settings.reset - false = If the tilt effect has to be reset on exit 413 * @param {boolean} settings.reset-to-start - true = On reset event (mouse leave) will return to initial start angle (if startX or startY is set) 414 * @param {gyroscope} settings.gyroscope - Enable tilting by deviceorientation events 415 * @param {gyroscopeSensitivity} settings.gyroscopeSensitivity - Between 0 and 1 - The angle at which max tilt position is reached. 1 = 90deg, 0.5 = 45deg, etc.. 416 * @param {gyroscopeSamples} settings.gyroscopeSamples - How many gyroscope moves to decide the starting position. 417 */ 418 extendSettings(settings) { 419 let defaultSettings = { 420 reverse: false, 421 max: 15, 422 startX: 0, 423 startY: 0, 424 perspective: 1000, 425 easing: "cubic-bezier(.03,.98,.52,.99)", 426 scale: 1, 427 speed: 300, 428 transition: true, 429 axis: null, 430 glare: false, 431 "max-glare": 1, 432 "glare-prerender": false, 433 "full-page-listening": false, 434 "mouse-event-element": null, 435 reset: true, 436 "reset-to-start": true, 437 gyroscope: true, 438 gyroscopeMinAngleX: -45, 439 gyroscopeMaxAngleX: 45, 440 gyroscopeMinAngleY: -45, 441 gyroscopeMaxAngleY: 45, 442 gyroscopeSamples: 10 443 }; 444 445 let newSettings = {}; 446 for (var property in defaultSettings) { 447 if (property in settings) { 448 newSettings[property] = settings[property]; 449 } else if (this.element.hasAttribute("data-tilt-" + property)) { 450 let attribute = this.element.getAttribute("data-tilt-" + property); 451 try { 452 newSettings[property] = JSON.parse(attribute); 453 } catch (e) { 454 newSettings[property] = attribute; 455 } 456 457 } else { 458 newSettings[property] = defaultSettings[property]; 459 } 460 } 461 462 return newSettings; 463 } 464 465 static init(elements, settings) { 466 if (elements instanceof Node) { 467 elements = [elements]; 468 } 469 470 if (elements instanceof NodeList) { 471 elements = [].slice.call(elements); 472 } 473 474 if (!(elements instanceof Array)) { 475 return; 476 } 477 478 elements.forEach((element) => { 479 if (!("vanillaTilt" in element)) { 480 element.vanillaTilt = new VanillaTilt(element, settings); 481 } 482 }); 483 } 484} 485 486if (typeof document !== "undefined") { 487 /* expose the class to window */ 488 window.VanillaTilt = VanillaTilt; 489 490 /** 491 * Auto load 492 */ 493 VanillaTilt.init(document.querySelectorAll("[data-tilt]")); 494}
494 495 496return VanillaTilt; 497 498}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.