diff options
Diffstat (limited to 'src/client/views/InkingStroke.tsx')
-rw-r--r-- | src/client/views/InkingStroke.tsx | 65 |
1 files changed, 40 insertions, 25 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index c915ae65a..b3647249a 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -21,7 +21,7 @@ Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class */ import React = require('react'); -import { action, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { Height, Width } from '../../fields/DocSymbols'; @@ -88,11 +88,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { if (!addAsAnnotation && !pinProps) return this.rootDoc; - const anchor = Docs.Create.InkConfigDocument({ + const anchor = Docs.Create.ConfigDocument({ title: 'Ink anchor:' + this.rootDoc.title, // set presentation timing for restoring shape - presDuration: 1100, - presTransition: 1000, + presentation_duration: 1100, + presentation_transition: 1000, annotationOn: this.rootDoc, }); if (anchor) { @@ -297,6 +297,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { */ nearestScreenPt = () => this._nearestScrPt; + @computed get screenCtrlPts() { + const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); + return inkData + .map(point => + this.screenToLocal() + .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] })); + } + startPt = () => this.screenCtrlPts[0]; + endPt = () => this.screenCtrlPts.lastElement(); /** * @param boundsLeft the screen space left coordinate of the ink stroke * @param boundsTop the screen space top coordinate of the ink stroke @@ -304,18 +316,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { */ componentUI = (boundsLeft: number, boundsTop: number) => { const inkDoc = this.props.Document; - const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); + const { inkData, inkStrokeWidth } = this.inkScaledData(); const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); - const screenPts = inkData - .map(point => - this.screenToLocal() - .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 screenHdlPts = screenPts; const startMarker = StrCast(this.layoutDoc.stroke_startMarker); const endMarker = StrCast(this.layoutDoc.stroke_endMarker); @@ -323,13 +327,13 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? ( !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : ( <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}> - <InkEndPtHandles inkView={this} inkDoc={inkDoc} startPt={screenPts[0]} endPt={screenPts.lastElement()} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> + <InkEndPtHandles inkView={this} inkDoc={inkDoc} startPt={this.startPt} endPt={this.endPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> </div> ) ) : ( <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}> {InteractionUtils.CreatePolyline( - screenPts, + this.screenCtrlPts, 0, 0, Colors.MEDIUM_BLUE, @@ -350,14 +354,23 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { 1.0, false )} - <InkControlPtHandles inkView={this} inkDoc={inkDoc} inkCtrlPoints={inkData} screenCtrlPoints={screenHdlPts} nearestScreenPt={this.nearestScreenPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> - <InkTangentHandles inkView={this} inkDoc={inkDoc} screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} /> + <InkControlPtHandles inkView={this} inkDoc={inkDoc} inkCtrlPoints={inkData} screenCtrlPoints={this.screenCtrlPts} nearestScreenPt={this.nearestScreenPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> + <InkTangentHandles inkView={this} inkDoc={inkDoc} screenCtrlPoints={this.screenCtrlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} /> </div> ); }; _subContentView: DocComponentView | undefined; setSubContentView = (doc: DocComponentView) => (this._subContentView = doc); + @computed get fillColor() { + const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); + return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FillColor) ?? 'transparent'; + } + @computed get strokeColor() { + const { inkData } = this.inkScaledData(); + const fillColor = this.fillColor; + return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); + } render() { TraceMobx(); const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData(); @@ -367,8 +380,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { const markerScale = NumCast(this.layoutDoc.stroke_markerScale, 1); const closed = InkingStroke.IsClosed(inkData); const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); - const fillColor = isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FillColor) ?? 'transparent'; - const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); + const fillColor = this.fillColor; // bcz: Hack!! Not really sure why, but having fractional values for width/height of mask ink strokes causes the dragging clone (see DragManager) to be offset from where it should be. if (isInkMask && (this.layoutDoc[Width]() !== Math.round(this.layoutDoc[Width]()) || this.layoutDoc[Height]() !== Math.round(this.layoutDoc[Height]()))) { @@ -383,7 +395,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { inkData, inkLeft, inkTop, - strokeColor, + this.strokeColor, inkStrokeWidth, inkStrokeWidth, StrCast(this.layoutDoc.stroke_lineJoin), @@ -403,20 +415,23 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { ); const highlight = !this.controlUndo && this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting); const highlightIndex = highlight?.highlightIndex; - const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); + const highlightColor = + (!this.props.isSelected() || !isInkMask) && highlight?.highlightIndex + ? highlight?.highlightColor + : StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false, mask: boolean = false) => + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false) => InteractionUtils.CreatePolyline( inkData, inkLeft, inkTop, - highlightColor, + mask && highlightColor === 'transparent' ? this.strokeColor : highlightColor, inkStrokeWidth, inkStrokeWidth + (fillColor ? (closed ? 2 : (highlightIndex ?? 0) + 2) : 2), StrCast(this.layoutDoc.stroke_lineJoin), StrCast(this.layoutDoc.stroke_lineCap), StrCast(this.layoutDoc.stroke_bezier), - !closed ? 'none' : !isInkMask && (fillColor === 'transparent' || suppressFill) ? 'none' : fillColor, + !closed || !fillColor || DashColor(fillColor).alpha() === 0 ? 'none' : fillColor, '', '', markerScale, @@ -456,7 +471,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { cursor: this.props.isSelected() ? 'default' : undefined, }} {...interactions}> - {clickableLine(this.onPointerDown, undefined, isInkMask)} + {clickableLine(this.onPointerDown, isInkMask)} {isInkMask ? null : inkLine} </svg> {!closed || (!RTFCast(this.rootDoc.text)?.Text && (!this.props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : ( |