PageSourceSearch

https://pondmakers.com/theme/basic/js/site-custom.js?ver=191202

js pondmakers.com collected 2026-10-02 00:07:42 UTC 11,544 bytes, 457 lines download raw bytes

1/*
2* File       : site-custom.js
3* Author     : B-WORKER
4*      
5*/
6
7jQuery(function($) {
8
9/* **************************************** *
10 * Functions INIT
11 * **************************************** */
12main_visual_slider();
13newsSlider();
14mainAbout();
15mainTech();
16footerHeight();
17
18 /* **************************************** *
19 * script
20 * **************************************** */ 
21
22//  반응형
23 var responsive_set = function(el) {
24	var $width =$(window).width();	
25
26	if ($width <= 860) {
27		initCountWhenCenter();
28	}else if ($width < 1023) {
29		//tablet
30	}else{
31		//pc
32	}
33}
34responsive_set();
35	
36window.addEventListener("resize", ()=>{
37	responsive_set();
38});
39
40//main visual
41function main_visual_slider(){	
42	if(!$('.main-visual').length){return;}	
43
44	const visualSwiper = new Swiper('.main-visual-container', {
45		slidesPerView : 1,
46		slidesPerGroup : 1,
47		navigation: {	
48			nextEl: '.main-visual .swiper-btn--next',	
49			prevEl: '.main-visual .swiper-btn--prev',	
50		},
51		pagination: {
52			el: '.swiper-pagination',
53			clickable: true,
54		},
55		grabCursor: false,
56		speed: 600,
57		autoplay: {
58			delay: 3000,
59			disableOnInteraction: false,
60		},
61		loop: true,
62		effect: "fade",
63		on: {
64			init: function(){
65				$(".main-visual__count > em").text(this.slides.length);
66			},
67			slideChange: function (swiper) {
68				$(".main-visual__count > i").text(this.realIndex + 1);	
69				progressBar(this);
70			},
71		},
72	});
73
74	function progressBar(el){
75		const Swiper = el;
76		const speed = Swiper.activeIndex == 0 ? -Swiper.params.speed : Swiper.params.speed;
77		const delay = Swiper.params.autoplay.delay;
78		const activeSlide = Swiper.slides[Swiper.activeIndex];
79		const currentVideoEl = activeSlide.querySelector('video');
80		const proVal = !currentVideoEl ? speed + delay : currentVideoEl.duration * 1000;
81		activeSlide.style.setProperty('--progress-duration', `${proVal}ms`);
82
83		if( !currentVideoEl ) return;
84		if( Swiper.autoplay.running ) currentVideoEl.addEventListener('ended', ()=>Swiper.slideNext());
85		currentVideoEl.currentTime = 0;
86		currentVideoEl.play();
87	}
88
89	$('.main-visual__play').on('click', function() {
90		if($(this).hasClass("pause")){
91			visualSwiper.autoplay.stop();
92		}else{
93			visualSwiper.autoplay.start();
94		}		
95
96		$('.main-visual__play').removeClass('on');
97		$(this).siblings('.main-visual__play').addClass('on');
98	});
99}
100
101function newsSlider() {
102  if (!$('.main-news__slider').length) return;
103
104  const track = document.querySelector('.main-news__track');
105  const slides = track.children;
106
107  // ✅ 슬라이드가 3개 미만이면 작동하지 않음
108  if (slides.length < 3) return;
109
110  const originalHTML = track.innerHTML;
111  track.innerHTML = originalHTML + originalHTML + originalHTML; // 앞/중앙/뒤
112
113  const totalWidth = track.scrollWidth / 3;
114  gsap.set(track, { x: -totalWidth });
115
116  let autoTween = null;
117
118  function startAuto() {
119    if (autoTween) autoTween.kill();
120    autoTween = gsap.to(track, {
121      x: `-=${totalWidth}`,
122      duration: 30,
123      ease: "none",
124      repeat: -1
125    });
126  }
127
128  function wrapX(x) {
129    if (x > 0) x -= totalWidth;
130    if (x < -totalWidth * 2) x += totalWidth;
131    return x;
132  }
133
134  startAuto();
135
136  Draggable.create(track, {
137    type: "x",
138    inertia: false,
139    onPress() {
140      if (autoTween) autoTween.kill();
141    },
142    onDrag() {
143      this.x = wrapX(this.x);
144      gsap.set(track, { x: this.x });
145    },
146    onRelease() {
147      const x = wrapX(gsap.getProperty(track, "x"));
148      gsap.set(track, { x });
149      startAuto();
150    }
151  });
152}
153
154
155
156// about
157function mainAbout() {
158  gsap.registerPlugin(ScrollTrigger);
159
160  ScrollTrigger.matchMedia({
161    "(min-width: 861px)": function () {
162
163      const $section   = ".main-about";
164      const $box       = ".main-about__box";
165      const $titleWrap = ".main-about__title";
166      const $top       = ".main-about-top";
167      const $bottom    = ".main-about-bottom .wide-wrap";
168
169      const enEls = gsap.utils.toArray(".main-about__title h3[data-font-en]");
170      const koEl  = document.querySelector(".main-about__title h3:not([data-font-en])");
171
172      if (!koEl || enEls.length < 2) return;
173
174      const enLeft  = enEls[0];
175      const enRight = enEls[1];
176
177	  const titleTexts = ".main-about__title h3";
178
179      // ✅ 원(배경) 초기
180      gsap.set($box, {
181        opacity: 1,
182        width: "160vmax",
183        height: "160vmax",
184        borderRadius: "50%",
185        scale: 0,
186        transformOrigin: "50% 50%",
187        willChange: "transform"
188      });
189
190      // ✅ title 기본
191      gsap.set($titleWrap, {
192        xPercent: 0,
193        willChange: "transform"
194      });
195
196      // ✅ 가운데 텍스트(레퍼런스 txtmotion > p 역할)
197      // - maxWidth 0에서 시작해서 확장
198      gsap.set(koEl, {
199        display: "inline-block",
200        overflow: "hidden",
201        maxWidth: "0rem",
202        opacity: 1,
203        verticalAlign: "top"
204      });
205
206      // ✅ strong(영문)들
207      gsap.set([enLeft, enRight], {
208        opacity: 1,
209        paddingLeft: "2rem",
210        paddingRight: "2rem",
211        x: "0rem"
212      });
213
214      // ✅ 하단 숨김
215      gsap.set($bottom, { opacity: 0 });
216
217      // ✅ 카운트 1회 실행
218      let counted = false;
219      function startCount() {
220        if (counted) return;
221        counted = true;
222
223        const wrap = document.getElementById("count");
224        if (!wrap) return;
225
226        wrap.querySelectorAll(".count-num").forEach(span => {
227          const to = parseInt(span.dataset.to || span.textContent, 10) || 0;
228          const obj = { val: 0 };
229
230          gsap.to(obj, {
231            val: to,
232            duration: 1.4,
233            ease: "power2.out",
234            onUpdate: () => (span.textContent = Math.round(obj.val)),
235            onComplete: () => (span.textContent = to)
236          });
237        });
238      }
239
240      // ✅ timeline
241      const about = gsap.timeline({
242        defaults: { ease: "none" },
243        scrollTrigger: {
244          trigger: $section,
245          start: "top top",
246          end: "+=4000",
247          pin: true,
248          scrub: 1.2,
249          anticipatePin: 1,
250          invalidateOnRefresh: true,
251          onRefresh: () => {
252            // 리프레시 시 폭/이동값 초기화(폰트 로딩/리사이즈 대비)
253            gsap.set(koEl, { maxWidth: "0rem" });
254            gsap.set([enLeft, enRight], { x: "0rem", opacity: 1 });
255          }
256        }
257      });
258
259      // 1) ✅ 원 먼저 커짐
260      about
261		  .to($box, {
262			scale: 1,
263			background: "var(--c-gradient)",
264			duration: 1.5
265		  }, 0)
266
267		  // ✅ 원 안에 들어오면서 텍스트 흰색
268		  .to(titleTexts, {
269			color: "#fff",
270			duration: 0.4,
271			ease: "power1.out"
272		  }, 0.2);
273
274      // 2) ✅ txtmotion 구간
275      const t0 = 0.85;
276
277      // 가운데 텍스트 폭 계산
278      const koW = () => koEl.scrollWidth;                 // px
279      const koMax = () => `${(koW() + 40)}rem`;           // ✅ +40rem(=+40px) 여유치로 짤림 방지
280
281      // strong 벌어질 거리 = (중앙 텍스트 폭/2) + 여백
282      const gap = 40;                                    // 가운데 텍스트 양쪽 여백 (원하면 20~80)
283      const spread = () => (koW() / 2) + gap;
284
285      about
286        // (1) 타이틀 랩 살짝 이동
287        .to($titleWrap, { xPercent: -5.4, duration: 0.8 }, t0)
288
289        // (2) 가운데 텍스트: 0rem -> 텍스트 폭(+여유)까지 확장
290        .to(koEl, { maxWidth: koMax, duration: 0.7 }, t0)
291        // ✅ 애니 끝나면 제한 풀기(마지막 글자 짤림 100% 방지)
292        .set(koEl, { maxWidth: "none" }, t0 + 0.7)
293
294        // (3) strong padding + 중앙 텍스트 폭만큼 자동 벌어짐
295        .to(enLeft, {
296          paddingLeft: "10rem",
297          paddingRight: "10rem",
298          x: () => `-${spread()}rem`,
299          opacity: 0.25,
300          duration: 0.7
301        }, t0)
302        .to(enRight, {
303          paddingLeft: "10rem",
304          paddingRight: "10rem",
305          x: () => `${spread()}rem`,
306          opacity: 0.25,
307          duration: 0.7
308        }, t0)
309			  
310  // ✅ 끝나면 타이틀 랩 원위치 (왼쪽 쏠림 방지)
311  .to($titleWrap, { xPercent: 0, duration: 0.4 }, t0 + 0.7)
312
313// ✅ 여기서 머무르는 구간(변화 없음, 시간만 소비)
314// 숫자 0.8~1.6 정도로 조절 (클수록 더 오래 머뭄)
315.to({}, { duration: 1.2 }, t0 + 1.1)
316
317        // (4) strong fade out
318        .to([enLeft, enRight], { opacity: 0, duration: 0.5 }, t0 + 0.55);
319
320      // 3) 상단 페이드아웃
321      about.to($top, { opacity: 0, duration: 0.35 }, t0 + 1.5)
322
323      // 4) 하단 등장 + 카운트
324      about
325        .to($bottom, { opacity: 1, duration: 0.35 }, t0 + 1.15)
326        .add(() => startCount(), t0 + 1.22);
327
328      // cleanup
329      return () => {
330        about.scrollTrigger && about.scrollTrigger.kill();
331        about.kill();
332      };
333    },
334
335    "(max-width: 860px)": function () {
336      return;
337    }
338  });
339}
340
341
342
343
344
345// 반응형 카운팅
346function initCountWhenCenter() {
347  // ===== 카운트 옵저버 전역으로 1개만 =====
348let countIO = null;
349
350//  반응형
351var responsive_set = function() {
352  var w = $(window).width();
353
354  if (w < 860) {
355    initCountWhenCenter();     // "세팅"만 하고, 중앙 오기 전엔 실행 안 함
356  } else {
357    // 모바일 아니면 옵저버 제거
358    if (countIO) {
359      countIO.disconnect();
360      countIO = null;
361    }
362  }
363};
364responsive_set();
365
366window.addEventListener("resize", () => {
367  responsive_set();
368});
369
370// ===== 반응형 카운팅 (GSAP 없이) =====
371function initCountWhenCenter() {
372  const wrap = document.querySelector('#count');
373  if (!wrap) return;
374
375  // 이미 한번 끝났으면 다시 안 함
376  if (wrap.dataset.countDone === "1") return;
377
378  const nums = [...wrap.querySelectorAll('.count-num')];
379  const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
380
381  const animateCount = (el, to, duration = 1600) => {
382    const from = Number(String(el.textContent).replace(/,/g, '')) || 0;
383    const start = performance.now();
384
385    const tick = (now) => {
386      const t = Math.min((now - start) / duration, 1);
387      const v = Math.floor(from + (to - from) * easeOutCubic(t));
388      el.textContent = v.toLocaleString('en-US');
389      if (t < 1) requestAnimationFrame(tick);
390    };
391
392    requestAnimationFrame(tick);
393  };
394
395  const run = () => {
396    nums.forEach((el) => {
397      const to = Number(el.dataset.to || 0);
398      animateCount(el, to);
399    });
400    wrap.dataset.countDone = "1"; // ✅ 끝났다고 표시
401  };
402
403  // 옵저버가 이미 있으면 중복 생성 금지
404  if (countIO) return;
405
406  countIO = new IntersectionObserver(
407    (entries) => {
408      entries.forEach((e) => {
409        if (e.isIntersecting) {
410          run();
411          countIO.disconnect();
412          countIO = null;
413        }
414      });
415    },
416    {
417      root: null,
418      // ✅ 중앙 "밴드(10%)"로 감지: 45%~55% 구간에 들어오면 트리거
419      rootMargin: "-45% 0px -45% 0px",
420      threshold: 0,
421    }
422  );
423
424  countIO.observe(wrap);
425}
426
427}
428
429// 문화기술
430function mainTech(){
431	const tech = gsap.timeline({
432		scrollTrigger:{
433			trigger:".main-tech",
434			start:"0% 0%",
435			end:"80% 120%",
436			scrub:1,
437		}
438	});
439
440	gsap.set(".main-tech__thumb li",{scale:0});
441
442	tech
443	.to(".main-tech__thumb li:first-child",{scale:1},"1st")
444	.to(".main-tech__thumb li:nth-child(2)",{scale:1},"2nd")
445	.to(".main-tech__tag li",0.1,{yPercent:-100},"2nd")
446	.to(".main-tech__title li",0.1,{yPercent:-100},"2nd")
447}
448
449// footer
450function footerHeight() {
451	const footerHeight = Math.round($('.footer-inr').outerHeight());
452	$('#footer').height(footerHeight);
453}
454  
455
456}); // End jQuery
457

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.