aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/InkControl.tsx103
-rw-r--r--src/client/views/InkStrokeProperties.ts141
-rw-r--r--src/client/views/InkingStroke.tsx35
4 files changed, 179 insertions, 102 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index bf939d57c..d1682c09d 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -201,7 +201,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
(e: PointerEvent, down: number[], delta: number[]) => {
const movement = { X: delta[0], Y: e.clientY - down[1] };
const angle = Math.max(1, Math.abs(movement.Y / 10));
- InkStrokeProperties.Instance?.rotate(2 * movement.X / angle * (Math.PI / 180));
+ InkStrokeProperties.Instance?.rotateInk(2 * movement.X / angle * (Math.PI / 180));
return false;
},
() => this._rotateUndo?.end(),
diff --git a/src/client/views/InkControl.tsx b/src/client/views/InkControl.tsx
new file mode 100644
index 000000000..ae0fc0b22
--- /dev/null
+++ b/src/client/views/InkControl.tsx
@@ -0,0 +1,103 @@
+import React = require("react");
+import { observable, action } from "mobx";
+import { observer } from "mobx-react";
+import { InkStrokeProperties } from "./InkStrokeProperties";
+import { setupMoveUpEvents, emptyFunction } from "../../Utils";
+import { UndoManager } from "../util/UndoManager";
+import { ControlPoint } from "../../fields/InkField";
+import { Transform } from "../util/Transform";
+
+export interface InkControlProps {
+ control: ControlPoint;
+ left: number;
+ top: number;
+ scaleX: number;
+ scaleY: number;
+ strokeWidth: number;
+ ScreenToLocalTransform: () => Transform;
+}
+
+@observer
+export class InkControl extends React.Component<InkControlProps> {
+ @observable private _overControl = false;
+
+ @action
+ onPointerEnter = () => {
+ this._overControl = true;
+ }
+
+ @action
+ onPointerLeave = () => {
+ this._overControl = false;
+ }
+
+ /**
+ * Handles the movement of a selected control point when the user clicks and drags.
+ * @param controlNum The index of the currently selected control point.
+ */
+ @action
+ onControlDown = (e: React.PointerEvent, controlNum: number): void => {
+ if (InkStrokeProperties.Instance) {
+ InkStrokeProperties.Instance.moveControl(0, 0, 1);
+ const controlUndo = UndoManager.StartBatch("DocDecs set radius");
+ const screenScale = this.props.ScreenToLocalTransform().Scale;
+ setupMoveUpEvents(this, e,
+ (e: PointerEvent, down: number[], delta: number[]) => {
+ InkStrokeProperties.Instance?.moveControl(-delta[0] * screenScale, -delta[1] * screenScale, controlNum);
+ return false;
+ },
+ () => controlUndo?.end(), emptyFunction);
+ }
+ }
+
+ /**
+ * Deletes the currently selected points.
+ * @param e Keyboard Event.
+ */
+ @action
+ onDelete = (e: KeyboardEvent) => {
+ if (["-", "Backspace", "Delete"].includes(e.key)) {
+ if (InkStrokeProperties.Instance?.deletePoints()) e.stopPropagation();
+ }
+ }
+
+ /**
+ * Changes the current selected control point.
+ * @param i The number of the point to be selected.
+ */
+ @action
+ changeCurrPoint = (i: number) => {
+ if (InkStrokeProperties.Instance) {
+ InkStrokeProperties.Instance._currPoint = i;
+ document.addEventListener("keydown", this.onDelete, true);
+ }
+ }
+
+
+ render() {
+ const control = this.props.control;
+ const left = this.props.left;
+ const top = this.props.top;
+ const scaleX = this.props.scaleX;
+ const scaleY = this.props.scaleY;
+ const strokeWidth = this.props.strokeWidth;
+
+ return (
+ <svg height="10" width="10" key={`ctrl${control.I}`}>
+ <rect
+ x={(control.X - left) * scaleX}
+ y={(control.Y - top) * scaleY}
+ height={this._overControl ? strokeWidth * 1.5 : strokeWidth}
+ width={this._overControl ? strokeWidth * 1.5 : strokeWidth}
+ strokeWidth={strokeWidth / 6} stroke="#1F85DE"
+ fill={InkStrokeProperties.Instance?._currPoint === control.I ? "#1F85DE" : "white"}
+ onPointerDown={(e) => { this.changeCurrPoint(control.I); this.onControlDown(e, control.I); }}
+ onMouseEnter={this.onPointerEnter}
+ onMouseLeave={this.onPointerLeave}
+ pointerEvents="all"
+ cursor="default"
+ />
+ </svg>
+ )
+ }
+} \ No newline at end of file
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 5c5395984..720a89334 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -32,51 +32,52 @@ export class InkStrokeProperties {
const inks = SelectionManager.Views().filter(i => Document(i.rootDoc).type === DocumentType.INK);
return inks.length ? inks : undefined;
}
- @computed get unFilled() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.fillColor ? true : false, true) || false; }
- @computed get unStrokd() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.color ? true : false, true) || false; }
- @computed get solidFil() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.fillColor ? true : false, true) || false; }
- @computed get solidStk() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.color && (!i.rootDoc.strokeDash || i.rootDoc.strokeDash === "0") ? true : false, true) || false; }
- @computed get dashdStk() { return !this.unStrokd && this.getField("strokeDash") || ""; }
- @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
- @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
- @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
- @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
- @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
- @computed get shapeHgt() { return this.getField("_height"); }
- @computed get shapeWid() { return this.getField("_width"); }
- @computed get shapeXps() { return this.getField("x"); }
- @computed get shapeYps() { return this.getField("y"); }
- @computed get shapeRot() { return this.getField("rotation"); }
- set unFilled(value) { this.colorFil = value ? "" : this._lastFill; }
- set solidFil(value) { this.unFilled = !value; }
- set colorFil(value) { value && (this._lastFill = value); this.selectedInk?.forEach(i => i.rootDoc.fillColor = value ? value : undefined); }
- set colorStk(value) { value && (this._lastLine = value); this.selectedInk?.forEach(i => i.rootDoc.color = value ? value : undefined); }
- set markHead(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeStartMarker = value); }
- set markTail(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeEndMarker = value); }
- set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
- set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
- set dashdStk(value) {
- value && (this._lastDash = value) && (this.unStrokd = false);
- this.selectedInk?.forEach(i => i.rootDoc.strokeDash = value ? this._lastDash : undefined);
- }
- set shapeXps(value) { this.selectedInk?.forEach(i => i.rootDoc.x = Number(value)); }
- set shapeYps(value) { this.selectedInk?.forEach(i => i.rootDoc.y = Number(value)); }
- set shapeRot(value) { this.selectedInk?.forEach(i => i.rootDoc.rotation = Number(value)); }
- set widthStk(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeWidth = Number(value)); }
- set shapeWid(value) {
- this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
- const oldWidth = NumCast(i.rootDoc._width);
- i.rootDoc._width = Number(value);
- this._lock && (i.rootDoc._height = (i.rootDoc._width * NumCast(i.rootDoc._height)) / oldWidth);
- });
- }
- set shapeHgt(value) {
- this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
- const oldHeight = NumCast(i.rootDoc._height);
- i.rootDoc._height = Number(value);
- this._lock && (i.rootDoc._width = (i.rootDoc._height * NumCast(i.rootDoc._width)) / oldHeight);
- });
- }
+
+ // @computed get unFilled() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.fillColor ? true : false, true) || false; }
+ // @computed get unStrokd() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.color ? true : false, true) || false; }
+ // @computed get solidFil() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.fillColor ? true : false, true) || false; }
+ // @computed get solidStk() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.color && (!i.rootDoc.strokeDash || i.rootDoc.strokeDash === "0") ? true : false, true) || false; }
+ // @computed get dashdStk() { return !this.unStrokd && this.getField("strokeDash") || ""; }
+ // @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
+ // @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
+ // @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
+ // @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
+ // @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
+ // @computed get shapeHgt() { return this.getField("_height"); }
+ // @computed get shapeWid() { return this.getField("_width"); }
+ // @computed get shapeXps() { return this.getField("x"); }
+ // @computed get shapeYps() { return this.getField("y"); }
+ // @computed get shapeRot() { return this.getField("rotation"); }
+ // set unFilled(value) { this.colorFil = value ? "" : this._lastFill; }
+ // set solidFil(value) { this.unFilled = !value; }
+ // set colorFil(value) { value && (this._lastFill = value); this.selectedInk?.forEach(i => i.rootDoc.fillColor = value ? value : undefined); }
+ // set colorStk(value) { value && (this._lastLine = value); this.selectedInk?.forEach(i => i.rootDoc.color = value ? value : undefined); }
+ // set markHead(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeStartMarker = value); }
+ // set markTail(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeEndMarker = value); }
+ // set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
+ // set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
+ // set dashdStk(value) {
+ // value && (this._lastDash = value) && (this.unStrokd = false);
+ // this.selectedInk?.forEach(i => i.rootDoc.strokeDash = value ? this._lastDash : undefined);
+ // }
+ // set shapeXps(value) { this.selectedInk?.forEach(i => i.rootDoc.x = Number(value)); }
+ // set shapeYps(value) { this.selectedInk?.forEach(i => i.rootDoc.y = Number(value)); }
+ // set shapeRot(value) { this.selectedInk?.forEach(i => i.rootDoc.rotation = Number(value)); }
+ // set widthStk(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeWidth = Number(value)); }
+ // set shapeWid(value) {
+ // this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
+ // const oldWidth = NumCast(i.rootDoc._width);
+ // i.rootDoc._width = Number(value);
+ // this._lock && (i.rootDoc._height = (i.rootDoc._width * NumCast(i.rootDoc._height)) / oldWidth);
+ // });
+ // }
+ // set shapeHgt(value) {
+ // this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
+ // const oldHeight = NumCast(i.rootDoc._height);
+ // i.rootDoc._height = Number(value);
+ // this._lock && (i.rootDoc._width = (i.rootDoc._height * NumCast(i.rootDoc._width)) / oldHeight);
+ // });
+ // }
/**
* Adds a new control point to the ink instance when editing its format.
@@ -191,7 +192,7 @@ export class InkStrokeProperties {
*/
@undoBatch
@action
- rotate = (angle: number) => {
+ rotateInk = (angle: number) => {
this.applyFunction((doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => {
const oldXrange = (xs => ({ coord: NumCast(doc.x), min: Math.min(...xs), max: Math.max(...xs) }))(ink.map(p => p.X));
const oldYrange = (ys => ({ coord: NumCast(doc.y), min: Math.min(...ys), max: Math.max(...ys) }))(ink.map(p => p.Y));
@@ -301,29 +302,29 @@ 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) => {
- const val = String(color.hex);
- this.colorStk = val;
- return true;
- }
+ // /**
+ // * 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) => {
+ // const val = String(color.hex);
+ // this.colorStk = val;
+ // 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) => {
- const val = String(color.hex);
- this.colorFil = val;
- 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) => {
+ // const val = String(color.hex);
+ // this.colorFil = val;
+ // return true;
+ // }
} \ No newline at end of file
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 163eb05b0..9555557ec 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -18,6 +18,7 @@ import { FieldView, FieldViewProps } from "./nodes/FieldView";
import React = require("react");
import { InkStrokeProperties } from "./InkStrokeProperties";
import { CurrentUserUtils } from "../util/CurrentUserUtils";
+import { InkControl } from "./InkControl";
type InkDocument = makeInterface<[typeof documentSchema]>;
const InkDocument = makeInterface(documentSchema);
@@ -80,29 +81,6 @@ 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) {
- InkStrokeProperties.Instance._currPoint = i;
- document.addEventListener("keydown", this.onDelete, true);
- }
- }
-
- /**
- * Deletes the currently selected points.
- * @param e Keyboard Event.
- */
- @action
- onDelete = (e: KeyboardEvent) => {
- if (["-", "Backspace", "Delete"].includes(e.key)) {
- if (InkStrokeProperties.Instance?.deletePoints()) e.stopPropagation();
- }
- }
-
- /**
* Handles the movement of the entire ink object when the user clicks and drags.
* @param e React Pointer Event.
*/
@@ -113,7 +91,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
}
- public static MaskDim = 50000;
+ static readonly MaskDim = 50000;
render() {
TraceMobx();
const formatInstance = InkStrokeProperties.Instance;
@@ -143,7 +121,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
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);
- const selectedLine = InteractionUtils.CreatePolyline(data, lineLft - strokeWidth * 3, lineTop - strokeWidth * 3, "#1F85DE", strokeWidth / 6, strokeWidth / 6,
+ const selectedLine = InteractionUtils.CreatePolyline(data, lineLft - strokeWidth * 4 * scaleX, lineTop - strokeWidth * 4 * scaleX, "#1F85DE", strokeWidth / 6, strokeWidth / 6,
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);
@@ -203,12 +181,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
onPointerDown={(e) => this.onHandleDown(e, pts.I)} pointerEvents="all" cursor="default" display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
</svg>);
// Control points of the ink (blue outlined squares) that are made visible to user when editing its format.
- const controls = controlPoints.map((pts, i) =>
- <svg height="10" width="10" key={`ctrl${i}`}>
- <rect x={(pts.X - left) * scaleX} y={(pts.Y - top) * scaleY} height={strokeWidth} width={strokeWidth} strokeWidth={strokeWidth / 6} stroke="#1F85DE" fill={formatInstance && formatInstance._currPoint === pts.I ? "#1F85DE" : "white"}
- onPointerDown={(e) => { this.changeCurrPoint(pts.I); this.onControlDown(e, pts.I); }} pointerEvents="all" cursor="default"
- />
- </svg>);
+ const controls = controlPoints.map((pts, i) => <InkControl control={pts} left={left} top={top} scaleX={scaleX} scaleY={scaleY} strokeWidth={strokeWidth} ScreenToLocalTransform={this.props.ScreenToLocalTransform} /> );
// Set of two blue 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}`}>