aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-09-27 14:19:40 -0400
committerbobzel <zzzman@gmail.com>2024-09-27 14:19:40 -0400
commit42419cd85b7dc2aec0695f2b29b2f707ae7e36e2 (patch)
tree6afabe7f8f1d602dfe3ca313694b22f4e5b7ed25
parent186442fed4215b2de499cc9943229fd4856cc74b (diff)
fixed linting. cleaned up scribble erase code and fixed several issues with determining if cusp intersections amounted to a scribble. also fixed recognition of lines to not recognize scribbles.
-rw-r--r--eslint.config.mjs2
-rw-r--r--package-lock.json14
-rw-r--r--src/.DS_Storebin14340 -> 10244 bytes
-rw-r--r--src/Utils.ts3
-rw-r--r--src/client/views/GestureOverlay.tsx276
-rw-r--r--src/client/views/InkingStroke.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx24
-rw-r--r--src/fields/InkField.ts20
8 files changed, 137 insertions, 208 deletions
diff --git a/eslint.config.mjs b/eslint.config.mjs
index aebdc20d0..f7063caa5 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -48,7 +48,7 @@ export default [
'no-return-assign': 'error',
'no-await-in-loop': 'error',
'no-loop-func': 'error',
- '@typescript-eslint/no-cond-assign': 'error',
+ 'no-cond-assign': 'error',
'no-use-before-define': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'no-restricted-globals': ['error', 'event'],
diff --git a/package-lock.json b/package-lock.json
index fac1cc20b..727b22f34 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -130,6 +130,7 @@
"https": "^1.0.0",
"https-browserify": "^1.0.0",
"i": "^0.3.7",
+ "iink-ts": "^1.0.5",
"image-data-uri": "^2.0.1",
"image-size": "^1.0.2",
"image-size-stream": "^1.1.0",
@@ -20506,6 +20507,14 @@
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="
},
+ "node_modules/iink-ts": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/iink-ts/-/iink-ts-1.0.5.tgz",
+ "integrity": "sha512-LAWWPvgcsLtouI9ExVijZbPGIWMfJtVCcuznbIDyboaPb+cHYsftcuJdjDU7TQwIpGP4hmcjNQA57XPCw4MK2A==",
+ "dependencies": {
+ "json-css": "^1.5.6"
+ }
+ },
"node_modules/image-data-uri": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/image-data-uri/-/image-data-uri-2.0.1.tgz",
@@ -21989,6 +21998,11 @@
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
},
+ "node_modules/json-css": {
+ "version": "1.5.6",
+ "resolved": "https://registry.npmjs.org/json-css/-/json-css-1.5.6.tgz",
+ "integrity": "sha512-B/0T0OxZH9tSb93tXV6VOYtXqrPz/Vgz2QrCT/4NXen8HGElYkYr9V+8IrSVTMj/ftxa8cG1kcu7f3iAMlaFlQ=="
+ },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
diff --git a/src/.DS_Store b/src/.DS_Store
index 19eea5fce..b91453587 100644
--- a/src/.DS_Store
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/Utils.ts b/src/Utils.ts
index 0590c6930..724725c23 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/no-namespace */
import * as uuid from 'uuid';
export function clamp(n: number, lower: number, upper: number) {
@@ -205,7 +204,6 @@ export function intersectRect(r1: { left: number; top: number; width: number; he
}
export function stringHash(s?: string) {
- // eslint-disable-next-line no-bitwise
return !s ? undefined : Math.abs(s.split('').reduce((a, b) => (n => n & n)((a << 5) - a + b.charCodeAt(0)), 0));
}
@@ -254,6 +252,7 @@ export namespace JSONUtils {
try {
results = JSON.parse(source);
} catch (e) {
+ console.log('JSONparse error: ', e);
results = source;
}
return results;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 1cd6de55c..e9e12fc3b 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -1,10 +1,9 @@
import * as fitCurve from 'fit-curve';
-import { Bezier } from 'bezier-js';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnEmptyFilter, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../ClientUtils';
-import { emptyFunction } from '../../Utils';
+import { emptyFunction, intersectRect } from '../../Utils';
import { Doc, Opt, returnEmptyDoclist } from '../../fields/Doc';
import { InkData, InkField, InkTool } from '../../fields/InkField';
import { NumCast } from '../../fields/Types';
@@ -16,6 +15,7 @@ import { Docs } from '../documents/Documents';
import { InteractionUtils } from '../util/InteractionUtils';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { Transform } from '../util/Transform';
+import { undoable } from '../util/UndoManager';
import './GestureOverlay.scss';
import { InkingStroke } from './InkingStroke';
import { ObservableReactComponent } from './ObservableReactComponent';
@@ -37,7 +37,6 @@ import {
SetActiveInkColor,
SetActiveInkWidth,
} from './nodes/DocumentView';
-import { docs } from 'googleapis/build/src/apis/docs';
export enum ToolglassTools {
InkToText = 'inktotext',
IgnoreGesture = 'ignoregesture',
@@ -53,7 +52,9 @@ interface GestureOverlayProps {
* drew or perform the gesture's action
*/
export class GestureOverlay extends ObservableReactComponent<React.PropsWithChildren<GestureOverlayProps>> {
+ // eslint-disable-next-line no-use-before-define
static Instance: GestureOverlay;
+ // eslint-disable-next-line no-use-before-define
static Instances: GestureOverlay[] = [];
@observable public InkShape: Opt<Gestures> = undefined;
@@ -79,10 +80,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
}
private _overlayRef = React.createRef<HTMLDivElement>();
- private _d1: Doc | undefined;
- private _inkToTextDoc: Doc | undefined;
- private thumbIdentifier?: number;
- private pointerIdentifier?: number;
constructor(props: GestureOverlayProps) {
super(props);
@@ -136,119 +133,67 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
}
}
/**
- * this method returns if what the user drew is a scribble. if it is, it will determine what documents need
- * to be deleted and then it will delete them.
+ * If what the user drew is a scribble, this returns the documents that were scribbled over
* I changed it so it doesnt use triangles. It will modify an intersect array, with its length being
* how many sharp cusps there are. The first index will have a boolean that is based on if there is an
* intersection in the first 1/length percent of the stroke. The second index will be if there is an intersection
- * in the 2nd 1/length percent of the stroke. This array will be used in determineInScribble().
- * @returns
+ * in the 2nd 1/length percent of the stroke. This array will be used in determineIfScribble().
+ * @param ffview freeform view where scribble is drawn
+ * @param scribbleStroke scribble stroke in screen space coordinats
+ * @returns array of documents scribbled over
*/
- isScribble(inkData: InkData) {
- const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView);
- console.log(inkData.map(ink => ({ x: ink.X, y: ink.Y })));
- let intersectArray: boolean[] = [];
- const cuspArray = this.getCusps(inkData);
- console.log(cuspArray.length);
- for (let i = 0; i < cuspArray.length; i++) {
- intersectArray[i] = false;
- }
- const docsToDelete: Doc[] = [];
- let childDocs = (ffView?.ComponentView as CollectionFreeFormView).childDocs.slice(0, -1);
- childDocs.filter(doc => doc.type === 'ink').map(doc => DocumentView.getDocumentView(doc, DocumentView.getDocumentView(doc)));
- if ((ffView?.ComponentView as CollectionFreeFormView).childDocs) {
- for (const doc of childDocs) {
- const otherInk = DocumentView.getDocumentView(doc)?.ComponentView as InkingStroke;
- const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
- const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
- if (this.isRectangleOverlap(this.getExtremeCoordinates(otherScreenPts), this.getExtremeCoordinates(inkData))) {
- const intersects = this.doInksIntersect(inkData, otherScreenPts);
- intersects.forEach(intersect => {
- let percentage = '';
- if (intersect.includes('/')) {
- const leftOfSlash = intersect.split('/')[0];
- percentage = leftOfSlash;
- } else {
- percentage = intersect;
- }
- intersectArray[Math.floor((percentage as unknown as number) * cuspArray.length)] = true;
- const docsInBoundingBox = this.docsInBoundingBox(doc, childDocs);
- childDocs = childDocs.filter(doc => !docsInBoundingBox.includes(doc));
- docsToDelete.push(...docsInBoundingBox);
- docsToDelete.push(doc);
+ isScribble = (ffView: CollectionFreeFormView, cuspArray: { X: number; Y: number }[], scribbleStroke: { X: number; Y: number }[]) => {
+ const intersectArray = cuspArray.map(() => false);
+ const scribbleBounds = InkField.getBounds(scribbleStroke);
+ const docsToDelete = ffView.childDocs
+ .map(doc => DocumentView.getDocumentView(doc))
+ .filter(dv => dv?.ComponentView instanceof InkingStroke)
+ .map(dv => dv?.ComponentView as InkingStroke)
+ .filter(otherInk => {
+ const otherScreenPts = otherInk.inkScaledData?.().inkData.map(otherInk.ptToScreen);
+ if (intersectRect(InkField.getBounds(otherScreenPts), scribbleBounds)) {
+ const intersects = this.findInkIntersections(scribbleStroke, otherScreenPts).map(intersect => {
+ const percentage = intersect.split('/')[0];
+ intersectArray[Math.floor(Number(percentage) * cuspArray.length)] = true;
});
+ return intersects.length > 0;
}
- }
- console.log(intersectArray);
- if (intersectArray.length > 3 && this.determineIfScribble(intersectArray)) {
- const uniqueArray = Array.from(new Set(docsToDelete));
- console.log(uniqueArray.length);
- console.log('is a scribble');
- docsToDelete.forEach(doc => {
- ffView?.ComponentView?.removeDocument?.(doc);
- });
- this._points = [];
- return true;
- }
- }
- return false;
- }
- /**
- * this will return all the docs overlapping with the maindocs bounding box
- * @param mainDoc the bounding box of this doc will be used
- * @param childDocs the array of all docs in collection
- * @returns
- */
- docsInBoundingBox(mainDoc: Doc, childDocs: Doc[]): Doc[] {
- return childDocs.filter(
- doc =>
- typeof doc.x === 'number' &&
- typeof doc.y === 'number' &&
- typeof doc.width === 'number' &&
- typeof doc.height === 'number' &&
- typeof mainDoc.x === 'number' &&
- typeof mainDoc.y === 'number' &&
- typeof mainDoc.width === 'number' &&
- typeof mainDoc.height === 'number' &&
- doc.x < mainDoc.x + mainDoc.width &&
- doc.x + doc.width > mainDoc.x &&
- doc.y < mainDoc.y + mainDoc.height &&
- doc.y + doc.height > mainDoc.y
- );
- }
+ });
+ return !this.determineIfScribble(intersectArray) ? undefined :
+ [ ...docsToDelete.map(stroke => stroke.Document),
+ // bcz: NOTE: docsInBoundingBox test should be replaced with a docsInConvexHull test
+ ...this.docsInBoundingBox({ topLeft : ffView.ScreenToContentsXf().transformPoint(scribbleBounds.left, scribbleBounds.top),
+ bottomRight: ffView.ScreenToContentsXf().transformPoint(scribbleBounds.right,scribbleBounds.bottom)},
+ ffView.childDocs.filter(doc => !docsToDelete.map(s => s.Document).includes(doc)) )]; // prettier-ignore
+ };
/**
- * this method determines if what the user drew is a scribble based on certain criteria.
- * @param cuspBooleanArray will take in an array of booleans tht represent what sections(seperated by a cusp) in the scribble
- * has an object in it.
- * @returns
+ * Returns all docs in array that overlap bounds. Note that the bounds should be given in screen space coordinates.
+ * @param boundingBox screen space bounding box
+ * @param childDocs array of docs to test against bounding box
+ * @returns list of docs that overlap rect
*/
- determineIfScribble(cuspBooleanArray: boolean[]) {
- if (!cuspBooleanArray) {
- return false;
- }
- const quarterArrayLength = Math.ceil((cuspBooleanArray.length - 2) * 0.3);
- let hasObjectInFirstAndLast25 = true;
- for (let i = 0; i < quarterArrayLength; i++) {
- if (cuspBooleanArray[i] == false || cuspBooleanArray[cuspBooleanArray.length - 1 - i] == false) {
- hasObjectInFirstAndLast25 = false;
- }
- }
- const trueCount = cuspBooleanArray.filter(value => value).length;
- const percentageTrues = trueCount / cuspBooleanArray.length;
- return percentageTrues >= 0.5 || hasObjectInFirstAndLast25;
- }
+ docsInBoundingBox = (boundingBox: { topLeft: number[]; bottomRight: number[] }, childDocs: Doc[]): Doc[] => {
+ const rect = { left: boundingBox.topLeft[0], top: boundingBox.topLeft[1], width: boundingBox.bottomRight[0] - boundingBox.topLeft[0], height: boundingBox.bottomRight[1] - boundingBox.topLeft[1] };
+ return childDocs.filter(doc => intersectRect(rect, { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }));
+ };
/**
- * determines if two rectangles are overlapping each other
- * @param rect1 the rectangle object has has a minX,maxX,minY, and maxY
- * @param rect2
+ * Determines if what the array of cusp/intersection data corresponds to a scribble.
+ * true if there are at least 4 cusps and either:
+ * 1) the initial and final quarters of the array contain objects
+ * 2) or half of the cusps contain objects
+ * @param intersectArray array of booleans coresponding to which scribble sections (regions separated by a cusp) contain Docs
* @returns
*/
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- isRectangleOverlap(rect1: any, rect2: any): boolean {
- const noOverlap = rect1.maxX < rect2.minX || rect1.minX > rect2.maxX || rect1.maxY < rect2.minY || rect1.minY > rect2.maxY;
-
- return !noOverlap;
- }
+ determineIfScribble = (intersectArray: boolean[]) => {
+ const quarterArrayLength = Math.ceil(intersectArray.length / 3.9); // use 3.9 instead of 4 to work better with strokes with only 4 cusps
+ const { start, end } = intersectArray.reduce((res, val, i) => ({ // test for scribbles at start and end of scribble stroke
+ start: res.start || (val && i <= quarterArrayLength),
+ end: res.end || (val && i >= intersectArray.length - quarterArrayLength)
+ }), { start: false, end: false }); // prettier-ignore
+
+ const percentCuspsWithContent = intersectArray.filter(value => value).length / intersectArray.length;
+ return intersectArray.length > 3 && (percentCuspsWithContent >= 0.5 || (start && end));
+ };
/**
* determines if inks intersect
* @param line is pointData
@@ -260,32 +205,24 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
* it will return two numbers, one for each curve, seperated by a comma. Sometimes, the percentage it returns is inaccurate,
* espcially in the beginning and end parts of the stroke. dont know why. hope this makes sense
*/
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- doInksIntersect(scribble: InkData, inkStroke: InkData): string[] {
- let intersectArray: string[] = [];
- const extremeScribble = this.getExtremeCoordinates(scribble);
- const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView);
- if (ffView && ffView.ComponentView instanceof CollectionFreeFormView) {
- for (let i = 0; i < scribble.length - 3; i += 4) {
- // iterate over each segment of bezier curve
- for (let j = 0; j < inkStroke.length - 3; j += 4) {
- const scribbleCurve: Bezier = InkField.Segment(scribble, i);
- const strokeCurve: Bezier = InkField.Segment(inkStroke, j);
- const points = strokeCurve.points.map(point => ({
- X: point.x,
- Y: point.y,
- }));
- if (ffView && ffView.ComponentView instanceof CollectionFreeFormView && this.isRectangleOverlap(extremeScribble, this.getExtremeCoordinates(points))) {
- const result = (ffView.ComponentView as CollectionFreeFormView).bintersects(scribbleCurve, strokeCurve)[0];
- if (result !== undefined) {
- intersectArray.push(result.toString());
- }
+ findInkIntersections = (scribble: InkData, inkStroke: InkData): string[] => {
+ const intersectArray: string[] = [];
+ const scribbleBounds = InkField.getBounds(scribble);
+ for (let i = 0; i < scribble.length - 3; i += 4) { // for each segment of scribble
+ for (let j = 0; j < inkStroke.length - 3; j += 4) { // for each segment of ink stroke
+ const scribbleSeg = InkField.Segment(scribble, i);
+ const strokeSeg = InkField.Segment(inkStroke, j);
+ const strokeBounds = InkField.getBounds(strokeSeg.points.map(pt => ({ X: pt.x, Y: pt.y })));
+ if (intersectRect(scribbleBounds, strokeBounds)) {
+ const result = InkField.bintersects(scribbleSeg, strokeSeg)[0];
+ if (result !== undefined) {
+ intersectArray.push(result.toString());
}
}
- }
- }
+ } // prettier-ignore
+ } // prettier-ignore
return intersectArray;
- }
+ };
dryInk = () => {
const newPoints = this._points.reduce((p, pts) => {
p.push([pts.X, pts.Y]);
@@ -309,6 +246,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
};
@action
onPointerUp = () => {
+ const ffView = DocumentView.DownDocView?.ComponentView instanceof CollectionFreeFormView && DocumentView.DownDocView.ComponentView;
DocumentView.DownDocView = undefined;
if (this._points.length > 1) {
const B = this.svgBounds;
@@ -320,31 +258,34 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
? GestureUtils.GestureRecognizer.Recognize([points])
: undefined) ??
new Result(Gestures.Stroke, 1, Date.now); // prettier-ignore
+
+ const cuspArray = this.getCusps(points);
// if any of the shape is activated in the CollectionFreeFormViewChrome
// need to decide when to turn gestures back on
const actionPerformed = ((name: Gestures) => {
switch (name) {
case Gestures.Line:
+ if (cuspArray.length > 2) return undefined;
+ // eslint-disable-next-line no-fallthrough
case Gestures.Triangle:
case Gestures.Rectangle:
case Gestures.Circle:
this.makeBezierPolygon(Name, true);
return this.dispatchGesture(name);
case Gestures.RightAngle:
- return this.convertToText().length > 0;
+ return ffView && this.convertToText(ffView).length > 0;
default:
}
})(Score < 0.7 ? Gestures.Stroke : (Name as Gestures));
// if no gesture (or if the gesture was unsuccessful), "dry" the stroke into an ink document
+
if (!actionPerformed) {
- this.dryInk();
- setTimeout(() => {
- const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView);
- const scribbleInk = (ffView?.ComponentView as CollectionFreeFormView).childDocs[(ffView?.ComponentView as CollectionFreeFormView).childDocs.length - 1];
- if (this.isScribble((DocumentView.getDocumentView(scribbleInk)?.ComponentView as InkingStroke).inkScaledData().inkData)) {
- ffView?.ComponentView?.removeDocument?.(scribbleInk);
- }
- }, 1);
+ const scribbledOver = ffView && this.isScribble(ffView, cuspArray, this._points);
+ if (scribbledOver) {
+ undoable(() => ffView.removeDocument(scribbledOver), 'scribble erase')();
+ } else {
+ this.dryInk();
+ }
}
}
this._points.length = 0;
@@ -353,21 +294,19 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
* used in the rightAngle gesture to convert handwriting into text. will only work on collections
* TODO: make it work on individual ink docs.
*/
- convertToText() {
- const ffView = DocumentView.allViews().find(view => view.ComponentView instanceof CollectionFreeFormView);
+ convertToText = (ffView: CollectionFreeFormView) => {
let minX = 999999999;
let maxX = -999999999;
let minY = 999999999;
let maxY = -999999999;
const textDocs: Doc[] = [];
- (ffView?.ComponentView as CollectionFreeFormView).childDocs
+ ffView.childDocs
.filter(doc => doc.type === DocumentType.COL)
.forEach(doc => {
if (typeof doc.width === 'number' && typeof doc.height === 'number' && typeof doc.x === 'number' && typeof doc.y === 'number') {
const bounds = DocumentView.getDocumentView(doc)?.getBounds;
if (bounds) {
- const rect1 = { minX: bounds.left, maxX: bounds.right, minY: bounds.top, maxY: bounds.bottom };
- if (this.isRectangleOverlap(rect1, this.getExtremeCoordinates(this._points))) {
+ if (intersectRect({ ...bounds, width: bounds.right - bounds.left, height: bounds.bottom - bounds.top }, InkField.getBounds(this._points))) {
if (doc.x < minX) {
minX = doc.x;
}
@@ -383,9 +322,9 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
const newDoc = Docs.Create.TextDocument(doc.transcription as string, { title: '', x: doc.x as number, y: minY });
newDoc.height = doc.height;
newDoc.width = doc.width;
- if (ffView?.ComponentView?.addDocument && ffView?.ComponentView?.removeDocument) {
- ffView.ComponentView.addDocument(newDoc);
- ffView.ComponentView.removeDocument(doc);
+ if (ffView.addDocument && ffView.removeDocument) {
+ ffView.addDocument(newDoc);
+ ffView.removeDocument(doc);
}
textDocs.push(newDoc);
}
@@ -393,10 +332,11 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
}
});
return textDocs;
- }
+ };
/**
- * used to determine how many cusps and where the cusps are in order
- * @returns will return an array containing the coordinates of the sharp cusps
+ * Returns array of coordinates corresponding to the sharp cusps in an input stroke
+ * @param points array of X,Y stroke coordinates
+ * @returns array containing the coordinates of the sharp cusps
*/
getCusps(points: InkData) {
const arrayOfPoints: { X: number; Y: number }[] = [];
@@ -406,6 +346,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
const point2 = points[i + 1];
const point3 = points[i + 2];
if (this.find_angle(point1, point2, point3) < 90) {
+ // NOTE: this is not an accurate way to find cusps -- it is highly dependent on sampling rate and doesn't work well with slowly drawn scribbles
arrayOfPoints.push(point2);
}
}
@@ -413,34 +354,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
return arrayOfPoints;
}
/**
- * will look through an array of point data and return the coordinates of the smallest box that can fit all the points
- * @returns the minX,maxX,minY,maxY of the box
- */
- getExtremeCoordinates(points: { X: number; Y: number }[]) {
- const coordinates = points;
- if (coordinates.length === 0) {
- throw new Error('Coordinates array is empty');
- }
-
- let minX = coordinates[0].X;
- let maxX = coordinates[0].X;
- let minY = coordinates[0].Y;
- let maxY = coordinates[0].Y;
-
- coordinates.forEach(coord => {
- if (coord.X < minX) minX = coord.X;
- if (coord.X > maxX) maxX = coord.X;
- if (coord.Y < minY) minY = coord.Y;
- if (coord.Y > maxY) maxY = coord.Y;
- });
- return {
- minX,
- maxX,
- minY,
- maxY,
- };
- }
- /**
* takes in three points and then determines the angle of the points. used to determine if the cusp
* is sharp enoug
* @returns
@@ -770,6 +683,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
}
ScriptingGlobals.add('GestureOverlay', GestureOverlay);
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setPen(width: string, color: string, fill: string, arrowStart: string, arrowEnd: string, dash: string) {
runInAction(() => {
GestureOverlay.Instance.SavedColor = ActiveInkColor();
@@ -782,6 +696,7 @@ ScriptingGlobals.add(function setPen(width: string, color: string, fill: string,
SetActiveDash(dash);
});
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function resetPen() {
runInAction(() => {
SetActiveInkColor(GestureOverlay.Instance.SavedColor ?? 'rgb(0, 0, 0)');
@@ -789,6 +704,7 @@ ScriptingGlobals.add(function resetPen() {
});
}, 'resets the pen tool');
ScriptingGlobals.add(
+ // eslint-disable-next-line prefer-arrow-callback
function createText(text: string, X: number, Y: number) {
GestureOverlay.Instance.dispatchGesture(Gestures.Text, [{ X, Y }], text);
},
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index f04e3eece..177400882 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -49,7 +49,7 @@ import { PinDocView, PinProps } from './PinFuncs';
import { StyleProp } from './StyleProp';
import { ViewBoxInterface } from './ViewBoxInterface';
-// eslint-disable-next-line @typescript-eslint/no-var-requires
+// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
@observer
@@ -107,10 +107,10 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
* analyzes the ink stroke and saves the analysis of the stroke to the 'inkAnalysis' field,
* and the recognized words to the 'handwriting'
*/
- analyzeStrokes=()=> {
+ analyzeStrokes = () => {
const data: InkData = this.inkScaledData().inkData ?? [];
CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ['inkAnalysis', 'handwriting'], [data]);
- }
+ };
/**
* Toggles whether the ink stroke is displayed as an overlay mask or as a regular stroke.
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3e2c55114..36772e8ec 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -894,7 +894,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
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) {
@@ -1168,26 +1168,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.
@@ -1219,7 +1199,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).
diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts
index 32abf0076..ad524f73f 100644
--- a/src/fields/InkField.ts
+++ b/src/fields/InkField.ts
@@ -102,6 +102,26 @@ export class InkField extends ObjectField {
const top = Math.min(...ys);
return { right, left, bottom, top, width: right - left, height: bottom - top };
}
+
+ // 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
+ public static 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);
+ }
}
ScriptingGlobals.add('InkField', InkField);