126 lines
4.7 KiB
JavaScript
126 lines
4.7 KiB
JavaScript
import { progress } from '../../../utils/progress.mjs';
|
|
import { calcLength } from '../../../projection/geometry/delta-calc.mjs';
|
|
import { clamp } from '../../../utils/clamp.mjs';
|
|
import { mix } from '../../../utils/mix.mjs';
|
|
|
|
/**
|
|
* Apply constraints to a point. These constraints are both physical along an
|
|
* axis, and an elastic factor that determines how much to constrain the point
|
|
* by if it does lie outside the defined parameters.
|
|
*/
|
|
function applyConstraints(point, { min, max }, elastic) {
|
|
if (min !== undefined && point < min) {
|
|
// If we have a min point defined, and this is outside of that, constrain
|
|
point = elastic ? mix(min, point, elastic.min) : Math.max(point, min);
|
|
}
|
|
else if (max !== undefined && point > max) {
|
|
// If we have a max point defined, and this is outside of that, constrain
|
|
point = elastic ? mix(max, point, elastic.max) : Math.min(point, max);
|
|
}
|
|
return point;
|
|
}
|
|
/**
|
|
* Calculate constraints in terms of the viewport when defined relatively to the
|
|
* measured axis. This is measured from the nearest edge, so a max constraint of 200
|
|
* on an axis with a max value of 300 would return a constraint of 500 - axis length
|
|
*/
|
|
function calcRelativeAxisConstraints(axis, min, max) {
|
|
return {
|
|
min: min !== undefined ? axis.min + min : undefined,
|
|
max: max !== undefined
|
|
? axis.max + max - (axis.max - axis.min)
|
|
: undefined,
|
|
};
|
|
}
|
|
/**
|
|
* Calculate constraints in terms of the viewport when
|
|
* defined relatively to the measured bounding box.
|
|
*/
|
|
function calcRelativeConstraints(layoutBox, { top, left, bottom, right }) {
|
|
return {
|
|
x: calcRelativeAxisConstraints(layoutBox.x, left, right),
|
|
y: calcRelativeAxisConstraints(layoutBox.y, top, bottom),
|
|
};
|
|
}
|
|
/**
|
|
* Calculate viewport constraints when defined as another viewport-relative axis
|
|
*/
|
|
function calcViewportAxisConstraints(layoutAxis, constraintsAxis) {
|
|
let min = constraintsAxis.min - layoutAxis.min;
|
|
let max = constraintsAxis.max - layoutAxis.max;
|
|
// If the constraints axis is actually smaller than the layout axis then we can
|
|
// flip the constraints
|
|
if (constraintsAxis.max - constraintsAxis.min <
|
|
layoutAxis.max - layoutAxis.min) {
|
|
[min, max] = [max, min];
|
|
}
|
|
return { min, max };
|
|
}
|
|
/**
|
|
* Calculate viewport constraints when defined as another viewport-relative box
|
|
*/
|
|
function calcViewportConstraints(layoutBox, constraintsBox) {
|
|
return {
|
|
x: calcViewportAxisConstraints(layoutBox.x, constraintsBox.x),
|
|
y: calcViewportAxisConstraints(layoutBox.y, constraintsBox.y),
|
|
};
|
|
}
|
|
/**
|
|
* Calculate a transform origin relative to the source axis, between 0-1, that results
|
|
* in an asthetically pleasing scale/transform needed to project from source to target.
|
|
*/
|
|
function calcOrigin(source, target) {
|
|
let origin = 0.5;
|
|
const sourceLength = calcLength(source);
|
|
const targetLength = calcLength(target);
|
|
if (targetLength > sourceLength) {
|
|
origin = progress(target.min, target.max - sourceLength, source.min);
|
|
}
|
|
else if (sourceLength > targetLength) {
|
|
origin = progress(source.min, source.max - targetLength, target.min);
|
|
}
|
|
return clamp(0, 1, origin);
|
|
}
|
|
/**
|
|
* Rebase the calculated viewport constraints relative to the layout.min point.
|
|
*/
|
|
function rebaseAxisConstraints(layout, constraints) {
|
|
const relativeConstraints = {};
|
|
if (constraints.min !== undefined) {
|
|
relativeConstraints.min = constraints.min - layout.min;
|
|
}
|
|
if (constraints.max !== undefined) {
|
|
relativeConstraints.max = constraints.max - layout.min;
|
|
}
|
|
return relativeConstraints;
|
|
}
|
|
const defaultElastic = 0.35;
|
|
/**
|
|
* Accepts a dragElastic prop and returns resolved elastic values for each axis.
|
|
*/
|
|
function resolveDragElastic(dragElastic = defaultElastic) {
|
|
if (dragElastic === false) {
|
|
dragElastic = 0;
|
|
}
|
|
else if (dragElastic === true) {
|
|
dragElastic = defaultElastic;
|
|
}
|
|
return {
|
|
x: resolveAxisElastic(dragElastic, "left", "right"),
|
|
y: resolveAxisElastic(dragElastic, "top", "bottom"),
|
|
};
|
|
}
|
|
function resolveAxisElastic(dragElastic, minLabel, maxLabel) {
|
|
return {
|
|
min: resolvePointElastic(dragElastic, minLabel),
|
|
max: resolvePointElastic(dragElastic, maxLabel),
|
|
};
|
|
}
|
|
function resolvePointElastic(dragElastic, label) {
|
|
return typeof dragElastic === "number"
|
|
? dragElastic
|
|
: dragElastic[label] || 0;
|
|
}
|
|
|
|
export { applyConstraints, calcOrigin, calcRelativeAxisConstraints, calcRelativeConstraints, calcViewportAxisConstraints, calcViewportConstraints, defaultElastic, rebaseAxisConstraints, resolveAxisElastic, resolveDragElastic, resolvePointElastic };
|