PageSourceSearch

https://www.orix.co.jp/grp/js/top.js

js orix.co.jp collected 2026-09-24 17:13:18 UTC 18,053 bytes, 627 lines download raw bytes

1$(function () {
2
3
4  /* =========================================
5      PC/SPだし分け
6  ========================================= */
7  const mediaQuery = window.matchMedia('(min-width: 641px)');
8  mediaQuery.addEventListener('change', windowSwitch);
9
10  function windowSwitch(e) {
11    const isDesktop = e && typeof e.matches !== 'undefined' ? e.matches : mediaQuery.matches;
12    spHoverUnset(isDesktop);
13
14    if (isDesktop) {
15
16    } else {
17      spVaInit();
18    }
19  }
20
21  //初期化
22  windowSwitch();
23
24  /* =========================================
25      #クリック無効
26  ========================================= */
27  $(document).on('click', '.tp a', function (e) {
28    if ($(this).attr('href') == '#') {
29      e.preventDefault();
30    }
31  });
32
33  /* =========================================
34      spホバー無効
35  ========================================= */
36  function spHoverUnset(isDesktop) {
37    const hvTarget = $('.viewall, .newsReleases__tabBtn a, .newsReleases__list a, .kv__infoItem a, .latestUpdates a, .arrowPrev, .arrowNext, .caution a');
38    if (isDesktop) {
39      hvTarget.addClass('pcDisp');
40    }
41    else {
42      hvTarget.removeClass('pcDisp');
43    }
44  }
45
46  /* =========================================
47      h2見出し
48  ========================================= */
49  //アニメーション用テキスト分割
50  document.querySelectorAll('.h2__animTxt').forEach(el => {
51    const html = el.innerHTML;
52    const lines = html.split(/<br\s*\/?>/i);
53    el.textContent = '';
54
55    lines.forEach((line, lineIndex) => {
56      const baseDelay = 0;
57
58      [...line.trim()].forEach((char, charIndex) => {
59        const span = document.createElement('span');
60        const content = char === ' ' ? '\u00A0' : char;
61        span.setAttribute('data-text', content);
62
63        span.style.animationDelay = `${baseDelay + (charIndex * 0.1)}s`;
64        el.appendChild(span);
65      });
66
67      if (lineIndex < lines.length - 1) {
68        el.appendChild(document.createElement('br'));
69      }
70    });
71  });
72
73  //発火
74  const observer = new IntersectionObserver((entries) => {
75    entries.forEach(entry => {
76      if (entry.isIntersecting) {
77        // 画面に入ったらクラスを付与
78        $(entry.target).addClass('active');
79
80        // 一度発火したら監視を解除
81        observer.unobserve(entry.target);
82      }
83    });
84  }, {
85    threshold: 0.2 // 20%見えたら実行
86  });
87
88  // 対象要素をループして監視
89  $('.js-scrollh2').each(function () {
90    observer.observe(this);
91  });
92
93
94  /* =========================================
95        view all
96    ========================================= */
97  // ユニークID生成用のカウンター
98  let gradCounter = 0;
99
100  // --- 【共通】初期化処理(SP/PC問わず実行) ---
101  function vaBtnInit($btn) {
102    if ($btn.data('anim-state')) return $btn.data('anim-state');
103
104    const $line = $btn.find('.viewall__animationLine');
105    const $grad = $btn.find('linearGradient');
106
107    if (!$line.length || !$grad.length) return null;
108
109    const uniqueId = `dynamic-grad-${gradCounter++}`;
110    $grad.attr('id', uniqueId);
111    $line.attr('stroke', `url(#${uniqueId})`);
112
113    const state = {
114      $line: $line,
115      $grad: $grad,
116      current: 10,
117      target: 10,
118      isAnimating: false // 二重ループ防止用
119    };
120
121    $btn.data('anim-state', state);
122
123    // 初期状態の描画 (10%)
124    vaRender(state);
125    return state;
126  }
127
128  function vaRender(state) {
129    state.$line.css('stroke-dashoffset', 100 - state.current);
130    const gradWidth = Math.min(100, state.current * 3.0);
131    state.$grad.attr('x2', gradWidth + '%');
132  }
133
134  function vaAnimate(state) {
135    const diff = state.target - state.current;
136
137    // 差分が十分に小さくなったら停止
138    if (Math.abs(diff) < 0.1) {
139      state.current = state.target;
140      vaRender(state);
141      state.isAnimating = false;
142      return;
143    }
144
145    state.current += diff * 0.1;
146    vaRender(state);
147
148    requestAnimationFrame(() => vaAnimate(state));
149  }
150
151  const vaObserver = new MutationObserver((mutations) => {
152    mutations.forEach((mutation) => {
153      mutation.addedNodes.forEach((node) => {
154        // 要素ノードかつ .viewall を持っているかチェック
155        if (node.nodeType === 1) {
156          const $node = $(node);
157          if ($node.hasClass('viewall')) {
158            vaBtnInit($node);
159          }
160          // 子要素の中に .viewall がある場合も考慮
161          $node.find('.viewall').each(function () {
162            vaBtnInit($(this));
163          });
164        }
165      });
166    });
167  });
168
169  // body全体の要素追加を監視
170  vaObserver.observe(document.body, {
171    childList: true,
172    subtree: true
173  });
174
175  // 1. マウスイベントは .pcDisp を持っている時だけ target を更新する
176  $(document).on('mouseenter', '.viewall.pcDisp', function () {
177    const state = $(this).data('anim-state');
178    if (!state) return;
179
180    state.target = 100;
181
182    // アニメーションが動いていなければ開始
183    if (!state.isAnimating) {
184      state.isAnimating = true;
185      vaAnimate(state);
186    }
187  }).on('mouseleave', '.viewall.pcDisp', function () {
188    const state = $(this).data('anim-state');
189    if (!state) return;
190
191    state.target = 10;
192
193    if (!state.isAnimating) {
194      state.isAnimating = true;
195      vaAnimate(state);
196    }
197  });
198
199  $('.viewall').each(function () {
200    vaBtnInit($(this));
201  });
202
203  // sp用
204  function spVaInit() {
205    $('.viewall').each(function () {
206      const state = $(this).data('anim-state');
207      if (state) {
208        state.current = 10;
209        state.target = 10;
210        state.$line.css('stroke-dashoffset', 90);
211        state.$grad.attr('x2', '30%');
212      }
213    });
214  }
215
216  /* =========================================
217        ニュースリリース タブ
218    ========================================= */
219  // タブ切り替え
220  function switchTab(tab_id) {
221    if (!tab_id) return;
222
223    const cleanId = tab_id.replace('#', '');
224    const $targetBtn = $(`[data-nrtab-btn="${cleanId}"]`);
225
226    if ($targetBtn.length > 0) {
227      // ボタンの切り替え
228      $('.js-nrTab').removeClass('active');
229      $targetBtn.parent().addClass('active');
230
231      // パネルの切り替え(完全一致セレクタ)
232      $('.js-nrTabPanel').removeClass('active');
233      $(`.js-nrTabPanel#panel_${cleanId}`).addClass('active');
234    }
235  }
236
237  // 初期読み込み時
238  const hash = window.location.hash.replace('#', '');
239  if (hash) {
240    switchTab(hash);
241  }
242
243  // クリック時
244  $('[data-nrtab-btn]').on('click', function (e) {
245    e.preventDefault();
246    e.stopImmediatePropagation();
247
248    const tab_id = $(this).data('nrtab-btn').toString();
248 // 文字列として取得
249    const cleanId = tab_id.replace('#', '');
250
251    // URLの書き換え(#が重ならないようにパスから再構築)
252    const newUrl = window.location.pathname + window.location.search + '#' + cleanId;
253    history.pushState(null, null, newUrl);
254
255    switchTab(cleanId);
256    nrTextCut();
257    return false;
258  });
259
260
261  /* =========================================
262          ニュースリリース 文字数制限
263      ========================================= */
264  function nrTextCut() {
265    $('.newsReleases__title').each(function () {
266      const $title = $(this);
267      const $target = $title.find('.newsReleases__txtLine');
268
269      if ($target.length === 0) return;
270
271      // --- 初期化処理 ---
272      if (!$target.data('original-text')) {
273        $target.data('original-text', $target.text());
274      }
275
276      $target.text($target.data('original-text'));
277
278      // --- 閾値の計算 ---
279      const lineHeight = parseFloat($target.css('line-height'));
280      const threshold = lineHeight * 3.5;
281
282      // --- 判定とカット処理 ---
283      if ($title.height() > threshold) {
284        let text = $target.text();
285
286        // 3行文まで文字カット
287        while (text.length > 0 && $title.height() > threshold) {
288          text = text.slice(0, -1);
289          $target.text(text + '…');
290        }
291      }
292    });
293  }
294
295  //ロード時
296  nrTextCut();
297  //画面リサイズ時
298  $(window).on('resize', function () {
299    nrTextCut();
300  });
301
302
303  //KV(動画)
304  const container = document.getElementById('kv_video_container');
305  let kvVideo = document.getElementById('kv_background_time');
306
307  if (container && !kvVideo) {
308    kvVideo = document.createElement('video');
309    kvVideo.id = 'kv_background_time';
310    kvVideo.muted = true;
311    kvVideo.setAttribute('muted', '');
312    kvVideo.playsInline = true;
313    kvVideo.loop = true;
314
315    const currentHour = new Date().getHours();
316    const imgDay = '/grp/images/movie_day.mp4';
317    const imgNight = '/grp/images/movie_night.mp4';
318
319    kvVideo.src = (currentHour >= 5 && currentHour < 17) ? imgDay : imgNight;
320
321    const showKvElements = () => {
322      document.querySelectorAll('.kv').forEach(el => {
323        el.classList.add('is-active');
324      });
325    };
326
327    kvVideo.addEventListener('loadeddata', showKvElements, { once: true });
328    kvVideo.addEventListener('playing', showKvElements, { once: true });
329
330    container.appendChild(kvVideo);
331
332    const playPromise = kvVideo.play();
333    if (playPromise !== undefined) {
334      playPromise.catch((error) => {
335        console.warn('Playback prevented:', error);
336      });
337    }
338
339    setTimeout(() => {
340      showKvElements();
341    }, 2000);
342  }
343
344  const movieBtn = document.getElementById('js_movieBtn');
345  const kvArea = document.getElementById('js_kvArea');
346
347  if (movieBtn && kvArea && kvVideo) {
348    let isStopped = false;
349
350    movieBtn.addEventListener('click', function () {
351      isStopped = !isStopped;
352
353      if (isStopped) {
354        kvVideo.pause();
355        kvArea.classList.add('is-paused');
356      } else {
357        const playPromise = kvVideo.play();
358        if (playPromise !== undefined) {
359          playPromise.catch(() => { });
360        }
361        kvArea.classList.remove('is-paused');
362      }
363    });
364  }
365
366  document.querySelectorAll('.kv__lead').forEach(el => {
367    const html = el.innerHTML;
368    const lines = html.split(/<br\s*\/?>/i);
369    el.textContent = '';
370
371    lines.forEach((line, lineIndex) => {
372      const baseDelay = lineIndex < 2 ? 2 : 3;
373
374      [...line.trim()].forEach((char, charIndex) => {
375        const span = document.createElement('span');
376        const content = char === ' ' ? '\u00A0' : char;
377        span.setAttribute('data-text', content);
378
379        span.style.animationDelay = `${baseDelay + (charIndex * 0.1)}s`;
380        el.appendChild(span);
381      });
382
383      if (lineIndex < lines.length - 1) {
384        el.appendChild(document.createElement('br'));
385      }
386    });
387    const leadWidth = el.offsetWidth;
388    const leadHeight = el.offsetHeight;
389
390    const spans = el.querySelectorAll('span');
391    
392    spans.forEach(span => {
393      const leftOffset = span.offsetLeft;
394      const topOffset = span.offsetTop;
395      
396      span.style.backgroundSize = `${leadWidth}px ${leadHeight}px`;
397      span.style.backgroundPosition = `-${leftOffset}px -${topOffset}px`;
398    });
399  });
400
401  //KV(最新情報) カルーセル
402  const $sliderNews = $('.kv__infoList');
403  $sliderNews.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
404    $(this).find('.slick-slide[data-slick-index="' + currentSlide + '"]').addClass('is-exiting');
405  });
406  $sliderNews.on('afterChange', function (event, slick, currentSlide) {
407    $(this).find('.is-exiting').removeClass('is-exiting');
408  });
409  $sliderNews.slick({
410    autoplay: true,
411    autoplaySpeed: 5000,
412    speed: 500,
413    fade: true,
414    cssEase: 'linear',
415    arrows: false,
416    dots: false,
417    pauseOnHover: true
418  });
419
420  // KV リング
421  function updateScale() {
422    const isMobile = window.innerWidth <= 640;
423    const vwValue = isMobile ? 20 : 10;
424    const ringSize = (window.innerWidth * vwValue) / 100;
425    const diagonal = Math.sqrt(Math.pow(window.innerWidth, 2) + Math.pow(window.innerHeight, 2));
426    const scaleValue = (diagonal / ringSize) * 1.3;
427
428    document.documentElement.style.setProperty('--ring-scale', scaleValue);
429  }
430
431  window.addEventListener('resize', updateScale);
432  updateScale();
433
434  //最新情報 カルーセル
435  const $slider = $('.latestUpdates__slickArea');
436  let isSlickActive = false;
437
438  function toggleSlick() {
439    if (window.matchMedia('(max-width: 640px)').matches) {
440      if (isSlickActive) {
441        $slider.slick('unslick');
442        //$slider.find('.js-manual-clone').remove();
443        isSlickActive = false;
444      }
445    } else {
446      if (!isSlickActive) {
447        // const $clones = $slider.children().clone().addClass('js-manual-clone');
448        //$slider.append($clones);
449
450        $slider.slick({
451          autoplay: false,
452          infinite: false,
453          slidesToShow: 3,
454          slidesToScroll: 1,
455          initialSlide: 0,
456          prevArrow: '.arrowPrev',
457          nextArrow: '.arrowNext',
458          variableWidth: true
459        });
460
461        isSlickActive = true;
462      }
463    }
464  }
465
466  // ページ読み込み時に実行
467  toggleSlick();
468
469  // 画面をリサイズした時に実行
470  $(window).on('resize', function () {
471    toggleSlick();
472  });
473
474  //データで見る 背景アニメーション
475  const curvedWrapper = document.querySelector('.keyNumbers');
476  if (!curvedWrapper) return;
477
478  const maxCurve = parseInt(getComputedStyle(curvedWrapper).getPropertyValue('--max-curve'), 10);
479
480  const updateCurve = () => {
481    const rect = curvedWrapper.getBoundingClientRect();
482    const windowHeight = window.innerHeight;
483    const startPos = windowHeight * 0.6;
484    const endPos = 150;
485
486    let progress = (startPos - rect.top) / (startPos - endPos);
487    progress = Math.max(0, Math.min(progress, 1));
488
489    const currentCurve = maxCurve * (1 - progress);
490    curvedWrapper.style.setProperty('--curve-y', `${currentCurve}px`);
491  };
492
493  let ticking = false;
494  window.addEventListener('scroll', () => {
495    if (!ticking) {
496      window.requestAnimationFrame(() => {
497        updateCurve();
498        ticking = false;
499      });
500      ticking = true;
501    }
502  });
503
504  window.addEventListener('resize', () => {
505    window.requestAnimationFrame(updateCurve);
506  });
507  window.addEventListener('load', updateCurve);
508
509  updateCurve();
510
511  //データで見る カウントアップ
512  //カウントアップのアニメーション
513  const animateCountUp = (el, target, duration, hasComma) => {
514    let startTime = null;
515    const decimals = target.toString().split('.')[1]?.length || 0;
516
517    const formatNumber = (num) => {
518      if (hasComma) {
519        return num.toLocaleString(undefined, {
520          minimumFractionDigits: decimals,
521          maximumFractionDigits: decimals
522        });
523      } else {
524        return num.toFixed(decimals);
525      }
526    };
527
528    const step = (timestamp) => {
529      if (!startTime) startTime = timestamp;
530      const progress = Math.min((timestamp - startTime) / duration, 1);
531
532      const currentVal = progress * target;
533
534      el.innerText = formatNumber(currentVal);
535
536      if (progress < 1) {
537        window.requestAnimationFrame(step);
538      } else {
539        el.innerText = formatNumber(target);
540      }
541    };
542
543    window.requestAnimationFrame(step);
544  };
545
546  //スクロール検知
547  const countUpObserver = new IntersectionObserver((entries, instance) => {
548    entries.forEach(entry => {
549      if (entry.isIntersecting) {
550        const el = entry.target;
551        const target = parseFloat(el.getAttribute('data-count-target'));
552        const hasComma = el.getAttribute('data-has-comma') === 'true';
553        const duration = 1000;
554
555        animateCountUp(el, target, duration, hasComma);
556
557        instance.unobserve(el);
558      }
559    });
560  }, {
561    root: null,
562    rootMargin: '0px',
563    threshold: 0
564  });
565
566  //要素の初期化と監視の開始
567  document.querySelectorAll('.keyNumbers__counterNumber').forEach(counter => {
568    const originalText = counter.innerText;
569    const hasComma = originalText.includes(',');
570    counter.setAttribute('data-has-comma', hasComma);
571
572    const rawText = originalText.replace(/,/g, '');
573    const targetNum = parseFloat(rawText);
574
575    if (!isNaN(targetNum)) {
576      counter.setAttribute('data-count-target', targetNum);
577
578      const decimals = targetNum.toString().split('.')[1]?.length || 0;
579      counter.innerText = (0).toFixed(decimals);
580
581      countUpObserver.observe(counter);
582    }
583  });
584
585  // 円周アニメーション
586  const drawLineObserver = new IntersectionObserver((entries, instance) => {
587    entries.forEach(entry => {
588      if (entry.isIntersecting) {
589        const el = entry.target;
590
591        el.classList.add('is-moving');
592
593        instance.unobserve(el);
594      }
595    });
596  }, {
597    root: null,
598    rootMargin: '0px',
599    threshold: 0
600  });
601
602  document.querySelectorAll('.keyNumbers__listItem').forEach(item => {
603    drawLineObserver.observe(item);
604  });
605
606  //スクロール フェードアニメーション
607  const fadeElements = document.querySelectorAll('.scroll-fade');
608
609  const fadeOptions = {
610    root: null,
611    rootMargin: '0px 0px -150px 0px',
612    threshold: 0
613  };
614
615  const fadeObserver = new IntersectionObserver((entries, obs) => {
616    entries.forEach(entry => {
617      if (entry.isIntersecting) {
618        entry.target.classList.add('scroll-fade--active');
619        obs.unobserve(entry.target);
620      }
621    });
622  }, fadeOptions);
623
624  fadeElements.forEach(el => {
625    fadeObserver.observe(el);
626  });
627});

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.