aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoryipstanley <stanley_yip@brown.edu>2019-06-12 14:35:24 -0400
committeryipstanley <stanley_yip@brown.edu>2019-06-12 14:35:24 -0400
commit9ec4a529dc886acca8f147cfe913e60f938f3bda (patch)
tree9d5548a585b0a9cccfc9e4c7ce2451b802199886 /src
parentb96281d18a9c4ca0ea7f8360d7f69d12c325fada (diff)
reverse annotating
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DragManager.ts6
-rw-r--r--src/client/views/pdf/PDFViewer.tsx112
-rw-r--r--src/client/views/pdf/Page.tsx27
3 files changed, 116 insertions, 29 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index e92ed9b4a..2ffb77e44 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -154,14 +154,14 @@ export namespace DragManager {
}
export class AnnotationDragData {
- constructor(dragDoc: Doc, annotationDocs: Doc[], dropDoc: Doc) {
+ constructor(dragDoc: Doc, annotationDoc: Doc, dropDoc: Doc) {
this.dragDocument = dragDoc;
this.dropDocument = dropDoc;
- this.annotationDocuments = annotationDocs;
+ this.annotationDocument = annotationDoc;
this.xOffset = this.yOffset = 0;
}
dragDocument: Doc;
- annotationDocuments: Doc[];
+ annotationDocument: Doc;
dropDocument: Doc;
xOffset: number;
yOffset: number;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6823f640e..bfd0e036f 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -7,7 +7,7 @@ import "./PDFViewer.scss";
import "pdfjs-dist/web/pdf_viewer.css";
import { PDFBox } from "../nodes/PDFBox";
import Page from "./Page";
-import { NumCast, Cast, BoolCast } from "../../../new_fields/Types";
+import { NumCast, Cast, BoolCast, StrCast } from "../../../new_fields/Types";
import { Id } from "../../../new_fields/FieldSymbols";
import { DocUtils, Docs } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
@@ -18,6 +18,8 @@ import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocum
import { Transform } from "../../util/Transform";
import { emptyFunction, returnTrue, returnFalse } from "../../../Utils";
import { DocumentView } from "../nodes/DocumentView";
+import { DragManager } from "../../util/DragManager";
+import { Dictionary } from "typescript-collections";
interface IPDFViewerProps {
url: string;
@@ -83,12 +85,15 @@ class Viewer extends React.Component<IViewerProps> {
@observable private _loaded: boolean = false;
@observable private _pdf: Opt<Pdfjs.PDFDocumentProxy>;
@observable private _annotations: Doc[] = [];
+ @observable private _pointerEvents: "all" | "none" = "all";
+ @observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
private _pageBuffer: number = 1;
private _annotationLayer: React.RefObject<HTMLDivElement>;
private _reactionDisposer?: IReactionDisposer;
private _annotationReactionDisposer?: IReactionDisposer;
private _pagesLoaded: number = 0;
+ private _dropDisposer?: DragManager.DragDropDisposer;
constructor(props: IViewerProps) {
super(props);
@@ -96,6 +101,7 @@ class Viewer extends React.Component<IViewerProps> {
this._annotationLayer = React.createRef();
}
+ @action
componentDidMount = () => {
let wasSelected = this.props.parent.props.isSelected();
// reaction for when document gets (de)selected
@@ -105,10 +111,12 @@ class Viewer extends React.Component<IViewerProps> {
// if deselected, render images in place of pdf
if (wasSelected && !this.props.parent.props.isSelected()) {
this.saveThumbnail();
+ this._pointerEvents = "all";
}
// if selected, render pdf
else if (!wasSelected && this.props.parent.props.isSelected()) {
this.renderPages(this.startIndex, this.endIndex, true);
+ this._pointerEvents = "none";
}
wasSelected = this.props.parent.props.isSelected();
},
@@ -133,6 +141,57 @@ class Viewer extends React.Component<IViewerProps> {
}, 1000);
}
+ private mainCont = (div: HTMLDivElement | null) => {
+ if (this._dropDisposer) {
+ this._dropDisposer();
+ }
+ if (div) {
+ this._dropDisposer = DragManager.MakeDropTarget(div, {
+ handlers: { drop: this.drop.bind(this) }
+ });
+ }
+ }
+
+ makeAnnotationDocuments = (sourceDoc: Doc): Doc => {
+ let annoDocs: Doc[] = [];
+ this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {
+ for (let anno of value) {
+ let annoDoc = new Doc();
+ if (anno.style.left) annoDoc.x = parseInt(anno.style.left);
+ if (anno.style.top) annoDoc.y = parseInt(anno.style.top);
+ if (anno.style.height) annoDoc.height = parseInt(anno.style.height);
+ if (anno.style.width) annoDoc.width = parseInt(anno.style.width);
+ annoDoc.page = key;
+ annoDoc.target = sourceDoc;
+ annoDoc.type = AnnotationTypes.Region;
+ annoDocs.push(annoDoc);
+ anno.remove();
+ }
+ });
+
+ let annoDoc = new Doc();
+ annoDoc.annotations = new List<Doc>(annoDocs);
+ DocUtils.MakeLink(sourceDoc, annoDoc, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
+ this._savedAnnotations.clear();
+ return annoDoc;
+ }
+
+ drop = async (e: Event, de: DragManager.DropEvent) => {
+ if (de.data instanceof DragManager.LinkDragData) {
+ let sourceDoc = de.data.linkSourceDocument;
+ let destDoc = this.makeAnnotationDocuments(sourceDoc);
+ let targetAnnotations = DocListCast(this.props.parent.Document.annotations);
+ if (targetAnnotations) {
+ targetAnnotations.push(destDoc);
+ this.props.parent.Document.annotations = new List<Doc>(targetAnnotations);
+ }
+ else {
+ this.props.parent.Document.annotations = new List<Doc>([destDoc]);
+ }
+ }
+ e.stopPropagation();
+ }
+
componentWillUnmount = () => {
if (this._reactionDisposer) {
this._reactionDisposer();
@@ -219,6 +278,8 @@ class Viewer extends React.Component<IViewerProps> {
parent={this.props.parent}
renderAnnotations={this.renderAnnotations}
makePin={this.createPinAnnotation}
+ sendAnnotations={this.receiveAnnotations}
+ receiveAnnotations={this.sendAnnotations}
{...this.props} />
));
let arr = Array.from(Array(numPages).keys()).map(() => false);
@@ -257,6 +318,8 @@ class Viewer extends React.Component<IViewerProps> {
parent={this.props.parent}
makePin={this.createPinAnnotation}
renderAnnotations={this.renderAnnotations}
+ sendAnnotations={this.receiveAnnotations}
+ receiveAnnotations={this.sendAnnotations}
{...this.props} />
);
this._isPage[i] = true;
@@ -269,6 +332,15 @@ class Viewer extends React.Component<IViewerProps> {
return;
}
+ @action
+ receiveAnnotations = (annotations: HTMLDivElement[], page: number) => {
+ this._savedAnnotations.setValue(page, annotations);
+ }
+
+ sendAnnotations = (page: number): HTMLDivElement[] | undefined => {
+ return this._savedAnnotations.getValue(page);
+ }
+
createPinAnnotation = (x: number, y: number, page: number): void => {
let targetDoc = Docs.TextDocument({ width: 100, height: 50, title: "New Pin Annotation" });
@@ -280,13 +352,15 @@ class Viewer extends React.Component<IViewerProps> {
pinAnno.target = targetDoc;
pinAnno.type = AnnotationTypes.Pin;
// this._annotations.push(pinAnno);
+ let annoDoc = new Doc();
+ annoDoc.annotations = new List<Doc>([pinAnno]);
let annotations = DocListCast(this.props.parent.Document.annotations);
if (annotations && annotations.length) {
- annotations.push(pinAnno);
+ annotations.push(annoDoc);
this.props.parent.Document.annotations = new List<Doc>(annotations);
}
else {
- this.props.parent.Document.annotations = new List<Doc>([pinAnno]);
+ this.props.parent.Document.annotations = new List<Doc>([annoDoc]);
}
// let pinAnno = document.createElement("div");
// pinAnno.className = "pdfViewer-pinAnnotation";
@@ -349,20 +423,20 @@ class Viewer extends React.Component<IViewerProps> {
return counter;
}
- renderAnnotation = (anno: Doc): JSX.Element => {
- let type = NumCast(anno.type);
- switch (type) {
- case AnnotationTypes.Pin:
- return <PinAnnotation parent={this} document={anno} x={NumCast(anno.x)} y={NumCast(anno.y) + this.getPageHeight(NumCast(anno.page))} width={anno[WidthSym]()} height={anno[HeightSym]()} key={anno[Id]} />;
- case AnnotationTypes.Region:
- return <RegionAnnotation parent={this} document={anno} x={NumCast(anno.x)} y={NumCast(anno.y) + this.getPageHeight(NumCast(anno.page))} width={anno[WidthSym]()} height={anno[HeightSym]()} key={anno[Id]} />;
- default:
- return <div></div>;
- }
- }
-
- onDrop = (e: React.DragEvent) => {
- console.log("Dropped!");
+ renderAnnotation = (anno: Doc): JSX.Element[] => {
+ let annotationDocs = DocListCast(anno.annotations);
+ let res = annotationDocs.map(a => {
+ let type = NumCast(a.type);
+ switch (type) {
+ case AnnotationTypes.Pin:
+ return <PinAnnotation parent={this} document={a} x={NumCast(a.x)} y={NumCast(a.y) + this.getPageHeight(NumCast(a.page))} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
+ case AnnotationTypes.Region:
+ return <RegionAnnotation parent={this} document={a} x={NumCast(a.x)} y={NumCast(a.y) + this.getPageHeight(NumCast(a.page))} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
+ default:
+ return <div></div>;
+ }
+ });
+ return res;
}
// ScreenToLocalTransform = (): Transform => {
@@ -380,11 +454,11 @@ class Viewer extends React.Component<IViewerProps> {
render() {
trace();
return (
- <div onDrop={this.onDrop}>
+ <div ref={this.mainCont} style={{ pointerEvents: "all" }}>
<div className="viewer">
{this._visibleElements}
</div>
- <div className="pdfViewer-annotationLayer" ref={this._annotationLayer} style={{ height: this.props.parent.Document.nativeHeight, width: `100%`, pointerEvents: "none" }}>
+ <div className="pdfViewer-annotationLayer" ref={this._annotationLayer} style={{ height: this.props.parent.Document.nativeHeight, width: `100%`, pointerEvents: this._pointerEvents }}>
<div className="pdfViewer-annotationLayer-subCont" style={{ transform: `translateY(${-this.scrollY}px)` }}>
{this._annotations.map(anno => this.renderAnnotation(anno))}
</div>
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 73a7a93a0..908804605 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -24,6 +24,8 @@ interface IPageProps {
parent: PDFBox;
renderAnnotations: (annotations: Doc[], removeOld: boolean) => void;
makePin: (x: number, y: number, page: number) => void;
+ sendAnnotations: (annotations: HTMLDivElement[], page: number) => void;
+ receiveAnnotations: (page: number) => HTMLDivElement[] | undefined;
}
@observer
@@ -61,11 +63,19 @@ export default class Page extends React.Component<IPageProps> {
componentDidMount = (): void => {
if (this.props.pdf) {
this.update(this.props.pdf);
+ }
+ let received = this.props.receiveAnnotations(this.props.page);
+ this._currentAnnotations = received ? received : [];
+ if (this._annotationLayer.current) {
+ this._annotationLayer.current.append(...this._currentAnnotations);
}
}
componentWillUnmount = (): void => {
+ console.log(this._currentAnnotations);
+ this.props.sendAnnotations(this._currentAnnotations, this.props.page);
+
if (this._reactionDisposer) {
this._reactionDisposer();
}
@@ -134,8 +144,9 @@ export default class Page extends React.Component<IPageProps> {
* This method makes the list of current annotations into documents linked to
* the parameter passed in.
*/
- makeAnnotationDocuments = (targetDoc: Doc): Doc[] => {
+ makeAnnotationDocuments = (targetDoc: Doc): Doc => {
let annoDocs: Doc[] = [];
+
for (let anno of this._currentAnnotations) {
let annoDoc = new Doc();
annoDoc.x = anno.offsetLeft;
@@ -146,11 +157,13 @@ export default class Page extends React.Component<IPageProps> {
annoDoc.target = targetDoc;
annoDoc.type = AnnotationTypes.Region;
annoDocs.push(annoDoc);
- DocUtils.MakeLink(annoDoc, targetDoc, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
anno.remove();
}
+ let annoDoc = new Doc();
+ annoDoc.annotations = new List<Doc>(annoDocs);
+ DocUtils.MakeLink(annoDoc, targetDoc, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
this._currentAnnotations = [];
- return annoDocs;
+ return annoDoc;
}
/**
@@ -171,17 +184,17 @@ export default class Page extends React.Component<IPageProps> {
let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" });
targetDoc.targetPage = this.props.page;
// creates annotation documents for current highlights
- let annotationDocs = this.makeAnnotationDocuments(targetDoc);
+ let annotationDoc = this.makeAnnotationDocuments(targetDoc);
let targetAnnotations = DocListCast(this.props.parent.Document.annotations);
if (targetAnnotations) {
- targetAnnotations.push(...annotationDocs);
+ targetAnnotations.push(annotationDoc);
this.props.parent.Document.annotations = new List<Doc>(targetAnnotations);
}
else {
- this.props.parent.Document.annotations = new List<Doc>(annotationDocs);
+ this.props.parent.Document.annotations = new List<Doc>([annotationDoc]);
}
// create dragData and star tdrag
- let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDocs, targetDoc);
+ let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDoc, targetDoc);
if (this._textLayer.current) {
DragManager.StartAnnotationDrag([this._textLayer.current], dragData, e.pageX, e.pageY, {
handlers: {