diff options
| author | bobzel <zzzman@gmail.com> | 2021-11-29 14:09:17 -0500 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2021-11-29 14:09:17 -0500 |
| commit | 061dab5285d3a334a258d8097a6e95b065b30de3 (patch) | |
| tree | 0f77cdacae4330e0588538b3ba5f3445616a0530 /src/client/views/InkingStroke.tsx | |
| parent | 7e6baacfe6c1b55a3fe1807903455f9ff3844d74 (diff) | |
added moving ink stroke segments. added stretching and rotating ink strokes about opposite end point.
Diffstat (limited to 'src/client/views/InkingStroke.tsx')
| -rw-r--r-- | src/client/views/InkingStroke.tsx | 79 |
1 files changed, 56 insertions, 23 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 59efb36dd..ecc82a580 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,28 +1,29 @@ import React = require("react"); import { action, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../fields/Doc"; +import { Doc, WidthSym } from "../../fields/Doc"; import { documentSchema } from "../../fields/documentSchemas"; import { InkData, InkField, InkTool } from "../../fields/InkField"; import { makeInterface } from "../../fields/Schema"; import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; -import { emptyFunction, returnFalse, setupMoveUpEvents, OmitKeys } from "../../Utils"; +import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { InteractionUtils } from "../util/InteractionUtils"; import { SnappingManager } from "../util/SnappingManager"; +import { Transform } from "../util/Transform"; +import { UndoManager } from "../util/UndoManager"; import { ContextMenu } from "./ContextMenu"; import { ViewBoxBaseComponent } from "./DocComponent"; import { Colors } from "./global/globalEnums"; -import { InkControlPtHandles } from "./InkControlPtHandles"; +import { InkControlPtHandles, InkEndPtHandles } from "./InkControlPtHandles"; import "./InkStroke.scss"; import { InkStrokeProperties } from "./InkStrokeProperties"; import { InkTangentHandles } from "./InkTangentHandles"; import { FieldView, FieldViewProps } from "./nodes/FieldView"; -import Color = require("color"); -import { Transform } from "../util/Transform"; import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox"; +import Color = require("color"); type InkDocument = makeInterface<[typeof documentSchema]>; const InkDocument = makeInterface(documentSchema); @@ -89,21 +90,49 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume /** * Handles the movement of the entire ink object when the user clicks and drags. */ + @action onPointerDown = (e: React.PointerEvent) => { + const ptFromScreen = this.ptFromScreen; this._handledClick = false; - if (this.props.isSelected(true)) { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, + if (InkStrokeProperties.Instance && ptFromScreen) { + const inkView = this.props.docViewPath().lastElement(); + const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); + const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint( + (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, + (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); + const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); + const controlIndex = nearestSeg; + const wasSelected = InkStrokeProperties.Instance?._currentPoint === controlIndex; + var controlUndo: UndoManager.Batch | undefined; + const isEditing = this._properties?._controlButton && this.props.isSelected(); + setupMoveUpEvents(this, e, + !isEditing ? returnFalse : action((e: PointerEvent, down: number[], delta: number[]) => { + if (!controlUndo) controlUndo = UndoManager.StartBatch("drag ink ctrl pt"); + const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] }); + const inkMoveStart = ptFromScreen({ X: 0, Y: 0 }); + InkStrokeProperties.Instance?.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex); + InkStrokeProperties.Instance?.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex + 3); + return false; + }), + !isEditing ? returnFalse : action(() => { + if (controlUndo) { + InkStrokeProperties.Instance?.snapControl(inkView, controlIndex); + InkStrokeProperties.Instance?.snapControl(inkView, controlIndex + 3); + } + controlUndo?.end(); + controlUndo = undefined; + UndoManager.FilterBatches(["data", "x", "y", "width", "height"]); + }), action((e: PointerEvent, doubleTap: boolean | undefined) => { doubleTap = doubleTap || this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick; if (doubleTap && this._properties) { this._properties._controlButton = true; InkStrokeProperties.Instance && (InkStrokeProperties.Instance._currentPoint = -1); this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView - } else if (this._properties?._controlButton) { + } else if (isEditing) { this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance?.addPoints(this.props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); } - }), this._properties?._controlButton, this._properties?._controlButton - ); + }), isEditing, isEditing, () => wasSelected && InkStrokeProperties.Instance && (InkStrokeProperties.Instance._currentPoint = -1)); } } @@ -185,7 +214,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume this._nearestScrPt = nearestPt; } - nearestScreenPt = () => this._nearestScrPt; componentUI = (boundsLeft: number, boundsTop: number) => { const inkDoc = this.props.Document; @@ -200,11 +228,17 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume const startMarker = StrCast(this.layoutDoc.strokeStartMarker); const endMarker = StrCast(this.layoutDoc.strokeEndMarker); - return SnappingManager.GetIsDragging() ? (null) : <div className="inkstroke-UI" style={{ - clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` - }} > - {!this._properties?._controlButton ? (null) : - <> + return SnappingManager.GetIsDragging() ? (null) : + !this._properties?._controlButton ? + (!this.props.isSelected() || InkingStroke.IsClosed(inkData) ? (null) : + <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}> + <InkEndPtHandles + inkView={this.props.docViewPath().lastElement()} + inkDoc={inkDoc} + startPt={this.ptToScreen(inkData[0])} + endPt={this.ptToScreen(inkData.lastElement())} + screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /></div>) : + <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}> {InteractionUtils.CreatePolyline(screenPts, 0, 0, Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth, StrCast(inkDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(inkDoc.strokeBezier), "none", startMarker, endMarker, StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)} @@ -222,8 +256,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.props.ScreenToLocalTransform} /> - </>} - </div>; + </div>; } render() { @@ -246,11 +279,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== "transparent" ? StrCast(this.layoutDoc.color, "transparent") : "transparent") : ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "yellow", "magenta", "cyan", "orange"][highlightIndex]; // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, - inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15), + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, + inkStrokeWidth, inkStrokeWidth + (CurrentUserUtils.SelectedTool === InkTool.Eraser ? 0 : highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15), StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker, - undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, false); + undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, + false, downHdlr); // Set of points rendered upon the ink that can be added if a user clicks on one. return <div className="inkStroke-wrapper" style={{ display: "flex", alignItems: "center", height: "100%" }}> @@ -266,7 +300,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume }} onPointerLeave={action(e => this._nearestScrPt = undefined)} onPointerMove={this.props.isSelected() ? this.onPointerMove : undefined} - onPointerDown={this.onPointerDown} onClick={e => this._handledClick && e.stopPropagation()} onContextMenu={() => { const cm = ContextMenu.Instance; @@ -275,7 +308,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume cm?.addItem({ description: "Edit Points", event: action(() => { if (this._properties) { this._properties._controlButton = !this._properties._controlButton; } }), icon: "paint-brush" }); }} > - {clickableLine} + {clickableLine(this.onPointerDown)} {inkLine} </svg> {!closed ? (null) : |
