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); this.por = { x: 0, y: 0 }; this.eor = null; this.y_offset = 0; } update(delta, point) { this.count += delta; this.count = Math.min(Math.max(this.count, 1), 20); const scale = this.committed / this.count; const x = point.x - this.por.x; container.style.transform = `translate(${x}px, 0px) scale(${scale})`; } set point_of_reference(point) { const rect = container.getClientRects()[0]; this.por = { x: point.x, y: point.y - rect.y }; container.style.transformOrigin = `${this.por.x}px ${this.por.y}px`; this.eor = Z.document.shadowRoot.elementFromPoint(point.x, point.y); this.y_offset = this.eor.getBoundingClientRect().y; } commit() { console.log('commit'); this.count = Math.round(this.count); container.style.gridTemplateColumns = `repeat(${this.count}, 1fr)`; container.classList.toggle('tiling', this.count != 1); container.style.transform = 'scale(1)'; this.committed = this.count; void container.offsetHeight; const rect = this.eor.getBoundingClientRect(); Z.document.scrollBy({ top: rect.y - this.y_offset, behavior: 'instant', }); } }); 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.onstart = (event) => { zoom.point_of_reference = event.point; }; pinch.onpinch = (event) => { zoom.update(event.zoom_delta / 20, event.point); }; pinch.onfinish = () => { zoom.commit(); };