diff --git a/web-ui/arduino-emulator.html b/web-ui/arduino-emulator.html
index e46344f..f1f1585 100644
--- a/web-ui/arduino-emulator.html
+++ b/web-ui/arduino-emulator.html
@@ -138,7 +138,7 @@
}
#canvas-zoom-overlay.open { display:flex; }
#canvas-zoom-img {
- image-rendering:pixelated; max-width:90vw; max-height:90vh;
+ image-rendering:pixelated;
border:2px solid #333; border-radius:4px;
box-shadow:0 8px 40px rgba(0,0,0,.8);
}
@@ -7927,31 +7927,54 @@ function mobToggleBoard(){
(function() {
const overlay = document.createElement('div');
overlay.id = 'canvas-zoom-overlay';
- overlay.innerHTML = '![]()
클릭 또는 ESC로 닫기
';
+ const zoomCanvas = document.createElement('canvas');
+ zoomCanvas.id = 'canvas-zoom-img';
+ overlay.appendChild(zoomCanvas);
+ const hint = document.createElement('div');
+ hint.id = 'canvas-zoom-hint';
+ hint.textContent = '클릭 또는 ESC로 닫기';
+ overlay.appendChild(hint);
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');
+ let _src = null, _rafId = null;
+
+ function _loop() {
+ if (!_src || !overlay.classList.contains('open')) return;
+ const ctx = zoomCanvas.getContext('2d');
+ ctx.imageSmoothingEnabled = false;
+ ctx.drawImage(_src, 0, 0, zoomCanvas.width, zoomCanvas.height);
+ _rafId = requestAnimationFrame(_loop);
}
- function closeZoom() { overlay.classList.remove('open'); }
+ function openZoom(canvas) {
+ _src = canvas;
+ // 화면의 90% 이내에서 최대 정수 배율
+ const maxScale = Math.min(
+ Math.floor(window.innerWidth * 0.9 / canvas.width),
+ Math.floor(window.innerHeight * 0.9 / canvas.height)
+ );
+ const scale = Math.max(1, maxScale);
+ zoomCanvas.width = canvas.width * scale;
+ zoomCanvas.height = canvas.height * scale;
+ overlay.classList.add('open');
+ cancelAnimationFrame(_rafId);
+ _loop();
+ }
+
+ function closeZoom() {
+ overlay.classList.remove('open');
+ cancelAnimationFrame(_rafId);
+ _src = null;
+ }
overlay.addEventListener('click', closeZoom);
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeZoom(); });
- // body 끝에서 실행되므로 DOM 이미 준비됨 — 직접 연결
['tft-canvas', 'oled-canvas'].forEach(id => {
const c = document.getElementById(id);
- if (c) c.addEventListener('click', () => openZoom(c));
+ if (c) c.addEventListener('click', e => { e.stopPropagation(); openZoom(c); });
});
- // canvas가 나중에 그려질 수 있으므로 전역 노출
window._canvasZoomOpen = openZoom;
})();