aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authoreleanor-park <eleanor_park@brown.edu>2024-10-01 18:45:03 -0400
committereleanor-park <eleanor_park@brown.edu>2024-10-01 18:45:03 -0400
commit5d859cab5fa714860723fa252498c407d5909cdc (patch)
treea8366cbcacdbb18fb24204e8b89187db49a26785 /src/client/views/collections
parent06ab521c759e44a26be58fdf7ffc8d790e551236 (diff)
parent39dc004c0f8e4bcc21ca0c2ecb0b665037f3d1ad (diff)
Merge branch 'eleanor-gptdraw' of https://github.com/brown-dash/Dash-Web into eleanor-gptdraw
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx85
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx37
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx16
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx48
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx20
5 files changed, 113 insertions, 93 deletions
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index d9c27254a..e5a6ebc7f 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -1,4 +1,4 @@
-import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, trace } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
@@ -46,8 +46,9 @@ export class CollectionCardView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [key: string]: IReactionDisposer } = {};
private _textToDoc = new Map<string, Doc>();
+ private _dropped = false; // indicate when a card doc has just moved;
- @observable _forceChildXf = false;
+ @observable _forceChildXf = 0;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
@observable _maxRowCount = 10;
@@ -99,8 +100,7 @@ export class CollectionCardView extends CollectionSubView() {
};
componentDidMount() {
- this.Document.childFilters_boolean = 'OR'; // bcz: really shouldn't be assigning to fields from within didMount -- this should be a default/override beahavior somehow
-
+ this._props.setContentViewBox?.(this);
// Reaction to cardSort changes
this._disposers.sort = reaction(
() => GPTPopup.Instance.visible,
@@ -112,6 +112,17 @@ export class CollectionCardView extends CollectionSubView() {
}
}
);
+ // if card deck moves, then the child doc views are hidden so their screen to local transforms will return empty rectangles
+ // when inquired from the dom (below in childScreenToLocal). When the doc is actually renders, we need to act like the
+ // dash data just changed and trigger a React involidation with the correct data (read from the dom).
+ this._disposers.child = reaction(
+ () => [this.Document.x, this.Document.y],
+ () => {
+ if (!Array.from(this._docRefs.values()).every(dv => dv.ContentDiv?.getBoundingClientRect().width)) {
+ setTimeout(action(() => this._forceChildXf++));
+ }
+ }
+ );
}
componentWillUnmount() {
@@ -176,6 +187,7 @@ export class CollectionCardView extends CollectionSubView() {
inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d));
childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2);
+ childPanelHeight = () => this._props.PanelHeight() * this.fitContentScale;
onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
isChildContentActive = () => !!this.isContentActive();
@@ -267,14 +279,7 @@ export class CollectionCardView extends CollectionSubView() {
@action
onPointerMove = (x: number, y: number) => {
- this._docDraggedIndex = -1;
- if (DragManager.docsBeingDragged.length) {
- const newIndex = this.findCardDropIndex(x, y);
-
- if (newIndex !== this._docDraggedIndex && newIndex != -1) {
- this._docDraggedIndex = newIndex;
- }
- }
+ this._docDraggedIndex = DragManager.docsBeingDragged.length ? this.findCardDropIndex(x, y) : -1;
};
/**
@@ -306,6 +311,7 @@ export class CollectionCardView extends CollectionSubView() {
if (de.complete.docDragData.removeDocument?.(draggedDoc)) {
this.dataDoc[this.fieldKey] = new List<Doc>(sorted);
}
+ this._dropped = true;
}
e.stopPropagation();
return true;
@@ -340,7 +346,8 @@ export class CollectionCardView extends CollectionSubView() {
* @param isDesc
* @returns
*/
- sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ sort = (docsIn: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ const docs = docsIn.slice(); // need make new object list since sort() modifies the incoming list which confuses mobx caching
sortType &&
docs.sort((docA, docB) => {
const [typeA, typeB] = (() => {
@@ -364,21 +371,21 @@ export class CollectionCardView extends CollectionSubView() {
const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0;
return isDesc ? out : -out;
});
- if (dragIndex != -1) {
+ if (dragIndex !== -1) {
const draggedDoc = DragManager.docsBeingDragged[0];
const originalIndex = docs.findIndex(doc => doc === draggedDoc);
originalIndex !== -1 && docs.splice(originalIndex, 1);
- docs.splice(dragIndex, 0, draggedDoc);
+ draggedDoc && docs.splice(dragIndex, 0, draggedDoc);
}
- return [...docs]; // need to spread docs into a new object list since sort() modifies the incoming list which confuses mobx caching
+ return docs;
};
displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => (
<DocumentView
{...this._props}
- ref={action((r: DocumentView) => r?.ContentDiv && this._docRefs.set(doc, r))}
+ ref={action((r: DocumentView) => (!r?.ContentDiv ? this._docRefs.delete(doc) : this._docRefs.set(doc, r)))}
Document={doc}
NativeWidth={returnZero}
NativeHeight={returnZero}
@@ -387,11 +394,12 @@ export class CollectionCardView extends CollectionSubView() {
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
+ containerViewPath={this.childContainerViewPath}
ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot
isContentActive={emptyFunction}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
PanelWidth={this.childPanelWidth}
- PanelHeight={() => this._props.PanelHeight() * this.fitContentScale}
+ PanelHeight={this.childPanelHeight}
dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
showTags={true}
@@ -593,7 +601,10 @@ export class CollectionCardView extends CollectionSubView() {
const isSelected = view?.ComponentView?.isAnyChildContentActive?.() || view?.IsSelected ? true : false;
const childScreenToLocal = () => {
+ // need to explicitly trigger an invalidation since we're reading everything from the Dom
this._forceChildXf;
+ this._props.ScreenToLocalTransform();
+
const dref = this._docRefs.get(doc);
const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
return new Transform(-translateX + (dref?.centeringX || 0) * scale,
@@ -608,25 +619,30 @@ export class CollectionCardView extends CollectionSubView() {
return (rowCenterIndex - indexInRow) * 100 - 50;
};
const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
- const vscale = Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale) / (aspect * this.childPanelWidth()),
- (this._props.PanelHeight() - 80) / (aspect * (this._props.PanelWidth() / 10))); // prettier-ignore
+ const vscale = Math.max(1,Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale) / (aspect * this.childPanelWidth()),
+ (this._props.PanelHeight() - 80) / (aspect * (this._props.PanelWidth() / 10)))); // prettier-ignore
const hscale = Math.min(this.sortedDocs.length, this._maxRowCount) / 2; // bcz: hack - the grid is divided evenly into maxRowCount cells, so the max scaling would be maxRowCount -- but making things that wide is ugly, so cap it off at half the window size
return (
<div
key={doc[Id]}
className={`card-item${isSelected ? '-active' : anySelected ? '-inactive' : ''}`}
- onPointerUp={() => {
- if (DocumentView.SelectedDocs().includes(doc)) return;
- // this turns off documentDecorations during a transition, then turns them back on afterward.
- SnappingManager.SetIsResizing(doc[Id]);
- setTimeout(
- action(() => {
- SnappingManager.SetIsResizing(undefined);
- this._forceChildXf = !this._forceChildXf;
- }),
- 900
- );
- }}
+ onPointerUp={action(() => {
+ // if a card doc has just moved, or a card is selected and in front, then ignore this event
+ if (DocumentView.SelectedDocs().includes(doc) || this._dropped) {
+ this._dropped = false;
+ } else {
+ // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
+ // Turn them back on when the animation has completed and the render and backend structures are in synch
+ SnappingManager.SetIsResizing(doc[Id]);
+ setTimeout(
+ action(() => {
+ SnappingManager.SetIsResizing(undefined);
+ this._forceChildXf++;
+ }),
+ 600
+ );
+ }
+ })}
style={{
width: this.childPanelWidth(),
height: 'max-content',
@@ -635,7 +651,7 @@ export class CollectionCardView extends CollectionSubView() {
rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg)
scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`,
}} // prettier-ignore
- onMouseEnter={() => this.setHoveredNodeIndex(index)}>
+ onPointerEnter={() => !SnappingManager.IsDragging && this.setHoveredNodeIndex(index)}>
{this.displayDoc(doc, childScreenToLocal)}
</div>
);
@@ -649,7 +665,8 @@ export class CollectionCardView extends CollectionSubView() {
<div
className="collectionCardView-outer"
ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)}
- onPointerMove={e => this.onPointerMove(e.clientX, e.clientY)}
+ onPointerLeave={action(() => (this._docDraggedIndex = -1))}
+ onPointerMove={e => this.onPointerMove(...this._props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY))}
onDrop={this.onExternalDrop.bind(this)}
style={{
background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string,
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 4951590dc..c5da8e037 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -14,7 +14,9 @@ import { DocumentView } from '../nodes/DocumentView';
import { FocusViewOptions } from '../nodes/FocusViewOptions';
import './CollectionCarousel3DView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { Transform } from '../../util/Transform';
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss');
@observer
@@ -45,15 +47,32 @@ export class CollectionCarousel3DView extends CollectionSubView() {
}
centerScale = Number(CAROUSEL3D_CENTER_SCALE);
+ sideScale = Number(CAROUSEL3D_SIDE_SCALE);
panelWidth = () => this._props.PanelWidth() / 3;
- panelHeight = () => this._props.PanelHeight() * Number(CAROUSEL3D_SIDE_SCALE);
+ panelHeight = () => this._props.PanelHeight() * this.sideScale;
onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
isChildContentActive = () => !!this.isContentActive();
- childScreenToLocal = () =>
- this._props // document's left is the panel shifted by the doc's index * panelWidth/#docs. But it scales by centerScale around its center, so it's left moves left by the distance of the left from the center (panelwidth/2) * the scale delta (centerScale-1)
- .ScreenToLocalTransform() // the top behaves the same way ecept it's shifted by the 'top' amount specified for the panel in css and then by the scale factor.
- .translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2)
+ childScreenLeftToLocal = () =>
+ this._props
+ .ScreenToLocalTransform()
+ .scale(this._props.NativeDimScaling?.() || 1)
+ .translate(-(this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight())
+ .scale(1 / this.sideScale);
+ childScreenRightToLocal = () =>
+ this._props
+ .ScreenToLocalTransform()
+ .scale(this._props.NativeDimScaling?.() || 1)
+ .translate(-2 * this.panelWidth() - (this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight())
+ .scale(1 / this.sideScale);
+ childCenterScreenToLocal = () =>
+ this._props
+ .ScreenToLocalTransform()
+ .scale(this._props.NativeDimScaling?.() || 1)
+ .translate(
+ -this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, // Focused Doc is shifted right by 1/3 panel width then left by increased size percent of center * 1/2 * panel width / 3
+ -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2
+ ) // top is top margin % of panelHeight - increased size percent of center * panelHeight / 2
.scale(1 / this.centerScale);
focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => {
@@ -65,11 +84,11 @@ export class CollectionCarousel3DView extends CollectionSubView() {
index !== -1 && (this.layoutDoc._carousel_index = index);
return undefined;
};
+
@computed get content() {
const currentIndex = NumCast(this.layoutDoc._carousel_index);
- const displayDoc = (childPair: { layout: Doc; data: Doc }) => (
+ const displayDoc = (childPair: { layout: Doc; data: Doc }, dxf: () => Transform) => (
<DocumentView
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
Document={childPair.layout}
TemplateDataDocument={childPair.data}
@@ -83,7 +102,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
focus={this.focus}
- ScreenToLocalTransform={this.childScreenToLocal}
+ ScreenToLocalTransform={dxf}
isContentActive={this.isChildContentActive}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
PanelWidth={this.panelWidth}
@@ -93,7 +112,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
return this.carouselItems.map((childPair, index) => (
<div key={childPair.layout[Id]} className={`collectionCarousel3DView-item${index === currentIndex ? '-active' : ''} ${index}`} style={{ width: this.panelWidth() }}>
- {displayDoc(childPair)}
+ {displayDoc(childPair, index < currentIndex ? this.childScreenLeftToLocal : index === currentIndex ? this.childCenterScreenToLocal : this.childScreenRightToLocal)}
</div>
));
}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 9741c45fe..74cf580c9 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -3,8 +3,8 @@ import { IReactionDisposer, action, computed, makeObservable, observable, reacti
import { observer } from 'mobx-react';
import * as React from 'react';
import { StopEvent, returnOne, returnZero } from '../../../ClientUtils';
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
-import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { Doc, Opt } from '../../../fields/Doc';
+import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { ContextMenu } from '../ContextMenu';
@@ -71,7 +71,7 @@ export class CollectionCarouselView extends CollectionSubView() {
@computed get marginX() { return NumCast(this.layoutDoc.caption_xMargin, 50); } // prettier-ignore
@computed get carouselIndex() { return NumCast(this.layoutDoc._carousel_index) % this.carouselItems.length; } // prettier-ignore
@computed get carouselItems() {
- return DocListCast(this.childDocList)
+ return this.childDocs
.filter(doc => doc.type !== DocumentType.LINK)
.filter(doc => {
switch (StrCast(this.layoutDoc.filterOp)) {
@@ -144,7 +144,6 @@ export class CollectionCarouselView extends CollectionSubView() {
revealItems.push({description: 'Quiz Cards', event: () => {this.layoutDoc.filterOp = cardMode.QUIZ;}, icon: 'pencil',}); // prettier-ignore
!revealOptions && cm.addItem({ description: 'Filter Flashcards', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' });
};
- childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this._props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null));
isChildContentActive = () =>
this._props.isContentActive?.() === false
@@ -155,6 +154,8 @@ export class CollectionCarouselView extends CollectionSubView() {
? false
: undefined;
+ childScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1);
+
renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => {
return (
<DocumentView
@@ -163,9 +164,11 @@ export class CollectionCarouselView extends CollectionSubView() {
Document={doc}
NativeWidth={returnZero}
NativeHeight={returnZero}
- fitWidth={undefined}
+ fitWidth={this._props.childLayoutFitWidth}
+ showTags={true}
containerViewPath={this.childContainerViewPath}
setContentViewBox={undefined}
+ ScreenToLocalTransform={this.childScreenToLocalXf}
onDoubleClickScript={this.onContentDoubleClick}
onClickScript={this.onContentClick}
isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
@@ -245,9 +248,6 @@ export class CollectionCarouselView extends CollectionSubView() {
<div key="fwd" className="carouselView-fwd" onClick={this.advance}>
<FontAwesomeIcon icon="chevron-right" size="2x" />
</div>
- <div key="star" className="carouselView-star" onClick={this.star}>
- <FontAwesomeIcon icon="star" color={TagItem.docHasTag(this.carouselItems?.[this.carouselIndex], this.starField) ? 'yellow' : 'gray'} size="1x" />
- </div>
<div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)} style={{ visibility: this.layoutDoc.filterOp === cardMode.PRACTICE ? 'visible' : 'hidden' }}>
<FontAwesomeIcon icon="xmark" color="red" size="1x" />
</div>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ccce2662a..0cc63d632 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -510,12 +510,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
e.stopPropagation();
break;
case InkTool.SmartDraw:
- setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, e => this.showSmartDraw(e.pageX, e.pageY), hit !== -1);
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, () => this.showSmartDraw(e.pageX, e.pageY), hit !== -1);
e.stopPropagation();
+ break;
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);
+ const ahit = this._clusters.handlePointerDown(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY));
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, ahit !== -1, false);
}
break;
default:
@@ -655,13 +656,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@action
- onEraserClick = (e: PointerEvent, doubleTap?: boolean) => {
+ onEraserClick = (e: PointerEvent) => {
e.preventDefault();
e.stopImmediatePropagation();
this.erase(e, [0, 0]);
};
- forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: any) => {
+ forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: string) => {
this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points), text));
};
@@ -857,13 +858,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
strokeToTVals.set(inkView, [Math.floor(inkData.length / 4) + 1]);
}
}
-
for (let i = 0; i < inkData.length - 3; i += 4) {
// iterate over each segment of bezier curve
for (let j = 0; j < eraserInkData.length - 3; j += 4) {
const intersectCurve: Bezier = InkField.Segment(inkData, i); // other curve
const eraserCurve: Bezier = InkField.Segment(eraserInkData, j); // eraser curve
- this.bintersects(intersectCurve, eraserCurve).forEach((val: string | number, k: number) => {
+ InkField.bintersects(intersectCurve, eraserCurve).forEach((val: string | number, k: number) => {
// Converting the Bezier.js Split type to a t-value number.
const t = +val.toString().split('/')[0];
if (k % 2 === 0) {
@@ -1137,26 +1137,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return this.getClosestTs(tVals, excludeT, startIndex, mid - 1);
};
- // for some reason bezier.js doesn't handle the case of intersecting a linear curve, so we wrap the intersection
- // call in a test for linearity
- bintersects = (curve: Bezier, otherCurve: Bezier) => {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- if ((curve as any)._linear) {
- // bezier.js doesn't intersect properly if the curve is actually a line -- so get intersect other curve against this line, then figure out the t coordinates of the intersection on this line
- const intersections = otherCurve.lineIntersects({ p1: curve.points[0], p2: curve.points[3] });
- if (intersections.length) {
- const intPt = otherCurve.get(intersections[0]);
- const intT = curve.project(intPt).t;
- return intT ? [intT] : [];
- }
- }
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- if ((otherCurve as any)._linear) {
- return curve.lineIntersects({ p1: otherCurve.points[0], p2: otherCurve.points[3] });
- }
- return curve.intersects(otherCurve);
- };
-
/**
* Determines all possible intersections of the current curve of the intersected ink stroke with all other curves of all
* ink strokes in the current collection.
@@ -1188,7 +1168,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (apt.d !== undefined && apt.d < 1 && apt.t !== undefined && !tVals.includes(apt.t)) {
tVals.push(apt.t);
}
- this.bintersects(curve, otherCurve).forEach((val: string | number, ival: number) => {
+ InkField.bintersects(curve, otherCurve).forEach((val: string | number, ival: number) => {
// Converting the Bezier.js Split type to a t-value number.
const t = +val.toString().split('/')[0];
if (ival % 2 === 0 && !tVals.includes(t)) tVals.push(t); // bcz: Hack! don't know why but intersection points are doubled from bezier.js (but not identical).
@@ -1267,9 +1247,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
this._drawing.push(inkDoc);
});
- const collection = MarqueeView.getCollection(this._drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
- console.log('is error here');
- return collection;
+ return MarqueeView.getCollection(this._drawing, undefined, true, { left: opts.x, top: opts.y, width: 1, height: 1 });
};
/**
@@ -2033,6 +2011,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!options && ContextMenu.Instance.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
const mores = ContextMenu.Instance.findByDescription('More...');
const moreItems = mores?.subitems ?? [];
+ moreItems.push({
+ description: 'recognize all ink',
+ event: () => {
+ this.unprocessedDocs.push(...this.childDocs.filter(doc => doc.type === DocumentType.INK));
+ CollectionFreeFormView.collectionsWithUnprocessedInk.add(this);
+ },
+ icon: 'pen',
+ });
!mores && ContextMenu.Instance.addItem({ description: 'More...', subitems: moreItems, icon: 'eye' });
};
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index f1dba58ce..b1f6815b3 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -57,6 +57,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
return { left: NumCast(pinDoc._freeform_panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._freeform_panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps };
}
+ // eslint-disable-next-line no-use-before-define
static Instance: MarqueeView;
constructor(props: SubCollectionViewProps & MarqueeViewProps) {
@@ -457,20 +458,19 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
let x_offset = 0;
let y_offset = 0;
let row_count = 0;
+ const newColDim = 900;
for (const label of labelGroups) {
- const newCollection = MarqueeView.getCollection([], undefined, false, { top: 1, left: 1, width: 1, height: 1 });
- newCollection._width = 900;
- newCollection._height = 900;
- newCollection._x = this.Bounds.left;
- newCollection._y = this.Bounds.top;
+ const newCollection = MarqueeView.getCollection([], undefined, false, this.Bounds);
+ newCollection._x = this.Bounds.left + x_offset;
+ newCollection._y = this.Bounds.top + y_offset;
+ newCollection._width = newColDim;
+ newCollection._height = newColDim;
newCollection._freeform_panX = this.Bounds.left + this.Bounds.width / 2;
newCollection._freeform_panY = this.Bounds.top + this.Bounds.height / 2;
- newCollection._x = (newCollection._x as number) + x_offset;
- newCollection._y = (newCollection._y as number) + y_offset;
- x_offset += (newCollection._width as number) + 40;
+ x_offset += newColDim + 40;
row_count += 1;
if (row_count == 3) {
- y_offset += (newCollection._height as number) + 40;
+ y_offset += newColDim + 40;
x_offset = 0;
row_count = 0;
}
@@ -549,7 +549,6 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
};
touchesLine(r1: { left: number; top: number; width: number; height: number }) {
- // eslint-disable-next-line no-restricted-syntax
for (const lassoPt of this._lassoPts) {
const topLeft = this.Transform.transformPoint(lassoPt[0], lassoPt[1]);
if (r1.left < topLeft[0] && topLeft[0] < r1.left + r1.width && r1.top < topLeft[1] && topLeft[1] < r1.top + r1.height) {
@@ -570,7 +569,6 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
let hasLeft = false;
let hasBottom = false;
let hasRight = false;
- // eslint-disable-next-line no-restricted-syntax
for (const lassoPt of this._lassoPts) {
const truePoint = this.Transform.transformPoint(lassoPt[0], lassoPt[1]);
hasLeft = hasLeft || (truePoint[0] > tl[0] && truePoint[0] < r1.left && truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);