From 4f1f20a52a5c01b3046a56f37b6c7c029d3e10f0 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 13 Mar 2019 15:17:53 -0400 Subject: fixed a variety of things related to selection, dragging, marqueeing --- .../views/collections/CollectionVideoView.tsx | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/client/views/collections/CollectionVideoView.tsx (limited to 'src/client/views/collections/CollectionVideoView.tsx') diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx new file mode 100644 index 000000000..a6471f53c --- /dev/null +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -0,0 +1,50 @@ +import { action, computed } from "mobx"; +import { observer } from "mobx-react"; +import { Document } from "../../../fields/Document"; +import { KeyStore } from "../../../fields/KeyStore"; +import { ContextMenu } from "../ContextMenu"; +import { CollectionView, CollectionViewType } from "./CollectionView"; +import { CollectionViewProps } from "./CollectionViewBase"; +import React = require("react"); +import { FieldId } from "../../../fields/Field"; + + +@observer +export class CollectionVideoView extends React.Component { + + public static LayoutString(fieldKey: string = "DataKey") { + return `<${CollectionVideoView.name} Document={Document} + ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} + isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + } + + public SelectedDocs: FieldId[] = [] + @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0; + @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0; + + @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); } + @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } + // "inherited" CollectionView API starts here... + + public active: () => boolean = () => CollectionView.Active(this); + + addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); } + removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } + + specificContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } }); + } + } + + get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; } + get subView(): any { return CollectionView.SubView(this); } + + render() { + return (
+ {/* */} +
) + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 41f458fb4f383bfbf8d5b651189c2f4731262ff8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 13 Mar 2019 20:33:51 -0400 Subject: added annotations for videos. added custom play controls for videos. --- src/client/documents/Documents.ts | 5 +- src/client/views/InkingCanvas.tsx | 6 +- .../views/collections/CollectionFreeFormView.tsx | 8 +-- src/client/views/collections/CollectionPDFView.tsx | 13 ++-- .../views/collections/CollectionVideoView.scss | 35 +++++++++ .../views/collections/CollectionVideoView.tsx | 83 +++++++++++++++++++--- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/fields/KeyStore.ts | 1 - 10 files changed, 126 insertions(+), 31 deletions(-) create mode 100644 src/client/views/collections/CollectionVideoView.scss (limited to 'src/client/views/collections/CollectionVideoView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f35d553b1..15e16a491 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -23,6 +23,7 @@ import { PDFField } from "../../fields/PDFField"; import { PDFBox } from "../views/nodes/PDFBox"; import { CollectionPDFView } from "../views/collections/CollectionPDFView"; import { RichTextField } from "../../fields/RichTextField"; +import { CollectionVideoView } from "../views/collections/CollectionVideoView"; export interface DocumentOptions { x?: number; @@ -138,9 +139,9 @@ export namespace Documents { } function GetVideoPrototype(): Document { if (!videoProto) { - videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionView.LayoutString("AnnotationsKey"), + videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionVideoView.LayoutString("AnnotationsKey"), { x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations] }); - videoProto.SetNumber(KeyStore.CurFrame, 1); + videoProto.SetNumber(KeyStore.CurPage, 0); videoProto.SetText(KeyStore.BackgroundLayout, VideoBox.LayoutString()); } return videoProto; diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 0d87c1239..064d1cba2 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -74,7 +74,7 @@ export class InkingCanvas extends React.Component { color: InkingControl.Instance.selectedColor, width: InkingControl.Instance.selectedWidth, tool: InkingControl.Instance.selectedTool, - page: this.props.Document.GetNumber(KeyStore.CurPage, 0) + page: this.props.Document.GetNumber(KeyStore.CurPage, -1) }); this.inkData = data; this._isDrawing = true; @@ -145,11 +145,11 @@ export class InkingCanvas extends React.Component { // parse data from server let paths: Array = [] - let curPage = this.props.Document.GetNumber(KeyStore.CurPage, 0) + let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1) Array.from(lines).map(item => { let id = item[0]; let strokeData = item[1]; - if (strokeData.page == 0 || strokeData.page == curPage) + if (strokeData.page == -1 || strokeData.page == curPage) paths.push( { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1); + var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); const lvalue = this.props.Document.GetT>(this.props.fieldKey, ListField); let active: Document[] = []; if (lvalue && lvalue != FieldWaiting) { lvalue.Data.map(doc => { - var page = doc.GetNumber(KeyStore.Page, 0); - if (page == curPage || page == 0) { + var page = doc.GetNumber(KeyStore.Page, -1); + if (page == curPage || page == -1) { active.push(doc); } }) @@ -257,7 +257,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @computed get views() { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1); + var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); const lvalue = this.props.Document.GetT>(this.props.fieldKey, ListField); if (lvalue && lvalue != FieldWaiting) { return lvalue.Data.map(doc => { diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index f22c07060..91ffc9500 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -18,13 +18,12 @@ export class CollectionPDFView extends React.Component { isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; } - public SelectedDocs: FieldId[] = [] - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0; + private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } + private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } + @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : -1; + @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1; - @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); } - @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } - @computed private get uIButtons() { + private get uIButtons() { return (
@@ -33,7 +32,7 @@ export class CollectionPDFView extends React.Component { } // "inherited" CollectionView API starts here... - + public SelectedDocs: FieldId[] = [] public active: () => boolean = () => CollectionView.Active(this); addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); } diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss new file mode 100644 index 000000000..6c2f5a62a --- /dev/null +++ b/src/client/views/collections/CollectionVideoView.scss @@ -0,0 +1,35 @@ +.collectionVideoView-controls{ + width: 100%; + height: 100%; + position: absolute; +} +.collectionVideoView-time{ + color : white; + top :25px; + left : 25px; + position: absolute; + background-color: rgba(50, 50, 50, 0.2); +} +.collectionVideoView-play { + width: 25px; + height: 20px; + bottom: 25px; + left : 25px; + position: absolute; + color : white; + background-color: rgba(50, 50, 50, 0.2); + border-radius: 4px; + text-align: center; +} +.collectionVideoView-full { + width: 25px; + height: 20px; + bottom: 25px; + right : 25px; + position: absolute; + color : white; + background-color: rgba(50, 50, 50, 0.2); + border-radius: 4px; + text-align: center; + +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index a6471f53c..058325b21 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,4 +1,4 @@ -import { action, computed } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; @@ -7,6 +7,8 @@ import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; import React = require("react"); import { FieldId } from "../../../fields/Field"; +import { ReplaceAroundStep } from "prosemirror-transform"; +import "./CollectionVideoView.scss" @observer @@ -18,14 +20,10 @@ export class CollectionVideoView extends React.Component { isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; } - public SelectedDocs: FieldId[] = [] - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0; - - @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 0); } - @computed private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } + private _mainCont = React.createRef(); // "inherited" CollectionView API starts here... + public SelectedDocs: FieldId[] = [] public active: () => boolean = () => CollectionView.Active(this); addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); } @@ -40,11 +38,74 @@ export class CollectionVideoView extends React.Component { get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; } get subView(): any { return CollectionView.SubView(this); } + componentDidMount() { + this.repete(); + } + + player = (): HTMLVideoElement => { + return this._mainCont.current!.getElementsByTagName("video")[0]; + } + + @action + repete = () => { + if (this.player()) { + this.ctime = this.player().currentTime; + this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this.ctime)); + } + setTimeout(() => this.repete(), 100) + } + + + @observable + ctime: number = 0 + @observable + playing: boolean = false; + + @action + onPlayDown = () => { + if (this.player()) { + if (this.player().paused) { + this.player().play(); + this.playing = true; + } else { + this.player().pause(); + this.playing = false; + } + } + } + @action + onFullDown = (e: React.PointerEvent) => { + if (this.player()) { + this.player().requestFullscreen(); + e.stopPropagation(); + e.preventDefault(); + } + } + + @action + onResetDown = () => { + if (this.player()) { + this.player().pause(); + this.player().currentTime = 0; + } + + } + render() { - return (
- {/* */} + return (
+
+ {this.subView} +
+ {"" + Math.round(this.ctime)} + {" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)} +
+
+ {this.playing ? "\"" : ">"} +
+
+ F +
+
) } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 17a0fbd23..bbb4a5d83 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -50,7 +50,7 @@ export class CollectionView extends React.Component { @action public static AddDocument(props: CollectionViewProps, doc: Document) { - doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, 0)); + doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, -1)); if (props.Document.Get(props.fieldKey) instanceof Field) { //TODO This won't create the field if it doesn't already exist const value = props.Document.GetData(props.fieldKey, ListField, new Array()) diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 544af41a2..b0b5a63a4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -86,7 +86,7 @@ export class PDFBox extends React.Component { @observable private _interactive: boolean = false; @observable private _loaded: boolean = false; - @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, 0); } + @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, -1); } componentDidMount() { this._reactionDisposer = reaction( diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 9c60d4348..053d9dd56 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -51,7 +51,7 @@ export class VideoBox extends React.Component {
{({ measureRef }) => -
diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss new file mode 100644 index 000000000..28878c6fa --- /dev/null +++ b/src/client/views/collections/CollectionPDFView.scss @@ -0,0 +1,28 @@ +.collectionPdfView-buttonTray { + width: 100%; + height: 100%; + top : 25px; + left : 20px; + position: relative; + transform-origin: left top; + position: absolute; +} +.collectionPdfView-cont{ + width: 100%; + height: 100%; + position: absolute; +} +.collectionPdfView-backward { + color : white; + top :0px; + left : 0px; + position: absolute; + background-color: rgba(50, 50, 50, 0.2); +} +.collectionPdfView-forward { + color : white; + top :0px; + left : 25px; + position: absolute; + background-color: rgba(50, 50, 50, 0.2); +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index be3a281f2..124d82c8b 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -5,6 +5,7 @@ import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; +import "./CollectionPDFView.scss" import React = require("react"); import { FieldId } from "../../../fields/Field"; @@ -24,10 +25,11 @@ export class CollectionPDFView extends React.Component { @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1; private get uIButtons() { + let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); return ( -
- - +
+ +
); } @@ -49,7 +51,7 @@ export class CollectionPDFView extends React.Component { get subView(): any { return CollectionView.SubView(this); } render() { - return (
+ return (
{this.subView} {this.props.isSelected() ? this.uIButtons : (null)}
) diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss index 6c2f5a62a..ec3c0327d 100644 --- a/src/client/views/collections/CollectionVideoView.scss +++ b/src/client/views/collections/CollectionVideoView.scss @@ -1,4 +1,9 @@ -.collectionVideoView-controls{ +.collectionVideoView-buttonTray{ + width: 100%; + height: 100%; + position: absolute; +} +.collectionVideoView-cont{ width: 100%; height: 100%; position: absolute; @@ -9,6 +14,7 @@ left : 25px; position: absolute; background-color: rgba(50, 50, 50, 0.2); + transform-origin: left top; } .collectionVideoView-play { width: 25px; @@ -20,6 +26,7 @@ background-color: rgba(50, 50, 50, 0.2); border-radius: 4px; text-align: center; + transform-origin: left bottom; } .collectionVideoView-full { width: 25px; @@ -31,5 +38,6 @@ background-color: rgba(50, 50, 50, 0.2); border-radius: 4px; text-align: center; + transform-origin: right bottom; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9856a1284..9b01c23c9 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -7,7 +7,6 @@ import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; import React = require("react"); import { FieldId } from "../../../fields/Field"; -import { ReplaceAroundStep } from "prosemirror-transform"; import "./CollectionVideoView.scss" @@ -21,6 +20,25 @@ export class CollectionVideoView extends React.Component { } private _mainCont = React.createRef(); + + private get uIButtons() { + let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); + return ( +
+
+ {"" + Math.round(this.ctime)} + {" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)} +
+
+ {this.playing ? "\"" : ">"} +
+
+ F +
+
); + } + + // "inherited" CollectionView API starts here... @observable @@ -40,20 +58,20 @@ export class CollectionVideoView extends React.Component { get subView(): any { return CollectionView.SubView(this); } componentDidMount() { - this.repete(); + this.updateTimecode(); } - player = (): HTMLVideoElement => { - return this._mainCont.current!.getElementsByTagName("video")[0]; + get player(): HTMLVideoElement | undefined { + return this._mainCont.current ? this._mainCont.current.getElementsByTagName("video")[0] : undefined; } @action - repete = () => { - if (this.player()) { - this.ctime = this.player().currentTime; + updateTimecode = () => { + if (this.player) { + this.ctime = this.player.currentTime; this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this.ctime)); } - setTimeout(() => this.repete(), 100) + setTimeout(() => this.updateTimecode(), 100) } @@ -64,20 +82,20 @@ export class CollectionVideoView extends React.Component { @action onPlayDown = () => { - if (this.player()) { - if (this.player().paused) { - this.player().play(); + if (this.player) { + if (this.player.paused) { + this.player.play(); this.playing = true; } else { - this.player().pause(); + this.player.pause(); this.playing = false; } } } @action onFullDown = (e: React.PointerEvent) => { - if (this.player()) { - this.player().requestFullscreen(); + if (this.player) { + this.player.requestFullscreen(); e.stopPropagation(); e.preventDefault(); } @@ -85,28 +103,17 @@ export class CollectionVideoView extends React.Component { @action onResetDown = () => { - if (this.player()) { - this.player().pause(); - this.player().currentTime = 0; + if (this.player) { + this.player.pause(); + this.player.currentTime = 0; } } render() { return (
-
- {this.subView} -
- {"" + Math.round(this.ctime)} - {" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)} -
-
- {this.playing ? "\"" : ">"} -
-
- F -
-
+ {this.subView} + {this.uIButtons}
) } } \ No newline at end of file diff --git a/src/client/views/collections/PreviewCursor.tsx b/src/client/views/collections/PreviewCursor.tsx index ab68fbc46..a1411250a 100644 --- a/src/client/views/collections/PreviewCursor.tsx +++ b/src/client/views/collections/PreviewCursor.tsx @@ -16,7 +16,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView"; export interface PreviewCursorProps { getTransform: () => Transform; container: CollectionFreeFormView; - addLiveTextDocuemnt: (doc: Document) => void; + addLiveTextDocument: (doc: Document) => void; } @observer @@ -57,11 +57,13 @@ export class PreviewCursor extends React.Component { @action onKeyPress = (e: KeyboardEvent) => { //if not these keys, make a textbox if preview cursor is active! - if (!e.ctrlKey && !e.altKey) { + if (!e.ctrlKey && !e.altKey && !e.defaultPrevented) { //make textbox and add it to this collection let [x, y] = this.props.getTransform().transformPoint(this._lastX, this._lastY); let newBox = Documents.TextDocument({ width: 200, height: 100, x: x, y: y, title: "new" }); - this.props.addLiveTextDocuemnt(newBox); + this.props.addLiveTextDocument(newBox); + e.stopPropagation(); + e.preventDefault(); } } diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 9f92410d4..ad947afd5 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -11,5 +11,5 @@ } .pdfBox-contentContainer { position: absolute; - transform-origin: "left top"; + transform-origin: left top; } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 05b23c6b94b47393ba4d34a393e5080f20aff099 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 14 Mar 2019 19:14:07 -0400 Subject: fixed scrollzooming on videos. --- .../views/collections/CollectionVideoView.scss | 6 +----- .../views/collections/CollectionVideoView.tsx | 23 +++++++++++----------- 2 files changed, 12 insertions(+), 17 deletions(-) (limited to 'src/client/views/collections/CollectionVideoView.tsx') diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss index ec3c0327d..ddcd74616 100644 --- a/src/client/views/collections/CollectionVideoView.scss +++ b/src/client/views/collections/CollectionVideoView.scss @@ -1,8 +1,4 @@ -.collectionVideoView-buttonTray{ - width: 100%; - height: 100%; - position: absolute; -} + .collectionVideoView-cont{ width: 100%; height: 100%; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9b01c23c9..0e2d250aa 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -23,19 +23,18 @@ export class CollectionVideoView extends React.Component { private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); - return ( -
-
- {"" + Math.round(this.ctime)} - {" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)} + return ([ +
+ {"" + Math.round(this.ctime)} + {" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)} +
, +
+ {this.playing ? "\"" : ">"} +
, +
+ F
-
- {this.playing ? "\"" : ">"} -
-
- F -
-
); + ]); } -- cgit v1.2.3-70-g09d2 From f089e10dfd42edc395729a6b71e42385745f364e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 14 Mar 2019 22:21:16 -0400 Subject: marquees can now delete ink or move it to a new collection. --- src/client/documents/Documents.ts | 3 ++ src/client/views/InkingCanvas.scss | 3 +- src/client/views/InkingCanvas.tsx | 22 +++++----- src/client/views/InkingStroke.tsx | 2 - src/client/views/Main.tsx | 2 +- .../views/collections/CollectionFreeFormView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 6 +-- src/client/views/collections/MarqueeView.tsx | 47 +++++++++++++++++----- 8 files changed, 63 insertions(+), 26 deletions(-) (limited to 'src/client/views/collections/CollectionVideoView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4e0eefcc6..8402118b8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -24,10 +24,12 @@ import { PDFBox } from "../views/nodes/PDFBox"; import { CollectionPDFView } from "../views/collections/CollectionPDFView"; import { RichTextField } from "../../fields/RichTextField"; import { CollectionVideoView } from "../views/collections/CollectionVideoView"; +import { StrokeData, InkField } from "../../fields/InkField"; export interface DocumentOptions { x?: number; y?: number; + ink?: Map; width?: number; height?: number; nativeWidth?: number; @@ -87,6 +89,7 @@ export namespace Documents { if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); } if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); } if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); } + if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); } return doc; } function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document { diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index f654b194b..37fa3143d 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -1,8 +1,9 @@ .inking-canvas { - position: fixed; + position: absolute; top: -50000px; left: -50000px; // z-index: 99; //overlays ink on top of everything svg { + position:absolute; width: 100000px; height: 100000px; .highlight { diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 064d1cba2..84c47f616 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -1,4 +1,5 @@ import { observer } from "mobx-react"; +import { observable } from "mobx"; import { action, computed } from "mobx"; import { InkingControl } from "./InkingControl"; import React = require("react"); @@ -6,14 +7,10 @@ import { Transform } from "../util/Transform"; import { Document } from "../../fields/Document"; import { KeyStore } from "../../fields/KeyStore"; import { InkField, InkTool, StrokeData, StrokeMap } from "../../fields/InkField"; -import { JsxArgs } from "./nodes/DocumentView"; import { InkingStroke } from "./InkingStroke"; import "./InkingCanvas.scss" -import { CollectionDockingView } from "./collections/CollectionDockingView"; import { Utils } from "../../Utils"; import { FieldWaiting } from "../../fields/Field"; -import { getMapLikeKeys } from "mobx/lib/internal"; - interface InkCanvasProps { getScreenTransform: () => Transform; @@ -22,7 +19,16 @@ interface InkCanvasProps { @observer export class InkingCanvas extends React.Component { - + static InkOffset: number = 50000; + public static IntersectStrokeRect(stroke: StrokeData, selRect: { left: number, top: number, width: number, height: number }): boolean { + let inside = false; + stroke.pathData.map(val => { + if (selRect.left < val.x - InkingCanvas.InkOffset && selRect.left + selRect.width > val.x - InkingCanvas.InkOffset && + selRect.top < val.y - InkingCanvas.InkOffset && selRect.top + selRect.height > val.y - InkingCanvas.InkOffset) + inside = true; + }); + return inside + } private _isDrawing: boolean = false; private _idGenerator: string = ""; @@ -51,7 +57,6 @@ export class InkingCanvas extends React.Component { document.removeEventListener("mouseup", this.handleMouseUp); } - @action handleMouseDown = (e: React.PointerEvent): void => { if (e.button != 0 || @@ -62,7 +67,6 @@ export class InkingCanvas extends React.Component { if (InkingControl.Instance.selectedTool === InkTool.Eraser) { return } - e.stopPropagation() const point = this.relativeCoordinatesForEvent(e); // start the new line, saves a uuid to represent the field of the stroke @@ -110,8 +114,8 @@ export class InkingCanvas extends React.Component { relativeCoordinatesForEvent = (e: React.MouseEvent): { x: number, y: number } => { let [x, y] = this.props.getScreenTransform().transformPoint(e.clientX, e.clientY); - x += 50000 - y += 50000 + x += InkingCanvas.InkOffset; + y += InkingCanvas.InkOffset; return { x, y }; } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index d724421d3..87b5c43d8 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -21,8 +21,6 @@ export class InkingStroke extends React.Component { @observable private _strokeColor: string = this.props.color; @observable private _strokeWidth: string = this.props.width; - private _canvasColor: string = "#cdcdcd"; - deleteStroke = (e: React.MouseEvent): void => { if (InkingControl.Instance.selectedTool === InkTool.Eraser && e.buttons === 1) { this.props.deleteCallback(this.props.id); diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 8ee028076..d73e9b8fe 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -58,7 +58,7 @@ Documents.initProtos(mainDocId, (res?: Document) => { let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})) let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" })) - let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, backgroundColor: "Transparent", title: "a freeform collection" })); + let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); let addSchemaNode = action(() => Documents.SchemaDocument([Documents.TextDocument()], { width: 200, height: 200, title: "a schema collection" })); let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, title: "video node" })); let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, title: "a schema collection" })); diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 98fb23fa4..c8b745254 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -338,7 +338,9 @@ export class CollectionFreeFormView extends CollectionViewBase { {this.views}
- + {this.overlayView}
); diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 0e2d250aa..b64ef3c07 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -24,14 +24,14 @@ export class CollectionVideoView extends React.Component { private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); return ([ -
+
{"" + Math.round(this.ctime)} {" " + Math.round((this.ctime - Math.trunc(this.ctime)) * 100)}
, -
+
{this.playing ? "\"" : ">"}
, -
+
F
]); diff --git a/src/client/views/collections/MarqueeView.tsx b/src/client/views/collections/MarqueeView.tsx index d9e4df1e9..67716f99a 100644 --- a/src/client/views/collections/MarqueeView.tsx +++ b/src/client/views/collections/MarqueeView.tsx @@ -3,21 +3,22 @@ import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { FieldWaiting, Opt } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; -import { ListField } from "../../../fields/ListField"; import { Documents } from "../../documents/Documents"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); - +import { InkField, StrokeData } from "../../../fields/InkField"; +import { Utils } from "../../../Utils"; +import { InkingCanvas } from "../InkingCanvas"; interface MarqueeViewProps { getMarqueeTransform: () => Transform; getTransform: () => Transform; container: CollectionFreeFormView; addDocument: (doc: Document) => void; - activeDocuemnts: () => Document[]; + activeDocuments: () => Document[]; selectDocuments: (docs: Document[]) => void; removeDocument: (doc: Document) => boolean; } @@ -94,29 +95,57 @@ export class MarqueeView extends React.Component marqueeCommand = (e: KeyboardEvent) => { if (e.key == "Backspace") { this.marqueeSelect().map(d => this.props.removeDocument(d)); + this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField); this.cleanupInteractions(); } if (e.key == "c") { let bounds = this.Bounds; - let selected = this.marqueeSelect().map(m => m); - this.marqueeSelect().map(d => this.props.removeDocument(d)); - //setTimeout(() => { - this.props.addDocument(Documents.FreeformDocument(selected.map(d => { + let selected = this.marqueeSelect().map(d => { + this.props.removeDocument(d); d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2); d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2); d.SetNumber(KeyStore.Page, 0); d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0)); return d; - }), { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, height: bounds.height, title: "a nested collection" })); + }); + let liftedInk = this.marqueeInkSelect(true); + this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField); + //setTimeout(() => { + this.props.addDocument(Documents.FreeformDocument(selected, { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, backgroundColor: "Transparent", height: bounds.height, ink: liftedInk, title: "a nested collection" })); // }, 100); this.cleanupInteractions(); } } + marqueeInkSelect(select: boolean) { + let selRect = this.Bounds; + let centerShiftX = 0 - (selRect.left + selRect.width / 2); // moves each point by the offset that shifts the selection's center to the origin. + let centerShiftY = 0 - (selRect.top + selRect.height / 2); + let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); + if (ink && ink != FieldWaiting) { + let idata = new Map(); + ink.Data.forEach((value: StrokeData, key: string, map: any) => { + let inside = InkingCanvas.IntersectStrokeRect(value, selRect); + if (inside && select) { + idata.set(key, + { + pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }), + color: value.color, + width: value.width, + tool: value.tool, + page: -1 + }); + } else if (!inside && !select) { + idata.set(key, value); + } + }) + return idata; + } + } marqueeSelect() { let selRect = this.Bounds; let selection: Document[] = []; - this.props.activeDocuemnts().map(doc => { + this.props.activeDocuments().map(doc => { var x = doc.GetNumber(KeyStore.X, 0); var y = doc.GetNumber(KeyStore.Y, 0); var w = doc.GetNumber(KeyStore.Width, 0); -- cgit v1.2.3-70-g09d2