├── .github └── FUNDING.yml ├── img ├── ex1.png ├── ex2.png └── ex3.png ├── examples ├── test.pdf ├── simpler.html ├── mostsimple.html ├── simpledoc.html ├── simpledoctoolbar.html └── example.html ├── notice.min ├── notice ├── css ├── pdfjs-viewer.css └── pdftoolbar.css ├── dist ├── pdfjs-viewer.min.css ├── pdfjs-viewer.css ├── pdfjs-viewer.min.css.map ├── pdfjs-viewer.compress.js ├── pdfjs-viewer.min.js ├── pdfjs-viewer.js ├── pdfjs-viewer.compress.js.map └── pdfjs-viewer.min.js.map ├── Makefile ├── LICENSE ├── README.md └── js └── pdfjs-viewer.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: [ "https://paypal.me/caralla" ] 2 | -------------------------------------------------------------------------------- /img/ex1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dealfonso/pdfjs-viewer/HEAD/img/ex1.png -------------------------------------------------------------------------------- /img/ex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dealfonso/pdfjs-viewer/HEAD/img/ex2.png -------------------------------------------------------------------------------- /img/ex3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dealfonso/pdfjs-viewer/HEAD/img/ex3.png -------------------------------------------------------------------------------- /examples/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dealfonso/pdfjs-viewer/HEAD/examples/test.pdf -------------------------------------------------------------------------------- /notice.min: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 Carlos A. (https://github.com/dealfonso); License: http://www.apache.org/licenses/LICENSE-2.0 */ 2 | -------------------------------------------------------------------------------- /notice: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2021 Carlos A. (https://github.com/dealfonso) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | -------------------------------------------------------------------------------- /examples/simpler.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Simple PDFjs-viewer 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/mostsimple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Simple PDFjs-viewer 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /examples/simpledoc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Single PDFjs-viewer 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 |
19 |
20 |

Example for PDFjs-viewer

21 |

This is a simple document embeded in a div, integrated with bootstrap

22 |
23 |
24 |
25 |
26 | 27 | 44 | 45 | -------------------------------------------------------------------------------- /css/pdfjs-viewer.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Carlos de Alfonso (https://github.com/dealfonso) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | .pdfjs-viewer { 17 | overflow: auto; 18 | border: 1px solid #aaa; 19 | background: #ccc; 20 | /* width: 100%; */ 21 | } 22 | .pdfjs-viewer.horizontal-scroll { 23 | display: flex; 24 | } 25 | .pdfjs-viewer.horizontal-scroll .pdfpage { 26 | margin-left: 1em; 27 | margin-top: 0.25em !important; 28 | margin-bottom: 0.25em !important; 29 | display: block; 30 | } 31 | .pdfpage { 32 | position: relative; 33 | margin-bottom: 1em; 34 | margin-top: 1em; 35 | margin-left: auto; 36 | margin-right: auto; 37 | box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09); 38 | /* display: flex; */ 39 | } 40 | .pdfpage canvas { 41 | position: absolute; 42 | left: 0; 43 | top: 0; 44 | height: 100%; 45 | width: 100%; 46 | } 47 | .pdfpage.placeholder { 48 | display: flex; 49 | margin-bottom: 0em !important; 50 | margin-top: 0em !important; 51 | height: 100%; 52 | width: 100%; 53 | } 54 | .pdfpage .content-wrapper { 55 | margin: 0 !important; 56 | padding: 0 !important; 57 | display: flex !important; 58 | } 59 | .pdfpage .content-wrapper .loader { 60 | border: 2px solid #f3f3f3; 61 | border-top: 3px solid #3498db; 62 | border-radius: 50%; 63 | width: 24px; 64 | height: 24px; 65 | animation: spin 1s linear infinite; 66 | margin: auto; 67 | } 68 | @keyframes spin { 69 | 0% { transform: rotate(0deg); } 70 | 100% { transform: rotate(360deg); } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /dist/pdfjs-viewer.min.css: -------------------------------------------------------------------------------- 1 | .pdfjs-viewer{overflow:auto;border:1px solid #aaa;background:#ccc}.pdfjs-viewer.horizontal-scroll{display:flex}.pdfjs-viewer.horizontal-scroll .pdfpage{margin-left:1em;margin-top:.25em!important;margin-bottom:.25em!important;display:block}.pdfpage{position:relative;margin-bottom:1em;margin-top:1em;margin-left:auto;margin-right:auto;box-shadow:0 4px 8px 0 rgba(0,0,0,.1),0 6px 20px 0 rgba(0,0,0,.09)}.pdfpage canvas{position:absolute;left:0;top:0;height:100%;width:100%}.pdfpage.placeholder{display:flex;margin-bottom:0!important;margin-top:0!important;height:100%;width:100%}.pdfpage .content-wrapper{margin:0!important;padding:0!important;display:flex!important}.pdfpage .content-wrapper .loader{border:2px solid #f3f3f3;border-top:3px solid #3498db;border-radius:50%;width:24px;height:24px;animation:spin 1s linear infinite;margin:auto}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}.pdfjs-toolbar{width:100%;height:32px;background:#ddd;z-index:100;vertical-align:middle;display:flex;margin:0;padding:0}.pdfjs-toolbar *{margin:auto 0}.pdfjs-toolbar span{margin-right:.5em;margin-left:.5em;width:4em!important;font-size:12px}.pdfjs-toolbar a.button,.pdfjs-toolbar button,.pdfjs-toolbar label.button{min-width:26px;height:28px;border:none;padding:2px 4px 0;margin:auto 1px;border-radius:2px;line-height:12px;font-size:14px;background-color:#ddd;cursor:pointer}.pdfjs-toolbar button i,.pdfjs-toolbar label.button i{font-size:26px;padding:0;margin:0}.pdfjs-toolbar a.button:hover,.pdfjs-toolbar button:hover,.pdfjs-toolbar label.button:hover{background-color:#ccc}button.pushed{background-color:#aaa!important}.pdfjs-toolbar a.button{color:inherit}.pdfjs-toolbar .divider{flex:1}.pdfjs-toolbar .v-sep{width:0;height:20px;border-left:1px solid #bbb}.pdfjs-toolbar .h-sep{width:100%;height:0;border-top:1px solid #bbb;margin:.25em 0}.pdfjs-toolbar .dropdown.dropdown-right,.pdfjs-toolbar .dropdown.right{float:right}.pdfjs-toolbar .dropdown.dropdown-right .dropdown-content,.pdfjs-toolbar .dropdown.right .dropdown-content{right:0;left:auto}.pdfjs-toolbar .dropdown-value{background-color:#ccc;padding:0 4px 2;cursor:pointer}.pdfjs-toolbar .dropdown-value i{width:auto;font-size:12px}.pdfjs-toolbar .dropdown-content{display:none;position:absolute;margin-top:0;background-color:#eee;min-width:10em;z-index:1;font-size:12px;box-shadow:0 4px 8px 0 rgba(0,0,0,.1),0 6px 20px 0 rgba(0,0,0,.09)}.pdfjs-toolbar .dropdown-content a{all:initial;font:inherit;color:#000;padding:6px 8px;text-decoration:none;display:flex;cursor:pointer}.pdfjs-toolbar .dropdown-content i{font-size:16px;padding-right:.5em}.pdfjs-toolbar .dropdown-content a:hover{background-color:#ddd}.dropdown .dropdown-content:hover,.pdfjs-toolbar .dropdown:hover .dropdown-content{display:block} 2 | /*# sourceMappingURL=pdfjs-viewer.min.css.map */ -------------------------------------------------------------------------------- /css/pdftoolbar.css: -------------------------------------------------------------------------------- 1 | .pdfjs-toolbar { 2 | width: 100%; 3 | height: 32px; 4 | background: #ddd; 5 | z-index: 100; 6 | vertical-align: middle; 7 | display: flex; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | .pdfjs-toolbar * { 12 | margin: auto 0; 13 | } 14 | .pdfjs-toolbar span { 15 | margin-right: 0.5em; 16 | margin-left: 0.5em; 17 | width: 4em !important; 18 | font-size: 12px; 19 | } 20 | .pdfjs-toolbar button, .pdfjs-toolbar label.button, .pdfjs-toolbar a.button { 21 | min-width: 26px; 22 | height: 28px; 23 | border: none; 24 | padding: 2px 4px 0; 25 | margin: auto 1px; 26 | border-radius: 2px; 27 | line-height: 12px; 28 | font-size: 14px; 29 | background-color: #ddd; 30 | cursor: pointer; 31 | } 32 | .pdfjs-toolbar button i, .pdfjs-toolbar label.button i { 33 | font-size: 26px; 34 | padding: 0; 35 | margin: 0; 36 | } 37 | .pdfjs-toolbar button:hover, .pdfjs-toolbar label.button:hover, .pdfjs-toolbar a.button:hover { 38 | background-color: #ccc; 39 | } 40 | button.pushed { 41 | background-color: #aaa !important; 42 | } 43 | .pdfjs-toolbar a.button { 44 | color: inherit; 45 | } 46 | .pdfjs-toolbar .divider { 47 | flex: 1; 48 | } 49 | .pdfjs-toolbar .v-sep { 50 | width: 0px; 51 | height: 20px; 52 | border-left: 1px solid #bbb; 53 | } 54 | .pdfjs-toolbar .h-sep { 55 | width: 100%; 56 | height: 0px; 57 | border-top: 1px solid #bbb; 58 | margin: 0.25em 0; 59 | } 60 | .pdfjs-toolbar .dropdown.dropdown-right, .pdfjs-toolbar .dropdown.right { 61 | float: right 62 | } 63 | .pdfjs-toolbar .dropdown.dropdown-right .dropdown-content, .pdfjs-toolbar .dropdown.right .dropdown-content { 64 | right: 0; 65 | left: auto; 66 | } 67 | .pdfjs-toolbar .dropdown-value { 68 | background-color: #ccc; 69 | padding: 0px 4px 2; 70 | cursor: pointer; 71 | } 72 | .pdfjs-toolbar .dropdown-value i { 73 | width: auto; 74 | font-size: 12px; 75 | } 76 | /* Dropdown Content (Hidden by Default) */ 77 | .pdfjs-toolbar .dropdown-content { 78 | display: none; 79 | position: absolute; 80 | margin-top: 0; 81 | background-color: #eee; 82 | min-width: 10em; 83 | z-index: 1; 84 | font-size: 12px; 85 | box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09); 86 | } 87 | /* Links inside the dropdown */ 88 | .pdfjs-toolbar .dropdown-content a { 89 | all: initial; 90 | font: inherit; 91 | color: black; 92 | padding: 6px 8px; 93 | text-decoration: none; 94 | display: flex; 95 | cursor: pointer; 96 | } 97 | .pdfjs-toolbar .dropdown-content i { 98 | font-size: 16px; 99 | padding-right: 0.5em; 100 | } 101 | .pdfjs-toolbar .dropdown-content a:hover { 102 | background-color: #ddd; 103 | } 104 | .pdfjs-toolbar .dropdown:hover .dropdown-content, .dropdown .dropdown-content:hover { 105 | display: block; 106 | } -------------------------------------------------------------------------------- /examples/simpledoctoolbar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Single PDFjs-viewer 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 38 | 39 | 40 |
41 |
42 |

Example for PDFjs-viewer

43 |

This is a simple document embeded in a div (integrated with bootstrap)

44 |
45 |
46 |
47 |
48 | 49 | 50 | 51 | 52 | 53 |
54 |
55 | 56 | 100% 57 | 58 | 59 | 60 | 61 |
62 |
63 |
64 |
65 |
66 |
67 | 68 | 75 | -------------------------------------------------------------------------------- /dist/pdfjs-viewer.css: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2021 Carlos A. (https://github.com/dealfonso) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | .pdfjs-viewer { 18 | overflow: auto; 19 | border: 1px solid #aaa; 20 | background: #ccc 21 | } 22 | .pdfjs-viewer.horizontal-scroll { 23 | display: flex 24 | } 25 | .pdfjs-viewer.horizontal-scroll .pdfpage { 26 | margin-left: 1em; 27 | margin-top: .25em!important; 28 | margin-bottom: .25em!important; 29 | display: block 30 | } 31 | .pdfpage { 32 | position: relative; 33 | margin-bottom: 1em; 34 | margin-top: 1em; 35 | margin-left: auto; 36 | margin-right: auto; 37 | box-shadow: 0 4px 8px 0 rgba(0,0,0,.1),0 6px 20px 0 rgba(0,0,0,.09) 38 | } 39 | .pdfpage canvas { 40 | position: absolute; 41 | left: 0; 42 | top: 0; 43 | height: 100%; 44 | width: 100% 45 | } 46 | .pdfpage.placeholder { 47 | display: flex; 48 | margin-bottom: 0!important; 49 | margin-top: 0!important; 50 | height: 100%; 51 | width: 100% 52 | } 53 | .pdfpage .content-wrapper { 54 | margin: 0!important; 55 | padding: 0!important; 56 | display: flex!important 57 | } 58 | .pdfpage .content-wrapper .loader { 59 | border: 2px solid #f3f3f3; 60 | border-top: 3px solid #3498db; 61 | border-radius: 50%; 62 | width: 24px; 63 | height: 24px; 64 | animation: spin 1s linear infinite; 65 | margin: auto 66 | } 67 | @keyframes spin { 68 | 0% { 69 | transform: rotate(0) 70 | } 71 | 100% { 72 | transform: rotate(360deg) 73 | } 74 | } 75 | .pdfjs-toolbar { 76 | width: 100%; 77 | height: 32px; 78 | background: #ddd; 79 | z-index: 100; 80 | vertical-align: middle; 81 | display: flex; 82 | margin: 0; 83 | padding: 0 84 | } 85 | .pdfjs-toolbar * { 86 | margin: auto 0 87 | } 88 | .pdfjs-toolbar span { 89 | margin-right: .5em; 90 | margin-left: .5em; 91 | width: 4em!important; 92 | font-size: 12px 93 | } 94 | .pdfjs-toolbar a.button, 95 | .pdfjs-toolbar button, 96 | .pdfjs-toolbar label.button { 97 | min-width: 26px; 98 | height: 28px; 99 | border: none; 100 | padding: 2px 4px 0; 101 | margin: auto 1px; 102 | border-radius: 2px; 103 | line-height: 12px; 104 | font-size: 14px; 105 | background-color: #ddd; 106 | cursor: pointer 107 | } 108 | .pdfjs-toolbar button i, 109 | .pdfjs-toolbar label.button i { 110 | font-size: 26px; 111 | padding: 0; 112 | margin: 0 113 | } 114 | .pdfjs-toolbar a.button:hover, 115 | .pdfjs-toolbar button:hover, 116 | .pdfjs-toolbar label.button:hover { 117 | background-color: #ccc 118 | } 119 | button.pushed { 120 | background-color: #aaa!important 121 | } 122 | .pdfjs-toolbar a.button { 123 | color: inherit 124 | } 125 | .pdfjs-toolbar .divider { 126 | flex: 1 127 | } 128 | .pdfjs-toolbar .v-sep { 129 | width: 0; 130 | height: 20px; 131 | border-left: 1px solid #bbb 132 | } 133 | .pdfjs-toolbar .h-sep { 134 | width: 100%; 135 | height: 0; 136 | border-top: 1px solid #bbb; 137 | margin: .25em 0 138 | } 139 | .pdfjs-toolbar .dropdown.dropdown-right, 140 | .pdfjs-toolbar .dropdown.right { 141 | float: right 142 | } 143 | .pdfjs-toolbar .dropdown.dropdown-right .dropdown-content, 144 | .pdfjs-toolbar .dropdown.right .dropdown-content { 145 | right: 0; 146 | left: auto 147 | } 148 | .pdfjs-toolbar .dropdown-value { 149 | background-color: #ccc; 150 | padding: 0 4px 2; 151 | cursor: pointer 152 | } 153 | .pdfjs-toolbar .dropdown-value i { 154 | width: auto; 155 | font-size: 12px 156 | } 157 | .pdfjs-toolbar .dropdown-content { 158 | display: none; 159 | position: absolute; 160 | margin-top: 0; 161 | background-color: #eee; 162 | min-width: 10em; 163 | z-index: 1; 164 | font-size: 12px; 165 | box-shadow: 0 4px 8px 0 rgba(0,0,0,.1),0 6px 20px 0 rgba(0,0,0,.09) 166 | } 167 | .pdfjs-toolbar .dropdown-content a { 168 | all: initial; 169 | font: inherit; 170 | color: #000; 171 | padding: 6px 8px; 172 | text-decoration: none; 173 | display: flex; 174 | cursor: pointer 175 | } 176 | .pdfjs-toolbar .dropdown-content i { 177 | font-size: 16px; 178 | padding-right: .5em 179 | } 180 | .pdfjs-toolbar .dropdown-content a:hover { 181 | background-color: #ddd 182 | } 183 | .dropdown .dropdown-content:hover, 184 | .pdfjs-toolbar .dropdown:hover .dropdown-content { 185 | display: block 186 | } -------------------------------------------------------------------------------- /dist/pdfjs-viewer.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["dist/pdfjs-viewer.css"],"names":[],"mappings":"AAgBA,cACE,SAAU,KACV,OAAQ,IAAI,MAAM,KAClB,WAAY,KAEd,gCACE,QAAS,KAEX,yCACE,YAAa,IACb,WAAY,gBACZ,cAAe,gBACf,QAAS,MAEX,SACE,SAAU,SACV,cAAe,IACf,WAAY,IACZ,YAAa,KACb,aAAc,KACd,WAAY,EAAE,IAAI,IAAI,EAAE,cAAc,CAAC,EAAE,IAAI,KAAK,EAAE,gBAEtD,gBACE,SAAU,SACV,KAAM,EACN,IAAK,EACL,OAAQ,KACR,MAAO,KAET,qBACE,QAAS,KACT,cAAe,YACf,WAAY,YACZ,OAAQ,KACR,MAAO,KAET,0BACE,OAAQ,YACR,QAAS,YACT,QAAS,eAEX,kCACE,OAAQ,IAAI,MAAM,QAClB,WAAY,IAAI,MAAM,QACtB,cAAe,IACf,MAAO,KACP,OAAQ,KACR,UAAW,KAAK,GAAG,OAAO,SAC1B,OAAQ,KAEV,gBACE,GACE,UAAW,UAEb,KACE,UAAW,gBAGf,eACE,MAAO,KACP,OAAQ,KACR,WAAY,KACZ,QAAS,IACT,eAAgB,OAChB,QAAS,KACT,OAAQ,EACR,QAAS,EAEX,iBACE,OAAQ,KAAK,EAEf,oBACE,aAAc,KACd,YAAa,KACb,MAAO,cACP,UAAW,KAEb,wBACA,sBACA,4BACE,UAAW,KACX,OAAQ,KACR,OAAQ,KACR,QAAS,IAAI,IAAI,EACjB,OAAQ,KAAK,IACb,cAAe,IACf,YAAa,KACb,UAAW,KACX,iBAAkB,KAClB,OAAQ,QAEV,wBACA,8BACE,UAAW,KACX,QAAS,EACT,OAAQ,EAEV,8BACA,4BACA,kCACE,iBAAkB,KAEpB,cACE,iBAAkB,eAEpB,wBACE,MAAO,QAET,wBACE,KAAM,EAER,sBACE,MAAO,EACP,OAAQ,KACR,YAAa,IAAI,MAAM,KAEzB,sBACE,MAAO,KACP,OAAQ,EACR,WAAY,IAAI,MAAM,KACtB,OAAQ,MAAM,EAEhB,wCACA,+BACE,MAAO,MAET,0DACA,iDACE,MAAO,EACP,KAAM,KAER,+BACE,iBAAkB,KAClB,QAAS,EAAE,IAAI,EACf,OAAQ,QAEV,iCACE,MAAO,KACP,UAAW,KAEb,iCACE,QAAS,KACT,SAAU,SACV,WAAY,EACZ,iBAAkB,KAClB,UAAW,KACX,QAAS,EACT,UAAW,KACX,WAAY,EAAE,IAAI,IAAI,EAAE,cAAc,CAAC,EAAE,IAAI,KAAK,EAAE,gBAEtD,mCACE,IAAK,QACL,KAAM,QACN,MAAO,KACP,QAAS,IAAI,IACb,gBAAiB,KACjB,QAAS,KACT,OAAQ,QAEV,mCACE,UAAW,KACX,cAAe,KAEjB,yCACE,iBAAkB,KAEpB,kCACA,iDACE,QAAS","sourcesContent":["/**\n Copyright 2021 Carlos A. (https://github.com/dealfonso)\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n.pdfjs-viewer {\n overflow: auto;\n border: 1px solid #aaa;\n background: #ccc\n}\n.pdfjs-viewer.horizontal-scroll {\n display: flex\n}\n.pdfjs-viewer.horizontal-scroll .pdfpage {\n margin-left: 1em;\n margin-top: .25em!important;\n margin-bottom: .25em!important;\n display: block\n}\n.pdfpage {\n position: relative;\n margin-bottom: 1em;\n margin-top: 1em;\n margin-left: auto;\n margin-right: auto;\n box-shadow: 0 4px 8px 0 rgba(0,0,0,.1),0 6px 20px 0 rgba(0,0,0,.09)\n}\n.pdfpage canvas {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n width: 100%\n}\n.pdfpage.placeholder {\n display: flex;\n margin-bottom: 0!important;\n margin-top: 0!important;\n height: 100%;\n width: 100%\n}\n.pdfpage .content-wrapper {\n margin: 0!important;\n padding: 0!important;\n display: flex!important\n}\n.pdfpage .content-wrapper .loader {\n border: 2px solid #f3f3f3;\n border-top: 3px solid #3498db;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n animation: spin 1s linear infinite;\n margin: auto\n}\n@keyframes spin {\n 0% {\n transform: rotate(0)\n }\n 100% {\n transform: rotate(360deg)\n }\n}\n.pdfjs-toolbar {\n width: 100%;\n height: 32px;\n background: #ddd;\n z-index: 100;\n vertical-align: middle;\n display: flex;\n margin: 0;\n padding: 0\n}\n.pdfjs-toolbar * {\n margin: auto 0\n}\n.pdfjs-toolbar span {\n margin-right: .5em;\n margin-left: .5em;\n width: 4em!important;\n font-size: 12px\n}\n.pdfjs-toolbar a.button,\n.pdfjs-toolbar button,\n.pdfjs-toolbar label.button {\n min-width: 26px;\n height: 28px;\n border: none;\n padding: 2px 4px 0;\n margin: auto 1px;\n border-radius: 2px;\n line-height: 12px;\n font-size: 14px;\n background-color: #ddd;\n cursor: pointer\n}\n.pdfjs-toolbar button i,\n.pdfjs-toolbar label.button i {\n font-size: 26px;\n padding: 0;\n margin: 0\n}\n.pdfjs-toolbar a.button:hover,\n.pdfjs-toolbar button:hover,\n.pdfjs-toolbar label.button:hover {\n background-color: #ccc\n}\nbutton.pushed {\n background-color: #aaa!important\n}\n.pdfjs-toolbar a.button {\n color: inherit\n}\n.pdfjs-toolbar .divider {\n flex: 1\n}\n.pdfjs-toolbar .v-sep {\n width: 0;\n height: 20px;\n border-left: 1px solid #bbb\n}\n.pdfjs-toolbar .h-sep {\n width: 100%;\n height: 0;\n border-top: 1px solid #bbb;\n margin: .25em 0\n}\n.pdfjs-toolbar .dropdown.dropdown-right,\n.pdfjs-toolbar .dropdown.right {\n float: right\n}\n.pdfjs-toolbar .dropdown.dropdown-right .dropdown-content,\n.pdfjs-toolbar .dropdown.right .dropdown-content {\n right: 0;\n left: auto\n}\n.pdfjs-toolbar .dropdown-value {\n background-color: #ccc;\n padding: 0 4px 2;\n cursor: pointer\n}\n.pdfjs-toolbar .dropdown-value i {\n width: auto;\n font-size: 12px\n}\n.pdfjs-toolbar .dropdown-content {\n display: none;\n position: absolute;\n margin-top: 0;\n background-color: #eee;\n min-width: 10em;\n z-index: 1;\n font-size: 12px;\n box-shadow: 0 4px 8px 0 rgba(0,0,0,.1),0 6px 20px 0 rgba(0,0,0,.09)\n}\n.pdfjs-toolbar .dropdown-content a {\n all: initial;\n font: inherit;\n color: #000;\n padding: 6px 8px;\n text-decoration: none;\n display: flex;\n cursor: pointer\n}\n.pdfjs-toolbar .dropdown-content i {\n font-size: 16px;\n padding-right: .5em\n}\n.pdfjs-toolbar .dropdown-content a:hover {\n background-color: #ddd\n}\n.dropdown .dropdown-content:hover,\n.pdfjs-toolbar .dropdown:hover .dropdown-content {\n display: block\n}"]} -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Name of the library (if not specified, the name of the current folder will be used) 2 | LIBRARY_NAME = pdfjs-viewer 3 | # The files that compose your library (if not specified, all the .js files in the src folder will be used) 4 | FILES = js/pdfjs-viewer.js 5 | # The css files that accompany your library (if not specified, no css files will be used) 6 | CSSFILES = css/pdfjs-viewer.css css/pdftoolbar.css 7 | # Folder in which the build files will be located (if not specified, the folder "dist" will be used) 8 | DIST_FOLDER = 9 | # Dependencies of your library (if not specified, no dependencies will be used) 10 | DEPENDS = 11 | # Folder in which the dependencies are located 12 | DEPENDS_FOLDER = ./depends 13 | # Files to include before the source files (it is a js file that will be included before the source files) 14 | # * In most cases, this is not needed, but it is useful for libraries that need to be initialized 15 | PRE = 16 | # Files to include after the source files 17 | # * In most cases, this is not needed, but it is useful for libraries that need an epilogue 18 | POST = 19 | # The variable to use to export the library (if empty, the makefile will not add any enclosure; it is assumed that the library is already enclosed) 20 | ENCLOSURE = 21 | # The minified license to include in the minified version (if the content of the variable is an existing file, otherwise will use the variable as the license) 22 | LICENSE_MIN = notice.min 23 | 24 | ##################################################################################### 25 | # Handle with care from here 26 | ##################################################################################### 27 | 28 | # Get the current folder name 29 | current_dir = $(notdir $(shell pwd)) 30 | # If LIBRARY_NAME is not specified, use the current folder name 31 | LIBRARY_NAME := $(if $(LIBRARY_NAME),$(LIBRARY_NAME),$(current_dir)) 32 | # Folder in which the build files will be located 33 | DIST_FOLDER := $(if $(DIST_FOLDER),$(DIST_FOLDER),dist) 34 | # The name of the build files 35 | FILEPATH = $(DIST_FOLDER)/$(LIBRARY_NAME) 36 | FILENAME := $(notdir $(FILEPATH)) 37 | 38 | # If the LICENSE_MIN is a single filename and it exists, use the content of the file as the license for the minified version. Otherwise, use the variable as the license 39 | LICENSE_MIN := $(shell test $(words $(LICENSE_MIN)) -eq 1 && test -f $(LICENSE_MIN) && cat $(LICENSE_MIN) || echo $(LICENSE_MIN)) 40 | 41 | # The enclosure parameter 42 | ENCLOSURE := $(if $(ENCLOSURE),-e $(ENCLOSURE),) 43 | 44 | # Files of the dependencies to include in the build 45 | DEP_FILES = $(foreach fd, $(DEPENDS), $(DEPENDS_FOLDER)/$(fd)/dist/$(fd).module.js) 46 | 47 | # The version of this library (this is intended to track the version of this template) 48 | MAKEFILE_VERSION = 1.3.1 49 | 50 | # The result files 51 | RESULT_FILES_CSS = $(if $(CSSFILES),$(FILEPATH).css $(FILEPATH).min.css) 52 | RESULT_FILES_JS = $(FILEPATH).full.js $(FILEPATH).min.js $(FILEPATH).js $(FILEPATH).compress.js $(FILEPATH).module.js $(FILEPATH).min.js.map $(FILEPATH).compress.js.map 53 | RESULT_FILES = $(RESULT_FILES_JS) $(RESULT_FILES_CSS) 54 | 55 | INTERMEDIATE_FILES_JS = $(FILEPATH).raw.js 56 | INTERMEDIATE_FILES_CSS = $(if $(CSSFILES),$(FILEPATH).raw.css) 57 | INTERMEDIATE_FILES = $(INTERMEDIATE_FILES_JS) $(INTERMEDIATE_FILES_CSS) 58 | 59 | INPUT_FILES = $(DEP_FILES) 60 | 61 | all: $(RESULT_FILES) 62 | 63 | js: $(RESULT_FILES_JS) 64 | 65 | css: $(RESULT_FILES_CSS) 66 | 67 | module: $(FILEPATH).module.js 68 | 69 | clean: 70 | rm -f $(RESULT_FILES) $(INTERMEDIATE_FILES) 71 | if [ $(DIST_FOLDER) != "." ] && [ -d $(DIST_FOLDER) ] && [ -z "$(ls -A $(DIST_FOLDER))" ]; then rm -r $(DIST_FOLDER); fi 72 | 73 | cleanall: clean 74 | for fd in $(DEPENDS); do $(MAKE) -C $(DEPENDS_FOLDER)/$$fd clean; done 75 | 76 | depends: $(DEP_FILES) 77 | 78 | $(FILEPATH).full.js: $(FILEPATH).raw.js 79 | @mkdir -p $(DIST_FOLDER) 80 | cat $(FILEPATH).raw.js | uglifyjs $(ENCLOSURE) | js-beautify -t -s 1 -m 1 -j -n | cat notice - > $(FILEPATH).full.js 81 | 82 | $(FILEPATH).js: $(FILEPATH).raw.js 83 | @mkdir -p $(DIST_FOLDER) 84 | cat $(FILEPATH).raw.js | uglifyjs $(ENCLOSURE) -b | js-beautify -t -s 1 -m 1 -j -n | cat notice - > $(FILEPATH).js 85 | 86 | $(FILEPATH).min.js: $(FILEPATH).js 87 | @mkdir -p $(DIST_FOLDER) 88 | echo "$(LICENSE_MIN)" 89 | cd $(DIST_FOLDER) && uglifyjs $(FILENAME).js --beautify beautify=false,preamble='"$(LICENSE_MIN)"' --toplevel --module -m --source-map "filename='$(FILENAME).min.js.map',includeSources=true" -o $(FILENAME).min.js 90 | 91 | $(FILEPATH).compress.js: $(FILEPATH).js 92 | @mkdir -p $(DIST_FOLDER) 93 | cd $(DIST_FOLDER) && uglifyjs $(FILENAME).js --beautify beautify=false,preamble='"$(LICENSE_MIN)"' --compress passes=3,dead_code=true,toplevel=true --toplevel --module -m --source-map "filename='$(FILENAME).compress.js.map',includeSources=true" -o $(FILENAME).compress.js 94 | 95 | $(FILEPATH).module.js: $(FILEPATH).raw.js 96 | @mkdir -p $(DIST_FOLDER) 97 | ( cat notice; echo 'if (typeof imports === "undefined") { var imports = {}; }' ; cat $(FILEPATH).raw.js | uglifyjs $(ENCLOSURE) | js-beautify -t -s 1 -m 1 -j -n ) > $(FILEPATH).module.js 98 | 99 | $(FILEPATH).css: $(FILEPATH).raw.css 100 | @mkdir -p $(DIST_FOLDER) 101 | cleancss $(FILEPATH).raw.css --format beautify | cat notice - > $(FILEPATH).css 102 | 103 | $(FILEPATH).min.css: $(FILEPATH).css 104 | @mkdir -p $(DIST_FOLDER) 105 | cleancss --source-map $(FILEPATH).css --source-map-inline-sources -o $(FILEPATH).min.css 106 | 107 | %.module.js: 108 | $(MAKE) -C $(dir $(@D)) module 109 | 110 | %.raw.js: $(FILES) $(PRE) $(POST) $(DEP_FILES) 111 | @mkdir -p $(DIST_FOLDER) 112 | cat $(DEP_FILES) $(PRE) $(FILES) $(POST) > $(FILEPATH).raw.js 113 | 114 | %.raw.css: $(CSSFILES) 115 | @mkdir -p $(DIST_FOLDER) 116 | cat $(CSSFILES) > $(FILEPATH).raw.css 117 | 118 | ################################################################################ 119 | # CHANGELOG 120 | ################################################################################ 121 | # 122 | # 1.4.0 123 | # * Remove the intermediate files when cleaning 124 | # * Prevent trying to remove folder . if it is the dist folder 125 | # * Add CSS files 126 | # 127 | # ---------------------------------------------------------------- 128 | # 129 | # 1.3.0 130 | # * Enable to specify the license for the minified version by using a file or a text string 131 | # * Add the ENCLOSURE variable to specify the enclosure of the library. If not specified, the library is assumed to be enclosed. 132 | # The most common value is "exports:window" to export the library to the window object. 133 | # 134 | # ---------------------------------------------------------------- 135 | # 136 | # 1.2.0 137 | # * Add different variables for FILENAME and FILEPATH to avoid problems with the path 138 | # * Change the creation of the raw file to use the dependencies as a prerequisite and create a true raw file 139 | # * Add the creation of map source files for the minified and compressed versions 140 | # 141 | # ---------------------------------------------------------------- 142 | # 143 | # 1.1.0 144 | # * Reorder the parameters of the Makefile. 145 | # * Add targets to build the files by their name so that "make" checks if the 146 | # files are up to date, to avoid rebuilding if not needed. 147 | # 148 | # ---------------------------------------------------------------- 149 | # 1.0.0 150 | # * Initial version 151 | # 152 | -------------------------------------------------------------------------------- /dist/pdfjs-viewer.compress.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 Carlos A. (https://github.com/dealfonso); License: http://www.apache.org/licenses/LICENSE-2.0 */ 2 | !function(exports,$){if(void 0===$)console.error("jQuery-like library not available");else{let defaults={visibleThreshold:.5,extraPagesToLoad:3,pageClass:"pdfpage",contentClass:"content-wrapper",onDocumentReady:()=>{},onNewPage:(t,e)=>{},onPageRender:(t,e)=>{},zoomValues:[.25,.5,.75,1,1.25,1.5,2,4,8],onZoomChange:t=>{},onActivePageChanged:(t,e)=>{},zoomFillArea:.95,emptyContent:()=>$('
'),renderingScale:1.5};class Zoomer{constructor(t,e={}){this.current=1,this.viewer=t,this.settings=Object.assign({},{zoomValues:[.25,.5,.75,1,1.25,1.5,2,4,8],fillArea:.9},e),this.settings.zoomValues=this.settings.zoomValues.sort()}get(e=null){if(null===e)return this.current;if(parseFloat(e)!=e){var i=this.viewer.getActivePage();let t=[];switch(e){case"in":e=this.current,0<(t=this.settings.zoomValues.filter(t=>et.2*e.clientHeight*this._zoom.current||Math.abs(e.scrollLeft-s.left)>.2*e.clientWidth*this._zoom.current)&&(s={top:e.scrollTop,left:e.scrollLeft},this._visiblePages()),i=!1)}.bind(this),this.$container.off("scroll"),this.$container.on("scroll",this.__scrollHandler)}_createSkeleton(t,e){var i={$div:null,width:0,height:0,loaded:!1},s=(void 0!==t.getViewport?(s=t.getViewport({rotation:this._rotation,scale:1}),i.width=s.width,i.height=s.height,i.loaded=!0):(i.width=t.width,i.height=t.height),console.assert(0`).attr("data-page",e).data("width",i.width).data("height",i.height).data("zoom",this._zoom.current).addClass(this.settings.pageClass).width(i.width*this._zoom.current).height(i.height*this._zoom.current),$(`
`).width(i.width).height(i.height));return i.$div.append(s),this._cleanPage(i.$div),i}_placeSkeleton(t,e){let i=e-1,s=null;for(;0this.pdf.numPages)return!1;let e=t="string"==typeof t?parseInt(t):t;if("number"==typeof t){if(void 0===this.pages[t])return!1;e=this.pages[t].$div}return this._areaOfPageVisible(e)>e.outerWidth()*e.outerHeight()*this.settings.visibleThreshold}_visiblePages(i=!1){let s=0,a=null;if(0===this.pages.length)this._visibles=[],this._setActivePage(0);else{var n=this.pages.filter(function(t){var e=this._areaOfPageVisible(t.$div);return e>s&&(s=e,a=t.$div.data("page")),0t.$div);this._setActivePage(a);let e=n.map(t=>parseInt($(t).data("page")));if(0");var s=o.get(0),h=s.getContext("2d");return s.height=n.height*a,s.width=n.width*a,s.getContext("2d"),t.render({canvasContext:h,viewport:n,transform:1!==a?[a,0,0,a,0,0]:null}).promise.then(function(){return this._setPageContent(i.$div,o),this._documentReady&&("function"==typeof this.settings.onPageRender&&this.settings.onPageRender.call(this,i.$div.get(0),e),this.$container.get(0).dispatchEvent(new CustomEvent("pagerender",{detail:{pageNumber:e,page:i.$div.get(0)}}))),i}.bind(this))}getActivePage(){return null===this._activePage||null===this.pdf||this._activePage<1||this._activePage>this.pdf.numPages?null:this.pages[this._activePage].$div}getPages(){return this.pages}getPageCount(){return null===this.pdf?0:this.pdf.numPages}next(){this._activePaget.replace(/[A-Z]/g,t=>"-"+t.toLowerCase());let $target=$(target),result={};if(0<$target.length)for(var originalAttributeName in $target=$($target[0]),attributeDefaults){let attributeName=camelcaseToSnakecase(originalAttributeName),attributeValue=$target.attr(attributeName);if(null!=attributeValue){switch(typeof attributeDefaults[originalAttributeName]){case"float":try{attributeValue=parseFloat(attributeValue)}catch(_){}break;case"number":try{attributeValue=parseInt(attributeValue)}catch(_){}break;case"function":let functionString=attributeValue;attributeValue=function(){eval(functionString)}.bind(target[0])}result[originalAttributeName]=attributeValue}}return result}function init(e){let i=recoverAttributes(e,Object.assign({pdfDocument:"",initialZoom:""},defaults));if(null!=i.pdfDocument){let t=new PDFjsViewer($(e),i);t.loadDocument(i.pdfDocument).then(function(){null!=i.initialZoom&&t.setZoom(i.initialZoom)}),e.get(0).pdfViewer=t}}$(function(){$(".pdfjs-viewer").each(function(){init($(this))})}),exports.PDFjsViewer=PDFjsViewer}}(window,window._$??window.jQuery??void 0); -------------------------------------------------------------------------------- /dist/pdfjs-viewer.min.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 Carlos A. (https://github.com/dealfonso); License: http://www.apache.org/licenses/LICENSE-2.0 */ 2 | (function(exports,$){"use strict";if($===undefined){console.error("jQuery-like library not available");return}let defaults={visibleThreshold:.5,extraPagesToLoad:3,pageClass:"pdfpage",contentClass:"content-wrapper",onDocumentReady:()=>{},onNewPage:(t,e)=>{},onPageRender:(t,e)=>{},zoomValues:[.25,.5,.75,1,1.25,1.5,2,4,8],onZoomChange:t=>{},onActivePageChanged:(t,e)=>{},zoomFillArea:.95,emptyContent:()=>$('
'),renderingScale:1.5};class Zoomer{constructor(t,e={}){let i={zoomValues:[.25,.5,.75,1,1.25,1.5,2,4,8],fillArea:.9};this.current=1;this.viewer=t;this.settings=Object.assign({},i,e);this.settings.zoomValues=this.settings.zoomValues.sort()}get(e=null){if(e===null){return this.current}if(parseFloat(e)==e){return e}let t=this.viewer.getActivePage();let i=[];switch(e){case"in":e=this.current;i=this.settings.zoomValues.filter(t=>t>e);if(i.length>0){e=Math.min(...i)}break;case"out":e=this.current;i=this.settings.zoomValues.filter(t=>t0){e=Math.max(...i)}break;case"fit":e=Math.min(this.get("width"),this.get("height"));break;case"width":e=this.settings.fillArea*this.viewer.$container.width()/t.data("width");break;case"height":e=this.settings.fillArea*this.viewer.$container.height()/t.data("height");break;default:e=this.current;break}return e}zoomPages(n){n=this.get(n);this.viewer.getPages().forEach(function(t){let e=t.$div;let i=e.data("width");let s=e.data("height");e.width(i*n).height(s*n);e.data("zoom",n);e.find(`.${this.viewer.settings.contentClass}`).width(i*n).height(s*n)}.bind(this));this.current=n}}class PDFjsViewer{version="2.0.0";constructor(t,e={}){this.settings=Object.assign({},defaults,e);this._zoom=new Zoomer(this,{zoomValues:this.settings.zoomValues,fillArea:this.settings.zoomFillArea});t=$(t);this.$container=t;t.get(0)._pdfjsViewer=this;this._setScrollListener();this.pages=[];this.pdf=null;this._documentReady=false}setZoom(t){let e=this.$container.get(0);let i=this._zoom.current;let s={top:e.scrollTop,left:e.scrollLeft};this._zoom.zoomPages(t);e.scrollLeft=s.left*this._zoom.current/i;e.scrollTop=s.top*this._zoom.current/i;this._visiblePages(true);if(this._documentReady){if(typeof this.settings.onZoomChange==="function")this.settings.onZoomChange.call(this,this._zoom.current);this.$container.get(0).dispatchEvent(new CustomEvent("zoomchange",{detail:{zoom:this._zoom.current}}))}return this._zoom.current}getZoom(){return this._zoom.current}_cleanPage(t){let e=this.settings.emptyContent();t.find(`.${this.settings.contentClass}`).html("").append(e)}_setPageContent(t,e){t.find(`.${this.settings.contentClass}`).html("").append(e)}refreshAll(){this._visiblePages(true)}_setScrollListener(){let i=false;let s={top:0,left:0};this.__scrollHandler=function(t){if(i===true){return}i=true;let e=this.$container.get(0);if(Math.abs(e.scrollTop-s.top)>e.clientHeight*.2*this._zoom.current||Math.abs(e.scrollLeft-s.left)>e.clientWidth*.2*this._zoom.current){s={top:e.scrollTop,left:e.scrollLeft};this._visiblePages()}i=false}.bind(this);this.$container.off("scroll");this.$container.on("scroll",this.__scrollHandler)}_createSkeleton(e,t){let i={$div:null,width:0,height:0,loaded:false};if(e.getViewport!==undefined){let t=e.getViewport({rotation:this._rotation,scale:1});i.width=t.width;i.height=t.height;i.loaded=true}else{i.width=e.width;i.height=e.height}console.assert(i.width>0&&i.height>0,"Page width and height must be greater than 0");i.$div=$(`
`).attr("data-page",t).data("width",i.width).data("height",i.height).data("zoom",this._zoom.current).addClass(this.settings.pageClass).width(i.width*this._zoom.current).height(i.height*this._zoom.current);let s=$(`
`).width(i.width).height(i.height);i.$div.append(s);this._cleanPage(i.$div);return i}_placeSkeleton(t,e){let i=e-1;let s=null;while(i>0&&(s=this.$container.find(`.${this.settings.pageClass}[data-page="${i}"]`)).length===0){i--}if(i===0){this.$container.append(t.$div)}else{s.after(t.$div)}}_createSkeletons(e){for(let t=1;t<=this.pageCount;t++){if(this.pages[t]===undefined){e=this._createSkeleton(e,t);this.pages[t]=e;this._placeSkeleton(e,t);if(typeof this.settings.onNewPage==="function"){this.settings.onNewPage.call(this,e.$div.get(0),t)}this.$container.get(0).dispatchEvent(new CustomEvent("newpage",{detail:{pageNumber:t,page:e.$div.get(0)}}))}}}_setActivePage(e){if(this._activePage!==e){this._activePage=e;let t=this.getActivePage();if(this._documentReady){t=t==null?null:t.get(0);if(typeof this.settings.onActivePageChanged==="function"){this.settings.onActivePageChanged.call(this,t,e)}this.$container.get(0).dispatchEvent(new CustomEvent("activepagechanged",{detail:{activePageNumber:e,activePage:t}}))}}}_areaOfPageVisible(t){if(t===undefined){return 0}let e=this.$container.offset();let i=this.$container.width();let s=this.$container.height();let n=t.offset();n.top-=e.top;n.left-=e.left;n.bottom=n.top+t.outerHeight();n.right=n.left+t.outerWidth();let a=Math.min(Math.max(n.top,0),s);let h=Math.min(Math.max(t.outerHeight()+n.top,0),s);let o=Math.min(Math.max(n.left,0),i);let l=Math.min(Math.max(t.outerWidth()+n.left,0),i);let r=l-o;let g=h-a;return r*g}isPageVisible(t){if(this.pdf===null||t===undefined||t===null||t<1||t>this.pdf.numPages){return false}if(typeof t==="string"){t=parseInt(t)}let e=t;if(typeof t==="number"){if(this.pages[t]===undefined)return false;e=this.pages[t].$div}return this._areaOfPageVisible(e)>e.outerWidth()*e.outerHeight()*this.settings.visibleThreshold}_visiblePages(t=false){let i=0;let s=null;if(this.pages.length===0){this._visibles=[];this._setActivePage(0);return}let e=this.pages.filter(function(t){let e=this._areaOfPageVisible(t.$div);if(e>i){i=e;s=t.$div.data("page")}return e>0}.bind(this)).map(t=>t.$div);this._setActivePage(s);let n=e.map(t=>{return parseInt($(t).data("page"))});if(n.length>0){let e=Math.min(...n);let i=Math.max(...n);for(let t=Math.max(1,e-this.settings.extraPagesToLoad);t0){let e=this._pagesLoading.shift();this.pdf.getPage(e).then(function(t){this._renderPage(t,e)}.bind(this)).then(function(t){if(this._pagesLoading.length>0){this._loadingTask()}}.bind(this))}this._loading=false}scrollToPage(t){if(this.pages.length===0||this.pages[t]===undefined){return}let e=this.pages[t].$div;if(e.length===0){console.warn(`Page ${t} not found`);return}let i=e.position();let s=this.$container.position();if(i!==undefined){this.$container.get(0).scrollTop=this.$container.get(0).scrollTop+i.top-s.top;this.$container.get(0).scrollLeft=this.$container.get(0).scrollLeft+i.left-s.left}this._setActivePage(t)}_renderPage(t,e){let i=this.pages[e];let s=this.settings.renderingScale;let n=window.devicePixelRatio||1;let a=t.getViewport({rotation:this._rotation,scale:this._zoom.current*s});i.width=a.width/this._zoom.current/s;i.height=a.height/this._zoom.current/s;i.$div.data("width",i.width);i.$div.data("height",i.height);i.$div.width(i.width*this._zoom.current);i.$div.height(i.height*this._zoom.current);i.loaded=true;let h=$("");let o=h.get(0);let l=o.getContext("2d");o.height=a.height*n;o.width=a.width*n;o.getContext("2d");var r=n!==1?[n,0,0,n,0,0]:null;var g={canvasContext:l,viewport:a,transform:r};return t.render(g).promise.then(function(){this._setPageContent(i.$div,h);if(this._documentReady){if(typeof this.settings.onPageRender==="function"){this.settings.onPageRender.call(this,i.$div.get(0),e)}this.$container.get(0).dispatchEvent(new CustomEvent("pagerender",{detail:{pageNumber:e,page:i.$div.get(0)}}))}return i}.bind(this))}getActivePage(){if(this._activePage===null||this.pdf===null){return null}if(this._activePage<1||this._activePage>this.pdf.numPages){return null}return this.pages[this._activePage].$div}getPages(){return this.pages}getPageCount(){if(this.pdf===null){return 0}return this.pdf.numPages}next(){if(this._activePage1){this.scrollToPage(this._activePage-1)}}first(){if(this._activePage!==1){this.scrollToPage(1)}}last(){if(this.pdf===null)return;if(this._activePage!==this.pdf.numPages){this.scrollToPage(this.pdf.numPages)}}rotate(t,e=false){if(e){t=t+this._rotation}this._rotation=t;let i=this.$container.get(0);let s={top:i.scrollTop,left:i.scrollLeft,height:i.scrollHeight,width:i.scrollWidth};return this.forceViewerInitialization().then(function(){let t={top:i.scrollTop,left:i.scrollLeft,height:i.scrollHeight,width:i.scrollWidth};i.scrollTop=s.top*(t.height/s.height);i.scrollLeft=s.left*(t.width/s.width)}.bind(this))}forceViewerInitialization(){this.pages=[];this.$container.find(`.${this.settings.pageClass}`).remove();this._pagesLoading=[];this._loading=false;this._visibles=[];this._activePage=null;return this.pdf.getPage(1).then(function(t){this._createSkeletons(t);this._visiblePages();this._setActivePage(1)}.bind(this))}async loadDocument(t){this._documentReady=false;this.pages=[];this.$container.find(`.${this.settings.pageClass}`).remove();this.pdf=null;let e=pdfjsLib.getDocument(t);return e.promise.then(function(t){this.pdf=t;this.pageCount=t.numPages;this._rotation=0;return this.forceViewerInitialization()}.bind(this)).then(function(){if(typeof this.settings.onDocumentReady==="function"){this.settings.onDocumentReady.call(this)}this.$container.get(0).dispatchEvent(new CustomEvent("documentready",{detail:{document:this.pdf}}));this._setActivePage(0);this._documentReady=true;this._setActivePage(1)}.bind(this))}}function recoverAttributes(target,attributeDefaults){const camelcaseToSnakecase=t=>t.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`);let $target=$(target);let result={};if($target.length>0){$target=$($target[0]);for(let originalAttributeName in attributeDefaults){let attributeName=camelcaseToSnakecase(originalAttributeName);let attributeValue=$target.attr(attributeName);if(attributeValue!=null){switch(typeof attributeDefaults[originalAttributeName]){case"float":try{attributeValue=parseFloat(attributeValue)}catch(_){}break;case"number":try{attributeValue=parseInt(attributeValue)}catch(_){}break;case"function":let functionString=attributeValue;attributeValue=function(){eval(functionString)}.bind(target[0]);break;default:break}result[originalAttributeName]=attributeValue}}}return result}function init(e){let i=recoverAttributes(e,Object.assign({pdfDocument:"",initialZoom:""},defaults));if(i["pdfDocument"]!=null){let t=new PDFjsViewer($(e),i);t.loadDocument(i["pdfDocument"]).then(function(){if(i["initialZoom"]!=null){t.setZoom(i["initialZoom"])}});e.get(0).pdfViewer=t}}$(function(){$(".pdfjs-viewer").each(function(){let t=$(this);init(t)})});exports.PDFjsViewer=PDFjsViewer})(window,window._$??window.jQuery??undefined); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /examples/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Visor PDFs 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 19 | 75 | 76 | 77 |
78 |
79 | 80 |
81 | 82 |
83 | 84 | 85 | 86 |
87 | 88 |
89 | 90 | 111 | 112 |
113 | print 114 | 115 | 116 | file_download 117 | 132 |
133 |
134 |
135 |
136 |
137 |
138 |

