aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/InkingStroke.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/InkingStroke.tsx')
-rw-r--r--src/client/views/InkingStroke.tsx57
1 files changed, 38 insertions, 19 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 40fe6aa68..06671961d 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -25,16 +25,16 @@ import { action, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import { Doc, WidthSym } from "../../fields/Doc";
import { InkData, InkField, InkTool } from "../../fields/InkField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
+import { BoolCast, Cast, NumCast, RTFCast, StrCast } from "../../fields/Types";
import { TraceMobx } from "../../fields/util";
-import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils";
+import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils";
import { CognitiveServices } from "../cognitive_services/CognitiveServices";
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 { DocComponent, ViewBoxBaseComponent } from "./DocComponent";
import { Colors } from "./global/globalEnums";
import { InkControlPtHandles, InkEndPtHandles } from "./InkControlPtHandles";
import "./InkStroke.scss";
@@ -43,6 +43,7 @@ import { InkTangentHandles } from "./InkTangentHandles";
import { FieldView, FieldViewProps } from "./nodes/FieldView";
import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox";
import Color = require("color");
+import { DocComponentView } from "./nodes/DocumentView";
@observer
export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -67,6 +68,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
this._selDisposer?.();
}
+ // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke
+ // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc)
+ screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1);
+
+ getAnchor = () => {
+ console.log(document.activeElement);
+ return this._subContentView?.getAnchor?.() || this.rootDoc;
+ }
+
+ scrollFocus = (textAnchor: Doc, smooth: boolean) => {
+ return this._subContentView?.scrollFocus?.(textAnchor, smooth);
+ }
/**
* @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space);
* DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since
@@ -119,7 +132,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
this._handledClick = false;
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(
+ 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 { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY });
@@ -160,7 +173,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
*/
ptFromScreen = (scrPt: { X: number, Y: number }) => {
const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
- const docPt = this.props.ScreenToLocalTransform().transformPoint(scrPt.X, scrPt.Y);
+ const docPt = this.screenToLocal().transformPoint(scrPt.X, scrPt.Y);
const inkPt = {
X: (docPt[0] - inkStrokeWidth / 2) / inkScaleX + inkStrokeWidth / 2 + inkLeft,
Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop,
@@ -178,7 +191,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2,
Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2
};
- const scrPt = this.props.ScreenToLocalTransform().inverse().transformPoint(docPt.X, docPt.Y);
+ const scrPt = this.screenToLocal().inverse().transformPoint(docPt.X, docPt.Y);
return { X: scrPt[0], Y: scrPt[1] };
}
@@ -192,7 +205,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
snapPt = (scrPt: { X: number, Y: number }, excludeSegs?: number[]) => {
const { inkData } = this.inkScaledData();
const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, this.ptFromScreen(scrPt), excludeSegs ?? []);
- return { nearestPt, distance: distance * this.props.ScreenToLocalTransform().inverse().Scale };
+ return { nearestPt, distance: distance * this.screenToLocal().inverse().Scale };
}
/**
@@ -220,10 +233,14 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
};
}
+ //
+ // this updates the highlight for the nearest point on the curve to the cursor.
+ // if the user double clicks, this highlighted point will be added as a control point in the curve.
+ //
@action
onPointerMove = (e: React.PointerEvent) => {
const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
- const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(
+ 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 { distance, nearestT, nearestSeg, nearestPt } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY });
@@ -246,10 +263,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 screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.props.ScreenToLocalTransform().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke
+ 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.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
- const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(
+ 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;
@@ -264,9 +281,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
<InkEndPtHandles
inkView={this.props.docViewPath().lastElement()}
inkDoc={inkDoc}
- startPt={this.ptToScreen(inkData[0])}
- endPt={this.ptToScreen(inkData.lastElement())}
- screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /></div>) :
+ startPt={screenPts[0]}
+ endPt={screenPts.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),
@@ -277,17 +295,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
inkCtrlPoints={inkData}
screenCtrlPoints={screenHdlPts}
nearestScreenPt={this.nearestScreenPt}
- screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
+ screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
<InkTangentHandles
inkView={this.props.docViewPath().lastElement()}
inkDoc={inkDoc}
screenCtrlPoints={screenHdlPts}
screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
+ ScreenToLocalTransform={this.screenToLocal} />
</div>;
}
+ _subContentView: DocComponentView | undefined;
+ setSubContentView = (doc: DocComponentView) => this._subContentView = doc;
render() {
TraceMobx();
const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
@@ -315,7 +334,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker,
markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0,
false, downHdlr);
-
return <div className="inkStroke-wrapper">
<svg className="inkStroke"
style={{
@@ -336,7 +354,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
{clickableLine(this.onPointerDown)}
{inkLine}
</svg>
- {!closed ? (null) :
+ {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) :
<div className="inkStroke-text" style={{
color: StrCast(this.layoutDoc.textColor, "black"),
pointerEvents: this.props.isDocumentActive?.() ? "all" : undefined,
@@ -344,6 +362,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
}}>
<FormattedTextBox
{...OmitKeys(this.props, ['children']).omit}
+ setContentView={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"}