|
@@ -0,0 +1,621 @@
|
|
|
+import { KeyboardManager } from "./tools.js";
|
|
|
+import { AnnotationEditorType } from "../constants"
|
|
|
+import { bindEvents } from "./ui_utils.js";
|
|
|
+import { PDFAnnotationSticky } from "./pdf_annotation_sticky.js";
|
|
|
+import { InkEditor } from "./pdf_measure_editor.js";
|
|
|
+
|
|
|
+/**
|
|
|
+ * Manage all the different editors on a page.
|
|
|
+ */
|
|
|
+class PDFAnnotationLayer {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param {AnnotationEditorLayerOptions} options
|
|
|
+ */
|
|
|
+ constructor(options) {
|
|
|
+ this._cancelled = false;
|
|
|
+
|
|
|
+ this._allowClick = false;
|
|
|
+
|
|
|
+ this._boundPointerup = this.pointerup.bind(this);
|
|
|
+
|
|
|
+ this._boundPointerdown = this.pointerdown.bind(this);
|
|
|
+
|
|
|
+ this._editors = new Map();
|
|
|
+
|
|
|
+ this._hadPointerDown = false;
|
|
|
+
|
|
|
+ this._isCleaningUp = false;
|
|
|
+
|
|
|
+ this._uiManager = options.uiManager;
|
|
|
+
|
|
|
+ this.pageDiv = options.pageDiv;
|
|
|
+ this.div = null;
|
|
|
+ this.scale = options.scale;
|
|
|
+ this._accessibilityManager = options.accessibilityManager
|
|
|
+ options.uiManager.registerEditorTypes([PDFAnnotationSticky, InkEditor]);
|
|
|
+ this.annotationStorage = options.annotationStorage || null;
|
|
|
+ this.pageIndex = options.pageIndex;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Update the toolbar if it's required to reflect the tool currently used.
|
|
|
+ * @param {number} mode
|
|
|
+ */
|
|
|
+ updateToolbar(mode) {
|
|
|
+ this._uiManager.updateToolbar(mode);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The mode has changed: it must be updated.
|
|
|
+ * @param {number} mode
|
|
|
+ */
|
|
|
+ updateMode(mode = this._uiManager.getMode()) {
|
|
|
+ this._cleanup();
|
|
|
+ if (mode === AnnotationEditorType.INK) {
|
|
|
+ // We always want to an ink editor ready to draw in.
|
|
|
+ this.addInkEditorIfNeeded(false);
|
|
|
+ this.disableClick();
|
|
|
+ } else {
|
|
|
+ this.enableClick();
|
|
|
+ }
|
|
|
+ this._uiManager.unselectAll();
|
|
|
+
|
|
|
+ this.div.classList.toggle(
|
|
|
+ "freeTextEditing",
|
|
|
+ mode === AnnotationEditorType.FREETEXT
|
|
|
+ );
|
|
|
+ this.div.classList.toggle("inkEditing", mode === AnnotationEditorType.INK);
|
|
|
+ }
|
|
|
+
|
|
|
+ moveEditorInDOM(editor) {
|
|
|
+ this._accessibilityManager?.moveElementInDOM(
|
|
|
+ this.div,
|
|
|
+ editor.div,
|
|
|
+ editor.contentDiv,
|
|
|
+ /* isRemovable = */ true
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ addInkEditorIfNeeded(isCommitting) {
|
|
|
+ if (
|
|
|
+ !isCommitting &&
|
|
|
+ this._uiManager.getMode() !== AnnotationEditorType.INK
|
|
|
+ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isCommitting) {
|
|
|
+ // We're removing an editor but an empty one can already exist so in this
|
|
|
+ // case we don't need to create a new one.
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ if (editor.isEmpty()) {
|
|
|
+ editor.setInBackground();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const editor = this._createAndAddNewEditor({ offsetX: 0, offsetY: 0 });
|
|
|
+ editor.setInBackground();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set the editing state.
|
|
|
+ * @param {boolean} isEditing
|
|
|
+ */
|
|
|
+ setEditingState(isEditing) {
|
|
|
+ this._uiManager.setEditingState(isEditing);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add some commands into the CommandManager (undo/redo stuff).
|
|
|
+ * @param {Object} params
|
|
|
+ */
|
|
|
+ addCommands(params) {
|
|
|
+ this._uiManager.addCommands(params);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Enable pointer events on the main div in order to enable
|
|
|
+ * editor creation.
|
|
|
+ */
|
|
|
+ enable() {
|
|
|
+ this.div.style.pointerEvents = "auto";
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ editor.enableEditing();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Disable editor creation.
|
|
|
+ */
|
|
|
+ disable() {
|
|
|
+ this.div.style.pointerEvents = "none";
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ editor.disableEditing();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set the current editor.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ setActiveEditor(editor) {
|
|
|
+ const currentActive = this._uiManager.getActive();
|
|
|
+ if (currentActive === editor) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._uiManager.setActiveEditor(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ enableClick() {
|
|
|
+ this.div.addEventListener("pointerdown", this._boundPointerdown);
|
|
|
+ this.div.addEventListener("pointerup", this._boundPointerup);
|
|
|
+ }
|
|
|
+
|
|
|
+ disableClick() {
|
|
|
+ this.div.removeEventListener("pointerdown", this._boundPointerdown);
|
|
|
+ this.div.removeEventListener("pointerup", this._boundPointerup);
|
|
|
+ }
|
|
|
+
|
|
|
+ attach(editor) {
|
|
|
+ this._editors.set(editor.id, editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ detach(editor) {
|
|
|
+ this._editors.delete(editor.id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Remove an editor.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ remove(editor) {
|
|
|
+ // Since we can undo a removal we need to keep the
|
|
|
+ // parent property as it is, so don't null it!
|
|
|
+
|
|
|
+ this._uiManager.removeEditor(editor);
|
|
|
+ this.detach(editor);
|
|
|
+ this.annotationStorage.remove(editor.id);
|
|
|
+ editor.div.style.display = "none";
|
|
|
+ setTimeout(() => {
|
|
|
+ // When the div is removed from DOM the focus can move on the
|
|
|
+ // document.body, so we just slightly postpone the removal in
|
|
|
+ // order to let an element potentially grab the focus before
|
|
|
+ // the body.
|
|
|
+ editor.div.style.display = "";
|
|
|
+ editor.div.remove();
|
|
|
+ editor.isAttachedToDOM = false;
|
|
|
+ if (document.activeElement === document.body) {
|
|
|
+ this._uiManager.focusMainContainer();
|
|
|
+ }
|
|
|
+ }, 0);
|
|
|
+
|
|
|
+ if (!this._isCleaningUp) {
|
|
|
+ this.addInkEditorIfNeeded(/* isCommitting = */ false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * An editor can have a different parent, for example after having
|
|
|
+ * being dragged and droped from a page to another.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ _changeParent(editor) {
|
|
|
+ if (editor.parent === this) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.attach(editor);
|
|
|
+ editor.pageIndex = this.pageIndex;
|
|
|
+ editor.parent?.detach(editor);
|
|
|
+ editor.parent = this;
|
|
|
+ if (editor.div && editor.isAttachedToDOM) {
|
|
|
+ editor.div.remove();
|
|
|
+ this.div.append(editor.div);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add a new editor in the current view.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ add(editor) {
|
|
|
+ this._changeParent(editor);
|
|
|
+ this._uiManager.addEditor(editor);
|
|
|
+ this.attach(editor);
|
|
|
+
|
|
|
+ if (!editor.isAttachedToDOM) {
|
|
|
+ const div = editor.render();
|
|
|
+ this.div.append(div);
|
|
|
+ editor.isAttachedToDOM = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ editor.onceAdded();
|
|
|
+ this.addToAnnotationStorage(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add an editor in the annotation storage.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ addToAnnotationStorage(editor) {
|
|
|
+ if (!editor.isEmpty() && !this.annotationStorage.has(editor.id)) {
|
|
|
+ this.annotationStorage.setValue(editor.id, editor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ updateAnnotationStorage(key) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add or rebuild depending if it has been removed or not.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ addOrRebuild(editor) {
|
|
|
+ if (editor.needsToBeRebuilt()) {
|
|
|
+ editor.rebuild();
|
|
|
+ } else {
|
|
|
+ this.add(editor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add a new editor and make this addition undoable.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ addUndoableEditor(editor) {
|
|
|
+ this.addOrRebuild(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get an id for an editor.
|
|
|
+ * @returns {string}
|
|
|
+ */
|
|
|
+ getNextId() {
|
|
|
+ return this._uiManager.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a new editor
|
|
|
+ * @param {Object} params
|
|
|
+ * @returns {AnnotationEditor}
|
|
|
+ */
|
|
|
+ _createNewEditor(params) {
|
|
|
+ switch (this._uiManager.getMode()) {
|
|
|
+ case AnnotationEditorType.FREETEXT:
|
|
|
+ return new PDFAnnotationSticky(params);
|
|
|
+ case AnnotationEditorType.INK:
|
|
|
+ return new InkEditor(params);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create a new editor
|
|
|
+ * @param {Object} data
|
|
|
+ * @returns {AnnotationEditor}
|
|
|
+ */
|
|
|
+ deserialize(data) {
|
|
|
+ switch (data.annotationType) {
|
|
|
+ case AnnotationEditorType.FREETEXT:
|
|
|
+ return PDFAnnotationSticky.deserialize(data, this);
|
|
|
+ case AnnotationEditorType.INK:
|
|
|
+ return InkEditor.deserialize(data, this);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create and add a new editor.
|
|
|
+ * @param {PointerEvent} event
|
|
|
+ * @returns {AnnotationEditor}
|
|
|
+ */
|
|
|
+ _createAndAddNewEditor(event) {
|
|
|
+ const id = this.getNextId();
|
|
|
+ const editor = this._createNewEditor({
|
|
|
+ parent: this,
|
|
|
+ id,
|
|
|
+ x: event.offsetX,
|
|
|
+ y: event.offsetY,
|
|
|
+ });
|
|
|
+ if (editor) {
|
|
|
+ this.add(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ return editor;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set the last selected editor.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ setSelected(editor) {
|
|
|
+ this._uiManager.setSelected(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add or remove an editor the current selection.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ toggleSelected(editor) {
|
|
|
+ this._uiManager.toggleSelected(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Check if the editor is selected.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ isSelected(editor) {
|
|
|
+ return this._uiManager.isSelected(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Unselect an editor.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ unselect(editor) {
|
|
|
+ this._uiManager.unselect(editor);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Pointerup callback.
|
|
|
+ * @param {PointerEvent} event
|
|
|
+ */
|
|
|
+ pointerup(event) {
|
|
|
+ const isMac = KeyboardManager.platform.isMac;
|
|
|
+ if (event.button !== 0 || (event.ctrlKey && isMac)) {
|
|
|
+ // Don't create an editor on right click.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (event.target !== this.div) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!this._hadPointerDown) {
|
|
|
+ // It can happen when the user starts a drag inside a text editor
|
|
|
+ // and then releases the mouse button outside of it. In such a case
|
|
|
+ // we don't want to create a new editor, hence we check that a pointerdown
|
|
|
+ // occured on this div previously.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._hadPointerDown = false;
|
|
|
+
|
|
|
+ if (!this._allowClick) {
|
|
|
+ this._allowClick = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._createAndAddNewEditor(event);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Pointerdown callback.
|
|
|
+ * @param {PointerEvent} event
|
|
|
+ */
|
|
|
+ pointerdown(event) {
|
|
|
+ const isMac = KeyboardManager.platform.isMac;
|
|
|
+ if (event.button !== 0 || (event.ctrlKey && isMac)) {
|
|
|
+ // Do nothing on right click.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (event.target !== this.div) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._hadPointerDown = true;
|
|
|
+
|
|
|
+ const editor = this._uiManager.getActive();
|
|
|
+ this._allowClick = !editor || editor.isEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Drag callback.
|
|
|
+ * @param {DragEvent} event
|
|
|
+ */
|
|
|
+ drop(event) {
|
|
|
+ const id = event.dataTransfer.getData("text/plain");
|
|
|
+ const editor = this._uiManager.getEditor(id);
|
|
|
+ if (!editor) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ event.preventDefault();
|
|
|
+ event.dataTransfer.dropEffect = "move";
|
|
|
+
|
|
|
+ this._changeParent(editor);
|
|
|
+
|
|
|
+ const rect = this.div.getBoundingClientRect();
|
|
|
+ const endX = event.clientX - rect.x;
|
|
|
+ const endY = event.clientY - rect.y;
|
|
|
+
|
|
|
+ editor.translate(endX - editor.startX, endY - editor.startY);
|
|
|
+ editor.div.focus();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Dragover callback.
|
|
|
+ * @param {DragEvent} event
|
|
|
+ */
|
|
|
+ dragover(event) {
|
|
|
+ event.preventDefault();
|
|
|
+ }
|
|
|
+
|
|
|
+ _cleanup() {
|
|
|
+ // When we're cleaning up, some editors are removed but we don't want
|
|
|
+ // to add a new one which will induce an addition in this._editors, hence
|
|
|
+ // an infinite loop.
|
|
|
+ this._isCleaningUp = true;
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ if (editor.isEmpty()) {
|
|
|
+ editor.remove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this._isCleaningUp = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ _removeAll() {
|
|
|
+ // When we're cleaning up, some editors are removed but we don't want
|
|
|
+ // to add a new one which will induce an addition in this._editors, hence
|
|
|
+ // an infinite loop.
|
|
|
+ this._isCleaningUp = true;
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ editor.remove();
|
|
|
+ }
|
|
|
+ this._isCleaningUp = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Render the main editor.
|
|
|
+ * @param {Object} parameters
|
|
|
+ */
|
|
|
+ render(viewport) {
|
|
|
+ if (this._cancelled) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const clonedViewport = viewport.clone({ dontFlip: true });
|
|
|
+ if (this.div) {
|
|
|
+ this.update({ viewport: clonedViewport });
|
|
|
+ this.show();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create an AnnotationEditor layer div
|
|
|
+ this.div = document.createElement("div");
|
|
|
+ this.div.className = "annotationLayer";
|
|
|
+ this.div.tabIndex = 0;
|
|
|
+ this.pageDiv.append(this.div);
|
|
|
+
|
|
|
+ this._uiManager.addLayer(this);
|
|
|
+
|
|
|
+ this.viewport = clonedViewport
|
|
|
+ bindEvents(this, this.pageDiv, ["dragover", "drop"]);
|
|
|
+
|
|
|
+ this.setDimensions();
|
|
|
+ for (const editor of this._uiManager.getEditors(this.pageIndex)) {
|
|
|
+ this.add(editor);
|
|
|
+ }
|
|
|
+ this.updateMode();
|
|
|
+ }
|
|
|
+
|
|
|
+ cancel() {
|
|
|
+ this._cancelled = true;
|
|
|
+ this.destroy();
|
|
|
+ }
|
|
|
+
|
|
|
+ hide() {
|
|
|
+ if (!this.div) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.div.hidden = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ show() {
|
|
|
+ if (!this.div) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.div.hidden = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Destroy the main editor.
|
|
|
+ */
|
|
|
+ destroy() {
|
|
|
+ if (!this.div) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.pageDiv = null;
|
|
|
+ if (this._uiManager.getActive()?.parent === this) {
|
|
|
+ this._uiManager.setActiveEditor(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ editor.isAttachedToDOM = false;
|
|
|
+ editor.div.remove();
|
|
|
+ editor.parent = null;
|
|
|
+ }
|
|
|
+ this.div.remove();
|
|
|
+ this.div = null;
|
|
|
+ this._editors.clear();
|
|
|
+ this._uiManager.removeLayer(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Remove an editor.
|
|
|
+ * @param {AnnotationEditor} editor
|
|
|
+ */
|
|
|
+ removeAllAnnotations() {
|
|
|
+ // Since we can undo a removal we need to keep the
|
|
|
+ // parent property as it is, so don't null it!
|
|
|
+
|
|
|
+ if (this._uiManager.getActive()?.parent === this) {
|
|
|
+ this._uiManager.setActiveEditor(null);
|
|
|
+ }
|
|
|
+ for (const editor of this._editors.values()) {
|
|
|
+ this.remove(editor)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Update the main editor.
|
|
|
+ * @param {Object} parameters
|
|
|
+ */
|
|
|
+ update(parameters) {
|
|
|
+ // Editors have their dimensions/positions in percent so to avoid any
|
|
|
+ // issues (see #15582), we must commit the current one before changing
|
|
|
+ // the viewport.
|
|
|
+ this._uiManager.commitOrRemove();
|
|
|
+
|
|
|
+ this.viewport = parameters.viewport;
|
|
|
+ this.setDimensions();
|
|
|
+ this.updateMode();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get the scale factor from the viewport.
|
|
|
+ * @returns {number}
|
|
|
+ */
|
|
|
+ get scaleFactor() {
|
|
|
+ return this.viewport.scale;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get page dimensions.
|
|
|
+ * @returns {Object} dimensions.
|
|
|
+ */
|
|
|
+ get pageDimensions() {
|
|
|
+ const [pageLLx, pageLLy, pageURx, pageURy] = this.viewport.viewBox;
|
|
|
+ const width = pageURx - pageLLx;
|
|
|
+ const height = pageURy - pageLLy;
|
|
|
+
|
|
|
+ return [width, height];
|
|
|
+ }
|
|
|
+
|
|
|
+ get viewportBaseDimensions() {
|
|
|
+ const { width, height, rotation } = this.viewport;
|
|
|
+ return rotation % 180 === 0 ? [width, height] : [height, width];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set the dimensions of the main div.
|
|
|
+ */
|
|
|
+ setDimensions() {
|
|
|
+ const { width, height, rotation } = this.viewport;
|
|
|
+
|
|
|
+ const flipOrientation = rotation % 180 !== 0,
|
|
|
+ widthStr = Math.floor(width) + "px",
|
|
|
+ heightStr = Math.floor(height) + "px";
|
|
|
+
|
|
|
+ this.div.style.width = flipOrientation ? heightStr : widthStr;
|
|
|
+ this.div.style.height = flipOrientation ? widthStr : heightStr;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export { PDFAnnotationLayer };
|