scratch-paint/src/helper/view.js

112 lines
3.5 KiB
JavaScript
Raw Normal View History

import paper from '@scratch/paper';
import {getSelectedRootItems} from './selection';
import {getRaster} from './layer';
import {getHitBounds} from './bitmap';
// Vectors are imported and exported at SVG_ART_BOARD size.
// Once they are imported however, both SVGs and bitmaps are on
// canvases of ART_BOARD size.
const SVG_ART_BOARD_WIDTH = 480;
const SVG_ART_BOARD_HEIGHT = 360;
const ART_BOARD_WIDTH = 480 * 2;
const ART_BOARD_HEIGHT = 360 * 2;
const PADDING_PERCENT = 25; // Padding as a percent of the max of width/height of the sprite
const MIN_RATIO = .125; // Zoom in to at least 1/8 of the screen. This way you don't end up incredibly
// zoomed in for tiny costumes.
2018-08-16 16:49:43 -04:00
const clampViewBounds = () => {
2017-10-27 09:33:06 -04:00
const {left, right, top, bottom} = paper.project.view.bounds;
if (left < 0) {
paper.project.view.scrollBy(new paper.Point(-left, 0));
}
if (top < 0) {
paper.project.view.scrollBy(new paper.Point(0, -top));
}
if (bottom > ART_BOARD_HEIGHT) {
paper.project.view.scrollBy(new paper.Point(0, ART_BOARD_HEIGHT - bottom));
2017-10-27 09:33:06 -04:00
}
if (right > ART_BOARD_WIDTH) {
paper.project.view.scrollBy(new paper.Point(ART_BOARD_WIDTH - right, 0));
2017-10-27 09:33:06 -04:00
}
};
2017-10-27 10:06:01 -04:00
// Zoom keeping a project-space point fixed.
// This article was helpful http://matthiasberth.com/tech/stable-zoom-and-pan-in-paperjs
const zoomOnFixedPoint = (deltaZoom, fixedPoint) => {
const view = paper.view;
2017-10-27 10:06:01 -04:00
const preZoomCenter = view.center;
2018-04-20 11:20:38 -04:00
const newZoom = Math.max(0.5, view.zoom + deltaZoom);
2017-10-27 10:06:01 -04:00
const scaling = view.zoom / newZoom;
const preZoomOffset = fixedPoint.subtract(preZoomCenter);
const postZoomOffset = fixedPoint.subtract(preZoomOffset.multiply(scaling))
.subtract(preZoomCenter);
view.zoom = newZoom;
view.translate(postZoomOffset.multiply(-1));
2018-08-16 16:49:43 -04:00
clampViewBounds();
2017-10-27 10:06:01 -04:00
};
// Zoom keeping the selection center (if any) fixed.
2017-10-27 09:33:06 -04:00
const zoomOnSelection = deltaZoom => {
let fixedPoint;
const items = getSelectedRootItems();
if (items.length > 0) {
let rect = null;
for (const item of items) {
if (rect) {
rect = rect.unite(item.bounds);
} else {
rect = item.bounds;
}
}
fixedPoint = rect.center;
} else {
fixedPoint = paper.project.view.center;
}
zoomOnFixedPoint(deltaZoom, fixedPoint);
};
const resetZoom = () => {
paper.project.view.zoom = .5;
2018-08-16 16:49:43 -04:00
clampViewBounds();
};
const pan = (dx, dy) => {
paper.project.view.scrollBy(new paper.Point(dx, dy));
2018-08-16 16:49:43 -04:00
clampViewBounds();
};
const zoomToFit = isBitmap => {
resetZoom();
let bounds;
if (isBitmap) {
bounds = getHitBounds(getRaster());
} else {
bounds = paper.project.activeLayer.bounds;
}
if (bounds && bounds.width && bounds.height) {
// Ratio of (sprite length plus padding on all sides) to art board length.
let ratio = Math.max(bounds.width * (1 + (2 * PADDING_PERCENT / 100)) / ART_BOARD_WIDTH,
bounds.height * (1 + (2 * PADDING_PERCENT / 100)) / ART_BOARD_HEIGHT);
// Clamp ratio
ratio = Math.max(Math.min(1, ratio), MIN_RATIO);
if (ratio < 1) {
paper.view.center = bounds.center;
paper.view.zoom = paper.view.zoom / ratio;
clampViewBounds();
}
}
};
export {
ART_BOARD_HEIGHT,
ART_BOARD_WIDTH,
SVG_ART_BOARD_WIDTH,
SVG_ART_BOARD_HEIGHT,
2018-08-16 16:49:43 -04:00
clampViewBounds,
pan,
resetZoom,
zoomOnSelection,
zoomOnFixedPoint,
zoomToFit
2017-10-27 09:33:06 -04:00
};