diff options
Diffstat (limited to 'src/client/views/InkingStroke.tsx')
-rw-r--r-- | src/client/views/InkingStroke.tsx | 157 |
1 files changed, 62 insertions, 95 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 51baaa23e..f497ca447 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -23,30 +23,33 @@ import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { DashColor, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { Doc } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { DashColor, returnFalse, setupMoveUpEvents } from '../../Utils'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; import { Docs } from '../documents/Documents'; +import { DocumentType } from '../documents/DocumentTypes'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; -import { ViewBoxAnnotatableComponent, ViewBoxBaseComponent, ViewBoxInterface } from './DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from './DocComponent'; import { Colors } from './global/globalEnums'; import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; import { FieldView, FieldViewProps } from './nodes/FieldView'; -import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { PinProps, PresBox } from './nodes/trails'; -import { StyleProp } from './StyleProvider'; +import { FormattedTextBox, FormattedTextBoxProps } from './nodes/formattedText/FormattedTextBox'; +import { PinDocView, PinProps } from './PinFuncs'; +import { StyleProp } from './StyleProp'; + const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore + @observer -export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface { +export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() { static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); @@ -65,7 +68,9 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() this._props.setContentViewBox?.(this); this._disposers.selfDisper = reaction( () => this._props.isSelected(), // react to stroke being deselected by turning off ink handles - selected => !selected && (InkStrokeProperties.Instance._controlButton = false) + selected => { + !selected && (InkStrokeProperties.Instance._controlButton = false); + } ); } componentWillUnmount() { @@ -88,7 +93,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() if (anchor) { anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), inkable: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), inkable: true } }, this.Document); return anchor; } return this.Document; @@ -140,7 +145,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() e, !isEditing ? returnFalse - : action((e: PointerEvent, down: number[], delta: number[]) => { + : action((moveEv: PointerEvent, down: number[], delta: number[]) => { if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch('drag ink ctrl pt'); const inkMoveEnd = this.ptFromScreen({ X: delta[0], Y: delta[1] }); const inkMoveStart = this.ptFromScreen({ X: 0, Y: 0 }); @@ -155,7 +160,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() this.controlUndo = undefined; UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']); }), - action((e: PointerEvent, doubleTap: boolean | undefined) => { + action((moveEv: PointerEvent, doubleTap: boolean | undefined) => { if (doubleTap) { InkStrokeProperties.Instance._controlButton = true; InkStrokeProperties.Instance._currentPoint = -1; @@ -167,7 +172,9 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() }), isEditing, isEditing, - action(() => wasSelected && (InkStrokeProperties.Instance._currentPoint = -1)) + action(() => { + wasSelected && (InkStrokeProperties.Instance._currentPoint = -1); + }) ); }; @@ -325,32 +332,34 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() false )} <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.ScreenToLocalBoxXf} /> + <InkTangentHandles inkView={this} inkDoc={inkDoc} screenCtrlPoints={this.screenCtrlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> </div> ); }; - _subContentView: ViewBoxInterface | undefined; - setSubContentView = (doc: ViewBoxInterface) => (this._subContentView = doc); - @computed get fillColor() { + _subContentView: ViewBoxInterface<FormattedTextBoxProps> | undefined; + setSubContentView = (box: ViewBoxInterface<FormattedTextBoxProps>) => { + this._subContentView = box; + }; + @computed get fillColor(): string { const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent'; } @computed get strokeColor() { const { inkData } = this.inkScaledData(); - const fillColor = this.fillColor; + const { fillColor } = this; 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(); + const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY } = this.inkScaledData(); const startMarker = StrCast(this.layoutDoc.stroke_startMarker); const endMarker = StrCast(this.layoutDoc.stroke_endMarker); const markerScale = NumCast(this.layoutDoc.stroke_markerScale, 1); const closed = InkingStroke.IsClosed(inkData); const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); - const fillColor = this.fillColor; + const { fillColor } = this; // 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(NumCast(this.layoutDoc._width)) || this.layoutDoc._height !== Math.round(NumCast(this.layoutDoc._height)))) { @@ -387,12 +396,11 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() 1.0, false, undefined, - undefined, - color === 'transparent' ? highlightColor : undefined + undefined ); const higlightMargin = Math.min(12, Math.max(2, 0.3 * inkStrokeWidth)); // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false) => + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false): any => InteractionUtils.CreatePolyline( inkData, inkLeft, @@ -415,22 +423,29 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() 0.0, false, downHdlr, - mask, - highlightColor + mask ); // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. // this attempts to figure out the lineHeight ratio by inquiring the body's lineHeight and dividing by the fontsize which should yield 1.428571429 // see: https://bibwild.wordpress.com/2019/06/10/bootstrap-3-to-4-changes-in-how-font-size-line-height-and-spacing-is-done-or-what-happened-to-line-height-computed/ - const lineHeightGuess = +getComputedStyle(document.body).lineHeight.replace('px', '') / +getComputedStyle(document.body).fontSize.replace('px', ''); + // const lineHeightGuess = +getComputedStyle(document.body).lineHeight.replace('px', '') / +getComputedStyle(document.body).fontSize.replace('px', ''); const interactions = { - onPointerLeave: action(() => (this._nearestScrPt = undefined)), + onPointerLeave: action(() => { + this._nearestScrPt = undefined; + }), onPointerMove: this._props.isSelected() ? this.onPointerMove : undefined, onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), onContextMenu: () => { const cm = ContextMenu.Instance; !Doc.noviceMode && cm?.addItem({ description: 'Recognize Writing', event: this.analyzeStrokes, icon: 'paint-brush' }); cm?.addItem({ description: 'Toggle Mask', event: () => InkingStroke.toggleMask(this.dataDoc), icon: 'paint-brush' }); - cm?.addItem({ description: 'Edit Points', event: action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton)), icon: 'paint-brush' }); + cm?.addItem({ + description: 'Edit Points', + event: action(() => { + InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton; + }), + icon: 'paint-brush', + }); }, }; return ( @@ -438,10 +453,11 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() <svg className="inkStroke" style={{ - transform: isInkMask ? `rotate(-${NumCast(this._props.CollectionFreeFormDocumentView?.()._props.rotation ?? 0)}deg) translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined, + transform: isInkMask ? `rotate(-${NumCast(this._props.LocalRotation?.() ?? 0)}deg) translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined, // mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset', cursor: this._props.isSelected() ? 'default' : undefined, }} + // eslint-disable-next-line react/jsx-props-no-spreading {...interactions}> {clickableLine(this.onPointerDown, isInkMask)} {isInkMask ? null : inkLine} @@ -455,18 +471,19 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() width: NumCast(this.layoutDoc._width), transform: `scale(${this._props.NativeDimScaling?.() || 1})`, transformOrigin: 'top left', - //top: (this._props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this._props.NativeDimScaling?.() || 1)) / 2, + // top: (this._props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this._props.NativeDimScaling?.() || 1)) / 2, }}> <FormattedTextBox + // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} setHeight={undefined} setContentViewBox={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text) yPadding={10} xPadding={10} fieldKey="text" - //dontRegisterView={true} - noSidebar={true} - dontScale={true} + // dontRegisterView={true} + noSidebar + dontScale isContentActive={this._props.isContentActive} /> </div> @@ -475,67 +492,17 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>() ); } } - -export function SetActiveInkWidth(width: string): void { - !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); -} -export function SetActiveBezierApprox(bezier: string): void { - ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier); -} -export function SetActiveInkColor(value: string) { - ActiveInkPen() && (ActiveInkPen().activeInkColor = value); -} -export function SetActiveIsInkMask(value: boolean) { - ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value); -} -export function SetActiveInkHideTextLabels(value: boolean) { - ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value); -} -export function SetActiveFillColor(value: string) { - ActiveInkPen() && (ActiveInkPen().activeFillColor = value); -} -export function SetActiveArrowStart(value: string) { - ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); -} -export function SetActiveArrowEnd(value: string) { - ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); -} -export function SetActiveArrowScale(value: number) { - ActiveInkPen() && (ActiveInkPen().activeArrowScale = value); -} -export function SetActiveDash(dash: string): void { - !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); -} -export function ActiveInkPen(): Doc { - return Doc.UserDoc(); -} -export function ActiveInkColor(): string { - return StrCast(ActiveInkPen()?.activeInkColor, 'black'); -} -export function ActiveFillColor(): string { - return StrCast(ActiveInkPen()?.activeFillColor, ''); -} -export function ActiveIsInkMask(): boolean { - return BoolCast(ActiveInkPen()?.activeIsInkMask, false); -} -export function ActiveInkHideTextLabels(): boolean { - return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); -} -export function ActiveArrowStart(): string { - return StrCast(ActiveInkPen()?.activeArrowStart, ''); -} -export function ActiveArrowEnd(): string { - return StrCast(ActiveInkPen()?.activeArrowEnd, ''); -} -export function ActiveArrowScale(): number { - return NumCast(ActiveInkPen()?.activeArrowScale, 1); -} -export function ActiveDash(): string { - return StrCast(ActiveInkPen()?.activeDash, '0'); -} -export function ActiveInkWidth(): number { - return Number(ActiveInkPen()?.activeInkWidth); -} -export function ActiveInkBezierApprox(): string { - return StrCast(ActiveInkPen()?.activeInkBezier); -} +Docs.Prototypes.TemplateMap.set(DocumentType.INK, { + // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method + layout: { view: InkingStroke, dataField: 'stroke' }, + options: { + acl: '', + systemIcon: 'BsFillPencilFill', // + _layout_nativeDimEditable: true, + _layout_reflowVertical: true, + _layout_reflowHorizontal: true, + layout_hideDecorationTitle: true, // don't show title when selected + _layout_fitWidth: false, + layout_isSvg: true, + }, +}); |