Lens Zoom New
Magnifier that follows the pointer over a floor plan and makes small dimensions and room names readable. For drawings, product details or maps where the fine print matters.
Beweeg over de tekening
How to use it
- Paste the HTML where the components should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Lens Zoom · Bron: Magic UI · licentie MIT. Laat deze vermelding staan bij hergebruik. -->
<div class="jouw-container">
<div class="lnz"><div class="lnz__img" role="img" aria-label="Plattegrond begane grond, Molenstraat 8 in Gouda"></div><div class="lnz__lens" aria-hidden="true"></div><span class="lnz__hint">Beweeg over de tekening</span></div>
</div>/* Lens Zoom · Bron: Magic UI · licentie MIT. Laat deze vermelding staan bij hergebruik. */
.lnz{position:relative;width:92%;height:88%;border-radius:4px;overflow:hidden;background:#fff;border:1px solid rgba(10,10,10,.12);touch-action:none;cursor:none;font-family:'Switzer',system-ui,sans-serif}
.lnz__img{position:absolute;inset:0;background-size:100% 100%}
.lnz__lens{--s:120px;position:absolute;left:0;top:0;width:var(--s);height:var(--s);border-radius:50%;border:2px solid #F5480F;box-shadow:0 8px 24px rgba(10,10,10,.25),inset 0 0 0 4px rgba(255,255,255,.6);background-repeat:no-repeat;background-color:#fff;pointer-events:none;opacity:0;transition:opacity .2s}
.lnz.is-on .lnz__lens{opacity:1}
.lnz__hint{position:absolute;left:10px;top:10px;font:500 9px/1 'JetBrains Mono',monospace;letter-spacing:.12em;text-transform:uppercase;background:#0a0a0a;color:#fff;padding:5px 7px;border-radius:3px;transition:opacity .3s}
.lnz.is-used .lnz__hint{opacity:0}
@media(max-width:420px){.lnz__lens{--s:96px}}
@media(hover:none){.lnz{cursor:auto}}// Lens Zoom · Bron: Magic UI · licentie MIT. Laat deze vermelding staan bij hergebruik.
// root = het element waarin de HTML staat
function init(root){
var w = root.querySelector('.lnz'); if (!w) return;
var img = w.querySelector('.lnz__img'), lens = w.querySelector('.lnz__lens'), Z = 2.6, url = '', lx = .55, ly = .33;
function paint() {
var c = document.createElement('canvas'), W = 1400, H = 900; c.width = W; c.height = H; var x = c.getContext('2d');
x.fillStyle = '#fbfaf8'; x.fillRect(0, 0, W, H);
x.strokeStyle = 'rgba(10,10,10,.05)'; x.lineWidth = 1;
for (var g = 0; g < W; g += 25) { x.beginPath(); x.moveTo(g, 0); x.lineTo(g, H); x.stroke(); }
for (g = 0; g < H; g += 25) { x.beginPath(); x.moveTo(0, g); x.lineTo(W, g); x.stroke(); }
x.strokeStyle = '#0a0a0a'; x.lineWidth = 14; x.lineJoin = 'miter';
x.strokeRect(120, 110, 1050, 640);
x.lineWidth = 7;
[[560, 110, 560, 430], [120, 430, 420, 430], [500, 430, 760, 430], [760, 430, 760, 750], [960, 110, 960, 330], [960, 400, 960, 430], [760, 430, 1170, 430], [380, 430, 380, 750]].forEach(function (l) { x.beginPath(); x.moveTo(l[0], l[1]); x.lineTo(l[2], l[3]); x.stroke(); });
x.strokeStyle = '#F5480F'; x.lineWidth = 7;
[[220, 110, 420, 110], [680, 110, 880, 110], [120, 520, 120, 660], [1170, 180, 1170, 300], [900, 750, 1080, 750]].forEach(function (l) { x.beginPath(); x.moveTo(l[0], l[1]); x.lineTo(l[2], l[3]); x.stroke(); });
x.strokeStyle = '#0a0a0a'; x.lineWidth = 2;
[[420, 430, 80, 0], [960, 330, 70, 1], [500, 750, 90, 2]].forEach(function (d) { x.beginPath(); if (d[3] === 0) { x.arc(d[0], d[1], d[2], 0, Math.PI / 2); } else if (d[3] === 1) { x.arc(d[0], d[1], d[2], Math.PI, Math.PI * 1.5); } else { x.arc(d[0], d[1], d[2], Math.PI, Math.PI * 1.5); } x.stroke(); });
x.fillStyle = '#0a0a0a'; x.textAlign = 'center';
function room(n, a, cx, cy) { x.font = "600 22px Switzer, sans-serif"; x.fillText(n, cx, cy); x.font = "500 15px 'JetBrains Mono', monospace"; x.fillStyle = 'rgba(10,10,10,.6)'; x.fillText(a, cx, cy + 24); x.fillStyle = '#0a0a0a'; }
room('Woonkamer', '32,4 m²', 340, 270); room('Keuken', '14,8 m²', 760, 270); room('Toilet', '1,6 m²', 1065, 380); room('Hal', '6,2 m²', 250, 600); room('Berging', '5,1 m²', 570, 600); room('Werkkamer', '11,3 m²', 965, 600); room('Trap', '', 1065, 230);
x.strokeStyle = '#0a0a0a'; x.lineWidth = 1.5; x.font = "500 14px 'JetBrains Mono', monospace";
function dim(x1, y1, x2, y2, t) { x.beginPath(); x.moveTo(x1, y1); x.lineTo(x2, y2); x.stroke(); x.beginPath(); x.moveTo(x1, y1 - 8); x.lineTo(x1, y1 + 8); x.moveTo(x2, y2 - 8); x.lineTo(x2, y2 + 8); x.stroke(); x.fillText(t, (x1 + x2) / 2, y1 - 8); }
dim(120, 70, 560, 70, '4.400'); dim(560, 70, 960, 70, '4.000'); dim(960, 70, 1170, 70, '2.100');
x.save(); x.translate(1215, 430); x.rotate(Math.PI / 2); dim(-320, 0, 320, 0, '6.400'); x.restore();
x.strokeStyle = '#0a0a0a'; x.lineWidth = 1.5; for (var s = 0; s < 8; s++) { x.strokeRect(990, 140 + s * 22, 150, 22); }
x.fillStyle = '#0a0a0a'; x.fillRect(880, 790, 400, 80); x.fillStyle = '#fff'; x.textAlign = 'left';
x.font = "600 18px Switzer, sans-serif"; x.fillText('Molenstraat 8 · Gouda', 900, 822);
x.font = "500 13px 'JetBrains Mono', monospace"; x.fillText('BEGANE GROND · SCHAAL 1:100 · BLAD 2/5', 900, 850);
x.fillStyle = '#F5480F'; x.fillRect(120, 800, 30, 30); x.fillStyle = '#0a0a0a'; x.font = "500 13px 'JetBrains Mono', monospace"; x.fillText('NIEUWE KOZIJNEN', 162, 820);
url = 'url(' + c.toDataURL('image/png') + ')'; img.style.backgroundImage = url; lens.style.backgroundImage = url; place();
}
function place() {
var W = w.clientWidth, H = w.clientHeight, s = lens.offsetWidth, r = s / 2;
var cx = Math.max(r, Math.min(W - r, lx * W)), cy = Math.max(r, Math.min(H - r, ly * H));
lens.style.transform = 'translate(' + (cx - r) + 'px,' + (cy - r) + 'px)';
lens.style.backgroundSize = (W * Z) + 'px ' + (H * Z) + 'px';
lens.style.backgroundPosition = (-(lx * W * Z - r)) + 'px ' + (-(ly * H * Z - r)) + 'px';
}
function mv(e) { var b = w.getBoundingClientRect(); lx = Math.max(0, Math.min(1, (e.clientX - b.left) / b.width)); ly = Math.max(0, Math.min(1, (e.clientY - b.top) / b.height)); w.classList.add('is-on', 'is-used'); place(); }
w.addEventListener('pointermove', mv); w.addEventListener('pointerdown', mv);
w.addEventListener('pointerleave', function (e) { if (e.pointerType === 'mouse') w.classList.remove('is-on'); });
if ('ResizeObserver' in window) new ResizeObserver(place).observe(w);
paint(); w.classList.add('is-on');
if (document.fonts && document.fonts.load) Promise.all(["500 15px 'JetBrains Mono'", '600 22px Switzer'].map(function (f) { return document.fonts.load(f).catch(function () {}); })).then(paint);
}
init(document.querySelector('.jouw-container'));
More components
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →