PageSourceSearch

https://tinyvoice.com/wp-content/themes/tinyvoice/js/tinyvoice-main.js?ver=1787639765

js tinyvoice.com collected 2026-10-02 19:10:14 UTC 16,761 bytes, 564 lines download raw bytes

1$(function () {
2  // navigation
3  // =================================================
4
5  var $root = $("html"),
6    $nav_header = $(".banner,.logo"),
7    $navicon = $('[data-navicon="button"]'),
8    header_height = $(".banner").height(),
9    hero_height = $("#hero").height(),
10    offset_val = hero_height - header_height,
11    eventType = document.ontouchstart !== null ? "click" : "touchstart";
12
13  // Methods
14  // =================================================
15
16  function navSlide() {
17    var scroll_top = $(window).scrollTop();
18
19    if (scroll_top >= offset_val) {
20      $nav_header.addClass("is-sticky");
21    } else {
22      $nav_header.removeClass("is-sticky");
23    }
24  }
25
26  $(window).scroll(navSlide);
27
28  $(".icon-menu").on("click", function () {
29    $(this).toggleClass("is--closed");
30    $(".banner").toggleClass("is-open");
31    $("html, body").toggleClass("nav-open");
32  });
33
34  $(".scrollto").click(function () {
35    $(".banner").removeClass("is-open");
36    $(".icon-menu").removeClass("is--closed");
37    $("html, body").removeClass("nav-open");
38  });
39
40  $('a[href*="#"]:not([href="#"])').click(e => {
41    const target = $(e.target.hash);
42
43    if (target.length) {
44      // target.offset().topは行間などレイアウト由来の端数(小数px)を持つことがあり、
45      // 切り捨てると固定ヘッダー(50px)の下にその端数ぶんの隙間ができ、
46      // 前のセクションの端が細い線状に見えてしまう。四捨五入して端数を
47      // ヘッダー側(見えない側)に寄せる。
48      $("html, body").animate(
49        {
50          scrollTop: Math.round(target.offset().top) - 50
51        },
52        500
53      );
54
55      return false;
56    }
57  });
58});
59
60$(function () {
61  $(window).on("load resize", function () {
62    var wH = $(window).height();
63    $("#hero").css("height", wH + "px");
64  });
65});
66
67$(function () {
68  $(".producer-content-wrap").slick({
69    accessibility: true,
70    focusOnSelect: false,
71    cssEase: "linear",
72    draggable: false,
73    lazyLoad: "ondemand",
74    rows: 2,
75    slidesToShow: 5,
76    slidesToScroll: 1,
77    autoplay: false,
78    speed: 5000,
79    arrows: false,
80    pauseOnHover: false,
81    responsive: [
82      {
83        breakpoint: 801,
84        settings: {
85          slidesToShow: 4,
86        }
87      },
88	  {
89        breakpoint: 650,
90        settings: {
91          slidesToShow: 3,
92        }
93      },
94      {
95        breakpoint: 480,
96        settings: {
97          slidesToShow: 2,
98        }
99      }
100    ]
101  });
102
103  $(".enginner-content-wrap").slick({
104    accessibility: true,
105    focusOnSelect: false,
106    cssEase: "linear",
107    draggable: false,
108    lazyLoad: "ondemand",
109    rows: 1,
110    slidesToShow: 5,
111    slidesToScroll: 1,
112    autoplay: false,
113    speed: 5000,
114    arrows: false,
115    pauseOnHover: false,
116    responsive: [
117		{
118			breakpoint: 801,
119			settings: {
120			slidesToShow: 4,
121			}
122		},
123		{
124			breakpoint: 650,
125			settings: {
126			slidesToShow: 3,
127			}
128		},
129		{
130			breakpoint: 480,
131			settings: {
132			slidesToShow: 2,
133			}
134		}
135	]
136  });
137
138	$('.works-front-inner').slick({
139		accessibility: true,
140		focusOnSelect: true,
141		cssEase: 'ease-in-out',
142		draggable: false,
143		lazyLoad: 'ondemand',
144		slidesToShow: 4,
145		slidesToScroll: 4,
146		rows: 2,
147		autoplay: true,
148		autoplaySpeed: 5000,
149		speed: 200,
150		arrows: true,
151		prevArrow: $('.slider-prev'),
152		nextArrow: $('.slider-next'),
153		responsive: [
154			{
155				breakpoint: 801,
156				settings: {
157					slidesToShow: 3,
158				}
159			},
160			{
161				breakpoint: 650,
162				settings: {
163					slidesToShow: 2,
164					slidesToScroll: 2
165				}
166			}
167		]
168	});
169
170	// Producer/Engineerスライダーは元々autoplaySpeed:0+speed:5000でslickの自動再生を
171	// 使い、常に一定速度で流れ続ける演出だった。だが、進行中の5秒トランジションの
172	// 開始時にslick内部で予約される完了処理(こちらからは参照もキャンセルもできない
173	// setTimeout)を経由するせいで、ホバーで割り込む/再開する処理をどう工夫しても、
174	// 「離してすぐ動かない」「再開時にワープする」「連続ホバーで速度が乱れる」の
175	// いずれかが必ず起きてしまうことが分かった(検証で複数パターン確認済み)。
176	//
177	// そこでslickの自動再生機構は使わず(autoplay: falseで初期化)、代わりに
178	// requestAnimationFrameで自前に一定速度スクロールを実装する。止める/再開するは
179	// 単にrAFループを止める/再開するだけなので、途中経過の位置がそのまま保持され、
180	// 「同じ位置から同じ速度で続きが動く」がループの回し方以外に何も考えずに実現できる。
181	// スライドの並び自体(クローンを含むDOM構造)はslickが作ったものをそのまま使い、
182	// 見た目のtranslateXだけをこちらで直接動かす。
183	function continuousScroll($wrap) {
184		var instance = $wrap.get(0).slick;
185		if (!instance) {
186			return;
187		}
188		// スライド枚数がslidesToShow以下の場合、slick自身も無限スクロール用のクローンを
189		// 生成しない(スクロールする必要がないため)。この状態で無理に自前スクロールを
190		// 動かすと、クローンが存在しない領域(空白)に入り込んでしまう。全件が常に画面内に
191		// 収まっている=そもそも動かす意味がないケースなので、何もしない。
192		if (instance.slideCount <= instance.options.slidesToShow) {
193			return;
194		}
195		var $track = $wrap.find(".slick-track");
196		var loopWidth = instance.slideWidth * instance.slideCount;
197		// 1msあたりの移動量。元のspeed(1コマ=slidesToScroll分をspeed msで移動)と
198		// 同じ体感速度になるよう、単位をpx/msに換算しておく。
199		var pxPerMs = (instance.slideWidth * instance.options.slidesToScroll) / instance.options.speed;
200
201		var baseX = 0;
202		var m = /translate3d\(\s*(-?[\d.]+)px/.exec($track.css("transform"));
203		if (m) {
204			baseX = parseFloat(m[1]);
205		}
206		var pos = 0; // 0以上、常に加算のみ。ループ幅を超えたら折り返す。
207		var running = false;
208		var rafId = null;
209		var lastTs = null;
210
211		function applyPosition() {
212			var x = baseX - pos;
213			// Safariは小数点以下を含むtranslate3dの値をJSから毎フレーム書き換えると、
214			// サブピクセル単位のガタつき(振動して見える)が出ることがある既知の挙動。
215			// 整数pxに丸めて滑らかにする。
216			$track.css("transform", "translate3d(" + Math.round(x) + "px, 0px, 0px)");
217		}
218
219		function tick(ts) {
220			if (!running) {
221				return;
222			}
223			if (lastTs !== null) {
224				var delta = ts - lastTs;
225				pos += pxPerMs * delta;
226				if (pos >= loopWidth) {
227					pos -= loopWidth;
228				}
229				applyPosition();
230			}
231			lastTs = ts;
232			rafId = requestAnimationFrame(tick);
233		}
234
235		function start() {
236			if (running) {
237				return;
238			}
239			running = true;
240			lastTs = null;
241			rafId = requestAnimationFrame(tick);
242		}
243
244		function stop() {
245			running = false;
246			if (rafId) {
247				cancelAnimationFrame(rafId);
248				rafId = null;
249			}
250		}
251
252		$track.css("transition", "none");
253		start();
254
255		// スマホ等のタッチデバイスでは「ホバーで停止/離れたら再開」という概念自体が
256		// 成立しない。タップ操作はブラウザによって擬似的なmouseenter(mouseleaveを
257		// 伴わない)を発火させることがあり、詳細画面からブラウザバックで戻った直後に
258		// これが発火してstop()が呼ばれ、下のpageshowでの再始動後すぐにまた止まって
259		// しまう不具合の原因になっていた。タッチデバイスではそもそもこのホバー制御を
260		// 付けない。
261		var isTouchDevice = ("ontouchstart" in window) || (navigator.maxTouchPoints > 0);
262		if (!isTouchDevice) {
263			$wrap.on("mouseenter", stop);
264			$wrap.on("mouseleave", start);
265		}
266
267		// スマホでProducer詳細等に遷移してからブラウザバックした場合、bfcache復元
268		// (pageshowイベントでevent.persisted === true)されたページ上では、
269		// バックグラウンドに回っている間に停止したrequestAnimationFrameのループが
270		// 二度と呼ばれなくなることがある(iOS Safari等)。runningフラグ自体は
271		// trueのままなので通常のstart()呼び出しでは再始動できず、見た目には
272		// 「スクロールが完全に止まったまま」になってしまう。stop()を挟んで
273		// running状態を確実にリセットしてから改めてstart()する。
274		window.addEventListener("pageshow", function (event) {
275			if (event.persisted) {
276				stop();
277				start();
278			}
279		});
280	}
281	continuousScroll($(".producer-content-wrap"));
282	continuousScroll($(".enginner-content-wrap"));
283});
284
285$(function () {
286  // ハンバーガーメニュー幅のサブメニューを閉じる。開く時の完全な逆再生になる
287  // よう、①上下から中央へ背景が閉じつつ文字が消える(is-closing、0.3秒)
288  // → ②線が左から右へ消える(is-closing-line、0.3秒)
289  // → ③display:noneでスペースも元に戻る、の順にクラスを付け替える。
290  function closeMobileSubmenu($submenu) {
291    var closeToken = ($submenu.data("tvCloseToken") || 0) + 1;
292    $submenu.data("tvCloseToken", closeToken);
293
294    $submenu.removeClass("is-open is-closing-line").addClass("is-closing");
295
296    setTimeout(function () {
297      if ($submenu.data("tvCloseToken") !== closeToken) return; // 途中で再度開かれた場合は何もしない
298      $submenu.removeClass("is-closing").addClass("is-closing-line");
299    }, 300);
300
301    setTimeout(function () {
302      if ($submenu.data("tvCloseToken") !== closeToken) return;
303      $submenu.removeClass("is-closing-line");
304      $submenu.css("display", "none");
305    }, 300 + 300);
306  }
307
308  $(".dropdown").click(function () {
309    var $item = $(this).closest(".nav__list-item");
310    var $submenu = $item.find(".nav__list-submenu");
311
312    // ハンバーガーメニュー幅: ①高さは即座に確定(About Usも一瞬で最終位置へ、
313    // この時点ではまだ透明で文字も見えない) → ②中央の線が右から左へ伸びる
314    // → ③線を起点に上下均等に背景がf5f5f5へ広がると同時に文字がフェードイン
315    // (②③はCSS側のトランジションで制御、SCSS参照)。
316    if (window.matchMedia("(max-width: 1024px)").matches) {
317      var isOpen = $submenu.hasClass("is-open");
318
319      $(".nav__list-submenu.is-open").not($submenu).each(function () {
320        closeMobileSubmenu($(this));
321      });
322
323      if (isOpen) {
324        closeMobileSubmenu($submenu);
325      } else {
326        // クローズ中の再オープンに備え、進行中のクローズ処理を無効化してから
327        // クローズ用クラスを外しておく。
328        $submenu.data("tvCloseToken", ($submenu.data("tvCloseToken") || 0) + 1);
329        $submenu.removeClass("is-closing is-closing-line");
330        $submenu.css("display", "block");
331        // 高さを即座に確定させた状態を強制的にリフローさせてから
332        // is-openを付与することで、線・文字のトランジションが正しく発火する。
333        $submenu[0].offsetHeight;
334        $submenu.addClass("is-open");
335      }
336      return;
337    }
338
339    if ($submenu.is(":visible")) {
340      $(".nav__list-submenu").fadeOut();
341    } else {
342      $(".nav__list-submenu").fadeOut();
343      $submenu.fadeIn();
344    }
345  });
346});
347
348$(window).scroll(function (){
349  $('.fadeOff').each(function(){
350    var target = $(this).offset().top;
351    var scroll = $(window).scrollTop();
352    var windowHeight = $(window).height();
353    if (scroll > target - windowHeight + 150){
354      $(this).addClass("fadeInUp");
355    } else {
356      $(this).removeClass("fadeInUp");
357    }
358  });
359});
360
361// MAPが一つの場合
362// $(function() {
363//   var map;
364//   var am = new google.maps.LatLng(35.639333, 139.703206);
365
366//   function initialize() {
367
368//     var mapOptions = {
369//       zoom: 15,
370//       center: am,
371//       mapTypeControl: false,
372//       scrollwheel: false,
373//       zoomControl: true,
374//       streetViewControl: false,
375//       fullscreenControl: false,
376//     };
377
378//     map = new google.maps.Map(document.getElementById('map-canvas'),
379//       mapOptions);
380
381//     var contentString =
382
383//       '<div id="infowindow-content">' +
384//       '<ul>' +
385//       '<li>TINYVOICE PRODUCTION</li>' +
386//       '<li>〒153-0061 東京都目黒区中目黒3-6-5 アイエム中目黒5F</li>' +
387//       '<li><a href="https://goo.gl/maps/rx9nPxnZobcJQhEf9" target="_blank"><button class="btn">GoogleMapを開く</button></a></li>' +
388//       '</ul>' +
389//       '</div>';
390
391//     var infowindow = new google.maps.InfoWindow({
392//       content: contentString
393//     });
394
395//     var marker = new google.maps.Marker({
396//       position: am,
397//       map: map,
398//       draggable: false,
399//     });
400
401//     google.maps.event.addListener(marker, 'click', function() {
402//       infowindow.open(map, marker);
403//     });
404//   }
405
406//   google.maps.event.addDomListener(window, 'load', initialize);
407
408//   google.maps.event.addDomListener(window, "resize", function() {
409
410//     var center = map.getCenter();
411//     google.maps.event.trigger(map, "resize");
412//     map.setCenter(center);
413//   });
414
415// });
416
417
418// MAPが2つの場合
419// $(function() {
420// 	var styles = [
421// 	   {
422// 		   "featureType": "administrative",
423// 		   "elementType": "labels.text.fill",
424// 		   "stylers": [
425// 			   {
426// 				   "color": "#444444"
427// 			   }
428// 		   ]
429// 	   },
430// 	   {
431// 		   "featureType": "landscape",
432// 		   "elementType": "all",
433// 		   "stylers": [
434// 			 {
435// 				 "visibility": "on"
436// 			 },
437// 			 {
438// 			   "saturation": -100
439// 			 }, {
440// 			   "lightness": -5
441// 			 }
442// 		   ]
443// 	   },
444// 	   {
445// 		   "featureType": "poi",
446// 		   "elementType": "all",
447// 		   "stylers": [
448// 			   {
449// 				   "visibility": "on"
450// 			   },
451// 			   {
452// 				 "saturation": -100
453// 			   }, {
454// 				 "lightness": -5
455// 			   }
456// 		   ]
457// 	   },
458// 	   {
459// 		   "featureType": "road",
460// 		   "elementType": "all",
461// 		   "stylers": [
462// 			   {
463// 				   "saturation": -100
464// 			   },
465// 			   {
466// 				   "lightness": 45
467// 			   }
468// 		   ]
469// 	   },
470// 	   {
471// 		   "featureType": "road.highway",
472// 		   "elementType": "all",
473// 		   "stylers": [
474// 			   {
475// 				   "visibility": "simplified"
476// 			   }
477// 		   ]
478// 	   },
479// 	   {
480// 		   "featureType": "road.arterial",
481// 		   "elementType": "labels.icon",
482// 		   "stylers": [
483// 			   {
484// 				   "visibility": "on"
485// 			   }
486// 		   ]
487// 	   },
488// 	   {
489// 		   "featureType": "transit",
490// 		   "elementType": "all",
491// 		   "stylers": [
492// 			   {
493// 				   "visibility": "off"
494// 			   }
495// 		   ]
496// 	   },
497// 	   {
498// 		   "featureType": "water",
499// 		   "elementType": "all",
500// 		   "stylers": [
501// 			   {
502// 				   "color": "#818181"
503// 			   },
504// 			   {
505// 				   "visibility": "on"
506// 			   }
507// 		   ]
508// 	   }
509//    ];
510
511// 	var locations = [
512// 	   ['<h3>Studio Vision</h3><p>〒107-0061</p><p>東京都港区北青山3-5-5-101</p>', 35.66747189646178, 139.71416752613123],
513// 	   ['<h3>nano Studio</h3><p>〒153-0061</p><p>東京都目黒区中目黒3-6-5 アイエム中目黒3F</p>', 35.63952542467924, 139.70323568380107]
514// 	];
515
516// 	var icons = [
517// 		{
518// 			url: '/theme/tinyvoice/images/icon-map_vision.svg',
519// 			scaledSize: new google.maps.Size(150, 50), // scaled size
520// 		},
521// 		{
522// 			url: '/theme/tinyvoice/images/icon-map_nano.svg',
523// 			scaledSize: new google.maps.Size(150, 50), // scaled size
524// 		},
525// 	];
526
527
528// 	var map = new google.maps.Map(document.getElementById('map-canvas'),{
529// 	  styles: styles,
530// 	  scrollwheel: false,
531// 	  mapTypeControl: false,
532// 	  streetViewControl: false,
533// 	  fullscreenControl: false,
534// 	  mapTypeId: google.maps.MapTypeId.ROADMAP
535// 	});
536// 	var infowindow = new google.maps.InfoWindow();
537
538// 	// 表示領域を生成します。
539// 	var bounds = new google.maps.LatLngBounds();
540// 	var marker;
541
542
543
544// 	for (var i = 0; i < locations.length; i++) {
545// 	  marker = new google.maps.Marker({
546// 		position: new google.maps.LatLng(locations[i][1], locations[i][2]),
547// 		icon: icons[i],
548// 		map: map
549// 	  });
550// 	  // 地図表示領域をマーカー位置に合わせて拡大します。
551// 	  bounds.extend (marker.position);
552
553// 	  google.maps.event.addListener(marker, 'click', (function(marker, i) {
554// 		return function() {
555// 		  infowindow.setContent(locations[i][0]);
556// 		  infowindow.open(map, marker);
557// 		}
558// 	  })(marker, i));
559// 	}
560
561// 	// 地図表示領域の変更を反映します。
562// 	map.fitBounds (bounds);
563
564//   });

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.