Cargue un fichero

139 |
140 |
141 |
142 |
143 | 144 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://data.jsdelivr.com/v1/package/gh/dealfonso/pdfjs-viewer/badge?style=rounded)](https://www.jsdelivr.com/package/gh/dealfonso/pdfjs-viewer) ![](https://img.shields.io/github/v/release/dealfonso/pdfjs-viewer) ![](https://img.shields.io/github/release-date/dealfonso/pdfjs-viewer) ![](https://img.shields.io/github/languages/code-size/dealfonso/pdfjs-viewer) ![](https://img.shields.io/github/license/dealfonso/pdfjs-viewer) 2 | 3 | # PDFjs-viewer 4 | 5 | The distribution of [Mozilla's PDF.js](https://mozilla.github.io/pdf.js/) includes an example of a viewer that can be used in a web page by means of inserting using an `iframe`. But the viewer cannot be easily used or customized for using it as part of a web application. 6 | 7 | PDFjs-viewer is an embeddable and easily customizable PDF viewer that is implemented using the PDF.js library. 8 | 9 | So, if you have a `div` in your web application, you can convert it into a PDF viewer as in the next example: 10 | 11 | ```html 12 |
13 |
14 | 18 | ``` 19 | 20 | or even easier 21 | 22 | ```html 23 |
24 | ``` 25 | 26 | The PDFjsViewer is customizable and has different options and callbacks that enable it to be easily integrated in your application. 27 | 28 | Some examples included in the distribution: 29 | - A simple PDF viewer, for a simple document. 30 | - A simpler PDF viewer, using the declarative way (i.e. setting the _pdfjs-viewer_ class to any object). 31 | - A PDF viewer with a toolbar that enables navigation through the document. 32 | - A PDF viewer with thumbnails that interact with the main document. 33 | - A PDF viewer in which it is possible to create selections and move them across different pages. 34 | 35 | **DISCLAIMER:** _PDFjs-viewer is written from scratch and has nothing to do with the example viewer in the PDF.js distribution._ 36 | 37 | ## Is PDFjs-viewer for me? 38 | 39 | Well, if you need a PDF viewer in your web application, you can try to embed the viewer that comes in the [PDF.js distribution](https://github.com/mozilla/pdf.js) in an `iframe`. It is well-supported and has a lot of background. 40 | 41 | But if (as in my case) you need more than simply a PDF viewer embedded in an `iframe`: you need to draw in the pages of the PDF, need to add more features to your viewer, customize the style, etc., PDFjs-viewer is worth a try. 42 | 43 | > The origin of PDFjs-viewer was to enable drawing a selection over the pages, to add a digital signature with an external application. 44 | 45 | ### Technical facts 46 | 47 | - The pages of each document are rendered on demand, to avoid having all the pages using the memory of the browser. The viewer detects the visible pages, and renders each of them. Although rendering is fast, using the options (i.e. `extraPagesToLoad`) it is advisable to render some extra pages to enable a better user experience when scrolling the document. 48 | - PDFjs-viewer adds some callbacks that are called upon different events: `onDocumentReady`, `onNewPage`, `onPageRender`, `onZoomChange`, `onActivePageChanged`. Each callback is binded to the PDFjsViewer instance, so it is possible to use `this` to refer to it. 49 | - PDFjs-viewer renders the pages according to the size of the DIVs in which they are included. In this way, the amount of memory is adjusted to the minimum needed. `PDFjsViewer` considers the `pixel_ratio` feature to increase the resolution of the images according to the features of the device in which the document has been opened (e.g. retina displays and so on). 50 | - PDFjs-viewer includes support for zooming the pages so that the user does not need to deal with this typical feature. 51 | 52 | ## Using 53 | 54 | ### Dependencies 55 | PDFjs-viewer depends on Mozilla's [PDF.js library](https://mozilla.github.io/pdf.js). So please be sure to include the dependencies in your project: 56 | 57 | ```html 58 | 59 | 63 | ``` 64 | 65 | PDFjs-viewer also depends on a [jQuery](https://jquery.com/) compatible library, so please include it in your project before including the PDFjs-viewer library: 66 | 67 | ```html 68 | 69 | ``` 70 | 71 | #### Troubleshooting 72 | Some users have reported problems with jQuery. So I added support for an alternative library called [nojquery](https://github.com/jsutilslib/nojquery). If you want to use this library instead, please include it before the PDFjs-viewer library. 73 | 74 | **nojquery** is a library that provides a subset of jQuery functions that are used in PDFjs-viewer. It is a lightweight library that can be used as a replacement for jQuery in some cases. `PDFjs-viewer` will use `nojquery` with more priority than jQuery if it is included in the project. 75 | 76 | ```html 77 | 78 | ``` 79 | 80 | ### From source 81 | 82 | There is a single _javascript_ file that contains the whole PDFjsViewer class (in folder `js`). 83 | 84 | There are also a set of _css_ files that contain some styles to be used in the library and examples. These files can also be included individually in your project, or combined into a single file by concatenating them. 85 | 86 | A `Makefile` is provided to create the single all-in-one minified `js` and `css` files for the library. 87 | 88 | ```console 89 | # npm install -g uglify-js clean-css-cli 90 | ... 91 | # git clone https://github.com/dealfonso/pdfjs-viewer 92 | # cd pdfjs-viewer 93 | # make 94 | uglifyjs js/*.js -b | cat notice - > pdfjs-viewer.js 95 | uglifyjs js/*.js | cat notice.min - > pdfjs-viewer.min.js 96 | cleancss css/*.css --format beautify | cat notice - > pdfjs-viewer.css 97 | cleancss css/*.css | cat notice.min - > pdfjs-viewer.min.css 98 | ``` 99 | 100 | Now you can use files `pdfjs-viewer.min.js` and `pdfjs-viewer.min.css` in your project (jQuery or nojquery is a prerequisite): 101 | 102 | ```html 103 | 104 | 105 | 106 | ``` 107 | 108 | ### From a CDN 109 | 110 | It is possible to use `pdfjs-viewer` directly from a CDN: 111 | 112 | ```html 113 | 114 | 115 | 116 | ``` 117 | 118 | ## API 119 | 120 | The creation of a PDF viewer consists of creating a `PDFjsViewer` object, setting the object in which the PDF viewer should be set, and configuring the options that we may need. 121 | 122 | ```javascript 123 | var options = { 124 | ... 125 | }; 126 | var pdfViewer = new PDFjsViewer(document.querySelector('.pdfjs-viewer'), options); 127 | ``` 128 | 129 | ### Options 130 | 131 | The possible option values along with the default values are the next (the comments in the code are self-explanatory): 132 | ```javascript 133 | // Fraction of the area of the page that has to be visible to be considered that it is visible 134 | visibleThreshold: 0.5, 135 | // Number of pages to load appart from the currently visible one (to enable fast scrolling) 136 | extraPagesToLoad: 3, 137 | // The class used for each page (the div that wraps the content of the page) 138 | pageClass: "pdfpage", 139 | // Prefix of the id used for each page (the page id will be -) 140 | pageIdPrefix: "page", 141 | // The class used for the content of each page (the div that contains the page) 142 | contentClass: "content-wrapper", 143 | // Posible zoom values to iterate over using "in" and "out" 144 | zoomValues: [ 0.25, 0.5, 0.75, 1, 1.25, 1.50, 2, 4, 8 ], 145 | // Percentage of the container that will be filled with the page 146 | zoomFillArea: 0.95, 147 | // Function called when a document has been loaded and its structure has been created 148 | onDocumentReady: () => {}, 149 | // Function called when a new page is created (it is bound to the object, and receives an html object as parameter, and the page number) 150 | onNewPage: (page, i) => {}, 151 | // Function called when a page is rendered (it is bound to the object, and receives an html object as parameter, and the page number) 152 | onPageRender: (page, i) => {}, 153 | // Function called when the zoom level changes (it receives the zoom level) 154 | onZoomChange: (zoomlevel) => {}, 155 | // Function called whenever the active page is changed (the active page is the one that is shown in the viewer) 156 | onActivePageChanged: (page, i) => {}, 157 | // Function called to get the content of an empty page 158 | emptyContent: () => $('
') 159 | // The scale to which the pages are rendered (1.5 is the default value for the PDFjs viewer); a higher value will render the pages with a higher resolution 160 | // but it will consume more memory and CPU. A lower value will render the pages with a lower resolution, but they will be uglier. 161 | renderingScale: 1.5, 162 | ``` 163 | 164 | ### Methods 165 | 166 | The public methods of the PDFViewer class are the next: 167 | 168 | - `loadDocument(document)`: Loads the document and returns a promise to load it (and so the result is _thenable_ to add actions after loading the document, or is _catchable_ in case of error). The `document` can be either an _url_ or a _bin array_. 169 | - `forceViewerInitialization()`: Forces the creation (or re-creation) of the whole content of the viewer (i.e. new divs, structures, etc.). It is usefull for full refresh of the viewer (e.g. when changes the rotation of the pages). 170 | - `refreshAll()`: Recalculates which pages are now visible and forces redrawing them. 171 | - `getActivePage()`: Gets the jQuery div object corresponding to the active page (or null, if none of the pages have been set). 172 | - `first()`: Scrolls to the first page of the document. 173 | - `last()`: Scrolls to the last page of the document. 174 | - `next()`: Scrolls to the next page (if any). 175 | - `prev()`: Scrolls to the previous page (if any). 176 | - `getPageCount()`: Gets the number of pages of the document. 177 | - `getPages()`: Retrieves all the pages of the document (the pageinfo structures). 178 | - `scrollToPage(i)`: Sets the scroll position of the container to page number `i` 179 | - `isPageVisible(i)`: Returns true if page number `i` is considered to be visible 180 | - `setZoom(zoom)`: Sets the current zoom level and applies it to all the pages (it is possible to use a float value which represents a fraction or a keyword 'in', 'out', 'width', 'height' or 'fit'). 181 | - `getZoom()`: Obtain the current zoom level 182 | - `rotate(deg, accumulate = false)`: Rotates the pages of the document `deg` degrees (if `accumulate` is set to `false`), or increases the rotation by `deg` degrees (if `accumulate` is set to `true`). 183 | 184 | ## Declarative 185 | 186 | If simply need a PDF viewer in a _div_, you can use the declarative way, which means that whenever an object is declared with class `pdfjs-viewer`, it is attached a `PDFjsViewer` object as the property `pdfViewer` of the HTML object. 187 | 188 | So it is possible to use a tag like the next one: 189 | 190 | ```html 191 |
192 | ``` 193 | 194 | And the div will automatically load the pdf file and when loaded, it will zoom to fit the first page. 195 | 196 | Now if we get the object is obtained in _javascript_, the `pdfViewer` property will contain the object. 197 | 198 | ```javascript 199 | let viewer = document.getElementById("viewer"); 200 | console.log(viewer.pdfViewer); 201 | ``` 202 | 203 | The rest of options in the API section can also be set as parameters for this tag as _snake-case_. For example, it is possible to add an `onDocumentReady` handler in the next way: 204 | 205 | ```html 206 |
207 | ``` 208 | 209 | ## Examples 210 | 211 | ### Example 1 - the most simple example 212 | 213 | The most simple example is to include a PDF viewer as the whole body of the web application: 214 | 215 | ```html 216 | 220 | ``` 221 | 222 | In this example, the whole page will be a PDF viewer showing document _test.pdf_. 223 | 224 | ![example 1](img/ex1.png) 225 | 226 | Check the example at [PDFjs-viewer example-1](https://codepen.io/dealfonso/pen/QWqMJwp) 227 | 228 | ### Example 2 - a viewer in a DIV 229 | 230 | To create a viewer in a DIV, it is needed to add class `pdfjs-viewer` class to the div. 231 | 232 | In this snippet, we are also using some of the callbacks that PDFjs-viewer provides, to update parts of our interface. 233 | 234 | ```html 235 |
236 |
237 |

