PageSourceSearch

https://hotelqueen-shinjuku.com/js/index.js

js hotelqueen-shinjuku.com collected 2026-10-04 13:19:51 UTC 4,775 bytes, 162 lines download raw bytes

1
2gsap.registerPlugin(ScrollTrigger);
3
4/**
5 * ↓ 予約ボタンscroll時に非表示にする
6 */
7// スクロール中フラグを <html> に付与
8let showTimer;
9ScrollTrigger.addEventListener("scrollStart", () => {
10    document.documentElement.classList.add("is-scrolling");
11    // 連続スクロールに備えて一旦タイマーは消す
12    if (showTimer) showTimer.kill();
13});
14
15// スクロール停止後に少し遅らせて再表示(体感を良くする)
16ScrollTrigger.addEventListener("scrollEnd", () => {
17    // 200ms 後に表示(数値は好みで)
18    showTimer = gsap.delayedCall(0.2, () => {
19        document.documentElement.classList.remove("is-scrolling");
20    });
21});
22
23
24/**
25 * promo-text h2 strong → span の順に:letterSpacing(0.15em→0.03em) + fade
26 * ふわっとを終盤まで残して、最後ほど減速
27 */
28(() => {
29    const h2 = document.querySelector(".promo-text h2");
30    if (!h2) return;
31
32    const strong = h2.querySelector("strong");
33    const span = h2.querySelector("span");
34    if (!strong || !span) return;
35
36    // 初期:ふわっと(広め&薄め&少し下&少しボケ)
37    gsap.set([strong, span], {
38        autoAlpha: 0,
39        letterSpacing: "0.05em",
40        filter: "blur(3px)"
41    });
42
43    const tl = gsap.timeline({
44        scrollTrigger: {
45            trigger: ".promo-text",
46            start: "top 75%",
47            toggleActions: "play none none reverse"
48            // once: true にしたいなら↑を消して once: true を追加でもOK
49        }
50    });
51
52    // --- strong(先) ---
53    tl.to(strong, {
54        duration: 0.6,
55        autoAlpha: 0.75,
56        letterSpacing: "0.05em",
57        filter: "blur(3px)",
58        ease: "power2.out"
59    })
60        .to(strong, {
61            duration: 1.05,
62            autoAlpha: 1,
63            letterSpacing: "0.03em",
64            filter: "blur(0px)",
65            ease: "expo.out" // 終盤ほどゆっくり
66        }, ">-0.10")
67
68        // --- span(直後) ---
69        .to(span, {
70            duration: 0.6,
71            autoAlpha: 0.75,
72            letterSpacing: "0.05em",
73            filter: "blur(3px)",
74            ease: "power2.out"
75        }, ">-0.45")
76        .to(span, {
77            duration: 1.05,
78            autoAlpha: 1,
79            letterSpacing: "0.03em",
80            filter: "blur(0px)",
81            ease: "expo.out"
82        }, ">-0.10");
83})();
84/**
85 * ↓ .viproom-contentsのアニメーション発火
86 */
87gsap.fromTo(".viproom-contents",
88    { autoAlpha: 0, y: 20 },
89    {
90        autoAlpha: 1,
91        y: 0,
92        duration: 2,
93        ease: "power3.out",
94        scrollTrigger: {
95            trigger: ".viproom-contents",
96            start: "top 80%",
97            end: "bottom 20%",
98            toggleActions: "play reverse play reverse",
99            // 入るときに再生、出るときに逆再生
100        }
101    }
102);
103
104gsap.utils.toArray(".service-item").forEach(item => {
105    gsap.fromTo(item,
106        { autoAlpha: 0, y: 0 },
107        {
108            autoAlpha: 1,
109            y: 0,
110            duration: 0.5,
111            ease: "power3.out",
112            scrollTrigger: {
113                trigger: item,
114                start: "top 80%",
115                end: "bottom 30%",
116                toggleActions: "play none none none", // アニメーションは一方向だけ
117                onLeave: () => gsap.to(item, { autoAlpha: 0, duration: 0 }),
118                onEnterBack: () => gsap.to(item, { autoAlpha: 1, duration: 0.5 })
119            }
120        }
121    );
122});
123
124/**
125 * ↓ .reasonを順番に発火
126 */
127gsap.utils.toArray('.reason').forEach((el) => {
128    ScrollTrigger.create({
129        trigger: el,
130        start: "top 75%",
131        onEnter: () => el.classList.add('visible'),
132        once: true // 一度可視になったら以後は発火しない
133    });
134});
135
136document.addEventListener("DOMContentLoaded", () => {
137    const wrap = document.querySelector(".page-title__position");
138    if (!wrap) return;
139
140    // 分割対象:英字があるならそれ、なければ全体
141    const target = wrap.querySelector(".page-title__en") || wrap;
142
143    // 二重に分割しない
144    if (target.dataset.splitted === "1") return;
145    target.dataset.splitted = "1";
146
147    const text = (target.textContent || "").trimEnd();
148    target.textContent = "";
149
150    const delayStep = 45; // 1文字ごとの遅延(ms)
151
152    [...text].forEach((ch, i) => {
153        const span = document.createElement("span");
154        span.className = "char";
155        span.textContent = ch === " " ? "\u00A0" : ch; // スペース維持
156        span.style.transitionDelay = `${i * delayStep}ms`;
157        target.appendChild(span);
158    });
159
160    wrap.classList.add("is-ready");
161    requestAnimationFrame(() => wrap.classList.add("is-in"));
162});

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.