Skip to content

Instantly share code, notes, and snippets.

@rpggio
Last active December 25, 2019 11:23
Show Gist options
  • Save rpggio/4c1fd9e2d5d0030ba429 to your computer and use it in GitHub Desktop.
Save rpggio/4c1fd9e2d5d0030ba429 to your computer and use it in GitHub Desktop.
An implementation of pan and zoom in Paper.js, based on http://matthiasberth.com/articles/stable-zoom-and-pan-in-paperjs/. Requires jquery-mousewheel to capture wheel events.
class ViewZoom {
project: paper.Project;
factor = 1.25;
private _minZoom: number;
private _maxZoom: number;
private mouseNativeStart: paper.Point;
private viewCenterStart: paper.Point;
constructor(project: paper.Project) {
this.project = project;
const view = this.project.view;
(<any>$(view.element)).mousewheel((event) => {
const mousePosition = new paper.Point(event.offsetX, event.offsetY);
this.changeZoomCentered(event.deltaY, mousePosition);
});
view.on("mousedown", ev => {
this.viewCenterStart = view.center;
// Have to use native mouse offset, because ev.delta
// changes as the view is scrolled.
this.mouseNativeStart = new paper.Point(ev.event.offsetX, ev.event.offsetY);
});
view.on("mousedrag", ev => {
if(this.viewCenterStart){
const nativeDelta = new paper.Point(
ev.event.offsetX - this.mouseNativeStart.x,
ev.event.offsetY - this.mouseNativeStart.y
);
// Move into view coordinates to subract delta,
// then back into project coords.
view.center = view.viewToProject(
view.projectToView(this.viewCenterStart)
.subtract(nativeDelta));
}
});
view.on("mouseup", ev => {
if(this.mouseNativeStart){
this.mouseNativeStart = null;
this.viewCenterStart = null;
}
});
}
get zoom(): number{
return this.project.view.zoom;
}
get zoomRange(): number[] {
return [this._minZoom, this._maxZoom];
}
/**
* Set zoom level.
* @returns zoom level that was set, or null if it was not changed
*/
setZoomConstrained(zoom: number): number {
if(this._minZoom) {
zoom = Math.max(zoom, this._minZoom);
}
if(this._maxZoom){
zoom = Math.min(zoom, this._maxZoom);
}
const view = this.project.view;
if(zoom != view.zoom){
view.zoom = zoom;
return zoom;
}
return null;
}
setZoomRange(range: paper.Size[]): number[] {
const view = this.project.view;
const aSize = range.shift();
const bSize = range.shift();
const a = aSize && Math.min(
view.bounds.height / aSize.height,
view.bounds.width / aSize.width);
const b = bSize && Math.min(
view.bounds.height / bSize.height,
view.bounds.width / bSize.width);
const min = Math.min(a,b);
if(min){
this._minZoom = min;
}
const max = Math.max(a,b);
if(max){
this._maxZoom = max;
}
return [this._minZoom, this._maxZoom];
}
changeZoomCentered(delta: number, mousePos: paper.Point) {
if (!delta) {
return;
}
const view = this.project.view;
const oldZoom = view.zoom;
const oldCenter = view.center;
const viewPos = view.viewToProject(mousePos);
let newZoom = delta > 0
? view.zoom * this.factor
: view.zoom / this.factor;
newZoom = this.setZoomConstrained(newZoom);
if(!newZoom){
return;
}
const zoomScale = oldZoom / newZoom;
const centerAdjust = viewPos.subtract(oldCenter);
const offset = viewPos.subtract(centerAdjust.multiply(zoomScale))
.subtract(oldCenter);
view.center = view.center.add(offset);
};
zoomTo(rect: paper.Rectangle){
const view = this.project.view;
view.center = rect.center;
view.zoom = Math.min(
view.viewSize.height / rect.height,
view.viewSize.width / rect.width);
}
}
@brendonmm
Copy link

The reference site url was changed to: http://matthiasberth.com/tech/stable-zoom-and-pan-in-paperjs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment