From b618b2e1cb3b4ba91c31fb4c7199c6ce925f07a5 Mon Sep 17 00:00:00 2001 From: kim Date: Tue, 30 Jun 2026 17:57:13 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20TFT/OLED=20=EC=BA=94=EB=B2=84=EC=8A=A4?= =?UTF-8?q?=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20=ED=99=95=EB=8C=80=20?= =?UTF-8?q?=EC=98=A4=EB=B2=84=EB=A0=88=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 클릭 → 화면 최대 3배 확대, 90vw/90vh 이내로 제한 - 오버레이 클릭 또는 ESC 키로 닫기 - cursor:zoom-in/zoom-out 표시 Co-Authored-By: Claude Sonnet 4.6 --- web-ui/arduino-emulator.html | 55 ++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/web-ui/arduino-emulator.html b/web-ui/arduino-emulator.html index 96202cd..6ab8da9 100644 --- a/web-ui/arduino-emulator.html +++ b/web-ui/arduino-emulator.html @@ -117,7 +117,6 @@ .oled-dot { width:6px; height:6px; border-radius:50%; background:#333; flex-shrink:0; } .oled-dot.on { background:#60a5fa; box-shadow:0 0 4px #60a5fa; } .oled-wrap { background:#000; border:2px solid #222; border-radius:4px; padding:4px; position:relative; } - #oled-canvas { display:block; max-width:100%; height:auto; image-rendering:pixelated; } .oled-placeholder { position:absolute; inset:4px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; pointer-events:none; } .oled-placeholder span { font-size:10px; color:#333; letter-spacing:.05em; } .oled-placeholder .oled-ph-grid { width:100%; height:2px; background:repeating-linear-gradient(90deg,#1a1a1a 0,#1a1a1a 4px,transparent 4px,transparent 8px); } @@ -128,7 +127,25 @@ .tft-dot { width:6px; height:6px; border-radius:50%; background:#333; flex-shrink:0; } .tft-dot.on { background:#22c55e; box-shadow:0 0 4px #22c55e; } .tft-wrap { background:#000; border:2px solid #222; border-radius:4px; padding:4px; overflow:hidden; } - #tft-canvas { display:block; width:100%; height:auto; image-rendering:pixelated; } + #tft-canvas { display:block; width:100%; height:auto; image-rendering:pixelated; cursor:zoom-in; } + #oled-canvas { display:block; max-width:100%; height:auto; image-rendering:pixelated; cursor:zoom-in; } + + /* 확대 오버레이 */ + #canvas-zoom-overlay { + display:none; position:fixed; inset:0; z-index:9999; + background:rgba(0,0,0,.85); align-items:center; justify-content:center; + cursor:zoom-out; + } + #canvas-zoom-overlay.open { display:flex; } + #canvas-zoom-img { + image-rendering:pixelated; max-width:90vw; max-height:90vh; + border:2px solid #333; border-radius:4px; + box-shadow:0 8px 40px rgba(0,0,0,.8); + } + #canvas-zoom-hint { + position:fixed; bottom:24px; left:50%; transform:translateX(-50%); + font-size:11px; color:#555; pointer-events:none; + } /* DHT sensor controls */ .dht-section { padding:10px 14px; flex-shrink:0; border-bottom:1px solid var(--bdr-in); } @@ -7905,6 +7922,40 @@ function mobToggleBoard(){ document.getElementById('mobtab-serial').classList.remove('active'); } } + +// ── 캔버스 확대 오버레이 ────────────────────────────────────────────────────── +(function() { + const overlay = document.createElement('div'); + overlay.id = 'canvas-zoom-overlay'; + overlay.innerHTML = '
클릭 또는 ESC로 닫기
'; + document.body.appendChild(overlay); + + function openZoom(canvas) { + const img = document.getElementById('canvas-zoom-img'); + img.src = canvas.toDataURL(); + // 자연 크기의 3배, 화면 90% 이내 + const scale = Math.min(3, window.innerWidth * 0.9 / canvas.width, window.innerHeight * 0.9 / canvas.height); + img.style.width = (canvas.width * scale) + 'px'; + img.style.height = (canvas.height * scale) + 'px'; + overlay.classList.add('open'); + } + + function closeZoom() { overlay.classList.remove('open'); } + + overlay.addEventListener('click', closeZoom); + document.addEventListener('keydown', e => { if (e.key === 'Escape') closeZoom(); }); + + // TFT / OLED 캔버스에 클릭 핸들러 연결 (DOM 준비 후) + document.addEventListener('DOMContentLoaded', () => { + ['tft-canvas', 'oled-canvas'].forEach(id => { + const c = document.getElementById(id); + if (c) c.addEventListener('click', () => openZoom(c)); + }); + }); + + // canvas가 나중에 그려질 수 있으므로 전역 노출 + window._canvasZoomOpen = openZoom; +})();