PageSourceSearch

https://www.tokyodome-hotels.co.jp/assets/common/scripts/modules/mvAnimation.js

js tokyodome-hotels.co.jp collected 2026-09-24 10:46:25 UTC 3,024 bytes, 93 lines download raw bytes

1(() => {
2    const config = {
3        selectors: {
4            item: '.fn-animation-item',
5            button: '.js-state-btn',
6            buttonText: '.fn-state-btn__text',
7        },
8        interval: 5500,
9        texts: {
10            play: '再生する',
11            stop: '停止する',
12        },
13    };
14    const items = document.querySelectorAll(config.selectors.item);
15    const btn = document.querySelector(config.selectors.button);
16    const btnText = document.querySelector(config.selectors.buttonText);
17    if (!items.length || !btn || !btnText)
18        return;
19    let current = 0;
20    let intervalId = null;
21    let isPlaying = false;
22    /** 停止時のtransformを保存 */
23    const savedTransforms = new Map();
24    /** transformの復元処理 */
25    const restoreTransform = (item) => {
26        const saved = savedTransforms.get(item);
27        if (!saved)
28            return;
29        item.style.transform = saved;
30        requestAnimationFrame(() => {
31            item.style.transform = '';
32        });
33    };
34    /** 指定インデックスのアイテムを表示 */
35    const showItem = (index) => {
36        items.forEach((item, i) => {
37            item.classList.remove('is-show', 'is-zoom');
38            item.style.transition = '';
39            if (i === index) {
40                item.classList.add('is-show', 'is-zoom');
41                restoreTransform(item);
42            }
43        });
44    };
45    /** 再生開始 */
46    const startAnimation = () => {
47        if (intervalId !== null)
48            return;
49        showItem(current);
50        intervalId = window.setInterval(() => {
51            current = (current + 1) % items.length;
52            showItem(current);
53        }, config.interval);
54        isPlaying = true;
55        btnText.textContent = config.texts.stop;
56        btn.classList.remove('is-play');
57    };
58    /** 停止処理 */
59    const stopAnimation = () => {
60        if (intervalId === null)
61            return;
62        window.clearInterval(intervalId);
63        intervalId = null;
64        // 現在のtransformを固定・保存
65        items.forEach((item) => {
66            if (item.classList.contains('is-show')) {
67                const style = window.getComputedStyle(item);
68                savedTransforms.set(item, style.transform);
69                item.style.transform = style.transform;
70                item.classList.remove('is-zoom');
71            }
72        });
73        isPlaying = false;
74        btnText.textContent = config.texts.play;
75        btn.classList.add('is-play');
76    };
77    /** イベント登録 */
78    const bindEvents = () => {
79        // ボタンクリック
80        btn.addEventListener('click', () => {
81            isPlaying ? stopAnimation() : startAnimation();
82        });
83        // ページ離脱時
84        window.addEventListener('beforeunload', stopAnimation);
85    };
86    /** 初期化 */
87    const init = () => {
88        startAnimation();
89        bindEvents();
90    };
91    document.addEventListener('DOMContentLoaded', init);
92})();
93export {};

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.