diff options
author | bobzel <zzzman@gmail.com> | 2024-09-27 14:19:40 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-09-27 14:19:40 -0400 |
commit | 42419cd85b7dc2aec0695f2b29b2f707ae7e36e2 (patch) | |
tree | 6afabe7f8f1d602dfe3ca313694b22f4e5b7ed25 | |
parent | 186442fed4215b2de499cc9943229fd4856cc74b (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.mjs | 2 | ||||
-rw-r--r-- | package-lock.json | 14 | ||||
-rw-r--r-- | src/.DS_Store | bin | 14340 -> 10244 bytes | |||
-rw-r--r-- | src/Utils.ts | 3 | ||||
-rw-r--r-- | src/client/views/GestureOverlay.tsx | 276 | ||||
-rw-r--r-- | src/client/views/InkingStroke.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 24 | ||||
-rw-r--r-- | src/fields/InkField.ts | 20 |
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 Binary files differindex 19eea5fce..b91453587 100644 --- a/src/.DS_Store +++ b/src/.DS_Store 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); |