/* 메인 「보아텍이 함께한 공간」 — 설치사례 페이지와 같은 데이터(js/cases-data.js)로 그림 (2026-10-23) 전체: LED 2건 + 분류별 최신 1건 / 분류 탭: 해당 분류 최신 6건 */ (function () { 'use strict'; var D = window.VOATEK_CASES; if (!D) return; var tabs = document.getElementById('caseTabs'), ul = document.getElementById('cases'); if (!tabs || !ul) return; var CAT = {}; D.cats.forEach(function (c) { CAT[c.k] = c.label; }); var esc = function (s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); }; var CODE = {"etc": "c1", "hall": "c2", "public": "c3", "church": "c4", "edu": "c5", "hotel": "c7"}; var PER = 6, pick = {}, order = []; function add(it, all) { if (!pick[it.id]) { pick[it.id] = { it: it, all: false }; order.push(it.id); } if (all) pick[it.id].all = true; } // 전체 D.items.filter(function (i) { return i.cat === 'led'; }).slice(0, 2).forEach(function (i) { add(i, true); }); D.cats.forEach(function (c) { if (c.k === 'all' || c.k === 'led') return; var inCat = D.items.filter(function (i) { return i.cat === c.k; }); var f = inCat.filter(function (i) { return !/^(OO|대전 OO)/.test(i.name); })[0] || inCat[0]; if (f) add(f, true); }); // 분류별 D.cats.forEach(function (c) { if (c.k === 'all') return; D.items.filter(function (i) { return i.cat === c.k; }).slice(0, PER).forEach(function (i) { add(i, false); }); }); tabs.innerHTML = D.cats.map(function (c, n) { return ''; }).join(''); var html = order.map(function (id) { var p = pick[id], it = p.it, led = it.cat === 'led'; var sub = led ? 'LED' : ''; var meta = led ? esc(it.venue || '') + ' · LED전광판' : esc(CAT[it.cat]) + ' · ' + esc(it.type); return '
  • ' + '' + '
    ' + esc(it.name) + ' 설치 현장
    ' + '
    ' + sub + '' + esc(it.name) + '' + meta + '
  • '; }).join(''); ul.insertAdjacentHTML('afterbegin', html); })(); /* VOATEK main page · preview build (vanilla JS, no dependencies) */ (function () { 'use strict'; var doc = document, root = doc.documentElement, body = doc.body; var RM = window.matchMedia('(prefers-reduced-motion: reduce)').matches; var mqMobile = window.matchMedia('(max-width: 960px)'); var HOVER = window.matchMedia('(hover: hover)').matches; var LOW = (navigator.hardwareConcurrency || 8) <= 4; var $ = function (s, c) { return (c || doc).querySelector(s); }; var $$ = function (s, c) { return Array.prototype.slice.call((c || doc).querySelectorAll(s)); }; var clamp = function (v, a, b) { return v < a ? a : v > b ? b : v; }; var easeOut = function (t) { return 1 - Math.pow(1 - t, 3); }; var vh = function () { return window.innerHeight; }; /* ---------- toast ---------- */ var toastEl = $('#toast'), toastT; if (!toastEl) { toastEl = doc.createElement('div'); } function toast(msg) { toastEl.textContent = msg; toastEl.classList.add('on'); clearTimeout(toastT); toastT = setTimeout(function () { toastEl.classList.remove('on'); }, 2600); } $$('[data-toast]').forEach(function (b) { b.addEventListener('click', function () { toast(b.dataset.toast); }); }); $$('a[href="#"]').forEach(function (a) { a.addEventListener('click', function (e) { e.preventDefault(); }); }); /* ---------- preview toggle ---------- */ var pv = $('#pvToggle'); if (pv) pv.addEventListener('change', function () { body.classList.toggle('pv-off', !pv.checked); }); /* ---------- count-up ---------- */ function countUp(el) { var to = +el.dataset.to, dur = +(el.dataset.dur || 1200), t0 = performance.now(); if (RM) { el.textContent = to.toLocaleString('ko-KR'); return; } (function step(t) { var p = Math.min((t - t0) / dur, 1), e = p === 1 ? 1 : 1 - Math.pow(2, -10 * p); el.textContent = Math.round(to * e).toLocaleString('ko-KR'); if (p < 1) requestAnimationFrame(step); })(t0); } if (!RM) $$('.count').forEach(function (el) { el.textContent = '0'; }); /* ---------- reveal ---------- */ var io = new IntersectionObserver(function (es) { es.forEach(function (e) { if (!e.isIntersecting) return; var el = e.target; if (el.hasAttribute('data-stagger')) { Array.prototype.slice.call(el.children).forEach(function (k, i) { k.style.transitionDelay = (Math.min(i, 8) * 0.08) + 's'; }); } el.classList.add('is-in'); $$('.count', el).forEach(countUp); if (el.classList.contains('count')) countUp(el); io.unobserve(el); }); }, { threshold: 0.2, rootMargin: '0px 0px -40px 0px' }); $$('.reveal, [data-stagger]:not(.reveal)').forEach(function (el) { io.observe(el); }); /* ========================================================= Pixel-wave field (hero + contact) ========================================================= */ function Field(canvas, opt) { this.cv = canvas; this.ctx = canvas.getContext('2d'); this.o = opt; this.waves = []; this.mouse = null; this.run = false; this.last = 0; this.lastWave = 0; this.cx = 0; this.cy = 0; this.resize(); var self = this; window.addEventListener('resize', function () { self.resize(); if (!self.run) self.frame(performance.now(), true); }); if (opt.mouse && HOVER) { var host = canvas.parentElement; host.addEventListener('mousemove', function (e) { var r = canvas.getBoundingClientRect(); self.mouse = { x: e.clientX - r.left, y: e.clientY - r.top }; }); host.addEventListener('mouseleave', function () { self.mouse = null; }); host.addEventListener('click', function (e) { if (e.target.closest('a,button')) return; var r = canvas.getBoundingClientRect(); self.addWave(e.clientX - r.left, e.clientY - r.top, performance.now()); }); } new IntersectionObserver(function (es) { es.forEach(function (e) { e.isIntersecting ? self.start() : self.stop(); }); }, { threshold: 0 }).observe(canvas); doc.addEventListener('visibilitychange', function () { doc.hidden ? self.stop() : self.start(); }); } Field.prototype.resize = function () { var cv = this.cv, dpr = Math.min(window.devicePixelRatio || 1, 2); this.w = cv.clientWidth; this.h = cv.clientHeight; this.dpr = dpr; cv.width = Math.round(this.w * dpr); cv.height = Math.round(this.h * dpr); this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0); var sp = this.o.spacing * ((mqMobile.matches || LOW) ? 1.5 : 1); this.sp = sp; var cols = Math.ceil(this.w / sp) + 1, rows = Math.ceil(this.h / sp) + 1; this.n = cols * rows; this.px = new Float32Array(this.n); this.py = new Float32Array(this.n); this.b = new Float32Array(this.n); var ox = (this.w - (cols - 1) * sp) / 2, oy = (this.h - (rows - 1) * sp) / 2, k = 0; for (var r = 0; r < rows; r++) for (var c = 0; c < cols; c++) { this.px[k] = ox + c * sp; this.py[k] = oy + r * sp; k++; } this.baseX = this.w * this.o.cx; this.baseY = this.h * this.o.cy; if (!this.cx) { this.cx = this.baseX; this.cy = this.baseY; } this.maxR = Math.hypot(Math.max(this.baseX, this.w - this.baseX), Math.max(this.baseY, this.h - this.baseY)) + 60; // pre-render base dots var off = doc.createElement('canvas'); off.width = cv.width; off.height = cv.height; var oc = off.getContext('2d'); oc.setTransform(dpr, 0, 0, dpr, 0, 0); oc.fillStyle = 'rgba(255,255,255,' + this.o.base + ')'; for (var i = 0; i < this.n; i++) oc.fillRect(this.px[i] - 1, this.py[i] - 1, 2, 2); this.off = off; }; Field.prototype.addWave = function (x, y, t) { this.waves.push({ x: x, y: y, t0: t }); if (this.waves.length > 3) this.waves.shift(); }; Field.prototype.start = function () { if (this.run || RM || this.paused) return; this.run = true; var self = this; var loop = function (t) { if (!self.run) return; self.frame(t); requestAnimationFrame(loop); }; requestAnimationFrame(loop); }; Field.prototype.stop = function () { this.run = false; }; Field.prototype.frame = function (t, still) { var o = this.o, ctx = this.ctx, w = this.w, h = this.h; if (!this.started) { this.started = t; this.lastWave = t - o.interval + o.first; } // wave center follows mouse slightly var tx = this.baseX, ty = this.baseY; if (this.mouse) { tx += (this.mouse.x - this.baseX) * 0.16; ty += (this.mouse.y - this.baseY) * 0.16; } this.cx += (tx - this.cx) * 0.08; this.cy += (ty - this.cy) * 0.08; if (t - this.lastWave > o.interval) { this.addWave(this.cx, this.cy, t); this.lastWave = t; } var speed = this.maxR / o.travel, band = o.band; var live = []; for (var j = 0; j < this.waves.length; j++) { var wv = this.waves[j], age = (t - wv.t0) / 1000, rad = age * speed; if (rad - band < this.maxR * 1.3) live.push({ x: wv.x, y: wv.y, r: rad, f: clamp(1 - rad / (this.maxR * 1.25), 0, 1) }); } this.waves = this.waves.filter(function (wv) { return (t - wv.t0) / 1000 * speed < this.maxR * 1.3; }, this); if (still && !live.length) live.push({ x: this.cx, y: this.cy, r: this.maxR * 0.35, f: 0.8 }); ctx.clearRect(0, 0, w, h); ctx.drawImage(this.off, 0, 0, w, h); // rings for (var q = 0; q < live.length; q++) { var L = live[q]; ctx.beginPath(); ctx.arc(L.x, L.y, Math.max(L.r, 0.1), 0, Math.PI * 2); ctx.strokeStyle = 'rgba(' + o.ring + ',' + (0.22 * L.f) + ')'; ctx.lineWidth = 1; ctx.stroke(); } // lit pixels var b = this.b, px = this.px, py = this.py, mx = this.mouse ? this.mouse.x : -9999, my = this.mouse ? this.mouse.y : -9999; ctx.fillStyle = 'rgb(' + o.lit + ')'; var decay = still ? 0 : 0.955; for (var i = 0; i < this.n; i++) { var target = 0, x = px[i], y = py[i]; for (var k = 0; k < live.length; k++) { var W = live[k], dx = x - W.x, dy = y - W.y, d = Math.abs(Math.sqrt(dx * dx + dy * dy) - W.r); if (d < band) { var v = (1 - d / band) * W.f; if (v > target) target = v; } } if (this.mouse) { var mdx = x - mx, mdy = y - my, md = mdx * mdx + mdy * mdy; if (md < 14400) { var mv = 0.45 * (1 - Math.sqrt(md) / 120); if (mv > target) target = mv; } } var nb = b[i] * decay; if (target * o.peak > nb) nb = target * o.peak; b[i] = nb; if (nb > 0.04) { ctx.globalAlpha = nb; ctx.fillRect(x - 1.25, y - 1.25, 2.5, 2.5); } } if (o.spark && !still) for (var s = 0; s < o.spark; s++) { var si = (Math.random() * this.n) | 0; if (b[si] < 0.5) b[si] = 0.35 + Math.random() * 0.4; } ctx.globalAlpha = 1; }; var heroCv = $('#heroCanvas'); if (heroCv) { var hf = new Field(heroCv, { spacing: 16, base: 0.11, lit: '47,107,255', ring: '228,114,0', cx: 0.7, cy: 0.5, interval: 3200, first: 200, travel: 3.8, band: 56, peak: 1, mouse: true, spark: 7 }); if (RM) hf.frame(performance.now(), true); } var ctCv = $('#ctCanvas'); if (ctCv) { var cf = new Field(ctCv, { spacing: 22, base: 0.05, lit: '228,114,0', ring: '228,114,0', cx: 0.85, cy: 0.35, interval: 5200, first: 600, travel: 3.4, band: 50, peak: 0.55, mouse: false }); if (RM) cf.frame(performance.now(), true); } /* ---------- hero intro + rotator ---------- */ var hero = $('.hero'); requestAnimationFrame(function () { setTimeout(function () { hero.classList.add('go'); }, 60); }); setTimeout(function () { var l = $('.launch'); if (l && !RM) l.classList.add('glow'); }, 1500); var track = $('.hero-rot-track'); if (track) { var items = track.children, n = items.length, idx = 0; track.appendChild(items[0].cloneNode(true)); var all = track.children; function mark(i) { for (var k = 0; k < all.length; k++) all[k].classList.toggle('cur', k === i); } mark(0); if (!RM) setInterval(function () { if (doc.hidden) return; idx++; mark(idx); track.style.transition = ''; track.style.transform = 'translateY(' + (-1.16 * idx) + 'em)'; if (idx === n) setTimeout(function () { track.style.transition = 'none'; track.style.transform = 'translateY(0)'; idx = 0; mark(0); }, 650); }, 2500); } /* ---------- hero slider (3 slides) ---------- */ var slides = $$('.hs', hero), pagerBtns = $$('.hero-pager button', hero), cur = 0, DUR = 6500, timer = null, paused = RM; var pauseBtn = $('.hc-pause', hero); hero.style.setProperty('--dur', DUR + 'ms'); function show(n) { n = (n + slides.length) % slides.length; if (n === cur && slides[n].classList.contains('on')) { schedule(); return; } slides.forEach(function (s, i) { var on = i === n; s.classList.toggle('on', on); s.setAttribute('aria-hidden', !on); $$('a,button', s).forEach(function (a) { if (on) a.removeAttribute('tabindex'); else a.setAttribute('tabindex', '-1'); }); }); pagerBtns.forEach(function (b, i) { b.setAttribute('aria-selected', i === n); var bar = $('b', b); bar.style.animation = 'none'; void bar.offsetWidth; bar.style.animation = ''; }); if (typeof hf !== 'undefined') { hf.paused = n !== 0; if (n === 0) hf.start(); else hf.stop(); } cur = n; schedule(); } function schedule() { clearTimeout(timer); if (!paused) timer = setTimeout(function () { show(cur + 1); }, DUR); } function setPaused(p) { paused = p; hero.classList.toggle('paused', p); pauseBtn.setAttribute('aria-pressed', p); pauseBtn.setAttribute('aria-label', p ? '자동 넘김 재생' : '자동 넘김 멈춤'); if (p) clearTimeout(timer); else show(cur + 1); } pagerBtns.forEach(function (b) { b.addEventListener('click', function () { show(+b.dataset.go); }); }); $('.hc-prev', hero).addEventListener('click', function () { show(cur - 1); }); $('.hc-next', hero).addEventListener('click', function () { show(cur + 1); }); pauseBtn.addEventListener('click', function () { setPaused(!paused); }); // swipe (mobile) var sx = null; hero.addEventListener('touchstart', function (e) { sx = e.touches[0].clientX; }, { passive: true }); hero.addEventListener('touchend', function (e) { if (sx === null) return; var dx = e.changedTouches[0].clientX - sx; sx = null; if (Math.abs(dx) > 50) show(cur + (dx < 0 ? 1 : -1)); }); // stop auto-advance while hero is off screen or tab hidden new IntersectionObserver(function (es) { es.forEach(function (e) { if (e.isIntersecting) { if (!paused) schedule(); } else clearTimeout(timer); }); }, { threshold: 0.3 }).observe(hero); doc.addEventListener('visibilitychange', function () { if (doc.hidden) clearTimeout(timer); else if (!paused) schedule(); }); if (RM) setPaused(true); else schedule(); /* ---------- scroll state (카페24 공통 헤더 사용) ---------- */ var mcall = $('#mcall'), dots = $('.dots'); function onHeader() { var y = window.scrollY, heroH = hero.offsetHeight; if (mcall) mcall.classList.toggle('on', y > heroH * 0.8 && y < doc.body.scrollHeight - vh() * 1.6); if (dots) dots.classList.toggle('on', y > heroH * 0.5); } /* ---------- section dots ---------- */ var dotLinks = $$('.dots a'); var secIO = new IntersectionObserver(function (es) { es.forEach(function (e) { if (!e.isIntersecting) return; var key = e.target.dataset.sec; dotLinks.forEach(function (d) { d.classList.toggle('cur', d.dataset.dot === key); }); dots.classList.toggle('on-light', e.target.dataset.theme === 'light'); }); }, { rootMargin: '-50% 0px -50% 0px' }); $$('section[data-sec]').forEach(function (s) { secIO.observe(s); }); /* ========================================================= scroll-scrubbed pieces ========================================================= */ // pixel edges function hash(a, b) { var s = Math.sin(a * 127.1 + b * 311.7) * 43758.5453; return s - Math.floor(s); } var edges = $$('.pxedge').map(function (el) { var cols = mqMobile.matches ? 20 : 40; el.style.setProperty('--cols', cols); var cells = []; for (var r = 0; r < 6; r++) for (var c = 0; c < cols; c++) { var i = doc.createElement('i'); el.appendChild(i); var fromBottom = 5 - r; cells.push({ el: i, th: (fromBottom / 6) * 0.72 + hash(c, r) * 0.26, on: false }); } return { el: el, cells: cells }; }); // cabinet wall var wall = $('#wall'), assy = $('#assy'), cabs = [], cabCount = $('#cabCount'), assyHead = $('.assy-head'), hint = $('.assy-hint'); if (wall) { for (var i = 0; i < 12; i++) { var c = i % 4, r = Math.floor(i / 4), d = doc.createElement('div'); d.className = 'cab'; d.style.backgroundPosition = (c / 3 * 100) + '% ' + (r / 2 * 100) + '%'; wall.appendChild(d); var sx = (c - 1.5), sy = (r - 1); cabs.push({ el: d, c: c, r: r, dx: sx * 110 + (hash(i, 3) - 0.5) * 220, dy: sy * 120 + (hash(i, 7) - 0.5) * 200 + 40, rot: (hash(i, 11) - 0.5) * 16, delay: hash(i, 5) * 0.35 }); } } // B안: 캐비닛 12칸은 제자리에 두고 한 칸씩 점등 → 다 켜지면 이음선 사라짐 var LIT_ORDER = [5, 6, 1, 2, 4, 7, 9, 10, 0, 3, 8, 11]; cabs.forEach(function (C, k) { C.el.style.transform = 'none'; C.el.style.opacity = 1; C.start = 0.04 + LIT_ORDER.indexOf(k) * 0.058; }); function renderAssy(p) { var seam = clamp((p - 0.78) / 0.12, 0, 1), title = clamp((p - 0.82) / 0.14, 0, 1), done = 0; for (var k = 0; k < cabs.length; k++) { var C = cabs[k], tl = clamp((p - C.start) / 0.07, 0, 1); C.el.style.setProperty('--dark', (1 - tl).toFixed(3)); C.el.style.setProperty('--px', (Math.sin(tl * Math.PI) * 0.9).toFixed(3)); if (tl > 0.98) done++; } wall.style.setProperty('--gap', ((1 - seam) * 4).toFixed(1) + 'px'); wall.style.setProperty('--glow', clamp((p - 0.1) / 0.7, 0, 1).toFixed(3)); wall.classList.toggle('lit', seam > 0.95); assyHead.style.setProperty('--t', title.toFixed(3)); cabCount.textContent = (done < 10 ? '0' : '') + done; if (hint) hint.style.opacity = clamp(1 - p * 3, 0, 1); } var assyAuto = false; function autoAssy() { if (assyAuto) return; assyAuto = true; if (RM) { renderAssy(1); return; } var t0 = performance.now(); (function step(t) { var p = clamp((t - t0) / 2600, 0, 1); renderAssy(p); if (p < 1) requestAnimationFrame(step); })(t0); } if (wall) { renderAssy(RM ? 1 : 0); if (mqMobile.matches || RM) { new IntersectionObserver(function (es) { es.forEach(function (e) { if (e.isIntersecting) autoAssy(); }); }, { threshold: 0.35 }).observe(wall); } } var tl = $('#timeline'), tlItems = $$('#timeline li'), steps = $('.steps'), stepItems = $$('.steps li'); var refresh = $('.refresh'), warrantyEl = $('#warranty'), scrubCases = null; function onScrub() { var H = vh(); // timeline if (tl) { var r = tl.getBoundingClientRect(), p = RM ? 1 : clamp((H * 0.85 - r.top) / (H * 0.55), 0, 1); tl.style.setProperty('--p', p.toFixed(3)); tlItems.forEach(function (li) { li.classList.toggle('on', p >= +li.dataset.at); }); } // edges edges.forEach(function (E) { var r = E.el.getBoundingClientRect(), q = RM ? 1 : clamp((H - r.top) / (H * 0.55), 0, 1); E.cells.forEach(function (C) { var on = q > C.th; if (on !== C.on) { C.on = on; C.el.classList.toggle('on', on); } }); }); // cabinet assembly (desktop scrub) if (wall && !mqMobile.matches && !RM) { var ar = assy.getBoundingClientRect(), range = ar.height - H; renderAssy(clamp(-ar.top / range, 0, 1)); } // design steps if (steps) { var sr = steps.getBoundingClientRect(), sp = RM ? 1 : clamp((H * 0.82 - sr.top) / (H * 0.5), 0, 1); steps.style.setProperty('--p', sp.toFixed(3)); stepItems.forEach(function (li, i) { li.classList.toggle('on', sp >= (i / Math.max(1, stepItems.length - 1)) * 0.96 + 0.001); }); } // refresh bands only while visible if (scrubCases) scrubCases(H); if (warrantyEl) { var wr = warrantyEl.getBoundingClientRect(); warrantyEl.classList.toggle('on-screen', wr.top < H && wr.bottom > 0); } if (refresh) { var rr = refresh.getBoundingClientRect(); refresh.classList.toggle('is-play', rr.top < H && rr.bottom > 0); } } var ticking = false; function onScroll() { if (ticking) return; ticking = true; requestAnimationFrame(function () { ticking = false; onHeader(); onScrub(); }); } window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); onHeader(); onScrub(); /* ---------- LED type cards: magnifier on the same image ---------- */ var ZOOM = 2.4, LS = 150; function placeLens(card, x, y) { var media = $('.tcard-media', card), img = $('img', media), lens = $('.lens', media); var W = media.clientWidth, Hh = media.clientHeight, nw = img.naturalWidth || W, nh = img.naturalHeight || Hh; var s = Math.max(W / nw, Hh / nh), rw = nw * s, rh = nh * s, ox = (W - rw) / 2, oy = (Hh - rh) / 2; x = clamp(x, 0, W); y = clamp(y, 0, Hh); lens.style.backgroundImage = 'url("' + img.currentSrc + '")'; lens.style.backgroundSize = (rw * ZOOM) + 'px ' + (rh * ZOOM) + 'px'; lens.style.backgroundPosition = (-((x - ox) * ZOOM - LS / 2)) + 'px ' + (-((y - oy) * ZOOM - LS / 2)) + 'px'; lens.style.setProperty('--lx', (x - LS / 2) + 'px'); lens.style.setProperty('--ly', (y - LS / 2) + 'px'); } $$('.tcard').forEach(function (card) { var media = $('.tcard-media', card); card.addEventListener('mousemove', function (e) { var r = media.getBoundingClientRect(); placeLens(card, e.clientX - r.left, e.clientY - r.top); }); card.addEventListener('mouseenter', function (e) { var r = media.getBoundingClientRect(); placeLens(card, e.clientX - r.left, e.clientY - r.top); }); card.addEventListener('focus', function () { placeLens(card, media.clientWidth * 0.62, media.clientHeight * 0.5); }); if (!HOVER) card.addEventListener('click', function () { var on = !card.classList.contains('act'); $$('.tcard').forEach(function (c) { c.classList.remove('act'); }); if (on) { placeLens(card, media.clientWidth * 0.62, media.clientHeight * 0.5); card.classList.add('act'); } }); }); /* ---------- projects: metafacade "WORLD OF" style scroll motion + tabs ---------- */ var casesEl = $('#cases'); if (casesEl) { var caseItems = $$('.case', casesEl), empty = $('.case-empty', casesEl); scrubCases = function (H) { if (RM) return; var single = mqMobile.matches, cr = casesEl.getBoundingClientRect(); if (cr.bottom < -200 || cr.top > H + 200) return; var prog = clamp((H - cr.top) / (cr.height + H), 0, 1), col = 0; caseItems.forEach(function (c) { if (c.classList.contains('gone')) return; var r = c.getBoundingClientRect(), mid = r.top + r.height / 2; // -1 (bottom of screen) .. 0 (center) .. 1 (top of screen) var d = clamp((H / 2 - mid) / (H * 0.62), -1, 1), ad = Math.abs(d); var scale = 1 - (single ? 0.06 : 0.14) * Math.pow(ad, 1.4); var op = 1 - (single ? 0.35 : 0.62) * Math.pow(ad, 1.6); var shift = (!single && col % 2 === 1) ? (110 - prog * 220) : 0; // 2nd column moves at a different speed c.style.transform = 'translate3d(0,' + shift.toFixed(1) + 'px,0) scale(' + scale.toFixed(3) + ')'; if (!c.classList.contains('out')) c.style.opacity = op.toFixed(3); c.style.setProperty('--zoom', (1 + 0.12 * ad).toFixed(3)); col++; }); }; $$('#caseTabs button').forEach(function (btn) { btn.addEventListener('click', function () { $$('#caseTabs button').forEach(function (b) { b.setAttribute('aria-selected', b === btn); }); var f = btn.dataset.f; caseItems.forEach(function (c) { c.classList.add('out'); }); setTimeout(function () { var show = caseItems.filter(function (c) { return f === 'all' ? c.dataset.all === '1' : c.dataset.c === f; }); var all = $('#caseAll'), CODE = {"etc": "c1", "hall": "c2", "public": "c3", "church": "c4", "edu": "c5", "hotel": "c7"}; if (all) all.href = '/bizdemo79551/mp2/mp2_sub2.php?sub=02' + (CODE[f] ? '&com_board_category_code=' + CODE[f] : ''); caseItems.forEach(function (c) { c.classList.toggle('gone', show.indexOf(c) < 0); }); empty.hidden = show.length > 0; scrubCases(vh()); requestAnimationFrame(function () { show.forEach(function (c) { c.classList.remove('out'); }); scrubCases(vh()); }); }, RM ? 0 : 220); }); }); scrubCases(vh()); } /* ---------- liquid glass: 마우스를 따라오는 반사광 ---------- */ if (HOVER && !RM) { $$('.caps li, .tcard, .feat, .lg-plan, .pcard, .team, .certs li, .board, .ct-form, .w3-card, .biz-grid, .hero-pager, .whys > li, .br, .cl-grid > div').forEach(function (el) { el.classList.add('glare'); el.addEventListener('mousemove', function (e) { var r = el.getBoundingClientRect(); el.style.setProperty('--gx', (e.clientX - r.left) + 'px'); el.style.setProperty('--gy', (e.clientY - r.top) + 'px'); }); }); } else { $$('.caps li, .tcard, .feat, .lg-plan, .pcard, .team, .certs li, .board, .ct-form, .w3-card, .whys > li, .br, .cl-grid > div').forEach(function (el) { el.classList.add('glare'); }); } /* ---------- 팀 섹션 시안 A/B 전환 (검토용) ---------- */ $$('.pp-switch button').forEach(function (b) { b.addEventListener('click', function () { $$('.pp-switch button').forEach(function (x) { x.setAttribute('aria-selected', x === b); }); $$('.pp-v').forEach(function (v) { var on = v.dataset.v === b.dataset.v; v.hidden = !on; if (on) $$('.reveal, [data-stagger]', v).forEach(function (r) { r.classList.add('is-in'); }); }); }); }); /* ---------- contact form (preview only) ---------- */ var form = $('#ctForm'); if (form) form.addEventListener('submit', function (e) { e.preventDefault(); var tel = form.tel, agree = form.agree, ok = true; tel.classList.toggle('err', !tel.value.trim()); if (!tel.value.trim()) ok = false; if (!agree.checked) ok = false; if (!ok) { toast('연락처와 개인정보 동의를 확인해 주세요.'); (tel.value.trim() ? agree : tel).focus(); return; } toast('미리보기 화면이라 실제로 전송되지는 않습니다.'); }); })(); /* 공지사항·자료실 최신글 (카페24 게시판 목록에서 읽어 옴) */ (function () { ['vtNotice', 'vtData'].forEach(function (id) { var ul = document.getElementById(id); if (!ul || !window.fetch || !window.TextDecoder) return; fetch(ul.getAttribute('data-src'), { credentials: 'same-origin' }).then(function (r) { return r.arrayBuffer(); }).then(function (buf) { var html = new TextDecoder('euc-kr').decode(buf), d = new DOMParser().parseFromString(html, 'text/html'), out = []; Array.prototype.slice.call(d.querySelectorAll('table.board tr[onclick]')).some(function (tr) { var links = tr.querySelectorAll('td[align="left"] a[href]'), a = links[links.length - 1], dt = tr.querySelector('.bbsetc_dateof_write'); if (!a) return false; var t = a.textContent.replace(/\s+/g, ' ').trim(); if (!t) return false; out.push('
  • '); out[out.length - 1] = out[out.length - 1].replace('', '' + t.replace(/[&<>]/g, function (c) { return { '&': '&', '<': '<', '>': '>' }[c]; }) + ''); return out.length >= 4; }); ul.innerHTML = out.length ? out.join('') : '
  • 등록된 글이 없습니다.
  • '; }).catch(function () { ul.innerHTML = '
  • 목록을 불러오지 못했습니다.
  • '; }); }); })();