From e5905220a84a62fff36965a3bf74a55b793ae31b Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 29 Sep 2021 11:26:58 -0400 Subject: fixed filling of curves. added toggling of brokenindex with right-click. changed look of ink handles to be lighter weight and to reflect brokenindex sttate --- src/client/util/InteractionUtils.tsx | 2 +- src/client/views/InkControlPtHandles.tsx | 95 ++++++++++++++++++-------------- src/client/views/InkTangentHandles.tsx | 55 +++++++++--------- src/client/views/InkingStroke.tsx | 1 + 4 files changed, 82 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 633876683..d43ebd692 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -99,7 +99,7 @@ export namespace InteractionUtils { const toScr = (p: { X: number, Y: number }) => ` ${!p ? 0 : (p.X - left - width / 2) * scalex + width / 2}, ${!p ? 0 : (p.Y - top - width / 2) * scaley + width / 2} `; const strpts = bezier ? - pts.reduce((acc: string, pt, i) => acc + (i % 4 !== 0 ? "" : "M" + toScr(pt) + "C" + toScr(pts[i + 1]) + toScr(pts[i + 2]) + toScr(pts[i + 3])), "") : + pts.reduce((acc: string, pt, i) => acc + (i % 4 !== 0 ? "" : (i === 0 ? "M" + toScr(pt) : "") + "C" + toScr(pts[i + 1]) + toScr(pts[i + 2]) + toScr(pts[i + 3])), "") : pts.reduce((acc: string, pt) => acc + `${toScr(pt)} `, ""); const dashArray = dash && Number(dash) ? String(Number(width) * Number(dash)) : undefined; diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx index 898c3bf26..f80aca268 100644 --- a/src/client/views/InkControlPtHandles.tsx +++ b/src/client/views/InkControlPtHandles.tsx @@ -10,6 +10,7 @@ import { Transform } from "../util/Transform"; import { UndoManager } from "../util/UndoManager"; import { Colors } from "./global/globalEnums"; import { InkStrokeProperties } from "./InkStrokeProperties"; +import { List } from "../../fields/List"; export interface InkControlProps { inkDoc: Doc; @@ -24,6 +25,8 @@ export interface InkControlProps { export class InkControlPtHandles extends React.Component { @observable private _overControl = -1; + + @observable controlUndo: UndoManager.Batch | undefined; /** * Handles the movement of a selected control point when the user clicks and drags. * @param controlIndex The index of the currently selected control point. @@ -31,34 +34,40 @@ export class InkControlPtHandles extends React.Component { @action onControlDown = (e: React.PointerEvent, controlIndex: number): void => { if (InkStrokeProperties.Instance) { - var controlUndo: UndoManager.Batch | undefined; const screenScale = this.props.ScreenToLocalTransform().Scale; const order = controlIndex % 4; const handleIndexA = ((order === 3 ? controlIndex - 1 : controlIndex - 2) + this.props.inkCtrlPoints.length) % this.props.inkCtrlPoints.length; const handleIndexB = (order === 3 ? controlIndex + 2 : controlIndex + 1) % this.props.inkCtrlPoints.length; const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number")); setupMoveUpEvents(this, e, - (e: PointerEvent, down: number[], delta: number[]) => { - if (!controlUndo) controlUndo = UndoManager.StartBatch("drag ink ctrl pt"); + action((e: PointerEvent, down: number[], delta: number[]) => { + if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("drag ink ctrl pt"); InkStrokeProperties.Instance?.moveControl(-delta[0] * screenScale, -delta[1] * screenScale, controlIndex); return false; - }, - () => { - controlUndo?.end(); + }), + action(() => { + this.controlUndo?.end(); + this.controlUndo = undefined; UndoManager.FilterBatches(["data", "x", "y", "width", "height"]); - }, + }), action((e: PointerEvent, doubleTap: boolean | undefined) => { const equivIndex = controlIndex === 0 ? this.props.inkCtrlPoints.length - 1 : controlIndex === this.props.inkCtrlPoints.length - 1 ? 0 : controlIndex; - if (doubleTap) { - if (brokenIndices?.includes(equivIndex)) { - if (!controlUndo) controlUndo = UndoManager.StartBatch("make smooth"); - InkStrokeProperties.Instance?.snapHandleTangent(equivIndex, handleIndexA, handleIndexB); - } - if (equivIndex !== controlIndex && brokenIndices?.includes(controlIndex)) { - if (!controlUndo) controlUndo = UndoManager.StartBatch("make smooth"); - InkStrokeProperties.Instance?.snapHandleTangent(controlIndex, handleIndexA, handleIndexB); + if (doubleTap || e.button === 2) { + if (!brokenIndices?.includes(equivIndex) && !brokenIndices?.includes(controlIndex)) { + if (brokenIndices) brokenIndices.push(controlIndex); + else this.props.inkDoc.brokenInkIndices = new List([controlIndex]); + } else { + if (brokenIndices?.includes(equivIndex)) { + if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("make smooth"); + InkStrokeProperties.Instance?.snapHandleTangent(equivIndex, handleIndexA, handleIndexB); + } + if (equivIndex !== controlIndex && brokenIndices?.includes(controlIndex)) { + if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("make smooth"); + InkStrokeProperties.Instance?.snapHandleTangent(controlIndex, handleIndexA, handleIndexB); + } } - controlUndo?.end(); + this.controlUndo?.end(); + this.controlUndo = undefined; } })); } @@ -92,9 +101,6 @@ export class InkControlPtHandles extends React.Component { } render() { - const formatInstance = InkStrokeProperties.Instance; - if (!formatInstance) return (null); - // Accessing the current ink's data and extracting all control points. const scrData = this.props.screenCtrlPoints; const sreenCtrlPoints: ControlPoint[] = []; @@ -111,41 +117,46 @@ export class InkControlPtHandles extends React.Component { } const screenSpaceLineWidth = this.props.screenSpaceLineWidth; - const rectHdlSize = (i: number) => this._overControl === i ? screenSpaceLineWidth * 6 : screenSpaceLineWidth * 4; - const nearestScreenPt = this.props.nearestScreenPt(); + const TagType = (broken?: boolean) => broken ? "rect" : "circle"; + const hdl = (control: { X: number, Y: number, I: number }, scale: number, color: string) => { + const broken = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number"))?.includes(control.I); + const Tag = TagType(broken) as keyof JSX.IntrinsicElements; + return { + this.changeCurrPoint(control.I); + this.onControlDown(e, control.I); + }} + onMouseEnter={() => this.onEnterControl(control.I)} + onMouseLeave={this.onLeaveControl} + pointerEvents="all" + cursor="default" + />; + } return ( {!nearestScreenPt ? (null) : } - {sreenCtrlPoints.map((control, i) => - { - this.changeCurrPoint(control.I); - this.onControlDown(e, control.I); - }} - onMouseEnter={e => this.onEnterControl(i)} - onMouseLeave={this.onLeaveControl} - pointerEvents="all" - cursor="default" - /> - )} + {sreenCtrlPoints.map(control => hdl(control, this._overControl !== control.I ? 1 : 3 / 2, Colors.WHITE))} ); } diff --git a/src/client/views/InkTangentHandles.tsx b/src/client/views/InkTangentHandles.tsx index 759e48134..4f1a406c2 100644 --- a/src/client/views/InkTangentHandles.tsx +++ b/src/client/views/InkTangentHandles.tsx @@ -68,62 +68,61 @@ export class InkTangentHandles extends React.Component { // Accessing the current ink's data and extracting all handle points and handle lines. const data = this.props.screenCtrlPoints; - const handlePoints: HandlePoint[] = []; - const handleLines: HandleLine[] = []; + const tangentHandles: HandlePoint[] = []; + const tangentLines: HandleLine[] = []; const closed = data.lastElement().X === data[0].X && data.lastElement().Y === data[0].Y; if (data.length >= 4) { for (let i = 0; i <= data.length - 4; i += 4) { - handlePoints.push({ ...data[i + 1], I: i + 1, dot1: i, dot2: i === 0 ? (closed ? data.length - 1 : i) : i - 1 }); - handlePoints.push({ ...data[i + 2], I: i + 2, dot1: i + 3, dot2: i === data.length ? (closed ? (i + 4) % data.length : i + 3) : i + 4 }); + tangentHandles.push({ ...data[i + 1], I: i + 1, dot1: i, dot2: i === 0 ? (closed ? data.length - 1 : i) : i - 1 }); + tangentHandles.push({ ...data[i + 2], I: i + 2, dot1: i + 3, dot2: i === data.length ? (closed ? (i + 4) % data.length : i + 3) : i + 4 }); } // Adding first and last (single) handle lines. if (closed) { - handleLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: data.length - 1 }); + tangentLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: data.length - 1 }); } else { - handleLines.push({ X1: data[0].X, Y1: data[0].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: 0 }); - handleLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[data.length - 1].X, Y2: data[data.length - 1].Y, X3: data[data.length - 1].X, Y3: data[data.length - 1].Y, dot1: data.length - 1, dot2: data.length - 1 }); + tangentLines.push({ X1: data[0].X, Y1: data[0].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: 0 }); + tangentLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[data.length - 1].X, Y2: data[data.length - 1].Y, X3: data[data.length - 1].X, Y3: data[data.length - 1].Y, dot1: data.length - 1, dot2: data.length - 1 }); } for (let i = 2; i < data.length - 4; i += 4) { - handleLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 }); + tangentLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 }); } } const screenSpaceLineWidth = this.props.screenSpaceLineWidth; return ( <> - {handlePoints.map((pts, i) => + {tangentHandles.map((pts, i) => this.onHandleDown(e, pts.I)} pointerEvents="all" cursor="default" display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} /> )} - {handleLines.map((pts, i) => - - + {tangentLines.map((pts, i) => { + const tangentLine = (x1: number, y1: number, x2: number, y2: number) => - )} + strokeDasharray={"1 1"} + strokeWidth={1} + display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} />; + return + {tangentLine(pts.X1, pts.Y1, pts.X2, pts.Y2)} + {tangentLine(pts.X2, pts.Y2, pts.X3, pts.Y3)} + ; + })} ); } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 867677005..4cd7f7698 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -210,6 +210,7 @@ export class InkingStroke extends ViewBoxBaseComponent this._nearestScrPt = undefined)} onPointerMove={this.props.isSelected() ? this.onPointerMove : undefined} -- cgit v1.2.3-70-g09d2