From 3ca852f483e0868975678d3db97d72d637d8414c Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 3 Apr 2022 01:03:38 -0400 Subject: fixed ink handles to work in lightbox, so re-enabled open in lightbox for selected ink. fixed double-click to not lock out in some cases because pendingDoubleClick never gets unset. fixed text to not jitter scroll bar when typing enter at end of autosize texst box. --- src/client/views/InkStrokeProperties.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/client/views/InkStrokeProperties.ts') diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 41cace1e3..e4486fc78 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -207,7 +207,7 @@ export class InkStrokeProperties { @undoBatch @action stretchInk = (inkStrokes: DocumentView[], scaling: number, scrpt: PointData, scrVec: PointData, scaleUniformly: boolean) => { - this.applyFunction(inkStrokes, (view: DocumentView, ink: InkData, xScale: number, yScale: number, inkStrokeWidth: number) => { + this.applyFunction(inkStrokes, (view: DocumentView, ink: InkData) => { const ptFromScreen = view.ComponentView?.ptFromScreen; const ptToScreen = view.ComponentView?.ptToScreen; return !ptToScreen || !ptFromScreen ? ink : @@ -227,7 +227,7 @@ export class InkStrokeProperties { @undoBatch @action moveControlPtHandle = (inkView: DocumentView, deltaX: number, deltaY: number, controlIndex: number, origInk?: InkData) => - this.applyFunction(inkView, (view: DocumentView, ink: InkData, xScale: number, yScale: number) => { + this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const order = controlIndex % 4; const closed = InkingStroke.IsClosed(ink); if (origInk && this._currentPoint > 0 && this._currentPoint < ink.length - 1) { @@ -435,13 +435,13 @@ export class InkStrokeProperties { @undoBatch @action moveTangentHandle = (inkView: DocumentView, deltaX: number, deltaY: number, handleIndex: number, oppositeHandleIndex: number, controlIndex: number) => - this.applyFunction(inkView, (view: DocumentView, ink: InkData, xScale: number, yScale: number) => { + this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const doc = view.rootDoc; const closed = InkingStroke.IsClosed(ink); const oldHandlePoint = ink[handleIndex]; const oppositeHandlePoint = ink[oppositeHandleIndex]; const controlPoint = ink[controlIndex]; - const newHandlePoint = { X: ink[handleIndex].X - deltaX / xScale, Y: ink[handleIndex].Y - deltaY / yScale }; + const newHandlePoint = { X: ink[handleIndex].X - deltaX, Y: ink[handleIndex].Y - deltaY }; const inkCopy = ink.slice(); inkCopy[handleIndex] = newHandlePoint; const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number")); -- cgit v1.2.3-70-g09d2 From a2df645d2ffe83be24c20997c26eaf7257e847c0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 2 May 2022 18:09:22 -0400 Subject: fixed scaling ink label in lightbox,etc views. changed ink strokes so that clicking on label of closed stroke is lower preceden than clicking on line. fixed fontsize UI for setting ink label sizes. can no longer slide ink pts that are cusps along curve. --- src/client/views/InkStrokeProperties.ts | 61 +++++++++++----------- src/client/views/InkingStroke.tsx | 44 +++++++++++----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 3 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 3 +- src/client/views/nodes/button/FontIconBox.tsx | 2 +- .../views/nodes/formattedText/RichTextMenu.tsx | 19 ++++--- src/client/views/pdf/PDFViewer.tsx | 3 +- 9 files changed, 84 insertions(+), 57 deletions(-) (limited to 'src/client/views/InkStrokeProperties.ts') diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index e4486fc78..922f309d7 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -230,42 +230,41 @@ export class InkStrokeProperties { this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const order = controlIndex % 4; const closed = InkingStroke.IsClosed(ink); - if (origInk && this._currentPoint > 0 && this._currentPoint < ink.length - 1) { + const brokenIndices = Cast(inkView.props.Document.brokenInkIndices, listSpec("number"), []); + if (origInk && this._currentPoint > 0 && this._currentPoint < ink.length - 1 && brokenIndices.findIndex(value => value === controlIndex) === -1) { const cpt_before = ink[controlIndex]; const cpt = { X: cpt_before.X + deltaX, Y: cpt_before.Y + deltaY }; - if (true) { - const newink = origInk.slice(); - const start = this._currentPoint === 0 ? 0 : this._currentPoint - 4; - const splicedPoints = origInk.slice(start, start + (this._currentPoint === 0 || this._currentPoint === ink.length - 1 ? 4 : 8)); - const { nearestT, nearestSeg } = InkStrokeProperties.nearestPtToStroke(splicedPoints, cpt); - const samplesLeft: Point[] = []; - const samplesRight: Point[] = []; - var startDir = { x: 0, y: 0 }; - var endDir = { x: 0, y: 0 }; - for (var i = 0; i < nearestSeg / 4 + 1; i++) { - const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); - if (i === 0) startDir = bez.derivative(0); - if (i === nearestSeg / 4) endDir = bez.derivative(nearestT); - for (var t = 0; t < (i === nearestSeg / 4 ? nearestT + .05 : 1); t += 0.05) { - const pt = bez.compute(i !== nearestSeg / 4 ? t : Math.min(nearestT, t)); - samplesLeft.push(new Point(pt.x, pt.y)); - } + const newink = origInk.slice(); + const start = this._currentPoint === 0 ? 0 : this._currentPoint - 4; + const splicedPoints = origInk.slice(start, start + (this._currentPoint === 0 || this._currentPoint === ink.length - 1 ? 4 : 8)); + const { nearestT, nearestSeg } = InkStrokeProperties.nearestPtToStroke(splicedPoints, cpt); + const samplesLeft: Point[] = []; + const samplesRight: Point[] = []; + var startDir = { x: 0, y: 0 }; + var endDir = { x: 0, y: 0 }; + for (var i = 0; i < nearestSeg / 4 + 1; i++) { + const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); + if (i === 0) startDir = bez.derivative(0); + if (i === nearestSeg / 4) endDir = bez.derivative(nearestT); + for (var t = 0; t < (i === nearestSeg / 4 ? nearestT + .05 : 1); t += 0.05) { + const pt = bez.compute(i !== nearestSeg / 4 ? t : Math.min(nearestT, t)); + samplesLeft.push(new Point(pt.x, pt.y)); } - var { finalCtrls } = FitOneCurve(samplesLeft, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); - for (var i = nearestSeg / 4; i < splicedPoints.length / 4; i++) { - const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); - if (i === nearestSeg / 4) startDir = bez.derivative(nearestT); - if (i === splicedPoints.length / 4 - 1) endDir = bez.derivative(1); - for (var t = i === nearestSeg / 4 ? nearestT : 0; t < (i === nearestSeg / 4 ? 1 + .05 + 1e-7 : 1 + 1e-7); t += 0.05) { - const pt = bez.compute(Math.min(1, t)); - samplesRight.push(new Point(pt.x, pt.y)); - } + } + var { finalCtrls } = FitOneCurve(samplesLeft, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); + for (var i = nearestSeg / 4; i < splicedPoints.length / 4; i++) { + const bez = new Bezier(splicedPoints.slice(i * 4, i * 4 + 4).map(p => ({ x: p.X, y: p.Y }))); + if (i === nearestSeg / 4) startDir = bez.derivative(nearestT); + if (i === splicedPoints.length / 4 - 1) endDir = bez.derivative(1); + for (var t = i === nearestSeg / 4 ? nearestT : 0; t < (i === nearestSeg / 4 ? 1 + .05 + 1e-7 : 1 + 1e-7); t += 0.05) { + const pt = bez.compute(Math.min(1, t)); + samplesRight.push(new Point(pt.x, pt.y)); } - const { finalCtrls: rightCtrls, error: errorRight } = FitOneCurve(samplesRight, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); - finalCtrls = finalCtrls.concat(rightCtrls); - newink.splice(this._currentPoint - 4, 8, ...finalCtrls); - return newink; } + const { finalCtrls: rightCtrls, error: errorRight } = FitOneCurve(samplesRight, { X: startDir.x, Y: startDir.y }, { X: endDir.x, Y: endDir.y }); + finalCtrls = finalCtrls.concat(rightCtrls); + newink.splice(this._currentPoint - 4, 8, ...finalCtrls); + return newink; } return ink.map((pt, i) => { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 06671961d..1871ab5a4 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -328,12 +328,25 @@ export class InkingStroke extends ViewBoxBaseComponent() { 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 = (downHdlr?: (e: React.PointerEvent) => void) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, inkStrokeWidth, inkStrokeWidth + (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, + StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker, markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, false, downHdlr); + const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", "")); + const lineHeightGuess = (+getComputedStyle(document.body).lineHeight.replace("px", "")) / (+getComputedStyle(document.body).fontSize.replace("px", "")); + const interactions = { + 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.UserDoc().noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); + cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); + cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); + } + }; return
() { mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset", cursor: this.props.isSelected() ? "default" : undefined }} - onPointerLeave={action(e => this._nearestScrPt = undefined)} - onPointerMove={this.props.isSelected() ? this.onPointerMove : undefined} - onClick={e => this._handledClick && e.stopPropagation()} - onContextMenu={() => { - const cm = ContextMenu.Instance; - !Doc.UserDoc().noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); - cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); - cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); - }} + {...(!closed ? interactions : {})} > - {clickableLine(this.onPointerDown)} {inkLine} + {clickableLine(this.onPointerDown)} {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) :
() { yPadding={10} xPadding={10} fieldKey={"text"} - fontSize={12} + fontSize={fsize} dontRegisterView={true} noSidebar={true} dontScale={true} @@ -374,6 +382,16 @@ export class InkingStroke extends ViewBoxBaseComponent() { />
} + {!closed ? null : + {clickableLine(this.onPointerDown, true)} + }
; } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3f16d3c49..edadd59c0 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -38,7 +38,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this._savedAnnotations; render() { TraceMobx(); @@ -408,7 +409,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.props.PanelWidth() / 5; infoHeight = () => this.props.PanelHeight() / 5; anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; - + savedAnnotations = () => this._savedAnnotations; render() { const renderAnnotations = (docFilters?: () => string[]) => (null); // bcz: commmented this out. Otherwise, any documents that are rendered with an InfoWindow of a marker @@ -618,7 +618,7 @@ export class MapBox extends ViewBoxAnnotatableComponent} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index e57cb1abe..c8b72990f 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -800,6 +800,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent; } + savedAnnotations = () => this._savedAnnotations; render() { const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding); const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad; @@ -847,7 +848,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent} diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index ca13590de..d3ff2586b 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -656,7 +656,7 @@ ScriptingGlobals.add(function setFontHighlight(color?: string, checkResult?: boo ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: boolean) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; if (checkResult) { - return (editorView ? RichTextMenu.Instance.fontSize : StrCast(Doc.UserDoc().fontSize, "10px")).replace("px", ""); + return RichTextMenu.Instance.fontSize.replace("px", ""); } if (typeof size === "number") size = size.toString(); if (size && Number(size).toString() === size) size += "px"; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 4814d6e9a..c5f76cc8d 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -9,7 +9,7 @@ import { wrapInList } from "prosemirror-schema-list"; import { EditorState, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { Doc } from "../../../../fields/Doc"; -import { Cast, StrCast } from "../../../../fields/Types"; +import { Cast, NumCast, StrCast } from "../../../../fields/Types"; import { DocServer } from "../../../DocServer"; import { LinkManager } from "../../../util/LinkManager"; import { SelectionManager } from "../../../util/SelectionManager"; @@ -118,7 +118,7 @@ export class RichTextMenu extends AntimodeMenu { this.activeListType = this.getActiveListStyle(); this._activeAlignment = this.getActiveAlignment(); this._activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; - this._activeFontSize = !activeSizes.length ? "13px" : activeSizes[0]; + this._activeFontSize = !activeSizes.length ? StrCast(this.TextView.Document.fontSize, StrCast(Doc.UserDoc().fontSize, "10px")) : activeSizes[0]; this._activeFontColor = !activeColors.length ? "black" : activeColors.length > 0 ? String(activeColors[0]) : "..."; this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length > 0 ? String(activeHighlights[0]) : "..."; @@ -310,10 +310,17 @@ export class RichTextMenu extends AntimodeMenu { setFontSize = (fontSize: string) => { if (this.view) { - const fmark = this.view.state.schema.marks.pFontSize.create({ fontSize }); - this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); - this.view.focus(); - this.updateMenu(this.view, undefined, this.props); + if (this.view.state.selection.from === 1 && this.view.state.selection.empty && + (!this.view.state.doc.nodeAt(1) || !this.view.state.doc.nodeAt(1)?.marks.some(m => m.type.name === fontSize))) { + this.TextView.dataDoc.fontSize = fontSize; + this.view.focus(); + this.updateMenu(this.view, undefined, this.props); + } else { + const fmark = this.view.state.schema.marks.pFontSize.create({ fontSize }); + this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); + this.view.focus(); + this.updateMenu(this.view, undefined, this.props); + } } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index b55b2cf44..d3876906e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -562,6 +562,7 @@ export class PDFViewer extends React.Component { ; } contentZoom = () => this._zoomed; + savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); return
@@ -586,7 +587,7 @@ export class PDFViewer extends React.Component { addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)} docView={this.props.docViewPath().lastElement()} finishMarquee={this.finishMarquee} - savedAnnotations={this._savedAnnotations} + savedAnnotations={this.savedAnnotations} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />}
-- cgit v1.2.3-70-g09d2 From a969d0212c69844cbbe82b24f124a496145a1d9b Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 2 May 2022 18:38:03 -0400 Subject: disallowed dragging a control point past another control point. --- src/client/views/InkStrokeProperties.ts | 1 + src/client/views/InkingStroke.tsx | 3 +++ 2 files changed, 4 insertions(+) (limited to 'src/client/views/InkStrokeProperties.ts') diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 922f309d7..0449da483 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -238,6 +238,7 @@ export class InkStrokeProperties { const start = this._currentPoint === 0 ? 0 : this._currentPoint - 4; const splicedPoints = origInk.slice(start, start + (this._currentPoint === 0 || this._currentPoint === ink.length - 1 ? 4 : 8)); const { nearestT, nearestSeg } = InkStrokeProperties.nearestPtToStroke(splicedPoints, cpt); + if ((nearestSeg === 0 && nearestT < 1e-1) || (nearestSeg === 4 && (1 - nearestT) < 1e-1)) return ink.slice(); const samplesLeft: Point[] = []; const samplesRight: Point[] = []; var startDir = { x: 0, y: 0 }; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 1871ab5a4..5e9990444 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -335,6 +335,9 @@ export class InkingStroke extends ViewBoxBaseComponent() { markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, false, downHdlr); const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", "")); + // 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 interactions = { onPointerLeave: action(() => this._nearestScrPt = undefined), -- cgit v1.2.3-70-g09d2