1(function ($) { 2 "use strict"; 3 function aimo_section_start_render() { 4 var _elementor = typeof elementor != 'undefined' ? elementor : elementorFrontend; 5 6 _elementor.hooks.addFilter('pxl_section_start_render', function (html, settings, el) { 7 8 if (typeof settings.pxl_parallax_bg_img != 'undefined' && settings.pxl_parallax_bg_img.url != '') { 9 html += '<div class="pxl-section-bg-parallax"></div>'; 10 } 11 12 if (typeof settings.pxl_color_offset != 'undefined' && settings.pxl_color_offset != 'none') { 13 html += '<div class="pxl-section-overlay-color"></div>'; 14 } 15 16 if (typeof settings.pxl_overlay_img != 'undefined' && settings.pxl_overlay_img.url != '') { 17 html += '<div class="pxl-overlay--image pxl-overlay--imageLeft"><div class="bg-image"></div></div>'; 18 } 19 20 if (typeof settings.pxl_overlay_img2 != 'undefined' && settings.pxl_overlay_img2.url != '') { 21 html += '<div class="pxl-overlay--image pxl-overlay--imageRight"><div class="bg-image"></div></div>'; 22 } 23 24 return html; 25 }); 26 27 $('.pxl-section-bg-parallax').parent('.elementor-element').addClass('pxl-section-parallax-overflow'); 28 } 29 30 function aimo_column_before_render() { 31 var _elementor = typeof elementor != 'undefined' ? elementor : elementorFrontend; 32 _elementor.hooks.addFilter('pxl-custom-column/before-render', function (html, settings, el) { 33 if (typeof settings.pxl_column_parallax_bg_img != 'undefined' && settings.pxl_column_parallax_bg_img.url != '') { 34 html += '<div class="pxl-column-bg-parallax"></div>'; 35 } 36 return html; 37 }); 38 } 39 40 function aimo_css_inline_js() { 41 var _inline_css = "<style>"; 42 $(document).find('.pxl-inline-css').each(function () { 43 var _this = $(this); 44 _inline_css += _this.attr("data-css") + " "; 45 _this.remove(); 46 }); 47 _inline_css += "</style>"; 48 $('head').append(_inline_css); 49 } 50 51 function aimo_section_before_render() { 52 var _elementor = typeof elementor != 'undefined' ? elementor : elementorFrontend; 53 _elementor.hooks.addFilter('pxl-custom-section/before-render', function (html, settings, el) { 54 if (typeof settings['row_divider'] !== 'undefined') { 55 if (settings['row_divider'] == 'angle-top' || settings['row_divider'] == 'angle-bottom' || settings['row_divider'] == 'angle-top-right' || settings['row_divider'] == 'angle-bottom-left') { 56 html = '<svg class="pxl-row-angle" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg>'; 57 return html; 58 } 59 if (settings['row_divider'] == 'angle-top-bottom' || settings['row_divider'] == 'angle-top-bottom-left') { 60 html = '<svg class="pxl-row-angle pxl-row-angle-top" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg><svg class="pxl-row-angle pxl-row-angle-bottom" style="fill:#ffffff" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 100 100" version="1.1" preserveAspectRatio="none" height="130px"><path stroke="" stroke-width="0" d="M0 100 L100 0 L200 100"></path></svg>'; 61 return html; 62 } 63 if (settings['row_divider'] == 'wave-animation-top' || settings['row_divider'] == 'wave-animation-bottom') { 64 html = '<svg class="pxl-row-angle" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 1440 150" fill="#fff">
64<path d="M 0 26.1978 C 275.76 83.8152 430.707 65.0509 716.279 25.6386 C 930.422 -3.86123 1210.32 -3.98357 1439 9.18045 C 2072.34 45.9691 2201.93 62.4429 2560 26.198 V 172.199 L 0 172.199 V 26.1978 Z"><animate repeatCount="indefinite" fill="freeze" attributeName="d" dur="10s" values="M0 25.9086C277 84.5821 433 65.736 720 25.9086C934.818 -3.9019 1214.06 -5.23669 1442 8.06597C2079 45.2421 2208 63.5007 2560 25.9088V171.91L0 171.91V25.9086Z; M0 86.3149C316 86.315 444 159.155 884 51.1554C1324 -56.8446 1320.29 34.1214 1538 70.4063C1814 116.407 2156 188.408 2560 86.315V232.317L0 232.316V86.3149Z; M0 53.6584C158 11.0001 213 0 363 0C513 0 855.555 115.001 1154 115.001C1440 115.001 1626 -38.0004 2560 53.6585V199.66L0 199.66V53.6584Z; M0 25.9086C277 84.5821 433 65.736 720 25.9086C934.818 -3.9019 1214.06 -5.23669 1442 8.06597C2079 45.2421 2208 63.5007 2560 25.9088V171.91L0 171.91V25.9086Z"></animate></path></svg>'; 65 return html; 66 } 67 if (settings['row_divider'] == 'curved-top' || settings['row_divider'] == 'curved-bottom') { 68 html = '<svg class="pxl-row-angle" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 1920 128" version="1.1" preserveAspectRatio="none" style="fill:#ffffff"><path stroke-width="0" d="M-1,126a3693.886,3693.886,0,0,1,1921,2.125V-192H-7Z"></path></svg>'; 69 return html; 70 } 71 } 72 }); 73 } 74 75 var PXL_Icon_Contact_Form = function ($scope, $) { 76 77 setTimeout(function () { 78 $('.pxl--item').each(function () { 79 var icon_input = $(this).find(".pxl--form-icon"), 80 control_wrap = $(this).find('.wpcf7-form-control'); 81 control_wrap.before(icon_input.clone()); 82 icon_input.remove(); 83 }); 84 }, 10); 85 86 }; 87 88 function aimo_split_text($scope) { 89 90 setTimeout(function () { 91 92 var st = $scope.find(".pxl-split-text"); 93 if (st.length == 0) return; 94 gsap.registerPlugin(SplitText); 95 st.each(function (index, el) { 96 el.split = new SplitText(el, { 97 type: "lines,words,chars", 98 linesClass: "split-line" 99 }); 100 gsap.set(el, { perspective: 400 }); 101 102 if ($(el).hasClass('split-in-fade')) { 103 $(el).addClass('active'); 104 gsap.set(el.split.chars, { 105 opacity: 0, 106 ease: "Back.easeOut", 107 }); 108 } 109 if ($(el).hasClass('split-in-right')) { 110 gsap.set(el.split.chars, { 111 opacity: 0, 112 x: "50", 113 ease: "Back.easeOut", 114 }); 115 } 116 if ($(el).hasClass('split-in-left')) { 117 gsap.set(el.split.chars, { 118 opacity: 0, 119 x: "-50", 120 ease: "circ.out", 121 }); 122 } 123 if ($(el).hasClass('split-in-up')) { 124 gsap.set(el.split.chars, { 125 opacity: 0, 126 y: "80", 127 ease: "circ.out", 128 }); 129 } 130 if ($(el).hasClass('split-in-down')) { 131 gsap.set(el.split.chars, { 132 opacity: 0, 133 y: "-80", 134 ease: "circ.out", 135 }); 136 } 137 if ($(el).hasClass('split-in-rotate')) { 138 gsap.set(el.split.chars, { 139 opacity: 0, 140 rotateX: "50deg", 141 ease: "circ.out", 142 }); 143 } 144 if ($(el).hasClass('split-in-scale')) { 145 gsap.set(el.split.chars, { 146 opacity: 0, 147 scale: "0.5", 148 ease: "circ.out", 149 }); 150 } 151 el.anim = gsap.to(el.split.chars, { 152 scrollTrigger: { 153 trigger: el, 154 toggleActions: "restart pause resume reverse", 155 start: "top 90%", 156 }, 157 x: "0", 158 y: "0", 159 rotateX: "0", 160 scale: 1, 161 opacity: 1, 162 duration: 0.8, 163 stagger: 0.02, 164 }); 165 }); 166 167 }, 200); 168 } 169 170 function aimo_zoom_point() { 171 elementorFrontend.waypoint($(document).find('.pxl-zoom-point'), function () { 172 var offset = $(this).offset(); 173 var offset_top = offset.top; 174 var scroll_top = $(window).scrollTop(); 175 }, { 176 offset: -100, 177 triggerOnce: true 178 }); 179 } 180 181 function aimo_scroll_fixed_section() { 182 if ($('.pxl-section-fix-top').length > 0) { 183 ScrollTrigger.matchMedia({ 184 "(min-width: 991px)": function () { 185 const pinnedSections = ['.pxl-section-fix-top']; 186 pinnedSections.forEach(className => { 187 gsap.to(".pxl-section-fix-bottom", { 188 scrollTrigger: { 189 trigger: ".pxl-section-fix-bottom", 190 scrub: true, 191 pin: className, 192 pinSpacing: false, 193 start: 'top bottom', 194 end: "bottom top", 195 }, 196 }); 197 }); 198 } 199 }); 200 } 201 } 202 203 function aimo_item_marquee($scope) { 204 const logos = $scope.find('.pxl-item--marquee'); 205 gsap.set(logos, { autoAlpha: 1 }) 206 207 logos.each(function (index, el) { 208 gsap.set(el, { xPercent: 100 * index }); 209 }); 210 211 if (logos.length > 2) { 212 const logosWrap = gsap.utils.wrap(-100, ((logos.length - 1) * 100)); 213 const durationNumber = logos.data('duration'); 214 const slipType = logos.data('slip-type'); 215 var slipResult = `-=${logos.length * 100}`; 216 if (slipType == 'right') { 217 slipResult = `+=${logos.length * 100}`; 218 } 219 gsap.to(logos, { 220 xPercent: slipResult, 221 duration: durationNumber, 222 repeat: -1, 223 ease: 'none', 224 modifiers: { 225 xPercent: xPercent => logosWrap(parseFloat(xPercent)) 226 } 227 }); 228 } 229 } 230 231 function aimo_item_marquee2($scope) { 232 const textWrapper = $scope.find('.pxl-text-marquee'); 233 const text_marquee = textWrapper.find('.pxl-text--marquee'); 234 const boxes = gsap.utils.toArray(text_marquee); 235 236 const isRTL = textWrapper.hasClass('pxl-right-to-left'); 237 const isLTR = textWrapper.hasClass('pxl-left-to-right'); 238 239 const loop = text_horizontalLoop(boxes, { 240 paused: false, 241 repeat: -1, 242 reversed: isLTR // â nếu là Left to Right thì reverse 243 }); 244 245 function text_horizontalLoop(items, config) { 246 items = gsap.utils.toArray(items); 247 config = config || {}; 248 let tl = gsap.timeline({ 249 repeat: config.repeat, 250 paused: config.paused, 251 defaults: { ease: "none" }, 252 onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100) 253 }), 254 length = items.length, 255 startX = items[0].offsetLeft, 256 times = [], 257 widths = [], 258 xPercents = [], 259 curIndex = 0, 260 pixelsPerSecond = (config.speed || 1) * 100, 261 snap = config.snap === false ? v => v : gsap.utils.snap(config.snap || 1), 262 totalWidth, curX, distanceToStart, distanceToLoop, item, i; 263 264 gsap.set(items, { 265 xPercent: (i, el) => { 266 let w = widths[i] = parseFloat(gsap.getProperty(el, "width", "px")); 267 xPercents[i] = snap(parseFloat(gsap.getProperty(el, "x", "px")) / w * 100 + gsap.getProperty(el, "xPercent"));
268 return xPercents[i]; 269 } 270 }); 271 272 gsap.set(items, { x: 0 }); 273 274 totalWidth = items[length - 1].offsetLeft + xPercents[length - 1] / 100 * widths[length - 1] - startX + items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], "scaleX") + (parseFloat(config.paddingRight) || 0); 275 276 for (i = 0; i < length; i++) { 277 item = items[i]; 278 curX = xPercents[i] / 100 * widths[i]; 279 distanceToStart = item.offsetLeft + curX - startX; 280 distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX"); 281 282 tl.to(item, { 283 xPercent: snap((curX - distanceToLoop) / widths[i] * 100), 284 duration: distanceToLoop / pixelsPerSecond 285 }, 0) 286 .fromTo(item, { 287 xPercent: snap((curX - distanceToLoop + totalWidth) / widths[i] * 100) 288 }, { 289 xPercent: xPercents[i], 290 duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, 291 immediateRender: false 292 }, distanceToLoop / pixelsPerSecond) 293 .add("label" + i, distanceToStart / pixelsPerSecond); 294 295 times[i] = distanceToStart / pixelsPerSecond; 296 } 297 298 function toIndex(index, vars) { 299 vars = vars || {}; 300 if (Math.abs(index - curIndex) > length / 2) { 301 index += (index > curIndex) ? -length : length; 302 } 303 let newIndex = gsap.utils.wrap(0, length, index), 304 time = times[newIndex]; 305 if ((time > tl.time()) !== (index > curIndex)) { 306 vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) }; 307 time += tl.duration() * (index > curIndex ? 1 : -1); 308 } 309 curIndex = newIndex; 310 vars.overwrite = true; 311 return tl.tweenTo(time, vars); 312 } 313 314 tl.next = vars => toIndex(curIndex + 1, vars); 315 tl.previous = vars => toIndex(curIndex - 1, vars); 316 tl.current = () => curIndex; 317 tl.toIndex = (index, vars) => toIndex(index, vars); 318 tl.times = times; 319 tl.progress(1, true).progress(0, true); 320 321 if (config.reversed) { 322 tl.vars.onReverseComplete(); 323 tl.reverse(); 324 } 325 326 return tl; 327 } 328 } 329 330 331 function aimo_animation_image() { 332 let revealContainers = document.querySelectorAll(".pxl-scroll-reveal"); 333 if (revealContainers.length > 0 && window.innerWidth > 767) { 334 gsap.registerPlugin(ScrollTrigger); 335 336 revealContainers.forEach((container) => { 337 let image = container.querySelector("img"); 338 339 let tl = gsap.timeline({ 340 scrollTrigger: { 341 trigger: container, 342 toggleActions: "play none none none" 343 } 344 }); 345 346 tl.set(container, { autoAlpha: 1 }); 347 348 tl.from(container, { 349 xPercent: -100, 350 duration: 1.5, 351 ease: Power2.out 352 }); 353 354 tl.from(image, { 355 xPercent: 100, 356 scale: 1.3, 357 duration: 1.5, 358 delay: -1.5, 359 ease: Power2.out 360 }); 361 }); 362 } 363 364 } 365 function aimo_process3() { 366 const cards = document.querySelectorAll(".pxl-process3 .pxl--item"); 367 368 if (window.innerWidth > 960) { 369 cards.forEach((card, index) => { 370 card.style.left = `${index * 120}px`; 371 card.style.top = `${index * 52}px`; 372 card.style.position = "absolute"; 373 card.style.transition = "transform 0.3s ease, z-index 0s"; 374 375 card.addEventListener("click", (event) => { 376 event.stopPropagation(); 377 378 cards.forEach((otherCard) => { 379 otherCard.style.zIndex = "1"; 380 otherCard.style.transform = "scale(1)"; 381 const icon = otherCard.querySelector(".pxl-icon"); 382 if (icon) { 383 icon.classList.remove("pxl_spin"); 384 } 385 const image = otherCard.querySelector("img"); 386 if (image) { 387 image.style.borderRadius = "12px"; 388 } 389 }); 390 391 card.style.zIndex = "10"; 392 card.style.transform = "scale(1.1)"; 393 394 const icon = card.querySelector(".pxl-icon"); 395 if (icon) { 396 icon.classList.add("pxl_spin"); 397 } 398 const image = card.querySelector("img"); 399 if (image) { 400 image.style.borderRadius = "0px"; 401 } 402 }); 403 }); 404 405 document.addEventListener("click", () => { 406 cards.forEach((card) => { 407 card.style.zIndex = "1"; 408 card.style.transform = "scale(1)"; 409 const icon = card.querySelector(".pxl-icon"); 410 if (icon) { 411 icon.classList.remove("pxl_spin"); 412 } 413 const image = card.querySelector("img"); 414 if (image) { 415 image.style.borderRadius = "12px"; 416 } 417 }); 418 }); 419 } 420 } 421 window.addEventListener("resize", aimo_process3); 422 423 /*//////////////*/ 424 function aimo_split_scroll_color() { 425 var revealContainers = document.querySelectorAll(".pxl-heading .pxl-heading--text-scroll"); 426 427 if (revealContainers.length > 0) {
428 revealContainers.forEach((container) => { 429 var text = new SplitText(container, { type: 'words, chars' }); 430 431 text.words.forEach((word) => { 432 if (word.children.length > 0) { 433 word.children[0].classList.add("first-char"); 434 } 435 }); 436 437 gsap.fromTo(text.chars, 438 { 439 position: 'relative', 440 display: 'inline-block', 441 opacity: 0.2, 442 x: -5, 443 }, 444 { 445 opacity: 1, 446 x: 0, 447 stagger: 0.1, 448 scrollTrigger: { 449 trigger: container, 450 toggleActions: "play pause reverse pause", 451 start: "top 90%", 452 end: "top 40%", 453 scrub: 0.7, 454 } 455 } 456 ); 457 }); 458 } 459 } 460 461 function aimo_image_split() { 462 let boxWidth = 0; 463 let lastScrollY = window.scrollY; 464 const mq = window.matchMedia("(max-width: 1200px)"); 465 let isScrolling = false; 466 467 function handleScroll() { 468 const container = document.querySelector('.pxl-image-split .containers'); 469 const box = document.querySelector('.pxl-image-split .pxl-width'); 470 const fillerSpace = document.querySelector('.pxl-image-split .filler-space'); 471 if (container && box && fillerSpace) { 472 const containerTop = container.getBoundingClientRect().top; 473 const fillerBottom = fillerSpace.getBoundingClientRect().bottom; 474 const fillerTop = fillerSpace.getBoundingClientRect().top; 475 const boxTop = box.getBoundingClientRect().top; 476 const deltaY = window.scrollY - lastScrollY; 477 478 if (containerTop <= 0) { 479 if (deltaY > 0) { 480 boxWidth = Math.min(100, boxWidth + deltaY * 0.1); 481 } 482 483 if (deltaY < 0 && fillerBottom >= window.innerHeight) { 484 boxWidth = Math.max(0, boxWidth - Math.abs(deltaY) * 0.15); 485 } 486 if (fillerTop >= boxTop) { 487 boxWidth = 0; 488 } 489 box.style.width = boxWidth + '%'; 490 } 491 } 492 493 lastScrollY = window.scrollY; 494 isScrolling = false; 495 } 496 497 function smoothScrollHandler() { 498 if (!isScrolling) { 499 isScrolling = true; 500 requestAnimationFrame(handleScroll); 501 } 502 } 503 504 function checkMediaQuery() { 505 if (!mq.matches) { 506 window.addEventListener('scroll', smoothScrollHandler); 507 } else { 508 window.removeEventListener('scroll', smoothScrollHandler); 509 } 510 } 511 512 function handleResize() { 513 checkMediaQuery(); 514 } 515 516 if (document.querySelector('.pxl-image-split .containers') && 517 document.querySelector('.pxl-image-split .pxl-width') && 518 document.querySelector('.pxl-image-split .filler-space')) { 519 checkMediaQuery(); 520 mq.addEventListener('change', checkMediaQuery); 521 window.addEventListener('resize', handleResize); 522 } 523 } 524 /* Custom WebGL Effects */ 525 function aimo_webgl_effects() { 526 var WebGL_vs = `#ifdef GL_ES 527 precision mediump float; 528 #endif 529 530 attribute vec3 aVertexPosition; 531 attribute vec2 aTextureCoord; 532 533 uniform mat4 uMVMatrix; 534 uniform mat4 uPMatrix; 535 536 uniform mat4 texture0Matrix; 537 uniform mat4 texture1Matrix; 538 uniform mat4 mapMatrix; 539 540 varying vec3 vVertexPosition; 541 varying vec2 vTextureCoord0; 542 varying vec2 vTextureCoord1; 543 varying vec2 vTextureCoordMap; 544 545 void main() { 546 vec3 vertexPosition = aVertexPosition; 547 548 gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0
548); 549 550 vTextureCoord0 = (texture0Matrix * vec4(aTextureCoord, 0., 1.)).xy; 551 vTextureCoord1 = (texture1Matrix * vec4(aTextureCoord, 0., 1.)).xy; 552 vTextureCoordMap = (mapMatrix * vec4(aTextureCoord, 0., 1.)).xy; 553 vVertexPosition = vertexPosition; 554 }`; 555 556 var WebGL_fs = `#ifdef GL_ES 557 precision mediump float; 558 #endif 559 560 #define PI2 6.28318530718 561 #define PI 3.14159265359 562 #define S(a,b,n) smoothstep(a,b,n) 563 564 uniform float uTime; 565 uniform float uProgress; 566 uniform vec2 uReso; 567 uniform vec2 uMouse; 568 569 varying vec3 vVertexPosition; 570 varying vec2 vTextureCoord0; 571 varying vec2 vTextureCoord1; 572 varying vec2 vTextureCoordMap; 573 574 uniform sampler2D texture0; 575 uniform sampler2D texture1; 576 uniform sampler2D map; 577 578 float exponentialEasing (float x, float a){ 579 580 float epsilon = 0.00001; 581 float min_param_a = 0.0 + epsilon; 582 float max_param_a = 1.0 - epsilon; 583 a = max(min_param_a, min(max_param_a, a)); 584 585 if (a < 0.5){ 586 a = 2.0 * a; 587 float y = pow(x, a); 588 return y; 589 } else { 590 a = 2.0 * (a-0.5); 591 float y = pow(x, 1.0 / (1.-a)); 592 return y; 593 } 594 } 595 596 vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) { 597 vec4 color = vec4(0.0); 598 vec2 off1 = vec2(1.411764705882353) * direction; 599 vec2 off2 = vec2(3.2941176470588234) * direction; 600 vec2 off3 = vec2(5.176470588235294) * direction; 601 color += texture2D(image, uv) * 0.1964825501511404; 602 color += texture2D(image, uv + (off1 / resolution)) * 0.2969069646728344; 603 color += texture2D(image, uv - (off1 / resolution)) * 0.2969069646728344; 604 color += texture2D(image, uv + (off2 / resolution)) * 0.09447039785044732; 605 color += texture2D(image, uv - (off2 / resolution)) * 0.09447039785044732; 606 color += texture2D(image, uv + (off3 / resolution)) * 0.010381362401148057; 607 color += texture2D(image, uv - (off3 / resolution)) * 0.010381362401148057; 608 return color; 609 } 610 611 void main(){ 612 vec2 uv0 = vTextureCoord0; 613 vec2 uv1 = vTextureCoord1; 614 615 float progress0 = uProgress; 616 float progress1 = 1. - uProgress; 617 618 vec4 map = blur13(map, vTextureCoordMap, uReso, vec2(2.)) + 0.5; 619 620 uv0.x += progress0 * map.r; 621 uv1.x -= progress1 * map.r; 622 623 vec4 color = texture2D( texture0, uv0 ); 624 vec4 color1 = texture2D( texture1, uv1 ); 625 626 gl_FragColor = mix(color, color1, progress0 ); 627 }`; 628 class WebglHover { 629 constructor(set) { 630 this.canvas = set.canvas; 631 this.webGLCurtain = new Curtains({ 632 container: this.canvas, 633 watchScroll: false, 634 pixelRatio: Math.min(1.5, window.devicePixelRatio) 635 }) 636 this.planeElement = set.planeElement; 637 this.mouse = { 638 x: 0, 639 y: 0 640 }; 641 this.params = { 642 vertexShader: WebGL_vs, 643 fragmentShader: WebGL_fs, 644 widthSegments: 40, 645 heightSegments: 40, 646 uniforms: { 647 time: { 648 name: "uTime", 649 type: "1f", 650 value: 0 651 }, 652 mousepos: { 653 name: "uMouse", 654 type: "2f", 655 value: [0, 0] 656 }, 657 resolution: { 658 name: "uReso", 659 type: "2f", 660 value: [innerWidth, innerHeight] 661 }, 662 progress: { 663 name: "uProgress", 664 type: "1f",
665 value: 0 666 } 667 } 668 }; 669 this.initPlane(); 670 } 671 672 initPlane() { 673 this.plane = this.webGLCurtain.addPlane(this.planeElement, this.params); 674 // this.plane = new Plane(this.webGLCurtain, this.planeElement, this.params) 675 676 if (this.plane) { 677 this.plane.onReady(() => { 678 this.update(); 679 this.initEvent(); 680 }); 681 } 682 } 683 684 update() { 685 this.plane.onRender(() => { 686 this.plane.uniforms.time.value += 0.01; 687 this.plane.uniforms.resolution.value = [innerWidth, innerHeight]; 688 }); 689 } 690 691 initEvent() { 692 this.planeElement.addEventListener("mouseenter", e => { 693 gsap.to(this.plane.uniforms.progress, .8, { 694 value: 1 695 }); 696 }); 697 698 this.planeElement.addEventListener("mouseout", e => { 699 gsap.to(this.plane.uniforms.progress, .8, { 700 value: 0 701 }); 702 }); 703 } 704 } 705 706 if (navigator.userAgent.indexOf('Safari') == -1 || navigator.userAgent.indexOf('Chrome') > -1) { 707 $('.pxl-image-effect1.normal').each(function () { 708 const $this = $(this), 709 canvas = $this.find('.canvas')[0], 710 planeElement = $this.find('.item--image')[0], 711 initialized = $this.data('initialized'); 712 713 if (!initialized && canvas && planeElement) { 714 new WebglHover({ 715 canvas: canvas, 716 planeElement: planeElement 717 }); 718 $this.data('initialized', true); 719 } 720 }); 721 } 722 723 // Effect Expo 724 var WebExpo_vs = `#ifdef GL_ES 725 precision mediump float; 726 #endif 727 728 attribute vec3 aVertexPosition; 729 attribute vec2 aTextureCoord; 730 731 uniform mat4 uMVMatrix; 732 uniform mat4 uPMatrix; 733 734 varying vec2 vTextureCoord; 735 736 void main() { 737 gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0
737); 738 739 vTextureCoord = aTextureCoord; 740 }`; 741 742 var WebExpo_fs = ` 743 #ifdef GL_ES 744 precision mediump float; 745 #endif 746 747 varying vec3 vVertexPosition; 748 varying vec2 vTextureCoord; 749 750 uniform float uTime; 751 752 uniform sampler2D planeTexture; 753 754 void main() { 755 vec2 textureCoord = vTextureCoord; 756 757 const float PI = 3.141592; 758 759 textureCoord.x += ( 760 sin(textureCoord.x * 2.5 + ((uTime * (PI / 3.0)) * 0.031)) 761 + sin(textureCoord.y * 2.5 + ((uTime * (PI / 2.489)) * 0.017)) 762 ) * 0.0075; 763 764 textureCoord.y += ( 765 sin(textureCoord.y * 2.5 + ((uTime * (PI / 2.023)) * 0.023)) 766 + sin(textureCoord.x * 2.5 + ((uTime * (PI / 3.1254)) * 0.037)) 767 ) * 0.0125; 768 769 gl_FragColor = texture2D(planeTexture, textureCoord); 770 } 771 `; 772 773 class WebGLExpo { 774 constructor(set) { 775 this.canvas = set.canvas; 776 this.webGLCurtain = new Curtains({ 777 container: this.canvas, 778 watchScroll: false, 779 pixelRatio: Math.min(1.5, window.devicePixelRatio) 780 }) 781 this.planeElement = set.planeElement; 782 this.mouse = { 783 x: 0, 784 y: 0 785 }; 786 this.params = { 787 vertexShader: WebExpo_vs, 788 fragmentShader: WebExpo_fs, 789 widthSegments: 40, 790 heightSegments: 40, 791 uniforms: { 792 time: { 793 name: "uTime", 794 type: "1f", 795 value: 0 796 }, 797 mousepos: { 798 name: "uMouse", 799 type: "2f", 800 value: [0, 0] 801 }, 802 resolution: { 803 name: "uReso", 804 type: "2f", 805 value: [innerWidth, innerHeight] 806 }, 807 progress: { 808 name: "uProgress", 809 type: "1f", 810 value: 0 811 } 812 } 813 }; 814 this.initPlane(); 815 } 816 817 initPlane() { 818 this.plane = this.webGLCurtain.addPlane(this.planeElement, this.params); 819 this.plane = new Plane(this.webGLCurtain, this.planeElement, this.params) 820 821 if (this.plane) { 822 this.plane.onReady(() => { 823 this.update(); 824 this.initEvent(); 825 }); 826 } 827 } 828 829 update() { 830 this.plane.onRender(() => { 831 this.plane.uniforms.resolution.value = [innerWidth, innerHeight]; 832 }); 833 } 834 835 initEvent() { 836 let isHovered = false; 837 838 this.planeElement.addEventListener("mouseenter", e => { 839 isHovered = true; 840 }); 841 842 this.planeElement.addEventListener("mouseout", e => { 843 isHovered = false; 844 }); 845 846 this.plane.onRender(() => { 847 if (isHovered) { 848 this.plane.uniforms.time.value++; 849 } 850 }); 851 852 } 853 } 854 855 if (navigator.userAgent.indexOf('Safari') == -1 || navigator.userAgent.indexOf('Chrome') > -1) { 856 $('.pxl-image-effect1.expo').each(function () { 857 const $this = $(this), 858 canvas = $this.find('.canvas')[0], 859 planeElement = $this.find('.item--image')[0], 860 initialized = $this.data('initialized'); 861 862 if (!initialized && canvas && planeElement) { 863 new WebGLExpo({ 864 canvas: canvas, 865 planeElement: planeElement 866 }); 867 $this.data('initialized', true); 868 } 869 }); 870 } 871 872 // Effect Wave 873 const WebWave_vs = ` 874 precision mediump float; 875 876 attribute vec3 aVertexPosition; 877 attribute vec2 aTextureCoord; 878 879 uniform mat4 uMVMatrix; 880 uniform mat4 uPMatrix; 881 882 varying vec3 vVertexPosition; 883 varying vec2 vTextureCoord; 884 885 uniform float uTime; 886 887 void main() { 888 vec3 vertexPosition = aVertexPosition; 889 890 float waveCoords = ((uTime / 45.0) * 3.5) - 1.75; 891 892 float distanceToWave = distance(vec2(vertexPosition.x, 0.0), vec2(waveCoords, 0.0
892)); 893 894 vertexPosition.z -= (cos(clamp(distanceToWave, 0.0, 0.75) * 3.141592) - cos(0.75 * 3.141592) + (2.0 * sin(3.141592 * uTime / 90.0))) * 0.025; 895 896 gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0); 897 898 vTextureCoord = aTextureCoord; 899 vVertexPosition = vertexPosition; 900 } 901 `; 902 903 const WebWave_fs = `precision mediump float; 904 905 uniform float uTime; 906 907 varying vec3 vVertexPosition; 908 varying vec2 vTextureCoord; 909 910 uniform sampler2D uExample; 911 912 913 void main() { 914 915 vec2 textureCoords = vec2(vTextureCoord.x, vTextureCoord.y); 916 vec4 finalColor = texture2D(uExample, textureCoords); 917 918 gl_FragColor = finalColor; 919 }`; 920 921 class ImgCurtain { 922 constructor(set) { 923 this.canvas = set.canvas; 924 this.webGLCurtain = new Curtains({ 925 container: this.canvas, 926 watchScroll: false, 927 pixelRatio: Math.min(1.5, window.devicePixelRatio) 928 }) 929 this.planeElement = set.planeElement; 930 this.mouse = { 931 x: 0, 932 y: 0 933 }; 934 this.params = { 935 vertexShader: WebWave_vs, 936 fragmentShader: WebWave_fs, 937 widthSegments: 40, 938 heightSegments: 40, 939 uniforms: { 940 time: { 941 name: "uTime", 942 type: "1f", 943 value: 0 944 }, 945 resolution: { 946 name: "uReso", 947 type: "2f", 948 value: [innerWidth, innerHeight] 949 } 950 } 951 }; 952 this.initPlane(); 953 } 954 955 initPlane() { 956 this.plane = this.webGLCurtain.addPlane(this.planeElement, this.params); 957 958 if (this.plane) { 959 this.plane.onReady(() => { 960 this.update(); 961 this.initEvent(); 962 }); 963 } 964 } 965 966 update() { 967 this.plane.onRender(() => { 968 this.plane.uniforms.time.value += 0.01; 969 this.plane.uniforms.resolution.value = [innerWidth, innerHeight]; 970 }); 971 } 972 973 initEvent() { 974 let isHovered = false; 975 976 this.planeElement.addEventListener("mouseenter", e => { 977 isHovered = true; 978 }); 979 980 this.planeElement.addEventListener("mouseout", e => { 981 isHovered = false; 982 }); 983 984 this.plane.onRender(() => { 985 if (isHovered) { 986 this.plane.uniforms.time.value += (45 - this.plane.uniforms.time.value) * 0.0375; 987 } else { 988 this.plane.uniforms.time.value += (0 - this.plane.uniforms.time.value) * 0.0375; 989 } 990 }); 991 } 992 } 993 994 if (navigator.userAgent.indexOf('Safari') == -1 || navigator.userAgent.indexOf('Chrome') > -1) { 995 $('.pxl-image-effect1.wave').each(function () { 996 const $this = $(this), 997 canvas = $this.find('.canvas')[0], 998 planeElement = $this.find('.item--image')[0], 999 initialized = $this.data('initialized'); 1000 1001 if (!initialized && canvas && planeElement) { 1002 new ImgCurtain({ 1003 canvas: canvas, 1004 planeElement: planeElement 1005 }); 1006 $this.data('initialized', true); 1007 } 1008 }); 1009 } 1010 1011 1012 if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { 1013 $('.pxl-image-effect1 .image-front').css('opacity', '1'); 1014 } 1015 1016 } 1017 /* Img Carousel 4 */ 1018 function aimo_img_2d($scope) { 1019 const items = gsap.utils.toArray($scope.find(".pxl-image-2d .item")); 1020 if (!items.length) return; 1021 1022 const radiusX = 1200; 1023 const radiusY = 1000; 1024 const activeAngle = -90; 1025 const angleStep = 360 / items.length; 1026 1027 let rotation = 0; 1028 let activeIndex = 0; 1029 1030 let isDragging = false; 1031 let wasDragging = false; 1032 let startX = 0; 1033 1034 function updatePositions() { 1035 const rad = Math.PI / 180; 1036
1037 items.forEach((el, i) => { 1038 const angle = (rotation + i * angleStep + activeAngle) * rad; 1039 const x = Math.cos(angle) * radiusX; 1040 const y = Math.sin(angle) * radiusY; 1041 1042 const relativeIndex = (i - activeIndex + items.length) % items.length; 1043 1044 let opacity = 0; 1045 let rotate = 0; 1046 1047 if (relativeIndex === 0) { 1048 opacity = 1; 1049 rotate = 0; 1050 } else if (relativeIndex === 1 || relativeIndex === items.length - 1) { 1051 opacity = 1; 1052 rotate = relativeIndex === 1 ? 18 : -18; 1053 } else if (relativeIndex === 2 || relativeIndex === items.length - 2) { 1054 opacity = 1; 1055 rotate = relativeIndex === 2 ? 30 : -30; 1056 } 1057 1058 gsap.to(el, { 1059 x, 1060 y, 1061 rotate, 1062 opacity, 1063 duration: 0.4, 1064 ease: "power2.out" 1065 }); 1066 1067 el.classList.toggle("active", i === activeIndex); 1068 }); 1069 } 1070 1071 function goTo(index) { 1072 activeIndex = (index + items.length) % items.length; 1073 rotation = -activeIndex * angleStep; 1074 updatePositions(); 1075 } 1076 1077 // Initial render 1078 goTo(0); 1079 1080 // Click item Äá» chuyá»n 1081 items.forEach((el, i) => { 1082 el.addEventListener("click", (e) => { 1083 // Nếu vừa kéo thì không xá» lý click 1084 if (wasDragging) return; 1085 goTo(i); 1086 }); 1087 1088 // FIX: Nếu img nằm trong <a>, ngÄn má» link khi drag 1089 const link = el.querySelector('a'); 1090 if (link) { 1091 link.addEventListener("click", (e) => { 1092 if (wasDragging) { 1093 e.preventDefault(); 1094 e.stopPropagation(); 1095 } 1096 }); 1097 } 1098 }); 1099 1100 // Scroll page Äá» chuyá»n 1101 let scrollTween; 1102 1103 window.addEventListener("wheel", (e) => { 1104 if (scrollTween && scrollTween.isActive()) return; 1105 if (e.deltaY <= 0) return; 1106 1107 const stepAmount = angleStep / 2; 1108 1109 const targetRotation = rotation - stepAmount; // sang trái 1110 const snappedIndex = Math.round(-targetRotation / angleStep); 1111 1112 scrollTween = gsap.to({ value: rotation }, { 1113 value: -snappedIndex * angleStep, // tween Äến rotation snap luôn 1114 duration: 3, 1115 ease: "power3.out", 1116 onUpdate: function () { 1117 rotation = this.targets()[0].value; 1118 updatePositions(); 1119 }, 1120 onComplete: () => { 1121 goTo(snappedIndex); // Äảm bảo index & rotation Äá»ng bá» 1122 } 1123 }); 1124 }); 1125 1126 1127 1128 1129 // Drag tay Äá» chuyá»n 1130 $scope.on("mousedown touchstart", (e) => { 1131 isDragging = true; 1132 wasDragging = false; 1133 startX = e.pageX || e.originalEvent.touches[0].pageX; 1134 }); 1135 1136 $(document).on("mousemove touchmove", (e) => { 1137 if (!isDragging) return; 1138 const currentX = e.pageX || e.originalEvent.touches[0].pageX; 1139 const diffX = currentX - startX; 1140 1141 if (Math.abs(diffX) > 10) { 1142 wasDragging = true; 1143 goTo(activeIndex + (diffX < 0 ? 1 : -1)); 1144 isDragging = false; 1145 } 1146 }); 1147 1148 $(document).on("mouseup touchend", () => { 1149 isDragging = false; 1150 setTimeout(() => { 1151 wasDragging = false; 1152 }, 100); 1153 }); 1154 1155 // Tá»± Äá»ng xoay sau má»i 5s 1156 setInterval(() => { 1157 goTo(activeIndex + 1); 1158 }, 5000); 1159 } 1160 1161 //animation_scroll 1162 function aimo_animation_scroll() { 1163 const elements = document.querySelectorAll('.animate-on-scroll'); 1164 if (window.innerWidth > 991 && elements.length > 0) {
1165 elements.forEach(function (el) { 1166 gsap.fromTo(el, 1167 { transform: 'translateY(200px)', opacity: 0 }, 1168 { 1169 transform: 'translateY(0)', 1170 opacity: 1, 1171 duration: 1.15, 1172 ease: 'power2.out', 1173 scrollTrigger: { 1174 trigger: el, 1175 start: 'top bottom', 1176 toggleActions: 'play none none none' 1177 } 1178 } 1179 ); 1180 }); 1181 } 1182 } 1183 /* ScrollEffect */ 1184 function aimo_ScrollEffect() { 1185 const textElements = document.querySelectorAll('.pxl---text-scroll'); 1186 1187 if (textElements.length > 0) { 1188 textElements.forEach(function (textElement) { 1189 const splitter = new SplitText(textElement, { 1190 type: "words,chars" 1191 }); 1192 1193 const chars = splitter.chars; 1194 1195 gsap.fromTo(chars, { 1196 filter: 'blur(10px) brightness(30%)', 1197 willChange: 'filter' 1198 }, { 1199 filter: 'blur(0px) brightness(100%)', 1200 ease: 'none', 1201 stagger: 0.05, 1202 scrollTrigger: { 1203 trigger: textElement, 1204 start: 'top bottom-=15%', 1205 end: 'bottom center+=15%', 1206 scrub: 0.2, 1207 }, 1208 }); 1209 }); 1210 } 1211 } 1212 1213 ///image box 1214 function aimo_image_rotate($scope) { 1215 const images = $scope.find('.pxl-image-box2.pxl-image-box-animation .pxl-box-inner .img-counter'); 1216 let current = 0; 1217 1218 function rotateImage(img) { 1219 return gsap.to(img, { 1220 rotation: 360, 1221 duration: 6, 1222 ease: 'linear', 1223 }); 1224 } 1225 1226 function showNextImage() { 1227 const prev = images[current]; 1228 current = (current + 1) % images.length; 1229 const next = images[current]; 1230 1231 // Reset z-index 1232 images.each(function () { 1233 $(this).css('zIndex', 0); 1234 }); 1235 $(next).css('zIndex', 1); 1236 1237 gsap.set(next, { rotation: 0, opacity: 0 }); 1238 gsap.to(next, { opacity: 1, duration: 1 }); 1239 rotateImage(next); 1240 1241 gsap.to(prev, { opacity: 0, duration: 1 }); 1242 } 1243 1244 gsap.set(images[0], { opacity: 1 }); 1245 rotateImage(images[0]); 1246 1247 setInterval(showNextImage, 6000); 1248 } 1249 1250 $(window).on('elementor/frontend/init', function () { 1251 aimo_section_start_render(); 1252 aimo_column_before_render(); 1253 aimo_css_inline_js(); 1254 aimo_section_before_render(); 1255 aimo_zoom_point(); 1256 aimo_scroll_fixed_section(); 1257 aimo_animation_image(); 1258 aimo_process3(); 1259 aimo_split_scroll_color(); 1260 aimo_image_split(); 1261 aimo_webgl_effects(); 1262 aimo_animation_scroll(); 1263 aimo_ScrollEffect(); 1264 elementorFrontend.hooks.addAction('frontend/element_ready/pxl_image_carousel.default', function ($scope) { 1265 aimo_img_2d($scope); 1266 }); 1267 elementorFrontend.hooks.addAction('frontend/element_ready/pxl_contact_form.default', PXL_Icon_Contact_Form); 1268 elementorFrontend.hooks.addAction('frontend/element_ready/pxl_heading.default', function ($scope) { 1269 aimo_split_text($scope); 1270 }); 1271 elementorFrontend.hooks.addAction('frontend/element_ready/pxl_text_marquee.default', function ($scope) { 1272 aimo_item_marquee2($scope); 1273 }); 1274 elementorFrontend.hooks.addAction('frontend/element_ready/pxl_image_box.default', function ($scope) { 1275 aimo_image_rotate($scope); 1276 }); 1277 }); 1278 1279})(jQuery);
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.