Parse
File Parse zoom.js
This tree is parsed live from the source file.
Classes
-
{{ item.name }}
- {{ key }}
Not Classes
{{ getTree() }}
Comments
{{ getTreeComments() }}
Source
/*
---
title: Zoom
category: zoom
scale
---
Scale a set of points in a _zooming_ method, relative to an `origin` point.
Apply a set of points to an instance of `Zoom`, then apply an update().
const zoom = new Zoom(stage, pointList)
const origin = {x: 100, y: 100}
, factor = 1.5 // 50% bigger.
// run `update` when a change occurs.
zoom.update(origin, factor)
// Draw points.
zoom.zoomPoints.pen.indicators(ctx, { color: 'gray', width: 1})
*/
class Zoom {
constructor(stage, points=[], factor=1, center={x:0, y:0}, lens=1) {
this.stage = stage
this.points = points
this.factor = factor
this.lens = lens
this.center = center
this._cachePoints = new PointList
}
add(...points) {
this.points = this.points.concat(points)
}
update3(center = this.center, factor = this.factor) {
// Lensed zoom: farther points move disproportionately more.
const zoomPoints = this.getZoomPoints()
const originPoints = this.points
const lensStrength = this.lens // e.g. 0.0 = off, 0.3 = subtle, 1.0 = chunky
// 1) Find max radius to normalize distances (so lensing is consistent).
let maxR = 0
for (let i = 0; i < originPoints.length; i++) {
const p = originPoints[i]
const dx = p.x - center.x
const dy = p.y - center.y
const r = Math.hypot(dx, dy)
if (r > maxR) maxR = r
}
// Avoid div by zero if all points are at the center.
if (maxR === 0) maxR = 1
// 2) Apply lens curve per point.
for (let i = 0; i < originPoints.length; i++) {
const originPoint = originPoints[i]
const sibling = zoomPoints[i]
const dx = originPoint.x - center.x
const dy = originPoint.y - center.y
const r = Math.hypot(dx, dy)
const t = r / maxR // normalized radius [0..1]
// Quadratic barrel curve: 1 + k * t^2 (k = lensStrength)
// - k > 0 pushes far points further (barrel)
// - k < 0 pulls far points in (pincushion)
const lensCurve = 1 + (lensStrength * t)
const s = factor * lensCurve // total scale for displacement & radius
sibling.update({
x: center.x + dx * s,
y: center.y + dy * s,
radius: originPoint.radius * s,
rotation: originPoint.rotation
})
}
}
update(center=this.center, factor=this.factor) {
// move and scale all items relative to the factor and center.
let zoomPoints = this.getZoomPoints()
let originPoints = this.points
let lens = this.lens
originPoints.forEach((originPoint,i,a)=>{
let sibling = zoomPoints[i]
// the xy is a scale of the origin distance from the center
let dis = originPoint.distance2D(center)
// let offs = {x: 20, y: 20 } // originPoint.distance2D(center)
sibling.update({
x: center.x + (dis.x * factor * lens)
, y: center.y + (dis.y * factor * lens)
, radius: originPoint.radius * factor * lens
, rotation: originPoint.rotation
// x: originPoint.x + (dis.x * factor)
// , y: originPoint.y + (dis.y * factor)
// , radius: originPoint.radius * (1+factor)
// , rotation: originPoint.rotation
})
})
}
update2(center = this.center, factor = this.factor) {
// Lensed zoom: farther points move disproportionately more.
const zoomPoints = this.getZoomPoints()
const originPoints = this.points
const lensStrength = this.lens // e.g. 0.0 = off, 0.3 = subtle, 1.0 = chunky
// 1) Find max radius to normalize distances (so lensing is consistent).
let maxR = 0
for (let i = 0; i < originPoints.length; i++) {
const p = originPoints[i]
const dx = p.x - center.x
const dy = p.y - center.y
const r = Math.hypot(dx, dy)
if (r > maxR) maxR = r
}
// Avoid div by zero if all points are at the center.
if (maxR === 0) maxR = 1
// 2) Apply lens curve per point.
for (let i = 0; i < originPoints.length; i++) {
const originPoint = originPoints[i]
const sibling = zoomPoints[i]
const dx = originPoint.x - center.x
const dy = originPoint.y - center.y
const r = Math.hypot(dx, dy)
const t = r / maxR // normalized radius [0..1]
// Quadratic barrel curve: 1 + k * t^2 (k = lensStrength)
// - k > 0 pushes far points further (barrel)
// - k < 0 pulls far points in (pincushion)
const lensCurve = 1 + (lensStrength * t * t)
const s = factor * lensCurve // total scale for displacement & radius
sibling.update({
x: center.x + dx * s,
y: center.y + dy * s,
radius: originPoint.radius * s,
rotation: originPoint.rotation
})
}
}
get zoomPoints() {
if(this._zoomPoints) {
return this._zoomPoints
}
return this._cachePoints;
}
getZoomPoints() {
if(this._zoomPoints) {
return this._zoomPoints
}
let zoomPoints = this._cachePoints
this.points.forEach((e,i,a)=>{
zoomPoints.push(e.copy())
})
this._zoomPoints = zoomPoints
return zoomPoints
}
}
copy