aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authoreleanor-park <eleanor_park@brown.edu>2024-07-11 12:08:26 -0400
committereleanor-park <eleanor_park@brown.edu>2024-07-11 12:08:26 -0400
commitb88f3a79b4558b222864b7c925fd0d5086cdcea2 (patch)
tree4f830b4a4dd96948983115e1e5bff07a1a6eb3d1 /src/client/views/collections
parent4438e7fe202ff4091b26f073122e7866ec9abb46 (diff)
Revert "Merge branch 'eleanor-gptdraw' into master"
This reverts commit 4438e7fe202ff4091b26f073122e7866ec9abb46, reversing changes made to 59ca918ea0918b41f1e2fa4b6acb8725ca9b44af.
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionMenu.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx242
-rw-r--r--src/client/views/collections/collectionFreeForm/ImageLabelHandler.scss14
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx6
4 files changed, 74 insertions, 190 deletions
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 45d9394ed..3ec875df4 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -6,7 +6,7 @@
align-content: center;
justify-content: space-between;
background-color: $dark-gray;
- height: 40px;
+ height: 35px;
border-bottom: $standard-border;
padding: 0 10px;
align-items: center;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8f8cb9083..d611db1f8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
-import { Bezier, Point } from 'bezier-js';
+import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -27,7 +27,6 @@ import { aggregateBounds, clamp, emptyFunction, intersectRect, Utils } from '../
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocUtils } from '../../../documents/DocUtils';
-import { FitCurve, GenerateControlPoints } from '../../../util/bezierFit';
import { DragManager } from '../../../util/DragManager';
import { dropActionType } from '../../../util/DropActionTypes';
import { CompileScript } from '../../../util/Scripting';
@@ -56,7 +55,6 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable
import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors';
import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
-import { DrawingOptions, SmartDrawHandler } from '../../smartdraw/SmartDrawHandler';
@observer
class CollectionFreeFormOverlayView extends React.Component<{ elements: () => ViewDefResult[] }> {
@@ -120,7 +118,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _panZoomTransition: number = 0; // sets the pan/zoom transform ease time- used by nudge(), focus() etc to smoothly zoom/pan. set to 0 to use document's transition time or default of 0
@observable _firstRender = false; // this turns off rendering of the collection's content so that there's instant feedback when a tab is switched of what content will be shown. could be used for performance improvement
@observable _showAnimTimeline = false;
- @observable _showDrawingEditor = false;
@observable _deleteList: DocumentView[] = [];
@observable _timelineRef = React.createRef<Timeline>();
@observable _marqueeViewRef = React.createRef<MarqueeView>();
@@ -500,30 +497,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (!this.Document.isGroup) {
// group freeforms don't pan when dragged -- instead let the event go through to allow the group itself to drag
// prettier-ignore
- const hit = this._clusters.handlePointerDown(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY));
switch (Doc.ActiveTool) {
- case InkTool.Highlighter:
- case InkTool.Write:
- case InkTool.Pen:
- break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
+ case InkTool.Highlighter: break;
+ case InkTool.Write: break;
+ case InkTool.Pen: break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
case InkTool.StrokeEraser:
case InkTool.SegmentEraser:
+ this._batch = UndoManager.StartBatch('collectionErase');
+ this._eraserPts.length = 0;
+ setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction);
+ break;
case InkTool.RadiusEraser:
this._batch = UndoManager.StartBatch('collectionErase');
this._eraserPts.length = 0;
- setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, this.onEraserClick, hit !== -1);
- e.stopPropagation();
+ setupMoveUpEvents(this, e, this.onRadiusEraserMove, this.onEraserUp, emptyFunction);
break;
- case InkTool.SmartDraw:
- setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, this.showSmartDraw, hit !== -1);
- e.stopPropagation();
case InkTool.None:
if (!(this._props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
const hit = this._clusters.handlePointerDown(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY));
setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, hit !== -1, false);
}
break;
- default:
+ default:
}
}
}
@@ -574,7 +569,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
}
};
-
@action
onEraserUp = (): void => {
this._deleteList.lastElement()?._props.removeDocument?.(this._deleteList.map(ink => ink.Document));
@@ -615,48 +609,34 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
_eraserLock = 0;
_eraserPts: number[][] = []; // keep track of the last few eraserPts to make the eraser circle 'stretch'
- erase = (e: PointerEvent, delta: number[]) => {
- e.stopImmediatePropagation();
+ /**
+ * Erases strokes by intersecting them with an invisible "eraser stroke".
+ * By default this iterates through all intersected ink strokes, determines their segmentation, draws back the non-intersected segments,
+ * and deletes the original stroke.
+ */
+ @action
+ onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
const currPoint = { X: e.clientX, Y: e.clientY };
this._eraserPts.push([currPoint.X, currPoint.Y]);
this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5));
- if (Doc.ActiveTool === InkTool.RadiusEraser) {
- const strokeMap: Map<DocumentView, number[]> = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint);
- strokeMap.forEach((intersects, stroke) => {
- if (!this._deleteList.includes(stroke)) {
- this._deleteList.push(stroke);
- SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1');
- SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black');
- const segments = this.radiusErase(stroke, intersects.sort());
- segments?.forEach(segment =>
- this.forceStrokeGesture(
- e,
- Gestures.Stroke,
- segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[])
- )
- );
- }
- stroke.layoutDoc.opacity = 0;
- stroke.layoutDoc.dontIntersect = true;
- });
- } else {
- this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
- if (!this._deleteList.includes(intersect.inkView)) {
- this._deleteList.push(intersect.inkView);
- SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
- SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
- // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
- if (Doc.ActiveTool !== InkTool.StrokeEraser) {
- // this._eraserLock++;
- const segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it
- const newStrokes = segments?.map(segment => {
- const points = segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]);
- const bounds = InkField.getBounds(points);
- const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
- const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale;
- return Docs.Create.InkDocument(
- points,
- { title: 'stroke',
+ // if (this._eraserLock) return false; // leaving this commented out in case the idea is revisited in the future
+ this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
+ if (!this._deleteList.includes(intersect.inkView)) {
+ this._deleteList.push(intersect.inkView);
+ SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
+ SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
+ // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
+ if (Doc.ActiveTool !== InkTool.StrokeEraser) {
+ // this._eraserLock++;
+ const segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it
+ const newStrokes = segments?.map(segment => {
+ const points = segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]);
+ const bounds = InkField.getBounds(points);
+ const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
+ const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale;
+ return Docs.Create.InkDocument(
+ points,
+ { title: 'stroke',
x: B.x - inkWidth / 2,
y: B.y - inkWidth / 2,
_width: B.width + inkWidth,
@@ -675,30 +655,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
newStrokes && this.addDocument?.(newStrokes);
// setTimeout(() => this._eraserLock--);
}
- });
- }
- return false;
- };
-
- /**
- * Erases strokes by intersecting them with an invisible "eraser stroke".
- * By default this iterates through all intersected ink strokes, determines their segmentation, draws back the non-intersected segments,
- * and deletes the original stroke.
- */
- @action
- onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
- this.erase(e, delta);
- // if (this._eraserLock) return false; // leaving this commented out in case the idea is revisited in the future
+ // Lower ink opacity to give the user a visual indicator of deletion.
+ intersect.inkView.layoutDoc.opacity = 0;
+ intersect.inkView.layoutDoc.dontIntersect = true;
+ }
+ });
return false;
};
- @action
- onEraserClick = (e: PointerEvent, doubleTap?: boolean) => {
- e.preventDefault();
- e.stopImmediatePropagation();
- this.erase(e, [0, 0]);
- };
-
/**
* Erases strokes by intersecting them with a circle of variable radius. Essentially creates an InkField for the
* eraser circle, then determines its intersections with other ink strokes. Each stroke's DocumentView and its
@@ -708,32 +672,32 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
* @param delta
* @returns
*/
- // @action
- // onRadiusEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
- // const currPoint = { X: e.clientX, Y: e.clientY };
- // this._eraserPts.push([currPoint.X, currPoint.Y]);
- // this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5));
- // const strokeMap: Map<DocumentView, number[]> = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint);
-
- // strokeMap.forEach((intersects, stroke) => {
- // if (!this._deleteList.includes(stroke)) {
- // this._deleteList.push(stroke);
- // SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1');
- // SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black');
- // const segments = this.radiusErase(stroke, intersects.sort());
- // segments?.forEach(segment =>
- // this.forceStrokeGesture(
- // e,
- // Gestures.Stroke,
- // segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[])
- // )
- // );
- // }
- // stroke.layoutDoc.opacity = 0;
- // stroke.layoutDoc.dontIntersect = true;
- // });
- // return false;
- // };
+ @action
+ onRadiusEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
+ const currPoint = { X: e.clientX, Y: e.clientY };
+ this._eraserPts.push([currPoint.X, currPoint.Y]);
+ this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5));
+ const strokeMap: Map<DocumentView, number[]> = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint);
+
+ strokeMap.forEach((intersects, stroke) => {
+ if (!this._deleteList.includes(stroke)) {
+ this._deleteList.push(stroke);
+ SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1');
+ SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black');
+ const segments = this.radiusErase(stroke, intersects.sort());
+ segments?.forEach(segment =>
+ this.forceStrokeGesture(
+ e,
+ Gestures.Stroke,
+ segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[])
+ )
+ );
+ }
+ stroke.layoutDoc.opacity = 0;
+ stroke.layoutDoc.dontIntersect = true;
+ });
+ return false;
+ };
forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: any) => {
this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points), text));
@@ -764,7 +728,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// increase radius slightly based on the erased stroke's width, added to make eraser look more realistic
const radius = ActiveEraserWidth() + 5 + inkStrokeWidth * 0.1; // add 5 to prevent eraser from being too small
const c = 0.551915024494; // circle tangent length to side ratio
- const movement = { x: Math.max(endInkCoordsIn.X - startInkCoordsIn.X, 1), y: Math.max(endInkCoordsIn.Y - startInkCoordsIn.Y, 1) };
+ const movement = { x: endInkCoordsIn.X - startInkCoordsIn.X, y: endInkCoordsIn.Y - startInkCoordsIn.Y };
const moveLen = Math.sqrt(movement.x ** 2 + movement.y ** 2);
const direction = { x: (movement.x / moveLen) * radius, y: (movement.y / moveLen) * radius };
const normal = { x: -direction.y, y: direction.x }; // prettier-ignore
@@ -1275,60 +1239,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@action
- showSmartDraw = (e: PointerEvent, doubleTap?: boolean) => {
- SmartDrawHandler.Instance.displaySmartDrawHandler(e.pageX, e.pageY, this.createDrawing, this.removeDrawing);
- };
-
- _drawing: Doc[] = [];
- @undoBatch
- createDrawing = (e: React.PointerEvent<Element>, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => {
- strokeData.forEach((stroke: [InkData, string, string]) => {
- const bounds = InkField.getBounds(stroke[0]);
- const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
- const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale;
- const inkDoc = Docs.Create.InkDocument(
- stroke[0],
- { title: 'stroke',
- x: B.x - inkWidth / 2,
- y: B.y - inkWidth / 2,
- _width: B.width + inkWidth,
- _height: B.height + inkWidth,
- stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
- inkWidth,
- stroke[1],
- undefined,
- stroke[2] === 'none' ? undefined : stroke[2]
- );
- this._drawing.push(inkDoc);
- this.addDocument(inkDoc);
- });
- const collection = this._marqueeViewRef.current?.collection(undefined, true, this._drawing);
- if (collection) {
- const docData = collection[DocData];
- docData.title = opts.text;
- docData.drawingInput = opts.text;
- docData.drawingComplexity = opts.complexity;
- docData.drawingColored = opts.autoColor;
- docData.drawingSize = opts.size;
- docData.drawingData = gptRes;
- }
- this._batch?.end();
- };
-
- removeDrawing = (doc?: Doc) => {
- this._batch = UndoManager.StartBatch('regenerateDrawing');
- if (doc) {
- const docData: Doc = doc[DocData];
- const children = docData.data as unknown as Doc[];
- this._props.removeDocument?.(doc);
- this._props.removeDocument?.(children);
- } else {
- this._props.removeDocument?.(this._drawing);
- }
- this._drawing = [];
- };
-
- @action
zoom = (pointX: number, pointY: number, deltaY: number): void => {
if (this.Document.isGroup || this.Document[(this._props.viewField ?? '_') + 'freeform_noZoom']) return;
let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05;
@@ -1921,10 +1831,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
onCursorMove = (e: React.PointerEvent) => {
- const locPt = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY);
- this._eraserX = locPt[0];
- this._eraserY = locPt[1];
- // Doc.ActiveTool === InkTool.RadiusEraser ? this._childPointerEvents = 'none' : this._childPointerEvents = 'all'
+ this._eraserX = e.clientX;
+ this._eraserY = e.clientY;
// super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
};
@@ -2031,14 +1939,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}),
icon: 'eye',
});
- optionItems.push({
- description: (this._showDrawingEditor ? 'Close' : 'Show') + ' Drawing Editor',
- event: action(() => {
- this._showDrawingEditor = !this._showDrawingEditor;
- this._showDrawingEditor ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, this.createDrawing, this.removeDrawing) : SmartDrawHandler.Instance.hideRegenerate();
- }),
- icon: 'pen-to-square',
- });
this._props.renderDepth &&
optionItems.push({
description: 'Use Background Color as Default',
@@ -2243,8 +2143,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onPointerMove={this.onCursorMove}
style={{
position: 'fixed',
- left: this._eraserX,
- top: this._eraserY,
+ left: this._eraserX - 60,
+ top: this._eraserY - 100,
width: (ActiveEraserWidth() + 5) * 2,
height: (ActiveEraserWidth() + 5) * 2,
borderRadius: '50%',
diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelHandler.scss b/src/client/views/collections/collectionFreeForm/ImageLabelHandler.scss
index 9b8727e1a..e7413bf8e 100644
--- a/src/client/views/collections/collectionFreeForm/ImageLabelHandler.scss
+++ b/src/client/views/collections/collectionFreeForm/ImageLabelHandler.scss
@@ -42,17 +42,3 @@
}
}
}
-
-.complexity-slider {
- width: 50%; /* Full-width */
- height: 25px; /* Specified height */
- background: #d3d3d3; /* Grey background */
- outline: none; /* Remove outline */
- opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
- -webkit-transition: 0.2s; /* 0.2 seconds transition on hover */
- transition: opacity 0.2s;
-
- :hover {
- opacity: 1; /* Fully shown on mouse-over */
- }
-}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 5aff3ed6f..dc15c83c5 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -36,7 +36,6 @@ import { CollectionFreeFormView } from './CollectionFreeFormView';
import { ImageLabelHandler } from './ImageLabelHandler';
import { MarqueeOptionsMenu } from './MarqueeOptionsMenu';
import './MarqueeView.scss';
-import { collectionOf } from '@turf/turf';
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -375,8 +374,8 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
return doc;
})(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
newCollection.isSystem = undefined;
- newCollection._width = this.Bounds.width || 1; // if width/height are unset/0, then groups won't autoexpand to contain their children
- newCollection._height = this.Bounds.height || 1;
+ newCollection._width = this.Bounds.width;
+ newCollection._height = this.Bounds.height;
newCollection._dragWhenActive = makeGroup;
newCollection.x = this.Bounds.left;
newCollection.y = this.Bounds.top;
@@ -427,7 +426,6 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
this._props.selectDocuments([newCollection]);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- return newCollection;
});
/**