const container = Z.by_id('container'); function getRandomColor() { var letters = '0123456789ABCDEF'; var color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } for (let i = 0; i < 10000; ++i) { container.appendChild(Z.native('div', { innerText: i, className: 'image', style: { background: getRandomColor(), aspectRatio: '1 / ' + (Math.random() + 0.5), }, })); } const zoom = new (class { constructor() { this.committed = 5; this.count = 5; container.style.gridTemplateColumns = `repeat(5, 1fr)`; container.classList.toggle('tiling', this.count != 1); } update(delta, point) { this.count += delta; this.count = Math.min(Math.max(this.count, 1), 20); const scale = this.committed / this.count; const rects = Z.document.getClientRects()[0]; const x = point.x; const y = point.y - rects.y; container.style.transformOrigin = `${x}px ${y}px`; container.style.transform = `scale(${scale})`; } commit() { console.log('commit'); this.count = Math.round(this.count); container.style.transform = 'scale(1)'; container.style.gridTemplateColumns = `repeat(${this.count}, 1fr)`; container.classList.toggle('tiling', this.count != 1); this.committed = this.count; } }); Z.document.onwheel = (event) => { if (!event.ctrlKey) { return; } event.preventDefault(); zoom.update(event.wheelDeltaY / 120, { x: 0, y: 0 }); zoom.commit(); }; const pinch = new Pinch(Z.document); pinch.onpinch = (delta, point) => { zoom.update(delta / 20, point); }; pinch.onfinish = (delta) => { zoom.commit(); };