├── .gitignore
├── README.md
├── example
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── static
│ │ ├── output.pdf
│ │ └── test.pdf
├── src
│ ├── App.vue
│ ├── README.md
│ └── main.js
└── yarn.lock
├── package.json
└── src
├── PDFJSAnnotate.js
├── UI
├── arrow.js
├── circle.js
├── edit.js
├── eraser.js
├── event.js
├── index.js
├── page.js
├── pen.js
├── point.js
├── rect.js
├── text.js
└── utils.js
├── a11y
├── createScreenReaderOnly.js
├── initEventHandlers.js
├── insertElementWithinChildren.js
├── insertElementWithinElement.js
├── insertScreenReaderComment.js
├── insertScreenReaderHint.js
├── renderScreenReaderComments.js
└── renderScreenReaderHints.js
├── adapter
├── LocalStoreAdapter.js
├── LocalUserStoreAdapter.js
└── StoreAdapter.js
├── config.js
├── css
├── cmaps
│ ├── 78-EUC-H.bcmap
│ ├── 78-EUC-V.bcmap
│ ├── 78-H.bcmap
│ ├── 78-RKSJ-H.bcmap
│ ├── 78-RKSJ-V.bcmap
│ ├── 78-V.bcmap
│ ├── 78ms-RKSJ-H.bcmap
│ ├── 78ms-RKSJ-V.bcmap
│ ├── 83pv-RKSJ-H.bcmap
│ ├── 90ms-RKSJ-H.bcmap
│ ├── 90ms-RKSJ-V.bcmap
│ ├── 90msp-RKSJ-H.bcmap
│ ├── 90msp-RKSJ-V.bcmap
│ ├── 90pv-RKSJ-H.bcmap
│ ├── 90pv-RKSJ-V.bcmap
│ ├── Add-H.bcmap
│ ├── Add-RKSJ-H.bcmap
│ ├── Add-RKSJ-V.bcmap
│ ├── Add-V.bcmap
│ ├── Adobe-CNS1-0.bcmap
│ ├── Adobe-CNS1-1.bcmap
│ ├── Adobe-CNS1-2.bcmap
│ ├── Adobe-CNS1-3.bcmap
│ ├── Adobe-CNS1-4.bcmap
│ ├── Adobe-CNS1-5.bcmap
│ ├── Adobe-CNS1-6.bcmap
│ ├── Adobe-CNS1-UCS2.bcmap
│ ├── Adobe-GB1-0.bcmap
│ ├── Adobe-GB1-1.bcmap
│ ├── Adobe-GB1-2.bcmap
│ ├── Adobe-GB1-3.bcmap
│ ├── Adobe-GB1-4.bcmap
│ ├── Adobe-GB1-5.bcmap
│ ├── Adobe-GB1-UCS2.bcmap
│ ├── Adobe-Japan1-0.bcmap
│ ├── Adobe-Japan1-1.bcmap
│ ├── Adobe-Japan1-2.bcmap
│ ├── Adobe-Japan1-3.bcmap
│ ├── Adobe-Japan1-4.bcmap
│ ├── Adobe-Japan1-5.bcmap
│ ├── Adobe-Japan1-6.bcmap
│ ├── Adobe-Japan1-UCS2.bcmap
│ ├── Adobe-Korea1-0.bcmap
│ ├── Adobe-Korea1-1.bcmap
│ ├── Adobe-Korea1-2.bcmap
│ ├── Adobe-Korea1-UCS2.bcmap
│ ├── B5-H.bcmap
│ ├── B5-V.bcmap
│ ├── B5pc-H.bcmap
│ ├── B5pc-V.bcmap
│ ├── CNS-EUC-H.bcmap
│ ├── CNS-EUC-V.bcmap
│ ├── CNS1-H.bcmap
│ ├── CNS1-V.bcmap
│ ├── CNS2-H.bcmap
│ ├── CNS2-V.bcmap
│ ├── ETHK-B5-H.bcmap
│ ├── ETHK-B5-V.bcmap
│ ├── ETen-B5-H.bcmap
│ ├── ETen-B5-V.bcmap
│ ├── ETenms-B5-H.bcmap
│ ├── ETenms-B5-V.bcmap
│ ├── EUC-H.bcmap
│ ├── EUC-V.bcmap
│ ├── Ext-H.bcmap
│ ├── Ext-RKSJ-H.bcmap
│ ├── Ext-RKSJ-V.bcmap
│ ├── Ext-V.bcmap
│ ├── GB-EUC-H.bcmap
│ ├── GB-EUC-V.bcmap
│ ├── GB-H.bcmap
│ ├── GB-V.bcmap
│ ├── GBK-EUC-H.bcmap
│ ├── GBK-EUC-V.bcmap
│ ├── GBK2K-H.bcmap
│ ├── GBK2K-V.bcmap
│ ├── GBKp-EUC-H.bcmap
│ ├── GBKp-EUC-V.bcmap
│ ├── GBT-EUC-H.bcmap
│ ├── GBT-EUC-V.bcmap
│ ├── GBT-H.bcmap
│ ├── GBT-V.bcmap
│ ├── GBTpc-EUC-H.bcmap
│ ├── GBTpc-EUC-V.bcmap
│ ├── GBpc-EUC-H.bcmap
│ ├── GBpc-EUC-V.bcmap
│ ├── H.bcmap
│ ├── HKdla-B5-H.bcmap
│ ├── HKdla-B5-V.bcmap
│ ├── HKdlb-B5-H.bcmap
│ ├── HKdlb-B5-V.bcmap
│ ├── HKgccs-B5-H.bcmap
│ ├── HKgccs-B5-V.bcmap
│ ├── HKm314-B5-H.bcmap
│ ├── HKm314-B5-V.bcmap
│ ├── HKm471-B5-H.bcmap
│ ├── HKm471-B5-V.bcmap
│ ├── HKscs-B5-H.bcmap
│ ├── HKscs-B5-V.bcmap
│ ├── Hankaku.bcmap
│ ├── Hiragana.bcmap
│ ├── KSC-EUC-H.bcmap
│ ├── KSC-EUC-V.bcmap
│ ├── KSC-H.bcmap
│ ├── KSC-Johab-H.bcmap
│ ├── KSC-Johab-V.bcmap
│ ├── KSC-V.bcmap
│ ├── KSCms-UHC-H.bcmap
│ ├── KSCms-UHC-HW-H.bcmap
│ ├── KSCms-UHC-HW-V.bcmap
│ ├── KSCms-UHC-V.bcmap
│ ├── KSCpc-EUC-H.bcmap
│ ├── KSCpc-EUC-V.bcmap
│ ├── Katakana.bcmap
│ ├── LICENSE
│ ├── NWP-H.bcmap
│ ├── NWP-V.bcmap
│ ├── RKSJ-H.bcmap
│ ├── RKSJ-V.bcmap
│ ├── Roman.bcmap
│ ├── UniCNS-UCS2-H.bcmap
│ ├── UniCNS-UCS2-V.bcmap
│ ├── UniCNS-UTF16-H.bcmap
│ ├── UniCNS-UTF16-V.bcmap
│ ├── UniCNS-UTF32-H.bcmap
│ ├── UniCNS-UTF32-V.bcmap
│ ├── UniCNS-UTF8-H.bcmap
│ ├── UniCNS-UTF8-V.bcmap
│ ├── UniGB-UCS2-H.bcmap
│ ├── UniGB-UCS2-V.bcmap
│ ├── UniGB-UTF16-H.bcmap
│ ├── UniGB-UTF16-V.bcmap
│ ├── UniGB-UTF32-H.bcmap
│ ├── UniGB-UTF32-V.bcmap
│ ├── UniGB-UTF8-H.bcmap
│ ├── UniGB-UTF8-V.bcmap
│ ├── UniJIS-UCS2-H.bcmap
│ ├── UniJIS-UCS2-HW-H.bcmap
│ ├── UniJIS-UCS2-HW-V.bcmap
│ ├── UniJIS-UCS2-V.bcmap
│ ├── UniJIS-UTF16-H.bcmap
│ ├── UniJIS-UTF16-V.bcmap
│ ├── UniJIS-UTF32-H.bcmap
│ ├── UniJIS-UTF32-V.bcmap
│ ├── UniJIS-UTF8-H.bcmap
│ ├── UniJIS-UTF8-V.bcmap
│ ├── UniJIS2004-UTF16-H.bcmap
│ ├── UniJIS2004-UTF16-V.bcmap
│ ├── UniJIS2004-UTF32-H.bcmap
│ ├── UniJIS2004-UTF32-V.bcmap
│ ├── UniJIS2004-UTF8-H.bcmap
│ ├── UniJIS2004-UTF8-V.bcmap
│ ├── UniJISPro-UCS2-HW-V.bcmap
│ ├── UniJISPro-UCS2-V.bcmap
│ ├── UniJISPro-UTF8-V.bcmap
│ ├── UniJISX0213-UTF32-H.bcmap
│ ├── UniJISX0213-UTF32-V.bcmap
│ ├── UniJISX02132004-UTF32-H.bcmap
│ ├── UniJISX02132004-UTF32-V.bcmap
│ ├── UniKS-UCS2-H.bcmap
│ ├── UniKS-UCS2-V.bcmap
│ ├── UniKS-UTF16-H.bcmap
│ ├── UniKS-UTF16-V.bcmap
│ ├── UniKS-UTF32-H.bcmap
│ ├── UniKS-UTF32-V.bcmap
│ ├── UniKS-UTF8-H.bcmap
│ ├── UniKS-UTF8-V.bcmap
│ ├── V.bcmap
│ └── WP-Symbol.bcmap
├── images
│ ├── annotation-check.svg
│ ├── annotation-comment.svg
│ ├── annotation-help.svg
│ ├── annotation-insert.svg
│ ├── annotation-key.svg
│ ├── annotation-newparagraph.svg
│ ├── annotation-noicon.svg
│ ├── annotation-note.svg
│ ├── annotation-paragraph.svg
│ ├── findbarButton-next-rtl.png
│ ├── findbarButton-next-rtl@2x.png
│ ├── findbarButton-next.png
│ ├── findbarButton-next@2x.png
│ ├── findbarButton-previous-rtl.png
│ ├── findbarButton-previous-rtl@2x.png
│ ├── findbarButton-previous.png
│ ├── findbarButton-previous@2x.png
│ ├── grab.cur
│ ├── grabbing.cur
│ ├── loading-icon.gif
│ ├── loading-small.png
│ ├── loading-small@2x.png
│ ├── secondaryToolbarButton-documentProperties.png
│ ├── secondaryToolbarButton-documentProperties@2x.png
│ ├── secondaryToolbarButton-firstPage.png
│ ├── secondaryToolbarButton-firstPage@2x.png
│ ├── secondaryToolbarButton-handTool.png
│ ├── secondaryToolbarButton-handTool@2x.png
│ ├── secondaryToolbarButton-lastPage.png
│ ├── secondaryToolbarButton-lastPage@2x.png
│ ├── secondaryToolbarButton-rotateCcw.png
│ ├── secondaryToolbarButton-rotateCcw@2x.png
│ ├── secondaryToolbarButton-rotateCw.png
│ ├── secondaryToolbarButton-rotateCw@2x.png
│ ├── shadow.png
│ ├── texture.png
│ ├── toolbarButton-bookmark.png
│ ├── toolbarButton-bookmark@2x.png
│ ├── toolbarButton-download.png
│ ├── toolbarButton-download@2x.png
│ ├── toolbarButton-menuArrows.png
│ ├── toolbarButton-menuArrows@2x.png
│ ├── toolbarButton-openFile.png
│ ├── toolbarButton-openFile@2x.png
│ ├── toolbarButton-pageDown-rtl.png
│ ├── toolbarButton-pageDown-rtl@2x.png
│ ├── toolbarButton-pageDown.png
│ ├── toolbarButton-pageDown@2x.png
│ ├── toolbarButton-pageUp-rtl.png
│ ├── toolbarButton-pageUp-rtl@2x.png
│ ├── toolbarButton-pageUp.png
│ ├── toolbarButton-pageUp@2x.png
│ ├── toolbarButton-presentationMode.png
│ ├── toolbarButton-presentationMode@2x.png
│ ├── toolbarButton-print.png
│ ├── toolbarButton-print@2x.png
│ ├── toolbarButton-search.png
│ ├── toolbarButton-search@2x.png
│ ├── toolbarButton-secondaryToolbarToggle-rtl.png
│ ├── toolbarButton-secondaryToolbarToggle-rtl@2x.png
│ ├── toolbarButton-secondaryToolbarToggle.png
│ ├── toolbarButton-secondaryToolbarToggle@2x.png
│ ├── toolbarButton-sidebarToggle-rtl.png
│ ├── toolbarButton-sidebarToggle-rtl@2x.png
│ ├── toolbarButton-sidebarToggle.png
│ ├── toolbarButton-sidebarToggle@2x.png
│ ├── toolbarButton-viewAttachments.png
│ ├── toolbarButton-viewAttachments@2x.png
│ ├── toolbarButton-viewOutline-rtl.png
│ ├── toolbarButton-viewOutline-rtl@2x.png
│ ├── toolbarButton-viewOutline.png
│ ├── toolbarButton-viewOutline@2x.png
│ ├── toolbarButton-viewThumbnail.png
│ ├── toolbarButton-viewThumbnail@2x.png
│ ├── toolbarButton-zoomIn.png
│ ├── toolbarButton-zoomIn@2x.png
│ ├── toolbarButton-zoomOut.png
│ └── toolbarButton-zoomOut@2x.png
├── pdf_viewer.css
└── toolbar.css
├── initColorPicker.js
├── pdfAnnotate.vue
├── render
├── appendChild.js
├── index.js
├── renderArrow.js
├── renderCircle.js
├── renderLine.js
├── renderPath.js
├── renderPoint.js
├── renderRect.js
└── renderText.js
└── utils
├── abstractFunction.js
├── mathUtils.js
├── normalizeColor.js
├── setAttributes.js
└── uuid.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## pdf-annotate-vue
2 |
3 | > Annotation layer for pdf.js in vue
4 |
5 |
6 | ## Install
7 |
8 | ```
9 | npm install pdf-annotate-vue -S
10 | or
11 | yarn add pdf-annotate-vue -S
12 | ```
13 |
14 | ## Example
15 |
16 | ```vue
17 |
18 |
19 | pdf path: {{pdf}}
20 |
21 |
22 |
23 |
24 |
44 |
45 | ```
46 |
47 |
48 | ## run example
49 |
50 | ```bash
51 | # Clone Project
52 | git clone https://github.com/AaronLeong/pdf-annotate-vue.git
53 |
54 | cd pdf-annotate-vue/example
55 | # Project setup --> install node_modules
56 | yarn install
57 | # Compiles and hot-reloads for development
58 | yarn run serve
59 |
60 | ```
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # pdf-anno-vue
2 |
3 | ## Project setup
4 | ```
5 | yarn install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | yarn run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | yarn run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | yarn run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | yarn run lint
26 | ```
27 |
28 | ### Customize configuration
29 | See [Configuration Reference](https://cli.vuejs.org/config/).
30 |
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pdf-anno-vue",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^2.6.5",
12 | "create-stylesheet": "^0.3.0",
13 | "pdf-annotate-vue": "^1.0.1",
14 | "pdfjs-dist": "^2.0.943",
15 | "vue": "^2.6.10"
16 | },
17 | "devDependencies": {
18 | "@vue/cli-plugin-babel": "^3.8.0",
19 | "@vue/cli-plugin-eslint": "^3.8.0",
20 | "@vue/cli-service": "^3.8.0",
21 | "babel-eslint": "^10.0.1",
22 | "eslint": "^5.16.0",
23 | "eslint-plugin-vue": "^5.0.0",
24 | "vue-template-compiler": "^2.6.10"
25 | },
26 | "eslintConfig": {
27 | "root": true,
28 | "env": {
29 | "node": true
30 | },
31 | "extends": [
32 | "plugin:vue/essential",
33 | "eslint:recommended"
34 | ],
35 | "rules": {},
36 | "parserOptions": {
37 | "parser": "babel-eslint"
38 | }
39 | },
40 | "postcss": {
41 | "plugins": {
42 | "autoprefixer": {}
43 | }
44 | },
45 | "browserslist": [
46 | "> 1%",
47 | "last 2 versions"
48 | ],
49 | "description": "## Project setup ``` yarn install ```",
50 | "main": "babel.config.js",
51 | "author": "",
52 | "license": "ISC"
53 | }
54 |
--------------------------------------------------------------------------------
/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/example/public/favicon.ico
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | pdf-anno-vue
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/example/public/static/output.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/example/public/static/output.pdf
--------------------------------------------------------------------------------
/example/public/static/test.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/example/public/static/test.pdf
--------------------------------------------------------------------------------
/example/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | pdf path: {{pdf}}
4 |
5 |
6 |
7 |
8 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/example/src/README.md:
--------------------------------------------------------------------------------
1 | README.md
--------------------------------------------------------------------------------
/example/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 |
4 | Vue.config.productionTip = false
5 |
6 | new Vue({
7 | render: h => h(App),
8 | }).$mount('#app')
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pdf-annotate-vue",
3 | "version": "1.0.2",
4 | "description": "Annotation layer for pdf.js in vue",
5 | "main": "./src/pdfAnnotate.vue",
6 | "homepage": "https://github.com/AaronLeong/pdf-annotate-vue",
7 | "bugs": {
8 | "url": "https://github.com/AaronLeong/pdf-annotate-vue/issues",
9 | "email": "mc2liang@gmail.com"
10 | },
11 | "repository": "github:AaronLeong/pdf-annotate-vue",
12 | "scripts": {
13 | "test": "echo \"Error: no test specified\" && exit 1"
14 | },
15 | "keywords": [
16 | "pdf",
17 | "annotation",
18 | "pdf.js",
19 | "pdfjs",
20 | "vue"
21 | ],
22 | "author": "Liang Shihua",
23 | "license": "MIT",
24 | "dependencies": {
25 | "create-stylesheet": "^0.3.0",
26 | "pdfjs-dist": "^2.0.943"
27 | },
28 | "devDependencies": {
29 | "@vue/cli-plugin-babel": "^3.8.0",
30 | "@vue/cli-plugin-eslint": "^3.8.0",
31 | "@vue/cli-service": "^3.8.0",
32 | "babel-eslint": "^10.0.1",
33 | "eslint": "^5.16.0",
34 | "eslint-plugin-vue": "^5.0.0",
35 | "vue-template-compiler": "^2.6.10"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/PDFJSAnnotate.js:
--------------------------------------------------------------------------------
1 | import StoreAdapter from './adapter/StoreAdapter';
2 | import LocalStoreAdapter from './adapter/LocalStoreAdapter';
3 | import LocalUserStoreAdapter from './adapter/LocalUserStoreAdapter';
4 | import render from './render';
5 | import UI from './UI';
6 | import config from './config';
7 | import uuid from './utils/uuid';
8 | import {
9 | findAnnotationAtPoint,
10 | findSVGContainer,
11 | convertToScreenPoint
12 | } from './UI/utils';
13 |
14 | export default {
15 | findAnnotationAtPoint,
16 | findSVGContainer,
17 | convertToScreenPoint,
18 |
19 | /**
20 | * Abstract class that needs to be defined so PDFJSAnnotate
21 | * knows how to communicate with your server.
22 | */
23 | StoreAdapter,
24 |
25 | /**
26 | * Implementation of StoreAdapter that stores annotation data to localStorage.
27 | */
28 | LocalStoreAdapter,
29 |
30 | /**
31 | * Implementation of StoreAdapter that stores annotation data to localStorage particular
32 | * to a specific user
33 | */
34 | LocalUserStoreAdapter,
35 |
36 | /**
37 | * Abstract instance of StoreAdapter
38 | */
39 | __storeAdapter: new StoreAdapter(),
40 |
41 | /**
42 | * Getter for the underlying StoreAdapter property
43 | *
44 | * @return {StoreAdapter}
45 | */
46 | getStoreAdapter() {
47 | return this.__storeAdapter;
48 | },
49 |
50 | /**
51 | * Setter for the underlying StoreAdapter property
52 | *
53 | * @param {StoreAdapter} adapter The StoreAdapter implementation to be used.
54 | */
55 | setStoreAdapter(adapter) {
56 | // TODO this throws an error when bundled
57 | // if (!(adapter instanceof StoreAdapter)) {
58 | // throw new Error('adapter must be an instance of StoreAdapter');
59 | // }
60 |
61 | this.__storeAdapter = adapter;
62 | },
63 |
64 | /**
65 | * UI is a helper for instrumenting UI interactions for creating,
66 | * editing, and deleting annotations in the browser.
67 | */
68 | UI,
69 |
70 | /**
71 | * Render the annotations for a page in the PDF Document
72 | *
73 | * @param {SVGElement} svg The SVG element that annotations should be rendered to
74 | * @param {PageViewport} viewport The PDFPage.getViewport data
75 | * @param {Object} data The StoreAdapter.getAnnotations data
76 | * @return {Promise}
77 | */
78 | render,
79 |
80 | /**
81 | * Convenience method for getting annotation data
82 | *
83 | * @alias StoreAdapter.getAnnotations
84 | * @param {String} documentId The ID of the document
85 | * @param {String} pageNumber The page number
86 | * @return {Promise}
87 | */
88 | getAnnotations(documentId, pageNumber) {
89 | return this.getStoreAdapter().getAnnotations(...arguments);
90 | },
91 |
92 | config,
93 |
94 | uuid
95 | };
96 |
--------------------------------------------------------------------------------
/src/UI/arrow.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import { appendChild } from '../render/appendChild';
3 | import {
4 | disableUserSelect,
5 | enableUserSelect,
6 | findSVGAtPoint,
7 | findSVGContainer,
8 | getMetadata,
9 | convertToSvgPoint,
10 | convertToScreenPoint,
11 | findAnnotationAtPoint
12 | } from './utils';
13 |
14 | let _enabled = false;
15 | let _penSize;
16 | let _penColor;
17 | let path;
18 | let lines;
19 | let originY;
20 | let originX;
21 |
22 | /**
23 | * Handle document.mousedown event
24 | */
25 | function handleDocumentMousedown(e) {
26 | let target = findAnnotationAtPoint(e.clientX, e.clientY);
27 | if (target === null) {
28 | return;
29 | }
30 |
31 | let type = target.getAttribute('data-pdf-annotate-type');
32 | if (type !== 'circle' && type !== 'fillcircle' && type !== 'emptycircle') {
33 | return;
34 | }
35 |
36 | let svg = findSVGContainer(target);
37 | let { documentId } = getMetadata(svg);
38 | let annotationId = target.getAttribute('data-pdf-annotate-id');
39 |
40 | PDFJSAnnotate.getStoreAdapter().getAnnotation(documentId, annotationId).then((annotation) => {
41 | if (annotation) {
42 | path = null;
43 | lines = [];
44 |
45 | let point = convertToScreenPoint([
46 | annotation.cx,
47 | annotation.cy
48 | ], svg);
49 |
50 | let rect = svg.getBoundingClientRect();
51 |
52 | originX = point[0] + rect.left;
53 | originY = point[1] + rect.top;
54 |
55 | document.addEventListener('mousemove', handleDocumentMousemove);
56 | document.addEventListener('mouseup', handleDocumentMouseup);
57 | }
58 | });
59 | }
60 |
61 | /**
62 | * Handle document.mouseup event
63 | *
64 | * @param {Event} e The DOM event to be handled
65 | */
66 | function handleDocumentMouseup(e) {
67 | let svg;
68 | if (lines.length > 1 && (svg = findSVGAtPoint(e.clientX, e.clientY))) {
69 | let { documentId, pageNumber } = getMetadata(svg);
70 |
71 | PDFJSAnnotate.getStoreAdapter().addAnnotation(documentId, pageNumber, {
72 | type: 'arrow',
73 | width: _penSize,
74 | color: _penColor,
75 | lines
76 | }).then((annotation) => {
77 | if (path) {
78 | svg.removeChild(path);
79 | }
80 |
81 | appendChild(svg, annotation);
82 | });
83 | }
84 |
85 | document.removeEventListener('mousemove', handleDocumentMousemove);
86 | document.removeEventListener('mouseup', handleDocumentMouseup);
87 | }
88 |
89 | /**
90 | * Handle document.mousemove event
91 | *
92 | * @param {Event} e The DOM event to be handled
93 | */
94 | function handleDocumentMousemove(e) {
95 | let x = lines.length === 0 ? originX : e.clientX;
96 | let y = lines.length === 0 ? originY : e.clientY;
97 |
98 | savePoint(x, y);
99 | }
100 |
101 | /**
102 | * Handle document.keyup event
103 | *
104 | * @param {Event} e The DOM event to be handled
105 | */
106 | function handleDocumentKeyup(e) {
107 | // Cancel rect if Esc is pressed
108 | if (e.keyCode === 27) {
109 | lines = null;
110 | path.parentNode.removeChild(path);
111 | document.removeEventListener('mousemove', handleDocumentMousemove);
112 | document.removeEventListener('mouseup', handleDocumentMouseup);
113 | }
114 | }
115 |
116 | /**
117 | * Save a point to the line being drawn.
118 | *
119 | * @param {Number} x The x coordinate of the point
120 | * @param {Number} y The y coordinate of the point
121 | */
122 | function savePoint(x, y) {
123 | let svg = findSVGAtPoint(x, y);
124 | if (!svg) {
125 | return;
126 | }
127 |
128 | let rect = svg.getBoundingClientRect();
129 | let point = convertToSvgPoint([
130 | x - rect.left,
131 | y - rect.top
132 | ], svg);
133 |
134 | if (lines.length < 2) {
135 | lines.push(point);
136 | return;
137 | }
138 | else {
139 | lines[1] = point; // update end point
140 | }
141 |
142 | if (path) {
143 | svg.removeChild(path);
144 | }
145 |
146 | path = appendChild(svg, {
147 | type: 'arrow',
148 | color: _penColor,
149 | width: _penSize,
150 | lines
151 | });
152 | }
153 |
154 | /**
155 | * Set the attributes of the pen.
156 | *
157 | * @param {Number} penSize The size of the lines drawn by the pen
158 | * @param {String} penColor The color of the lines drawn by the pen
159 | */
160 | export function setArrow(penSize = 10, penColor = '0000FF') {
161 | _penSize = parseInt(penSize, 10);
162 | _penColor = penColor;
163 | }
164 |
165 | /**
166 | * Enable the pen behavior
167 | */
168 | export function enableArrow() {
169 | if (_enabled) { return; }
170 |
171 | _enabled = true;
172 | document.addEventListener('mousedown', handleDocumentMousedown);
173 | document.addEventListener('keyup', handleDocumentKeyup);
174 | disableUserSelect();
175 | }
176 |
177 | /**
178 | * Disable the pen behavior
179 | */
180 | export function disableArrow() {
181 | if (!_enabled) { return; }
182 |
183 | _enabled = false;
184 | document.removeEventListener('mousedown', handleDocumentMousedown);
185 | document.removeEventListener('keyup', handleDocumentKeyup);
186 | enableUserSelect();
187 | }
188 |
189 |
--------------------------------------------------------------------------------
/src/UI/circle.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import { appendChild } from '../render/appendChild';
3 | import {
4 | findSVGAtPoint,
5 | getMetadata,
6 | convertToSvgPoint
7 | } from './utils';
8 |
9 | let _enabled = false;
10 | let _type;
11 | let _circleRadius = 10;
12 | let _circleColor = '0000FF';
13 |
14 | /**
15 | * Set the attributes of the pen.
16 | *
17 | * @param {Number} circleRadius The radius of the circle
18 | * @param {String} circleColor The color of the circle
19 | */
20 | export function setCircle(circleRadius = 10, circleColor = '0000FF') {
21 | _circleRadius = parseInt(circleRadius, 10);
22 | _circleColor = circleColor;
23 | }
24 |
25 | /**
26 | * Handle document.mouseup event
27 | *
28 | * @param {Event} e The DOM event to handle
29 | */
30 | function handleDocumentMouseup(e) {
31 | let svg = findSVGAtPoint(e.clientX, e.clientY);
32 | if (!svg) {
33 | return;
34 | }
35 | let rect = svg.getBoundingClientRect();
36 | saveCircle(svg, _type, {
37 | x: e.clientX - rect.left,
38 | y: e.clientY - rect.top
39 | }, _circleRadius, _circleColor);
40 | }
41 |
42 | /**
43 | * Save a circle annotation
44 | *
45 | * @param {SVGElement} svg
46 | * @param {String} type The type of circle (circle, emptycircle, fillcircle)
47 | * @param {Object} pt The point to use for annotation
48 | * @param {float} radius
49 | * @param {String} color The color of the rects
50 | */
51 | function saveCircle(svg, type, pt, radius, color) {
52 | // Initialize the annotation
53 | let svg_pt = convertToSvgPoint([ pt.x, pt.y ], svg);
54 | let annotation = {
55 | type,
56 | color,
57 | cx: svg_pt[0],
58 | cy: svg_pt[1],
59 | r: radius
60 | };
61 |
62 | let { documentId, pageNumber } = getMetadata(svg);
63 |
64 | // Add the annotation
65 | PDFJSAnnotate.getStoreAdapter().addAnnotation(documentId, pageNumber, annotation)
66 | .then((annotation) => {
67 | appendChild(svg, annotation);
68 | });
69 | }
70 |
71 | /**
72 | * Enable circle behavior
73 | */
74 | export function enableCircle(type) {
75 | _type = type;
76 |
77 | if (_enabled) { return; }
78 |
79 | _enabled = true;
80 | document.addEventListener('mouseup', handleDocumentMouseup);
81 | }
82 |
83 | /**
84 | * Disable circle behavior
85 | */
86 | export function disableCircle() {
87 | if (!_enabled) { return; }
88 |
89 | _enabled = false;
90 | document.removeEventListener('mouseup', handleDocumentMouseup);
91 | }
92 |
93 | export function addCircle(type, e) {
94 | let oldType = _type;
95 | _type = type;
96 | handleDocumentMouseup(e);
97 | _type = oldType;
98 | }
99 |
--------------------------------------------------------------------------------
/src/UI/eraser.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import {
3 | findAnnotationAtPoint,
4 | getMetadata
5 | } from './utils';
6 |
7 | let _canerase = false;
8 | let previousPoint = null;
9 |
10 | /**
11 | *
12 | * @param {PointerEvent} e DOM event to handle
13 | */
14 | function handleDocumentDown(e) {
15 | _canerase = true;
16 | previousPoint = [e.clientX, e.clientY];
17 | }
18 |
19 | /**
20 | *
21 | * @param {PointerEvent} e DOM event to handle
22 | */
23 | function handleDocumentUp(e) {
24 | _canerase = false;
25 | erase(findAnnotationAtPoint(e.clientX, e.clientY));
26 | }
27 |
28 | /**
29 | *
30 | * @param {PointerEvent} e DOM event to handle
31 | */
32 | function handleDocumentMouseMove(e) {
33 | if (!_canerase) {
34 | return;
35 | }
36 |
37 | // This algorithm attempts to get the various points between the last
38 | // PointerEvent and this one
39 | let check = [];
40 | let diffX = Math.abs(previousPoint[0] - e.clientX);
41 | let diffY = Math.abs(previousPoint[1] - e.clientY);
42 | if (diffX >= 1 || diffY >= 1) {
43 | let maxSteps = Math.round(Math.max(diffX, diffY));
44 | let subStepSize = Math.min(diffX, diffY) / maxSteps;
45 | let smallerTest = diffX < diffY;
46 | let startPoint = [
47 | Math.min(previousPoint[0], e.clientX),
48 | Math.min(previousPoint[1], e.clientY)
49 | ];
50 | for (let i = 0; i < maxSteps; i++) {
51 | if (smallerTest) {
52 | check.push([Math.round(startPoint[0] + (subStepSize * i)), Math.round(startPoint[1] + i)]);
53 | }
54 | else {
55 | check.push([Math.round(startPoint[0] + i), Math.round(startPoint[1] + (subStepSize * i))]);
56 | }
57 | }
58 | }
59 | for (let point of check) {
60 | erase(findAnnotationAtPoint(point[0], point[1]));
61 | }
62 | previousPoint = [e.clientX, e.clientY];
63 | }
64 |
65 | function erase(target) {
66 | if (!_canerase) {
67 | return;
68 | }
69 |
70 | if (target) {
71 | let { documentId } = getMetadata(target.parentElement);
72 | let annotationId = target.getAttribute('data-pdf-annotate-id');
73 | PDFJSAnnotate.getStoreAdapter().deleteAnnotation(documentId, annotationId).then(() => {
74 | let nodes = document.querySelectorAll(`[data-pdf-annotate-id="${annotationId}"]`);
75 | [...nodes].forEach((n) => {
76 | n.parentNode.removeChild(n);
77 | });
78 | });
79 | }
80 | }
81 |
82 | export function enableEraser() {
83 | document.addEventListener('pointermove', handleDocumentMouseMove);
84 | document.addEventListener('pointerdown', handleDocumentDown);
85 | document.addEventListener('pointerup', handleDocumentUp);
86 | }
87 |
88 | export function disableEraser() {
89 | document.removeEventListener('pointermove', handleDocumentMouseMove);
90 | document.removeEventListener('pointerdown', handleDocumentDown);
91 | document.removeEventListener('pointerup', handleDocumentUp);
92 | }
93 |
--------------------------------------------------------------------------------
/src/UI/event.js:
--------------------------------------------------------------------------------
1 | import EventEmitter from 'events';
2 | import {
3 | findAnnotationAtPoint,
4 | findSVGAtPoint
5 | } from './utils';
6 |
7 | const emitter = new EventEmitter();
8 |
9 | let clickNode;
10 |
11 | /**
12 | * Handle document.click event
13 | *
14 | * @param {Event} e The DOM event to be handled
15 | */
16 | document.addEventListener('click', function handleDocumentClick(e) {
17 | if (!findSVGAtPoint(e.clientX, e.clientY)) {
18 | return;
19 | }
20 |
21 | let target = findAnnotationAtPoint(e.clientX, e.clientY);
22 |
23 | // Emit annotation:blur if clickNode is no longer clicked
24 | if (clickNode && clickNode !== target) {
25 | emitter.emit('annotation:blur', clickNode);
26 | }
27 |
28 | // Emit annotation:click if target was clicked
29 | if (target) {
30 | emitter.emit('annotation:click', target);
31 | }
32 |
33 | clickNode = target;
34 | });
35 |
36 | // let mouseOverNode;
37 | // document.addEventListener('mousemove', function handleDocumentMousemove(e) {
38 | // let target = findAnnotationAtPoint(e.clientX, e.clientY);
39 | //
40 | // // Emit annotation:mouseout if target was mouseout'd
41 | // if (mouseOverNode && !target) {
42 | // emitter.emit('annotation:mouseout', mouseOverNode);
43 | // }
44 | //
45 | // // Emit annotation:mouseover if target was mouseover'd
46 | // if (target && mouseOverNode !== target) {
47 | // emitter.emit('annotation:mouseover', target);
48 | // }
49 | //
50 | // mouseOverNode = target;
51 | // });
52 |
53 | export function fireEvent() { emitter.emit(...arguments); };
54 | export function addEventListener() { emitter.on(...arguments); };
55 | export function removeEventListener() { emitter.removeListener(...arguments); };
56 |
--------------------------------------------------------------------------------
/src/UI/index.js:
--------------------------------------------------------------------------------
1 | import { addEventListener, removeEventListener, fireEvent } from './event';
2 | import { disableEdit, enableEdit } from './edit';
3 | import { disablePen, enablePen, setPen } from './pen';
4 | import { disableArrow, enableArrow, setArrow } from './arrow';
5 | import { disableEraser, enableEraser } from './eraser';
6 | import { disablePoint, enablePoint } from './point';
7 | import { disableRect, enableRect } from './rect';
8 | import { disableCircle, enableCircle, setCircle, addCircle } from './circle';
9 | import { disableText, enableText, setText } from './text';
10 | import { createPage, renderPage } from './page';
11 |
12 | export default {
13 | addEventListener,
14 | removeEventListener,
15 | fireEvent,
16 |
17 | disableEdit,
18 | enableEdit,
19 |
20 | disablePen,
21 | enablePen,
22 | setPen,
23 |
24 | disablePoint,
25 | enablePoint,
26 |
27 | disableRect,
28 | enableRect,
29 |
30 | disableCircle,
31 | enableCircle,
32 | setCircle,
33 | addCircle,
34 |
35 | disableArrow,
36 | enableArrow,
37 | setArrow,
38 |
39 | disableEraser,
40 | enableEraser,
41 |
42 | disableText,
43 | enableText,
44 | setText,
45 |
46 | createPage,
47 | renderPage
48 | };
49 |
--------------------------------------------------------------------------------
/src/UI/page.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import config from '../config';
3 | import renderScreenReaderHints from '../a11y/renderScreenReaderHints';
4 | import { DefaultTextLayerFactory } from 'pdfjs-dist/web/pdf_viewer.js';
5 |
6 | // Template for creating a new page
7 | const PAGE_TEMPLATE = `
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | `;
16 |
17 | /**
18 | * Create a new page to be appended to the DOM.
19 | *
20 | * @param {Number} pageNumber The page number that is being created
21 | * @return {HTMLElement}
22 | */
23 | export function createPage(pageNumber) {
24 | let temp = document.createElement('div');
25 | temp.innerHTML = PAGE_TEMPLATE;
26 |
27 | let page = temp.children[0];
28 | let canvas = page.querySelector('canvas');
29 |
30 | page.setAttribute('id', `pageContainer${pageNumber}`);
31 | page.setAttribute('data-page-number', pageNumber);
32 |
33 | canvas.mozOpaque = true;
34 | canvas.setAttribute('id', `page${pageNumber}`);
35 |
36 | return page;
37 | }
38 |
39 | /**
40 | * Render a page that has already been created.
41 | *
42 | * @param {Number} pageNumber The page number to be rendered
43 | * @param {Object} renderOptions The options for rendering
44 | * @return {Promise} Settled once rendering has completed
45 | * A settled Promise will be either:
46 | * - fulfilled: [pdfPage, annotations]
47 | * - rejected: Error
48 | */
49 | export function renderPage(pageNumber, renderOptions) {
50 | let {
51 | documentId,
52 | pdfDocument,
53 | scale,
54 | rotate
55 | } = renderOptions;
56 |
57 | // Load the page and annotations
58 | return Promise.all([
59 | pdfDocument.getPage(pageNumber),
60 | PDFJSAnnotate.getAnnotations(documentId, pageNumber)
61 | ]).then(([pdfPage, annotations]) => {
62 | let page = document.getElementById(`pageContainer${pageNumber}`);
63 | let svg = page.querySelector(config.annotationClassQuery());
64 | let canvas = page.querySelector('.canvasWrapper canvas');
65 | let canvasContext = canvas.getContext('2d', {alpha: false});
66 | let totalRotation = (rotate + pdfPage.rotate) % 360;
67 | let viewport = pdfPage.getViewport(scale, totalRotation);
68 | let transform = scalePage(pageNumber, viewport, canvasContext);
69 |
70 | // Render the page
71 | return Promise.all([
72 | pdfPage.render({ canvasContext, viewport, transform }),
73 | PDFJSAnnotate.render(svg, viewport, annotations)
74 | ]).then(() => {
75 | // Text content is needed for a11y, but is also necessary for creating
76 | // highlight and strikeout annotations which require selecting text.
77 | return pdfPage.getTextContent({normalizeWhitespace: true}).then((textContent) => {
78 | return new Promise((resolve, reject) => {
79 | // Render text layer for a11y of text content
80 | let textLayer = page.querySelector(config.textClassQuery());
81 | let textLayerFactory = new DefaultTextLayerFactory();
82 | let textLayerBuilder = textLayerFactory.createTextLayerBuilder(textLayer, pageNumber - 1, viewport);
83 | textLayerBuilder.setTextContent(textContent);
84 | textLayerBuilder.render();
85 |
86 | // Enable a11y for annotations
87 | // Timeout is needed to wait for `textLayerBuilder.render`
88 | setTimeout(() => {
89 | try {
90 | renderScreenReaderHints(annotations.annotations);
91 | resolve();
92 | }
93 | catch (e) {
94 | reject(e);
95 | }
96 | });
97 | });
98 | });
99 | }).then(() => {
100 | // Indicate that the page was loaded
101 | page.setAttribute('data-loaded', 'true');
102 |
103 | return [pdfPage, annotations];
104 | });
105 | });
106 | }
107 |
108 | /**
109 | * Scale the elements of a page.
110 | *
111 | * @param {Number} pageNumber The page number to be scaled
112 | * @param {Object} viewport The viewport of the PDF page (see pdfPage.getViewport(scale, rotate))
113 | * @param {Object} context The canvas context that the PDF page is rendered to
114 | * @return {Array} The transform data for rendering the PDF page
115 | */
116 | function scalePage(pageNumber, viewport, context) {
117 | let page = document.getElementById(`pageContainer${pageNumber}`);
118 | let canvas = page.querySelector('.canvasWrapper canvas');
119 | let svg = page.querySelector(config.annotationClassQuery());
120 | let wrapper = page.querySelector('.canvasWrapper');
121 | let textLayer = page.querySelector(config.textClassQuery());
122 | let outputScale = getOutputScale(context);
123 | let transform = !outputScale.scaled ? null : [outputScale.sx, 0, 0, outputScale.sy, 0, 0];
124 | let sfx = approximateFraction(outputScale.sx);
125 | let sfy = approximateFraction(outputScale.sy);
126 |
127 | // Adjust width/height for scale
128 | page.style.visibility = '';
129 | canvas.width = roundToDivide(viewport.width * outputScale.sx, sfx[0]);
130 | canvas.height = roundToDivide(viewport.height * outputScale.sy, sfy[0]);
131 | canvas.style.width = roundToDivide(viewport.width, sfx[1]) + 'px';
132 | canvas.style.height = roundToDivide(viewport.height, sfx[1]) + 'px';
133 | svg.setAttribute('width', viewport.width);
134 | svg.setAttribute('height', viewport.height);
135 | svg.style.width = `${viewport.width}px`;
136 | svg.style.height = `${viewport.height}px`;
137 | page.style.width = `${viewport.width}px`;
138 | page.style.height = `${viewport.height}px`;
139 | wrapper.style.width = `${viewport.width}px`;
140 | wrapper.style.height = `${viewport.height}px`;
141 | textLayer.style.width = `${viewport.width}px`;
142 | textLayer.style.height = `${viewport.height}px`;
143 |
144 | return transform;
145 | }
146 |
147 | /**
148 | * Approximates a float number as a fraction using Farey sequence (max order of 8).
149 | *
150 | * @param {Number} x Positive float number
151 | * @return {Array} Estimated fraction: the first array item is a numerator,
152 | * the second one is a denominator.
153 | */
154 | function approximateFraction(x) {
155 | // Fast path for int numbers or their inversions.
156 | if (Math.floor(x) === x) {
157 | return [x, 1];
158 | }
159 |
160 | const xinv = 1 / x;
161 | const limit = 8;
162 | if (xinv > limit) {
163 | return [1, limit];
164 | }
165 | else if (Math.floor(xinv) === xinv) {
166 | return [1, xinv];
167 | }
168 |
169 | const x_ = x > 1 ? xinv : x;
170 |
171 | // a/b and c/d are neighbours in Farey sequence.
172 | let a = 0; let b = 1; let c = 1; let d = 1;
173 |
174 | // Limit search to order 8.
175 | while (true) {
176 | // Generating next term in sequence (order of q).
177 | let p = a + c; let q = b + d;
178 | if (q > limit) {
179 | break;
180 | }
181 | if (x_ <= p / q) {
182 | c = p; d = q;
183 | }
184 | else {
185 | a = p; b = q;
186 | }
187 | }
188 |
189 | // Select closest of neighbours to x.
190 | if (x_ - a / b < c / d - x_) {
191 | return x_ === x ? [a, b] : [b, a];
192 | }
193 | else {
194 | return x_ === x ? [c, d] : [d, c];
195 | }
196 | }
197 |
198 | function getOutputScale(ctx) {
199 | let devicePixelRatio = window.devicePixelRatio || 1;
200 | let backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
201 | ctx.mozBackingStorePixelRatio ||
202 | ctx.msBackingStorePixelRatio ||
203 | ctx.oBackingStorePixelRatio ||
204 | ctx.backingStorePixelRatio || 1;
205 | let pixelRatio = devicePixelRatio / backingStoreRatio;
206 | return {
207 | sx: pixelRatio,
208 | sy: pixelRatio,
209 | scaled: pixelRatio !== 1
210 | };
211 | }
212 |
213 | function roundToDivide(x, div) {
214 | let r = x % div;
215 | return r === 0 ? x : Math.round(x - r + div);
216 | }
217 |
--------------------------------------------------------------------------------
/src/UI/pen.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import { appendChild } from '../render/appendChild';
3 | import {
4 | disableUserSelect,
5 | enableUserSelect,
6 | findSVGAtPoint,
7 | getMetadata,
8 | convertToSvgPoint
9 | } from './utils';
10 |
11 | let _enabled = false;
12 | let _candraw = false;
13 | let _penSize;
14 | let _penColor;
15 | let path;
16 | let lines = [];
17 |
18 | /**
19 | * Handle document.touchdown or document.pointerdown event
20 | * @param {PointerEvent} e The DOM event to be handled
21 | */
22 | function handleDocumentPointerdown(e) {
23 | e.preventDefault();
24 | path = null;
25 | lines = [];
26 | _candraw = true;
27 | }
28 |
29 | /**
30 | * Handle document.pointerup event
31 | *
32 | * @param {PointerEvent} e The DOM event to be handled
33 | */
34 | function handleDocumentPointerup(e) {
35 | saveToStorage(e.clientX, e.clientY);
36 | }
37 |
38 | function saveToStorage(x, y) {
39 | _candraw = false;
40 | let svg;
41 | if (lines.length > 1 && (svg = findSVGAtPoint(x, y))) {
42 | let { documentId, pageNumber } = getMetadata(svg);
43 | PDFJSAnnotate.getStoreAdapter().addAnnotation(documentId, pageNumber, {
44 | type: 'drawing',
45 | width: _penSize,
46 | color: _penColor,
47 | lines
48 | }).then((annotation) => {
49 | if (path) {
50 | svg.removeChild(path);
51 | }
52 |
53 | appendChild(svg, annotation);
54 | });
55 | }
56 | }
57 |
58 | /**
59 | * Handle document.mousemove event
60 | *
61 | * @param {PointerEvent} e The DOM event to be handled
62 | */
63 | function handleDocumentPointermove(e) {
64 | if (!e.srcElement.classList.contains('annotationLayer')) {
65 | return;
66 | }
67 | if (_candraw) {
68 | savePoint(e.clientX, e.clientY);
69 | }
70 | }
71 |
72 | /**
73 | * Handle document.keyup event
74 | *
75 | * @param {KeyboardEvent} e The DOM event to be handled
76 | * } e The DOM event to be handled
77 | */
78 | function handleDocumentKeyup(e) {
79 | // Cancel rect if Esc is pressed
80 | if (e.keyCode === 27) {
81 | lines = null;
82 | path.parentNode.removeChild(path);
83 | document.removeEventListener('pointermove', handleDocumentPointermove);
84 | document.removeEventListener('pointerup', handleDocumentPointerup);
85 | }
86 | }
87 |
88 | /**
89 | * Save a point to the line being drawn.
90 | *
91 | * @param {Number} x The x coordinate of the point
92 | * @param {Number} y The y coordinate of the point
93 | */
94 | function savePoint(x, y) {
95 | let svg = findSVGAtPoint(x, y);
96 | if (!svg) {
97 | return;
98 | }
99 |
100 | let rect = svg.getBoundingClientRect();
101 | let point = convertToSvgPoint([
102 | x - rect.left,
103 | y - rect.top
104 | ], svg);
105 | point[0] = point[0].toFixed(2);
106 | point[1] = point[1].toFixed(2);
107 | lines.push(point);
108 |
109 | if (lines.length <= 1) {
110 | return;
111 | }
112 |
113 | if (path) {
114 | svg.removeChild(path);
115 | }
116 |
117 | path = appendChild(svg, {
118 | type: 'drawing',
119 | color: _penColor,
120 | width: _penSize,
121 | lines
122 | });
123 | }
124 |
125 | /**
126 | * Set the attributes of the pen.
127 | *
128 | * @param {Number} penSize The size of the lines drawn by the pen
129 | * @param {String} penColor The color of the lines drawn by the pen
130 | */
131 | export function setPen(penSize = 1, penColor = '000000') {
132 | _penSize = parseInt(penSize, 10);
133 | _penColor = penColor;
134 | }
135 |
136 | /**
137 | * Enable the pen behavior
138 | */
139 | export function enablePen() {
140 | if (_enabled) {
141 | return;
142 | }
143 |
144 | _enabled = true;
145 | // Chrome and Firefox has different behaviors with how pen works, so we need different events.
146 | document.addEventListener('pointerdown', handleDocumentPointerdown);
147 | document.addEventListener('pointermove', handleDocumentPointermove);
148 | document.addEventListener('pointerup', handleDocumentPointerup);
149 |
150 | document.addEventListener('keyup', handleDocumentKeyup);
151 | disableUserSelect();
152 | }
153 |
154 | /**
155 | * Disable the pen behavior
156 | */
157 | export function disablePen() {
158 | if (!_enabled) {
159 | return;
160 | }
161 |
162 | _enabled = false;
163 | document.removeEventListener('pointerdown', handleDocumentPointerdown);
164 | document.removeEventListener('pointermove', handleDocumentPointermove);
165 | document.removeEventListener('pointerup', handleDocumentPointerup);
166 |
167 | document.removeEventListener('keyup', handleDocumentKeyup);
168 | enableUserSelect();
169 | }
170 |
171 |
--------------------------------------------------------------------------------
/src/UI/point.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import { appendChild } from '../render/appendChild';
3 | import {
4 | BORDER_COLOR,
5 | findSVGAtPoint,
6 | getMetadata,
7 | scaleDown
8 | } from './utils';
9 |
10 | let _enabled = false;
11 | let input;
12 |
13 | /**
14 | * Handle document.mouseup event
15 | *
16 | * @param {Event} The DOM event to be handled
17 | */
18 | function handleDocumentMouseup(e) {
19 | if (input || !findSVGAtPoint(e.clientX, e.clientY)) {
20 | return;
21 | }
22 |
23 | input = document.createElement('input');
24 | input.setAttribute('id', 'pdf-annotate-point-input');
25 | input.setAttribute('placeholder', 'Enter comment');
26 | input.style.border = `3px solid ${BORDER_COLOR}`;
27 | input.style.borderRadius = '3px';
28 | input.style.position = 'absolute';
29 | input.style.top = `${e.clientY}px`;
30 | input.style.left = `${e.clientX}px`;
31 |
32 | input.addEventListener('blur', handleInputBlur);
33 | input.addEventListener('keyup', handleInputKeyup);
34 |
35 | document.body.appendChild(input);
36 | input.focus();
37 | }
38 |
39 | /**
40 | * Handle input.blur event
41 | */
42 | function handleInputBlur() {
43 | savePoint();
44 | }
45 |
46 | /**
47 | * Handle input.keyup event
48 | *
49 | * @param {Event} e The DOM event to handle
50 | */
51 | function handleInputKeyup(e) {
52 | if (e.keyCode === 27) {
53 | closeInput();
54 | }
55 | else if (e.keyCode === 13) {
56 | savePoint();
57 | }
58 | }
59 |
60 | /**
61 | * Save a new point annotation from input
62 | */
63 | function savePoint() {
64 | if (input.value.trim().length > 0) {
65 | let clientX = parseInt(input.style.left, 10);
66 | let clientY = parseInt(input.style.top, 10);
67 | let content = input.value.trim();
68 | let svg = findSVGAtPoint(clientX, clientY);
69 | if (!svg) {
70 | return;
71 | }
72 |
73 | let rect = svg.getBoundingClientRect();
74 | let { documentId, pageNumber } = getMetadata(svg);
75 | let annotation = Object.assign({
76 | type: 'point'
77 | }, scaleDown(svg, {
78 | x: clientX - rect.left,
79 | y: clientY - rect.top
80 | }));
81 |
82 | PDFJSAnnotate.getStoreAdapter().addAnnotation(documentId, pageNumber, annotation)
83 | .then((annotation) => {
84 | PDFJSAnnotate.getStoreAdapter().addComment(
85 | documentId,
86 | annotation.uuid,
87 | content
88 | );
89 |
90 | appendChild(svg, annotation);
91 | });
92 | }
93 |
94 | closeInput();
95 | }
96 |
97 | /**
98 | * Close the input element
99 | */
100 | function closeInput() {
101 | input.removeEventListener('blur', handleInputBlur);
102 | input.removeEventListener('keyup', handleInputKeyup);
103 | document.body.removeChild(input);
104 | input = null;
105 | }
106 |
107 | /**
108 | * Enable point annotation behavior
109 | */
110 | export function enablePoint() {
111 | if (_enabled) { return; }
112 |
113 | _enabled = true;
114 | document.addEventListener('mouseup', handleDocumentMouseup);
115 | }
116 |
117 | /**
118 | * Disable point annotation behavior
119 | */
120 | export function disablePoint() {
121 | if (!_enabled) { return; }
122 |
123 | _enabled = false;
124 | document.removeEventListener('mouseup', handleDocumentMouseup);
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/src/UI/rect.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import config from '../config';
3 | import { appendChild } from '../render/appendChild';
4 | import {
5 | BORDER_COLOR,
6 | disableUserSelect,
7 | enableUserSelect,
8 | findSVGAtPoint,
9 | getMetadata,
10 | convertToSvgRect
11 | } from './utils';
12 |
13 | let _enabled = false;
14 | let _type;
15 | let overlay;
16 | let originY;
17 | let originX;
18 |
19 | /**
20 | * Get the current window selection as rects
21 | *
22 | * @return {Array} An Array of rects
23 | */
24 | function getSelectionRects() {
25 | try {
26 | let selection = window.getSelection();
27 | let range = selection.getRangeAt(0);
28 | let rects = range.getClientRects();
29 |
30 | if (rects.length > 0 &&
31 | rects[0].width > 0 &&
32 | rects[0].height > 0) {
33 | return rects;
34 | }
35 | }
36 | catch (e) {}
37 |
38 | return null;
39 | }
40 |
41 | /**
42 | * Handle document.mousedown event
43 | *
44 | * @param {Event} e The DOM event to handle
45 | */
46 | function handleDocumentMousedown(e) {
47 | let svg;
48 | if (_type !== 'area' || !(svg = findSVGAtPoint(e.clientX, e.clientY))) {
49 | return;
50 | }
51 |
52 | let rect = svg.getBoundingClientRect();
53 | originY = e.clientY;
54 | originX = e.clientX;
55 |
56 | overlay = document.createElement('div');
57 | overlay.style.position = 'absolute';
58 | overlay.style.top = `${originY - rect.top}px`;
59 | overlay.style.left = `${originX - rect.left}px`;
60 | overlay.style.border = `3px solid ${BORDER_COLOR}`;
61 | overlay.style.borderRadius = '3px';
62 | svg.parentNode.appendChild(overlay);
63 |
64 | document.addEventListener('mousemove', handleDocumentMousemove);
65 | disableUserSelect();
66 | }
67 |
68 | /**
69 | * Handle document.mousemove event
70 | *
71 | * @param {Event} e The DOM event to handle
72 | */
73 | function handleDocumentMousemove(e) {
74 | let svg = overlay.parentNode.querySelector(config.annotationSvgQuery());
75 | let rect = svg.getBoundingClientRect();
76 |
77 | if (originX + (e.clientX - originX) < rect.right) {
78 | overlay.style.width = `${e.clientX - originX}px`;
79 | }
80 |
81 | if (originY + (e.clientY - originY) < rect.bottom) {
82 | overlay.style.height = `${e.clientY - originY}px`;
83 | }
84 | }
85 |
86 | /**
87 | * Handle document.mouseup event
88 | *
89 | * @param {Event} e The DOM event to handle
90 | */
91 | function handleDocumentMouseup(e) {
92 | let rects;
93 | if (_type !== 'area' && (rects = getSelectionRects())) {
94 | saveRect(_type, [...rects].map((r) => {
95 | return {
96 | top: r.top,
97 | left: r.left,
98 | width: r.width,
99 | height: r.height
100 | };
101 | }));
102 | }
103 | else if (_type === 'area' && overlay) {
104 | let svg = overlay.parentNode.querySelector(config.annotationSvgQuery());
105 | let rect = svg.getBoundingClientRect();
106 | saveRect(_type, [{
107 | top: parseInt(overlay.style.top, 10) + rect.top,
108 | left: parseInt(overlay.style.left, 10) + rect.left,
109 | width: parseInt(overlay.style.width, 10),
110 | height: parseInt(overlay.style.height, 10)
111 | }]);
112 |
113 | overlay.parentNode.removeChild(overlay);
114 | overlay = null;
115 |
116 | document.removeEventListener('mousemove', handleDocumentMousemove);
117 | enableUserSelect();
118 | }
119 | }
120 |
121 | /**
122 | * Handle document.keyup event
123 | *
124 | * @param {Event} e The DOM event to handle
125 | */
126 | function handleDocumentKeyup(e) {
127 | // Cancel rect if Esc is pressed
128 | if (e.keyCode === 27) {
129 | let selection = window.getSelection();
130 | selection.removeAllRanges();
131 | if (overlay && overlay.parentNode) {
132 | overlay.parentNode.removeChild(overlay);
133 | overlay = null;
134 | document.removeEventListener('mousemove', handleDocumentMousemove);
135 | }
136 | }
137 | }
138 |
139 | /**
140 | * Save a rect annotation
141 | *
142 | * @param {String} type The type of rect (area, highlight, strikeout)
143 | * @param {Array} rects The rects to use for annotation
144 | * @param {String} color The color of the rects
145 | */
146 | function saveRect(type, rects, color) {
147 | let svg = findSVGAtPoint(rects[0].left, rects[0].top);
148 | let annotation;
149 |
150 | if (!svg) {
151 | return;
152 | }
153 |
154 | let boundingRect = svg.getBoundingClientRect();
155 |
156 | console.log('saveRect', type)
157 | if (!color) {
158 | if (type === 'highlight') {
159 | color = 'FFFF00';
160 | }
161 | else if (type === 'strikeout') {
162 | color = 'FF0000';
163 | }
164 | }
165 |
166 | // Initialize the annotation
167 | annotation = {
168 | type,
169 | color,
170 | rectangles: [...rects].map((r) => {
171 | let offset = 0;
172 |
173 | if (type === 'strikeout') {
174 | offset = r.height / 2;
175 | }
176 |
177 | return convertToSvgRect({
178 | y: (r.top + offset) - boundingRect.top,
179 | x: r.left - boundingRect.left,
180 | width: r.width,
181 | height: r.height
182 | }, svg);
183 | }).filter((r) => r.width > 0 && r.height > 0 && r.x > -1 && r.y > -1)
184 | };
185 |
186 | // Short circuit if no rectangles exist
187 | if (annotation.rectangles.length === 0) {
188 | return;
189 | }
190 |
191 | // Special treatment for area as it only supports a single rect
192 | if (type === 'area') {
193 | let rect = annotation.rectangles[0];
194 | delete annotation.rectangles;
195 | annotation.x = rect.x;
196 | annotation.y = rect.y;
197 | annotation.width = rect.width;
198 | annotation.height = rect.height;
199 | }
200 |
201 | let { documentId, pageNumber } = getMetadata(svg);
202 |
203 | // Add the annotation
204 | console.log('annotation',annotation)
205 | PDFJSAnnotate.getStoreAdapter().addAnnotation(documentId, pageNumber, annotation)
206 | .then((annotation) => {
207 | appendChild(svg, annotation);
208 |
209 | });
210 |
211 | PDFJSAnnotate.getStoreAdapter().getAnnotations('#viewer',1).then(function(data){
212 | console.log(data)
213 | })
214 |
215 | }
216 |
217 | /**
218 | * Enable rect behavior
219 | */
220 | export function enableRect(type) {
221 | _type = type;
222 |
223 | if (_enabled) { return; }
224 |
225 | _enabled = true;
226 | document.addEventListener('mouseup', handleDocumentMouseup);
227 | document.addEventListener('mousedown', handleDocumentMousedown);
228 | document.addEventListener('keyup', handleDocumentKeyup);
229 | }
230 |
231 | /**
232 | * Disable rect behavior
233 | */
234 | export function disableRect() {
235 | if (!_enabled) { return; }
236 |
237 | _enabled = false;
238 | document.removeEventListener('mouseup', handleDocumentMouseup);
239 | document.removeEventListener('mousedown', handleDocumentMousedown);
240 | document.removeEventListener('keyup', handleDocumentKeyup);
241 | }
242 |
243 |
--------------------------------------------------------------------------------
/src/UI/text.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import { appendChild } from '../render/appendChild';
3 | import {
4 | BORDER_COLOR,
5 | findSVGAtPoint,
6 | getMetadata,
7 | convertToSvgPoint
8 | } from './utils';
9 |
10 | let _enabled = false;
11 | let input;
12 | let _textSize;
13 | let _textColor;
14 |
15 | /**
16 | * Handle document.mouseup event
17 | *
18 | * @param {Event} e The DOM event to handle
19 | */
20 | function handleDocumentMouseup(e) {
21 | if (input || !findSVGAtPoint(e.clientX, e.clientY)) {
22 | return;
23 | }
24 | if (!e.srcElement.classList.contains('annotationLayer')) {
25 | return;
26 | }
27 | input = document.createElement('input');
28 | input.setAttribute('id', 'pdf-annotate-text-input');
29 | input.setAttribute('placeholder', 'Enter text');
30 | input.style.border = `3px solid ${BORDER_COLOR}`;
31 | input.style.borderRadius = '3px';
32 | input.style.position = 'absolute';
33 | input.style.top = `${e.clientY}px`;
34 | input.style.left = `${e.clientX}px`;
35 | input.style.fontSize = `${_textSize}px`;
36 | input.style.zIndex = '41';
37 | input.addEventListener('blur', handleInputBlur);
38 | input.addEventListener('keyup', handleInputKeyup);
39 |
40 | document.body.appendChild(input);
41 | input.focus();
42 | }
43 |
44 | /**
45 | * Handle input.blur event
46 | */
47 | function handleInputBlur() {
48 | saveText();
49 | }
50 |
51 | /**
52 | * Handle input.keyup event
53 | *
54 | * @param {Event} e The DOM event to handle
55 | */
56 | function handleInputKeyup(e) {
57 | if (e.keyCode === 27) {
58 | closeInput();
59 | }
60 | else if (e.keyCode === 13) {
61 | saveText();
62 | }
63 | }
64 |
65 | /**
66 | * Save a text annotation from input
67 | */
68 | function saveText() {
69 | let value = (input.value) ? input.value.replace(/ +$/, '') : '';
70 | if (value.length > 0) {
71 | let clientX = parseInt(input.style.left, 10);
72 | let clientY = parseInt(input.style.top, 10);
73 | let svg = findSVGAtPoint(clientX, clientY);
74 | if (!svg) {
75 | return;
76 | }
77 | let height = _textSize;
78 | let { documentId, pageNumber, viewport } = getMetadata(svg);
79 | let scale = 1 / viewport.scale;
80 | let rect = svg.getBoundingClientRect();
81 | let pt = convertToSvgPoint([
82 | clientX - rect.left,
83 | clientY - rect.top + height], svg, viewport);
84 | let annotation = {
85 | type: 'textbox',
86 | size: _textSize * scale,
87 | color: _textColor,
88 | content: value,
89 | x: pt[0],
90 | y: pt[1],
91 | rotation: -viewport.rotation
92 | };
93 |
94 | PDFJSAnnotate.getStoreAdapter().addAnnotation(documentId, pageNumber, annotation)
95 | .then((annotation) => {
96 | appendChild(svg, annotation);
97 | });
98 | }
99 |
100 | closeInput();
101 | }
102 |
103 | /**
104 | * Close the input
105 | */
106 | function closeInput() {
107 | if (input) {
108 | input.removeEventListener('blur', handleInputBlur);
109 | input.removeEventListener('keyup', handleInputKeyup);
110 | document.body.removeChild(input);
111 | input = null;
112 | }
113 | }
114 |
115 | /**
116 | * Set the text attributes
117 | *
118 | * @param {Number} textSize The size of the text
119 | * @param {String} textColor The color of the text
120 | */
121 | export function setText(textSize = 12, textColor = '000000') {
122 | _textSize = parseInt(textSize, 10);
123 | _textColor = textColor;
124 | }
125 |
126 | /**
127 | * Enable text behavior
128 | */
129 | export function enableText() {
130 | if (_enabled) {
131 | return;
132 | }
133 |
134 | _enabled = true;
135 | document.addEventListener('mouseup', handleDocumentMouseup);
136 | }
137 |
138 | /**
139 | * Disable text behavior
140 | */
141 | export function disableText() {
142 | if (!_enabled) { return; }
143 |
144 | _enabled = false;
145 | document.removeEventListener('mouseup', handleDocumentMouseup);
146 | }
147 |
148 |
--------------------------------------------------------------------------------
/src/UI/utils.js:
--------------------------------------------------------------------------------
1 | import createStyleSheet from 'create-stylesheet';
2 | import { getTranslation } from '../render/appendChild';
3 | import {
4 | applyTransform,
5 | applyInverseTransform,
6 | translate,
7 | rotate,
8 | scale
9 | } from '../utils/mathUtils';
10 |
11 | export const BORDER_COLOR = '#00BFFF';
12 |
13 | const userSelectStyleSheet = createStyleSheet({
14 | body: {
15 | '-webkit-user-select': 'none',
16 | '-moz-user-select': 'none',
17 | '-ms-user-select': 'none',
18 | 'user-select': 'none'
19 | }
20 | });
21 | userSelectStyleSheet.setAttribute('data-pdf-annotate-user-select', 'true');
22 |
23 | /**
24 | * Find the SVGElement that contains all the annotations for a page
25 | *
26 | * @param {Element} node An annotation within that container
27 | * @return {SVGElement} The container SVG or null if it can't be found
28 | */
29 | export function findSVGContainer(node) {
30 | let parentNode = node;
31 |
32 | while ((parentNode = parentNode.parentNode) &&
33 | parentNode !== document) {
34 | if (parentNode.nodeName.toUpperCase() === 'SVG' &&
35 | parentNode.getAttribute('data-pdf-annotate-container') === 'true') {
36 | return parentNode;
37 | }
38 | }
39 |
40 | return null;
41 | }
42 |
43 | /**
44 | * Find an SVGElement container at a given point
45 | *
46 | * @param {Number} x The x coordinate of the point
47 | * @param {Number} y The y coordinate of the point
48 | * @return {SVGElement} The container SVG or null if one can't be found
49 | */
50 | export function findSVGAtPoint(x, y) {
51 | let elements = document.querySelectorAll('svg[data-pdf-annotate-container="true"]');
52 |
53 | for (let i = 0, l = elements.length; i < l; i++) {
54 | let el = elements[i];
55 | let rect = el.getBoundingClientRect();
56 |
57 | if (pointIntersectsRect(x, y, rect)) {
58 | return el;
59 | }
60 | }
61 |
62 | return null;
63 | }
64 |
65 | /**
66 | * Find an Element that represents an annotation at a given point.
67 | *
68 | * IMPORTANT: Requires the annotation layer to be the top most element so
69 | * either use z-ordering or make it the leaf container.
70 | *
71 | * @param {Number} x The x coordinate of the point
72 | * @param {Number} y The y coordinate of the point
73 | * @return {Element} The annotation element or null if one can't be found
74 | */
75 | export function findAnnotationAtPoint(x, y) {
76 | let el = null;
77 | let candidate = document.elementFromPoint(x, y);
78 | while (!el && candidate && candidate !== document) {
79 | let type = candidate.getAttribute('data-pdf-annotate-type');
80 | if (type) {
81 | el = candidate;
82 | }
83 | candidate = candidate.parentNode;
84 | }
85 | return el;
86 | }
87 |
88 | /**
89 | * Determine if a point intersects a rect
90 | *
91 | * @param {Number} x The x coordinate of the point
92 | * @param {Number} y The y coordinate of the point
93 | * @param {Object} rect The points of a rect (likely from getBoundingClientRect)
94 | * @return {Boolean} True if a collision occurs, otherwise false
95 | */
96 | export function pointIntersectsRect(x, y, rect) {
97 | return y >= rect.top && y <= rect.bottom && x >= rect.left && x <= rect.right;
98 | }
99 |
100 | /**
101 | * Get the rect of an annotation element accounting for offset.
102 | *
103 | * @param {Element} el The element to get the rect of
104 | * @return {Object} The dimensions of the element
105 | */
106 | export function getOffsetAnnotationRect(el) {
107 | let rect = el.getBoundingClientRect();
108 | let { width, height } = rect;
109 | let extraOffsetWidth = 0;
110 | let extraOffsetHeight = 0;
111 | if (['line', 'path'].indexOf(el.tagName.toLowerCase()) > -1 && el.getBBox) {
112 | let bbox = el.getBBox();
113 | extraOffsetWidth = (rect.width - bbox.width) / 2;
114 | extraOffsetHeight = (rect.height - bbox.height) / 2;
115 | width = bbox.width;
116 | height = bbox.height;
117 | }
118 | let { offsetLeft, offsetTop } = getOffset(el);
119 | return {
120 | top: rect.top - offsetTop + extraOffsetHeight,
121 | left: rect.left - offsetLeft + extraOffsetWidth,
122 | bottom: rect.bottom - offsetTop - extraOffsetHeight,
123 | right: rect.right - offsetLeft - extraOffsetWidth,
124 | width: width,
125 | height: height
126 | };
127 | }
128 |
129 | /**
130 | * Adjust scale from normalized scale (100%) to rendered scale.
131 | *
132 | * @param {SVGElement} svg The SVG to gather metadata from
133 | * @param {Object} rect A map of numeric values to scale
134 | * @return {Object} A copy of `rect` with values scaled up
135 | */
136 | export function scaleUp(svg, rect) {
137 | let result = {};
138 | let { viewport } = getMetadata(svg);
139 |
140 | Object.keys(rect).forEach((key) => {
141 | result[key] = rect[key] * viewport.scale;
142 | });
143 |
144 | return result;
145 | }
146 |
147 | export function convertToSvgRect(rect, svg, viewport) {
148 | let pt1 = [rect.x, rect.y];
149 | let pt2 = [rect.x + rect.width, rect.y + rect.height];
150 |
151 | pt1 = convertToSvgPoint(pt1, svg, viewport);
152 | pt2 = convertToSvgPoint(pt2, svg, viewport);
153 |
154 | return {
155 | x: Math.min(pt1[0], pt2[0]),
156 | y: Math.min(pt1[1], pt2[1]),
157 | width: Math.abs(pt2[0] - pt1[0]),
158 | height: Math.abs(pt2[1] - pt1[1])
159 | };
160 | }
161 |
162 | export function convertToSvgPoint(pt, svg, viewport) {
163 | viewport = viewport || getMetadata(svg).viewport;
164 |
165 | let xform = [ 1, 0, 0, 1, 0, 0 ];
166 | xform = scale(xform, viewport.scale, viewport.scale);
167 | xform = rotate(xform, viewport.rotation);
168 |
169 | let offset = getTranslation(viewport);
170 | xform = translate(xform, offset.x, offset.y);
171 |
172 | return applyInverseTransform(pt, xform);
173 | }
174 |
175 | export function convertToScreenPoint(pt, svg, viewport) {
176 | viewport = viewport || getMetadata(svg).viewport;
177 |
178 | let xform = [ 1, 0, 0, 1, 0, 0 ];
179 | xform = scale(xform, viewport.scale, viewport.scale);
180 | xform = rotate(xform, viewport.rotation);
181 |
182 | let offset = getTranslation(viewport);
183 | xform = translate(xform, offset.x, offset.y);
184 |
185 | return applyTransform(pt, xform);
186 | }
187 |
188 | /**
189 | * Adjust scale from rendered scale to a normalized scale (100%).
190 | *
191 | * @param {SVGElement} svg The SVG to gather metadata from
192 | * @param {Object} rect A map of numeric values to scale
193 | * @return {Object} A copy of `rect` with values scaled down
194 | */
195 | export function scaleDown(svg, rect) {
196 | let result = {};
197 | let { viewport } = getMetadata(svg);
198 |
199 | Object.keys(rect).forEach((key) => {
200 | result[key] = rect[key] / viewport.scale;
201 | });
202 |
203 | return result;
204 | }
205 |
206 | /**
207 | * Get the scroll position of an element, accounting for parent elements
208 | *
209 | * @param {Element} el The element to get the scroll position for
210 | * @return {Object} The scrollTop and scrollLeft position
211 | */
212 | export function getScroll(el) {
213 | let scrollTop = 0;
214 | let scrollLeft = 0;
215 | let parentNode = el;
216 |
217 | while ((parentNode = parentNode.parentNode) &&
218 | parentNode !== document) {
219 | scrollTop += parentNode.scrollTop;
220 | scrollLeft += parentNode.scrollLeft;
221 | }
222 |
223 | return { scrollTop, scrollLeft };
224 | }
225 |
226 | /**
227 | * Get the offset position of an element, accounting for parent elements
228 | *
229 | * @param {Element} el The element to get the offset position for
230 | * @return {Object} The offsetTop and offsetLeft position
231 | */
232 | export function getOffset(el) {
233 | let parentNode = el;
234 |
235 | while ((parentNode = parentNode.parentNode) &&
236 | parentNode !== document) {
237 | if (parentNode.nodeName.toUpperCase() === 'SVG') {
238 | break;
239 | }
240 | }
241 |
242 | let rect = parentNode.getBoundingClientRect();
243 |
244 | return { offsetLeft: rect.left, offsetTop: rect.top };
245 | }
246 |
247 | /**
248 | * Disable user ability to select text on page
249 | */
250 | export function disableUserSelect() {
251 | if (!userSelectStyleSheet.parentNode) {
252 | document.head.appendChild(userSelectStyleSheet);
253 | }
254 | }
255 |
256 | /**
257 | * Enable user ability to select text on page
258 | */
259 | export function enableUserSelect() {
260 | if (userSelectStyleSheet.parentNode) {
261 | userSelectStyleSheet.parentNode.removeChild(userSelectStyleSheet);
262 | }
263 | }
264 |
265 | /**
266 | * Get the metadata for a SVG container
267 | *
268 | * @param {SVGElement} svg The SVG container to get metadata for
269 | */
270 | export function getMetadata(svg) {
271 | return {
272 | documentId: svg.getAttribute('data-pdf-annotate-document'),
273 | pageNumber: parseInt(svg.getAttribute('data-pdf-annotate-page'), 10),
274 | viewport: JSON.parse(svg.getAttribute('data-pdf-annotate-viewport'))
275 | };
276 | }
277 |
--------------------------------------------------------------------------------
/src/a11y/createScreenReaderOnly.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Create a node that is only visible to screen readers
3 | *
4 | * @param {String} content The text content that should be read by screen reader
5 | * @param {String} [annotationId] The ID of the annotation assocaited
6 | * @return {Element} An Element that is only visible to screen readers
7 | */
8 | export default function createScreenReaderOnly(content, annotationId) {
9 | let node = document.createElement('div');
10 | let text = document.createTextNode(content);
11 | node.appendChild(text);
12 | node.setAttribute('id', `pdf-annotate-screenreader-${annotationId}`);
13 | node.style.position = 'absolute';
14 | node.style.left = '-10000px';
15 | node.style.top = 'auto';
16 | node.style.width = '1px';
17 | node.style.height = '1px';
18 | node.style.overflow = 'hidden';
19 | return node;
20 | }
21 |
--------------------------------------------------------------------------------
/src/a11y/initEventHandlers.js:
--------------------------------------------------------------------------------
1 | import renderScreenReaderHints from './renderScreenReaderHints';
2 | import insertScreenReaderComment from './insertScreenReaderComment';
3 | import renderScreenReaderComments from './renderScreenReaderComments';
4 | import { addEventListener } from '../UI/event';
5 | import PDFJSAnnotate from '../PDFJSAnnotate';
6 |
7 | /**
8 | * Initialize the event handlers for keeping screen reader hints synced with data
9 | */
10 | export default function initEventHandlers() {
11 | addEventListener('annotation:add', (documentId, pageNumber, annotation) => {
12 | reorderAnnotationsByType(documentId, pageNumber, annotation.type);
13 | });
14 | addEventListener('annotation:edit', (documentId, annotationId, annotation) => {
15 | reorderAnnotationsByType(documentId, annotation.page, annotation.type);
16 | });
17 | addEventListener('annotation:delete', removeAnnotation);
18 | addEventListener('comment:add', insertComment);
19 | addEventListener('comment:delete', removeComment);
20 | }
21 |
22 | /**
23 | * Reorder the annotation numbers by annotation type
24 | *
25 | * @param {String} documentId The ID of the document
26 | * @param {Number} pageNumber The page number of the annotations
27 | * @param {Strig} type The annotation type
28 | */
29 | function reorderAnnotationsByType(documentId, pageNumber, type) {
30 | PDFJSAnnotate.getStoreAdapter().getAnnotations(documentId, pageNumber)
31 | .then((annotations) => {
32 | return annotations.annotations.filter((a) => {
33 | return a.type === type;
34 | });
35 | })
36 | .then((annotations) => {
37 | annotations.forEach((a) => {
38 | removeAnnotation(documentId, a.uuid);
39 | });
40 |
41 | return annotations;
42 | })
43 | .then(renderScreenReaderHints);
44 | }
45 |
46 | /**
47 | * Remove the screen reader hint for an annotation
48 | *
49 | * @param {String} documentId The ID of the document
50 | * @param {String} annotationId The Id of the annotation
51 | */
52 | function removeAnnotation(documentId, annotationId) {
53 | removeElementById(`pdf-annotate-screenreader-${annotationId}`);
54 | removeElementById(`pdf-annotate-screenreader-${annotationId}-end`);
55 | }
56 |
57 | /**
58 | * Insert a screen reader hint for a comment
59 | *
60 | * @param {String} documentId The ID of the document
61 | * @param {String} annotationId The ID of tha assocated annotation
62 | * @param {Object} comment The comment to insert a hint for
63 | */
64 | function insertComment(documentId, annotationId, comment) {
65 | let list = document.querySelector(`pdf-annotate-screenreader-comment-list-${annotationId}`);
66 | let promise;
67 |
68 | if (!list) {
69 | promise = renderScreenReaderComments(documentId, annotationId, []).then(() => {
70 | list = document.querySelector(`pdf-annotate-screenreader-comment-list-${annotationId}`);
71 | return true;
72 | });
73 | }
74 | else {
75 | promise = Promise.resolve(true);
76 | }
77 |
78 | promise.then(() => {
79 | insertScreenReaderComment(comment);
80 | });
81 | }
82 |
83 | /**
84 | * Remove a screen reader hint for a comment
85 | *
86 | * @param {String} documentId The ID of the document
87 | * @param {String} commentId The ID of the comment
88 | */
89 | function removeComment(documentId, commentId) {
90 | removeElementById(`pdf-annotate-screenreader-comment-${commentId}`);
91 | }
92 |
93 | /**
94 | * Remove an element from the DOM by it's ID if it exists
95 | *
96 | * @param {String} elementId The ID of the element to be removed
97 | */
98 | function removeElementById(elementId) {
99 | let el = document.getElementById(elementId);
100 | if (el) {
101 | el.parentNode.removeChild(el);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/a11y/insertElementWithinChildren.js:
--------------------------------------------------------------------------------
1 | import config from '../config';
2 | import insertElementWithinElement from './insertElementWithinElement';
3 | import { pointIntersectsRect, scaleUp } from '../UI/utils';
4 |
5 | /**
6 | * Insert an element at a point within the document.
7 | * This algorithm will try to insert between elements if possible.
8 | * It will however use `insertElementWithinElement` if it is more accurate.
9 | *
10 | * @param {Element} el The element to be inserted
11 | * @param {Number} x The x coordinate of the point
12 | * @param {Number} y The y coordinate of the point
13 | * @param {Number} pageNumber The page number to limit elements to
14 | * @return {Boolean} True if element was able to be inserted, otherwise false
15 | */
16 | export default function insertElementWithinChildren(el, x, y, pageNumber) {
17 | // Try and use most accurate method of inserting within an element
18 | if (insertElementWithinElement(el, x, y, pageNumber, true)) {
19 | return true;
20 | }
21 |
22 | // Fall back to inserting between elements
23 | let svg = document.querySelector(`svg[data-pdf-annotate-page="${pageNumber}"]`);
24 | let rect = svg.getBoundingClientRect();
25 | let nodes = [...svg.parentNode.querySelectorAll(config.textClassQuery() + ' > div')];
26 |
27 | y = scaleUp(svg, {y}).y + rect.top;
28 | x = scaleUp(svg, {x}).x + rect.left;
29 |
30 | // Find the best node to insert before
31 | for (let i = 0, l = nodes.length; i < l; i++) {
32 | let n = nodes[i];
33 | let r = n.getBoundingClientRect();
34 | if (y <= r.top) {
35 | n.parentNode.insertBefore(el, n);
36 | return true;
37 | }
38 | }
39 |
40 | // If all else fails try to append to the bottom
41 | let textLayer = svg.parentNode.querySelector(config.textClassQuery());
42 | if (textLayer) {
43 | let textRect = textLayer.getBoundingClientRect();
44 | if (pointIntersectsRect(x, y, textRect)) {
45 | textLayer.appendChild(el);
46 | return true;
47 | }
48 | }
49 |
50 | return false;
51 | }
52 |
--------------------------------------------------------------------------------
/src/a11y/insertElementWithinElement.js:
--------------------------------------------------------------------------------
1 | import config from '../config';
2 | import {
3 | pointIntersectsRect,
4 | scaleUp,
5 | scaleDown
6 | } from '../UI/utils';
7 |
8 | /**
9 | * Insert an element at a point within the document.
10 | * This algorithm will only insert within an element amidst it's text content.
11 | *
12 | * @param {Element} el The element to be inserted
13 | * @param {Number} x The x coordinate of the point
14 | * @param {Number} y The y coordinate of the point
15 | * @param {Number} pageNumber The page number to limit elements to
16 | * @param {Boolean} insertBefore Whether the element is to be inserted before or after x
17 | * @return {Boolean} True if element was able to be inserted, otherwise false
18 | */
19 | export default function insertElementWithinElement(el, x, y, pageNumber, insertBefore) {
20 | const OFFSET_ADJUST = 2;
21 |
22 | // If inserting before adjust `x` by looking for element a few px to the right
23 | // Otherwise adjust a few px to the left
24 | // This is to allow a little tolerance by searching within the box, instead
25 | // of getting a false negative by testing right on the border.
26 | x = Math.max(x + (OFFSET_ADJUST * (insertBefore ? 1 : -1)), 0);
27 |
28 | let node = textLayerElementFromPoint(x, y + OFFSET_ADJUST, pageNumber);
29 | if (!node) {
30 | return false;
31 | }
32 |
33 | // Now that node has been found inverse the adjustment for `x`.
34 | // This is done to accomodate tolerance by cutting off on the outside of the
35 | // text boundary, instead of missing a character by cutting off within.
36 | x = x + (OFFSET_ADJUST * (insertBefore ? -1 : 1));
37 |
38 | let svg = document.querySelector(`svg[data-pdf-annotate-page="${pageNumber}"]`);
39 | let left = scaleDown(svg, {left: node.getBoundingClientRect().left}).left - svg.getBoundingClientRect().left;
40 | let temp = node.cloneNode(true);
41 | let head = temp.innerHTML.split('');
42 | let tail = [];
43 |
44 | // Insert temp off screen
45 | temp.style.position = 'absolute';
46 | temp.style.top = '-10000px';
47 | temp.style.left = '-10000px';
48 | document.body.appendChild(temp);
49 |
50 | while (head.length) {
51 | // Don't insert within HTML tags
52 | if (head[head.length - 1] === '>') {
53 | while (head.length) {
54 | tail.unshift(head.pop());
55 | if (tail[0] === '<') {
56 | break;
57 | }
58 | }
59 | }
60 |
61 | // Check if width of temp based on current head value satisfies x
62 | temp.innerHTML = head.join('');
63 | let width = scaleDown(svg, {width: temp.getBoundingClientRect().width}).width;
64 | if (left + width <= x) {
65 | break;
66 | }
67 | tail.unshift(head.pop());
68 | }
69 |
70 | // Update original node with new markup, including element to be inserted
71 | node.innerHTML = head.join('') + el.outerHTML + tail.join('');
72 | temp.parentNode.removeChild(temp);
73 |
74 | return true;
75 | }
76 |
77 | /**
78 | * Get a text layer element at a given point on a page
79 | *
80 | * @param {Number} x The x coordinate of the point
81 | * @param {Number} y The y coordinate of the point
82 | * @param {Number} pageNumber The page to limit elements to
83 | * @return {Element} First text layer element found at the point
84 | */
85 | function textLayerElementFromPoint(x, y, pageNumber) {
86 | let svg = document.querySelector(`svg[data-pdf-annotate-page="${pageNumber}"]`);
87 | let rect = svg.getBoundingClientRect();
88 | y = scaleUp(svg, {y}).y + rect.top;
89 | x = scaleUp(svg, {x}).x + rect.left;
90 | return [...svg.parentNode.querySelectorAll(config.textClassQuery() + ' [data-canvas-width]')].filter((el) => {
91 | return pointIntersectsRect(x, y, el.getBoundingClientRect());
92 | })[0];
93 | }
94 |
--------------------------------------------------------------------------------
/src/a11y/insertScreenReaderComment.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Insert a comment into the DOM to be available by screen reader
3 | *
4 | * @param {Object} comment The comment to be inserted
5 | */
6 | export default function insertScreenReaderComment(comment) {
7 | if (!comment) {
8 | return;
9 | }
10 |
11 | let list = document.querySelector(`#pdf-annotate-screenreader-${comment.annotation} ol`);
12 | if (list) {
13 | let item = document.createElement('li');
14 | item.setAttribute('id', `pdf-annotate-screenreader-comment-${comment.uuid}`);
15 | item.appendChild(document.createTextNode(`${comment.content}`));
16 | list.appendChild(item);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/a11y/insertScreenReaderHint.js:
--------------------------------------------------------------------------------
1 | import createScreenReaderOnly from './createScreenReaderOnly';
2 | import insertElementWithinChildren from './insertElementWithinChildren';
3 | import insertElementWithinElement from './insertElementWithinElement';
4 | import renderScreenReaderComments from './renderScreenReaderComments';
5 |
6 | // Annotation types that support comments
7 | const COMMENT_TYPES = ['highlight', 'point', 'area', 'circle', 'emptycircle', 'fillcircle'];
8 |
9 | /**
10 | * Insert a hint into the DOM for screen readers for a specific annotation.
11 | *
12 | * @param {Object} annotation The annotation to insert a hint for
13 | * @param {Number} num The number of the annotation out of all annotations of the same type
14 | */
15 | export default function insertScreenReaderHint(annotation, num = 0) {
16 | switch (annotation.type) {
17 | case 'highlight':
18 | case 'strikeout':
19 | let rects = annotation.rectangles;
20 | let first = rects[0];
21 | let last = rects[rects.length - 1];
22 |
23 | insertElementWithinElement(
24 | createScreenReaderOnly(`Begin ${annotation.type} annotation ${num}`, annotation.uuid),
25 | first.x, first.y, annotation.page, true
26 | );
27 |
28 | insertElementWithinElement(
29 | createScreenReaderOnly(`End ${annotation.type} annotation ${num}`, `${annotation.uuid}-end`),
30 | last.x + last.width, last.y, annotation.page, false
31 | );
32 | break;
33 |
34 | case 'textbox':
35 | case 'point':
36 | let text = annotation.type === 'textbox' ? ` (content: ${annotation.content})` : '';
37 |
38 | insertElementWithinChildren(
39 | createScreenReaderOnly(`${annotation.type} annotation ${num}${text}`, annotation.uuid),
40 | annotation.x, annotation.y, annotation.page
41 | );
42 | break;
43 |
44 | case 'drawing':
45 | case 'area':
46 | let x = typeof annotation.x !== 'undefined' ? annotation.x : annotation.lines[0][0];
47 | let y = typeof annotation.y !== 'undefined' ? annotation.y : annotation.lines[0][1];
48 |
49 | insertElementWithinChildren(
50 | createScreenReaderOnly(`Unlabeled drawing`, annotation.uuid),
51 | x, y, annotation.page
52 | );
53 | break;
54 |
55 | case 'circle':
56 | case 'fillcircle':
57 | case 'emptycircle':
58 | let x2 = typeof annotation.cx !== 'undefined' ? annotation.cx : annotation.lines[0][0];
59 | let y2 = typeof annotation.cy !== 'undefined' ? annotation.cy : annotation.lines[0][1];
60 |
61 | insertElementWithinChildren(
62 | createScreenReaderOnly(`Unlabeled drawing`, annotation.uuid),
63 | x2, y2, annotation.page
64 | );
65 | break;
66 | }
67 |
68 | // Include comments in screen reader hint
69 | if (COMMENT_TYPES.includes(annotation.type)) {
70 | renderScreenReaderComments(annotation.documentId, annotation.uuid);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/a11y/renderScreenReaderComments.js:
--------------------------------------------------------------------------------
1 | import PDFJSAnnotate from '../PDFJSAnnotate';
2 | import insertScreenReaderComment from './insertScreenReaderComment';
3 |
4 | /**
5 | * Insert the comments into the DOM to be available by screen reader
6 | *
7 | * Example output:
8 | *
9 | *
Begin highlight 1
10 | *
11 | * - Foo
12 | * - Bar
13 | * - Baz
14 | * - Qux
15 | *
16 | *
17 | * Some highlighted text goes here...
18 | * End highlight 1
19 | *
20 | * NOTE: `screenReaderOnly` is not a real class, just used for brevity
21 | *
22 | * @param {String} documentId The ID of the document
23 | * @param {String} annotationId The ID of the annotation
24 | * @param {Array} [comments] Optionally preloaded comments to be rendered
25 | * @return {Promise} Promise that once has comments, render them for screen reader
26 | */
27 | export default function renderScreenReaderComments(documentId, annotationId, comments) {
28 | let promise;
29 |
30 | if (Array.isArray(comments)) {
31 | promise = Promise.resolve(comments);
32 | }
33 | else {
34 | promise = PDFJSAnnotate.getStoreAdapter().getComments(documentId, annotationId);
35 | }
36 |
37 | return promise.then((comments) => {
38 | // Node needs to be found by querying DOM as it may have been inserted as innerHTML
39 | // leaving `screenReaderNode` as an invalid reference (see `insertElementWithinElement`).
40 | let node = document.getElementById(`pdf-annotate-screenreader-${annotationId}`);
41 | if (node) {
42 | let list = document.createElement('ol');
43 | list.setAttribute('id', `pdf-annotate-screenreader-comment-list-${annotationId}`);
44 | list.setAttribute('aria-label', 'Comments');
45 | node.appendChild(list);
46 | comments.forEach(insertScreenReaderComment);
47 | }
48 | });
49 | }
50 |
--------------------------------------------------------------------------------
/src/a11y/renderScreenReaderHints.js:
--------------------------------------------------------------------------------
1 | import insertScreenReaderHint from './insertScreenReaderHint';
2 | import initEventHandlers from './initEventHandlers';
3 |
4 | // TODO This is not the right place for this to live
5 | initEventHandlers();
6 |
7 | /**
8 | * Insert hints into the DOM for screen readers.
9 | *
10 | * @param {Array} annotations The annotations that hints are inserted for
11 | */
12 | export default function renderScreenReaderHints(annotations) {
13 | annotations = Array.isArray(annotations) ? annotations : [];
14 |
15 | // Insert hints for each type
16 | Object.keys(SORT_TYPES).forEach((type) => {
17 | let sortBy = SORT_TYPES[type];
18 | annotations
19 | .filter((a) => a.type === type)
20 | .sort(sortBy)
21 | .forEach((a, i) => insertScreenReaderHint(a, i + 1));
22 | });
23 | }
24 |
25 | // Sort annotations first by y, then by x.
26 | // This allows hints to be injected in the order they appear,
27 | // which makes numbering them easier.
28 | function sortByPoint(a, b) {
29 | if (a.y < b.y) {
30 | return a.x - b.x;
31 | }
32 | else {
33 | return 1;
34 | }
35 | }
36 |
37 | // Sort annotation by it's first rectangle
38 | function sortByRectPoint(a, b) {
39 | return sortByPoint(a.rectangles[0], b.rectangles[0]);
40 | }
41 |
42 | // Sort annotation by it's first line
43 | function sortByLinePoint(a, b) {
44 | let lineA = a.lines[0];
45 | let lineB = b.lines[0];
46 | return sortByPoint(
47 | {x: lineA[0], y: lineA[1]},
48 | {x: lineB[0], y: lineB[1]}
49 | );
50 | }
51 |
52 | // Arrange supported types and associated sort methods
53 | const SORT_TYPES = {
54 | 'highlight': sortByRectPoint,
55 | 'strikeout': sortByRectPoint,
56 | 'drawing': sortByLinePoint,
57 | 'textbox': sortByPoint,
58 | 'point': sortByPoint,
59 | 'area': sortByPoint
60 | };
61 |
62 |
--------------------------------------------------------------------------------
/src/adapter/LocalStoreAdapter.js:
--------------------------------------------------------------------------------
1 | import uuid from '../utils/uuid';
2 | import StoreAdapter from './StoreAdapter';
3 |
4 | // StoreAdapter for working with localStorage
5 | // This is ideal for testing, examples, and prototyping
6 | export default class LocalStoreAdapter extends StoreAdapter {
7 | constructor() {
8 | super({
9 | getAnnotations(documentId, pageNumber) {
10 | return new Promise((resolve, reject) => {
11 | let annotations = getAnnotations(documentId).filter((i) => {
12 | return i.page === pageNumber && i.class === 'Annotation';
13 | });
14 |
15 | resolve({
16 | documentId,
17 | pageNumber,
18 | annotations
19 | });
20 | });
21 | }
22 | });
23 |
24 | this.getAnnotation = (documentId, annotationId) => {
25 | return Promise.resolve(getAnnotations(documentId)[findAnnotation(documentId, annotationId)]);
26 | };
27 |
28 | this.addAnnotation = (documentId, pageNumber, annotation) => {
29 | return new Promise((resolve, reject) => {
30 | annotation.class = 'Annotation';
31 | annotation.uuid = uuid();
32 | annotation.page = pageNumber;
33 |
34 | let annotations = getAnnotations(documentId);
35 | annotations.push(annotation);
36 | updateAnnotations(documentId, annotations);
37 |
38 | resolve(annotation);
39 | });
40 | };
41 |
42 | this.editAnnotation = (documentId, annotationId, annotation) => {
43 | return new Promise((resolve, reject) => {
44 | let annotations = getAnnotations(documentId);
45 | annotations[findAnnotation(documentId, annotationId)] = annotation;
46 | updateAnnotations(documentId, annotations);
47 | resolve(annotation);
48 | });
49 | };
50 |
51 | this.deleteAnnotation = (documentId, annotationId) => {
52 | return new Promise((resolve, reject) => {
53 | let annotation = getAnnotations(documentId).filter(i => i.uuid === annotationId)[0] || {};
54 | if (!annotation) {
55 | return reject('Could not find annotation');
56 | }
57 | let index = findAnnotation(documentId, annotationId);
58 | if (index > -1) {
59 | let annotations = getAnnotations(documentId);
60 | annotations.splice(index, 1);
61 | updateAnnotations(documentId, annotations);
62 | }
63 |
64 | resolve(true);
65 | });
66 | };
67 |
68 | this.getComments = (documentId, annotationId) => {
69 | return new Promise((resolve, reject) => {
70 | resolve(getAnnotations(documentId).filter((i) => {
71 | return i.class === 'Comment' && i.annotation === annotationId;
72 | }));
73 | });
74 | };
75 |
76 | this.addComment = (documentId, annotationId, content) => {
77 | return new Promise((resolve, reject) => {
78 | let comment = {
79 | class: 'Comment',
80 | uuid: uuid(),
81 | annotation: annotationId,
82 | content: content
83 | };
84 |
85 | let annotations = getAnnotations(documentId);
86 | annotations.push(comment);
87 | updateAnnotations(documentId, annotations);
88 |
89 | resolve(comment);
90 | });
91 | };
92 |
93 | this.deleteComment = (documentId, commentId) => {
94 | return new Promise((resolve, reject) => {
95 | let comment = getAnnotations(documentId).filter(i => i.uuid === commentId)[0] || {};
96 | if (!comment) {
97 | return reject('Could not find annotation');
98 | }
99 | let index = -1;
100 | let annotations = getAnnotations(documentId);
101 | for (let i = 0, l = annotations.length; i < l; i++) {
102 | if (annotations[i].uuid === commentId) {
103 | index = i;
104 | break;
105 | }
106 | }
107 |
108 | if (index > -1) {
109 | annotations.splice(index, 1);
110 | updateAnnotations(documentId, annotations);
111 | }
112 |
113 | resolve(true);
114 | });
115 | };
116 | }
117 | }
118 |
119 | function getAnnotations(documentId) {
120 | return JSON.parse(localStorage.getItem(`${documentId}/annotations`)) || [];
121 | }
122 |
123 | function updateAnnotations(documentId, annotations) {
124 | localStorage.setItem(`${documentId}/annotations`, JSON.stringify(annotations));
125 | }
126 | /**
127 | *
128 | * @param {String} documentId Document id of the annotation
129 | * @param {String} annotationId The id of the annotation
130 | *
131 | * This function finds all the annotation made by one user.
132 | *
133 | * @return {int} The index of the annotation in localstorage
134 | */
135 | function findAnnotation(documentId, annotationId) {
136 | let index = -1;
137 | let annotations = getAnnotations(documentId);
138 | for (let i = 0, l = annotations.length; i < l; i++) {
139 | if (annotations[i].uuid === annotationId) {
140 | index = i;
141 | break;
142 | }
143 | }
144 | return index;
145 | }
146 |
--------------------------------------------------------------------------------
/src/adapter/LocalUserStoreAdapter.js:
--------------------------------------------------------------------------------
1 | import uuid from '../utils/uuid';
2 | import StoreAdapter from './StoreAdapter';
3 |
4 | // StoreAdapter for working with localStorage and associated user id
5 | // This is ideal for testing, examples, and prototyping
6 | export default class LocalUserStoreAdapter extends StoreAdapter {
7 | constructor(userId = 'user', globalEdit = false) {
8 | super({
9 | getAnnotations(documentId, pageNumber) {
10 | return new Promise((resolve, reject) => {
11 | let annotations = getAllAnnotations(documentId).filter((i) => {
12 | return i.page === pageNumber && i.class === 'Annotation';
13 | });
14 |
15 | resolve({
16 | documentId,
17 | pageNumber,
18 | annotations
19 | });
20 | });
21 | }
22 | });
23 |
24 | this._userId = userId;
25 | this._globalEdit = globalEdit;
26 |
27 | this.getAnnotation = (documentId, annotationId) => {
28 | return Promise.resolve(getAnnotations(documentId, this._userId)[findAnnotation(documentId, this._userId, annotationId)]);
29 | };
30 |
31 | this.addAnnotation = (documentId, pageNumber, annotation) => {
32 | return new Promise((resolve, reject) => {
33 | annotation.class = 'Annotation';
34 | annotation.uuid = uuid();
35 | annotation.page = pageNumber;
36 | annotation.userId = this._userId;
37 |
38 | let annotations = getAnnotations(documentId, this._userId);
39 | annotations.push(annotation);
40 | updateAnnotations(documentId, this._userId, annotations);
41 |
42 | resolve(annotation);
43 | });
44 | };
45 |
46 | this.editAnnotation = (documentId, annotationId, annotation) => {
47 | return new Promise((resolve, reject) => {
48 | if (!this._globalEdit && annotation.userId && annotation.userId !== this._userId) {
49 | reject('Non-matching userId');
50 | }
51 | let annotations = getAnnotations(documentId, annotation.userId);
52 | annotations[findAnnotation(documentId, annotation.userId, annotationId)] = annotation;
53 | updateAnnotations(documentId, annotation.userId, annotations);
54 | resolve(annotation);
55 | });
56 | };
57 |
58 | this.deleteAnnotation = (documentId, annotationId) => {
59 | return new Promise((resolve, reject) => {
60 | let annotation = getAllAnnotations(documentId).filter(i => i.uuid === annotationId)[0] || {};
61 | if (!annotation) {
62 | return reject('Could not find annotation');
63 | }
64 | else if (!this._globalEdit && annotation.userId && annotation.userId !== this._userId) {
65 | return reject('Non-matching userId');
66 | }
67 | let index = findAnnotation(documentId, annotation.userId, annotationId);
68 | if (index > -1) {
69 | let annotations = getAnnotations(documentId, annotation.userId);
70 | annotations.splice(index, 1);
71 | updateAnnotations(documentId, annotation.userId, annotations);
72 | }
73 |
74 | resolve(true);
75 | });
76 | };
77 |
78 | this.getComments = (documentId, annotationId) => {
79 | return new Promise((resolve, reject) => {
80 | resolve(getAnnotations(documentId, this._userId).filter((i) => {
81 | return i.class === 'Comment' && i.annotation === annotationId;
82 | }));
83 | });
84 | };
85 |
86 | this.addComment = (documentId, annotationId, content) => {
87 | return new Promise((resolve, reject) => {
88 | let comment = {
89 | class: 'Comment',
90 | uuid: uuid(),
91 | annotation: annotationId,
92 | content: content,
93 | userId: this._userId
94 | };
95 |
96 | let annotations = getAnnotations(documentId, this._userId);
97 | annotations.push(comment);
98 | updateAnnotations(documentId, this._userId, annotations);
99 |
100 | resolve(comment);
101 | });
102 | };
103 |
104 | this.deleteComment = (documentId, commentId) => {
105 | return new Promise((resolve, reject) => {
106 | let comment = getAllAnnotations(documentId).filter(i => i.uuid === commentId)[0] || {};
107 | if (!comment) {
108 | return reject('Could not find annotation');
109 | }
110 | else if (!this._globalEdit && comment.userId && comment.userId !== this._userId) {
111 | return reject('Non-matching userId');
112 | }
113 | let index = -1;
114 | let annotations = getAnnotations(documentId, comment.userId);
115 | for (let i = 0, l = annotations.length; i < l; i++) {
116 | if (annotations[i].uuid === commentId) {
117 | index = i;
118 | break;
119 | }
120 | }
121 |
122 | if (index > -1) {
123 | annotations.splice(index, 1);
124 | updateAnnotations(documentId, comment.userId, annotations);
125 | }
126 |
127 | resolve(true);
128 | });
129 | };
130 | }
131 |
132 | get userId() {
133 | return this._userId;
134 | }
135 | }
136 |
137 | function getAllAnnotations(documentId) {
138 | let all_annotations = [];
139 | let re = new RegExp(`${documentId}/(.*)/annotations`);
140 | for (let i = 0; i < localStorage.length; i++) {
141 | if (localStorage.key(i).search(re) > -1) {
142 | all_annotations.push(...JSON.parse(localStorage.getItem(localStorage.key(i))));
143 | }
144 | }
145 | return all_annotations;
146 | }
147 |
148 | function getAnnotations(documentId, userId) {
149 | return JSON.parse(localStorage.getItem(`${documentId}/${userId}/annotations`)) || [];
150 | }
151 |
152 | function updateAnnotations(documentId, userId, annotations) {
153 | localStorage.setItem(`${documentId}/${userId}/annotations`, JSON.stringify(annotations));
154 | }
155 | /**
156 | *
157 | * @param {String} documentId Document id of the annotation
158 | * @param {String} userId User id of the annotation
159 | * @param {String} annotationId The id of the annotation
160 | *
161 | * This function finds all the annotation made by one user.
162 | *
163 | * @return {int} The index of the annotation in localstorage
164 | */
165 | function findAnnotation(documentId, userId, annotationId) {
166 | let index = -1;
167 | let annotations = getAnnotations(documentId, userId);
168 | for (let i = 0, l = annotations.length; i < l; i++) {
169 | if (annotations[i].uuid === annotationId) {
170 | index = i;
171 | break;
172 | }
173 | }
174 | return index;
175 | }
176 |
--------------------------------------------------------------------------------
/src/adapter/StoreAdapter.js:
--------------------------------------------------------------------------------
1 | // Disable JSDoc as it cannot really deal with the odd way that the functions are defined
2 | /* eslint valid-jsdoc: 0 */
3 |
4 | import abstractFunction from '../utils/abstractFunction';
5 | import { fireEvent } from '../UI/event';
6 |
7 | // Adapter should never be invoked publicly
8 | export default class StoreAdapter {
9 | /**
10 | * Create a new StoreAdapter instance
11 | *
12 | * @param {Object} [definition] The definition to use for overriding abstract methods
13 | */
14 | constructor(definition = {}) {
15 | // Copy each function from definition if it is a function we know about
16 | Object.keys(definition).forEach((key) => {
17 | if (typeof definition[key] === 'function' &&
18 | typeof this[key] === 'function') {
19 | this[key] = definition[key];
20 | }
21 | });
22 | }
23 |
24 | /**
25 | * Get all the annotations for a given document and page number.
26 | *
27 | * @param {String} documentId The ID for the document the annotations belong to
28 | * @param {Number} pageNumber The number of the page the annotations belong to
29 | * @return {Promise} Promise that returns with list of annotations for document and page
30 | */
31 | __getAnnotations(documentId, pageNumber) { abstractFunction('getAnnotations'); }
32 | get getAnnotations() { return this.__getAnnotations; }
33 | set getAnnotations(fn) {
34 | this.__getAnnotations = function getAnnotations(documentId, pageNumber) {
35 | return fn(...arguments).then((annotations) => {
36 | // TODO may be best to have this happen on the server
37 | if (annotations.annotations) {
38 | annotations.annotations.forEach((a) => {
39 | a.documentId = documentId;
40 | });
41 | }
42 | return annotations;
43 | });
44 | };
45 | }
46 |
47 | /**
48 | * Get the definition for a specific annotation.
49 | *
50 | * @param {String} documentId The ID for the document the annotation belongs to
51 | * @param {String} annotationId The ID for the annotation
52 | * @return {Promise} Promise that returns the requested annotation
53 | */
54 | getAnnotation(documentId, annotationId) { abstractFunction('getAnnotation'); }
55 |
56 | /**
57 | * Add an annotation
58 | *
59 | * @param {String} documentId The ID for the document to add the annotation to
60 | * @param {String} pageNumber The page number to add the annotation to
61 | * @param {Object} annotation The definition for the new annotation
62 | * @return {Promise} Promise that returns with the added annotation
63 | */
64 | __addAnnotation(documentId, pageNumber, annotation) { abstractFunction('addAnnotation'); }
65 | get addAnnotation() { return this.__addAnnotation; }
66 | set addAnnotation(fn) {
67 | this.__addAnnotation = function addAnnotation(documentId, pageNumber, annotation) {
68 | return fn(...arguments).then((annotation) => {
69 | fireEvent('annotation:add', documentId, pageNumber, annotation);
70 | return annotation;
71 | });
72 | };
73 | }
74 |
75 | /**
76 | * Edit an annotation
77 | *
78 | * @param {String} documentId The ID for the document
79 | * @param {String} pageNumber the page number of the annotation
80 | * @param {Object} annotation The definition of the modified annotation
81 | * @return {Promise} Promise that returns with the edited annotation
82 | */
83 | __editAnnotation(documentId, pageNumber, annotation) { abstractFunction('editAnnotation'); }
84 | get editAnnotation() { return this.__editAnnotation; }
85 | set editAnnotation(fn) {
86 | this.__editAnnotation = function editAnnotation(documentId, annotationId, annotation) {
87 | return fn(...arguments).then((annotation) => {
88 | fireEvent('annotation:edit', documentId, annotationId, annotation);
89 | return annotation;
90 | });
91 | };
92 | }
93 |
94 | /**
95 | * Delete an annotation
96 | *
97 | * @param {String} documentId The ID for the document
98 | * @param {String} annotationId The ID for the annotation
99 | * @return {Promise} Promise that returns with boolean if annotation was deleted
100 | */
101 | __deleteAnnotation(documentId, annotationId) { abstractFunction('deleteAnnotation'); }
102 | get deleteAnnotation() { return this.__deleteAnnotation; }
103 | set deleteAnnotation(fn) {
104 | this.__deleteAnnotation = function deleteAnnotation(documentId, annotationId) {
105 | return fn(...arguments).then((success) => {
106 | if (success) {
107 | fireEvent('annotation:delete', documentId, annotationId);
108 | }
109 | return success;
110 | });
111 | };
112 | }
113 |
114 | /**
115 | * Get all the comments for an annotation
116 | *
117 | * @param {String} documentId The ID for the document
118 | * @param {String} annotationId The ID for the annotation
119 | * @return {Promise} Promise that returns with comments for annotation
120 | */
121 | getComments(documentId, annotationId) { abstractFunction('getComments'); }
122 |
123 | /**
124 | * Add a new comment
125 | *
126 | * @param {String} documentId The ID for the document
127 | * @param {String} annotationId The ID for the annotation
128 | * @param {Object} content The definition of the comment
129 | * @return {Promise} Promise that returns with the added comment
130 | */
131 | __addComment(documentId, annotationId, content) { abstractFunction('addComment'); }
132 | get addComment() { return this.__addComment; }
133 | set addComment(fn) {
134 | this.__addComment = function addComment(documentId, annotationId, content) {
135 | return fn(...arguments).then((comment) => {
136 | fireEvent('comment:add', documentId, annotationId, comment);
137 | return comment;
138 | });
139 | };
140 | }
141 |
142 | /**
143 | * Delete a comment
144 | *
145 | * @param {String} documentId The ID for the document
146 | * @param {String} commentId The ID for the comment
147 | * @return {Promise} Promise that returns with boolean if comment was deleted
148 | */
149 | __deleteComment(documentId, commentId) { abstractFunction('deleteComment'); }
150 | get deleteComment() { return this.__deleteComment; }
151 | set deleteComment(fn) {
152 | this.__deleteComment = function deleteComment(documentId, commentId) {
153 | return fn(...arguments).then((success) => {
154 | if (success) {
155 | fireEvent('comment:delete', documentId, commentId);
156 | }
157 | return success;
158 | });
159 | };
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | annotationLayerName: 'annotationLayer',
3 | textLayerName: 'textLayer',
4 | annotationSvgQuery: function() {
5 | return 'svg.' + this.annotationLayerName;
6 | },
7 | annotationClassQuery: function() {
8 | return '.' + this.annotationLayerName;
9 | },
10 | textClassQuery: function() {
11 | return '.' + this.textLayerName;
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/css/cmaps/78-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78ms-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78ms-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/78ms-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/78ms-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/83pv-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/83pv-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/90ms-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/90ms-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/90ms-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/90ms-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/90msp-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/90msp-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/90msp-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/90msp-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/90pv-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/90pv-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/90pv-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/90pv-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Add-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Add-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Add-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Add-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Add-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Add-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Add-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Add-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-0.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-0.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-1.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-1.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-3.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-3.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-4.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-4.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-5.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-5.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-6.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-6.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-CNS1-UCS2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-CNS1-UCS2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-0.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-0.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-1.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-1.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-3.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-3.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-4.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-4.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-5.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-5.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-GB1-UCS2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-GB1-UCS2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-0.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-0.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-1.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-1.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-3.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-3.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-4.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-4.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-5.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-5.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-6.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-6.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Japan1-UCS2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Japan1-UCS2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Korea1-0.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Korea1-0.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Korea1-1.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Korea1-1.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Korea1-2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Korea1-2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Adobe-Korea1-UCS2.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Adobe-Korea1-UCS2.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/B5pc-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/B5pc-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/B5pc-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/B5pc-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/CNS-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/CNS-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/CNS-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/CNS-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/CNS1-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/CNS1-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/CNS1-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/CNS1-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/CNS2-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/CNS2-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/CNS2-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/CNS2-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/ETHK-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/ETHK-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/ETHK-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/ETHK-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/ETen-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/ETen-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/ETen-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/ETen-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/ETenms-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/ETenms-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/ETenms-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/ETenms-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Ext-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Ext-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Ext-RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Ext-RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Ext-RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Ext-RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Ext-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Ext-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GB-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GB-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GB-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GB-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GB-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GB-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GB-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GB-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBK-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBK-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBK-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBK-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBK2K-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBK2K-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBK2K-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBK2K-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBKp-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBKp-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBKp-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBKp-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBT-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBT-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBT-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBT-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBT-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBT-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBT-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBT-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBTpc-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBTpc-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBTpc-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBTpc-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBpc-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBpc-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/GBpc-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/GBpc-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKdla-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKdla-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKdla-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKdla-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKdlb-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKdlb-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKdlb-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKdlb-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKgccs-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKgccs-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKgccs-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKgccs-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKm314-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKm314-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKm314-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKm314-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKm471-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKm471-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKm471-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKm471-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKscs-B5-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKscs-B5-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/HKscs-B5-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/HKscs-B5-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Hankaku.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Hankaku.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Hiragana.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Hiragana.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSC-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSC-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSC-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSC-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSC-Johab-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSC-Johab-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSC-Johab-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSC-Johab-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSCms-UHC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSCms-UHC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSCms-UHC-HW-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSCms-UHC-HW-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSCms-UHC-HW-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSCms-UHC-HW-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSCms-UHC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSCms-UHC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSCpc-EUC-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSCpc-EUC-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/KSCpc-EUC-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/KSCpc-EUC-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Katakana.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Katakana.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/LICENSE:
--------------------------------------------------------------------------------
1 | %%Copyright: -----------------------------------------------------------
2 | %%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
3 | %%Copyright: All rights reserved.
4 | %%Copyright:
5 | %%Copyright: Redistribution and use in source and binary forms, with or
6 | %%Copyright: without modification, are permitted provided that the
7 | %%Copyright: following conditions are met:
8 | %%Copyright:
9 | %%Copyright: Redistributions of source code must retain the above
10 | %%Copyright: copyright notice, this list of conditions and the following
11 | %%Copyright: disclaimer.
12 | %%Copyright:
13 | %%Copyright: Redistributions in binary form must reproduce the above
14 | %%Copyright: copyright notice, this list of conditions and the following
15 | %%Copyright: disclaimer in the documentation and/or other materials
16 | %%Copyright: provided with the distribution.
17 | %%Copyright:
18 | %%Copyright: Neither the name of Adobe Systems Incorporated nor the names
19 | %%Copyright: of its contributors may be used to endorse or promote
20 | %%Copyright: products derived from this software without specific prior
21 | %%Copyright: written permission.
22 | %%Copyright:
23 | %%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 | %%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 | %%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 | %%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 | %%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
28 | %%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 | %%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 | %%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 | %%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 | %%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 | %%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 | %%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 | %%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 | %%Copyright: -----------------------------------------------------------
37 |
--------------------------------------------------------------------------------
/src/css/cmaps/NWP-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/NWP-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/NWP-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/NWP-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/RKSJ-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/RKSJ-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/RKSJ-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/RKSJ-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/Roman.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/Roman.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UCS2-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UCS2-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UCS2-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UCS2-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UTF16-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UTF16-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UTF16-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UTF16-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UTF8-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UTF8-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniCNS-UTF8-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniCNS-UTF8-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UCS2-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UCS2-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UCS2-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UCS2-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UTF16-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UTF16-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UTF16-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UTF16-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UTF8-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UTF8-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniGB-UTF8-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniGB-UTF8-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UCS2-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UCS2-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UCS2-HW-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UCS2-HW-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UCS2-HW-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UCS2-HW-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UCS2-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UCS2-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UTF16-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UTF16-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UTF16-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UTF16-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UTF8-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UTF8-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS-UTF8-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS-UTF8-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS2004-UTF16-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS2004-UTF16-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS2004-UTF16-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS2004-UTF16-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS2004-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS2004-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS2004-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS2004-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS2004-UTF8-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS2004-UTF8-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJIS2004-UTF8-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJIS2004-UTF8-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISPro-UCS2-HW-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISPro-UCS2-HW-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISPro-UCS2-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISPro-UCS2-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISPro-UTF8-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISPro-UTF8-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISX0213-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISX0213-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISX0213-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISX0213-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISX02132004-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISX02132004-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniJISX02132004-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniJISX02132004-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UCS2-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UCS2-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UCS2-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UCS2-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UTF16-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UTF16-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UTF16-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UTF16-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UTF32-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UTF32-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UTF32-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UTF32-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UTF8-H.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UTF8-H.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/UniKS-UTF8-V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/UniKS-UTF8-V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/V.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/V.bcmap
--------------------------------------------------------------------------------
/src/css/cmaps/WP-Symbol.bcmap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/cmaps/WP-Symbol.bcmap
--------------------------------------------------------------------------------
/src/css/images/annotation-check.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/css/images/annotation-comment.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/src/css/images/annotation-help.svg:
--------------------------------------------------------------------------------
1 |
2 |
27 |
--------------------------------------------------------------------------------
/src/css/images/annotation-insert.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/css/images/annotation-key.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/css/images/annotation-newparagraph.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/src/css/images/annotation-noicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/css/images/annotation-note.svg:
--------------------------------------------------------------------------------
1 |
2 |
43 |
--------------------------------------------------------------------------------
/src/css/images/annotation-paragraph.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/src/css/images/findbarButton-next-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-next-rtl.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-next-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-next-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-next.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-next@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-next@2x.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-previous-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-previous-rtl.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-previous-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-previous-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-previous.png
--------------------------------------------------------------------------------
/src/css/images/findbarButton-previous@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/findbarButton-previous@2x.png
--------------------------------------------------------------------------------
/src/css/images/grab.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/grab.cur
--------------------------------------------------------------------------------
/src/css/images/grabbing.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/grabbing.cur
--------------------------------------------------------------------------------
/src/css/images/loading-icon.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/loading-icon.gif
--------------------------------------------------------------------------------
/src/css/images/loading-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/loading-small.png
--------------------------------------------------------------------------------
/src/css/images/loading-small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/loading-small@2x.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-documentProperties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-documentProperties.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-documentProperties@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-documentProperties@2x.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-firstPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-firstPage.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-firstPage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-firstPage@2x.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-handTool.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-handTool.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-handTool@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-handTool@2x.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-lastPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-lastPage.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-lastPage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-lastPage@2x.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-rotateCcw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-rotateCcw.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-rotateCcw@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-rotateCcw@2x.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-rotateCw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-rotateCw.png
--------------------------------------------------------------------------------
/src/css/images/secondaryToolbarButton-rotateCw@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/secondaryToolbarButton-rotateCw@2x.png
--------------------------------------------------------------------------------
/src/css/images/shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/shadow.png
--------------------------------------------------------------------------------
/src/css/images/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/texture.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-bookmark.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-bookmark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-bookmark@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-download.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-download@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-download@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-menuArrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-menuArrows.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-menuArrows@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-menuArrows@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-openFile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-openFile.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-openFile@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-openFile@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageDown-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageDown-rtl.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageDown-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageDown-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageDown.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageDown@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageDown@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageUp-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageUp-rtl.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageUp-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageUp-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageUp.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-pageUp@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-pageUp@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-presentationMode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-presentationMode.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-presentationMode@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-presentationMode@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-print.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-print@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-print@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-search.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-search@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-secondaryToolbarToggle-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-secondaryToolbarToggle-rtl.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-secondaryToolbarToggle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-secondaryToolbarToggle.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-secondaryToolbarToggle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-secondaryToolbarToggle@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-sidebarToggle-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-sidebarToggle-rtl.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-sidebarToggle-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-sidebarToggle-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-sidebarToggle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-sidebarToggle.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-sidebarToggle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-sidebarToggle@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewAttachments.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewAttachments.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewAttachments@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewAttachments@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewOutline-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewOutline-rtl.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewOutline-rtl@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewOutline-rtl@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewOutline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewOutline.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewOutline@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewOutline@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewThumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewThumbnail.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-viewThumbnail@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-viewThumbnail@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-zoomIn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-zoomIn.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-zoomIn@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-zoomIn@2x.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-zoomOut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-zoomOut.png
--------------------------------------------------------------------------------
/src/css/images/toolbarButton-zoomOut@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sxhxliang/pdf-annotate-vue/400f1e5f5c9eff7f82a042b765ce243411cfd912/src/css/images/toolbarButton-zoomOut@2x.png
--------------------------------------------------------------------------------
/src/css/pdf_viewer.css:
--------------------------------------------------------------------------------
1 | /* Copyright 2014 Mozilla Foundation
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | .textLayer {
17 | position: absolute;
18 | left: 0;
19 | top: 0;
20 | right: 0;
21 | bottom: 0;
22 | overflow: hidden;
23 | opacity: 0.2;
24 | line-height: 1.0;
25 | }
26 |
27 | .textLayer > div {
28 | color: transparent;
29 | position: absolute;
30 | white-space: pre;
31 | cursor: text;
32 | -webkit-transform-origin: 0% 0%;
33 | transform-origin: 0% 0%;
34 | }
35 |
36 | .textLayer .highlight {
37 | margin: -1px;
38 | padding: 1px;
39 |
40 | background-color: rgb(180, 0, 170);
41 | border-radius: 4px;
42 | }
43 |
44 | .textLayer .highlight.begin {
45 | border-radius: 4px 0px 0px 4px;
46 | }
47 |
48 | .textLayer .highlight.end {
49 | border-radius: 0px 4px 4px 0px;
50 | }
51 |
52 | .textLayer .highlight.middle {
53 | border-radius: 0px;
54 | }
55 |
56 | .textLayer .highlight.selected {
57 | background-color: rgb(0, 100, 0);
58 | }
59 |
60 | .textLayer ::-moz-selection { background: rgb(0,0,255); }
61 |
62 | .textLayer ::selection { background: rgb(0,0,255); }
63 |
64 | .textLayer .endOfContent {
65 | display: block;
66 | position: absolute;
67 | left: 0px;
68 | top: 100%;
69 | right: 0px;
70 | bottom: 0px;
71 | z-index: -1;
72 | cursor: default;
73 | -webkit-user-select: none;
74 | -moz-user-select: none;
75 | -ms-user-select: none;
76 | user-select: none;
77 | }
78 |
79 | .textLayer .endOfContent.active {
80 | top: 0px;
81 | }
82 |
83 |
84 | .annotationLayer section {
85 | position: absolute;
86 | }
87 |
88 | .annotationLayer .linkAnnotation > a,
89 | .annotationLayer .buttonWidgetAnnotation.pushButton > a {
90 | position: absolute;
91 | font-size: 1em;
92 | top: 0;
93 | left: 0;
94 | width: 100%;
95 | height: 100%;
96 | }
97 |
98 | .annotationLayer .linkAnnotation > a:hover,
99 | .annotationLayer .buttonWidgetAnnotation.pushButton > a:hover {
100 | opacity: 0.2;
101 | background: #ff0;
102 | box-shadow: 0px 2px 10px #ff0;
103 | }
104 |
105 | .annotationLayer .textAnnotation img {
106 | position: absolute;
107 | cursor: pointer;
108 | }
109 |
110 | .annotationLayer .textWidgetAnnotation input,
111 | .annotationLayer .textWidgetAnnotation textarea,
112 | .annotationLayer .choiceWidgetAnnotation select,
113 | .annotationLayer .buttonWidgetAnnotation.checkBox input,
114 | .annotationLayer .buttonWidgetAnnotation.radioButton input {
115 | background-color: rgba(0, 54, 255, 0.13);
116 | border: 1px solid transparent;
117 | box-sizing: border-box;
118 | font-size: 9px;
119 | height: 100%;
120 | margin: 0;
121 | padding: 0 3px;
122 | vertical-align: top;
123 | width: 100%;
124 | }
125 |
126 | .annotationLayer .choiceWidgetAnnotation select option {
127 | padding: 0;
128 | }
129 |
130 | .annotationLayer .buttonWidgetAnnotation.radioButton input {
131 | border-radius: 50%;
132 | }
133 |
134 | .annotationLayer .textWidgetAnnotation textarea {
135 | font: message-box;
136 | font-size: 9px;
137 | resize: none;
138 | }
139 |
140 | .annotationLayer .textWidgetAnnotation input[disabled],
141 | .annotationLayer .textWidgetAnnotation textarea[disabled],
142 | .annotationLayer .choiceWidgetAnnotation select[disabled],
143 | .annotationLayer .buttonWidgetAnnotation.checkBox input[disabled],
144 | .annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] {
145 | background: none;
146 | border: 1px solid transparent;
147 | cursor: not-allowed;
148 | }
149 |
150 | .annotationLayer .textWidgetAnnotation input:hover,
151 | .annotationLayer .textWidgetAnnotation textarea:hover,
152 | .annotationLayer .choiceWidgetAnnotation select:hover,
153 | .annotationLayer .buttonWidgetAnnotation.checkBox input:hover,
154 | .annotationLayer .buttonWidgetAnnotation.radioButton input:hover {
155 | border: 1px solid #000;
156 | }
157 |
158 | .annotationLayer .textWidgetAnnotation input:focus,
159 | .annotationLayer .textWidgetAnnotation textarea:focus,
160 | .annotationLayer .choiceWidgetAnnotation select:focus {
161 | background: none;
162 | border: 1px solid transparent;
163 | }
164 |
165 | .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before,
166 | .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after,
167 | .annotationLayer .buttonWidgetAnnotation.radioButton input:checked:before {
168 | background-color: #000;
169 | content: '';
170 | display: block;
171 | position: absolute;
172 | }
173 |
174 | .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before,
175 | .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after {
176 | height: 80%;
177 | left: 45%;
178 | width: 1px;
179 | }
180 |
181 | .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:before {
182 | -webkit-transform: rotate(45deg);
183 | transform: rotate(45deg);
184 | }
185 |
186 | .annotationLayer .buttonWidgetAnnotation.checkBox input:checked:after {
187 | -webkit-transform: rotate(-45deg);
188 | transform: rotate(-45deg);
189 | }
190 |
191 | .annotationLayer .buttonWidgetAnnotation.radioButton input:checked:before {
192 | border-radius: 50%;
193 | height: 50%;
194 | left: 30%;
195 | top: 20%;
196 | width: 50%;
197 | }
198 |
199 | .annotationLayer .textWidgetAnnotation input.comb {
200 | font-family: monospace;
201 | padding-left: 2px;
202 | padding-right: 0;
203 | }
204 |
205 | .annotationLayer .textWidgetAnnotation input.comb:focus {
206 | /*
207 | * Letter spacing is placed on the right side of each character. Hence, the
208 | * letter spacing of the last character may be placed outside the visible
209 | * area, causing horizontal scrolling. We avoid this by extending the width
210 | * when the element has focus and revert this when it loses focus.
211 | */
212 | width: 115%;
213 | }
214 |
215 | .annotationLayer .buttonWidgetAnnotation.checkBox input,
216 | .annotationLayer .buttonWidgetAnnotation.radioButton input {
217 | -webkit-appearance: none;
218 | -moz-appearance: none;
219 | appearance: none;
220 | padding: 0;
221 | }
222 |
223 | .annotationLayer .popupWrapper {
224 | position: absolute;
225 | width: 20em;
226 | }
227 |
228 | .annotationLayer .popup {
229 | position: absolute;
230 | z-index: 200;
231 | max-width: 20em;
232 | background-color: #FFFF99;
233 | box-shadow: 0px 2px 5px #333;
234 | border-radius: 2px;
235 | padding: 0.6em;
236 | margin-left: 5px;
237 | cursor: pointer;
238 | font: message-box;
239 | word-wrap: break-word;
240 | }
241 |
242 | .annotationLayer .popup h1 {
243 | font-size: 1em;
244 | border-bottom: 1px solid #000000;
245 | margin: 0;
246 | padding-bottom: 0.2em;
247 | }
248 |
249 | .annotationLayer .popup p {
250 | margin: 0;
251 | padding-top: 0.2em;
252 | }
253 |
254 | .annotationLayer .highlightAnnotation,
255 | .annotationLayer .underlineAnnotation,
256 | .annotationLayer .squigglyAnnotation,
257 | .annotationLayer .strikeoutAnnotation,
258 | .annotationLayer .lineAnnotation svg line,
259 | .annotationLayer .squareAnnotation svg rect,
260 | .annotationLayer .circleAnnotation svg ellipse,
261 | .annotationLayer .polylineAnnotation svg polyline,
262 | .annotationLayer .polygonAnnotation svg polygon,
263 | .annotationLayer .inkAnnotation svg polyline,
264 | .annotationLayer .stampAnnotation,
265 | .annotationLayer .fileAttachmentAnnotation {
266 | cursor: pointer;
267 | }
268 |
269 |
270 | .page .annotationLayer {
271 | position: absolute;
272 | left: 0;
273 | top: 0;
274 | right: 0;
275 | bottom: 0;
276 | overflow: hidden;
277 | opacity: 0.2;
278 | line-height: 1.0;
279 | }
280 |
281 |
282 | .pdfViewer .canvasWrapper {
283 | overflow: hidden;
284 | }
285 |
286 | /* .pdfViewer .page {
287 | direction: ltr;
288 | width: 816px;
289 | height: 1056px;
290 | margin: 1px auto -8px auto;
291 | position: relative;
292 | overflow: visible;
293 | border: 9px solid transparent;
294 | background-clip: content-box;
295 | -o-border-image: url(images/shadow.png) 9 9 repeat;
296 | border-image: url(images/shadow.png) 9 9 repeat;
297 | background-color: white;
298 | } */
299 |
300 | .pdfViewer.removePageBorders .page {
301 | margin: 0px auto 10px auto;
302 | border: none;
303 | }
304 |
305 | .pdfViewer.singlePageView {
306 | display: inline-block;
307 | }
308 |
309 | .pdfViewer.singlePageView .page {
310 | margin: 0;
311 | border: none;
312 | }
313 |
314 | .pdfViewer.scrollHorizontal, .pdfViewer.scrollWrapped, .spread {
315 | margin-left: 3.5px;
316 | margin-right: 3.5px;
317 | text-align: center;
318 | }
319 |
320 | .pdfViewer.scrollHorizontal, .spread {
321 | white-space: nowrap;
322 | }
323 |
324 | .pdfViewer.removePageBorders,
325 | .pdfViewer.scrollHorizontal .spread,
326 | .pdfViewer.scrollWrapped .spread {
327 | margin-left: 0;
328 | margin-right: 0;
329 | }
330 |
331 | .spread .page,
332 | .pdfViewer.scrollHorizontal .page,
333 | .pdfViewer.scrollWrapped .page,
334 | .pdfViewer.scrollHorizontal .spread,
335 | .pdfViewer.scrollWrapped .spread {
336 | display: inline-block;
337 | vertical-align: middle;
338 | }
339 |
340 | .spread .page,
341 | .pdfViewer.scrollHorizontal .page,
342 | .pdfViewer.scrollWrapped .page {
343 | margin-left: -3.5px;
344 | margin-right: -3.5px;
345 | }
346 |
347 | .pdfViewer.removePageBorders .spread .page,
348 | .pdfViewer.removePageBorders.scrollHorizontal .page,
349 | .pdfViewer.removePageBorders.scrollWrapped .page {
350 | margin-left: 5px;
351 | margin-right: 5px;
352 | }
353 |
354 | .pdfViewer .page canvas {
355 | margin: 0;
356 | display: block;
357 | }
358 |
359 | .pdfViewer .page canvas[hidden] {
360 | display: none;
361 | }
362 |
363 | .pdfViewer .page .loadingIcon {
364 | position: absolute;
365 | display: block;
366 | left: 0;
367 | top: 0;
368 | right: 0;
369 | bottom: 0;
370 | background: url('images/loading-icon.gif') center no-repeat;
371 | }
372 |
373 | .pdfPresentationMode .pdfViewer {
374 | margin-left: 0;
375 | margin-right: 0;
376 | }
377 |
378 | .pdfPresentationMode .pdfViewer .page,
379 | .pdfPresentationMode .pdfViewer .spread {
380 | display: block;
381 | }
382 |
383 | .pdfPresentationMode .pdfViewer .page,
384 | .pdfPresentationMode .pdfViewer.removePageBorders .page {
385 | margin-left: auto;
386 | margin-right: auto;
387 | }
388 |
389 | .pdfPresentationMode:-ms-fullscreen .pdfViewer .page {
390 | margin-bottom: 100% !important;
391 | }
392 |
393 | .pdfPresentationMode:-webkit-full-screen .pdfViewer .page {
394 | margin-bottom: 100%;
395 | border: 0;
396 | }
397 |
398 | .pdfPresentationMode:-moz-full-screen .pdfViewer .page {
399 | margin-bottom: 100%;
400 | border: 0;
401 | }
402 |
403 | .pdfPresentationMode:fullscreen .pdfViewer .page {
404 | margin-bottom: 100%;
405 | border: 0;
406 | }
407 |
--------------------------------------------------------------------------------
/src/css/toolbar.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | font-family: sans-serif;
7 | margin: 40px 0;
8 | }
9 |
10 | .toolbar {
11 | background-color: #eaeaea;
12 | border-bottom: 1px solid #d0d0d0;
13 | height: 35px;
14 | position: fixed;
15 | top: 0;
16 | left: 0;
17 | right: 0;
18 | padding: 0 5px;
19 | text-shadow: 1px 1px 0 #fff;
20 | z-index: 100;
21 | -webkit-box-shadow: inset 0px 1px 1px 0px rgba(255,255,255,1);
22 | -moz-box-shadow: inset 0px 1px 1px 0px rgba(255,255,255,1);
23 | box-shadow: inset 0px 1px 1px 0px rgba(255,255,255,1);
24 | }
25 | .toolbar .spacer {
26 | display: inline-block;
27 | border-left: 1px solid #c1c1c1;
28 | height: 34px;
29 | margin: 0 5px -11px;
30 | }
31 |
32 | .toolbar a {
33 | color: inherit;
34 | text-decoration: none;
35 | }
36 |
37 | .toolbar button {
38 | background-color: #eaeaea;
39 | border: 1px solid transparent;
40 | border-radius: 3px;
41 | font-size: 15px;
42 | padding: 3px;
43 | margin: 0;
44 | text-align: center;
45 | text-shadow: 1px 1px 0 #fff;
46 | position: relative;
47 | min-width: 27px;
48 | min-height: 27px;
49 | }
50 | .toolbar button:after {
51 | content: ' ';
52 | display: block;
53 | }
54 | .toolbar button.active {
55 | border-color: #bababa;
56 | -webkit-box-shadow: inset 0 0 1px rgba(0,0,0,0.25);
57 | -moz-box-shadow: inset 0 0 1px rgba(0,0,0,0.25);
58 | box-shadow: inset 0 0 1px rgba(0,0,0,0.25);
59 | }
60 | .toolbar button:hover,
61 | .toolbar button:focus {
62 | border-color: #bababa;
63 | }
64 |
65 | .toolbar button.pen {
66 | font-size: 16px;
67 | }
68 |
69 | .toolbar button.comment {
70 | font-size: 10px;
71 | color: #ffffff;
72 | text-shadow: 0 0 0 #000000;
73 | }
74 |
75 | .toolbar button.rectangle:after {
76 | width: 15px;
77 | height: 15px;
78 | border: 1px solid red;
79 | position: absolute;
80 | top: 4px;
81 | left: 4px;
82 | }
83 |
84 | .toolbar button.circle:after {
85 | width: 15px;
86 | height: 15px;
87 | border: 0px solid red;
88 | position: absolute;
89 | top: 4px;
90 | left: 4px;
91 | }
92 |
93 | .toolbar button.highlight:after {
94 | width: 17px;
95 | height: 17px;
96 | background: yellow;
97 | position: absolute;
98 | top: 4px;
99 | left: 4px;
100 | }
101 |
102 | .toolbar button.strikeout:after {
103 | width: 15px;
104 | height: 1px;
105 | background: red;
106 | position: absolute;
107 | top: 12px;
108 | left: 4px;
109 | }
110 |
111 | .toolbar button.text:after {
112 | content: 'T';
113 | font-family: 'Times New Roman';
114 | }
115 |
116 | .color {
117 | display: inline-block;
118 | width: 25px;
119 | height: 25px;
120 | border: 1px solid #000;
121 | vertical-align: middle;
122 | }
123 | .color-selected {
124 | border: 3px solid #666;
125 | width: 30px;
126 | height: 30px;
127 | margin-top: -1px;
128 | margin-left: -2px;
129 | margin-right: -2px;
130 | }
131 | .text-color, .pen-color, .hotspot-color {
132 | display: inline-block;
133 | }
134 |
--------------------------------------------------------------------------------
/src/initColorPicker.js:
--------------------------------------------------------------------------------
1 | // Color picker component
2 | const COLORS = [
3 | {hex: '#000000', name: 'Black'},
4 | {hex: '#EF4437', name: 'Red'},
5 | {hex: '#E71F63', name: 'Pink'},
6 | {hex: '#8F3E97', name: 'Purple'},
7 | {hex: '#65499D', name: 'Deep Purple'},
8 | {hex: '#4554A4', name: 'Indigo'},
9 | {hex: '#2083C5', name: 'Blue'},
10 | {hex: '#35A4DC', name: 'Light Blue'},
11 | {hex: '#09BCD3', name: 'Cyan'},
12 | {hex: '#009688', name: 'Teal'},
13 | {hex: '#43A047', name: 'Green'},
14 | {hex: '#8BC34A', name: 'Light Green'},
15 | {hex: '#FDC010', name: 'Yellow'},
16 | {hex: '#F8971C', name: 'Orange'},
17 | {hex: '#F0592B', name: 'Deep Orange'},
18 | {hex: '#F06291', name: 'Light Pink'}
19 | ];
20 |
21 | export default function initColorPicker(el, value, onChange) {
22 | function getNameFromHex(hex) {
23 | for (let color of COLORS) {
24 | if (color.hex === hex) {
25 | return color.name;
26 | }
27 | }
28 | }
29 |
30 | function setColor(hex, name, fireOnChange = true) {
31 | a.setAttribute('data-color', hex);
32 | a.setAttribute('data-name', name);
33 | a.setAttribute('title', name);
34 | a.style.background = hex;
35 | if (fireOnChange && typeof onChange === 'function') {
36 | onChange(hex);
37 | }
38 | closePicker();
39 | }
40 |
41 | function togglePicker() {
42 | if (isPickerOpen) {
43 | closePicker();
44 | }
45 | else {
46 | openPicker();
47 | }
48 | }
49 |
50 | function closePicker() {
51 | document.removeEventListener('keyup', handleDocumentKeyup);
52 | if (picker && picker.parentNode) {
53 | picker.parentNode.removeChild(picker);
54 | }
55 | isPickerOpen = false;
56 | a.focus();
57 | }
58 |
59 | function openPicker() {
60 | if (!picker) {
61 | picker = document.createElement('div');
62 | picker.style.background = '#fff';
63 | picker.style.border = '1px solid #ccc';
64 | picker.style.padding = '2px';
65 | picker.style.position = 'absolute';
66 | picker.style.width = '122px';
67 | el.style.position = 'relative';
68 |
69 | COLORS.map(createColorOption).forEach((c) => {
70 | c.style.margin = '2px';
71 | c.onclick = function() {
72 | setColor(c.getAttribute('data-color'), c.getAttribute('data-name'));
73 | };
74 | picker.appendChild(c);
75 | });
76 | }
77 |
78 | document.addEventListener('keyup', handleDocumentKeyup);
79 | el.appendChild(picker);
80 | isPickerOpen = true;
81 | }
82 |
83 | function createColorOption(color) {
84 | let e = document.createElement('a');
85 | e.className = 'color';
86 | e.setAttribute('href', 'javascript://');
87 | e.setAttribute('title', color.name);
88 | e.setAttribute('data-name', color.name);
89 | e.setAttribute('data-color', color.hex);
90 | e.style.background = color.hex;
91 | return e;
92 | }
93 |
94 | function handleDocumentKeyup(e) {
95 | if (e.keyCode === 27) {
96 | closePicker();
97 | }
98 | }
99 |
100 | let picker;
101 | let isPickerOpen = false;
102 | let name = getNameFromHex(value);
103 | let a = createColorOption({hex: value, name: name});
104 | a.onclick = togglePicker;
105 | el.appendChild(a);
106 | setColor(value, name, false);
107 | }
108 |
--------------------------------------------------------------------------------
/src/render/appendChild.js:
--------------------------------------------------------------------------------
1 | import objectAssign from 'object-assign';
2 | import renderLine from './renderLine';
3 | import renderPath from './renderPath';
4 | import renderPoint from './renderPoint';
5 | import renderRect from './renderRect';
6 | import renderText from './renderText';
7 | import renderCircle from './renderCircle';
8 | import renderArrow from './renderArrow';
9 |
10 | const isFirefox = /firefox/i.test(navigator.userAgent);
11 |
12 | /**
13 | * Get the x/y translation to be used for transforming the annotations
14 | * based on the rotation of the viewport.
15 | *
16 | * @param {Object} viewport The viewport data from the page
17 | * @return {Object}
18 | */
19 | export function getTranslation(viewport) {
20 | let x;
21 | let y;
22 |
23 | // Modulus 360 on the rotation so that we only
24 | // have to worry about four possible values.
25 | switch (viewport.rotation % 360) {
26 | case 0:
27 | x = y = 0;
28 | break;
29 | case 90:
30 | x = 0;
31 | y = (viewport.width / viewport.scale) * -1;
32 | break;
33 | case 180:
34 | x = (viewport.width / viewport.scale) * -1;
35 | y = (viewport.height / viewport.scale) * -1;
36 | break;
37 | case 270:
38 | x = (viewport.height / viewport.scale) * -1;
39 | y = 0;
40 | break;
41 | }
42 |
43 | return { x, y };
44 | }
45 |
46 | /**
47 | * Transform the rotation and scale of a node using SVG's native transform attribute.
48 | *
49 | * @param {Node} node The node to be transformed
50 | * @param {Object} viewport The page's viewport data
51 | * @return {Node}
52 | */
53 | function transform(node, viewport) {
54 | let trans = getTranslation(viewport);
55 |
56 | // Let SVG natively transform the element
57 | node.setAttribute('transform', `scale(${viewport.scale}) rotate(${viewport.rotation}) translate(${trans.x}, ${trans.y})`);
58 |
59 | // Manually adjust x/y for nested SVG nodes
60 | if (!isFirefox && node.nodeName.toLowerCase() === 'svg') {
61 | node.setAttribute('x', parseInt(node.getAttribute('x'), 10) * viewport.scale);
62 | node.setAttribute('y', parseInt(node.getAttribute('y'), 10) * viewport.scale);
63 |
64 | let x = parseInt(node.getAttribute('x', 10));
65 | let y = parseInt(node.getAttribute('y', 10));
66 | let width = parseInt(node.getAttribute('width'), 10);
67 | let height = parseInt(node.getAttribute('height'), 10);
68 | let path = node.querySelector('path');
69 | let svg = path.parentNode;
70 |
71 | // Scale width/height
72 | [node, svg, path, node.querySelector('rect')].forEach((n) => {
73 | n.setAttribute('width', parseInt(n.getAttribute('width'), 10) * viewport.scale);
74 | n.setAttribute('height', parseInt(n.getAttribute('height'), 10) * viewport.scale);
75 | });
76 |
77 | // Transform path but keep scale at 100% since it will be handled natively
78 | transform(path, objectAssign({}, viewport, { scale: 1 }));
79 |
80 | switch (viewport.rotation % 360) {
81 | case 90:
82 | node.setAttribute('x', viewport.width - y - width);
83 | node.setAttribute('y', x);
84 | svg.setAttribute('x', 1);
85 | svg.setAttribute('y', 0);
86 | break;
87 | case 180:
88 | node.setAttribute('x', viewport.width - x - width);
89 | node.setAttribute('y', viewport.height - y - height);
90 | svg.setAttribute('y', 2);
91 | break;
92 | case 270:
93 | node.setAttribute('x', y);
94 | node.setAttribute('y', viewport.height - x - height);
95 | svg.setAttribute('x', -1);
96 | svg.setAttribute('y', 0);
97 | break;
98 | }
99 | }
100 |
101 | return node;
102 | }
103 |
104 | /**
105 | * Append an annotation as a child of an SVG.
106 | *
107 | * @param {SVGElement} svg The SVG element to append the annotation to
108 | * @param {Object} annotation The annotation definition to render and append
109 | * @param {Object} viewport The page's viewport data
110 | * @return {SVGElement} A node that was created and appended by this function
111 | */
112 | export function appendChild(svg, annotation, viewport) {
113 | if (!viewport) {
114 | viewport = JSON.parse(svg.getAttribute('data-pdf-annotate-viewport'));
115 | }
116 |
117 | let child;
118 | switch (annotation.type) {
119 | case 'area':
120 | case 'highlight':
121 | child = renderRect(annotation);
122 | break;
123 | case 'circle':
124 | case 'fillcircle':
125 | case 'emptycircle':
126 | child = renderCircle(annotation);
127 | break;
128 | case 'strikeout':
129 | child = renderLine(annotation);
130 | break;
131 | case 'point':
132 | child = renderPoint(annotation);
133 | break;
134 | case 'textbox':
135 | child = renderText(annotation);
136 | break;
137 | case 'drawing':
138 | child = renderPath(annotation);
139 | break;
140 | case 'arrow':
141 | child = renderArrow(annotation);
142 | break;
143 | }
144 |
145 | // If no type was provided for an annotation it will result in node being null.
146 | // Skip appending/transforming if node doesn't exist.
147 | if (child) {
148 | // Set attributes
149 | child.setAttribute('data-pdf-annotate-id', annotation.uuid);
150 | child.setAttribute('aria-hidden', true);
151 |
152 | // Dynamically set any other attributes associated with annotation that is not related to drawing it
153 | Object.keys(annotation).filter((key) => {
154 | return ['color', 'x', 'y', 'cx', 'cy', 'color', 'documentId', 'lines', 'page',
155 | 'width', 'class', 'content', 'size', 'rotation', 'r'].indexOf(key) === -1;
156 | }).forEach((key) => {
157 | child.setAttribute(`data-pdf-annotate-${key}`, annotation[key]);
158 | });
159 |
160 | svg.appendChild(transform(child, viewport));
161 | }
162 |
163 | return child;
164 | }
165 |
166 | /**
167 | * Transform a child annotation of an SVG.
168 | *
169 | * @param {SVGElement} svg The SVG element with the child annotation
170 | * @param {Object} child The SVG child to transform
171 | * @param {Object} viewport The page's viewport data
172 | * @return {SVGElement} A node that was transformed by this function
173 | */
174 | export function transformChild(svg, child, viewport) {
175 | if (!viewport) {
176 | viewport = JSON.parse(svg.getAttribute('data-pdf-annotate-viewport'));
177 | }
178 |
179 | // If no type was provided for an annotation it will result in node being null.
180 | // Skip transforming if node doesn't exist.
181 | if (child) {
182 | child = transform(child, viewport);
183 | }
184 |
185 | return child;
186 | }
187 |
188 | export default {
189 | /**
190 | * Get the x/y translation to be used for transforming the annotations
191 | * based on the rotation of the viewport.
192 | */
193 | getTranslation,
194 |
195 | /**
196 | * Append an SVG child for an annotation
197 | */
198 | appendChild,
199 |
200 | /**
201 | * Transform an existing SVG child
202 | */
203 | transformChild
204 | };
205 |
--------------------------------------------------------------------------------
/src/render/index.js:
--------------------------------------------------------------------------------
1 | import { appendChild, transformChild } from './appendChild';
2 |
3 | /**
4 | * Render the response from PDFJSAnnotate.getStoreAdapter().getAnnotations to SVG
5 | *
6 | * @param {SVGElement} svg The SVG element to render the annotations to
7 | * @param {Object} viewport The page viewport data
8 | * @param {Object} data The response from PDFJSAnnotate.getStoreAdapter().getAnnotations
9 | * @return {Promise} Settled once rendering has completed
10 | * A settled Promise will be either:
11 | * - fulfilled: SVGElement
12 | * - rejected: Error
13 | */
14 | export default function render(svg, viewport, data) {
15 | return new Promise((resolve, reject) => {
16 | // Reset the content of the SVG
17 | svg.setAttribute('data-pdf-annotate-container', true);
18 | svg.setAttribute('data-pdf-annotate-viewport', JSON.stringify(viewport));
19 | svg.removeAttribute('data-pdf-annotate-document');
20 | svg.removeAttribute('data-pdf-annotate-page');
21 |
22 | // If there's no data nothing can be done
23 | if (!data) {
24 | svg.innerHTML = '';
25 | return resolve(svg);
26 | }
27 |
28 | svg.setAttribute('data-pdf-annotate-document', data.documentId);
29 | svg.setAttribute('data-pdf-annotate-page', data.pageNumber);
30 |
31 | // Make sure annotations is an array
32 | if (!Array.isArray(data.annotations) || data.annotations.length === 0) {
33 | return resolve(svg);
34 | }
35 |
36 | // Append or transform annotation to svg
37 | data.annotations.forEach((a) => {
38 | let node = svg.querySelector('[data-pdf-annotate-id="' + a.uuid + '"]');
39 | if (node) {
40 | transformChild(svg, node, viewport);
41 | }
42 | else {
43 | appendChild(svg, a, viewport);
44 | }
45 | });
46 |
47 | resolve(svg);
48 | });
49 | }
50 |
--------------------------------------------------------------------------------
/src/render/renderArrow.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 | import normalizeColor from '../utils/normalizeColor';
3 | import {
4 | makePoint, makeVector, makeVectorFromPoints,
5 | magnitude, unitVector, crossProduct,
6 | addVector, multiplyVector, negateVector
7 | } from '../utils/mathUtils';
8 |
9 | /**
10 | * Create SVGPathElement from an annotation definition.
11 | * This is used for anntations of type `drawing`.
12 | *
13 | * @param {Object} a The annotation definition
14 | * @return {SVGPathElement} The path to be rendered
15 | */
16 | export default function renderArrow(a) {
17 | let arrow = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
18 |
19 | if (a.lines.length === 2) {
20 | let p1 = a.lines[0];
21 | let p2 = a.lines[a.lines.length - 1];
22 |
23 | let arrowLength = 40;
24 | let pt0 = makePoint(p1[0], p1[1], 0);
25 | let pt1 = makePoint(p2[0], p2[1], 0);
26 | let x = makeVectorFromPoints(pt0, pt1);
27 | let unitX = unitVector(x);
28 | pt1 = addVector(pt0, multiplyVector(unitX, arrowLength));
29 | x = makeVectorFromPoints(pt0, pt1);
30 | let unitZ = makeVector(0, 0, 1);
31 | let unitY = unitVector(crossProduct(unitX, unitZ));
32 | let thickness = a.width || 10;
33 |
34 | let A = addVector(pt0, multiplyVector(unitY, thickness * 0.5));
35 | let B = addVector(A, multiplyVector(unitX, magnitude(x) - thickness * 2.0));
36 | let C = addVector(B, multiplyVector(unitY, thickness));
37 | let D = pt1;
38 | let G = addVector(pt0, multiplyVector(negateVector(unitY), thickness * 0.5));
39 | let F = addVector(G, multiplyVector(unitX, magnitude(x) - thickness * 2.0));
40 | let E = addVector(F, multiplyVector(negateVector(unitY), thickness));
41 |
42 | let points = '' +
43 | A.x + ',' + A.y + ' ' +
44 | B.x + ',' + B.y + ' ' +
45 | C.x + ',' + C.y + ' ' +
46 | D.x + ',' + D.y + ' ' +
47 | E.x + ',' + E.y + ' ' +
48 | F.x + ',' + F.y + ' ' +
49 | G.x + ',' + G.y;
50 |
51 | setAttributes(arrow, {
52 | points: points,
53 | stroke: normalizeColor(a.color || '#000'),
54 | fill: normalizeColor(a.color || '#000')
55 | });
56 | }
57 |
58 | return arrow;
59 | }
60 |
--------------------------------------------------------------------------------
/src/render/renderCircle.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 | import normalizeColor from '../utils/normalizeColor';
3 |
4 | /**
5 | * Create an SVGCircleElement from an annotation definition.
6 | * This is used for annotations of type `circle`.
7 | *
8 | * @param {Object} a The annotation definition
9 | * @return {SVGGElement|SVGCircleElement} A circle to be rendered
10 | */
11 | export default function renderCircle(a) {
12 | let circle = createCircle(a);
13 | let color = normalizeColor(a.color || '#f00');
14 |
15 | if (a.type === 'circle') {
16 | setAttributes(circle, {
17 | stroke: color,
18 | fill: 'none',
19 | 'stroke-width': 5
20 | });
21 | }
22 | if (a.type === 'emptycircle') {
23 | setAttributes(circle, {
24 | stroke: color,
25 | fill: 'none',
26 | 'stroke-width': 2
27 | });
28 | }
29 |
30 | if (a.type === 'fillcircle') {
31 | setAttributes(circle, {
32 | stroke: color,
33 | fill: color,
34 | 'stroke-width': 5
35 | });
36 | }
37 |
38 | return circle;
39 | }
40 |
41 | function createCircle(a) {
42 | let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
43 | setAttributes(circle, {
44 | cx: a.cx,
45 | cy: a.cy,
46 | r: a.r
47 | });
48 |
49 | return circle;
50 | }
51 |
--------------------------------------------------------------------------------
/src/render/renderLine.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 | import normalizeColor from '../utils/normalizeColor';
3 |
4 | /**
5 | * Create SVGLineElements from an annotation definition.
6 | * This is used for anntations of type `strikeout`.
7 | *
8 | * @param {Object} a The annotation definition
9 | * @return {SVGGElement} A group of all lines to be rendered
10 | */
11 | export default function renderLine(a) {
12 | let group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
13 | setAttributes(group, {
14 | stroke: normalizeColor(a.color || '#f00'),
15 | strokeWidth: 1
16 | });
17 |
18 | a.rectangles.forEach((r) => {
19 | let line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
20 |
21 | setAttributes(line, {
22 | x1: r.x,
23 | y1: r.y,
24 | x2: r.x + r.width,
25 | y2: r.y
26 | });
27 |
28 | group.appendChild(line);
29 | });
30 |
31 | return group;
32 | }
33 |
--------------------------------------------------------------------------------
/src/render/renderPath.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 | import normalizeColor from '../utils/normalizeColor';
3 |
4 | /**
5 | * Create SVGPathElement from an annotation definition.
6 | * This is used for anntations of type `drawing`.
7 | *
8 | * @param {Object} a The annotation definition
9 | * @return {SVGPathElement} The path to be rendered
10 | */
11 | export default function renderPath(a) {
12 | let d = [];
13 | let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
14 |
15 | if (a.lines.length > 0) {
16 | d.push(`M${a.lines[0][0]} ${a.lines[0][1]}`);
17 | for (let i = 1, l = a.lines.length; i < l; i++) {
18 | let p1 = a.lines[i];
19 | let p2 = a.lines[i + 1];
20 | if (p2) {
21 | d.push(`L${p1[0]} ${p1[1]}`);
22 | }
23 | }
24 | }
25 |
26 | /*
27 |
28 | if(a.lines.length>2) {
29 | var p1 = a.lines[0];
30 | var p2 = a.lines[a.lines.length-1];
31 |
32 | var p3 = []; //arrow
33 | var p4 = [];
34 | var p0 = []; //arrow intersection
35 |
36 | if (p2) {
37 | var k = -(p2[0]-p1[0])/(p2[1]-p1[1]);
38 |
39 | var deltaX = 3;
40 | p0[0] = p1[0]+0.8*(p2[0]-p1[0]);
41 | p0[1] = p1[1]+0.8*(p2[1]-p1[1]);
42 |
43 | p3[0] = p0[0] + deltaX;
44 | p3[1] = p0[1] + k*deltaX;
45 |
46 | p4[0] = p0[0] - deltaX;
47 | p4[1] = p0[1] - k*deltaX;
48 |
49 | if(Math.abs(p2[1]-p1[1]) < 20) {
50 |
51 | p3[0] = p0[0] ;
52 | p3[1] = p0[1] + deltaX*1;
53 |
54 | p4[0] = p0[0] ;
55 | p4[1] = p0[1] - deltaX*1;
56 |
57 | }
58 |
59 | d.push(`M${p1[0]} ${p1[1]} ${p2[0]} ${p2[1]}`);
60 | //d.push(`M${p1[0]} ${p1[1]} ${p2[0]} ${p2[1]}`);
61 | d.push(`M${p2[0]} ${p2[1]} ${p3[0]} ${p3[1]}`);
62 | d.push(`M${p3[0]} ${p3[1]} ${p4[0]} ${p4[1]}`);
63 | d.push(`M${p4[0]} ${p4[1]} ${p2[0]} ${p2[1]}`);
64 | }
65 | } */
66 |
67 | setAttributes(path, {
68 | d: `${d.join(' ')}`, // `${d.join(' ')}Z`,
69 | stroke: normalizeColor(a.color || '#000'),
70 | strokeWidth: a.width || 1,
71 | fill: 'none'
72 | });
73 |
74 | return path;
75 | }
76 |
--------------------------------------------------------------------------------
/src/render/renderPoint.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 |
3 | const SIZE = 25;
4 | const D = 'M499.968 214.336q-113.832 0 -212.877 38.781t-157.356 104.625 -58.311 142.29q0 62.496 39.897 119.133t112.437 97.929l48.546 27.9 -15.066 53.568q-13.392 50.778 -39.06 95.976 84.816 -35.154 153.45 -95.418l23.994 -21.204 31.806 3.348q38.502 4.464 72.54 4.464 113.832 0 212.877 -38.781t157.356 -104.625 58.311 -142.29 -58.311 -142.29 -157.356 -104.625 -212.877 -38.781z';
5 |
6 | /**
7 | * Create SVGElement from an annotation definition.
8 | * This is used for anntations of type `comment`.
9 | *
10 | * @param {Object} a The annotation definition
11 | * @return {SVGElement} A svg to be rendered
12 | */
13 | export default function renderPoint(a) {
14 | let outerSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
15 | let innerSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
16 | let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
17 | let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
18 |
19 | setAttributes(outerSVG, {
20 | width: SIZE,
21 | height: SIZE,
22 | x: a.x,
23 | y: a.y
24 | });
25 |
26 | setAttributes(innerSVG, {
27 | width: SIZE,
28 | height: SIZE,
29 | x: 0,
30 | y: (SIZE * 0.05) * -1,
31 | viewBox: '0 0 1000 1000'
32 | });
33 |
34 | setAttributes(rect, {
35 | width: SIZE,
36 | height: SIZE,
37 | stroke: '#000',
38 | fill: '#ff0'
39 | });
40 |
41 | setAttributes(path, {
42 | d: D,
43 | strokeWidth: 50,
44 | stroke: '#000',
45 | fill: '#fff'
46 | });
47 |
48 | innerSVG.appendChild(path);
49 | outerSVG.appendChild(rect);
50 | outerSVG.appendChild(innerSVG);
51 |
52 | return outerSVG;
53 | }
54 |
--------------------------------------------------------------------------------
/src/render/renderRect.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 | import normalizeColor from '../utils/normalizeColor';
3 |
4 | /**
5 | * Create SVGRectElements from an annotation definition.
6 | * This is used for anntations of type `area` and `highlight`.
7 | *
8 | * @param {Object} a The annotation definition
9 | * @return {SVGGElement|SVGRectElement} A group of all rects to be rendered
10 | */
11 | export default function renderRect(a) {
12 | if (a.type === 'highlight') {
13 | let group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
14 | setAttributes(group, {
15 | fill: normalizeColor(a.color || '#ff0'),
16 | fillOpacity: 0.2
17 | });
18 |
19 | a.rectangles.forEach((r) => {
20 | group.appendChild(createRect(r));
21 | });
22 |
23 | return group;
24 | }
25 | else {
26 | let rect = createRect(a);
27 | setAttributes(rect, {
28 | stroke: normalizeColor(a.color || '#f00'),
29 | fill: 'none'
30 | });
31 |
32 | return rect;
33 | }
34 | }
35 |
36 | function createRect(r) {
37 | let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
38 |
39 | setAttributes(rect, {
40 | x: r.x,
41 | y: r.y,
42 | width: r.width,
43 | height: r.height
44 | });
45 |
46 | return rect;
47 | }
48 |
--------------------------------------------------------------------------------
/src/render/renderText.js:
--------------------------------------------------------------------------------
1 | import setAttributes from '../utils/setAttributes';
2 | import normalizeColor from '../utils/normalizeColor';
3 |
4 | /**
5 | * Create SVGTextElement from an annotation definition.
6 | * This is used for anntations of type `textbox`.
7 | *
8 | * @param {Object} a The annotation definition
9 | * @return {SVGTextElement} A text to be rendered
10 | */
11 | export default function renderText(a) {
12 | // Text should be rendered at 0 degrees relative to
13 | // document rotation
14 | let text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
15 | setAttributes(text, {
16 | x: a.x,
17 | y: a.y,
18 | fill: normalizeColor(a.color || '#000'),
19 | fontSize: a.size,
20 | transform: `rotate(${a.rotation})`,
21 | style: 'white-space: pre'
22 | });
23 | text.innerHTML = a.content;
24 |
25 | let g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
26 | g.appendChild(text);
27 |
28 | return g;
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/abstractFunction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Throw an Error for an abstract function that hasn't been implemented.
3 | *
4 | * @param {String} name The name of the abstract function
5 | */
6 | export default function abstractFunction(name) {
7 | throw new Error(name + ' is not implemented');
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/mathUtils.js:
--------------------------------------------------------------------------------
1 | // Transform point by matrix
2 | //
3 | export function applyTransform(p, m) {
4 | let xt = p[0] * m[0] + p[1] * m[2] + m[4];
5 | let yt = p[0] * m[1] + p[1] * m[3] + m[5];
6 | return [xt, yt];
7 | };
8 |
9 | // Transform point by matrix inverse
10 | //
11 | export function applyInverseTransform(p, m) {
12 | let d = m[0] * m[3] - m[1] * m[2];
13 | let xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
14 | let yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
15 | return [xt, yt];
16 | };
17 |
18 | // Concatenates two transformation matrices together and returns the result.
19 | export function transform(m1, m2) {
20 | return [
21 | m1[0] * m2[0] + m1[2] * m2[1],
22 | m1[1] * m2[0] + m1[3] * m2[1],
23 | m1[0] * m2[2] + m1[2] * m2[3],
24 | m1[1] * m2[2] + m1[3] * m2[3],
25 | m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
26 | m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
27 | ];
28 | };
29 |
30 | export function translate(m, x, y) {
31 | return [
32 | m[0],
33 | m[1],
34 | m[2],
35 | m[3],
36 | m[0] * x + m[2] * y + m[4],
37 | m[1] * x + m[3] * y + m[5]
38 | ];
39 | };
40 |
41 | export function rotate(m, angle) {
42 | angle = angle * Math.PI / 180;
43 |
44 | let cosValue = Math.cos(angle);
45 | let sinValue = Math.sin(angle);
46 |
47 | return [
48 | m[0] * cosValue + m[2] * sinValue,
49 | m[1] * cosValue + m[3] * sinValue,
50 | m[0] * (-sinValue) + m[2] * cosValue,
51 | m[1] * (-sinValue) + m[3] * cosValue,
52 | m[4],
53 | m[5]
54 | ];
55 | };
56 |
57 | export function scale(m, x, y) {
58 | return [
59 | m[0] * x,
60 | m[1] * x,
61 | m[2] * y,
62 | m[3] * y,
63 | m[4],
64 | m[5]
65 | ];
66 | };
67 |
68 | export function makePoint(x, y, z) {
69 | return { x: x, y: y, z: z };
70 | };
71 |
72 | export function makeVector(xcoord, ycoord, zcoord) {
73 | return { xcoord: xcoord, ycoord: ycoord, zcoord: zcoord };
74 | };
75 |
76 | export function makeVectorFromPoints(pt1, pt2) {
77 | let xcoord = pt2.x - pt1.x;
78 | let ycoord = pt2.y - pt1.y;
79 | let zcoord = pt2.z - pt1.z;
80 | return makeVector(xcoord, ycoord, zcoord);
81 | };
82 |
83 | export function addVector(pt, v) {
84 | return makePoint(pt.x + v.xcoord, pt.y + v.ycoord, pt.z + v.zcoord);
85 | };
86 |
87 | export function multiplyVector(v, scalar) {
88 | return makeVector(v.xcoord * scalar, v.ycoord * scalar, v.zcoord * scalar);
89 | };
90 |
91 | export function magnitude(v) {
92 | return Math.sqrt(
93 | Math.pow(v.xcoord, 2) + Math.pow(v.ycoord, 2) + Math.pow(v.zcoord, 2)
94 | );
95 | };
96 |
97 | export function negateVector(v) {
98 | return multiplyVector(v, -1);
99 | };
100 |
101 | export function unitVector(v) {
102 | let mag = magnitude(v);
103 | let xcoord = v.xcoord / mag;
104 | let ycoord = v.ycoord / mag;
105 | let zcoord = v.zcoord / mag;
106 | return makeVector(xcoord, ycoord, zcoord);
107 | };
108 |
109 | export function crossProduct(u, v) {
110 | //
111 | // u X v = < u2*v3 - u3*v2,
112 | // u3*v1 - u1*v3,
113 | // u1*v2 - u2*v1 >
114 | let xcoord = u.ycoord * v.zcoord - u.zcoord * v.ycoord;
115 | let ycoord = u.zcoord * v.xcoord - u.xcoord * v.zcoord;
116 | let zcoord = u.xcoord * v.ycoord - u.ycoord * v.xcoord;
117 | return makeVector(xcoord, ycoord, zcoord);
118 | };
119 |
--------------------------------------------------------------------------------
/src/utils/normalizeColor.js:
--------------------------------------------------------------------------------
1 | const REGEX_HASHLESS_HEX = /^([a-f0-9]{6}|[a-f0-9]{3})$/i;
2 |
3 | /**
4 | * Normalize a color value
5 | *
6 | * @param {String} color The color to normalize
7 | * @return {String}
8 | */
9 | export default function normalizeColor(color) {
10 | if (REGEX_HASHLESS_HEX.test(color)) {
11 | color = `#${color}`;
12 | }
13 | return color;
14 | }
15 |
--------------------------------------------------------------------------------
/src/utils/setAttributes.js:
--------------------------------------------------------------------------------
1 | const UPPER_REGEX = /[A-Z]/g;
2 |
3 | // Don't convert these attributes from camelCase to hyphenated-attributes
4 | const BLACKLIST = [
5 | 'viewBox'
6 | ];
7 |
8 | let keyCase = (key) => {
9 | if (BLACKLIST.indexOf(key) === -1) {
10 | key = key.replace(UPPER_REGEX, match => '-' + match.toLowerCase());
11 | }
12 | return key;
13 | };
14 |
15 | /**
16 | * Set attributes for a node from a map
17 | *
18 | * @param {Node} node The node to set attributes on
19 | * @param {Object} attributes The map of key/value pairs to use for attributes
20 | */
21 | export default function setAttributes(node, attributes) {
22 | Object.keys(attributes).forEach((key) => {
23 | node.setAttribute(keyCase(key), attributes[key]);
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/uuid.js:
--------------------------------------------------------------------------------
1 | const REGEXP = /[xy]/g;
2 | const PATTERN = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
3 |
4 | function replacement(c) {
5 | let r = Math.random() * 16 | 0;
6 | let v = c === 'x' ? r : (r & 0x3 | 0x8);
7 | return v.toString(16);
8 | }
9 |
10 | /**
11 | * Generate a univierally unique identifier
12 | *
13 | * @return {String} A UUID
14 | */
15 | export default function uuid() {
16 | return PATTERN.replace(REGEXP, replacement);
17 | }
18 |
--------------------------------------------------------------------------------