Example for PDFjs-viewer

238 |

This is a simple document embeded in a div (integrated with bootstrap)

239 |
240 |
241 |
242 | ... 243 |
244 |
245 |
246 |
247 |
248 | 266 | ``` 267 | 268 | ![example 2](img/ex2.png) 269 | 270 | Check the example at [PDFjs-viewer example-2](https://codepen.io/dealfonso/pen/qBPPEEd) 271 | 272 | ### Example 3 - a document with thumbnails and a toolbar 273 | 274 | Each of the PDFjsViewer objects is independent from each other, so it is possible to include multiple PDF documents in the same web application. 275 | 276 | In this example, we have included two independent documents (which at the end, have the same PDF source): one to act as thumbnails and other to act as the main document. Then using the callbacks, it is possible to make them interact one with the other to mark the _active page_ in the thumbnails when scrolling the main document, or showing a specific page when clicking on one of the pages in the thumbnails documents. 277 | 278 | ![example 3](img/ex3.png) 279 | 280 | Check the example at [PDFjs-viewer example-3](https://codepen.io/dealfonso/pen/dyVVYgP) 281 | 282 | ## Collaborations 283 | 284 | I really appreciate collaborations either by detecting bugs or by suggesting new features for this project. In this case, you can open issues and I'll try to address them in a best-effort basis. 285 | 286 | Also I welcome collaborations for enhancing the viewer. So if you can add new features, please fork the project and create pull requests. In this case, please add documentation about the new features both in the documentation as in the pull-request description. -------------------------------------------------------------------------------- /dist/pdfjs-viewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2021 Carlos A. (https://github.com/dealfonso) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | (function (exports, $) { 18 | "use strict"; 19 | if ($ === undefined) { 20 | console.error("jQuery-like library not available"); 21 | return; 22 | } 23 | let defaults = { 24 | visibleThreshold: .5, 25 | extraPagesToLoad: 3, 26 | pageClass: "pdfpage", 27 | contentClass: "content-wrapper", 28 | onDocumentReady: () => {}, 29 | onNewPage: (page, i) => {}, 30 | onPageRender: (page, i) => {}, 31 | zoomValues: [.25, .5, .75, 1, 1.25, 1.5, 2, 4, 8], 32 | onZoomChange: zoomlevel => {}, 33 | onActivePageChanged: (page, i) => {}, 34 | zoomFillArea: .95, 35 | emptyContent: () => $('
'), 36 | renderingScale: 1.5 37 | }; 38 | class Zoomer { 39 | constructor(viewer, options = {}) { 40 | let defaults = { 41 | zoomValues: [.25, .5, .75, 1, 1.25, 1.5, 2, 4, 8], 42 | fillArea: .9 43 | }; 44 | this.current = 1; 45 | this.viewer = viewer; 46 | this.settings = Object.assign({}, defaults, options); 47 | this.settings.zoomValues = this.settings.zoomValues.sort(); 48 | } 49 | get(zoom = null) { 50 | if (zoom === null) { 51 | return this.current; 52 | } 53 | if (parseFloat(zoom) == zoom) { 54 | return zoom; 55 | } 56 | let $activepage = this.viewer.getActivePage(); 57 | let zoomValues = []; 58 | switch (zoom) { 59 | case "in": 60 | zoom = this.current; 61 | zoomValues = this.settings.zoomValues.filter(x => x > zoom); 62 | if (zoomValues.length > 0) { 63 | zoom = Math.min(...zoomValues); 64 | } 65 | break; 66 | case "out": 67 | zoom = this.current; 68 | zoomValues = this.settings.zoomValues.filter(x => x < zoom); 69 | if (zoomValues.length > 0) { 70 | zoom = Math.max(...zoomValues); 71 | } 72 | break; 73 | case "fit": 74 | zoom = Math.min(this.get("width"), this.get("height")); 75 | break; 76 | case "width": 77 | zoom = this.settings.fillArea * this.viewer.$container.width() / $activepage.data("width"); 78 | break; 79 | case "height": 80 | zoom = this.settings.fillArea * this.viewer.$container.height() / $activepage.data("height"); 81 | break; 82 | default: 83 | zoom = this.current; 84 | break; 85 | } 86 | return zoom; 87 | } 88 | zoomPages(zoom) { 89 | zoom = this.get(zoom); 90 | this.viewer.getPages().forEach(function (page) { 91 | let $page = page.$div; 92 | let c_width = $page.data("width"); 93 | let c_height = $page.data("height"); 94 | $page.width(c_width * zoom).height(c_height * zoom); 95 | $page.data("zoom", zoom); 96 | $page.find(`.${this.viewer.settings.contentClass}`).width(c_width * zoom).height(c_height * zoom); 97 | }.bind(this)); 98 | this.current = zoom; 99 | } 100 | } 101 | class PDFjsViewer { 102 | version = "2.0.0"; 103 | constructor($container, options = {}) { 104 | this.settings = Object.assign({}, defaults, options); 105 | this._zoom = new Zoomer(this, { 106 | zoomValues: this.settings.zoomValues, 107 | fillArea: this.settings.zoomFillArea 108 | }); 109 | $container = $($container); 110 | this.$container = $container; 111 | $container.get(0)._pdfjsViewer = this; 112 | this._setScrollListener(); 113 | this.pages = []; 114 | this.pdf = null; 115 | this._documentReady = false; 116 | } 117 | setZoom(zoom) { 118 | let container = this.$container.get(0); 119 | let prevzoom = this._zoom.current; 120 | let prevScroll = { 121 | top: container.scrollTop, 122 | left: container.scrollLeft 123 | }; 124 | this._zoom.zoomPages(zoom); 125 | container.scrollLeft = prevScroll.left * this._zoom.current / prevzoom; 126 | container.scrollTop = prevScroll.top * this._zoom.current / prevzoom; 127 | this._visiblePages(true); 128 | if (this._documentReady) { 129 | if (typeof this.settings.onZoomChange === "function") this.settings.onZoomChange.call(this, this._zoom.current); 130 | this.$container.get(0).dispatchEvent(new CustomEvent("zoomchange", { 131 | detail: { 132 | zoom: this._zoom.current 133 | } 134 | })); 135 | } 136 | return this._zoom.current; 137 | } 138 | getZoom() { 139 | return this._zoom.current; 140 | } 141 | _cleanPage($page) { 142 | let $emptyContent = this.settings.emptyContent(); 143 | $page.find(`.${this.settings.contentClass}`).html("").append($emptyContent); 144 | } 145 | _setPageContent($page, $content) { 146 | $page.find(`.${this.settings.contentClass}`).html("").append($content); 147 | } 148 | refreshAll() { 149 | this._visiblePages(true); 150 | } 151 | _setScrollListener() { 152 | let scrollLock = false; 153 | let scrollPos = { 154 | top: 0, 155 | left: 0 156 | }; 157 | this.__scrollHandler = function (e) { 158 | if (scrollLock === true) { 159 | return; 160 | } 161 | scrollLock = true; 162 | let container = this.$container.get(0); 163 | if (Math.abs(container.scrollTop - scrollPos.top) > container.clientHeight * .2 * this._zoom.current || Math.abs(container.scrollLeft - scrollPos.left) > container.clientWidth * .2 * this._zoom.current) { 164 | scrollPos = { 165 | top: container.scrollTop, 166 | left: container.scrollLeft 167 | }; 168 | this._visiblePages(); 169 | } 170 | scrollLock = false; 171 | }.bind(this); 172 | this.$container.off("scroll"); 173 | this.$container.on("scroll", this.__scrollHandler); 174 | } 175 | _createSkeleton(page, i) { 176 | let pageinfo = { 177 | $div: null, 178 | width: 0, 179 | height: 0, 180 | loaded: false 181 | }; 182 | if (page.getViewport !== undefined) { 183 | let viewport = page.getViewport({ 184 | rotation: this._rotation, 185 | scale: 1 186 | }); 187 | pageinfo.width = viewport.width; 188 | pageinfo.height = viewport.height; 189 | pageinfo.loaded = true; 190 | } else { 191 | pageinfo.width = page.width; 192 | pageinfo.height = page.height; 193 | } 194 | console.assert(pageinfo.width > 0 && pageinfo.height > 0, "Page width and height must be greater than 0"); 195 | pageinfo.$div = $(`
`).attr("data-page", i).data("width", pageinfo.width).data("height", pageinfo.height).data("zoom", this._zoom.current).addClass(this.settings.pageClass).width(pageinfo.width * this._zoom.current).height(pageinfo.height * this._zoom.current); 196 | let $content = $(`
`).width(pageinfo.width).height(pageinfo.height); 197 | pageinfo.$div.append($content); 198 | this._cleanPage(pageinfo.$div); 199 | return pageinfo; 200 | } 201 | _placeSkeleton(pageinfo, i) { 202 | let prevpage = i - 1; 203 | let $prevpage = null; 204 | while (prevpage > 0 && ($prevpage = this.$container.find(`.${this.settings.pageClass}[data-page="${prevpage}"]`)).length === 0) { 205 | prevpage--; 206 | } 207 | if (prevpage === 0) { 208 | this.$container.append(pageinfo.$div); 209 | } else { 210 | $prevpage.after(pageinfo.$div); 211 | } 212 | } 213 | _createSkeletons(pageinfo) { 214 | for (let i = 1; i <= this.pageCount; i++) { 215 | if (this.pages[i] === undefined) { 216 | pageinfo = this._createSkeleton(pageinfo, i); 217 | this.pages[i] = pageinfo; 218 | this._placeSkeleton(pageinfo, i); 219 | if (typeof this.settings.onNewPage === "function") { 220 | this.settings.onNewPage.call(this, pageinfo.$div.get(0), i); 221 | } 222 | this.$container.get(0).dispatchEvent(new CustomEvent("newpage", { 223 | detail: { 224 | pageNumber: i, 225 | page: pageinfo.$div.get(0) 226 | } 227 | })); 228 | } 229 | } 230 | } 231 | _setActivePage(i) { 232 | if (this._activePage !== i) { 233 | this._activePage = i; 234 | let activePage = this.getActivePage(); 235 | if (this._documentReady) { 236 | activePage = activePage == null ? null : activePage.get(0); 237 | if (typeof this.settings.onActivePageChanged === "function") { 238 | this.settings.onActivePageChanged.call(this, activePage, i); 239 | } 240 | this.$container.get(0).dispatchEvent(new CustomEvent("activepagechanged", { 241 | detail: { 242 | activePageNumber: i, 243 | activePage: activePage 244 | } 245 | })); 246 | } 247 | } 248 | } 249 | _areaOfPageVisible($page) { 250 | if ($page === undefined) { 251 | return 0; 252 | } 253 | let c_offset = this.$container.offset(); 254 | let c_width = this.$container.width(); 255 | let c_height = this.$container.height(); 256 | let position = $page.offset(); 257 | position.top -= c_offset.top; 258 | position.left -= c_offset.left; 259 | position.bottom = position.top + $page.outerHeight(); 260 | position.right = position.left + $page.outerWidth(); 261 | let page_y0 = Math.min(Math.max(position.top, 0), c_height); 262 | let page_y1 = Math.min(Math.max($page.outerHeight() + position.top, 0), c_height); 263 | let page_x0 = Math.min(Math.max(position.left, 0), c_width); 264 | let page_x1 = Math.min(Math.max($page.outerWidth() + position.left, 0), c_width); 265 | let vis_x = page_x1 - page_x0; 266 | let vis_y = page_y1 - page_y0; 267 | return vis_x * vis_y; 268 | } 269 | isPageVisible(i) { 270 | if (this.pdf === null || i === undefined || i === null || i < 1 || i > this.pdf.numPages) { 271 | return false; 272 | } 273 | if (typeof i === "string") { 274 | i = parseInt(i); 275 | } 276 | let $page = i; 277 | if (typeof i === "number") { 278 | if (this.pages[i] === undefined) return false; 279 | $page = this.pages[i].$div; 280 | } 281 | return this._areaOfPageVisible($page) > $page.outerWidth() * $page.outerHeight() * this.settings.visibleThreshold; 282 | } 283 | _visiblePages(forceRedraw = false) { 284 | let max_area = 0; 285 | let i_page = null; 286 | if (this.pages.length === 0) { 287 | this._visibles = []; 288 | this._setActivePage(0); 289 | return; 290 | } 291 | let $visibles = this.pages.filter(function (pageinfo) { 292 | let areaVisible = this._areaOfPageVisible(pageinfo.$div); 293 | if (areaVisible > max_area) { 294 | max_area = areaVisible; 295 | i_page = pageinfo.$div.data("page"); 296 | } 297 | return areaVisible > 0; 298 | }.bind(this)).map(x => x.$div); 299 | this._setActivePage(i_page); 300 | let visibles = $visibles.map(x => { 301 | return parseInt($(x).data("page")); 302 | }); 303 | if (visibles.length > 0) { 304 | let minVisible = Math.min(...visibles); 305 | let maxVisible = Math.max(...visibles); 306 | for (let i = Math.max(1, minVisible - this.settings.extraPagesToLoad); i < minVisible; i++) { 307 | if (!visibles.includes(i)) visibles.push(i); 308 | } 309 | for (let i = maxVisible + 1; i <= Math.min(maxVisible + this.settings.extraPagesToLoad, this.pdf.numPages); i++) { 310 | if (!visibles.includes(i)) visibles.push(i); 311 | } 312 | } 313 | let nowVisibles = visibles; 314 | if (!forceRedraw) { 315 | nowVisibles = visibles.filter(function (x) { 316 | return !this._visibles.includes(x); 317 | }.bind(this)); 318 | } 319 | this._visibles.filter(function (x) { 320 | return !visibles.includes(x); 321 | }).forEach(function (i) { 322 | this._cleanPage(this.pages[i].$div); 323 | }.bind(this)); 324 | this._visibles = visibles; 325 | this.loadPages(...nowVisibles); 326 | } 327 | loadPages(...pages) { 328 | this._pagesLoading.push(...pages); 329 | if (this._loading) { 330 | return; 331 | } 332 | this._loadingTask(); 333 | } 334 | _loadingTask() { 335 | this._loading = true; 336 | if (this._pagesLoading.length > 0) { 337 | let pagei = this._pagesLoading.shift(); 338 | this.pdf.getPage(pagei).then(function (page) { 339 | this._renderPage(page, pagei); 340 | }.bind(this)).then(function (pageinfo) { 341 | if (this._pagesLoading.length > 0) { 342 | this._loadingTask(); 343 | } 344 | }.bind(this)); 345 | } 346 | this._loading = false; 347 | } 348 | scrollToPage(i) { 349 | if (this.pages.length === 0 || this.pages[i] === undefined) { 350 | return; 351 | } 352 | let $page = this.pages[i].$div; 353 | if ($page.length === 0) { 354 | console.warn(`Page ${i} not found`); 355 | return; 356 | } 357 | let position = $page.position(); 358 | let containerPosition = this.$container.position(); 359 | if (position !== undefined) { 360 | this.$container.get(0).scrollTop = this.$container.get(0).scrollTop + position.top - containerPosition.top; 361 | this.$container.get(0).scrollLeft = this.$container.get(0).scrollLeft + position.left - containerPosition.left; 362 | } 363 | this._setActivePage(i); 364 | } 365 | _renderPage(page, i) { 366 | let pageinfo = this.pages[i]; 367 | let scale = this.settings.renderingScale; 368 | let pixel_ratio = window.devicePixelRatio || 1; 369 | let viewport = page.getViewport({ 370 | rotation: this._rotation, 371 | scale: this._zoom.current * scale 372 | }); 373 | pageinfo.width = viewport.width / this._zoom.current / scale; 374 | pageinfo.height = viewport.height / this._zoom.current / scale; 375 | pageinfo.$div.data("width", pageinfo.width); 376 | pageinfo.$div.data("height", pageinfo.height); 377 | pageinfo.$div.width(pageinfo.width * this._zoom.current); 378 | pageinfo.$div.height(pageinfo.height * this._zoom.current); 379 | pageinfo.loaded = true; 380 | let $canvas = $(""); 381 | let canvas = $canvas.get(0); 382 | let context = canvas.getContext("2d"); 383 | canvas.height = viewport.height * pixel_ratio; 384 | canvas.width = viewport.width * pixel_ratio; 385 | canvas.getContext("2d"); 386 | var transform = pixel_ratio !== 1 ? [pixel_ratio, 0, 0, pixel_ratio, 0, 0] : null; 387 | var renderContext = { 388 | canvasContext: context, 389 | viewport: viewport, 390 | transform: transform 391 | }; 392 | return page.render(renderContext).promise.then(function () { 393 | this._setPageContent(pageinfo.$div, $canvas); 394 | if (this._documentReady) { 395 | if (typeof this.settings.onPageRender === "function") { 396 | this.settings.onPageRender.call(this, pageinfo.$div.get(0), i); 397 | } 398 | this.$container.get(0).dispatchEvent(new CustomEvent("pagerender", { 399 | detail: { 400 | pageNumber: i, 401 | page: pageinfo.$div.get(0) 402 | } 403 | })); 404 | } 405 | return pageinfo; 406 | }.bind(this)); 407 | } 408 | getActivePage() { 409 | if (this._activePage === null || this.pdf === null) { 410 | return null; 411 | } 412 | if (this._activePage < 1 || this._activePage > this.pdf.numPages) { 413 | return null; 414 | } 415 | return this.pages[this._activePage].$div; 416 | } 417 | getPages() { 418 | return this.pages; 419 | } 420 | getPageCount() { 421 | if (this.pdf === null) { 422 | return 0; 423 | } 424 | return this.pdf.numPages; 425 | } 426 | next() { 427 | if (this._activePage < this.pdf.numPages) { 428 | this.scrollToPage(this._activePage + 1); 429 | } 430 | } 431 | prev() { 432 | if (this._activePage > 1) { 433 | this.scrollToPage(this._activePage - 1); 434 | } 435 | } 436 | first() { 437 | if (this._activePage !== 1) { 438 | this.scrollToPage(1); 439 | } 440 | } 441 | last() { 442 | if (this.pdf === null) return; 443 | if (this._activePage !== this.pdf.numPages) { 444 | this.scrollToPage(this.pdf.numPages); 445 | } 446 | } 447 | rotate(deg, accumulate = false) { 448 | if (accumulate) { 449 | deg = deg + this._rotation; 450 | } 451 | this._rotation = deg; 452 | let container = this.$container.get(0); 453 | let prevScroll = { 454 | top: container.scrollTop, 455 | left: container.scrollLeft, 456 | height: container.scrollHeight, 457 | width: container.scrollWidth 458 | }; 459 | return this.forceViewerInitialization().then(function () { 460 | let newScroll = { 461 | top: container.scrollTop, 462 | left: container.scrollLeft, 463 | height: container.scrollHeight, 464 | width: container.scrollWidth 465 | }; 466 | container.scrollTop = prevScroll.top * (newScroll.height / prevScroll.height); 467 | container.scrollLeft = prevScroll.left * (newScroll.width / prevScroll.width); 468 | }.bind(this)); 469 | } 470 | forceViewerInitialization() { 471 | this.pages = []; 472 | this.$container.find(`.${this.settings.pageClass}`).remove(); 473 | this._pagesLoading = []; 474 | this._loading = false; 475 | this._visibles = []; 476 | this._activePage = null; 477 | return this.pdf.getPage(1).then(function (page) { 478 | this._createSkeletons(page); 479 | this._visiblePages(); 480 | this._setActivePage(1); 481 | }.bind(this)); 482 | } 483 | async loadDocument(document) { 484 | this._documentReady = false; 485 | this.pages = []; 486 | this.$container.find(`.${this.settings.pageClass}`).remove(); 487 | this.pdf = null; 488 | let loadingTask = pdfjsLib.getDocument(document); 489 | return loadingTask.promise.then(function (pdf) { 490 | this.pdf = pdf; 491 | this.pageCount = pdf.numPages; 492 | this._rotation = 0; 493 | return this.forceViewerInitialization(); 494 | }.bind(this)).then(function () { 495 | if (typeof this.settings.onDocumentReady === "function") { 496 | this.settings.onDocumentReady.call(this); 497 | } 498 | this.$container.get(0).dispatchEvent(new CustomEvent("documentready", { 499 | detail: { 500 | document: this.pdf 501 | } 502 | })); 503 | this._setActivePage(0); 504 | this._documentReady = true; 505 | this._setActivePage(1); 506 | }.bind(this)); 507 | } 508 | } 509 | 510 | function recoverAttributes(target, attributeDefaults) { 511 | const camelcaseToSnakecase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`); 512 | let $target = $(target); 513 | let result = {}; 514 | if ($target.length > 0) { 515 | $target = $($target[0]); 516 | for (let originalAttributeName in attributeDefaults) { 517 | let attributeName = camelcaseToSnakecase(originalAttributeName); 518 | let attributeValue = $target.attr(attributeName); 519 | if (attributeValue != null) { 520 | switch (typeof attributeDefaults[originalAttributeName]) { 521 | case "float": 522 | try { 523 | attributeValue = parseFloat(attributeValue); 524 | } catch (_) {} 525 | break; 526 | case "number": 527 | try { 528 | attributeValue = parseInt(attributeValue); 529 | } catch (_) {} 530 | break; 531 | case "function": 532 | let functionString = attributeValue; 533 | attributeValue = function () { 534 | eval(functionString); 535 | }.bind(target[0]); 536 | break; 537 | default: 538 | break; 539 | } 540 | result[originalAttributeName] = attributeValue; 541 | } 542 | } 543 | } 544 | return result; 545 | } 546 | 547 | function init(element) { 548 | let options = recoverAttributes(element, Object.assign({ 549 | pdfDocument: "", 550 | initialZoom: "" 551 | }, defaults)); 552 | if (options["pdfDocument"] != null) { 553 | let pdfViewer = new PDFjsViewer($(element), options); 554 | pdfViewer.loadDocument(options["pdfDocument"]).then(function () { 555 | if (options["initialZoom"] != null) { 556 | pdfViewer.setZoom(options["initialZoom"]); 557 | } 558 | }); 559 | element.get(0).pdfViewer = pdfViewer; 560 | } 561 | } 562 | $(function () { 563 | $(".pdfjs-viewer").each(function () { 564 | let $viewer = $(this); 565 | init($viewer); 566 | }); 567 | }); 568 | exports.PDFjsViewer = PDFjsViewer; 569 | })(window, window._$ ?? window.jQuery ?? undefined); 570 | -------------------------------------------------------------------------------- /dist/pdfjs-viewer.compress.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"pdfjs-viewer.compress.js.map","sources":["pdfjs-viewer.js"],"sourcesContent":["/**\n Copyright 2021 Carlos A. (https://github.com/dealfonso)\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n(function (exports, $) {\n\t\"use strict\";\n\tif ($ === undefined) {\n\t\tconsole.error(\"jQuery-like library not available\");\n\t\treturn;\n\t}\n\tlet defaults = {\n\t\tvisibleThreshold: .5,\n\t\textraPagesToLoad: 3,\n\t\tpageClass: \"pdfpage\",\n\t\tcontentClass: \"content-wrapper\",\n\t\tonDocumentReady: () => {},\n\t\tonNewPage: (page, i) => {},\n\t\tonPageRender: (page, i) => {},\n\t\tzoomValues: [.25, .5, .75, 1, 1.25, 1.5, 2, 4, 8],\n\t\tonZoomChange: zoomlevel => {},\n\t\tonActivePageChanged: (page, i) => {},\n\t\tzoomFillArea: .95,\n\t\temptyContent: () => $('
'),\n\t\trenderingScale: 1.5\n\t};\n\tclass Zoomer {\n\t\tconstructor(viewer, options = {}) {\n\t\t\tlet defaults = {\n\t\t\t\tzoomValues: [.25, .5, .75, 1, 1.25, 1.5, 2, 4, 8],\n\t\t\t\tfillArea: .9\n\t\t\t};\n\t\t\tthis.current = 1;\n\t\t\tthis.viewer = viewer;\n\t\t\tthis.settings = Object.assign({}, defaults, options);\n\t\t\tthis.settings.zoomValues = this.settings.zoomValues.sort();\n\t\t}\n\t\tget(zoom = null) {\n\t\t\tif (zoom === null) {\n\t\t\t\treturn this.current;\n\t\t\t}\n\t\t\tif (parseFloat(zoom) == zoom) {\n\t\t\t\treturn zoom;\n\t\t\t}\n\t\t\tlet $activepage = this.viewer.getActivePage();\n\t\t\tlet zoomValues = [];\n\t\t\tswitch (zoom) {\n\t\t\tcase \"in\":\n\t\t\t\tzoom = this.current;\n\t\t\t\tzoomValues = this.settings.zoomValues.filter(x => x > zoom);\n\t\t\t\tif (zoomValues.length > 0) {\n\t\t\t\t\tzoom = Math.min(...zoomValues);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"out\":\n\t\t\t\tzoom = this.current;\n\t\t\t\tzoomValues = this.settings.zoomValues.filter(x => x < zoom);\n\t\t\t\tif (zoomValues.length > 0) {\n\t\t\t\t\tzoom = Math.max(...zoomValues);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"fit\":\n\t\t\t\tzoom = Math.min(this.get(\"width\"), this.get(\"height\"));\n\t\t\t\tbreak;\n\t\t\tcase \"width\":\n\t\t\t\tzoom = this.settings.fillArea * this.viewer.$container.width() / $activepage.data(\"width\");\n\t\t\t\tbreak;\n\t\t\tcase \"height\":\n\t\t\t\tzoom = this.settings.fillArea * this.viewer.$container.height() / $activepage.data(\"height\");\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tzoom = this.current;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn zoom;\n\t\t}\n\t\tzoomPages(zoom) {\n\t\t\tzoom = this.get(zoom);\n\t\t\tthis.viewer.getPages().forEach(function (page) {\n\t\t\t\tlet $page = page.$div;\n\t\t\t\tlet c_width = $page.data(\"width\");\n\t\t\t\tlet c_height = $page.data(\"height\");\n\t\t\t\t$page.width(c_width * zoom).height(c_height * zoom);\n\t\t\t\t$page.data(\"zoom\", zoom);\n\t\t\t\t$page.find(`.${this.viewer.settings.contentClass}`).width(c_width * zoom).height(c_height * zoom);\n\t\t\t}.bind(this));\n\t\t\tthis.current = zoom;\n\t\t}\n\t}\n\tclass PDFjsViewer {\n\t\tversion = \"2.0.0\";\n\t\tconstructor($container, options = {}) {\n\t\t\tthis.settings = Object.assign({}, defaults, options);\n\t\t\tthis._zoom = new Zoomer(this, {\n\t\t\t\tzoomValues: this.settings.zoomValues,\n\t\t\t\tfillArea: this.settings.zoomFillArea\n\t\t\t});\n\t\t\t$container = $($container);\n\t\t\tthis.$container = $container;\n\t\t\t$container.get(0)._pdfjsViewer = this;\n\t\t\tthis._setScrollListener();\n\t\t\tthis.pages = [];\n\t\t\tthis.pdf = null;\n\t\t\tthis._documentReady = false;\n\t\t}\n\t\tsetZoom(zoom) {\n\t\t\tlet container = this.$container.get(0);\n\t\t\tlet prevzoom = this._zoom.current;\n\t\t\tlet prevScroll = {\n\t\t\t\ttop: container.scrollTop,\n\t\t\t\tleft: container.scrollLeft\n\t\t\t};\n\t\t\tthis._zoom.zoomPages(zoom);\n\t\t\tcontainer.scrollLeft = prevScroll.left * this._zoom.current / prevzoom;\n\t\t\tcontainer.scrollTop = prevScroll.top * this._zoom.current / prevzoom;\n\t\t\tthis._visiblePages(true);\n\t\t\tif (this._documentReady) {\n\t\t\t\tif (typeof this.settings.onZoomChange === \"function\") this.settings.onZoomChange.call(this, this._zoom.current);\n\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"zoomchange\", {\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tzoom: this._zoom.current\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t}\n\t\t\treturn this._zoom.current;\n\t\t}\n\t\tgetZoom() {\n\t\t\treturn this._zoom.current;\n\t\t}\n\t\t_cleanPage($page) {\n\t\t\tlet $emptyContent = this.settings.emptyContent();\n\t\t\t$page.find(`.${this.settings.contentClass}`).html(\"\").append($emptyContent);\n\t\t}\n\t\t_setPageContent($page, $content) {\n\t\t\t$page.find(`.${this.settings.contentClass}`).html(\"\").append($content);\n\t\t}\n\t\trefreshAll() {\n\t\t\tthis._visiblePages(true);\n\t\t}\n\t\t_setScrollListener() {\n\t\t\tlet scrollLock = false;\n\t\t\tlet scrollPos = {\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0\n\t\t\t};\n\t\t\tthis.__scrollHandler = function (e) {\n\t\t\t\tif (scrollLock === true) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tscrollLock = true;\n\t\t\t\tlet container = this.$container.get(0);\n\t\t\t\tif (Math.abs(container.scrollTop - scrollPos.top) > container.clientHeight * .2 * this._zoom.current || Math.abs(container.scrollLeft - scrollPos.left) > container.clientWidth * .2 * this._zoom.current) {\n\t\t\t\t\tscrollPos = {\n\t\t\t\t\t\ttop: container.scrollTop,\n\t\t\t\t\t\tleft: container.scrollLeft\n\t\t\t\t\t};\n\t\t\t\t\tthis._visiblePages();\n\t\t\t\t}\n\t\t\t\tscrollLock = false;\n\t\t\t}.bind(this);\n\t\t\tthis.$container.off(\"scroll\");\n\t\t\tthis.$container.on(\"scroll\", this.__scrollHandler);\n\t\t}\n\t\t_createSkeleton(page, i) {\n\t\t\tlet pageinfo = {\n\t\t\t\t$div: null,\n\t\t\t\twidth: 0,\n\t\t\t\theight: 0,\n\t\t\t\tloaded: false\n\t\t\t};\n\t\t\tif (page.getViewport !== undefined) {\n\t\t\t\tlet viewport = page.getViewport({\n\t\t\t\t\trotation: this._rotation,\n\t\t\t\t\tscale: 1\n\t\t\t\t});\n\t\t\t\tpageinfo.width = viewport.width;\n\t\t\t\tpageinfo.height = viewport.height;\n\t\t\t\tpageinfo.loaded = true;\n\t\t\t} else {\n\t\t\t\tpageinfo.width = page.width;\n\t\t\t\tpageinfo.height = page.height;\n\t\t\t}\n\t\t\tconsole.assert(pageinfo.width > 0 && pageinfo.height > 0, \"Page width and height must be greater than 0\");\n\t\t\tpageinfo.$div = $(`
`).attr(\"data-page\", i).data(\"width\", pageinfo.width).data(\"height\", pageinfo.height).data(\"zoom\", this._zoom.current).addClass(this.settings.pageClass).width(pageinfo.width * this._zoom.current).height(pageinfo.height * this._zoom.current);\n\t\t\tlet $content = $(`
`).width(pageinfo.width).height(pageinfo.height);\n\t\t\tpageinfo.$div.append($content);\n\t\t\tthis._cleanPage(pageinfo.$div);\n\t\t\treturn pageinfo;\n\t\t}\n\t\t_placeSkeleton(pageinfo, i) {\n\t\t\tlet prevpage = i - 1;\n\t\t\tlet $prevpage = null;\n\t\t\twhile (prevpage > 0 && ($prevpage = this.$container.find(`.${this.settings.pageClass}[data-page=\"${prevpage}\"]`)).length === 0) {\n\t\t\t\tprevpage--;\n\t\t\t}\n\t\t\tif (prevpage === 0) {\n\t\t\t\tthis.$container.append(pageinfo.$div);\n\t\t\t} else {\n\t\t\t\t$prevpage.after(pageinfo.$div);\n\t\t\t}\n\t\t}\n\t\t_createSkeletons(pageinfo) {\n\t\t\tfor (let i = 1; i <= this.pageCount; i++) {\n\t\t\t\tif (this.pages[i] === undefined) {\n\t\t\t\t\tpageinfo = this._createSkeleton(pageinfo, i);\n\t\t\t\t\tthis.pages[i] = pageinfo;\n\t\t\t\t\tthis._placeSkeleton(pageinfo, i);\n\t\t\t\t\tif (typeof this.settings.onNewPage === \"function\") {\n\t\t\t\t\t\tthis.settings.onNewPage.call(this, pageinfo.$div.get(0), i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"newpage\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tpageNumber: i,\n\t\t\t\t\t\t\tpage: pageinfo.$div.get(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_setActivePage(i) {\n\t\t\tif (this._activePage !== i) {\n\t\t\t\tthis._activePage = i;\n\t\t\t\tlet activePage = this.getActivePage();\n\t\t\t\tif (this._documentReady) {\n\t\t\t\t\tactivePage = activePage == null ? null : activePage.get(0);\n\t\t\t\t\tif (typeof this.settings.onActivePageChanged === \"function\") {\n\t\t\t\t\t\tthis.settings.onActivePageChanged.call(this, activePage, i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"activepagechanged\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tactivePageNumber: i,\n\t\t\t\t\t\t\tactivePage: activePage\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_areaOfPageVisible($page) {\n\t\t\tif ($page === undefined) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tlet c_offset = this.$container.offset();\n\t\t\tlet c_width = this.$container.width();\n\t\t\tlet c_height = this.$container.height();\n\t\t\tlet position = $page.offset();\n\t\t\tposition.top -= c_offset.top;\n\t\t\tposition.left -= c_offset.left;\n\t\t\tposition.bottom = position.top + $page.outerHeight();\n\t\t\tposition.right = position.left + $page.outerWidth();\n\t\t\tlet page_y0 = Math.min(Math.max(position.top, 0), c_height);\n\t\t\tlet page_y1 = Math.min(Math.max($page.outerHeight() + position.top, 0), c_height);\n\t\t\tlet page_x0 = Math.min(Math.max(position.left, 0), c_width);\n\t\t\tlet page_x1 = Math.min(Math.max($page.outerWidth() + position.left, 0), c_width);\n\t\t\tlet vis_x = page_x1 - page_x0;\n\t\t\tlet vis_y = page_y1 - page_y0;\n\t\t\treturn vis_x * vis_y;\n\t\t}\n\t\tisPageVisible(i) {\n\t\t\tif (this.pdf === null || i === undefined || i === null || i < 1 || i > this.pdf.numPages) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (typeof i === \"string\") {\n\t\t\t\ti = parseInt(i);\n\t\t\t}\n\t\t\tlet $page = i;\n\t\t\tif (typeof i === \"number\") {\n\t\t\t\tif (this.pages[i] === undefined) return false;\n\t\t\t\t$page = this.pages[i].$div;\n\t\t\t}\n\t\t\treturn this._areaOfPageVisible($page) > $page.outerWidth() * $page.outerHeight() * this.settings.visibleThreshold;\n\t\t}\n\t\t_visiblePages(forceRedraw = false) {\n\t\t\tlet max_area = 0;\n\t\t\tlet i_page = null;\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\tthis._visibles = [];\n\t\t\t\tthis._setActivePage(0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet $visibles = this.pages.filter(function (pageinfo) {\n\t\t\t\tlet areaVisible = this._areaOfPageVisible(pageinfo.$div);\n\t\t\t\tif (areaVisible > max_area) {\n\t\t\t\t\tmax_area = areaVisible;\n\t\t\t\t\ti_page = pageinfo.$div.data(\"page\");\n\t\t\t\t}\n\t\t\t\treturn areaVisible > 0;\n\t\t\t}.bind(this)).map(x => x.$div);\n\t\t\tthis._setActivePage(i_page);\n\t\t\tlet visibles = $visibles.map(x => {\n\t\t\t\treturn parseInt($(x).data(\"page\"));\n\t\t\t});\n\t\t\tif (visibles.length > 0) {\n\t\t\t\tlet minVisible = Math.min(...visibles);\n\t\t\t\tlet maxVisible = Math.max(...visibles);\n\t\t\t\tfor (let i = Math.max(1, minVisible - this.settings.extraPagesToLoad); i < minVisible; i++) {\n\t\t\t\t\tif (!visibles.includes(i)) visibles.push(i);\n\t\t\t\t}\n\t\t\t\tfor (let i = maxVisible + 1; i <= Math.min(maxVisible + this.settings.extraPagesToLoad, this.pdf.numPages); i++) {\n\t\t\t\t\tif (!visibles.includes(i)) visibles.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet nowVisibles = visibles;\n\t\t\tif (!forceRedraw) {\n\t\t\t\tnowVisibles = visibles.filter(function (x) {\n\t\t\t\t\treturn !this._visibles.includes(x);\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tthis._visibles.filter(function (x) {\n\t\t\t\treturn !visibles.includes(x);\n\t\t\t}).forEach(function (i) {\n\t\t\t\tthis._cleanPage(this.pages[i].$div);\n\t\t\t}.bind(this));\n\t\t\tthis._visibles = visibles;\n\t\t\tthis.loadPages(...nowVisibles);\n\t\t}\n\t\tloadPages(...pages) {\n\t\t\tthis._pagesLoading.push(...pages);\n\t\t\tif (this._loading) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._loadingTask();\n\t\t}\n\t\t_loadingTask() {\n\t\t\tthis._loading = true;\n\t\t\tif (this._pagesLoading.length > 0) {\n\t\t\t\tlet pagei = this._pagesLoading.shift();\n\t\t\t\tthis.pdf.getPage(pagei).then(function (page) {\n\t\t\t\t\tthis._renderPage(page, pagei);\n\t\t\t\t}.bind(this)).then(function (pageinfo) {\n\t\t\t\t\tif (this._pagesLoading.length > 0) {\n\t\t\t\t\t\tthis._loadingTask();\n\t\t\t\t\t}\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tthis._loading = false;\n\t\t}\n\t\tscrollToPage(i) {\n\t\t\tif (this.pages.length === 0 || this.pages[i] === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet $page = this.pages[i].$div;\n\t\t\tif ($page.length === 0) {\n\t\t\t\tconsole.warn(`Page ${i} not found`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet position = $page.position();\n\t\t\tlet containerPosition = this.$container.position();\n\t\t\tif (position !== undefined) {\n\t\t\t\tthis.$container.get(0).scrollTop = this.$container.get(0).scrollTop + position.top - containerPosition.top;\n\t\t\t\tthis.$container.get(0).scrollLeft = this.$container.get(0).scrollLeft + position.left - containerPosition.left;\n\t\t\t}\n\t\t\tthis._setActivePage(i);\n\t\t}\n\t\t_renderPage(page, i) {\n\t\t\tlet pageinfo = this.pages[i];\n\t\t\tlet scale = this.settings.renderingScale;\n\t\t\tlet pixel_ratio = window.devicePixelRatio || 1;\n\t\t\tlet viewport = page.getViewport({\n\t\t\t\trotation: this._rotation,\n\t\t\t\tscale: this._zoom.current * scale\n\t\t\t});\n\t\t\tpageinfo.width = viewport.width / this._zoom.current / scale;\n\t\t\tpageinfo.height = viewport.height / this._zoom.current / scale;\n\t\t\tpageinfo.$div.data(\"width\", pageinfo.width);\n\t\t\tpageinfo.$div.data(\"height\", pageinfo.height);\n\t\t\tpageinfo.$div.width(pageinfo.width * this._zoom.current);\n\t\t\tpageinfo.$div.height(pageinfo.height * this._zoom.current);\n\t\t\tpageinfo.loaded = true;\n\t\t\tlet $canvas = $(\"\");\n\t\t\tlet canvas = $canvas.get(0);\n\t\t\tlet context = canvas.getContext(\"2d\");\n\t\t\tcanvas.height = viewport.height * pixel_ratio;\n\t\t\tcanvas.width = viewport.width * pixel_ratio;\n\t\t\tcanvas.getContext(\"2d\");\n\t\t\tvar transform = pixel_ratio !== 1 ? [pixel_ratio, 0, 0, pixel_ratio, 0, 0] : null;\n\t\t\tvar renderContext = {\n\t\t\t\tcanvasContext: context,\n\t\t\t\tviewport: viewport,\n\t\t\t\ttransform: transform\n\t\t\t};\n\t\t\treturn page.render(renderContext).promise.then(function () {\n\t\t\t\tthis._setPageContent(pageinfo.$div, $canvas);\n\t\t\t\tif (this._documentReady) {\n\t\t\t\t\tif (typeof this.settings.onPageRender === \"function\") {\n\t\t\t\t\t\tthis.settings.onPageRender.call(this, pageinfo.$div.get(0), i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"pagerender\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tpageNumber: i,\n\t\t\t\t\t\t\tpage: pageinfo.$div.get(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\treturn pageinfo;\n\t\t\t}.bind(this));\n\t\t}\n\t\tgetActivePage() {\n\t\t\tif (this._activePage === null || this.pdf === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (this._activePage < 1 || this._activePage > this.pdf.numPages) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.pages[this._activePage].$div;\n\t\t}\n\t\tgetPages() {\n\t\t\treturn this.pages;\n\t\t}\n\t\tgetPageCount() {\n\t\t\tif (this.pdf === null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn this.pdf.numPages;\n\t\t}\n\t\tnext() {\n\t\t\tif (this._activePage < this.pdf.numPages) {\n\t\t\t\tthis.scrollToPage(this._activePage + 1);\n\t\t\t}\n\t\t}\n\t\tprev() {\n\t\t\tif (this._activePage > 1) {\n\t\t\t\tthis.scrollToPage(this._activePage - 1);\n\t\t\t}\n\t\t}\n\t\tfirst() {\n\t\t\tif (this._activePage !== 1) {\n\t\t\t\tthis.scrollToPage(1);\n\t\t\t}\n\t\t}\n\t\tlast() {\n\t\t\tif (this.pdf === null) return;\n\t\t\tif (this._activePage !== this.pdf.numPages) {\n\t\t\t\tthis.scrollToPage(this.pdf.numPages);\n\t\t\t}\n\t\t}\n\t\trotate(deg, accumulate = false) {\n\t\t\tif (accumulate) {\n\t\t\t\tdeg = deg + this._rotation;\n\t\t\t}\n\t\t\tthis._rotation = deg;\n\t\t\tlet container = this.$container.get(0);\n\t\t\tlet prevScroll = {\n\t\t\t\ttop: container.scrollTop,\n\t\t\t\tleft: container.scrollLeft,\n\t\t\t\theight: container.scrollHeight,\n\t\t\t\twidth: container.scrollWidth\n\t\t\t};\n\t\t\treturn this.forceViewerInitialization().then(function () {\n\t\t\t\tlet newScroll = {\n\t\t\t\t\ttop: container.scrollTop,\n\t\t\t\t\tleft: container.scrollLeft,\n\t\t\t\t\theight: container.scrollHeight,\n\t\t\t\t\twidth: container.scrollWidth\n\t\t\t\t};\n\t\t\t\tcontainer.scrollTop = prevScroll.top * (newScroll.height / prevScroll.height);\n\t\t\t\tcontainer.scrollLeft = prevScroll.left * (newScroll.width / prevScroll.width);\n\t\t\t}.bind(this));\n\t\t}\n\t\tforceViewerInitialization() {\n\t\t\tthis.pages = [];\n\t\t\tthis.$container.find(`.${this.settings.pageClass}`).remove();\n\t\t\tthis._pagesLoading = [];\n\t\t\tthis._loading = false;\n\t\t\tthis._visibles = [];\n\t\t\tthis._activePage = null;\n\t\t\treturn this.pdf.getPage(1).then(function (page) {\n\t\t\t\tthis._createSkeletons(page);\n\t\t\t\tthis._visiblePages();\n\t\t\t\tthis._setActivePage(1);\n\t\t\t}.bind(this));\n\t\t}\n\t\tasync loadDocument(document) {\n\t\t\tthis._documentReady = false;\n\t\t\tthis.pages = [];\n\t\t\tthis.$container.find(`.${this.settings.pageClass}`).remove();\n\t\t\tthis.pdf = null;\n\t\t\tlet loadingTask = pdfjsLib.getDocument(document);\n\t\t\treturn loadingTask.promise.then(function (pdf) {\n\t\t\t\tthis.pdf = pdf;\n\t\t\t\tthis.pageCount = pdf.numPages;\n\t\t\t\tthis._rotation = 0;\n\t\t\t\treturn this.forceViewerInitialization();\n\t\t\t}.bind(this)).then(function () {\n\t\t\t\tif (typeof this.settings.onDocumentReady === \"function\") {\n\t\t\t\t\tthis.settings.onDocumentReady.call(this);\n\t\t\t\t}\n\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"documentready\", {\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tdocument: this.pdf\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t\tthis._setActivePage(0);\n\t\t\t\tthis._documentReady = true;\n\t\t\t\tthis._setActivePage(1);\n\t\t\t}.bind(this));\n\t\t}\n\t}\n\n\tfunction recoverAttributes(target, attributeDefaults) {\n\t\tconst camelcaseToSnakecase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);\n\t\tlet $target = $(target);\n\t\tlet result = {};\n\t\tif ($target.length > 0) {\n\t\t\t$target = $($target[0]);\n\t\t\tfor (let originalAttributeName in attributeDefaults) {\n\t\t\t\tlet attributeName = camelcaseToSnakecase(originalAttributeName);\n\t\t\t\tlet attributeValue = $target.attr(attributeName);\n\t\t\t\tif (attributeValue != null) {\n\t\t\t\t\tswitch (typeof attributeDefaults[originalAttributeName]) {\n\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tattributeValue = parseFloat(attributeValue);\n\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"number\":\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tattributeValue = parseInt(attributeValue);\n\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"function\":\n\t\t\t\t\t\tlet functionString = attributeValue;\n\t\t\t\t\t\tattributeValue = function () {\n\t\t\t\t\t\t\teval(functionString);\n\t\t\t\t\t\t}.bind(target[0]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tresult[originalAttributeName] = attributeValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction init(element) {\n\t\tlet options = recoverAttributes(element, Object.assign({\n\t\t\tpdfDocument: \"\",\n\t\t\tinitialZoom: \"\"\n\t\t}, defaults));\n\t\tif (options[\"pdfDocument\"] != null) {\n\t\t\tlet pdfViewer = new PDFjsViewer($(element), options);\n\t\t\tpdfViewer.loadDocument(options[\"pdfDocument\"]).then(function () {\n\t\t\t\tif (options[\"initialZoom\"] != null) {\n\t\t\t\t\tpdfViewer.setZoom(options[\"initialZoom\"]);\n\t\t\t\t}\n\t\t\t});\n\t\t\telement.get(0).pdfViewer = pdfViewer;\n\t\t}\n\t}\n\t$(function () {\n\t\t$(\".pdfjs-viewer\").each(function () {\n\t\t\tlet $viewer = $(this);\n\t\t\tinit($viewer);\n\t\t});\n\t});\n\texports.PDFjsViewer = PDFjsViewer;\n})(window, window._$ ?? window.jQuery ?? undefined);\n"],"names":["exports","$","undefined","console","error","let","defaults","visibleThreshold","extraPagesToLoad","pageClass","contentClass","onDocumentReady","onNewPage","page","i","onPageRender","zoomValues","onZoomChange","zoomlevel","onActivePageChanged","zoomFillArea","emptyContent","renderingScale","Zoomer","constructor","viewer","options","this","current","settings","Object","assign","fillArea","sort","get","zoom","parseFloat","$activepage","getActivePage","filter","x","length","Math","min","max","$container","width","data","height","zoomPages","getPages","forEach","$page","$div","c_width","c_height","find","bind","PDFjsViewer","version","_zoom","_pdfjsViewer","_setScrollListener","pages","pdf","_documentReady","setZoom","container","prevzoom","prevScroll","scrollTop","scrollLeft","_visiblePages","call","dispatchEvent","CustomEvent","detail","getZoom","_cleanPage","$emptyContent","html","append","_setPageContent","$content","refreshAll","scrollLock","scrollPos","top","left","__scrollHandler","e","abs","clientHeight","clientWidth","off","on","_createSkeleton","pageinfo","loaded","getViewport","viewport","rotation","_rotation","scale","assert","attr","addClass","_placeSkeleton","prevpage","$prevpage","after","_createSkeletons","pageCount","pageNumber","_setActivePage","_activePage","activePage","activePageNumber","_areaOfPageVisible","position","page_y0","page_y1","page_x0","c_offset","offset","bottom","outerHeight","right","outerWidth","isPageVisible","numPages","parseInt","forceRedraw","max_area","i_page","_visibles","$visibles","areaVisible","map","visibles","minVisible","maxVisible","includes","push","nowVisibles","loadPages","_pagesLoading","_loading","_loadingTask","pagei","shift","getPage","then","_renderPage","scrollToPage","containerPosition","warn","pixel_ratio","window","devicePixelRatio","$canvas","canvas","context","getContext","render","canvasContext","transform","promise","getPageCount","next","prev","first","last","rotate","deg","accumulate","scrollHeight","scrollWidth","forceViewerInitialization","newScroll","remove","loadDocument","document","pdfjsLib","getDocument","recoverAttributes","target","attributeDefaults","camelcaseToSnakecase","str","replace","letter","toLowerCase","$target","result","originalAttributeName","attributeName","attributeValue","_","functionString","eval","init","element","pdfDocument","initialZoom","pdfViewer","each","_$","jQuery"],"mappings":"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"} -------------------------------------------------------------------------------- /dist/pdfjs-viewer.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"pdfjs-viewer.min.js.map","sources":["pdfjs-viewer.js"],"sourcesContent":["/**\n Copyright 2021 Carlos A. (https://github.com/dealfonso)\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n(function (exports, $) {\n\t\"use strict\";\n\tif ($ === undefined) {\n\t\tconsole.error(\"jQuery-like library not available\");\n\t\treturn;\n\t}\n\tlet defaults = {\n\t\tvisibleThreshold: .5,\n\t\textraPagesToLoad: 3,\n\t\tpageClass: \"pdfpage\",\n\t\tcontentClass: \"content-wrapper\",\n\t\tonDocumentReady: () => {},\n\t\tonNewPage: (page, i) => {},\n\t\tonPageRender: (page, i) => {},\n\t\tzoomValues: [.25, .5, .75, 1, 1.25, 1.5, 2, 4, 8],\n\t\tonZoomChange: zoomlevel => {},\n\t\tonActivePageChanged: (page, i) => {},\n\t\tzoomFillArea: .95,\n\t\temptyContent: () => $('
'),\n\t\trenderingScale: 1.5\n\t};\n\tclass Zoomer {\n\t\tconstructor(viewer, options = {}) {\n\t\t\tlet defaults = {\n\t\t\t\tzoomValues: [.25, .5, .75, 1, 1.25, 1.5, 2, 4, 8],\n\t\t\t\tfillArea: .9\n\t\t\t};\n\t\t\tthis.current = 1;\n\t\t\tthis.viewer = viewer;\n\t\t\tthis.settings = Object.assign({}, defaults, options);\n\t\t\tthis.settings.zoomValues = this.settings.zoomValues.sort();\n\t\t}\n\t\tget(zoom = null) {\n\t\t\tif (zoom === null) {\n\t\t\t\treturn this.current;\n\t\t\t}\n\t\t\tif (parseFloat(zoom) == zoom) {\n\t\t\t\treturn zoom;\n\t\t\t}\n\t\t\tlet $activepage = this.viewer.getActivePage();\n\t\t\tlet zoomValues = [];\n\t\t\tswitch (zoom) {\n\t\t\tcase \"in\":\n\t\t\t\tzoom = this.current;\n\t\t\t\tzoomValues = this.settings.zoomValues.filter(x => x > zoom);\n\t\t\t\tif (zoomValues.length > 0) {\n\t\t\t\t\tzoom = Math.min(...zoomValues);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"out\":\n\t\t\t\tzoom = this.current;\n\t\t\t\tzoomValues = this.settings.zoomValues.filter(x => x < zoom);\n\t\t\t\tif (zoomValues.length > 0) {\n\t\t\t\t\tzoom = Math.max(...zoomValues);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"fit\":\n\t\t\t\tzoom = Math.min(this.get(\"width\"), this.get(\"height\"));\n\t\t\t\tbreak;\n\t\t\tcase \"width\":\n\t\t\t\tzoom = this.settings.fillArea * this.viewer.$container.width() / $activepage.data(\"width\");\n\t\t\t\tbreak;\n\t\t\tcase \"height\":\n\t\t\t\tzoom = this.settings.fillArea * this.viewer.$container.height() / $activepage.data(\"height\");\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tzoom = this.current;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn zoom;\n\t\t}\n\t\tzoomPages(zoom) {\n\t\t\tzoom = this.get(zoom);\n\t\t\tthis.viewer.getPages().forEach(function (page) {\n\t\t\t\tlet $page = page.$div;\n\t\t\t\tlet c_width = $page.data(\"width\");\n\t\t\t\tlet c_height = $page.data(\"height\");\n\t\t\t\t$page.width(c_width * zoom).height(c_height * zoom);\n\t\t\t\t$page.data(\"zoom\", zoom);\n\t\t\t\t$page.find(`.${this.viewer.settings.contentClass}`).width(c_width * zoom).height(c_height * zoom);\n\t\t\t}.bind(this));\n\t\t\tthis.current = zoom;\n\t\t}\n\t}\n\tclass PDFjsViewer {\n\t\tversion = \"2.0.0\";\n\t\tconstructor($container, options = {}) {\n\t\t\tthis.settings = Object.assign({}, defaults, options);\n\t\t\tthis._zoom = new Zoomer(this, {\n\t\t\t\tzoomValues: this.settings.zoomValues,\n\t\t\t\tfillArea: this.settings.zoomFillArea\n\t\t\t});\n\t\t\t$container = $($container);\n\t\t\tthis.$container = $container;\n\t\t\t$container.get(0)._pdfjsViewer = this;\n\t\t\tthis._setScrollListener();\n\t\t\tthis.pages = [];\n\t\t\tthis.pdf = null;\n\t\t\tthis._documentReady = false;\n\t\t}\n\t\tsetZoom(zoom) {\n\t\t\tlet container = this.$container.get(0);\n\t\t\tlet prevzoom = this._zoom.current;\n\t\t\tlet prevScroll = {\n\t\t\t\ttop: container.scrollTop,\n\t\t\t\tleft: container.scrollLeft\n\t\t\t};\n\t\t\tthis._zoom.zoomPages(zoom);\n\t\t\tcontainer.scrollLeft = prevScroll.left * this._zoom.current / prevzoom;\n\t\t\tcontainer.scrollTop = prevScroll.top * this._zoom.current / prevzoom;\n\t\t\tthis._visiblePages(true);\n\t\t\tif (this._documentReady) {\n\t\t\t\tif (typeof this.settings.onZoomChange === \"function\") this.settings.onZoomChange.call(this, this._zoom.current);\n\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"zoomchange\", {\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tzoom: this._zoom.current\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t}\n\t\t\treturn this._zoom.current;\n\t\t}\n\t\tgetZoom() {\n\t\t\treturn this._zoom.current;\n\t\t}\n\t\t_cleanPage($page) {\n\t\t\tlet $emptyContent = this.settings.emptyContent();\n\t\t\t$page.find(`.${this.settings.contentClass}`).html(\"\").append($emptyContent);\n\t\t}\n\t\t_setPageContent($page, $content) {\n\t\t\t$page.find(`.${this.settings.contentClass}`).html(\"\").append($content);\n\t\t}\n\t\trefreshAll() {\n\t\t\tthis._visiblePages(true);\n\t\t}\n\t\t_setScrollListener() {\n\t\t\tlet scrollLock = false;\n\t\t\tlet scrollPos = {\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0\n\t\t\t};\n\t\t\tthis.__scrollHandler = function (e) {\n\t\t\t\tif (scrollLock === true) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tscrollLock = true;\n\t\t\t\tlet container = this.$container.get(0);\n\t\t\t\tif (Math.abs(container.scrollTop - scrollPos.top) > container.clientHeight * .2 * this._zoom.current || Math.abs(container.scrollLeft - scrollPos.left) > container.clientWidth * .2 * this._zoom.current) {\n\t\t\t\t\tscrollPos = {\n\t\t\t\t\t\ttop: container.scrollTop,\n\t\t\t\t\t\tleft: container.scrollLeft\n\t\t\t\t\t};\n\t\t\t\t\tthis._visiblePages();\n\t\t\t\t}\n\t\t\t\tscrollLock = false;\n\t\t\t}.bind(this);\n\t\t\tthis.$container.off(\"scroll\");\n\t\t\tthis.$container.on(\"scroll\", this.__scrollHandler);\n\t\t}\n\t\t_createSkeleton(page, i) {\n\t\t\tlet pageinfo = {\n\t\t\t\t$div: null,\n\t\t\t\twidth: 0,\n\t\t\t\theight: 0,\n\t\t\t\tloaded: false\n\t\t\t};\n\t\t\tif (page.getViewport !== undefined) {\n\t\t\t\tlet viewport = page.getViewport({\n\t\t\t\t\trotation: this._rotation,\n\t\t\t\t\tscale: 1\n\t\t\t\t});\n\t\t\t\tpageinfo.width = viewport.width;\n\t\t\t\tpageinfo.height = viewport.height;\n\t\t\t\tpageinfo.loaded = true;\n\t\t\t} else {\n\t\t\t\tpageinfo.width = page.width;\n\t\t\t\tpageinfo.height = page.height;\n\t\t\t}\n\t\t\tconsole.assert(pageinfo.width > 0 && pageinfo.height > 0, \"Page width and height must be greater than 0\");\n\t\t\tpageinfo.$div = $(`
`).attr(\"data-page\", i).data(\"width\", pageinfo.width).data(\"height\", pageinfo.height).data(\"zoom\", this._zoom.current).addClass(this.settings.pageClass).width(pageinfo.width * this._zoom.current).height(pageinfo.height * this._zoom.current);\n\t\t\tlet $content = $(`
`).width(pageinfo.width).height(pageinfo.height);\n\t\t\tpageinfo.$div.append($content);\n\t\t\tthis._cleanPage(pageinfo.$div);\n\t\t\treturn pageinfo;\n\t\t}\n\t\t_placeSkeleton(pageinfo, i) {\n\t\t\tlet prevpage = i - 1;\n\t\t\tlet $prevpage = null;\n\t\t\twhile (prevpage > 0 && ($prevpage = this.$container.find(`.${this.settings.pageClass}[data-page=\"${prevpage}\"]`)).length === 0) {\n\t\t\t\tprevpage--;\n\t\t\t}\n\t\t\tif (prevpage === 0) {\n\t\t\t\tthis.$container.append(pageinfo.$div);\n\t\t\t} else {\n\t\t\t\t$prevpage.after(pageinfo.$div);\n\t\t\t}\n\t\t}\n\t\t_createSkeletons(pageinfo) {\n\t\t\tfor (let i = 1; i <= this.pageCount; i++) {\n\t\t\t\tif (this.pages[i] === undefined) {\n\t\t\t\t\tpageinfo = this._createSkeleton(pageinfo, i);\n\t\t\t\t\tthis.pages[i] = pageinfo;\n\t\t\t\t\tthis._placeSkeleton(pageinfo, i);\n\t\t\t\t\tif (typeof this.settings.onNewPage === \"function\") {\n\t\t\t\t\t\tthis.settings.onNewPage.call(this, pageinfo.$div.get(0), i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"newpage\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tpageNumber: i,\n\t\t\t\t\t\t\tpage: pageinfo.$div.get(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_setActivePage(i) {\n\t\t\tif (this._activePage !== i) {\n\t\t\t\tthis._activePage = i;\n\t\t\t\tlet activePage = this.getActivePage();\n\t\t\t\tif (this._documentReady) {\n\t\t\t\t\tactivePage = activePage == null ? null : activePage.get(0);\n\t\t\t\t\tif (typeof this.settings.onActivePageChanged === \"function\") {\n\t\t\t\t\t\tthis.settings.onActivePageChanged.call(this, activePage, i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"activepagechanged\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tactivePageNumber: i,\n\t\t\t\t\t\t\tactivePage: activePage\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_areaOfPageVisible($page) {\n\t\t\tif ($page === undefined) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tlet c_offset = this.$container.offset();\n\t\t\tlet c_width = this.$container.width();\n\t\t\tlet c_height = this.$container.height();\n\t\t\tlet position = $page.offset();\n\t\t\tposition.top -= c_offset.top;\n\t\t\tposition.left -= c_offset.left;\n\t\t\tposition.bottom = position.top + $page.outerHeight();\n\t\t\tposition.right = position.left + $page.outerWidth();\n\t\t\tlet page_y0 = Math.min(Math.max(position.top, 0), c_height);\n\t\t\tlet page_y1 = Math.min(Math.max($page.outerHeight() + position.top, 0), c_height);\n\t\t\tlet page_x0 = Math.min(Math.max(position.left, 0), c_width);\n\t\t\tlet page_x1 = Math.min(Math.max($page.outerWidth() + position.left, 0), c_width);\n\t\t\tlet vis_x = page_x1 - page_x0;\n\t\t\tlet vis_y = page_y1 - page_y0;\n\t\t\treturn vis_x * vis_y;\n\t\t}\n\t\tisPageVisible(i) {\n\t\t\tif (this.pdf === null || i === undefined || i === null || i < 1 || i > this.pdf.numPages) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (typeof i === \"string\") {\n\t\t\t\ti = parseInt(i);\n\t\t\t}\n\t\t\tlet $page = i;\n\t\t\tif (typeof i === \"number\") {\n\t\t\t\tif (this.pages[i] === undefined) return false;\n\t\t\t\t$page = this.pages[i].$div;\n\t\t\t}\n\t\t\treturn this._areaOfPageVisible($page) > $page.outerWidth() * $page.outerHeight() * this.settings.visibleThreshold;\n\t\t}\n\t\t_visiblePages(forceRedraw = false) {\n\t\t\tlet max_area = 0;\n\t\t\tlet i_page = null;\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\tthis._visibles = [];\n\t\t\t\tthis._setActivePage(0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet $visibles = this.pages.filter(function (pageinfo) {\n\t\t\t\tlet areaVisible = this._areaOfPageVisible(pageinfo.$div);\n\t\t\t\tif (areaVisible > max_area) {\n\t\t\t\t\tmax_area = areaVisible;\n\t\t\t\t\ti_page = pageinfo.$div.data(\"page\");\n\t\t\t\t}\n\t\t\t\treturn areaVisible > 0;\n\t\t\t}.bind(this)).map(x => x.$div);\n\t\t\tthis._setActivePage(i_page);\n\t\t\tlet visibles = $visibles.map(x => {\n\t\t\t\treturn parseInt($(x).data(\"page\"));\n\t\t\t});\n\t\t\tif (visibles.length > 0) {\n\t\t\t\tlet minVisible = Math.min(...visibles);\n\t\t\t\tlet maxVisible = Math.max(...visibles);\n\t\t\t\tfor (let i = Math.max(1, minVisible - this.settings.extraPagesToLoad); i < minVisible; i++) {\n\t\t\t\t\tif (!visibles.includes(i)) visibles.push(i);\n\t\t\t\t}\n\t\t\t\tfor (let i = maxVisible + 1; i <= Math.min(maxVisible + this.settings.extraPagesToLoad, this.pdf.numPages); i++) {\n\t\t\t\t\tif (!visibles.includes(i)) visibles.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet nowVisibles = visibles;\n\t\t\tif (!forceRedraw) {\n\t\t\t\tnowVisibles = visibles.filter(function (x) {\n\t\t\t\t\treturn !this._visibles.includes(x);\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tthis._visibles.filter(function (x) {\n\t\t\t\treturn !visibles.includes(x);\n\t\t\t}).forEach(function (i) {\n\t\t\t\tthis._cleanPage(this.pages[i].$div);\n\t\t\t}.bind(this));\n\t\t\tthis._visibles = visibles;\n\t\t\tthis.loadPages(...nowVisibles);\n\t\t}\n\t\tloadPages(...pages) {\n\t\t\tthis._pagesLoading.push(...pages);\n\t\t\tif (this._loading) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._loadingTask();\n\t\t}\n\t\t_loadingTask() {\n\t\t\tthis._loading = true;\n\t\t\tif (this._pagesLoading.length > 0) {\n\t\t\t\tlet pagei = this._pagesLoading.shift();\n\t\t\t\tthis.pdf.getPage(pagei).then(function (page) {\n\t\t\t\t\tthis._renderPage(page, pagei);\n\t\t\t\t}.bind(this)).then(function (pageinfo) {\n\t\t\t\t\tif (this._pagesLoading.length > 0) {\n\t\t\t\t\t\tthis._loadingTask();\n\t\t\t\t\t}\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tthis._loading = false;\n\t\t}\n\t\tscrollToPage(i) {\n\t\t\tif (this.pages.length === 0 || this.pages[i] === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet $page = this.pages[i].$div;\n\t\t\tif ($page.length === 0) {\n\t\t\t\tconsole.warn(`Page ${i} not found`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet position = $page.position();\n\t\t\tlet containerPosition = this.$container.position();\n\t\t\tif (position !== undefined) {\n\t\t\t\tthis.$container.get(0).scrollTop = this.$container.get(0).scrollTop + position.top - containerPosition.top;\n\t\t\t\tthis.$container.get(0).scrollLeft = this.$container.get(0).scrollLeft + position.left - containerPosition.left;\n\t\t\t}\n\t\t\tthis._setActivePage(i);\n\t\t}\n\t\t_renderPage(page, i) {\n\t\t\tlet pageinfo = this.pages[i];\n\t\t\tlet scale = this.settings.renderingScale;\n\t\t\tlet pixel_ratio = window.devicePixelRatio || 1;\n\t\t\tlet viewport = page.getViewport({\n\t\t\t\trotation: this._rotation,\n\t\t\t\tscale: this._zoom.current * scale\n\t\t\t});\n\t\t\tpageinfo.width = viewport.width / this._zoom.current / scale;\n\t\t\tpageinfo.height = viewport.height / this._zoom.current / scale;\n\t\t\tpageinfo.$div.data(\"width\", pageinfo.width);\n\t\t\tpageinfo.$div.data(\"height\", pageinfo.height);\n\t\t\tpageinfo.$div.width(pageinfo.width * this._zoom.current);\n\t\t\tpageinfo.$div.height(pageinfo.height * this._zoom.current);\n\t\t\tpageinfo.loaded = true;\n\t\t\tlet $canvas = $(\"\");\n\t\t\tlet canvas = $canvas.get(0);\n\t\t\tlet context = canvas.getContext(\"2d\");\n\t\t\tcanvas.height = viewport.height * pixel_ratio;\n\t\t\tcanvas.width = viewport.width * pixel_ratio;\n\t\t\tcanvas.getContext(\"2d\");\n\t\t\tvar transform = pixel_ratio !== 1 ? [pixel_ratio, 0, 0, pixel_ratio, 0, 0] : null;\n\t\t\tvar renderContext = {\n\t\t\t\tcanvasContext: context,\n\t\t\t\tviewport: viewport,\n\t\t\t\ttransform: transform\n\t\t\t};\n\t\t\treturn page.render(renderContext).promise.then(function () {\n\t\t\t\tthis._setPageContent(pageinfo.$div, $canvas);\n\t\t\t\tif (this._documentReady) {\n\t\t\t\t\tif (typeof this.settings.onPageRender === \"function\") {\n\t\t\t\t\t\tthis.settings.onPageRender.call(this, pageinfo.$div.get(0), i);\n\t\t\t\t\t}\n\t\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"pagerender\", {\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tpageNumber: i,\n\t\t\t\t\t\t\tpage: pageinfo.$div.get(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\treturn pageinfo;\n\t\t\t}.bind(this));\n\t\t}\n\t\tgetActivePage() {\n\t\t\tif (this._activePage === null || this.pdf === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (this._activePage < 1 || this._activePage > this.pdf.numPages) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.pages[this._activePage].$div;\n\t\t}\n\t\tgetPages() {\n\t\t\treturn this.pages;\n\t\t}\n\t\tgetPageCount() {\n\t\t\tif (this.pdf === null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn this.pdf.numPages;\n\t\t}\n\t\tnext() {\n\t\t\tif (this._activePage < this.pdf.numPages) {\n\t\t\t\tthis.scrollToPage(this._activePage + 1);\n\t\t\t}\n\t\t}\n\t\tprev() {\n\t\t\tif (this._activePage > 1) {\n\t\t\t\tthis.scrollToPage(this._activePage - 1);\n\t\t\t}\n\t\t}\n\t\tfirst() {\n\t\t\tif (this._activePage !== 1) {\n\t\t\t\tthis.scrollToPage(1);\n\t\t\t}\n\t\t}\n\t\tlast() {\n\t\t\tif (this.pdf === null) return;\n\t\t\tif (this._activePage !== this.pdf.numPages) {\n\t\t\t\tthis.scrollToPage(this.pdf.numPages);\n\t\t\t}\n\t\t}\n\t\trotate(deg, accumulate = false) {\n\t\t\tif (accumulate) {\n\t\t\t\tdeg = deg + this._rotation;\n\t\t\t}\n\t\t\tthis._rotation = deg;\n\t\t\tlet container = this.$container.get(0);\n\t\t\tlet prevScroll = {\n\t\t\t\ttop: container.scrollTop,\n\t\t\t\tleft: container.scrollLeft,\n\t\t\t\theight: container.scrollHeight,\n\t\t\t\twidth: container.scrollWidth\n\t\t\t};\n\t\t\treturn this.forceViewerInitialization().then(function () {\n\t\t\t\tlet newScroll = {\n\t\t\t\t\ttop: container.scrollTop,\n\t\t\t\t\tleft: container.scrollLeft,\n\t\t\t\t\theight: container.scrollHeight,\n\t\t\t\t\twidth: container.scrollWidth\n\t\t\t\t};\n\t\t\t\tcontainer.scrollTop = prevScroll.top * (newScroll.height / prevScroll.height);\n\t\t\t\tcontainer.scrollLeft = prevScroll.left * (newScroll.width / prevScroll.width);\n\t\t\t}.bind(this));\n\t\t}\n\t\tforceViewerInitialization() {\n\t\t\tthis.pages = [];\n\t\t\tthis.$container.find(`.${this.settings.pageClass}`).remove();\n\t\t\tthis._pagesLoading = [];\n\t\t\tthis._loading = false;\n\t\t\tthis._visibles = [];\n\t\t\tthis._activePage = null;\n\t\t\treturn this.pdf.getPage(1).then(function (page) {\n\t\t\t\tthis._createSkeletons(page);\n\t\t\t\tthis._visiblePages();\n\t\t\t\tthis._setActivePage(1);\n\t\t\t}.bind(this));\n\t\t}\n\t\tasync loadDocument(document) {\n\t\t\tthis._documentReady = false;\n\t\t\tthis.pages = [];\n\t\t\tthis.$container.find(`.${this.settings.pageClass}`).remove();\n\t\t\tthis.pdf = null;\n\t\t\tlet loadingTask = pdfjsLib.getDocument(document);\n\t\t\treturn loadingTask.promise.then(function (pdf) {\n\t\t\t\tthis.pdf = pdf;\n\t\t\t\tthis.pageCount = pdf.numPages;\n\t\t\t\tthis._rotation = 0;\n\t\t\t\treturn this.forceViewerInitialization();\n\t\t\t}.bind(this)).then(function () {\n\t\t\t\tif (typeof this.settings.onDocumentReady === \"function\") {\n\t\t\t\t\tthis.settings.onDocumentReady.call(this);\n\t\t\t\t}\n\t\t\t\tthis.$container.get(0).dispatchEvent(new CustomEvent(\"documentready\", {\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tdocument: this.pdf\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t\tthis._setActivePage(0);\n\t\t\t\tthis._documentReady = true;\n\t\t\t\tthis._setActivePage(1);\n\t\t\t}.bind(this));\n\t\t}\n\t}\n\n\tfunction recoverAttributes(target, attributeDefaults) {\n\t\tconst camelcaseToSnakecase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);\n\t\tlet $target = $(target);\n\t\tlet result = {};\n\t\tif ($target.length > 0) {\n\t\t\t$target = $($target[0]);\n\t\t\tfor (let originalAttributeName in attributeDefaults) {\n\t\t\t\tlet attributeName = camelcaseToSnakecase(originalAttributeName);\n\t\t\t\tlet attributeValue = $target.attr(attributeName);\n\t\t\t\tif (attributeValue != null) {\n\t\t\t\t\tswitch (typeof attributeDefaults[originalAttributeName]) {\n\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tattributeValue = parseFloat(attributeValue);\n\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"number\":\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tattributeValue = parseInt(attributeValue);\n\t\t\t\t\t\t} catch (_) {}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"function\":\n\t\t\t\t\t\tlet functionString = attributeValue;\n\t\t\t\t\t\tattributeValue = function () {\n\t\t\t\t\t\t\teval(functionString);\n\t\t\t\t\t\t}.bind(target[0]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tresult[originalAttributeName] = attributeValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction init(element) {\n\t\tlet options = recoverAttributes(element, Object.assign({\n\t\t\tpdfDocument: \"\",\n\t\t\tinitialZoom: \"\"\n\t\t}, defaults));\n\t\tif (options[\"pdfDocument\"] != null) {\n\t\t\tlet pdfViewer = new PDFjsViewer($(element), options);\n\t\t\tpdfViewer.loadDocument(options[\"pdfDocument\"]).then(function () {\n\t\t\t\tif (options[\"initialZoom\"] != null) {\n\t\t\t\t\tpdfViewer.setZoom(options[\"initialZoom\"]);\n\t\t\t\t}\n\t\t\t});\n\t\t\telement.get(0).pdfViewer = pdfViewer;\n\t\t}\n\t}\n\t$(function () {\n\t\t$(\".pdfjs-viewer\").each(function () {\n\t\t\tlet $viewer = $(this);\n\t\t\tinit($viewer);\n\t\t});\n\t});\n\texports.PDFjsViewer = PDFjsViewer;\n})(window, window._$ ?? window.jQuery ?? undefined);\n"],"names":["exports","$","undefined","console","error","let","defaults","visibleThreshold","extraPagesToLoad","pageClass","contentClass","onDocumentReady","onNewPage","page","i","onPageRender","zoomValues","onZoomChange","zoomlevel","onActivePageChanged","zoomFillArea","emptyContent","renderingScale","Zoomer","constructor","viewer","options","fillArea","this","current","settings","Object","assign","sort","get","zoom","parseFloat","$activepage","getActivePage","filter","x","length","Math","min","max","$container","width","data","height","zoomPages","getPages","forEach","$page","$div","c_width","c_height","find","bind","PDFjsViewer","version","_zoom","_pdfjsViewer","_setScrollListener","pages","pdf","_documentReady","setZoom","container","prevzoom","prevScroll","top","scrollTop","left","scrollLeft","_visiblePages","call","dispatchEvent","CustomEvent","detail","getZoom","_cleanPage","$emptyContent","html","append","_setPageContent","$content","refreshAll","scrollLock","scrollPos","__scrollHandler","e","abs","clientHeight","clientWidth","off","on","_createSkeleton","pageinfo","loaded","getViewport","viewport","rotation","_rotation","scale","assert","attr","addClass","_placeSkeleton","prevpage","$prevpage","after","_createSkeletons","pageCount","pageNumber","_setActivePage","_activePage","activePage","activePageNumber","_areaOfPageVisible","c_offset","offset","position","bottom","outerHeight","right","outerWidth","page_y0","page_y1","page_x0","page_x1","vis_x","vis_y","isPageVisible","numPages","parseInt","forceRedraw","max_area","i_page","_visibles","$visibles","areaVisible","map","visibles","minVisible","maxVisible","includes","push","nowVisibles","loadPages","_pagesLoading","_loading","_loadingTask","pagei","shift","getPage","then","_renderPage","scrollToPage","warn","containerPosition","pixel_ratio","window","devicePixelRatio","$canvas","canvas","context","getContext","transform","renderContext","canvasContext","render","promise","getPageCount","next","prev","first","last","rotate","deg","accumulate","scrollHeight","scrollWidth","forceViewerInitialization","newScroll","remove","loadDocument","document","loadingTask","pdfjsLib","getDocument","recoverAttributes","target","attributeDefaults","camelcaseToSnakecase","str","replace","letter","toLowerCase","$target","result","originalAttributeName","attributeName","attributeValue","_","functionString","eval","init","element","pdfDocument","initialZoom","pdfViewer","each","$viewer","_$","jQuery"],"mappings":"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"} -------------------------------------------------------------------------------- /js/pdfjs-viewer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Carlos de Alfonso (https://github.com/dealfonso) 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | (function(exports, $) { 17 | 'use strict'; 18 | 19 | if ($ === undefined) { 20 | console.error("jQuery-like library not available"); 21 | return; 22 | } 23 | 24 | let defaults = { 25 | // Threshold to consider that a page is visible 26 | visibleThreshold: 0.5, 27 | // Number of extra pages to load (appart from the visible) 28 | extraPagesToLoad: 3, 29 | // The class used for each page (the div that wraps the content of the page) 30 | pageClass: "pdfpage", 31 | // Prefix of the id used for each page (the page id will be -) 32 | pageIdPrefix: "page", 33 | // The class used for the content of each page (the div that contains the page) 34 | contentClass: "content-wrapper", 35 | // Function called when a document has been loaded and its structure has been created 36 | onDocumentReady: () => {}, 37 | // Function called when a new page is created (it is bound to the object, and receives a html object as parameter, and the page number) 38 | onNewPage: (page, i) => {}, 39 | // Function called when a page is rendered (it is bound to the object, and receives a html object as parameter, and the page number) 40 | onPageRender: (page, i) => {}, 41 | // Posible zoom values to iterate over using "in" and "out" 42 | zoomValues: [ 0.25, 0.5, 0.75, 1, 1.25, 1.50, 2, 4, 8 ], 43 | // Function called when the zoom level changes (it receives the zoom level) 44 | onZoomChange: (zoomlevel) => {}, 45 | // Function called whenever the active page is changed (the active page is the one that is shown in the viewer) 46 | onActivePageChanged: (page, i) => {}, 47 | // Percentage of the container that will be filled with the page 48 | zoomFillArea: 0.95, 49 | // Function called to get the content of an empty page 50 | emptyContent: () => $('
'), 51 | // The scale to which the pages are rendered (1.5 is the default value for the PDFjs viewer); a higher value will render the pages with a higher resolution 52 | // but it will consume more memory and CPU. A lower value will render the pages with a lower resolution, but they will be uglier. 53 | renderingScale: 1.5, 54 | } 55 | 56 | // Class used to help in zoom management; probably it can be moved to the main class, but it is used to group methods 57 | class Zoomer { 58 | /** 59 | * Construct the helper class 60 | * @param {PDFjsViewer} viewer - the viewer object 61 | * @param {*} options - the options object 62 | */ 63 | constructor(viewer, options = {}) { 64 | let defaults = { 65 | // The possible zoom values to iterate through using "in" and "out" 66 | zoomValues: [ 0.25, 0.5, 0.75, 1, 1.25, 1.50, 2, 4, 8 ], 67 | // The area to fill the container with the zoomed pages 68 | fillArea: 0.9, 69 | } 70 | 71 | // The current zooom value 72 | this.current = 1; 73 | // The viewer instance whose pages may be zoomed 74 | this.viewer = viewer; 75 | // The settings 76 | this.settings = Object.assign({}, defaults, options); 77 | 78 | // Need having the zoom values in order 79 | this.settings.zoomValues = this.settings.zoomValues.sort(); 80 | } 81 | 82 | /** Translates a zoom value into a float value; possible values: 83 | * - a float value 84 | * - a string with a keyword (e.g. "width", "height", "fit", "in", "out") 85 | * @param {number} zoom - the zoom value to be translated 86 | * @return {number} The zoom value 87 | */ 88 | get(zoom = null) { 89 | // If no zoom is specified, return the current one 90 | if (zoom === null) { 91 | return this.current; 92 | } 93 | // If it is a number, return it 94 | if (parseFloat(zoom) == zoom) { 95 | return zoom; 96 | } 97 | let $activepage = this.viewer.getActivePage(); 98 | let zoomValues = []; 99 | // If it is a keyword, return the corresponding value 100 | switch(zoom) { 101 | case "in": 102 | zoom = this.current; 103 | zoomValues = this.settings.zoomValues.filter((x) => x > zoom); 104 | if (zoomValues.length > 0) { 105 | zoom = Math.min(...zoomValues); 106 | } 107 | break; 108 | case "out": 109 | zoom = this.current; 110 | zoomValues = this.settings.zoomValues.filter((x) => x < zoom); 111 | if (zoomValues.length > 0) { 112 | zoom = Math.max(...zoomValues); 113 | } 114 | break; 115 | case "fit": 116 | zoom = Math.min(this.get("width"), this.get("height")); 117 | break; 118 | case "width": 119 | zoom = this.settings.fillArea * this.viewer.$container.width() / $activepage.data("width"); 120 | break; 121 | case "height": 122 | zoom = this.settings.fillArea * this.viewer.$container.height() / $activepage.data("height"); 123 | break; 124 | default: 125 | zoom = this.current; 126 | break; 127 | } 128 | return zoom; 129 | } 130 | 131 | /** 132 | * Sets the zoom value to each page (changes both the page and the content div); relies on the data-values for the page 133 | * @param {number} zoom - the zoom value to be set 134 | */ 135 | zoomPages(zoom) { 136 | zoom = this.get(zoom); 137 | this.viewer.getPages().forEach(function(page) { 138 | let $page = page.$div; 139 | let c_width = $page.data("width"); 140 | let c_height = $page.data("height"); 141 | 142 | $page.width(c_width * zoom).height(c_height * zoom); 143 | $page.data('zoom', zoom); 144 | $page.find(`.${this.viewer.settings.contentClass}`).width(c_width * zoom).height(c_height * zoom); 145 | }.bind(this)); 146 | this.current = zoom; 147 | } 148 | } 149 | 150 | class PDFjsViewer { 151 | // The version of the viewer 152 | version = "2.0.0"; 153 | 154 | /** 155 | * Constructs the object, and initializes actions: 156 | * - add the scroll handler to the container 157 | * - set the first adjusting action when the page is loaded 158 | * - creates the zoom helper 159 | * @param {jQuery} $container the jQuery value that will hold the pages 160 | * @param {dictionary} options options for the viewer 161 | */ 162 | constructor($container, options = {}) { 163 | 164 | this.settings = Object.assign({}, defaults, options); 165 | 166 | // Create the zoomer helper 167 | this._zoom = new Zoomer(this, { 168 | zoomValues: this.settings.zoomValues, 169 | fillArea: this.settings.zoomFillArea, 170 | }); 171 | 172 | $container = $($container); 173 | 174 | // Store the container 175 | this.$container = $container; 176 | 177 | // Add a reference to this object to the container 178 | $container.get(0)._pdfjsViewer = this; 179 | 180 | // Add the event listeners 181 | this._setScrollListener(); 182 | 183 | // Initialize some variables 184 | this.pages = []; 185 | this.pdf = null; 186 | 187 | // Whether the document is ready or not 188 | this._documentReady = false; 189 | } 190 | 191 | /** 192 | * Sets the current zoom level and applies it to all the pages 193 | * @param {number} zoom the desired zoom level, which will be a value (1 equals to 100%), or the keywords 'in', 'out', 'width', 'height' or 'fit' 194 | */ 195 | setZoom(zoom) { 196 | let container = this.$container.get(0); 197 | 198 | // Get the previous zoom and scroll position 199 | let prevzoom = this._zoom.current; 200 | let prevScroll = { 201 | top: container.scrollTop, 202 | left: container.scrollLeft 203 | }; 204 | 205 | // Now zoom the pages 206 | this._zoom.zoomPages(zoom); 207 | 208 | // Update the scroll position (to match the previous one), according to the new relationship of zoom 209 | container.scrollLeft = prevScroll.left * this._zoom.current / prevzoom; 210 | container.scrollTop = prevScroll.top * this._zoom.current / prevzoom; 211 | 212 | // Force to redraw the visible pages to upgrade the resolution 213 | this._visiblePages(true); 214 | 215 | // Call the callback (if provided) 216 | if (this._documentReady) { 217 | if (typeof this.settings.onZoomChange === "function") 218 | this.settings.onZoomChange.call(this, this._zoom.current); 219 | this.$container.get(0).dispatchEvent(new CustomEvent("zoomchange", { detail: { zoom: this._zoom.current } })); 220 | } 221 | 222 | return this._zoom.current; 223 | } 224 | 225 | /** 226 | * Obtain the current zoom level 227 | * @returns {number} the current zoom level 228 | */ 229 | getZoom() { 230 | return this._zoom.current; 231 | } 232 | 233 | /** 234 | * Function that removes the content of a page and replaces it with the empty content (i.e. a content generated by function emptyContent) 235 | * such content will not be visible except for the time that the 236 | * @param {jQuery} $page the page to be emptied 237 | */ 238 | _cleanPage($page) { 239 | let $emptyContent = this.settings.emptyContent(); 240 | $page.find(`.${this.settings.contentClass}`).html("").append($emptyContent) 241 | } 242 | 243 | /** 244 | * Function that replaces the content with the empty class in a page with a new content 245 | * @param {*} $page the page to be modified 246 | * @param {*} $content the new content that will be set in the page 247 | */ 248 | _setPageContent($page, $content) { 249 | $page.find(`.${this.settings.contentClass}`).html("").append($content) 250 | } 251 | 252 | /** 253 | * Recalculates which pages are now visible and forces redrawing them (moreover it cleans those not visible) 254 | */ 255 | refreshAll() { 256 | this._visiblePages(true); 257 | } 258 | 259 | /** Function that creates a scroll handler to update the active page and to load more pages as the scroll position changes */ 260 | _setScrollListener() { 261 | // Create a scroll handler that prevents reentrance if called multiple times and the loading of pages is not finished 262 | let scrollLock = false; 263 | let scrollPos = { top:0 , left:0 }; 264 | this.__scrollHandler = function(e) { 265 | // Avoid re-entrance for the same event while loading pages 266 | if (scrollLock === true) { 267 | return; 268 | } 269 | scrollLock = true; 270 | 271 | let container = this.$container.get(0); 272 | if ((Math.abs(container.scrollTop - scrollPos.top) > (container.clientHeight * 0.2 * this._zoom.current)) || 273 | (Math.abs(container.scrollLeft - scrollPos.left) > (container.clientWidth * 0.2 * this._zoom.current))) { 274 | scrollPos = { 275 | top: container.scrollTop, 276 | left: container.scrollLeft 277 | } 278 | this._visiblePages(); 279 | } 280 | 281 | scrollLock = false; 282 | }.bind(this); 283 | 284 | // Set the scroll handler 285 | this.$container.off('scroll'); 286 | this.$container.on('scroll', this.__scrollHandler); 287 | } 288 | /** 289 | * Function that creates the pageinfo structure for one page, along with the skeleton to host the page (i.e.
) 290 | * If the page is a pageinfo, the new pageinfo structure will not rely on the size (it will copy it, but it won't be marked as loaded). If it is a page, the size will 291 | * be calculated from the viewport and it will be marked as loaded. 292 | * This is done in this way, because when creating the pages in the first time, they will be created assuming that they are of the same size than the first one. If they 293 | * are not, the size will be adjusted later, when the pages are loaded. 294 | * 295 | * @param {*} page - the pageinfo (or the page) from which to create the pageinfo structure 296 | * @param {*} i - the number of the page to be created 297 | * @returns pageinfo - the pageinfo structure for the page 298 | */ 299 | _createSkeleton(page, i) { 300 | let pageinfo = { 301 | $div: null, 302 | width: 0, 303 | height: 0, 304 | loaded: false, 305 | }; 306 | 307 | // If it is a page, the size will be obtained from the viewport; otherwise, it will be copied from the provided pageinfo 308 | if (page.getViewport !== undefined) { 309 | let viewport = page.getViewport({rotation:this._rotation,scale:1}); 310 | pageinfo.width = viewport.width; 311 | pageinfo.height = viewport.height; 312 | pageinfo.loaded = true; 313 | } else { 314 | pageinfo.width = page.width; 315 | pageinfo.height = page.height; 316 | } 317 | console.assert(((pageinfo.width > 0) && (pageinfo.height > 0)), "Page width and height must be greater than 0"); 318 | 319 | // Now create the skeleton for the divs 320 | pageinfo.$div = $(`
`) 321 | .attr('data-page', i) 322 | .data('width', pageinfo.width) 323 | .data('height', pageinfo.height) 324 | .data('zoom', this._zoom.current) 325 | .addClass(this.settings.pageClass) 326 | .width(pageinfo.width * this._zoom.current) 327 | .height(pageinfo.height * this._zoom.current); 328 | 329 | let $content = $(`
`) 330 | .width(pageinfo.width) 331 | .height(pageinfo.height); 332 | 333 | pageinfo.$div.append($content); 334 | 335 | // Clean the page (i.e. put the empty content, etc.) 336 | this._cleanPage(pageinfo.$div); 337 | 338 | return pageinfo; 339 | } 340 | 341 | /** 342 | * This function places the page.$div in the container, according to its page number (i.e. it searches for the previous page and puts this page after) 343 | * * in principle, this method sould not be needed because all the pages are put in order; but this is created just in case it is needed in further versions 344 | * @param {*} pageinfo - the pageinfo structure for the page (needs a valid $div) 345 | * @param {*} i - the number of the page 346 | */ 347 | _placeSkeleton(pageinfo, i) { 348 | let prevpage = i - 1; 349 | let $prevpage = null; 350 | while ((prevpage>0) && (($prevpage = this.$container.find(`.${this.settings.pageClass}[data-page="${prevpage}"]`)).length === 0)) { 351 | prevpage--; 352 | } 353 | if (prevpage === 0) { 354 | this.$container.append(pageinfo.$div); 355 | } 356 | else { 357 | $prevpage.after(pageinfo.$div); 358 | } 359 | } 360 | 361 | /** 362 | * Creates the initial skeletons for all the pages, and places them into the container 363 | * @param {page/pageinfo} pageinfo - the initial pageinfo (or page) structure 364 | */ 365 | _createSkeletons(pageinfo) { 366 | for (let i = 1; i <= this.pageCount; i++) { 367 | if (this.pages[i] === undefined) { 368 | 369 | // Create the pageinfo structure, store it and place it in the appropriate place (the next page will be created similar to the previous one) 370 | pageinfo = this._createSkeleton(pageinfo, i); 371 | this.pages[i] = pageinfo; 372 | this._placeSkeleton(pageinfo, i); 373 | 374 | // Call the callback function (if provided) 375 | if (typeof this.settings.onNewPage === "function") { 376 | this.settings.onNewPage.call(this, pageinfo.$div.get(0), i); 377 | } 378 | this.$container.get(0).dispatchEvent(new CustomEvent("newpage", { detail: { pageNumber: i, page: pageinfo.$div.get(0) } })); 379 | } 380 | } 381 | } 382 | 383 | /** 384 | * Function to set the active page, and calling the callback (if provided) 385 | * @param {*} i - the number of the page to set active 386 | */ 387 | _setActivePage(i) { 388 | if (this._activePage !== i) { 389 | this._activePage = i; 390 | let activePage = this.getActivePage(); 391 | if (this._documentReady) { 392 | activePage = activePage==null?null:activePage.get(0); 393 | if (typeof this.settings.onActivePageChanged === "function") { 394 | this.settings.onActivePageChanged.call(this, activePage, i); 395 | } 396 | this.$container.get(0).dispatchEvent(new CustomEvent("activepagechanged", { detail: { activePageNumber: i, activePage: activePage } })); 397 | } 398 | } 399 | } 400 | 401 | /** 402 | * Obtains the area of a div that falls in the viewer 403 | * @param {*} $page - div whose area is to be calculated 404 | * @returns the visible area 405 | */ 406 | _areaOfPageVisible($page) { 407 | if ($page === undefined) { 408 | return 0; 409 | } 410 | let c_offset = this.$container.offset(); 411 | let c_width = this.$container.width(); 412 | let c_height = this.$container.height(); 413 | let position = $page.offset(); 414 | position.top -= c_offset.top; 415 | position.left -= c_offset.left; 416 | position.bottom = position.top + $page.outerHeight(); 417 | position.right = position.left + $page.outerWidth(); 418 | let page_y0 = Math.min(Math.max(position.top, 0), c_height); 419 | let page_y1 = Math.min(Math.max($page.outerHeight() + position.top, 0), c_height); 420 | let page_x0 = Math.min(Math.max(position.left, 0), c_width); 421 | let page_x1 = Math.min(Math.max($page.outerWidth() + position.left, 0), c_width); 422 | let vis_x = page_x1 - page_x0; 423 | let vis_y = page_y1 - page_y0; 424 | return (vis_x * vis_y); 425 | } 426 | 427 | /** 428 | * Function that returns true if the page is considered to be visible (the amount of visible area is greater than the threshold) 429 | * @param {*} i - the number of page to check 430 | * @returns true if the page is visible 431 | */ 432 | isPageVisible(i) { 433 | if ((this.pdf === null) || (i === undefined) || (i === null) || (i < 1) || (i > this.pdf.numPages)) { 434 | return false; 435 | } 436 | if (typeof i === "string") { 437 | i = parseInt(i); 438 | } 439 | let $page = i; 440 | if (typeof i === "number") { 441 | if (this.pages[i] === undefined) 442 | return false; 443 | $page = this.pages[i].$div; 444 | } 445 | return this._areaOfPageVisible($page) > ($page.outerWidth() * $page.outerHeight() * this.settings.visibleThreshold); 446 | } 447 | 448 | /** 449 | * Function that calculates which pages are visible in the viewer, draws them (if not already drawn), and clears those not visible 450 | * @param {*} forceRedraw - if true, the visible pages will be redrawn regardless of whether they are already drawn (useful for zoom changes) 451 | */ 452 | _visiblePages(forceRedraw = false) { 453 | // Will grab the page with the greater visible area to set it as active 454 | let max_area = 0; 455 | let i_page = null; 456 | 457 | // If there are no visible pages, return 458 | if (this.pages.length === 0) { 459 | this._visibles = []; 460 | this._setActivePage(0); 461 | return; 462 | } 463 | 464 | // Calculate the visible area for each page and consider it visible if the visible area is greater than 0 465 | let $visibles = this.pages.filter(function(pageinfo) { 466 | let areaVisible = this._areaOfPageVisible(pageinfo.$div); 467 | if (areaVisible > max_area) { 468 | max_area = areaVisible; 469 | i_page = pageinfo.$div.data('page'); 470 | } 471 | return areaVisible > 0; 472 | }.bind(this)).map((x) => x.$div); 473 | 474 | // Set the active page 475 | this._setActivePage(i_page); 476 | 477 | // Now get the visible pages 478 | let visibles = $visibles.map((x) => { 479 | return parseInt($(x).data('page')) 480 | }); 481 | if (visibles.length > 0) { 482 | // Now will add some extra pages (before and after) the visible ones, to have them prepared in case of scroll 483 | let minVisible = Math.min(...visibles); 484 | let maxVisible = Math.max(...visibles); 485 | 486 | for (let i = Math.max(1, minVisible - this.settings.extraPagesToLoad) ; i < minVisible ; i++) { 487 | if (!visibles.includes(i)) 488 | visibles.push(i) 489 | } 490 | for (let i = maxVisible + 1; i <= Math.min(maxVisible + this.settings.extraPagesToLoad, this.pdf.numPages); i++) { 491 | if (!visibles.includes(i)) 492 | visibles.push(i) 493 | } 494 | } 495 | 496 | // Now will draw the visible pages, but if not forcing, will only draw those that were not visible before 497 | let nowVisibles = visibles; 498 | if (! forceRedraw) { 499 | nowVisibles = visibles.filter(function (x) { 500 | return !this._visibles.includes(x) 501 | }.bind(this)); 502 | } 503 | 504 | // Get the pages that were visible before, that are not visible now, and clear them 505 | this._visibles.filter(function (x) { 506 | return !visibles.includes(x) 507 | }).forEach(function (i) { 508 | this._cleanPage(this.pages[i].$div); 509 | }.bind(this)) 510 | 511 | // Store the new visible pages 512 | this._visibles = visibles; 513 | 514 | // And now we'll queue the pages to load 515 | this.loadPages(...nowVisibles); 516 | } 517 | 518 | /** 519 | * Function queue a set of pages to be loaded; if not loading, the function starts the loading worker 520 | * @param {...pageinfo} pages - the pages to load 521 | */ 522 | loadPages(...pages) { 523 | this._pagesLoading.push(...pages); 524 | if (this._loading) { 525 | return; 526 | } 527 | this._loadingTask(); 528 | } 529 | 530 | /** 531 | * Function that gets the pages pending to load and renders them sequentially (to avoid multiple rendering promises) 532 | */ 533 | _loadingTask() { 534 | this._loading = true; 535 | if (this._pagesLoading.length > 0) { 536 | let pagei = this._pagesLoading.shift(); 537 | this.pdf.getPage(pagei).then(function(page) { 538 | // Render the page and update the information about the page with the loaded values 539 | this._renderPage(page, pagei); 540 | }.bind(this)).then(function(pageinfo) { 541 | // Once loaded, we are not loading anymore 542 | if (this._pagesLoading.length > 0) { 543 | this._loadingTask(); 544 | } 545 | }.bind(this)); 546 | } 547 | // Free the loading state 548 | this._loading = false; 549 | } 550 | 551 | /** 552 | * Function that sets the scroll position of the container to the specified page 553 | * @param {*} i - the number of the page to set the scroll position 554 | */ 555 | scrollToPage(i) { 556 | if ((this.pages.length === 0) || (this.pages[i] === undefined)) { 557 | return; 558 | } 559 | let $page = this.pages[i].$div; 560 | if ($page.length === 0) { 561 | console.warn(`Page ${i} not found`); 562 | return; 563 | } 564 | let position = $page.position(); 565 | let containerPosition = this.$container.position(); 566 | if (position !== undefined) { 567 | this.$container.get(0).scrollTop = this.$container.get(0).scrollTop + position.top - containerPosition.top; 568 | this.$container.get(0).scrollLeft = this.$container.get(0).scrollLeft + position.left - containerPosition.left; 569 | } 570 | this._setActivePage(i); 571 | } 572 | 573 | /** 574 | * Function that renders the page in a canvas, and sets the canvas into the $div 575 | * @param {*} page - the page to be rendered 576 | * @param {*} i - the number of the page to be rendered 577 | * @returns a promise to render the page (the result of the promise will be the pageinfo) 578 | */ 579 | _renderPage(page, i) { 580 | // Get the pageinfo structure 581 | let pageinfo = this.pages[i]; 582 | let scale = this.settings.renderingScale; 583 | 584 | // Calculate the pixel ratio of the device (we'll use a minimum of 1) 585 | let pixel_ratio = window.devicePixelRatio || 1; 586 | // Update the information that we know about the page to the actually loaded page 587 | let viewport = page.getViewport({rotation: this._rotation, scale: this._zoom.current * scale}); 588 | pageinfo.width = (viewport.width / this._zoom.current) / scale; 589 | pageinfo.height = (viewport.height / this._zoom.current) / scale; 590 | pageinfo.$div.data("width", pageinfo.width); 591 | pageinfo.$div.data("height", pageinfo.height); 592 | pageinfo.$div.width(pageinfo.width * this._zoom.current); 593 | pageinfo.$div.height(pageinfo.height * this._zoom.current); 594 | pageinfo.loaded = true; 595 | 596 | // Create the canvas and prepare the rendering context 597 | let $canvas = $(''); 598 | let canvas = $canvas.get(0); 599 | let context = canvas.getContext('2d'); 600 | canvas.height = viewport.height * pixel_ratio; 601 | canvas.width = viewport.width * pixel_ratio; 602 | canvas.getContext("2d")//.scale(pixel_ratio, pixel_ratio); 603 | var transform = pixel_ratio !== 1 604 | ? [pixel_ratio, 0, 0, pixel_ratio, 0, 0] 605 | : null; 606 | var renderContext = { 607 | canvasContext: context, 608 | viewport: viewport, 609 | transform: transform, 610 | }; 611 | 612 | // Render the page and put the resulting rendered canvas into the page $div 613 | return page.render(renderContext).promise.then(function() { 614 | this._setPageContent(pageinfo.$div, $canvas); 615 | 616 | // Call the callback (if provided) 617 | if (this._documentReady) { 618 | if (typeof this.settings.onPageRender === "function") { 619 | this.settings.onPageRender.call(this, pageinfo.$div.get(0), i); 620 | } 621 | this.$container.get(0).dispatchEvent(new CustomEvent("pagerender", { detail: { pageNumber: i, page: pageinfo.$div.get(0) } })); 622 | } 623 | return pageinfo; 624 | }.bind(this)); 625 | } 626 | 627 | /** Gets the div object corresponding to the active page */ 628 | getActivePage() { 629 | if ((this._activePage === null) || (this.pdf === null)) { 630 | return null; 631 | } 632 | if ((this._activePage < 1) || (this._activePage > this.pdf.numPages)) { 633 | return null; 634 | } 635 | return this.pages[this._activePage].$div; 636 | } 637 | 638 | /** Gets all the pages of the document (the pageinfo structures) */ 639 | getPages() { 640 | return this.pages; 641 | } 642 | 643 | /** Gets the number of pages of the document */ 644 | getPageCount() { 645 | if (this.pdf === null) { 646 | return 0; 647 | } 648 | return this.pdf.numPages; 649 | } 650 | 651 | /** Scrolls to the next page (if any) */ 652 | next() { 653 | if (this._activePage < this.pdf.numPages) { 654 | this.scrollToPage(this._activePage + 1); 655 | } 656 | } 657 | 658 | /** Scrolls to the previous page (if any) */ 659 | prev() { 660 | if (this._activePage > 1) { 661 | this.scrollToPage(this._activePage - 1); 662 | } 663 | } 664 | 665 | first() { 666 | if (this._activePage !== 1) { 667 | this.scrollToPage(1); 668 | } 669 | } 670 | 671 | last() { 672 | if (this.pdf === null) 673 | return; 674 | if (this._activePage !== this.pdf.numPages) { 675 | this.scrollToPage(this.pdf.numPages); 676 | } 677 | } 678 | /** 679 | * Rotates the pages of the document 680 | * @param {*} deg - degrees to rotate the pages 681 | * @param {*} accumulate - whether the rotation is accumulated or not 682 | */ 683 | rotate(deg, accumulate = false) { 684 | if (accumulate) { 685 | deg = deg + this._rotation; 686 | } 687 | this._rotation = deg; 688 | 689 | let container = this.$container.get(0); 690 | let prevScroll = { 691 | top: container.scrollTop, 692 | left: container.scrollLeft, 693 | height: container.scrollHeight, 694 | width: container.scrollWidth 695 | }; 696 | 697 | return this.forceViewerInitialization().then(function() { 698 | let newScroll = { 699 | top: container.scrollTop, 700 | left: container.scrollLeft, 701 | height: container.scrollHeight, 702 | width: container.scrollWidth 703 | }; 704 | container.scrollTop = prevScroll.top * (newScroll.height / prevScroll.height); 705 | container.scrollLeft = prevScroll.left * (newScroll.width / prevScroll.width); 706 | }.bind(this)); 707 | } 708 | /** 709 | * This functions forces the creation of the whole content of the viewer (i.e. new divs, structures, etc.). It is usefull for full refresh of the viewer (e.g. when changes 710 | * the rotation of the pages) 711 | * @returns a promise that is resolved when the viewer is fully initialized 712 | */ 713 | forceViewerInitialization() { 714 | // Store the pdf file 715 | // Now prepare a placeholder for the pages 716 | this.pages = []; 717 | 718 | // Remove all the pages 719 | this.$container.find(`.${this.settings.pageClass}`).remove(); 720 | 721 | this._pagesLoading = []; 722 | this._loading = false; 723 | this._visibles = []; 724 | this._activePage = null; 725 | return this.pdf.getPage(1).then(function(page) { 726 | this._createSkeletons(page); 727 | this._visiblePages(); 728 | this._setActivePage(1); 729 | }.bind(this)); 730 | } 731 | /** 732 | * Loads the document and creates the pages 733 | * @param {string} document - the url of the document to load 734 | */ 735 | async loadDocument(document) { 736 | // The document is not ready while loading 737 | this._documentReady = false; 738 | 739 | // Now prepare a placeholder for the pages 740 | this.pages = []; 741 | 742 | // Remove all the pages 743 | this.$container.find(`.${this.settings.pageClass}`).remove(); 744 | 745 | // Let's free the pdf file (if there was one before), and rely on the garbage collector to free the memory 746 | this.pdf = null; 747 | 748 | // Load the task and return the promise to load the document 749 | let loadingTask = pdfjsLib.getDocument(document); 750 | return loadingTask.promise.then(function(pdf) { 751 | // Store the pdf file and get the 752 | this.pdf = pdf; 753 | this.pageCount = pdf.numPages; 754 | this._rotation = 0; 755 | return this.forceViewerInitialization(); 756 | }.bind(this)).then(function() { 757 | if (typeof this.settings.onDocumentReady === "function") { 758 | this.settings.onDocumentReady.call(this); 759 | } 760 | this.$container.get(0).dispatchEvent(new CustomEvent("documentready", { detail: { document: this.pdf } })); 761 | 762 | // This is a trick to force active page changed event triggering after the document is ready 763 | this._setActivePage(0) 764 | this._documentReady = true; 765 | this._setActivePage(1) 766 | }.bind(this)); 767 | } 768 | } 769 | 770 | function recoverAttributes(target, attributeDefaults) { 771 | const camelcaseToSnakecase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`); 772 | let $target = $(target); 773 | let result = {}; 774 | if ($target.length > 0) { 775 | $target = $($target[0]); 776 | for (let originalAttributeName in attributeDefaults) { 777 | let attributeName = camelcaseToSnakecase(originalAttributeName) 778 | let attributeValue = $target.attr(attributeName); 779 | if (attributeValue != null) { 780 | switch (typeof(attributeDefaults[originalAttributeName])) { 781 | case 'float': 782 | try { 783 | attributeValue = parseFloat(attributeValue); 784 | } catch (_) { 785 | } 786 | break; 787 | case 'number': 788 | try { 789 | attributeValue = parseInt(attributeValue); 790 | } catch (_) { 791 | } 792 | break; 793 | case 'function': 794 | let functionString = attributeValue; 795 | attributeValue = function() { eval(functionString); }.bind(target[0]); break; 796 | default: 797 | break; 798 | } 799 | result[originalAttributeName] = attributeValue; 800 | } 801 | }; 802 | } 803 | return result; 804 | } 805 | 806 | function init(element) { 807 | let options = recoverAttributes(element, Object.assign({ 808 | pdfDocument: "", initialZoom: "" 809 | }, defaults)); 810 | if (options["pdfDocument"] != null) { 811 | let pdfViewer = new PDFjsViewer($(element), options); 812 | pdfViewer.loadDocument(options["pdfDocument"]).then(function() { 813 | if (options["initialZoom"] != null) { 814 | pdfViewer.setZoom(options["initialZoom"]); 815 | } 816 | }) 817 | element.get(0).pdfViewer = pdfViewer; 818 | } 819 | } 820 | 821 | $(function() { 822 | $('.pdfjs-viewer').each(function() { 823 | let $viewer = $(this); 824 | init($viewer); 825 | }) 826 | }); 827 | 828 | exports.PDFjsViewer = PDFjsViewer; 829 | })(window, window._$??window.jQuery??undefined); --------------------------------------------------------------------------------