aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DragManager.ts45
-rw-r--r--src/client/views/DocumentDecorations.tsx39
2 files changed, 60 insertions, 24 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 1ee4c57a2..d1d7f2a8a 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -255,9 +255,42 @@ export namespace DragManager {
export function SetSnapLines(horizLines: number[], vertLines: number[]) {
SnappingManager.setSnapLines(horizLines, vertLines);
}
+ export function snapDragAspect(dragPt: number[], snapAspect: number) {
+ let closest = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10);
+ let near = dragPt;
+ const intersect = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, dragx: number, dragy: number) => {
+ if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) return undefined; // Check if none of the lines are of length 0
+ const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
+ if (denominator === 0) return undefined; // Lines are parallel
+ let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
+ // let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;
+ //if (ua < 0 || ua > 1 || ub < 0 || ub > 1) return undefined; // is the intersection along the segments
+
+ // Return a object with the x and y coordinates of the intersection
+ let x = x1 + ua * (x2 - x1)
+ let y = y1 + ua * (y2 - y1)
+ const dist = Math.sqrt((dragx - x) * (dragx - x) + (dragy - y) * (dragy - y));
+ return { pt: [x, y], dist }
+ }
+ SnappingManager.vertSnapLines().forEach((xCoord, i) => {
+ const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, xCoord, -1, xCoord, 1, dragPt[0], dragPt[1]);
+ if (pt && pt.dist < closest) {
+ closest = pt.dist;
+ near = pt.pt;
+ }
+ });
+ SnappingManager.horizSnapLines().forEach((yCoord, i) => {
+ const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, -1, yCoord, 1, yCoord, dragPt[0], dragPt[1]);
+ if (pt && pt.dist < closest) {
+ closest = pt.dist;
+ near = pt.pt;
+ }
+ });
+ return { thisX: near[0], thisY: near[1] };
+ }
// snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line
- export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number, oneAxis: boolean = false) {
+ export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) {
const snapThreshold = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10);
const snapVal = (pts: number[], drag: number, snapLines: number[]) => {
if (snapLines.length) {
@@ -266,15 +299,13 @@ export namespace DragManager {
const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest));
const closestDists = rangePts.map((pt, i) => Math.abs(pt - closestPts[i]));
const minIndex = closestDists[0] < closestDists[1] && closestDists[0] < closestDists[2] ? 0 : closestDists[1] < closestDists[2] ? 1 : 2;
- return closestDists[minIndex] < snapThreshold ? [closestDists[minIndex], closestPts[minIndex] + offs[minIndex]] : [Number.MAX_VALUE, drag];
+ return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag;
}
- return [Number.MAX_VALUE, drag];
+ return drag;
};
- const xsnap = snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines());
- const ysnap = snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines());
return {
- thisX: !oneAxis || xsnap[0] < ysnap[0] ? xsnap[1] : e.pageX,
- thisY: !oneAxis || xsnap[0] > ysnap[0] ? ysnap[1] : e.pageY
+ thisX: snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()),
+ thisY: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines())
};
}
export let docsBeingDragged: Doc[] = [];
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index b939d96b6..3cd7f8da3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -3,7 +3,7 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faT
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DataSym, Field } from "../../new_fields/Doc";
+import { Doc, DataSym, Field, WidthSym, HeightSym } from "../../new_fields/Doc";
import { Document } from '../../new_fields/documentSchemas';
import { ScriptField } from '../../new_fields/ScriptField';
import { Cast, StrCast, NumCast } from "../../new_fields/Types";
@@ -262,24 +262,29 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
const first = SelectionManager.SelectedDocuments()[0];
- const fixedAspect = NumCast(first.layoutDoc._nativeWidth) !== 0;
- let { thisX, thisY } = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY, fixedAspect);
- if (fixedAspect) { // if aspect is set, then any snapped movement must be coerced to match the aspect ratio
- const aspect = NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight);
- const deltaX = thisX - this._snapX;
- const deltaY = thisY - this._snapY;
- if (thisX !== e.pageX) {
- const snapY = deltaX / aspect + this._snapY;
- thisY = Math.abs(deltaX / aspect) < 10 ? snapY : thisY;
- } else {
- const snapX = deltaY * aspect + this._snapX;
- thisX = Math.abs(deltaY * aspect) < 10 ? snapX : thisX;
+ let thisPt = { thisX: e.clientX - this._offX, thisY: e.clientY - this._offY };
+ const fixedAspect = first.layoutDoc._nativeWidth ? NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight) : 0;
+ if (fixedAspect) { // need to generalize for bl and tr drag handles
+ const project = (p: number[], a: number[], b: number[]) => {
+ var atob = [b[0] - a[0], b[1] - a[1]];
+ var atop = [p[0] - a[0], p[1] - a[1]];
+ var len = atob[0] * atob[0] + atob[1] * atob[1];
+ var dot = atop[0] * atob[0] + atop[1] * atob[1];
+ var t = dot / len;
+ dot = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]);
+ return [a[0] + atob[0] * t, a[1] + atob[1] * t];
}
+ const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1])
+ thisPt = DragManager.snapDragAspect(drag, fixedAspect);
+ } else {
+ thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY);
}
- move[0] = thisX - this._snapX;
- move[1] = thisY - this._snapY;
- this._snapX = thisX;
- this._snapY = thisY;
+
+ move[0] = thisPt.thisX - this._snapX;
+ move[1] = thisPt.thisY - this._snapY;
+ this._snapX = thisPt.thisX;
+ this._snapY = thisPt.thisY;
let dX = 0, dY = 0, dW = 0, dH = 0;
const unfreeze = () =>