aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/util/CurrentUserUtils.ts7
-rw-r--r--src/client/views/InkingStroke.tsx110
-rw-r--r--src/client/views/MainView.tsx3
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx167
-rw-r--r--src/client/views/global/globalScripts.ts19
6 files changed, 226 insertions, 84 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b160379df..61a58caaa 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -26,7 +26,7 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { UndoManager, undoable } from '../util/UndoManager';
import { ContextMenu } from '../views/ContextMenu';
import { ContextMenuProps } from '../views/ContextMenuItem';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveEraserWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
import { CollectionDockingView } from '../views/collections/CollectionDockingView';
import { CollectionView } from '../views/collections/CollectionView';
import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView';
@@ -1123,6 +1123,7 @@ export namespace Docs {
points: PointData[],
options: DocumentOptions = {},
strokeWidth = ActiveInkWidth(),
+ eraserWidth = ActiveEraserWidth(),
color = ActiveInkColor(),
stroke_bezier = ActiveInkBezierApprox(),
fillColor = ActiveFillColor(),
@@ -1138,6 +1139,7 @@ export namespace Docs {
I.fillColor = fillColor;
I.stroke = new InkField(points);
I.stroke_width = strokeWidth;
+ I.eraser_width = eraserWidth;
I.stroke_bezier = stroke_bezier;
I.stroke_startMarker = arrowStart;
I.stroke_endMarker = arrowEnd;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 031b79b25..59fc30635 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -34,6 +34,7 @@ import { SnappingManager } from "./SnappingManager";
import { UndoManager } from "./UndoManager";
import { LabelBox } from "../views/nodes/LabelBox";
import { ImageBox } from "../views/nodes/ImageBox";
+import { PiEraser } from "react-icons/pi";
interface Button {
// DocumentOptions fields a button can set
@@ -756,9 +757,8 @@ pie title Minerals in my tap water
{ title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.MultiToggleButton, toolType:"eraser", scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'},
subMenu: [
{ title: "Stroke", toolTip: "Stroke Erase", btnType: ButtonType.ToggleButton, icon: "eraser", toolType:"strokeeraser", ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} },
- { title: "Segment", toolTip: "Segment Erase", btnType: ButtonType.ToggleButton, icon: "minus", toolType:"segmenteraser",ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} },
- { title: "Radius", toolTip: "Radius Erase", btnType: ButtonType.ToggleButton, icon: "circle", toolType:"radiuseraser", ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} },
- // { title: "Width", toolTip: "Eraser Width", btnType: ButtonType.NumberSliderButton, toolType:"strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1},
+ { title: "Segment", toolTip: "Segment Erase", btnType: ButtonType.ToggleButton, icon: "xmarks-lines", toolType:"segmenteraser",ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} },
+ { title: "Radius", toolTip: "Radius Erase", btnType: ButtonType.ToggleButton, icon: "circle-xmark", toolType:"radiuseraser", ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'} },
]},
{ title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
{ title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
@@ -766,6 +766,7 @@ pie title Minerals in my tap water
{ title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } },
{ title: "Labels", toolTip: "Lab els", btnType: ButtonType.ToggleButton, icon: "text-width", toolType: "labels", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, },
{ title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1},
+ { title: "Eraser Width", toolTip: "Eraser Width", btnType: ButtonType.NumberSliderButton, toolType: "eraserWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1},
{ title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'} },
];
}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 1c24a4903..1ae96edfd 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -45,6 +45,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { PinProps, PresBox } from './nodes/trails';
import { StyleProp } from './StyleProvider';
const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
+
@observer
export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big)
@@ -330,31 +331,86 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
};
- splitByEraser = (inkCoords: {X: number; Y: number}, radius: number) => {
- // const ptsXscale = (NumCast(radius) - NumCast(radius)) / (oldXrange.max - oldXrange.min || 1) || 1;
- // const ptsYscale = (NumCast(doc._height) - NumCast(doc.stroke_width)) / (oldYrange.max - oldYrange.min || 1) || 1;
- // const newPoints = func(this.DocumentView?.(), ink, ptsXscale, ptsYscale, NumCast(radius));
- const controlPointDistance = 0.552284749831 * radius; // (4/3) * tan(pi / 8) * radius
- const points: { X: number; Y: number }[] = [
- { X: inkCoords.X + radius, Y: inkCoords.Y }, // right point
- { X: inkCoords.X + radius, Y: inkCoords.Y - controlPointDistance }, // right's top ctrl point
- { X: inkCoords.X + controlPointDistance, Y: inkCoords.Y - radius }, // top's right ctrl point
- { X: inkCoords.X, Y: inkCoords.Y - radius }, // top
- { X: inkCoords.X, Y: inkCoords.Y - radius }, // top again
- { X: inkCoords.X - controlPointDistance, Y: inkCoords.Y - radius }, // top's left ctrl point
- { X: inkCoords.X - radius, Y: inkCoords.Y - controlPointDistance }, // left's top ctrl point
- { X: inkCoords.X - radius, Y: inkCoords.Y }, // left
- { X: inkCoords.X - radius, Y: inkCoords.Y }, // left again
- { X: inkCoords.X - radius, Y: inkCoords.Y + controlPointDistance }, // left's bottom ctrl point
- { X: inkCoords.X - controlPointDistance, Y: inkCoords.Y + radius }, // bottom's left ctrl point
- { X: inkCoords.X, Y: inkCoords.Y + radius }, // bottom
- { X: inkCoords.X, Y: inkCoords.Y + radius }, // bottom again
- { X: inkCoords.X + controlPointDistance, Y: inkCoords.Y + radius }, // bottom's right ctrl point
- { X: inkCoords.X + radius, Y: inkCoords.Y + controlPointDistance }, // right's bottom ctrl point
- { X: inkCoords.X + radius, Y: inkCoords.Y }, // right again
- ];
+ coordWithSlope = (distance: number, slope: number) => {
+ return Math.sqrt((distance * distance) / (1 + slope * slope))
+ }
+
+
+ splitByEraser = (startInkCoords: {X: number; Y: number}, inkCoords: {X: number; Y: number}) => {
+
+ const radius = ActiveEraserWidth() / 2 + 3; // reduce values to avoid extreme radii
+ console.log("radius", radius);
+ const ctrlPtDist = 0.552284749831 * radius; // (4/3) * tan(pi / 8) * radius
+
+ var perpSlope = (inkCoords.Y - startInkCoords.Y) / (inkCoords.X - startInkCoords.X);
+ if (perpSlope > 500) {
+ perpSlope = 500; // avoid ridiculously high/infinity slopes
+ } else if (perpSlope < -500) {
+ perpSlope = -500
+ } else if (perpSlope === 0) {
+ perpSlope = 0.002
+ }
+ const slope = - 1 / perpSlope
+ console.log("slope", slope);
+ var points: { X: number; Y: number }[] = []
+ if (startInkCoords.X > inkCoords.X) {
+ points = [
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ // { X: startInkCoords.X + this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y + slope * this.coordWithSlope(ctrlPtDist, slope)},
+
+ { X: inkCoords.X + this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+
+ // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) + this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) },
+ // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) - this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+
+ { X: inkCoords.X - this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+
+ // { X: startInkCoords.X - this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y - slope * this.coordWithSlope(ctrlPtDist, slope) },
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ ];
+ } else {
+ points = [
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ // { X: startInkCoords.X + this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y + slope * this.coordWithSlope(ctrlPtDist, slope)},
+
+ { X: inkCoords.X + this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, slope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y + slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+
+ // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) + this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) },
+ { X: inkCoords.X + this.coordWithSlope(radius, perpSlope), Y: inkCoords.Y + perpSlope * this.coordWithSlope(radius, perpSlope) },
+ // { X: inkCoords.X - this.coordWithSlope(radius, perpSlope) - this.coordWithSlope(ctrlPtDist, slope), Y: inkCoords.Y - perpSlope * this.coordWithSlope(radius, perpSlope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+
+ { X: inkCoords.X - this.coordWithSlope(radius, slope) + this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) + perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, slope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) },
+ { X: inkCoords.X - this.coordWithSlope(radius, slope) - this.coordWithSlope(ctrlPtDist, perpSlope), Y: inkCoords.Y - slope * this.coordWithSlope(radius, slope) - perpSlope * this.coordWithSlope(ctrlPtDist, perpSlope) },
+
+ // { X: startInkCoords.X - this.coordWithSlope(ctrlPtDist, slope), Y: startInkCoords.Y - slope * this.coordWithSlope(ctrlPtDist, slope) },
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ { X: startInkCoords.X, Y: startInkCoords.Y },
+ ];
+ }
+
const eraserCircle = new InkField(points);
- return points;
+ return eraserCircle;
}
_subContentView: ViewBoxInterface | undefined;
@@ -533,6 +589,9 @@ export function SetActiveArrowScale(value: number) {
export function SetActiveDash(dash: string): void {
!isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
}
+export function SetEraserWidth(radius: string): void {
+ !isNaN(parseInt(radius)) && ActiveInkPen() && (ActiveInkPen().eraserWidth = radius);
+}
export function ActiveInkPen(): Doc {
return Doc.UserDoc();
}
@@ -566,3 +625,6 @@ export function ActiveInkWidth(): number {
export function ActiveInkBezierApprox(): string {
return StrCast(ActiveInkPen()?.activeInkBezier);
}
+export function ActiveEraserWidth(): number {
+ return Number(ActiveInkPen()?.eraserWidth);
+} \ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 58b8d255a..56db0c488 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -358,6 +358,9 @@ export class MainView extends ObservableReactComponent<{}> {
fa.faCut,
fa.faEllipsisV,
fa.faEraser,
+ fa.faDeleteLeft,
+ fa.faXmarksLines,
+ fa.faCircleXmark,
fa.faExclamation,
fa.faFileAlt,
fa.faFileAudio,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 60f7662ff..78dae87c3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -749,10 +749,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const segments =
Doc.ActiveTool === InkTool.SegmentEraser
? 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
- : this.radiusErase(intersect.inkView, intersect.t, currPoint);
- // } else if (Doc.ActiveTool === InkTool.RadiusEraser) {
- // segments = undefined;
- // }
+ : this.radiusErase(intersect.inkView, { X: down[0], Y: down[1] }, currPoint);
segments?.forEach(segment =>
this.forceStrokeGesture(
e,
@@ -763,7 +760,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
setTimeout(() => this._eraserLock--);
}
// Lower ink opacity to give the user a visual indicator of deletion.
- intersect.inkView.layoutDoc.opacity = 0.0;
+ intersect.inkView.layoutDoc.opacity = 0.2;
intersect.inkView.layoutDoc.dontIntersect = true;
}
});
@@ -831,63 +828,86 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@action
- radiusErase = (ink: DocumentView, eraseT: number, screenEraserPt: { X: number; Y: number }): Segment[] => {
+ radiusErase = (ink: DocumentView, startPt: { X: number; Y: number }, screenEraserPt: { X: number; Y: number }): Segment[] => {
const segments: Segment[] = [];
+ const startInkCoords = ink.ComponentView?.ptFromScreen?.(startPt);
const inkCoords = ink.ComponentView?.ptFromScreen?.(screenEraserPt); // coordinates in ink space
if (!inkCoords) return [];
- var segment1: Segment = [];
- var segment2: Segment = [];
- const eraseRadius = ActiveInkWidth() / 2;
+ var eraseSegment: Segment = []; // for eraser visualization
const inkStroke = ink?.ComponentView as InkingStroke;
- const { inkData } = inkStroke.inkScaledData();
-
- const eraserInkData = inkStroke.splitByEraser(inkCoords, eraseRadius);
- const tVals: number[] = []; // should be the tvals of the intersections
+ const eraserStroke: InkData = inkStroke.splitByEraser(startInkCoords, inkCoords).inkData;
+ const strokeToTVals: Map<InkingStroke, number[]> = new Map<InkingStroke, number[]>();
+ for (var i = 0; i < eraserStroke.length - 3; i +=4) {
+ eraseSegment.push(InkField.Segment(eraserStroke, i)); // for eraser visualization
+ this.getOtherInkIntersections(i, eraserStroke, strokeToTVals);
+ }
+ strokeToTVals.forEach((tVals, inkStroke) => {
+ var segment1: Segment = [];
+ var segment2: Segment = [];
+ const { inkData } = inkStroke.inkScaledData();
+ tVals.sort();
+ console.log('TVALS', inkStroke, tVals);
- for (var i = 0; i < eraserInkData.length - 3; i += 4) {
- const eraserBezier: Bezier = InkField.Segment(eraserInkData, i);
- segment1.push(eraserBezier);
- for (var j = 0; j < inkData.length; j += 4) {
- const inkSegment: Bezier = InkField.Segment(inkData, i);
- // this.bintersects(inkSegment, eraserBezier).forEach((val: string | number, i: number) => {
- // // Converting the Bezier.js Split type to a t-value number.
- // const t = +val.toString().split('/')[0];
- // if (i % 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).
- // });
+ var hasSplit = false;
+ var continueErasing = false;
+
+ // below is curve splitting logic
+ if (tVals.length) {
+ for (var i = 0; i < inkData.length - 3; i += 4) {
+ const inkSegment: Bezier = InkField.Segment(inkData, i);
+ const currCurveT = Math.floor(i / 4);
+
+ if (tVals.length === 2) {
+ if (tVals[0] > currCurveT && tVals[0] < currCurveT + 1) {
+ segment1.push(inkSegment.split(0, tVals[0] - currCurveT));
+ continueErasing = true;
+ if (tVals[1] > currCurveT && tVals[1] < currCurveT + 1) {
+ segment2.push(inkSegment.split(tVals[1] - currCurveT, 1));
+ continueErasing = false;
+ hasSplit = true;
+ }
+ } else if (tVals[1] > currCurveT && tVals[1] < currCurveT + 1) {
+ segment2.push(inkSegment.split(tVals[1] - currCurveT, 1));
+ continueErasing = false;
+ hasSplit = true;
+ } else if (!continueErasing) {
+ if (hasSplit) {
+ segment2.push(inkSegment);
+ } else {
+ segment1.push(inkSegment);
+ }
+ }
+ } else if (tVals.length === 1) {
+ if (tVals[0] > currCurveT && tVals[0] < currCurveT + 1) {
+ if (tVals[0] < Math.floor(inkData.length / 4) - tVals[0]) {
+ // if it's on the first end
+ segment1.push(inkSegment.split(tVals[0] - currCurveT, 1));
+ hasSplit = true;
+ } else {
+ segment1.push(inkSegment.split(0, tVals[0] - currCurveT));
+ hasSplit = true;
+ }
+ } else {
+ if (tVals[0] < Math.floor(inkData.length / 4) - tVals[0] && hasSplit) {
+ segment1.push(inkSegment);
+ } else if (tVals[0] >= Math.floor(inkData.length / 4) - tVals[0] && !hasSplit) {
+ segment1.push(inkSegment);
+ }
+ }
+ }
+ }
}
- }
- // segment1.push(eraserBezier);
-
- // for (var i = 0; i < inkData.length - 3; i += 4) {
- // const currCurveT = Math.floor(i/4);
- // const inkSegment: Bezier = InkField.Segment(inkData, i);
- // if (tVals[0] >= currCurveT && tVals[0] < currCurveT+1) {
- // tVals.shift()
- // i -= 4;
- // if (eraseT - eraseWidth > currCurveT && eraseT + eraseWidth < currCurveT + 1) {
- // segment1.push(inkSegment.split(0, eraseT - currCurveT - eraseWidth));
- // segment2.push(inkSegment.split(eraseT - currCurveT + eraseWidth, 1));
- // } else if (eraseT - eraseWidth < currCurveT) {
- // segment2.push(inkSegment.split(eraseT - currCurveT + eraseWidth, 1));
- // } else if (eraseT + eraseWidth > currCurveT + 1) {
- // segment1.push(inkSegment.split(0, eraseT - currCurveT - eraseWidth));
- // }
- // } else if (eraseT > currCurveT + 1) {
- // segment1.push(inkSegment);
- // } else {
- // segment2.push(inkSegment);
- // }
- // }
+ if (segment1.length && (Math.abs(segment1[0].points[0].x - segment1[0].points.lastElement().x) > 0.5 || Math.abs(segment1[0].points[0].y - segment1[0].points.lastElement().y) > 0.5)) {
+ segments.push(segment1);
+ }
+ if (segment2.length && (Math.abs(segment2[0].points[0].x - segment2[0].points.lastElement().x) > 0.5 || Math.abs(segment2[0].points[0].y - segment2[0].points.lastElement().y) > 0.5)) {
+ segments.push(segment2);
+ }
+ });
- // push 1 or both segments if they are not empty
- if (segment1.length && (Math.abs(segment1[0].points[0].x - segment1[0].points.lastElement().x) > 0.5 || Math.abs(segment1[0].points[0].y - segment1[0].points.lastElement().y) > 0.5)) {
- segments.push(segment1);
- }
- if (segment2.length && (Math.abs(segment2[0].points[0].x - segment2[0].points.lastElement().x) > 0.5 || Math.abs(segment2[0].points[0].y - segment2[0].points.lastElement().y) > 0.5)) {
- segments.push(segment2);
- }
+ segments.push(eraseSegment); // for eraser visualization
return segments;
};
@@ -1114,6 +1134,47 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return tVals;
};
+ /**
+ * For radius erase, a function to find an eraser's intersections with all ink strokes on the freeform canvas.
+ * @param i the index of the eraser's segment
+ * @param points the eraser's ink data points
+ * @param strokeToTVals Map of InkingStroke to the tVals of its intersections with the eraser
+ * @returns
+ */
+ getOtherInkIntersections = (i: number, points: InkData, strokeToTVals: Map<InkingStroke, number[]>): Map<InkingStroke, number[]> => {
+ // const tVals: [InkingStroke, number[]] = [];
+ // Iterating through all ink strokes in the current freeform collection.
+ this.childDocs
+ .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
+ .forEach(doc => {
+ // InkingStroke of other ink strokes
+ const otherInk = DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())?.ComponentView as InkingStroke;
+ // ink Data of other ink strokes
+ const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
+ for (var j = 0; j < otherInkData.length - 3; j += 4) {
+ const curve: Bezier = InkField.Segment(points, i); // eraser curve
+ const otherCurve: Bezier = InkField.Segment(otherInkData, j); // other curve
+ this.bintersects(otherCurve, curve).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) {
+ // here, add to the map
+ const inkList = strokeToTVals.get(otherInk);
+ if (inkList !== undefined) {
+ const inList = inkList.some(val => Math.abs(val - (t + Math.floor(j / 4))) <= 0.01);
+ if (!inList) {
+ inkList.push(t + Math.floor(j/4));
+ }
+ } else {
+ strokeToTVals.set(otherInk, [t + Math.floor(j/4)]);
+ }
+ }
+ });
+ }
+ });
+ return strokeToTVals;
+ };
+
@action
zoom = (pointX: number, pointY: number, deltaY: number): void => {
if (this.Document.isGroup || this.Document[(this._props.viewField ?? '_') + 'freeform_noZoom']) return;
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 2a5732708..279d3c24c 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -12,7 +12,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { UndoManager, undoable } from '../../util/UndoManager';
import { GestureOverlay } from '../GestureOverlay';
-import { ActiveFillColor, ActiveInkColor, ActiveInkHideTextLabels, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkHideTextLabels, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke';
+import { ActiveFillColor, ActiveInkColor, ActiveInkHideTextLabels, ActiveInkWidth, ActiveIsInkMask, ActiveEraserWidth, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkHideTextLabels, SetActiveInkWidth, SetActiveIsInkMask, SetEraserWidth } from '../InkingStroke';
import { CollectionFreeFormView } from '../collections/collectionFreeForm';
// import { InkTranscription } from '../InkTranscription';
import { DocData } from '../../../fields/DocSymbols';
@@ -338,11 +338,19 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean,
ScriptingGlobals.add(setActiveTool, 'sets the active ink tool mode');
+// ScriptingGlobals.add(function setEraserProperty(option: 'eraseWidth', value: any, checkResult?: boolean) {
+// setInk: (doc: Doc) => (doc[DocData].eraserWidth = NumCast(value))
+// InkingStroke.setEraserRadius(NumCast(value));
+// })
+
// toggle: Set overlay status of selected document
-ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', value: any, checkResult?: boolean) {
+ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor' | 'eraserWidth', value: any, checkResult?: boolean) {
const selected = SelectionManager.Docs.lastElement() ?? Doc.UserDoc();
+ if (option === 'eraserWidth') {
+ console.log('eraserWidth', value)
+ }
// prettier-ignore
- const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
+ const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor' | 'eraserWidth', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
['inkMask', {
checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())),
setInk: (doc: Doc) => (doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask),
@@ -368,6 +376,11 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fil
setInk: (doc: Doc) => (doc[DocData].color = String(value)),
setMode: () => { SetActiveInkColor(StrCast(value)); selected?.type === DocumentType.INK && setActiveTool(GestureOverlay.Instance.InkShape ?? InkTool.Pen, true, false);},
}],
+ [ 'eraserWidth', {
+ checkResult: () => (selected?._layout_isSvg ? NumCast(selected[DocData].eraser_width) : ActiveEraserWidth()),
+ setInk: (doc: Doc) => (doc[DocData].eraserWidth = NumCast(value)),
+ setMode: () => { SetEraserWidth(value.toString());},
+ }]
]);
if (checkResult) {