aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/SelectionManager.ts5
-rw-r--r--src/client/views/DocumentDecorations.tsx24
-rw-r--r--src/client/views/InkControlPtHandles.tsx12
-rw-r--r--src/client/views/InkStrokeProperties.ts104
-rw-r--r--src/client/views/InkingStroke.tsx49
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx6
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/server/DashUploadUtils.ts5
-rw-r--r--src/server/SharedMediaTypes.ts2
10 files changed, 144 insertions, 76 deletions
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index e507ec3bf..2cba2c1f2 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -27,7 +27,7 @@ export namespace SelectionManager {
manager.SelectedViews.set(docView, docView.rootDoc);
docView.props.whenChildContentsActiveChanged(true);
- } else if (!ctrlPressed && Array.from(manager.SelectedViews.entries()).length > 1) {
+ } else if (!ctrlPressed && (Array.from(manager.SelectedViews.entries()).length > 1 || manager.SelectedSchemaDocument)) {
Array.from(manager.SelectedViews.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false));
manager.SelectedSchemaDocument = undefined;
manager.SelectedViews.clear();
@@ -57,7 +57,8 @@ export namespace SelectionManager {
export function SelectView(docView: DocumentView, ctrlPressed: boolean): void {
manager.SelectView(docView, ctrlPressed);
}
- export function SelectSchemaViewDoc(document: Opt<Doc>): void {
+ export function SelectSchemaViewDoc(document: Opt<Doc>, deselectAllFirst?: boolean): void {
+ if (deselectAllFirst) manager.DeselectAll();
manager.SelectSchemaViewDoc(document);
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 5b44a0552..522995479 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,7 +1,7 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from '@material-ui/core';
-import { action, computed, observable, reaction, runInAction } from "mobx";
+import { action, computed, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import { DateField } from '../../fields/DateField';
import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSym } from "../../fields/Doc";
@@ -27,8 +27,6 @@ import { LightboxView } from './LightboxView';
import { DocumentView } from "./nodes/DocumentView";
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import React = require("react");
-import { dark } from '@material-ui/core/styles/createPalette';
-import { color } from 'd3-color';
@observer
export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> {
@@ -65,15 +63,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
@computed
get Bounds() {
- return SelectionManager.Views().map(dv => dv.getBounds()).reduce((bounds, rect) =>
+ const views = SelectionManager.Views();
+ return views.map(dv => dv.getBounds()).reduce((bounds, rect) =>
!rect ? bounds :
{
x: Math.min(rect.left, bounds.x),
y: Math.min(rect.top, bounds.y),
r: Math.max(rect.right, bounds.r),
- b: Math.max(rect.bottom, bounds.b)
+ b: Math.max(rect.bottom, bounds.b),
+ c: views.length === 1 ? rect.center : undefined
},
- { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
+ { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE, c: undefined as ({ X: number, Y: number } | undefined) });
}
@action
@@ -195,13 +195,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
@action
onRotateDown = (e: React.PointerEvent): void => {
this._rotateUndo = UndoManager.StartBatch("rotatedown");
- const pt = { x: (this.Bounds.x + this.Bounds.r) / 2, y: (this.Bounds.y + this.Bounds.b) / 2 };
+ const pt = { x: this.Bounds.c?.X ?? (this.Bounds.x + this.Bounds.r) / 2, y: this.Bounds.c?.Y ?? (this.Bounds.y + this.Bounds.b) / 2 };
setupMoveUpEvents(this, e,
(e: PointerEvent, down: number[], delta: number[]) => {
- const movement = { X: delta[0], Y: e.clientY - down[1] };
- const angle = Math.max(1, Math.abs(movement.Y / 10));
+ const docView = SelectionManager.Views()[0];
+ const { left, top, right, bottom } = docView.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 };
+ const centerPoint = { X: (left + right) / 2, Y: (top + bottom) / 2 };
+ const previousPoint = { X: e.clientX, Y: e.clientY };
+ const movedPoint = { X: e.clientX - delta[0], Y: e.clientY - delta[1] };
+ const angle = InkStrokeProperties.Instance?.angleChange(previousPoint, movedPoint, centerPoint);
const selectedInk = SelectionManager.Views().filter(i => Document(i.rootDoc).type === DocumentType.INK);
- InkStrokeProperties.Instance?.rotateInk(selectedInk, 2 * movement.X / angle * (Math.PI / 180), pt);
+ angle && InkStrokeProperties.Instance?.rotateInk(selectedInk, -angle, pt);
return false;
},
() => {
diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx
index 73de4a3e0..f24dab949 100644
--- a/src/client/views/InkControlPtHandles.tsx
+++ b/src/client/views/InkControlPtHandles.tsx
@@ -2,10 +2,10 @@ import React = require("react");
import { action, observable } from "mobx";
import { observer } from "mobx-react";
import { Doc } from "../../fields/Doc";
-import { ControlPoint, InkData, PointData } from "../../fields/InkField";
+import { ControlPoint, InkData, PointData, InkField } from "../../fields/InkField";
import { List } from "../../fields/List";
import { listSpec } from "../../fields/Schema";
-import { Cast } from "../../fields/Types";
+import { Cast, NumCast } from "../../fields/Types";
import { setupMoveUpEvents } from "../../Utils";
import { Transform } from "../util/Transform";
import { UndoManager } from "../util/UndoManager";
@@ -43,8 +43,8 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
*/
@action
onControlDown = (e: React.PointerEvent, controlIndex: number): void => {
- if (InkStrokeProperties.Instance) {
- const screenScale = this.props.ScreenToLocalTransform().Scale;
+ const ptFromScreen = this.props.inkView.ComponentView?.ptFromScreen;
+ if (InkStrokeProperties.Instance && ptFromScreen) {
const order = controlIndex % 4;
const handleIndexA = ((order === 3 ? controlIndex - 1 : controlIndex - 2) + this.props.inkCtrlPoints.length) % this.props.inkCtrlPoints.length;
const handleIndexB = (order === 3 ? controlIndex + 2 : controlIndex + 1) % this.props.inkCtrlPoints.length;
@@ -53,7 +53,9 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
setupMoveUpEvents(this, e,
action((e: PointerEvent, down: number[], delta: number[]) => {
if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("drag ink ctrl pt");
- InkStrokeProperties.Instance?.moveControlPtHandle(this.props.inkView, delta[0] * screenScale, delta[1] * screenScale, controlIndex);
+ const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] });
+ const inkMoveStart = ptFromScreen({ X: 0, Y: 0 });
+ InkStrokeProperties.Instance?.moveControlPtHandle(this.props.inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex);
return false;
}),
action(() => {
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 33e25bbbb..6687b2bc7 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -1,6 +1,6 @@
import { Bezier } from "bezier-js";
import { action, observable, reaction } from "mobx";
-import { Doc, Opt } from "../../fields/Doc";
+import { Doc, Opt, DocListCast } from "../../fields/Doc";
import { InkData, InkField, InkTool, PointData } from "../../fields/InkField";
import { List } from "../../fields/List";
import { listSpec } from "../../fields/Schema";
@@ -10,6 +10,7 @@ import { CurrentUserUtils } from "../util/CurrentUserUtils";
import { undoBatch } from "../util/UndoManager";
import { InkingStroke } from "./InkingStroke";
import { DocumentView } from "./nodes/DocumentView";
+import { DocumentManager } from "../util/DocumentManager";
export class InkStrokeProperties {
static Instance: InkStrokeProperties | undefined;
@@ -155,29 +156,24 @@ export class InkStrokeProperties {
}, true)
/**
- * Rotates the entire selected ink instance.
+ * Rotates ink stroke(s) about a point
+ * @param inkStrokes set of ink documentViews to rotate
* @param angle The angle at which to rotate the ink in radians.
+ * @param scrpt The center point of the rotation in screen coordinates
*/
@undoBatch
@action
rotateInk = (inkStrokes: DocumentView[], angle: number, scrpt: { x: number, y: number }) => {
this.applyFunction(inkStrokes, (view: DocumentView, ink: InkData, xScale: number, yScale: number, inkStrokeWidth: number) => {
- const oldXrangeMin = Math.min(...ink.map(p => p.X));
- const oldYrangeMin = Math.min(...ink.map(p => p.Y));
- const docViewCenterPt = view.screenToLocalTransform().transformPoint(scrpt.x, scrpt.y);
- const inkCenterPt = {
- X: (docViewCenterPt[0] - inkStrokeWidth / 2) / xScale + oldXrangeMin,
- Y: (docViewCenterPt[1] - inkStrokeWidth / 2) / yScale + oldYrangeMin
- };
- const newPoints = ink.map(i => {
- const pt = { X: i.X - inkCenterPt.X, Y: i.Y - inkCenterPt.Y };
- const newX = Math.cos(angle) * pt.X - Math.sin(angle) * pt.Y * yScale / xScale;
- const newY = Math.sin(angle) * pt.X * xScale / yScale + Math.cos(angle) * pt.Y;
- return { X: newX + inkCenterPt.X, Y: newY + inkCenterPt.Y };
- });
- const doc = view.rootDoc;
- doc.rotation = NumCast(doc.rotation) + angle;
- return newPoints;
+ view.rootDoc.rotation = NumCast(view.rootDoc.rotation) + angle;
+ const inkCenterPt = view.ComponentView?.ptFromScreen?.({ X: scrpt.x, Y: scrpt.y });
+ return !inkCenterPt ? ink :
+ ink.map(i => {
+ const pt = { X: i.X - inkCenterPt.X, Y: i.Y - inkCenterPt.Y };
+ const newX = Math.cos(angle) * pt.X - Math.sin(angle) * pt.Y * yScale / xScale;
+ const newY = Math.sin(angle) * pt.X * xScale / yScale + Math.cos(angle) * pt.Y;
+ return { X: newX + inkCenterPt.X, Y: newY + inkCenterPt.Y };
+ });
});
}
@@ -203,7 +199,7 @@ export class InkStrokeProperties {
(order === 3 && controlIndex !== ink.length - 1 && i === controlIndex + 1) ||
(order === 3 && controlIndex !== ink.length - 1 && i === controlIndex + 2) ||
((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlIndex === 0 || controlIndex === ink.length - 1))) {
- return ({ X: pt.X + deltaX / xScale, Y: pt.Y + deltaY / yScale });
+ return ({ X: pt.X + deltaX, Y: pt.Y + deltaY });
}
return pt;
});
@@ -211,7 +207,7 @@ export class InkStrokeProperties {
})
- public static nearestPtToStroke(ctrlPoints: { X: number, Y: number }[], refPt: { X: number, Y: number }, excludeSegs?: number[]) {
+ public static nearestPtToStroke(ctrlPoints: { X: number, Y: number }[], refInkSpacePt: { X: number, Y: number }, excludeSegs?: number[]) {
var distance = Number.MAX_SAFE_INTEGER;
var nearestT = -1;
var nearestSeg = -1;
@@ -219,9 +215,9 @@ export class InkStrokeProperties {
for (var i = 0; i < ctrlPoints.length - 3; i += 4) {
if (excludeSegs?.includes(i)) continue;
const array = [ctrlPoints[i], ctrlPoints[i + 1], ctrlPoints[i + 2], ctrlPoints[i + 3]];
- const point = new Bezier(array.map(p => ({ x: p.X, y: p.Y }))).project({ x: refPt.X, y: refPt.Y });
+ const point = new Bezier(array.map(p => ({ x: p.X, y: p.Y }))).project({ x: refInkSpacePt.X, y: refInkSpacePt.Y });
if (point.t !== undefined) {
- const dist = Math.sqrt((point.x - refPt.X) * (point.x - refPt.X) + (point.y - refPt.Y) * (point.y - refPt.Y));
+ const dist = Math.sqrt((point.x - refInkSpacePt.X) * (point.x - refInkSpacePt.X) + (point.y - refInkSpacePt.Y) * (point.y - refInkSpacePt.Y));
if (dist < distance) {
distance = dist;
nearestT = point.t;
@@ -238,34 +234,54 @@ export class InkStrokeProperties {
*/
snapControl = (inkView: DocumentView, controlIndex: number) => {
const inkDoc = inkView.rootDoc;
- const ink = Cast(inkDoc.data, InkField)?.inkData;
- if (ink) {
- const closed = InkingStroke.IsClosed(ink);
-
- // figure out which segments we don't want to snap to - avoid the dragged control point's segment and the next and prev segments (when they exist -- ie not for endpoints of unclosed curve)
- const thisseg = Math.floor(controlIndex / 4) * 4;
- const which = controlIndex % 4;
- const nextseg = which > 1 && (closed || controlIndex < ink.length - 1) ? (thisseg + 4) % ink.length : -1;
- const prevseg = which < 2 && (closed || controlIndex > 0) ? (thisseg - 4 + ink.length) % ink.length : -1;
- const refPt = ink[controlIndex];
- const { nearestPt } = InkStrokeProperties.nearestPtToStroke(ink, refPt, [thisseg, prevseg, nextseg]);
+ const ink = Cast(inkDoc[Doc.LayoutFieldKey(inkDoc)], InkField)?.inkData;
- // nearestPt is in inkDoc coordinates -- we need to compute the distance in screen coordinates.
- // so we scale the X & Y distances by the internal ink scale factor and then transform the final distance by the ScreenToLocal.Scale of the inkDoc itself.
- const oldXrange = (xs => ({ coord: NumCast(inkDoc.x), min: Math.min(...xs), max: Math.max(...xs) }))(ink.map(p => p.X));
- const oldYrange = (ys => ({ coord: NumCast(inkDoc.y), min: Math.min(...ys), max: Math.max(...ys) }))(ink.map(p => p.Y));
- const ptsXscale = ((NumCast(inkDoc._width) - NumCast(inkDoc.strokeWidth)) / ((oldXrange.max - oldXrange.min) || 1)) || 1;
- const ptsYscale = ((NumCast(inkDoc._height) - NumCast(inkDoc.strokeWidth)) / ((oldYrange.max - oldYrange.min) || 1)) || 1;
- const near = Math.sqrt((nearestPt.X - refPt.X) * (nearestPt.X - refPt.X) * ptsXscale * ptsXscale +
- (nearestPt.Y - refPt.Y) * (nearestPt.Y - refPt.Y) * ptsYscale * ptsYscale);
-
- if (near / (inkView.props.ScreenToLocalTransform().Scale || 1) < 10) {
- return this.moveControlPtHandle(inkView, (nearestPt.X - ink[controlIndex].X) * ptsXscale, (nearestPt.Y - ink[controlIndex].Y) * ptsYscale, controlIndex);
+ if (ink) {
+ const screenDragPt = inkView.ComponentView?.ptToScreen?.(ink[controlIndex]);
+ if (screenDragPt) {
+ const snapData = this.snapToAllCurves(screenDragPt, inkView, { nearestPt: { X: 0, Y: 0 }, distance: 10 }, ink, controlIndex);
+ if (snapData.distance < 10) {
+ const deltaX = (snapData.nearestPt.X - ink[controlIndex].X);
+ const deltaY = (snapData.nearestPt.Y - ink[controlIndex].Y);
+ const res = this.moveControlPtHandle(inkView, deltaX, deltaY, controlIndex);
+ console.log("X= " + snapData.nearestPt.X + " " + snapData.nearestPt.Y);
+ return res;
+ }
}
}
return false;
}
+ excludeSelfSnapSegs = (ink: InkData, controlIndex: number) => {
+ const closed = InkingStroke.IsClosed(ink);
+
+ // figure out which segments we don't want to snap to - avoid the dragged control point's segment and the next and prev segments (when they exist -- ie not for endpoints of unclosed curve)
+ const thisseg = Math.floor(controlIndex / 4) * 4;
+ const which = controlIndex % 4;
+ const nextseg = which > 1 && (closed || controlIndex < ink.length - 1) ? (thisseg + 4) % ink.length : -1;
+ const prevseg = which < 2 && (closed || controlIndex > 0) ? (thisseg - 4 + ink.length) % ink.length : -1;
+ return [thisseg, prevseg, nextseg];
+ }
+
+ snapToAllCurves = (screenDragPt: { X: number, Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number, Y: number }, distance: number }, ink: InkData, controlIndex: number) => {
+ const containingCollection = inkView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ containingCollection?.childDocs
+ .filter(doc => doc.type === DocumentType.INK)
+ .forEach(doc => {
+ const testInkView = DocumentManager.Instance.getDocumentView(doc, containingCollection?.props.CollectionView);
+ const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.rootDoc ? this.excludeSelfSnapSegs(ink, controlIndex) : []);
+ if (snapped && snapped.distance < snapData.distance) {
+ const snappedInkPt = doc === inkView.rootDoc ? snapped.nearestPt :
+ inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space
+
+ if (snappedInkPt) {
+ snapData = { nearestPt: snappedInkPt, distance: snapped.distance };
+ }
+ }
+ });
+ return snapData;
+ }
+
/**
* Snaps a control point with broken tangency back to synced rotation.
* @param handleIndexA The handle point that retains its current position.
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index d312331d0..ecb46a5b3 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -21,6 +21,7 @@ import { InkStrokeProperties } from "./InkStrokeProperties";
import { InkTangentHandles } from "./InkTangentHandles";
import { FieldView, FieldViewProps } from "./nodes/FieldView";
import Color = require("color");
+import { Transform } from "../util/Transform";
type InkDocument = makeInterface<[typeof documentSchema]>;
const InkDocument = makeInterface(documentSchema);
@@ -56,6 +57,22 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
this._selDisposer?.();
}
+ getCenter = (xf: Transform) => {
+ const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
+ const angle = -NumCast(this.layoutDoc.rotation);
+ const newPoints = inkData.map(pt => {
+ const newX = Math.cos(angle) * pt.X - Math.sin(angle) * pt.Y * inkScaleY / inkScaleX;
+ const newY = Math.sin(angle) * pt.X * inkScaleX / inkScaleY + Math.cos(angle) * pt.Y;
+ return { X: newX, Y: newY };
+ });
+ const crx = (Math.max(...newPoints.map(np => np.X)) + Math.min(...newPoints.map(np => np.X))) / 2;
+ const cry = (Math.max(...newPoints.map(np => np.Y)) + Math.min(...newPoints.map(np => np.Y))) / 2;
+ const cx = Math.cos(-angle) * crx - Math.sin(-angle) * cry * inkScaleY / inkScaleX;
+ const cy = Math.sin(-angle) * crx * inkScaleX / inkScaleY + Math.cos(-angle) * cry;
+ const tc = xf.transformPoint((cx - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (cy - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2);
+ return { X: tc[0], Y: tc[1] };
+ }
+
analyzeStrokes() {
const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ["inkAnalysis", "handwriting"], [data]);
@@ -107,6 +124,32 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
}
+ ptFromScreen = (scrPt: { X: number, Y: number }) => {
+ const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
+ const docPt = this.props.ScreenToLocalTransform().transformPoint(scrPt.X, scrPt.Y);
+ const inkPt = {
+ X: (docPt[0] - inkStrokeWidth / 2) / inkScaleX + inkStrokeWidth / 2 + inkLeft,
+ Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop,
+ };
+ return inkPt;
+ }
+ ptToScreen = (inkPt: { X: number, Y: number }) => {
+ const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
+ const docPt = {
+ X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2,
+ Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2
+ };
+ const scrPt = this.props.ScreenToLocalTransform().inverse().transformPoint(docPt.X, docPt.Y);
+ return { X: scrPt[0], Y: scrPt[1] };
+ }
+
+ snapPt = (scrPt: { X: number, Y: number }, excludeSegs?: number[]) => {
+ const { inkData } = this.inkScaledData();
+ const inkPt = this.ptFromScreen(scrPt);
+ const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, inkPt, excludeSegs ?? []);
+ return { nearestPt, distance: distance * this.props.ScreenToLocalTransform().inverse().Scale };
+ }
+
inkScaledData = () => {
const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1);
@@ -197,15 +240,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap),
StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker,
StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false);
- // Thin blue line indicating that the current ink stroke is selected.
- // const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
- // StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
- // Invisible polygonal line that enables the ink to be selected by the user.
const highlightIndex = BoolCast(this.props.Document.isLinkButton) && Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
const highlightColor = !highlightIndex ?
StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== "transparent" ? StrCast(this.layoutDoc.color, "transparent") : "transparent") :
["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "yellow", "magenta", "cyan", "orange"][highlightIndex];
-
+ // Invisible polygonal line that enables the ink to be selected by the user.
const clickableLine = InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor,
inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && (new Color(fillColor)).alpha() < 1 ? 6 : 15),
StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap),
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 5325d5827..f543d924d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -44,6 +44,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
}
private _reactionDisposer?: IReactionDisposer;
+ private _lightboxReactionDisposer?: IReactionDisposer;
private _containerRef = React.createRef<HTMLDivElement>();
private _flush: UndoManager.Batch | undefined;
private _ignoreStateChange = "";
@@ -298,6 +299,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
componentDidMount: () => void = () => {
if (this._containerRef.current) {
+ this._lightboxReactionDisposer = reaction(() => LightboxView.LightboxDoc, doc => setTimeout(() => !doc && this.onResize(undefined)));
new _global.ResizeObserver(this.onResize).observe(this._containerRef.current);
this._reactionDisposer = reaction(() => StrCast(this.props.Document.dockingConfig),
config => {
@@ -320,13 +322,14 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
window.removeEventListener('resize', this.onResize);
this._reactionDisposer?.();
+ this._lightboxReactionDisposer?.();
}
@action
onResize = (event: any) => {
const cur = this._containerRef.current;
// bcz: since GoldenLayout isn't a React component itself, we need to notify it to resize when its document container's size has changed
- cur && this._goldenLayout?.updateSize(cur.getBoundingClientRect().width, cur.getBoundingClientRect().height);
+ !LightboxView.LightboxDoc && cur && this._goldenLayout?.updateSize(cur.getBoundingClientRect().width, cur.getBoundingClientRect().height);
}
@action
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index bb4cae8c6..9769453a0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -5,9 +5,8 @@ import { Id } from "../../../../fields/FieldSymbols";
import { List } from "../../../../fields/List";
import { NumCast } from "../../../../fields/Types";
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
-import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { LinkManager } from "../../../util/LinkManager";
-import { ColorScheme } from "../../../util/SettingsManager";
+import { SelectionManager } from "../../../util/SelectionManager";
import { SnappingManager } from "../../../util/SnappingManager";
import { DocumentView } from "../../nodes/DocumentView";
import "./CollectionFreeFormLinkView.scss";
@@ -199,7 +198,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const strokeWidth = linkSize === -1 ? "3px" : Math.floor(2 + 10 * (linkSize / Math.max(...linkRelationshipSizes))) + "px";
return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
- <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, /*strokeDasharray: "2 2",*/ stroke, strokeWidth }}
+ <path className="collectionfreeformlinkview-linkLine" style={{ pointerEvents: "all", opacity: this._opacity, strokeDasharray: SelectionManager.SelectedSchemaDoc() === this.props.LinkDocs[0] ? "2 2" : undefined, stroke, strokeWidth }}
+ onClick={() => SelectionManager.SelectSchemaViewDoc(this.props.LinkDocs[0], true)}
d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
{textX === undefined ? (null) : <text className="collectionfreeformlinkview-linkText" x={textX} y={textY} onPointerDown={this.pointerDown} >
{Field.toString(this.props.LinkDocs[0].description as any as Field)}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 949e0e168..c9b246c10 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -97,6 +97,10 @@ export interface DocComponentView {
annotationKey?: string;
getTitle?: () => string;
getScrollHeight?: () => number;
+ getCenter?: (xf: Transform) => { X: number, Y: number };
+ ptToScreen?: (pt: { X: number, Y: number }) => { X: number, Y: number };
+ ptFromScreen?: (pt: { X: number, Y: number }) => { X: number, Y: number };
+ snapPt?: (pt: { X: number, Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number, Y: number }, distance: number };
search?: (str: string, bwd?: boolean, clear?: boolean) => boolean;
}
export interface DocumentViewSharedProps {
@@ -1179,9 +1183,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)];
if (this.docView.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
const docuBox = this.docView.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
- if (docuBox.length) return docuBox[0].getBoundingClientRect();
+ if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined };
}
- return { left, top, right, bottom };
+ return { left, top, right, bottom, center: this.ComponentView?.getCenter?.(xf) };
}
public iconify() {
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 54b71e8ce..f13580865 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -332,7 +332,7 @@ export namespace DashUploadUtils {
}
};
- const parseExifData = async (source: string): Promise<Upload.EnrichedExifData> => {
+ const parseExifData = async (source: string) => {
const image = await request.get(source, { encoding: null });
const { data, error } = await new Promise(resolve => {
new ExifImage({ image }, (error, data) => {
@@ -343,9 +343,8 @@ export namespace DashUploadUtils {
resolve({ data, error: reason });
});
});
- return { data: await exifr.parse(image) as any, error };
//data && bufferConverterRec(data);
- return { data, error };
+ return { data: await exifr.parse(image), error };
};
const { pngs, jpgs, webps, tiffs } = AcceptableMedia;
diff --git a/src/server/SharedMediaTypes.ts b/src/server/SharedMediaTypes.ts
index fdc65188f..cde95526f 100644
--- a/src/server/SharedMediaTypes.ts
+++ b/src/server/SharedMediaTypes.ts
@@ -44,7 +44,7 @@ export namespace Upload {
}
export interface EnrichedExifData {
- data: ExifData;
+ data: ExifData & ExifData["gps"];
error?: string;
}