aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/InkStrokeProperties.ts43
-rw-r--r--src/client/views/InkingStroke.tsx26
-rw-r--r--src/fields/InkField.ts4
3 files changed, 70 insertions, 3 deletions
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index b13b04f68..533fdf006 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -17,8 +17,11 @@ export class InkStrokeProperties {
private _lastDash = "2";
private _inkDocs: { x: number, y: number, width: number, height: number }[] = [];
+ // Indicates whether the ink is locked.
@observable _lock = false;
+ // Indicates whether the ink's format is being currently edited (displaying of control points).
@observable _controlBtn = false;
+ // Stores the index of the current selected control point of the ink instance.
@observable _currPoint = -1;
getField(key: string) {
@@ -80,6 +83,14 @@ export class InkStrokeProperties {
InkStrokeProperties.Instance = this;
}
+ /**
+ * Adds a new control point to the ink instance when editing its format.
+ * @param x The x-coordinate of the current new point.
+ * @param y The y-coordinate of the current new point.
+ * @param pts The list containing all of the points to be added in PointData form.
+ * @param index The index of the current new point.
+ * @param control The list of all control points of the ink.
+ */
@undoBatch
@action
addPoints = (x: number, y: number, pts: { X: number, Y: number }[], index: number, control: { X: number, Y: number }[]) => {
@@ -115,6 +126,12 @@ export class InkStrokeProperties {
}));
}
+ /**
+ * Helper function that enables other functions to be applied to a particular ink instance.
+ * @param func The inputted function.
+ * @param requireCurrPoint Indicates whether the current selected point is needed.
+ * @returns The applied function.
+ */
applyFunction = (func: (doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => { X: number, Y: number }[] | undefined, requireCurrPoint: boolean = false) => {
var appliedFunc = false;
this.selectedInk?.forEach(action(inkView => {
@@ -145,6 +162,10 @@ export class InkStrokeProperties {
return appliedFunc;
}
+ /**
+ * Deletes the points of the current ink instance.
+ * @returns The changed x- and y-coordinates of the control points.
+ */
@undoBatch
@action
deletePoints = () => this.applyFunction((doc: Doc, ink: InkData) => {
@@ -168,6 +189,11 @@ export class InkStrokeProperties {
return newPoints;
}, true);
+ /**
+ * Rotates the points of the current ink instance by a certain angle degree.
+ * @param angle The angle at which to rotate the ink (all of its x- and y-coordinates).
+ * @returns The changed x- and y-coordinates of the control points.
+ */
@undoBatch
@action
rotate = (angle: number) => {
@@ -186,6 +212,13 @@ export class InkStrokeProperties {
});
}
+ /**
+ * Handles the movement / scaling of control points of an ink instance.
+ * @param xDiff The movement of the control point's x-coordinate.
+ * @param yDiff The movement of the control point's y-coordinate.
+ * @param controlNum The index of the current control point selected.
+ * @returns The changed x- and y-coordinates of the control points.
+ */
@undoBatch
@action
control = (xDiff: number, yDiff: number, controlNum: number) =>
@@ -209,6 +242,11 @@ export class InkStrokeProperties {
return newPoints;
});
+ /**
+ * Changes the color of the border of the ink instance.
+ * @param color The new hex value to change the border to.
+ * @returns true.
+ */
@undoBatch
@action
switchStk = (color: ColorState) => {
@@ -217,6 +255,11 @@ export class InkStrokeProperties {
return true;
}
+ /**
+ * Changes the color of the fill of the ink instance.
+ * @param color The new hex value to change the fill to.
+ * @returns true.
+ */
@undoBatch
@action
switchFil = (color: ColorState) => {
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 449019ca8..859e53b97 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -41,6 +41,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
inkDoc._stayInCollection = inkDoc.isInkMask ? true : undefined;
});
+ /**
+ * Handles the movement of a selected control point when the user clicks and drags.
+ * @param e React Pointer Event.
+ * @param controlNum The number of the currently selected control point.
+ */
@action
onControlDown = (e: React.PointerEvent, controlNum: number): void => {
if (InkStrokeProperties.Instance) {
@@ -56,6 +61,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
}
+ /**
+ * Changes the current selected control point.
+ * @param i The number of the point to be selected.
+ */
@action
changeCurrPoint = (i: number) => {
if (InkStrokeProperties.Instance) {
@@ -64,6 +73,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
}
+ /**
+ * Deletes the currently selected points.
+ * @param e Keyboard Event.
+ */
@action
delPts = (e: KeyboardEvent) => {
if (["-", "Backspace", "Delete"].includes(e.key)) {
@@ -71,6 +84,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
}
+ /**
+ * Handles the movement of the entire ink object when the user clicks and drags.
+ * @param e React Pointer Event.
+ */
onPointerDown = (e: React.PointerEvent) => {
if (this.props.isSelected(true)) {
setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e: PointerEvent, doubleTap: boolean | undefined) =>
@@ -102,17 +119,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight() - strokeWidth) / (height - strokeWidth);
const strokeColor = StrCast(this.layoutDoc.color, "");
+ // Visually renders the polygonal line made by the user.
const points = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth,
StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker),
StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBot - lineTop > 1 && lineRgt - lineLft > 1, false);
+ // Invisible polygonal line that enables the ink to be selected by the user.
const hpoints = InteractionUtils.CreatePolyline(data, left, top,
this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, (strokeWidth + 15),
StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
"none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", false, true);
- //points for adding
const apoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth,
StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker),
@@ -153,24 +171,27 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
// }
const dotsize = Math.max(width * scaleX, height * scaleY) / 40;
+ // Additional points (controls) added by the user via click when editing the ink's format.
const addpoints = apoints.map((pts, i) =>
<svg height="10" width="10" key={`add${i}`}>
<circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} stroke="invisible" strokeWidth={dotsize / 2} fill="invisible"
onPointerDown={(e) => { formatInstance.addPoints(pts.X, pts.Y, apoints, i, controlPoints); }} pointerEvents="all" cursor="all-scroll"
/>
</svg>);
+ // Green circles that allow the user to edit the curvature of the line using the selected point as the anchor.
const handles = handlePoints.map((pts, i) =>
<svg height="10" width="10" key={`hdl${i}`}>
<circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth} strokeWidth={0} fill="green"
onPointerDown={(e) => this.onControlDown(e, pts.I)} pointerEvents="all" cursor="default" display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
</svg>);
-
+ // Points (red circles) of the ink that are made visible to user when editing its format.
const controls = controlPoints.map((pts, i) =>
<svg height="10" width="10" key={`ctrl${i}`}>
<circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} strokeWidth={0} fill="red"
onPointerDown={(e) => { this.changeCurrPoint(pts.I); this.onControlDown(e, pts.I); }} pointerEvents="all" cursor="default"
/>
</svg>);
+ // Set of two green lines (each with a handle at the end) that are rendered perpendicular to the current selected point while editing.
const handleLines = handleLine.map((pts, i) =>
<svg height="100" width="100" key={`line${i}`} >
<line x1={(pts.X1 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y1={(pts.Y1 - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
@@ -181,7 +202,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
</svg>);
-
return (
<svg className="inkingStroke"
style={{
diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts
index dbe51b24a..b79a03146 100644
--- a/src/fields/InkField.ts
+++ b/src/fields/InkField.ts
@@ -4,6 +4,7 @@ import { ObjectField } from "./ObjectField";
import { Copy, ToScriptString, ToString, Update } from "./FieldSymbols";
import { Scripting } from "../client/util/Scripting";
+// Helps keep track of the current ink tool in use.
export enum InkTool {
None = "none",
Pen = "pen",
@@ -12,11 +13,13 @@ export enum InkTool {
Stamp = "stamp"
}
+// Defines a point in an ink as a pair of x- and y-coordinates.
export interface PointData {
X: number;
Y: number;
}
+// Defines an ink as an array of points.
export type InkData = Array<PointData>;
const pointSchema = createSimpleSchema({
@@ -28,6 +31,7 @@ const strokeDataSchema = createSimpleSchema({
"*": true
});
+// Holistic class representing the store of an ink.
@Deserializable("ink")
export class InkField extends ObjectField {
@serializable(list(object(strokeDataSchema)))