diff options
-rw-r--r-- | src/client/util/DragManager.ts | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/pdf/PDFBox2.tsx | 28 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 327 | ||||
-rw-r--r-- | src/client/views/pdf/Page.tsx | 382 |
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 |