57 lines
2.0 KiB
JavaScript
57 lines
2.0 KiB
JavaScript
const OUTPUT_PIXELS = 64;
|
|
|
|
function positiveNumber(value, field) {
|
|
const number = Number(value);
|
|
if (!Number.isFinite(number) || number <= 0) {
|
|
throw new TypeError(field + " must be a positive number");
|
|
}
|
|
return number;
|
|
}
|
|
|
|
export function cropGeometry({
|
|
viewportWidth, viewportHeight, sourceWidth, sourceHeight, zoom, centerX, centerY,
|
|
}) {
|
|
const viewWidth = positiveNumber(viewportWidth, "viewportWidth");
|
|
const viewHeight = positiveNumber(viewportHeight, "viewportHeight");
|
|
const imageWidth = positiveNumber(sourceWidth, "sourceWidth");
|
|
const imageHeight = positiveNumber(sourceHeight, "sourceHeight");
|
|
const scaleZoom = positiveNumber(zoom, "zoom");
|
|
const x = Number(centerX), y = Number(centerY);
|
|
if (!Number.isFinite(x) || !Number.isFinite(y)) {
|
|
throw new TypeError("crop center must be finite");
|
|
}
|
|
const scale = Math.min(viewWidth / imageWidth, viewHeight / imageHeight) * scaleZoom;
|
|
const width = imageWidth * scale;
|
|
const height = imageHeight * scale;
|
|
return {
|
|
width,
|
|
height,
|
|
left: viewWidth / 2 - x * width,
|
|
top: viewHeight / 2 - y * height,
|
|
};
|
|
}
|
|
|
|
export function cropCenterBounds({
|
|
viewportWidth, viewportHeight, sourceWidth, sourceHeight, zoom,
|
|
}) {
|
|
const geometry = cropGeometry({
|
|
viewportWidth, viewportHeight, sourceWidth, sourceHeight, zoom,
|
|
centerX: 0.5, centerY: 0.5,
|
|
});
|
|
const visibleX = Math.min(Number(viewportWidth) / OUTPUT_PIXELS, geometry.width);
|
|
const visibleY = Math.min(Number(viewportHeight) / OUTPUT_PIXELS, geometry.height);
|
|
return {
|
|
minX: (visibleX - Number(viewportWidth) / 2) / geometry.width,
|
|
maxX: 1 + (Number(viewportWidth) / 2 - visibleX) / geometry.width,
|
|
minY: (visibleY - Number(viewportHeight) / 2) / geometry.height,
|
|
maxY: 1 + (Number(viewportHeight) / 2 - visibleY) / geometry.height,
|
|
};
|
|
}
|
|
|
|
export function clampCropCenter(value, bounds) {
|
|
return {
|
|
centerX: Math.max(bounds.minX, Math.min(bounds.maxX, Number(value.centerX))),
|
|
centerY: Math.max(bounds.minY, Math.min(bounds.maxY, Number(value.centerY))),
|
|
};
|
|
}
|