aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx5
-rw-r--r--src/client/views/pdf/PDFBox2.tsx28
-rw-r--r--src/client/views/pdf/PDFViewer.tsx327
-rw-r--r--src/client/views/pdf/Page.tsx382
5 files changed, 391 insertions, 353 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index a6c3dfa7a..e92ed9b4a 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -218,7 +218,7 @@ export namespace DragManager {
let ys: number[] = [];
const docs: Doc[] =
- dragData instanceof DocumentDragData ? dragData.draggedDocuments : [];
+ dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnnotationDragData ? [dragData.dragDocument] : [];
let dragElements = eles.map(ele => {
const w = ele.offsetWidth,
h = ele.offsetHeight;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index be37efd3d..1ced6a426 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -107,6 +107,11 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
e.stopPropagation();
return added;
}
+ else if (de.data instanceof DragManager.AnnotationDragData) {
+ console.log("dropped!");
+ console.log(de.data);
+ return this.props.addDocument(de.data.dropDocument);
+ }
return false;
}
diff --git a/src/client/views/pdf/PDFBox2.tsx b/src/client/views/pdf/PDFBox2.tsx
deleted file mode 100644
index 71825c260..000000000
--- a/src/client/views/pdf/PDFBox2.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import React = require("react");
-import { FieldViewProps, FieldView } from "../nodes/FieldView";
-import { DocComponent } from "../DocComponent";
-import { makeInterface } from "../../../new_fields/Schema";
-import { positionSchema } from "../nodes/DocumentView";
-import { pageSchema } from "../nodes/ImageBox";
-import { PDFViewer } from "./PDFViewer";
-import { RouteStore } from "../../../server/RouteStore";
-import { InkingControl } from "../InkingControl";
-import { observer } from "mobx-react";
-import { trace } from "mobx";
-
-type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
-const PdfDocument = makeInterface(positionSchema, pageSchema);
-
-@observer
-export class PDFBox2 extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) {
- public static LayoutString() { return FieldView.LayoutString(PDFBox2); }
-
- render() {
- trace();
- const pdfUrl = "https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf";
- let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool);
- return (
- <PDFViewer url={pdfUrl} />
- )
- }
-} \ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index b0a48ac84..0711ead23 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -2,19 +2,11 @@ import { observer } from "mobx-react";
import React = require("react");
import { observable, action, runInAction, computed, IReactionDisposer, reaction } from "mobx";
import * as Pdfjs from "pdfjs-dist";
-import { Opt, Doc, HeightSym, WidthSym, Field, DocListCast } from "../../../new_fields/Doc";
+import { Opt } from "../../../new_fields/Doc";
import "./PDFViewer.scss";
import "pdfjs-dist/web/pdf_viewer.css";
import { PDFBox } from "../nodes/PDFBox";
-import { PDFAnnotationLayer } from "./PDFAnnotationLayer";
-import { TSMethodSignature } from "babel-types";
-import { checkPropTypes } from "prop-types";
-import { DragManager } from "../../util/DragManager";
-import { Docs } from "../../documents/Documents";
-import { List } from "../../../new_fields/List";
-import { Cast } from "../../../new_fields/Types";
-import { emptyFunction } from "../../../Utils";
-const Curly = require("./curly.png");
+import Page from "./Page";
interface IPDFViewerProps {
url: string;
@@ -168,7 +160,7 @@ class Viewer extends React.Component<IViewerProps> {
parent={this.props.parent}
{...this.props} />
));
- let arr = Array.from(Array(numPages).keys()).map(i => false);
+ let arr = Array.from(Array(numPages).keys()).map(() => false);
this._visibleElements.push(...divs);
this._isPage.push(...arr);
}
@@ -263,316 +255,3 @@ class Viewer extends React.Component<IViewerProps> {
);
}
}
-
-interface IPageProps {
- pdf: Opt<Pdfjs.PDFDocumentProxy>;
- name: string;
- numPages: number;
- page: number;
- pageLoaded: (index: number, page: Pdfjs.PDFPageViewport) => void;
- parent: PDFBox;
-}
-
-@observer
-class Page extends React.Component<IPageProps> {
- @observable private _state: string = "N/A";
- @observable private _width: number = 0;
- @observable private _height: number = 0;
- @observable private _page: Opt<Pdfjs.PDFPageProxy>;
- @observable private _currPage: number = this.props.page + 1;
- @observable private _marqueeX: number = 0;
- @observable private _marqueeY: number = 0;
- @observable private _marqueeWidth: number = 0;
- @observable private _marqueeHeight: number = 0;
- @observable private _rotate: string = "";
-
- private _canvas: React.RefObject<HTMLCanvasElement>;
- private _textLayer: React.RefObject<HTMLDivElement>;
- private _annotationLayer: React.RefObject<HTMLDivElement>;
- private _marquee: React.RefObject<HTMLDivElement>;
- private _curly: React.RefObject<HTMLImageElement>;
- private _currentAnnotations: HTMLDivElement[] = [];
- private _marqueeing: boolean = false;
-
- constructor(props: IPageProps) {
- super(props);
- this._canvas = React.createRef();
- this._textLayer = React.createRef();
- this._annotationLayer = React.createRef();
- this._marquee = React.createRef();
- this._curly = React.createRef();
- }
-
- componentDidMount() {
- if (this.props.pdf) {
- this.update(this.props.pdf);
- }
- }
-
- componentDidUpdate() {
- if (this.props.pdf) {
- this.update(this.props.pdf);
- }
- }
-
- private update = (pdf: Pdfjs.PDFDocumentProxy) => {
- if (pdf) {
- this.loadPage(pdf);
- }
- else {
- this._state = "loading";
- }
- }
-
- private loadPage = (pdf: Pdfjs.PDFDocumentProxy) => {
- if (this._state === "rendering" || this._page) return;
-
- pdf.getPage(this._currPage).then(
- (page: Pdfjs.PDFPageProxy) => {
- this._state = "rendering";
- this.renderPage(page);
- }
- );
- }
-
- @action
- private renderPage = (page: Pdfjs.PDFPageProxy) => {
- let scale = 1;
- let viewport = page.getViewport(scale);
- let canvas = this._canvas.current;
- let textLayer = this._textLayer.current;
- if (canvas && textLayer) {
- let ctx = canvas.getContext("2d");
- canvas.width = viewport.width;
- this._width = viewport.width;
- canvas.height = viewport.height;
- this._height = viewport.height;
- this.props.pageLoaded(this._currPage, viewport);
- if (ctx) {
- // renders the page onto the canvas context
- page.render({ canvasContext: ctx, viewport: viewport });
- // renders text onto the text container
- page.getTextContent().then((res: Pdfjs.TextContent) => {
- //@ts-ignore
- Pdfjs.renderTextLayer({
- textContent: res,
- container: textLayer,
- viewport: viewport
- });
- });
-
- this._page = page;
- }
- }
- }
-
- makeAnnotationDocuments = (targetDoc: Doc): Doc[] => {
- let annoDocs: Doc[] = [];
- for (let anno of this._currentAnnotations) {
- let annoDoc = new Doc();
- annoDoc.x = anno.offsetLeft;
- annoDoc.y = anno.offsetTop;
- annoDoc.height = anno.offsetHeight;
- annoDoc.width = anno.offsetWidth;
- annoDoc.target = targetDoc;
- annoDocs.push(annoDoc);
- }
- return annoDocs;
- }
-
- startDrag = (e: PointerEvent) => {
- console.log("start drag");
- e.preventDefault();
- document.removeEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.endDrag);
- let thisDoc = this.props.parent.Document;
- let targetDoc = Docs.TextDocument();
- let annotationDocs = this.makeAnnotationDocuments(targetDoc);
- targetDoc.annotations = new List(annotationDocs);
- let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDocs, targetDoc);
- DragManager.StartAnnotationDrag(this._currentAnnotations, dragData, e.pageX, e.pageY, {
- handlers: {
- dragComplete: action(emptyFunction),
- },
- hideSource: false
- });
- e.stopPropagation();
- }
-
- endDrag = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.endDrag);
- e.stopPropagation();
- }
-
- @action
- onPointerDown = (e: React.PointerEvent) => {
- if (e.shiftKey && e.button === 0) {
- e.stopPropagation();
-
- document.removeEventListener("pointermove", this.startDrag);
- document.addEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.endDrag);
- document.addEventListener("pointerup", this.endDrag);
- }
- else if (e.button === 0) {
- let target: any = e.target;
- if (target && target.parentElement === this._textLayer.current) {
- e.stopPropagation();
- }
- else {
- e.stopPropagation();
- runInAction(() => {
- let current = this._textLayer.current;
- if (current) {
- let boundingRect = current.getBoundingClientRect();
- this._marqueeX = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
- this._marqueeY = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
- }
- });
- this._marqueeing = true;
- if (this._marquee.current) this._marquee.current.style.opacity = "0.2";
- }
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- if (!e.ctrlKey) {
- for (let anno of this._currentAnnotations) {
- anno.remove();
- }
- }
- }
- }
-
- @action
- onPointerMove = (e: PointerEvent) => {
- let target: any = e.target;
- if (this._marqueeing) {
- let current = this._textLayer.current;
- if (current) {
- let boundingRect = current.getBoundingClientRect();
- this._marqueeWidth = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width) - this._marqueeX;
- this._marqueeHeight = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height) - this._marqueeY;
- if (this._marquee.current && this._curly.current) {
- if (this._marqueeWidth > 100 && this._marqueeHeight > 100) {
- this._marquee.current.style.background = "red";
- this._curly.current.style.opacity = "0";
- }
- else {
- this._marquee.current.style.background = "transparent";
- this._curly.current.style.opacity = "1";
- }
-
- let ratio = this._marqueeWidth / this._marqueeHeight;
- if (ratio > 1.5) {
- // vertical
- this._rotate = "rotate(90deg) scale(1, 2)";
- }
- else if (ratio < 0.5) {
- // horizontal
- this._rotate = "scale(2, 1)";
- }
- else {
- // diagonal
- this._rotate = "rotate(45deg) scale(1.5, 1.5)";
- }
- }
- }
- e.stopPropagation();
- e.preventDefault();
- }
- else if (target && target.parentElement === this._textLayer.current) {
- e.stopPropagation();
- }
- }
-
- startAnnotation = (e: DragEvent) => {
- console.log("drag starting");
- }
-
- pointerDownCancel = (e: PointerEvent) => {
- e.stopPropagation();
- }
-
- @action
- onPointerUp = (e: PointerEvent) => {
- if (this._marqueeing) {
- this._marqueeing = false;
- if (this._marquee.current) {
- let copy = document.createElement("div");
- copy.style.left = this._marquee.current.style.left;
- copy.style.top = this._marquee.current.style.top;
- copy.style.width = this._marquee.current.style.width;
- copy.style.height = this._marquee.current.style.height;
- copy.style.opacity = this._marquee.current.style.opacity;
- copy.className = this._marquee.current.className;
- if (this._annotationLayer.current) {
- this._annotationLayer.current.append(copy);
- this._currentAnnotations.push(copy);
- }
- this._marquee.current.style.opacity = "0";
- }
-
- this._marqueeHeight = this._marqueeWidth = 0;
- }
- else {
- let sel = window.getSelection();
- // if selecting over a range of things
- if (sel && sel.type === "Range") {
- let clientRects = sel.getRangeAt(0).getClientRects();
- if (this._textLayer.current) {
- let boundingRect = this._textLayer.current.getBoundingClientRect();
- for (let i = 0; i < clientRects.length; i++) {
- let rect = clientRects.item(i);
- if (rect) {
- let annoBox = document.createElement("div");
- annoBox.className = "pdfViewer-annotationBox";
- // transforms the positions from screen onto the pdf div
- annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
- annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
- annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
- annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
- annoBox.ondragstart = this.startAnnotation;
- annoBox.onpointerdown = this.pointerDownCancel;
- if (this._annotationLayer.current) this._annotationLayer.current.append(annoBox);
- this._currentAnnotations.push(annoBox);
- }
- }
- }
- if (sel.empty) { // Chrome
- sel.empty();
- } else if (sel.removeAllRanges) { // Firefox
- sel.removeAllRanges();
- }
- }
- }
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
-
- annotationPointerDown = (e: React.PointerEvent) => {
- console.log("annotation");
- }
-
- // imgVisible = () => {
- // return this._marqueeWidth < 100 && this._marqueeHeight < 100 ? { opacity: "1" } : { opacity: "0" }
- // }
-
- render() {
- return (
- <div onPointerDown={this.onPointerDown} className={this.props.name} style={{ "width": this._width, "height": this._height }}>
- <div className="canvasContainer">
- <canvas ref={this._canvas} />
- </div>
- <div className="pdfAnnotationLayer-cont" ref={this._annotationLayer} style={{ width: "100%", height: "100%", position: "relative", top: "-100%" }}>
- <div className="pdfViewer-annotationBox" ref={this._marquee}
- style={{ left: `${this._marqueeX}px`, top: `${this._marqueeY}px`, width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px`, background: "transparent" }}>
- <img ref={this._curly} src="https://static.thenounproject.com/png/331760-200.png" style={{ width: "100%", height: "100%", transform: `${this._rotate}` }} />
- </div>
- </div>
- <div className="textlayer" ref={this._textLayer} style={{ "position": "relative", "top": `-${2 * this._height}px`, "height": `${this._height}px` }} />
- </div>
- );
- }
-} \ No newline at end of file
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
new file mode 100644
index 000000000..7cd72b27f
--- /dev/null
+++ b/src/client/views/pdf/Page.tsx
@@ -0,0 +1,382 @@
+import { observer } from "mobx-react";
+import React = require("react");
+import { observable, action, runInAction } from "mobx";
+import * as Pdfjs from "pdfjs-dist";
+import { Opt, Doc, FieldResult, Field } from "../../../new_fields/Doc";
+import "./PDFViewer.scss";
+import "pdfjs-dist/web/pdf_viewer.css";
+import { PDFBox } from "../nodes/PDFBox";
+import { DragManager } from "../../util/DragManager";
+import { Docs } from "../../documents/Documents";
+import { List } from "../../../new_fields/List";
+import { emptyFunction } from "../../../Utils";
+import { Cast, NumCast } from "../../../new_fields/Types";
+import { listSpec } from "../../../new_fields/Schema";
+
+interface IPageProps {
+ pdf: Opt<Pdfjs.PDFDocumentProxy>;
+ name: string;
+ numPages: number;
+ page: number;
+ pageLoaded: (index: number, page: Pdfjs.PDFPageViewport) => void;
+ parent: PDFBox;
+}
+
+@observer
+export default class Page extends React.Component<IPageProps> {
+ @observable private _state: string = "N/A";
+ @observable private _width: number = 0;
+ @observable private _height: number = 0;
+ @observable private _page: Opt<Pdfjs.PDFPageProxy>;
+ @observable private _currPage: number = this.props.page + 1;
+ @observable private _marqueeX: number = 0;
+ @observable private _marqueeY: number = 0;
+ @observable private _marqueeWidth: number = 0;
+ @observable private _marqueeHeight: number = 0;
+ @observable private _rotate: string = "";
+ @observable private _annotations: List<Doc> = new List<Doc>();
+
+ private _canvas: React.RefObject<HTMLCanvasElement>;
+ private _textLayer: React.RefObject<HTMLDivElement>;
+ private _annotationLayer: React.RefObject<HTMLDivElement>;
+ private _marquee: React.RefObject<HTMLDivElement>;
+ private _curly: React.RefObject<HTMLImageElement>;
+ private _currentAnnotations: HTMLDivElement[] = [];
+ private _marqueeing: boolean = false;
+ private _dragging: boolean = false;
+
+ constructor(props: IPageProps) {
+ super(props);
+ this._canvas = React.createRef();
+ this._textLayer = React.createRef();
+ this._annotationLayer = React.createRef();
+ this._marquee = React.createRef();
+ this._curly = React.createRef();
+ }
+
+ componentDidMount() {
+ if (this.props.pdf) {
+ this.update(this.props.pdf);
+ }
+ }
+
+ componentDidUpdate() {
+ if (this.props.pdf) {
+ this.update(this.props.pdf);
+ }
+ }
+
+ private update = (pdf: Pdfjs.PDFDocumentProxy) => {
+ if (pdf) {
+ this.loadPage(pdf);
+ }
+ else {
+ this._state = "loading";
+ }
+ }
+
+ private loadPage = (pdf: Pdfjs.PDFDocumentProxy) => {
+ if (this._state === "rendering" || this._page) return;
+
+ pdf.getPage(this._currPage).then(
+ (page: Pdfjs.PDFPageProxy) => {
+ this._state = "rendering";
+ this.renderPage(page);
+ }
+ );
+ }
+
+ @action
+ private renderPage = (page: Pdfjs.PDFPageProxy) => {
+ // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes
+ let scale = 2;
+ let viewport = page.getViewport(scale);
+ let canvas = this._canvas.current;
+ let textLayer = this._textLayer.current;
+ if (canvas && textLayer) {
+ let ctx = canvas.getContext("2d");
+ canvas.width = viewport.width;
+ this._width = viewport.width;
+ canvas.height = viewport.height;
+ this._height = viewport.height;
+ this.props.pageLoaded(this._currPage, viewport);
+ if (ctx) {
+ // renders the page onto the canvas context
+ page.render({ canvasContext: ctx, viewport: viewport });
+ // renders text onto the text container
+ page.getTextContent().then((res: Pdfjs.TextContent) => {
+ //@ts-ignore
+ Pdfjs.renderTextLayer({
+ textContent: res,
+ container: textLayer,
+ viewport: viewport
+ });
+ });
+
+ this._page = page;
+ }
+ }
+ }
+
+ /**
+ * @param targetDoc: Document that annotations are linked to
+ * This method makes the list of current annotations into documents linked to
+ * the parameter passed in.
+ */
+ makeAnnotationDocuments = (targetDoc: Doc): Doc[] => {
+ let annoDocs: Doc[] = [];
+ for (let anno of this._currentAnnotations) {
+ let annoDoc = new Doc();
+ annoDoc.x = anno.offsetLeft;
+ annoDoc.y = anno.offsetTop;
+ annoDoc.height = anno.offsetHeight;
+ annoDoc.width = anno.offsetWidth;
+ annoDoc.target = targetDoc;
+ annoDocs.push(annoDoc);
+ anno.remove();
+ }
+ this._currentAnnotations = [];
+ return annoDocs;
+ }
+
+ /**
+ * This is temporary for creating annotations from highlights. It will
+ * start a drag event and create or put the necessary info into the drag event.
+ */
+ @action
+ startDrag = (e: PointerEvent) => {
+ // the first 5 lines is a hack to prevent text selection while dragging
+ e.preventDefault();
+ e.stopPropagation();
+ if (this._dragging) {
+ return;
+ }
+ this._dragging = true;
+ let thisDoc = this.props.parent.Document;
+ // document that this annotation is linked to
+ 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 targetAnnotations = Cast(targetDoc.annotations, listSpec(Doc));
+ if (targetAnnotations) {
+ targetAnnotations.push(...annotationDocs);
+ targetDoc.annotations = targetAnnotations;
+ }
+ // temporary code (currently broken ? 6/7/19) to get annotations to rerender on pdf
+ let thisAnnotations = Cast(this.props.parent.Document.annotations, listSpec(Doc));
+ if (thisAnnotations) {
+ thisAnnotations.push(...annotationDocs);
+ this.props.parent.Document.annotations = thisAnnotations;
+ let temp = new List<Doc>(thisAnnotations);
+ temp.push(...this._annotations);
+ this._annotations = temp;
+ }
+ // create dragData and star tdrag
+ let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDocs, targetDoc);
+ if (this._textLayer.current) {
+ DragManager.StartAnnotationDrag([this._textLayer.current], dragData, e.pageX, e.pageY, {
+ handlers: {
+ dragComplete: action(emptyFunction),
+ },
+ hideSource: false
+ });
+ }
+ }
+
+ // cleans up events and boolean
+ endDrag = (e: PointerEvent): void => {
+ document.removeEventListener("pointermove", this.startDrag);
+ document.removeEventListener("pointerup", this.endDrag);
+ this._dragging = false;
+ e.stopPropagation();
+ }
+
+ @action
+ onPointerDown = (e: React.PointerEvent) => {
+ // if alt+left click, drag and annotate
+ if (e.altKey && e.button === 0) {
+ e.stopPropagation();
+
+ document.removeEventListener("pointermove", this.startDrag);
+ document.addEventListener("pointermove", this.startDrag);
+ document.removeEventListener("pointerup", this.endDrag);
+ document.addEventListener("pointerup", this.endDrag);
+ }
+ else if (e.button === 0) {
+ let target: any = e.target;
+ if (target && target.parentElement === this._textLayer.current) {
+ e.stopPropagation();
+ }
+ else {
+ e.stopPropagation();
+ // set marquee x and y positions to the spatially transformed position
+ let current = this._textLayer.current;
+ if (current) {
+ let boundingRect = current.getBoundingClientRect();
+ this._marqueeX = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
+ this._marqueeY = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
+ }
+ this._marqueeing = true;
+ if (this._marquee.current) this._marquee.current.style.opacity = "0.2";
+ }
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointerup", this.onPointerUp);
+ if (!e.ctrlKey) {
+ for (let anno of this._currentAnnotations) {
+ anno.remove();
+ }
+ this._currentAnnotations = [];
+ }
+ }
+ }
+
+ @action
+ onPointerMove = (e: PointerEvent) => {
+ let target: any = e.target;
+ if (this._marqueeing) {
+ let current = this._textLayer.current;
+ if (current) {
+ let boundingRect = current.getBoundingClientRect();
+ this._marqueeWidth = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width) - this._marqueeX;
+ this._marqueeHeight = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height) - this._marqueeY;
+ if (this._marquee.current && this._curly.current) {
+ if (this._marqueeWidth > 100 && this._marqueeHeight > 100) {
+ this._marquee.current.style.background = "red";
+ this._curly.current.style.opacity = "0";
+ }
+ else {
+ this._marquee.current.style.background = "transparent";
+ this._curly.current.style.opacity = "1";
+ }
+
+ let ratio = this._marqueeWidth / this._marqueeHeight;
+ if (ratio > 1.5) {
+ // vertical
+ this._rotate = "rotate(90deg) scale(1, 2)";
+ }
+ else if (ratio < 0.5) {
+ // horizontal
+ this._rotate = "scale(2, 1)";
+ }
+ else {
+ // diagonal
+ this._rotate = "rotate(45deg) scale(1.5, 1.5)";
+ }
+ }
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ else if (target && target.parentElement === this._textLayer.current) {
+ e.stopPropagation();
+ }
+ }
+
+ startAnnotation = () => {
+ console.log("drag starting");
+ }
+
+ pointerDownCancel = (e: PointerEvent) => {
+ e.stopPropagation();
+ }
+
+ @action
+ onPointerUp = () => {
+ if (this._marqueeing) {
+ this._marqueeing = false;
+ if (this._marquee.current) {
+ let copy = document.createElement("div");
+ copy.style.left = this._marquee.current.style.left;
+ copy.style.top = this._marquee.current.style.top;
+ copy.style.width = this._marquee.current.style.width;
+ copy.style.height = this._marquee.current.style.height;
+ copy.style.opacity = this._marquee.current.style.opacity;
+ copy.className = this._marquee.current.className;
+ if (this._annotationLayer.current) {
+ this._annotationLayer.current.append(copy);
+ this._currentAnnotations.push(copy);
+ }
+ this._marquee.current.style.opacity = "0";
+ }
+
+ this._marqueeHeight = this._marqueeWidth = 0;
+ }
+ else {
+ let sel = window.getSelection();
+ // if selecting over a range of things
+ if (sel && sel.type === "Range") {
+ let clientRects = sel.getRangeAt(0).getClientRects();
+ if (this._textLayer.current) {
+ let boundingRect = this._textLayer.current.getBoundingClientRect();
+ for (let i = 0; i < clientRects.length; i++) {
+ let rect = clientRects.item(i);
+ if (rect) {
+ let annoBox = document.createElement("div");
+ annoBox.className = "pdfViewer-annotationBox";
+ // transforms the positions from screen onto the pdf div
+ annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
+ annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
+ annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
+ annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
+ annoBox.ondragstart = this.startAnnotation;
+ annoBox.onpointerdown = this.pointerDownCancel;
+ if (this._annotationLayer.current) this._annotationLayer.current.append(annoBox);
+ this._currentAnnotations.push(annoBox);
+ }
+ }
+ }
+ if (sel.empty) { // Chrome
+ sel.empty();
+ } else if (sel.removeAllRanges) { // Firefox
+ sel.removeAllRanges();
+ }
+ }
+ }
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ renderAnnotation = (anno: Doc | undefined): HTMLDivElement => {
+ let annoBox = document.createElement("div");
+ if (anno) {
+ annoBox.className = "pdfViewer-annotationBox";
+ // transforms the positions from screen onto the pdf div
+ annoBox.style.top = NumCast(anno.x).toString();
+ annoBox.style.left = NumCast(anno.y).toString();
+ annoBox.style.width = NumCast(anno.width).toString();
+ annoBox.style.height = NumCast(anno.height).toString()
+ annoBox.onpointerdown = this.pointerDownCancel;
+ }
+ return annoBox;
+ }
+
+ annotationPointerDown = () => {
+ console.log("annotation");
+ }
+
+ // imgVisible = () => {
+ // return this._marqueeWidth < 100 && this._marqueeHeight < 100 ? { opacity: "1" } : { opacity: "0" }
+ // }
+
+ render() {
+ let annotations = this._annotations;
+ return (
+ <div onPointerDown={this.onPointerDown} className={this.props.name} style={{ "width": this._width, "height": this._height }}>
+ <div className="canvasContainer">
+ <canvas ref={this._canvas} />
+ </div>
+ <div className="pdfAnnotationLayer-cont" ref={this._annotationLayer} style={{ width: "100%", height: "100%", position: "relative", top: "-100%" }}>
+ <div className="pdfViewer-annotationBox" ref={this._marquee}
+ style={{ left: `${this._marqueeX}px`, top: `${this._marqueeY}px`, width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px`, background: "transparent" }}>
+ <img ref={this._curly} src="https://static.thenounproject.com/png/331760-200.png" style={{ width: "100%", height: "100%", transform: `${this._rotate}` }} />
+ </div>
+ {annotations.map(anno => this.renderAnnotation(anno instanceof Doc ? anno : undefined))}
+ </div>
+ <div className="textlayer" ref={this._textLayer} style={{ "position": "relative", "top": `-${2 * this._height}px`, "height": `${this._height}px` }} />
+ </div>
+ );
+ }
+} \ No newline at end of file