/** SVG viewBox camera. All pointer math is in viewport pixels / document units. */ export class Camera { constructor(bounds, width, height) { this.bounds = bounds; this.resize(width, height); this.fit(); } resize(width, height) { this.width = Math.max(1, width); this.height = Math.max(1, height); } fit() { const b = this.bounds; this.scale = Math.min(this.width / b.width, this.height / b.height); this.fitScale = this.scale; this.x = (this.width - b.width * this.scale) / 2 - b.x * this.scale; this.y = (this.height - b.height * this.scale) / 2 - b.y * this.scale; } world(x, y) { return { x: (x - this.x) / this.scale, y: (y - this.y) / this.scale }; } zoom(factor, x, y) { const p = this.world(x, y); this.scale = Math.min(this.fitScale * 200, Math.max(this.fitScale * .05, this.scale * factor)); this.x = x - p.x * this.scale; this.y = y - p.y * this.scale; } pan(x, y) { this.x += x; this.y += y; } get viewBox() { return `${-this.x / this.scale} ${-this.y / this.scale} ${this.width / this.scale} ${this.height / this.scale}`; } }