diff options
author | yunahi <60233430+yunahi@users.noreply.github.com> | 2020-08-10 22:20:15 +0900 |
---|---|---|
committer | yunahi <60233430+yunahi@users.noreply.github.com> | 2020-08-10 22:20:15 +0900 |
commit | d4ca38801b19e38b49b087be3e510cc0fca33eb8 (patch) | |
tree | 82628c406a2704784099a9d8230a4890d949d022 | |
parent | 7e18d27de76bd2b58281841910aee3c4829269dd (diff) |
fixed line, able to add/delete control points
-rw-r--r-- | src/client/util/InteractionUtils.tsx | 60 | ||||
-rw-r--r-- | src/client/views/GestureOverlay.tsx | 30 | ||||
-rw-r--r-- | src/client/views/InkingStroke.tsx | 30 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/FormatShapePane.tsx | 76 |
4 files changed, 176 insertions, 20 deletions
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 04a750f93..ae3b3e064 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -91,15 +91,61 @@ export namespace InteractionUtils { return myTouches; } - export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, + export function CreatePoints(points: { X: number, Y: number }[], left: number, top: number, color: string, width: number, strokeWidth: number, bezier: string, fill: string, arrowStart: string, arrowEnd: string, dash: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) { + let pts: { X: number; Y: number; }[] = []; + if (shape) { //if any of the shape are true + pts = makePolygon(shape, points); + } + else if ((points.length >= 5 && points[3].X === points[4].X) || (points.length === 4)) { + for (var i = 0; i < points.length - 3; i += 4) { + const array = [[points[i].X, points[i].Y], [points[i + 1].X, points[i + 1].Y], [points[i + 2].X, points[i + 2].Y], [points[i + 3].X, points[i + 3].Y]]; + for (var t = 0; t < 1; t += 0.01) { + const point = beziercurve(t, array); + pts.push({ X: point[0], Y: point[1] }); + } + } + } + else if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y === points[0].Y) { + //pointer is up (first and last points are the same) + const newPoints = points.reduce((p, pts) => { p.push([pts.X, pts.Y]); return p; }, [] as number[][]); + newPoints.pop(); + const bezierCurves = fitCurve(newPoints, parseInt(bezier)); + for (const curve of bezierCurves) { + for (var t = 0; t < 1; t += 0.01) { + const point = beziercurve(t, curve); + pts.push({ X: point[0], Y: point[1] }); + } + } + } else { + pts = points.slice(); + // bcz: Ugh... this is ugly, but shapes apprently have an extra point added that is = (p[0].x,p[0].y+1) as some sort of flag. need to remove it here. + if (pts.length > 2 && pts[pts.length - 2].X === pts[0].X && pts[pts.length - 2].Y === pts[0].Y) { + pts.pop(); + } + } + if (isNaN(scalex)) { + scalex = 1; + } + if (isNaN(scaley)) { + scaley = 1; + } + console.log(pts.length); + return pts; + } + + + + export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, + color: string, width: number, strokeWidth: number, bezier: string, fill: string, arrowStart: string, arrowEnd: string, + dash: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) { let pts: { X: number; Y: number; }[] = []; if (shape) { //if any of the shape are true pts = makePolygon(shape, points); } - else if (points.length >= 5 && points[3].X === points[4].X) { + else if ((points.length >= 5 && points[3].X === points[4].X) || (points.length === 4)) { for (var i = 0; i < points.length - 3; i += 4) { const array = [[points[i].X, points[i].Y], [points[i + 1].X, points[i + 1].Y], [points[i + 2].X, points[i + 2].Y], [points[i + 3].X, points[i + 3].Y]]; for (var t = 0; t < 1; t += 0.01) { @@ -139,6 +185,15 @@ export namespace InteractionUtils { const dashArray = String(Number(width) * Number(dash)); const defGuid = Utils.GenerateGuid(); const arrowDim = Math.max(0.5, 8 / Math.log(Math.max(2, strokeWidth))); + + const addables = pts.map((pts, i) => + <svg height="10" width="10"> + <circle cx={(pts.X - left - width / 2) * scalex + width / 2} cy={(pts.Y - top - width / 2) * scaley + width / 2} r={strokeWidth / 2} stroke="black" stroke-width={1} fill="blue" + onDoubleClick={(e) => { console.log(i); }} pointerEvents="all" cursor="all-scroll" + /> + </svg>); + + return (<svg fill={color}> {/* setting the svg fill sets the arrowStart fill */} {nodefs ? (null) : <defs> {arrowStart !== "dot" && arrowEnd !== "dot" ? (null) : <marker id={`dot${defGuid}`} orient="auto" overflow="visible"> @@ -167,6 +222,7 @@ export namespace InteractionUtils { markerStart={`url(#${arrowStart + "Start" + defGuid})`} markerEnd={`url(#${arrowEnd + "End" + defGuid})`} /> + {/* {addables} */} </svg>); } diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 30df7cf9a..a9fc20174 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -817,21 +817,21 @@ export default class GestureOverlay extends Touchable { // const b = firsty - m * firstx; this._points.push({ X: firstx, Y: firsty }); this._points.push({ X: firstx, Y: firsty }); - - this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); - this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); - this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); - this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); - - this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); - this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); - this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); - this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); - - this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); - this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); - this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); - this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); + //removed points + // this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); + // this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); + // this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); + // this._points.push({ X: firstx + fourth, Y: m * (firstx + fourth) + b }); + + // this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); + // this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); + // this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); + // this._points.push({ X: firstx + 2 * fourth, Y: m * (firstx + 2 * fourth) + b }); + + // this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); + // this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); + // this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); + // this._points.push({ X: firstx + 3 * fourth, Y: m * (firstx + 3 * fourth) + b }); this._points.push({ X: firstx + 4 * fourth, Y: m * (firstx + 4 * fourth) + b }); this._points.push({ X: firstx + 4 * fourth, Y: m * (firstx + 4 * fourth) + b }); diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index fe5bf1eb2..0afc71e9b 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -52,8 +52,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume FormatShapePane.Instance.Pinned = true; } - private _prevX = 0; - private _prevY = 0; + public _prevX = 0; + public _prevY = 0; private _controlNum = 0; @action onControlDown = (e: React.PointerEvent, i: number): void => { @@ -67,6 +67,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume @action changeCurrPoint = (i: number) => { FormatShapePane.Instance._currPoint = i; + document.addEventListener("keydown", this.delPts, true); } @action @@ -86,6 +87,13 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume this._controlUndo?.end(); this._controlUndo = undefined; } + @action + delPts = (e: KeyboardEvent | React.PointerEvent | undefined) => { + if (e instanceof KeyboardEvent ? e.key === "-" : true) { + FormatShapePane.Instance.deletePoints(); + } + } + public static MaskDim = 50000; render() { @@ -115,6 +123,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "transparent"), "none", "none", "0", scaleX, scaleY, "", this.props.active() ? "visiblepainted" : "none", false, true); + //points for adding + const apoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, + StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "transparent"), + StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), + StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false); + var controlPoints: { X: number, Y: number, I: number }[] = []; var handlePoints: { X: number, Y: number, I: number, dot1: number, dot2: number }[] = []; var handleLine: { X1: number, Y1: number, X2: number, Y2: number, X3: number, Y3: number, dot1: number, dot2: number }[] = []; @@ -146,11 +160,20 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume // } const dotsize = String(Math.max(width * scaleX, height * scaleY) / 40); + const addpoints = apoints.map((pts, i) => + + <svg height="10" width="10"> + <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={dotsize} stroke="invisible" stroke-width={String(Number(dotsize) / 2)} fill="invisible" + onPointerDown={(e) => { FormatShapePane.Instance.addPoints(pts.X, pts.Y, apoints, i, controlPoints); }} pointerEvents="all" cursor="all-scroll" + /> + </svg>); + const controls = controlPoints.map((pts, i) => <svg height="10" width="10"> <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={dotsize} stroke="black" stroke-width={String(Number(dotsize) / 2)} fill="red" - onPointerDown={(e) => { this.changeCurrPoint(pts.I); this.onControlDown(e, pts.I); }} pointerEvents="all" cursor="all-scroll" /> + onPointerDown={(e) => { this.changeCurrPoint(pts.I); this.onControlDown(e, pts.I); }} pointerEvents="all" cursor="all-scroll" + /> </svg>); const handles = handlePoints.map((pts, i) => @@ -193,6 +216,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume </defs> {hpoints} {points} + {FormatShapePane.Instance._controlBtn && this.props.isSelected() ? addpoints : ""} {FormatShapePane.Instance._controlBtn && this.props.isSelected() ? controls : ""} {FormatShapePane.Instance._controlBtn && this.props.isSelected() ? handles : ""} {FormatShapePane.Instance._controlBtn && this.props.isSelected() ? handleLines : ""} diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx index d526033a0..e805f9282 100644 --- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx +++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx @@ -163,6 +163,82 @@ export default class FormatShapePane extends AntimodeMenu { @undoBatch @action + addPoints = (x: number, y: number, pts: { X: number, Y: number }[], index: number, control: { X: number, Y: number }[]) => { + this.selectedInk?.forEach(action(inkView => { + if (this.selectedInk?.length === 1) { + const doc = Document(inkView.rootDoc); + if (doc.type === DocumentType.INK) { + const ink = Cast(doc.data, InkField)?.inkData; + if (ink) { + const newPoints: { X: number, Y: number }[] = []; + var counter = 0; + for (var k = 0; k < index; k++) { + for (var l = 0; l < control.length; l++) { + if (pts[k].X === control[l].X && pts[k].Y === control[l].Y) { + counter++; + } + } + } + //decide where to put the new coordinate + const spNum = Math.floor(counter / 2) * 4 + 2; + + for (var i = 0; i < spNum; i++) { + newPoints.push({ X: ink[i].X, Y: ink[i].Y }); + } + for (var j = 0; j < 4; j++) { + newPoints.push({ X: x, Y: y }); + + } + for (var i = spNum; i < ink.length; i++) { + newPoints.push({ X: ink[i].X, Y: ink[i].Y }); + } + this._currPoint = -1; + doc.data = new InkField(newPoints); + } + } + } + })); + } + + @undoBatch + @action + deletePoints = () => { + this.selectedInk?.forEach(action(inkView => { + if (this.selectedInk?.length === 1 && this._currPoint !== -1) { + const doc = Document(inkView.rootDoc); + if (doc.type === DocumentType.INK) { + const ink = Cast(doc.data, InkField)?.inkData; + if (ink && ink.length > 4) { + const newPoints: { X: number, Y: number }[] = []; + + console.log(ink.length, this._currPoint, Math.floor((this._currPoint + 2) / 4)); + + const toRemove = Math.floor(((this._currPoint + 2) / 4)); + for (var i = 0; i < ink.length; i++) { + if (Math.floor((i + 2) / 4) !== toRemove) { + console.log(i, toRemove); + newPoints.push({ X: ink[i].X, Y: ink[i].Y }); + } + } + this._currPoint = -1; + doc.data = new InkField(newPoints); + if (newPoints.length === 4) { + const newerPoints: { X: number, Y: number }[] = []; + newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y }); + newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y }); + newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y }); + newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y }); + doc.data = new InkField(newerPoints); + + } + } + } + } + })); + } + + @undoBatch + @action rotate = (angle: number) => { const _centerPoints: { X: number, Y: number }[] = []; SelectionManager.SelectedDocuments().forEach(action(inkView => { |