diff options
-rw-r--r-- | src/documents/Documents.ts | 53 | ||||
-rw-r--r-- | src/fields/PDFField.ts | 17 | ||||
-rw-r--r-- | src/views/nodes/ImageBox.tsx | 455 | ||||
-rw-r--r-- | src/views/nodes/PDFBox.scss | 0 | ||||
-rw-r--r-- | src/views/nodes/PDFBox.tsx | 102 | ||||
-rw-r--r-- | src/views/nodes/Sticky.tsx | 40 |
6 files changed, 347 insertions, 320 deletions
diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts index cca6f50e9..61d2e18b9 100644 --- a/src/documents/Documents.ts +++ b/src/documents/Documents.ts @@ -11,8 +11,6 @@ import { ImageField } from "../fields/ImageField"; import { ImageBox } from "../views/nodes/ImageBox"; import { CollectionFreeFormView } from "../views/collections/CollectionFreeFormView"; import { FIELD_ID } from "../fields/Field"; -import { PDFBox } from "../views/nodes/PDFBox"; -import { PDFField } from "../fields/PDFField"; interface DocumentOptions { x?: number; @@ -128,31 +126,32 @@ export namespace Documents { return Server.GetDocument(imageProtoId, true)!; } - let PDFProtoId: FIELD_ID; - function GetPDFPrototype(): Document { - if (PDFProtoId === undefined) { - let PDFProto = new Document(); - PDFProtoId = PDFProto.Id; - PDFProto.Set(KeyStore.Title, new TextField("PDF PROTO")); - PDFProto.Set(KeyStore.X, new NumberField(0)); - PDFProto.Set(KeyStore.Y, new NumberField(0)); - PDFProto.Set(KeyStore.Width, new NumberField(300)); - PDFProto.Set(KeyStore.Height, new NumberField(300)); - PDFProto.Set(KeyStore.Layout, new TextField(PDFBox.LayoutString())); - PDFProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); - Server.AddDocument(PDFProto); - return PDFProto; - } - return Server.GetDocument(PDFProtoId, true)!; - } - - export function PDFDocument(url: string, options: DocumentOptions = {}): Document{ - let doc = GetPDFPrototype().MakeDelegate(); - setupOptions(doc, options); - doc.Set(KeyStore.Data, new PDFField(new URL(url))); - Server.AddDocument(doc); - return Server.GetDocument(doc.Id, true); - } + //for PDF + //let PDFProtoId: FIELD_ID; + //function GetPDFPrototype(): Document { + //if (PDFProtoId === undefined) { + //let PDFProto = new Document(); + //PDFProtoId = PDFProto.Id; + //PDFProto.Set(KeyStore.Title, new TextField("PDF PROTO")); + // PDFProto.Set(KeyStore.X, new NumberField(0)); + //PDFProto.Set(KeyStore.Y, new NumberField(0)); + //PDFProto.Set(KeyStore.Width, new NumberField(300)); + // PDFProto.Set(KeyStore.Height, new NumberField(300)); + // PDFProto.Set(KeyStore.Layout, new TextField(PDFBox.LayoutString())); + //PDFProto.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); + //Server.AddDocument(PDFProto); + // return PDFProto; + //} + //return Server.GetDocument(PDFProtoId, true)!; + //} + + //export function PDFDocument(url: string, options: DocumentOptions = {}): Document{ + //let doc = GetPDFPrototype().MakeDelegate(); + //setupOptions(doc, options); + //doc.Set(KeyStore.Data, new PDFField(new URL(url))); + //Server.AddDocument(doc); + //return Server.GetDocument(doc.Id, true); + //} export function ImageDocument(url: string, options: DocumentOptions = {}): Document { let doc = GetImagePrototype().MakeDelegate(); diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts deleted file mode 100644 index fe74cd99e..000000000 --- a/src/fields/PDFField.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BasicField } from "./BasicField"; -import { Field } from "./Field"; - -export class PDFField extends BasicField<URL> { - constructor(data: URL | undefined = undefined) { - super(data == undefined ? new URL("") : data); - } - - toString(): string { - return this.Data.href; - } - - Copy(): Field { - return new PDFField(this.Data); - } - -}
\ No newline at end of file diff --git a/src/views/nodes/ImageBox.tsx b/src/views/nodes/ImageBox.tsx index 2f7cbbcc4..f53d94a6d 100644 --- a/src/views/nodes/ImageBox.tsx +++ b/src/views/nodes/ImageBox.tsx @@ -1,247 +1,400 @@ - -import Lightbox from 'react-image-lightbox'; -import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import { SelectionManager } from "../../util/SelectionManager"; +import 'react-image-lightbox/style.css'; import "./ImageBox.scss"; import React = require("react") -import { ImageField } from '../../fields/ImageField'; import { FieldViewProps, FieldView } from './FieldView'; -import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; -import { FieldWaiting } from '../../fields/Field'; import { observer } from "mobx-react" import { observable, action } from 'mobx'; import 'react-pdf/dist/Page/AnnotationLayer.css' //@ts-ignore import { Document, Page, PDFPageProxy, PageAnnotation} from "react-pdf"; import { Utils } from '../../Utils'; -import { any } from 'prop-types'; -import { Sticky } from './Sticky'; - +import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here +import { Annotation } from './Annotation'; + +/** ALSO LOOK AT: Annotation.tsx, Sticky.tsx + * + * Ok, so I know I built PDFNode on a ImageBox, but this method works... maybe make a duplicate + * and call it PDFNode. + * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, + * area selection (I call it stickies), embedded ink node for directly annotating using a pen or + * mouse, and pagination. + * + * Clearly, everything works perfectly. No bugs. Might as well publish it. + * + * ps watch out for some bugs. When highlighting, just highlight a section of one line... do not multiline highlight... plz + * + * + * + * + * + * HOW TO USE: + * AREA selection: + * 1) Click on Area button. + * 2) click on any part of the PDF, and drag to get desired sized area shape + * 3) You can write on the area (hence the reason why it's called sticky) + * 4) to make another area, you need to click on area button AGAIN. + * + * HIGHLIGHT: (Buggy. No multiline/multidiv text highlighting for now...) + * 1) just click and drag on a text + * 2) click highlight + * 3) for annotation, just pull your cursor over to that text + * 4) another method: click on highlight first and then drag on your desired text + * 5) To make another highlight, you need to reclick on the button + * + * Draw: + * 1) click draw and select color. then just draw like there's no tomorrow. + * 2) once you finish drawing your masterpiece, just reclick on the draw button to end your drawing session. + * + * Pagination: + * 1) click on arrows. You'll notice that stickies will stay in those page. But... highlights won't. + * 2) to test this out, make few area/stickies and then click on next page then come back. You'll see that they are all saved. + * + * + * written by: Andrew Kim + */ @observer export class ImageBox extends React.Component<FieldViewProps> { public static LayoutString() { return FieldView.LayoutString("ImageBox"); } - private _ref: React.RefObject<HTMLDivElement>; - private _mainDiv = React.createRef<HTMLDivElement>() + private _pdf = React.createRef<HTMLCanvasElement>(); + + //very useful for keeping track of X and y position throughout the PDF Canvas + private initX:number = 0; + private initY:number = 0; - private _downX: number = 0; - private _downY: number = 0; - private _lastTap: number = 0; - - @observable - private stickies:any[] = [] - - @observable private _photoIndex: number = 0; - @observable private _isOpen: boolean = false; - - constructor(props: FieldViewProps) { - super(props); - - this._ref = React.createRef(); - this.state = { - photoIndex: 0, - isOpen: false, - }; - } - - componentDidMount() { - } - - componentWillUnmount() { - } - + //checks if tool is on + private _toolOn:boolean = false; //checks if tool is on + private _pdfContext:any = null; //gets pdf context + private bool:Boolean = false; //general boolean debounce + private currSpan:any;//keeps track of current span (for highlighting) - + private _currTool: any; //keeps track of current tool button reference + private _drawToolOn:boolean = false; //boolean that keeps track of the drawing tool + private _drawTool = React.createRef<HTMLButtonElement>()//drawing tool button reference + + private _colorTool = React.createRef<HTMLButtonElement>(); //color button reference + private _currColor:string = "black"; //current color that user selected (for ink/pen) + + private _highlightTool = React.createRef<HTMLButtonElement>(); //highlighter button reference + private _highlightToolOn:boolean = false; + + @observable private stickies:any[] = [] //for storing CURRENT stickies + @observable private page:number = 1; //default is the first page. + @observable private numPage:number = 1; //default number of pages + @observable private stickiesPerPage: any = null; //for indexing stickies for EVERY PAGE + @observable private annotations:any[] = []; //keeps track of annotations + + /** + * for pagination backwards + */ @action onPageBack = () => { if (this.page > 1){ - this.page -= 1; - this.stickies = this.stickiesPerPage[this.page - 1]; + this.page -= 1; + this.stickiesPerPage[this.page] = this.stickies; //stores previous sticky and indexes to stickiesPerPage + this.stickies = []; //sets stickies to null array + if (this.stickies){//checks stickies is null or not + this.stickies = this.stickiesPerPage[this.page - 1]; //pulls up stickies for this page + } + } } + /** + * for pagination forwards + */ @action onPageForward = () => { if (this.page < this.numPage){ this.page += 1; - this.stickies = this.stickiesPerPage[this.page - 1]; + this.stickiesPerPage[this.page - 2] = this.stickies; //stores previous sticky and indexes to stickiesPerPage + this.stickies = []; //sets stickies to null array + if (this.stickiesPerPage[this.page - 1]){ + this.stickies = this.stickiesPerPage[this.page - 1]; //pulls up sticky for this page + } } } - - - @observable - searchText:string = ''; - - @observable - page:number = 1; //default is the first page. - - @observable - numPage:number = 1; //default number of pages - - @observable - stickiesPerPage: any = [...Array(this.numPage)].map(() => Array(1)); //makes 2d array for storage - - private textContent:any = null; - - private initX:number = 0; - private initY:number = 0; - - private _toolOn:boolean = false; - - + + /** + * selection tool used for area highlighting (stickies). Kinda temporary + */ selectionTool = () => { this._toolOn = true; } + /** + * when user draws on the canvas. When mouse pointer is down + */ + drawDown = (e:PointerEvent) => { + this.initX = e.offsetX; + this.initY = e.offsetY; + this._pdfContext.beginPath(); + this._pdfContext.lineTo(this.initX, this.initY); + this._pdfContext.strokeStyle = this._currColor; + document.addEventListener("pointermove", this.drawMove); + document.addEventListener("pointerup", this.drawUp); + + } - private _highlighter:boolean = false; - - - onPointerDown = (e: React.PointerEvent) => { - - if (this._toolOn){ - let mouse = e.nativeEvent; - this.initX = mouse.offsetX; - this.initY = mouse.offsetY; - } - if (this._highlighter){ - - } + //when user drags + drawMove = (e: PointerEvent):void =>{ + //x and y mouse movement + let x = this.initX += e.movementX, + y = this.initY += e.movementY; + //connects the point + this._pdfContext.lineTo(x, y); + this._pdfContext.stroke(); } + drawUp = (e:PointerEvent) => { + this._pdfContext.closePath(); + document.removeEventListener("pointermove", this.drawMove); + document.removeEventListener("pointerdown", this.drawDown); + document.addEventListener("pointerdown", this.drawDown); + } - makeEditableAndHighlight = (colour:string) => { + + /** + * highlighting helper function + */ + makeEditableAndHighlight = (colour:string) => { var range, sel = window.getSelection(); if (sel.rangeCount && sel.getRangeAt) { range = sel.getRangeAt(0); } document.designMode = "on"; + if (!document.execCommand("HiliteColor", false, colour)) { + document.execCommand("HiliteColor", false, colour); + } + if (range) { sel.removeAllRanges(); sel.addRange(range); - } - if (!document.execCommand("HiliteColor", false, colour)) { - document.execCommand("HIliteColor", false, colour); + let element = range.commonAncestorContainer.parentElement + if (element){ + let childNodes = element.childNodes; + childNodes.forEach((e) => { + if (e.nodeName == "SPAN"){ + let span = e; + span.addEventListener("mouseover", this.onEnter); + } + }) + } } document.designMode = "off"; } + /** + * when the cursor enters the highlight, it pops out annotation. ONLY WORKS FOR SINGLE DIV LINES + */ + @action + onEnter = (e:any) => { + let span:HTMLSpanElement = e.toElement; + this.currSpan = span; + if (e.toElement instanceof HTMLSpanElement){ + this.bool = true; + this.currSpan = span; + if(span.children.length == 0){ //this is why it only works for one div text lines... needs fix + if(span.offsetParent){ + let div = span.offsetParent; + //@ts-ignore + let divX = div.style.left + //@ts-ignore + let divY = div.style.top + //slicing "px" from the end + divX = divX.slice(0, divX.length - 2); //gets X of the DIV element (parent of Span) + divY = divY.slice(0, divY.length - 2); //gets Y of the DIV element (parent of Span) + let annotation = <Annotation key ={Utils.GenerateGuid()} Span = {this.currSpan} X = {divX} Y = {divY - 300} /> + this.annotations.push(annotation); + } + } + } + } - highlight = (colour:string) => { - var range, sel; + /** + * highlight function for highlighting actual text. This works fine. + */ + highlight = (color:string) => { if (window.getSelection()) { try { - console.log(document.getSelection()) - - - if (!document.execCommand("HiliteColor", false, colour)) { - this.makeEditableAndHighlight(colour); - } else if (document.execCommand("HiliteColor", false, "rgba(76, 175, 80, 0.3)")) { - this.makeEditableAndHighlight("black"); + if (!document.execCommand("hiliteColor", false, color)) { + this.makeEditableAndHighlight(color); } + //when the color is not the highlight color } catch (ex) { - this.makeEditableAndHighlight(colour) + this.makeEditableAndHighlight(color) } - } } + /** + * controls the area highlighting (stickies) Kinda temporary + */ + onPointerDown = (e: React.PointerEvent) => { + if (this._toolOn){ + let mouse = e.nativeEvent; + this.initX = mouse.offsetX; + this.initY = mouse.offsetY; + + } + } + + /** + * controls area highlighting and partially highlighting. Kinda temporary + */ @action onPointerUp = (e:React.PointerEvent) => { - this.highlight("rgba(76, 175, 80, 0.3)"); - + if (this._highlightToolOn){ + this.highlight("rgba(76, 175, 80, 0.3)"); //highlights to this default color. + this._highlightToolOn = false; + } if (this._toolOn){ - let mouse = e.nativeEvent; let finalX = mouse.offsetX; let finalY = mouse.offsetY; - let width = Math.abs(finalX - this.initX); - let height = Math.abs(finalY - this.initY); - + let width = Math.abs(finalX - this.initX); //width + let height = Math.abs(finalY - this.initY); //height + + //these two if statements are bidirectional dragging. You can drag from any point to another point and generate sticky + if (finalX < this.initX){ + this.initX = finalX; + } + if (finalY < this.initY){ + this.initY = finalY; + } + if (this._mainDiv.current){ - let sticky = <Sticky key ={Utils.GenerateGuid()}Height = {height} Width = {width} X = {this.initX} Y = {this.initY}/> - this.stickies.push(sticky); - //this.stickiesPerPage[this.page - 1].push(sticky); + let sticky = <Sticky key ={Utils.GenerateGuid()} Height = {height} Width = {width} X = {this.initX} Y = {this.initY}/> + this.stickies.push(sticky); } - this._toolOn = false; } } + + /** + * starts drawing the line when user presses down. + */ + onDraw = () => { + if (this._currTool != null){ + this._currTool.style.backgroundColor = "grey"; + } + this._highlightToolOn = false; + if (this._drawTool.current){ + this._currTool = this._drawTool.current; + if (this._drawToolOn){ + this._drawToolOn = false; + document.removeEventListener("pointerdown", this.drawDown); + document.removeEventListener("pointerup", this.drawUp); + document.removeEventListener("pointermove", this.drawMove); + this._drawTool.current.style.backgroundColor = "grey"; + } else { + this._drawToolOn = true; + document.addEventListener("pointerdown", this.drawDown); + this._drawTool.current.style.backgroundColor = "cyan"; + } + } + } + + /** + * for changing color (for ink/pen) + */ + onColorChange = (e:React.PointerEvent) => { + if (e.currentTarget.innerHTML == "Red"){ + this._currColor = "red"; + } else if (e.currentTarget.innerHTML == "Blue"){ + this._currColor = "blue"; + } else if (e.currentTarget.innerHTML == "Green"){ + this._currColor = "green"; + } else if (e.currentTarget.innerHTML == "Black"){ + this._currColor = "black"; + } + + } - displaySticky = () => { - try{ - this.stickies.filter( () => { - return this.stickies[this.stickies.length - 1] - }).map( (element: any) => { - return element - }) - } catch (ex) { - console.log(ex); //should be null + + /** + * For highlighting (text drag highlighting) + */ + onHighlight = () => { + this._drawToolOn = false; + if (this._currTool != null){ + this._currTool.style.backgroundColor = "grey"; + } + if (this._highlightTool.current){ + this._currTool = this._drawTool.current; + if (this._highlightToolOn){ + this._highlightToolOn = false; + this._highlightTool.current.style.backgroundColor = "grey"; + } else { + this._highlightToolOn = true; + this.highlight("rgba(76, 175, 80, 0.3)"); + this._highlightTool.current.style.backgroundColor = "orange"; + } } } + + + /** + * renders whole lot of shets, including pdf, stickies, and annotations. + */ + render() { return ( <div ref = {this._mainDiv} onPointerDown ={this.onPointerDown} onPointerUp = {this.onPointerUp} > - { this.stickies.filter( () => { + {this.stickies.filter( () => { //for loading stickies (area) return this.stickies[this.stickies.length - 1] }).map( (element: any) => { return element }) - } - - - - } - } - - + } + {this.annotations.filter( () => { //for loading annotations + return this.annotations[this.annotations.length - 1] + }).map( (element: any) => { + return element + }) + } + <button onClick = {this.onPageBack}>{"<"}</button> <button onClick = {this.onPageForward}>{">"}</button> <button onClick ={this.selectionTool}>{"Area"}</button> - <Document - file={Utils.pdf_example} - - onLoadError={ - (error: any) => { - console.log(error); - } - } - > + <button style ={{color: "white", backgroundColor: "grey"}} onClick = {this.onHighlight} ref = {this._highlightTool}>Highlight</button> + <button style ={{color: "white", backgroundColor: "grey"}} ref = {this._drawTool} onClick = {this.onDraw}>{"Draw"}</button> + <button ref = {this._colorTool} onPointerDown = {this.onColorChange}>{"Red"}</button> + <button ref = {this._colorTool} onPointerDown = {this.onColorChange}>{"Blue"}</button> + <button ref = {this._colorTool} onPointerDown = {this.onColorChange}>{"Green"}</button> + <button ref = {this._colorTool} onPointerDown = {this.onColorChange}>{"Black"}</button> + + <Document file={Utils.pdf_example}> <Page pageNumber={this.page} - onLoadSuccess={ - (page: PDFPageProxy) => { - page.getTextContent().then((obj:any) => { - this.textContent = obj - }); + (page:any) => { + if (this._mainDiv.current){ + this._mainDiv.current.childNodes.forEach((element) => { + if (element.nodeName == "DIV"){ + element.childNodes[0].childNodes.forEach((e) => { + if (e.nodeName == "CANVAS"){ + //@ts-ignore + this._pdfContext = e.getContext("2d") + } + }) + } + }) + } this.numPage = page.transport.numPages - + if (this.stickiesPerPage == null){ //only runs once, when stickiesPerPage is null + this.stickiesPerPage = [...Array(this.numPage)].map(() => Array(1)); + } } } - - onGetAnnotationSuccess = { - (anno: any) => { - console.log(anno) - } - } - - - - /> - - - - + /> </Document> - - </div> ); } diff --git a/src/views/nodes/PDFBox.scss b/src/views/nodes/PDFBox.scss deleted file mode 100644 index e69de29bb..000000000 --- a/src/views/nodes/PDFBox.scss +++ /dev/null diff --git a/src/views/nodes/PDFBox.tsx b/src/views/nodes/PDFBox.tsx deleted file mode 100644 index 6d881d530..000000000 --- a/src/views/nodes/PDFBox.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import Lightbox from 'react-image-lightbox'; -import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import { SelectionManager } from "../../util/SelectionManager"; -import "./ImageBox.scss"; -import React = require("react") -import { PDFField } from '../../fields/PDFField'; -import { FieldViewProps, FieldView } from './FieldView'; -import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; -import { FieldWaiting } from '../../fields/Field'; -import { observer } from "mobx-react" - -const {PdfLoader, - PdfHighlighter, - Tip, - Highlight, - Popup, - Spinner, - AreaHighlight} = require( "react-pdf-highlighter" ) - -import { observable, action } from 'mobx'; - -@observer -export class PDFBox extends React.Component<FieldViewProps> { - - public static LayoutString() { return FieldView.LayoutString("ImageBox"); } - private _ref: React.RefObject<HTMLDivElement>; - private _downX: number = 0; - private _downY: number = 0; - private _lastTap: number = 0; - @observable private _photoIndex: number = 0; - @observable private _isOpen: boolean = false; - - constructor(props: FieldViewProps) { - super(props); - - this._ref = React.createRef(); - this.state = { - photoIndex: 0, - isOpen: false, - - }; - } - - componentDidMount() { - } - - componentWillUnmount() { - } - - onPointerDown = (e: React.PointerEvent): void => { - if (Date.now() - this._lastTap < 300) { - if (e.buttons === 1 && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) { - e.stopPropagation(); - this._downX = e.clientX; - - this._downY = e.clientY; - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointerup", this.onPointerUp); - } - } else { - this._lastTap = Date.now(); - } - } - @action - onPointerUp = (e: PointerEvent): void => { - document.removeEventListener("pointerup", this.onPointerUp); - if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { - this._isOpen = true; - } - e.stopPropagation(); - } - - lightbox = (path: string) => { - const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"]; - if (this._isOpen && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) { - return (<Lightbox - mainSrc={images[this._photoIndex]} - nextSrc={images[(this._photoIndex + 1) % images.length]} - prevSrc={images[(this._photoIndex + images.length - 1) % images.length]} - onCloseRequest={() => this.setState({ isOpen: false })} - onMovePrevRequest={action(() => - this._photoIndex = (this._photoIndex + images.length - 1) % images.length - )} - onMoveNextRequest={action(() => - this._photoIndex = (this._photoIndex + 1) % images.length - )} - />) - } - } - - render() { - let field = this.props.doc.Get(this.props.fieldKey); - let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : - field instanceof PDFField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; - - return ( - <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} > - <PdfLoader url={"https://arxiv.org/pdf/1708.08021.pdf"}/> - - </div>) - } -}
\ No newline at end of file diff --git a/src/views/nodes/Sticky.tsx b/src/views/nodes/Sticky.tsx index 254c410c2..ca25c9bdd 100644 --- a/src/views/nodes/Sticky.tsx +++ b/src/views/nodes/Sticky.tsx @@ -1,15 +1,9 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app import { SelectionManager } from "../../util/SelectionManager"; -import "./ImageBox.scss"; import React = require("react") -import { FieldViewProps, FieldView } from './FieldView'; import { observer } from "mobx-react" import { observable, action } from 'mobx'; import 'react-pdf/dist/Page/AnnotationLayer.css' -//@ts-ignore -import { Document, Page, PDFPageProxy, PageAnnotation} from "react-pdf"; -import { Utils } from '../../Utils'; - interface IProps{ Height:number; @@ -18,34 +12,33 @@ interface IProps{ Y:number; } - - +/** + * Sticky, also known as area highlighting, is used to highlight large selection of the PDF file. + * Improvements that could be made: maybe store line array and store that somewhere for future rerendering. + * + * Written By: Andrew Kim + */ @observer export class Sticky extends React.Component<IProps> { - private initX:number = 0; private initY:number = 0; private _ref = React.createRef<HTMLCanvasElement>(); - private ctx:any; - - + private ctx:any; //context that keeps track of sticky canvas + /** + * drawing. Registers the first point that user clicks when mouse button is pressed down on canvas + */ drawDown = (e:React.PointerEvent) => { - if (this._ref.current){ + if (this._ref.current){ this.ctx = this._ref.current.getContext("2d"); let mouse = e.nativeEvent; this.initX = mouse.offsetX; - this.initY = mouse.offsetY; - - //do thiiissss - this.ctx.lineWidth; - + this.initY = mouse.offsetY; this.ctx.beginPath(); this.ctx.lineTo(this.initX, this.initY); this.ctx.strokeStyle = "black"; - document.addEventListener("pointermove", this.drawMove); document.addEventListener("pointerup", this.drawUp); } @@ -59,20 +52,22 @@ export class Sticky extends React.Component<IProps> { //connects the point this.ctx.lineTo(x, y); this.ctx.stroke(); + } + /** + * when user lifts the mouse, the drawing ends + */ drawUp = (e:PointerEvent) => { this.ctx.closePath(); + console.log(this.ctx); document.removeEventListener("pointermove", this.drawMove); } - - render() { return ( <div onPointerDown = {this.drawDown}> <canvas ref = {this._ref} height = {this.props.Height} width = {this.props.Width} - style = {{position:"absolute", top: "20px", left: "0px", @@ -81,7 +76,6 @@ export class Sticky extends React.Component<IProps> { transform: `translate(${this.props.X}px, ${this.props.Y}px)`, opacity: 0.4 }} - /> </div> |