aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/views/GestureOverlay.scss2
-rw-r--r--src/client/views/GestureOverlay.tsx69
-rw-r--r--src/client/views/InkingControl.tsx21
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/Palette.scss18
-rw-r--r--src/client/views/Palette.tsx25
-rw-r--r--src/client/views/Touchable.tsx18
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss14
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx54
-rw-r--r--src/client/views/nodes/DocumentView.tsx17
10 files changed, 184 insertions, 58 deletions
diff --git a/src/client/views/GestureOverlay.scss b/src/client/views/GestureOverlay.scss
index cbc1b6e7d..31601efd4 100644
--- a/src/client/views/GestureOverlay.scss
+++ b/src/client/views/GestureOverlay.scss
@@ -1,6 +1,6 @@
.gestureOverlay-cont {
width: 100vw;
- height: 100vw;
+ height: 100vh;
position: absolute;
top: 0;
left: 0;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index c88e3f7ae..848927912 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -43,9 +43,43 @@ export default class GestureOverlay extends Touchable {
@action
onPointerMove = (e: PointerEvent) => {
- this._points.push({ X: e.clientX, Y: e.clientY });
- e.stopPropagation();
- e.preventDefault();
+ if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) {
+ this._points.push({ X: e.clientX, Y: e.clientY });
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }
+
+ handleLineGesture = (): boolean => {
+ let actionPerformed = false;
+ const B = this.svgBounds;
+ const ep1 = this._points[0];
+ const ep2 = this._points[this._points.length - 1];
+
+ const target1 = document.elementFromPoint(ep1.X, ep1.Y);
+ const target2 = document.elementFromPoint(ep2.X, ep2.Y);
+ const callback = (doc: Doc) => {
+ if (!this._d1) {
+ this._d1 = doc;
+ }
+ else if (this._d1 !== doc && !LinkManager.Instance.doesLinkExist(this._d1, doc)) {
+ DocUtils.MakeLink({ doc: this._d1 }, { doc: doc });
+ actionPerformed = true;
+ }
+ }
+ const ge = new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
+ {
+ bubbles: true,
+ detail: {
+ points: this._points,
+ gesture: GestureUtils.Gestures.Line,
+ bounds: B,
+ callbackFn: callback
+ }
+ });
+ target1?.dispatchEvent(ge);
+ target2?.dispatchEvent(ge);
+ return actionPerformed;
}
@action
@@ -72,31 +106,10 @@ export default class GestureOverlay extends Touchable {
actionPerformed = true;
break;
case GestureUtils.Gestures.Line:
- const ep1 = this._points[0];
- const ep2 = this._points[this._points.length - 1];
- const target1 = document.elementFromPoint(ep1.X, ep1.Y);
- const target2 = document.elementFromPoint(ep2.X, ep2.Y);
- const callback = (doc: Doc) => {
- if (!this._d1) {
- this._d1 = doc;
- }
- else if (this._d1 !== doc && !LinkManager.Instance.doesLinkExist(this._d1, doc)) {
- DocUtils.MakeLink({ doc: this._d1 }, { doc: doc });
- actionPerformed = true;
- }
- }
- const ge = new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
- {
- bubbles: true,
- detail: {
- points: this._points,
- gesture: GestureUtils.Gestures.Line,
- bounds: B,
- callbackFn: callback
- }
- })
- target1?.dispatchEvent(ge);
- target2?.dispatchEvent(ge);
+ actionPerformed = this.handleLineGesture();
+ break;
+ case GestureUtils.Gestures.Scribble:
+ console.log("scribble");
break;
}
if (actionPerformed) {
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index e33f193b8..243123352 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -4,19 +4,18 @@ import { Doc } from "../../new_fields/Doc";
import { InkTool } from "../../new_fields/InkField";
import { List } from "../../new_fields/List";
import { listSpec } from "../../new_fields/Schema";
-import { Cast, NumCast, StrCast } from "../../new_fields/Types";
+import { Cast, NumCast, StrCast, FieldValue } from "../../new_fields/Types";
import { Utils } from "../../Utils";
import { Scripting } from "../util/Scripting";
import { SelectionManager } from "../util/SelectionManager";
import { undoBatch, UndoManager } from "../util/UndoManager";
import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
-
export class InkingControl {
@observable static Instance: InkingControl;
- @observable private _selectedTool: InkTool = InkTool.None;
- @observable private _selectedColor: string = "rgb(244, 67, 54)";
- @observable private _selectedWidth: string = "5";
+ @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(CurrentUserUtils.UserDocument.inkTool)) ?? InkTool.None; }
+ @computed private get _selectedColor(): string { return FieldValue(StrCast(CurrentUserUtils.UserDocument.inkColor)) ?? "rgb(244, 67, 54)"; }
+ @computed private get _selectedWidth(): string { return FieldValue(StrCast(CurrentUserUtils.UserDocument.inkWidth)) ?? "5"; }
@observable public _open: boolean = false;
constructor() {
@@ -24,7 +23,8 @@ export class InkingControl {
}
switchTool = action((tool: InkTool): void => {
- this._selectedTool = tool;
+ // this._selectedTool = tool;
+ CurrentUserUtils.UserDocument.inkTool = tool;
});
decimalToHexString(number: number) {
if (number < 0) {
@@ -36,7 +36,7 @@ export class InkingControl {
@undoBatch
switchColor = action((color: ColorState): void => {
- this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
+ CurrentUserUtils.UserDocument.inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
if (InkingControl.Instance.selectedTool === InkTool.None) {
const selected = SelectionManager.SelectedDocuments();
@@ -99,7 +99,8 @@ export class InkingControl {
});
@action
switchWidth = (width: string): void => {
- this._selectedWidth = width;
+ // this._selectedWidth = width;
+ CurrentUserUtils.UserDocument.inkWidth = width;
}
@computed
@@ -114,7 +115,8 @@ export class InkingControl {
@action
updateSelectedColor(value: string) {
- this._selectedColor = value;
+ // this._selectedColor = value;
+ CurrentUserUtils.UserDocument.inkColor = value;
}
@computed
@@ -127,6 +129,7 @@ Scripting.addGlobal(function activatePen(pen: any, width: any, color: any) { Ink
Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any) { InkingControl.Instance.switchTool(pen ? InkTool.Highlighter : InkTool.None); InkingControl.Instance.switchWidth(width); InkingControl.Instance.updateSelectedColor(color); });
Scripting.addGlobal(function activateEraser(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Eraser : InkTool.None); });
Scripting.addGlobal(function activateScrubber(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Scrubber : InkTool.None); });
+Scripting.addGlobal(function activateStamp(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Stamp : InkTool.None); });
Scripting.addGlobal(function deactivateInk() { return InkingControl.Instance.switchTool(InkTool.None); });
Scripting.addGlobal(function setInkWidth(width: any) { return InkingControl.Instance.switchWidth(width); });
Scripting.addGlobal(function setInkColor(color: any) { return InkingControl.Instance.updateSelectedColor(color); }); \ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 14c1803c0..f463ca306 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,7 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import {
faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight,
- faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt
+ faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faPhone, faStamp
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
@@ -135,6 +135,8 @@ export class MainView extends React.Component {
library.add(faChevronRight);
library.add(faEllipsisV);
library.add(faMusic);
+ library.add(faPhone);
+ library.add(faStamp);
this.initEventListeners();
this.initAuthenticationRouters();
}
diff --git a/src/client/views/Palette.scss b/src/client/views/Palette.scss
new file mode 100644
index 000000000..60004c81f
--- /dev/null
+++ b/src/client/views/Palette.scss
@@ -0,0 +1,18 @@
+.palette-container {
+ .palette-thumb {
+ width: 300px;
+ height: 300px;
+ touch-action: pan-x;
+ overflow: scroll;
+
+ .palette-thumbContent {
+ width: 100%;
+ height: 100%;
+
+ .palette-button {
+ width: 100px;
+ height: 100px;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
new file mode 100644
index 000000000..390b7e2c2
--- /dev/null
+++ b/src/client/views/Palette.tsx
@@ -0,0 +1,25 @@
+import * as React from "react";
+import "./Palette.scss";
+import { PointData } from "../../new_fields/InkField";
+
+export interface PaletteProps {
+ x: number;
+ y: number;
+ thumb: number[];
+}
+
+export default class Palette extends React.Component<PaletteProps> {
+ render() {
+ return (
+ <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
+ <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
+ <div className="palette-thumbContent">
+ <div className="palette-button" style={{ background: "green" }} onPointerDown={() => console.log("hi")}>1</div>
+ <div className="palette-button" style={{ background: "red" }}>2</div>
+ <div className="palette-button" style={{ background: "blue" }}>3</div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index 251cd41e5..3eb66ff72 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -1,6 +1,7 @@
import * as React from 'react';
import { action } from 'mobx';
import { InteractionUtils } from '../util/InteractionUtils';
+import { SelectionManager } from '../util/SelectionManager';
const HOLD_DURATION = 1000;
@@ -34,11 +35,19 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
case 1:
this.handle1PointerDown(e);
e.persist();
+ if (this.holdTimer) {
+ clearTimeout(this.holdTimer)
+ this.holdTimer = undefined;
+ }
this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(e), HOLD_DURATION);
+ console.log(this.holdTimer);
break;
case 2:
this.handle2PointersDown(e);
break;
+ case 5:
+ this.handleHandDown(e);
+ break;
}
}
}
@@ -54,7 +63,9 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return;
this._touchDrag = true;
if (this.holdTimer) {
+ console.log("clear");
clearTimeout(this.holdTimer);
+ this.holdTimer = undefined;
}
switch (myTouches.length) {
case 1:
@@ -88,7 +99,9 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
}
}
if (this.holdTimer) {
+ console.log("clear");
clearTimeout(this.holdTimer);
+ this.holdTimer = undefined;
}
this._touchDrag = false;
e.stopPropagation();
@@ -137,4 +150,9 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
e.stopPropagation();
e.preventDefault();
}
+
+ handleHandDown = (e: React.TouchEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ }
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index cb95dcbbc..8b3d332af 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -15,6 +15,11 @@
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
+ touch-action: none;
+
+ div {
+ touch-action: none;
+ }
.collectionSchemaView-tableContainer {
@@ -49,7 +54,7 @@
.rt-table {
height: 100%;
display: -webkit-inline-box;
- direction: ltr;
+ direction: ltr;
overflow: visible;
}
@@ -202,7 +207,7 @@ button.add-column {
border-bottom: 1px solid lightgray;
&:first-child {
- padding-top : 0;
+ padding-top: 0;
}
&:last-child {
@@ -231,7 +236,7 @@ button.add-column {
transition: background-color 0.2s;
&:hover {
- background-color: $light-color-secondary;
+ background-color: $light-color-secondary;
}
&.active {
@@ -267,7 +272,7 @@ button.add-column {
overflow-y: scroll;
position: absolute;
top: 28px;
- box-shadow: 0 10px 16px rgba(0,0,0,0.1);
+ box-shadow: 0 10px 16px rgba(0, 0, 0, 0.1);
.key-option {
background-color: $light-color;
@@ -380,6 +385,7 @@ button.add-column {
&.editing {
padding: 0;
+
input {
outline: 0;
border: none;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9656debf3..d7cccc036 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -44,6 +44,7 @@ import { TraceMobx } from "../../../../new_fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
import { LinkManager } from "../../../util/LinkManager";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
+import Palette from "../../Palette";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -444,6 +445,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
return;
}
+ if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
+ return;
+ }
if (!e.cancelBubble) {
const selectedTool = InkingControl.Instance.selectedTool;
if (selectedTool === InkTool.None) {
@@ -844,6 +848,53 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ["inkAnalysis", "handwriting"], inkData);
}
+ private thumbIdentifier?: number;
+ private hand?: React.Touch[];
+
+ @action
+ handleHandDown = (e: React.TouchEvent) => {
+ const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints);
+ this.hand = fingers;
+ const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
+ this.thumbIdentifier = thumb?.identifier;
+ const others = fingers.filter(f => f !== thumb);
+ const minX = Math.min(...others.map(f => f.clientX));
+ const minY = Math.min(...others.map(f => f.clientY));
+ const t = this.getTransform().transformPoint(minX, minY);
+ const th = this.getTransform().transformPoint(thumb.clientX, thumb.clientY);
+ this._palette = <Palette x={t[0]} y={t[1]} thumb={th} />;
+
+ document.removeEventListener("touchmove", this.onTouch);
+ document.removeEventListener("touchmove", this.handleHandMove);
+ document.addEventListener("touchmove", this.handleHandMove);
+ document.removeEventListener("touchend", this.handleHandUp);
+ document.addEventListener("touchend", this.handleHandUp);
+ }
+
+ @action
+ handleHandMove = (e: TouchEvent) => {
+ for (let i = 0; i < e.changedTouches.length; i++) {
+ const pt = e.changedTouches.item(i);
+ if (pt?.identifier === this.thumbIdentifier) {
+ }
+ }
+ }
+
+ @action
+ handleHandUp = (e: TouchEvent) => {
+ console.log(e.changedTouches.length);
+ this.onTouchEnd(e);
+ if (this.prevPoints.size < 3) {
+ if (this.hand) {
+ for (const h of this.hand) {
+ this.prevPoints.has(h.identifier) && this.prevPoints.delete(h.identifier);
+ }
+ }
+ this._palette = undefined;
+ document.removeEventListener("touchend", this.handleHandUp);
+ }
+ }
+
onContextMenu = (e: React.MouseEvent) => {
const layoutItems: ContextMenuProps[] = [];
@@ -907,9 +958,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
];
}
+ @observable private _palette?: JSX.Element;
+
children = () => {
const eles: JSX.Element[] = [];
this.extensionDoc && (eles.push(...this.childViews()));
+ this._palette && (eles.push(this._palette));
// this.currentStroke && (eles.push(this.currentStroke));
eles.push(<CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />);
return eles;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7d6b8bf01..415d0e2ef 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -256,7 +256,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
document.removeEventListener("touchend", this.onTouchEnd);
document.addEventListener("touchend", this.onTouchEnd);
if ((e.nativeEvent as any).formattedHandled) e.stopPropagation();
- console.log("down")
}
}
@@ -327,6 +326,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight);
if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) {
layoutDoc.ignoreAspect = false;
+
layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0;
layoutDoc.nativeHeight = nheight = layoutDoc.height || 0;
}
@@ -357,8 +357,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false);
}
}
- // let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX))
- // this.props.Document.width = newWidth;
e.stopPropagation();
e.preventDefault();
}
@@ -374,19 +372,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
return;
}
- // if (!InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE)) {
- // e.stopPropagation();
- // return;
- // }
if (!e.nativeEvent.cancelBubble || this.Document.onClick || this.Document.onDragStart) {
- // if ((e.nativeEvent.cancelBubble && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)))
- // // return if we're inking, and not selecting a button document
- // || (InkingControl.Instance.selectedTool !== InkTool.None && !this.Document.onClick)
- // // return if using pen or eraser
- // || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || InteractionUtils.IsType(e, InteractionUtils.ERASERTYPE)) {
- // return;
- // }
-
this._downX = e.clientX;
this._downY = e.clientY;
this._hitTemplateDrag = false;
@@ -408,6 +394,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onPointerMove = (e: PointerEvent): void => {
if ((e as any).formattedHandled) { e.stopPropagation(); return; }
+ if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) return;
if (e.cancelBubble && this.active) {
document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
}