Support rotating editor layer
- As in the annotation layer, use percent instead of pixels as unit; - handle the rotation of the editor layer in allowing editing when rotation angle is not zero; - the different editors are rotated counterclockwise in order to be usable when the main page is itself rotated; - add support for saving/printing rotated editors.
This commit is contained in:
parent
b5fea8ff14
commit
0c420f5135
@ -1509,6 +1509,19 @@ class WidgetAnnotation extends Annotation {
|
|||||||
return !!(this.data.fieldFlags & flag);
|
return !!(this.data.fieldFlags & flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _getRotationMatrix(rotation, width, height) {
|
||||||
|
switch (rotation) {
|
||||||
|
case 90:
|
||||||
|
return [0, 1, -1, 0, width, 0];
|
||||||
|
case 180:
|
||||||
|
return [-1, 0, 0, -1, width, height];
|
||||||
|
case 270:
|
||||||
|
return [0, -1, 1, 0, 0, height];
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid rotation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getRotationMatrix(annotationStorage) {
|
getRotationMatrix(annotationStorage) {
|
||||||
const storageEntry = annotationStorage
|
const storageEntry = annotationStorage
|
||||||
? annotationStorage.get(this.data.id)
|
? annotationStorage.get(this.data.id)
|
||||||
@ -1525,16 +1538,7 @@ class WidgetAnnotation extends Annotation {
|
|||||||
const width = this.data.rect[2] - this.data.rect[0];
|
const width = this.data.rect[2] - this.data.rect[0];
|
||||||
const height = this.data.rect[3] - this.data.rect[1];
|
const height = this.data.rect[3] - this.data.rect[1];
|
||||||
|
|
||||||
switch (rotation) {
|
return WidgetAnnotation._getRotationMatrix(rotation, width, height);
|
||||||
case 90:
|
|
||||||
return [0, 1, -1, 0, width, 0];
|
|
||||||
case 180:
|
|
||||||
return [-1, 0, 0, -1, width, height];
|
|
||||||
case 270:
|
|
||||||
return [0, -1, 1, 0, 0, height];
|
|
||||||
default:
|
|
||||||
throw new Error("Invalid rotation");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getBorderAndBackgroundAppearances(annotationStorage) {
|
getBorderAndBackgroundAppearances(annotationStorage) {
|
||||||
@ -3185,7 +3189,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static createNewDict(annotation, xref, { apRef, ap }) {
|
static createNewDict(annotation, xref, { apRef, ap }) {
|
||||||
const { color, fontSize, rect, user, value } = annotation;
|
const { color, fontSize, rect, rotation, user, value } = annotation;
|
||||||
const freetext = new Dict(xref);
|
const freetext = new Dict(xref);
|
||||||
freetext.set("Type", Name.get("Annot"));
|
freetext.set("Type", Name.get("Annot"));
|
||||||
freetext.set("Subtype", Name.get("FreeText"));
|
freetext.set("Subtype", Name.get("FreeText"));
|
||||||
@ -3196,7 +3200,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
|||||||
freetext.set("Contents", value);
|
freetext.set("Contents", value);
|
||||||
freetext.set("F", 4);
|
freetext.set("F", 4);
|
||||||
freetext.set("Border", [0, 0, 0]);
|
freetext.set("Border", [0, 0, 0]);
|
||||||
freetext.set("Rotate", 0);
|
freetext.set("Rotate", rotation);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
freetext.set("T", stringToUTF8String(user));
|
freetext.set("T", stringToUTF8String(user));
|
||||||
@ -3216,7 +3220,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
|||||||
|
|
||||||
static async createNewAppearanceStream(annotation, xref, params) {
|
static async createNewAppearanceStream(annotation, xref, params) {
|
||||||
const { baseFontRef, evaluator, task } = params;
|
const { baseFontRef, evaluator, task } = params;
|
||||||
const { color, fontSize, rect, value } = annotation;
|
const { color, fontSize, rect, rotation, value } = annotation;
|
||||||
|
|
||||||
const resources = new Dict(xref);
|
const resources = new Dict(xref);
|
||||||
const font = new Dict(xref);
|
const font = new Dict(xref);
|
||||||
@ -3244,8 +3248,12 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [x1, y1, x2, y2] = rect;
|
const [x1, y1, x2, y2] = rect;
|
||||||
const w = x2 - x1;
|
let w = x2 - x1;
|
||||||
const h = y2 - y1;
|
let h = y2 - y1;
|
||||||
|
|
||||||
|
if (rotation % 180 !== 0) {
|
||||||
|
[w, h] = [h, w];
|
||||||
|
}
|
||||||
|
|
||||||
const lines = value.split("\n");
|
const lines = value.split("\n");
|
||||||
const scale = fontSize / 1000;
|
const scale = fontSize / 1000;
|
||||||
@ -3301,6 +3309,11 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
|||||||
appearanceStreamDict.set("Length", appearance.length);
|
appearanceStreamDict.set("Length", appearance.length);
|
||||||
appearanceStreamDict.set("Resources", resources);
|
appearanceStreamDict.set("Resources", resources);
|
||||||
|
|
||||||
|
if (rotation) {
|
||||||
|
const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h);
|
||||||
|
appearanceStreamDict.set("Matrix", matrix);
|
||||||
|
}
|
||||||
|
|
||||||
const ap = new StringStream(appearance);
|
const ap = new StringStream(appearance);
|
||||||
ap.dict = appearanceStreamDict;
|
ap.dict = appearanceStreamDict;
|
||||||
|
|
||||||
@ -3669,18 +3682,19 @@ class InkAnnotation extends MarkupAnnotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static createNewDict(annotation, xref, { apRef, ap }) {
|
static createNewDict(annotation, xref, { apRef, ap }) {
|
||||||
|
const { paths, rect, rotation } = annotation;
|
||||||
const ink = new Dict(xref);
|
const ink = new Dict(xref);
|
||||||
ink.set("Type", Name.get("Annot"));
|
ink.set("Type", Name.get("Annot"));
|
||||||
ink.set("Subtype", Name.get("Ink"));
|
ink.set("Subtype", Name.get("Ink"));
|
||||||
ink.set("CreationDate", `D:${getModificationDate()}`);
|
ink.set("CreationDate", `D:${getModificationDate()}`);
|
||||||
ink.set("Rect", annotation.rect);
|
ink.set("Rect", rect);
|
||||||
ink.set(
|
ink.set(
|
||||||
"InkList",
|
"InkList",
|
||||||
annotation.paths.map(p => p.points)
|
paths.map(p => p.points)
|
||||||
);
|
);
|
||||||
ink.set("F", 4);
|
ink.set("F", 4);
|
||||||
ink.set("Border", [0, 0, 0]);
|
ink.set("Border", [0, 0, 0]);
|
||||||
ink.set("Rotate", 0);
|
ink.set("Rotate", rotation);
|
||||||
|
|
||||||
const n = new Dict(xref);
|
const n = new Dict(xref);
|
||||||
ink.set("AP", n);
|
ink.set("AP", n);
|
||||||
@ -3695,16 +3709,21 @@ class InkAnnotation extends MarkupAnnotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async createNewAppearanceStream(annotation, xref, params) {
|
static async createNewAppearanceStream(annotation, xref, params) {
|
||||||
const [x1, y1, x2, y2] = annotation.rect;
|
const { color, rect, rotation, paths, thickness } = annotation;
|
||||||
const w = x2 - x1;
|
const [x1, y1, x2, y2] = rect;
|
||||||
const h = y2 - y1;
|
let w = x2 - x1;
|
||||||
|
let h = y2 - y1;
|
||||||
|
|
||||||
|
if (rotation % 180 !== 0) {
|
||||||
|
[w, h] = [h, w];
|
||||||
|
}
|
||||||
|
|
||||||
const appearanceBuffer = [
|
const appearanceBuffer = [
|
||||||
`${annotation.thickness} w`,
|
`${thickness} w`,
|
||||||
`${getPdfColor(annotation.color, /* isFill */ false)}`,
|
`${getPdfColor(color, /* isFill */ false)}`,
|
||||||
];
|
];
|
||||||
const buffer = [];
|
const buffer = [];
|
||||||
for (const { bezier } of annotation.paths) {
|
for (const { bezier } of paths) {
|
||||||
buffer.length = 0;
|
buffer.length = 0;
|
||||||
buffer.push(
|
buffer.push(
|
||||||
`${numberToString(bezier[0])} ${numberToString(bezier[1])} m`
|
`${numberToString(bezier[0])} ${numberToString(bezier[1])} m`
|
||||||
@ -3728,6 +3747,11 @@ class InkAnnotation extends MarkupAnnotation {
|
|||||||
appearanceStreamDict.set("BBox", [0, 0, w, h]);
|
appearanceStreamDict.set("BBox", [0, 0, w, h]);
|
||||||
appearanceStreamDict.set("Length", appearance.length);
|
appearanceStreamDict.set("Length", appearance.length);
|
||||||
|
|
||||||
|
if (rotation) {
|
||||||
|
const matrix = WidgetAnnotation._getRotationMatrix(rotation, w, h);
|
||||||
|
appearanceStreamDict.set("Matrix", matrix);
|
||||||
|
}
|
||||||
|
|
||||||
const ap = new StringStream(appearance);
|
const ap = new StringStream(appearance);
|
||||||
ap.dict = appearanceStreamDict;
|
ap.dict = appearanceStreamDict;
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ class AnnotationElement {
|
|||||||
container.style.width = `${elementWidth}%`;
|
container.style.width = `${elementWidth}%`;
|
||||||
container.style.height = `${elementHeight}%`;
|
container.style.height = `${elementHeight}%`;
|
||||||
|
|
||||||
container.setAttribute("data-annotation-rotation", (360 - angle) % 360);
|
container.setAttribute("data-main-rotation", (360 - angle) % 360);
|
||||||
}
|
}
|
||||||
|
|
||||||
get _commonActions() {
|
get _commonActions() {
|
||||||
@ -2552,7 +2552,7 @@ class AnnotationLayer {
|
|||||||
|
|
||||||
style.width = flipOrientation ? heightStr : widthStr;
|
style.width = flipOrientation ? heightStr : widthStr;
|
||||||
style.height = flipOrientation ? widthStr : heightStr;
|
style.height = flipOrientation ? widthStr : heightStr;
|
||||||
div.setAttribute("data-annotation-rotation", rotation);
|
div.setAttribute("data-main-rotation", rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static #setAnnotationCanvasMap(div, annotationCanvasMap) {
|
static #setAnnotationCanvasMap(div, annotationCanvasMap) {
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
/** @typedef {import("../annotation_storage.js").AnnotationStorage} AnnotationStorage */
|
/** @typedef {import("../annotation_storage.js").AnnotationStorage} AnnotationStorage */
|
||||||
/** @typedef {import("../../web/interfaces").IL10n} IL10n */
|
/** @typedef {import("../../web/interfaces").IL10n} IL10n */
|
||||||
|
|
||||||
import { AnnotationEditorType, Util } from "../../shared/util.js";
|
|
||||||
import { bindEvents, KeyboardManager } from "./tools.js";
|
import { bindEvents, KeyboardManager } from "./tools.js";
|
||||||
|
import { AnnotationEditorType } from "../../shared/util.js";
|
||||||
import { FreeTextEditor } from "./freetext.js";
|
import { FreeTextEditor } from "./freetext.js";
|
||||||
import { InkEditor } from "./ink.js";
|
import { InkEditor } from "./ink.js";
|
||||||
|
|
||||||
@ -106,6 +106,7 @@ class AnnotationEditorLayer {
|
|||||||
} else {
|
} else {
|
||||||
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
||||||
}
|
}
|
||||||
|
this.setActiveEditor(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,6 +274,11 @@ class AnnotationEditorLayer {
|
|||||||
if (editor.parent === this) {
|
if (editor.parent === this) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.#uiManager.isActive(editor)) {
|
||||||
|
editor.parent.setActiveEditor(null);
|
||||||
|
}
|
||||||
|
|
||||||
this.attach(editor);
|
this.attach(editor);
|
||||||
editor.pageIndex = this.pageIndex;
|
editor.pageIndex = this.pageIndex;
|
||||||
editor.parent.detach(editor);
|
editor.parent.detach(editor);
|
||||||
@ -419,10 +425,10 @@ class AnnotationEditorLayer {
|
|||||||
this.#changeParent(editor);
|
this.#changeParent(editor);
|
||||||
|
|
||||||
const rect = this.div.getBoundingClientRect();
|
const rect = this.div.getBoundingClientRect();
|
||||||
editor.setAt(
|
const endX = event.clientX - rect.x;
|
||||||
event.clientX - rect.x - editor.mouseX,
|
const endY = event.clientY - rect.y;
|
||||||
event.clientY - rect.y - editor.mouseY
|
|
||||||
);
|
editor.translate(endX - editor.startX, endY - editor.startY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -463,11 +469,9 @@ class AnnotationEditorLayer {
|
|||||||
*/
|
*/
|
||||||
render(parameters) {
|
render(parameters) {
|
||||||
this.viewport = parameters.viewport;
|
this.viewport = parameters.viewport;
|
||||||
this.inverseViewportTransform = Util.inverseTransform(
|
|
||||||
this.viewport.transform
|
|
||||||
);
|
|
||||||
bindEvents(this, this.div, ["dragover", "drop", "keydown"]);
|
bindEvents(this, this.div, ["dragover", "drop", "keydown"]);
|
||||||
this.div.addEventListener("click", this.#boundClick);
|
this.div.addEventListener("click", this.#boundClick);
|
||||||
|
this.setDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -475,17 +479,9 @@ class AnnotationEditorLayer {
|
|||||||
* @param {Object} parameters
|
* @param {Object} parameters
|
||||||
*/
|
*/
|
||||||
update(parameters) {
|
update(parameters) {
|
||||||
const transform = Util.transform(
|
this.setActiveEditor(null);
|
||||||
parameters.viewport.transform,
|
|
||||||
this.inverseViewportTransform
|
|
||||||
);
|
|
||||||
this.viewport = parameters.viewport;
|
this.viewport = parameters.viewport;
|
||||||
this.inverseViewportTransform = Util.inverseTransform(
|
this.setDimensions();
|
||||||
this.viewport.transform
|
|
||||||
);
|
|
||||||
for (const editor of this.#editors.values()) {
|
|
||||||
editor.transform(transform);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -495,6 +491,38 @@ class AnnotationEditorLayer {
|
|||||||
get scaleFactor() {
|
get scaleFactor() {
|
||||||
return this.viewport.scale;
|
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;
|
||||||
|
this.div.setAttribute("data-main-rotation", rotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { AnnotationEditorLayer };
|
export { AnnotationEditorLayer };
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
|
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
|
||||||
|
|
||||||
import { unreachable, Util } from "../../shared/util.js";
|
|
||||||
import { bindEvents } from "./tools.js";
|
import { bindEvents } from "./tools.js";
|
||||||
|
import { unreachable } from "../../shared/util.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} AnnotationEditorParameters
|
* @typedef {Object} AnnotationEditorParameters
|
||||||
@ -47,8 +47,11 @@ class AnnotationEditor {
|
|||||||
this.pageIndex = parameters.parent.pageIndex;
|
this.pageIndex = parameters.parent.pageIndex;
|
||||||
this.name = parameters.name;
|
this.name = parameters.name;
|
||||||
this.div = null;
|
this.div = null;
|
||||||
this.x = Math.round(parameters.x);
|
|
||||||
this.y = Math.round(parameters.y);
|
const [width, height] = this.parent.viewportBaseDimensions;
|
||||||
|
this.x = parameters.x / width;
|
||||||
|
this.y = parameters.y / height;
|
||||||
|
this.rotation = this.parent.viewport.rotation;
|
||||||
|
|
||||||
this.isAttachedToDOM = false;
|
this.isAttachedToDOM = false;
|
||||||
}
|
}
|
||||||
@ -107,21 +110,14 @@ class AnnotationEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the pointer coordinates in order to correctly translate the
|
|
||||||
* div in case of drag-and-drop.
|
|
||||||
* @param {MouseEvent} event
|
|
||||||
*/
|
|
||||||
mousedown(event) {
|
|
||||||
this.mouseX = event.offsetX;
|
|
||||||
this.mouseY = event.offsetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use drag-and-drop in order to move an editor on a page.
|
* We use drag-and-drop in order to move an editor on a page.
|
||||||
* @param {DragEvent} event
|
* @param {DragEvent} event
|
||||||
*/
|
*/
|
||||||
dragstart(event) {
|
dragstart(event) {
|
||||||
|
const rect = this.parent.div.getBoundingClientRect();
|
||||||
|
this.startX = event.clientX - rect.x;
|
||||||
|
this.startY = event.clientY - rect.y;
|
||||||
event.dataTransfer.setData("text/plain", this.id);
|
event.dataTransfer.setData("text/plain", this.id);
|
||||||
event.dataTransfer.effectAllowed = "move";
|
event.dataTransfer.effectAllowed = "move";
|
||||||
}
|
}
|
||||||
@ -130,22 +126,53 @@ class AnnotationEditor {
|
|||||||
* Set the editor position within its parent.
|
* Set the editor position within its parent.
|
||||||
* @param {number} x
|
* @param {number} x
|
||||||
* @param {number} y
|
* @param {number} y
|
||||||
|
* @param {number} tx - x-translation in screen coordinates.
|
||||||
|
* @param {number} ty - y-translation in screen coordinates.
|
||||||
*/
|
*/
|
||||||
setAt(x, y) {
|
setAt(x, y, tx, ty) {
|
||||||
this.x = Math.round(x);
|
const [width, height] = this.parent.viewportBaseDimensions;
|
||||||
this.y = Math.round(y);
|
[tx, ty] = this.screenToPageTranslation(tx, ty);
|
||||||
|
|
||||||
this.div.style.left = `${this.x}px`;
|
this.x = (x + tx) / width;
|
||||||
this.div.style.top = `${this.y}px`;
|
this.y = (y + ty) / height;
|
||||||
|
|
||||||
|
this.div.style.left = `${100 * this.x}%`;
|
||||||
|
this.div.style.top = `${100 * this.y}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate the editor position within its parent.
|
* Translate the editor position within its parent.
|
||||||
|
* @param {number} x - x-translation in screen coordinates.
|
||||||
|
* @param {number} y - y-translation in screen coordinates.
|
||||||
|
*/
|
||||||
|
translate(x, y) {
|
||||||
|
const [width, height] = this.parent.viewportBaseDimensions;
|
||||||
|
[x, y] = this.screenToPageTranslation(x, y);
|
||||||
|
|
||||||
|
this.x += x / width;
|
||||||
|
this.y += y / height;
|
||||||
|
|
||||||
|
this.div.style.left = `${100 * this.x}%`;
|
||||||
|
this.div.style.top = `${100 * this.y}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a screen translation into a page one.
|
||||||
* @param {number} x
|
* @param {number} x
|
||||||
* @param {number} y
|
* @param {number} y
|
||||||
*/
|
*/
|
||||||
translate(x, y) {
|
screenToPageTranslation(x, y) {
|
||||||
this.setAt(this.x + x, this.y + y);
|
const { rotation } = this.parent.viewport;
|
||||||
|
switch (rotation) {
|
||||||
|
case 90:
|
||||||
|
return [y, -x];
|
||||||
|
case 180:
|
||||||
|
return [-x, -y];
|
||||||
|
case 270:
|
||||||
|
return [-y, x];
|
||||||
|
default:
|
||||||
|
return [x, y];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,8 +181,9 @@ class AnnotationEditor {
|
|||||||
* @param {number} height
|
* @param {number} height
|
||||||
*/
|
*/
|
||||||
setDims(width, height) {
|
setDims(width, height) {
|
||||||
this.div.style.width = `${width}px`;
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
this.div.style.height = `${height}px`;
|
this.div.style.width = `${(100 * width) / parentWidth}%`;
|
||||||
|
this.div.style.height = `${(100 * height) / parentHeight}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,54 +200,68 @@ class AnnotationEditor {
|
|||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
this.div = document.createElement("div");
|
this.div = document.createElement("div");
|
||||||
|
this.div.setAttribute("data-editor-rotation", (360 - this.rotation) % 360);
|
||||||
this.div.className = this.name;
|
this.div.className = this.name;
|
||||||
this.div.setAttribute("id", this.id);
|
this.div.setAttribute("id", this.id);
|
||||||
this.div.tabIndex = 100;
|
this.div.tabIndex = 100;
|
||||||
|
|
||||||
const [tx, ty] = this.getInitialTranslation();
|
const [tx, ty] = this.getInitialTranslation();
|
||||||
this.x = Math.round(this.x + tx);
|
this.translate(tx, ty);
|
||||||
this.y = Math.round(this.y + ty);
|
|
||||||
|
|
||||||
this.div.style.left = `${this.x}px`;
|
bindEvents(this, this.div, ["dragstart", "focusin", "focusout"]);
|
||||||
this.div.style.top = `${this.y}px`;
|
|
||||||
|
|
||||||
bindEvents(this, this.div, [
|
|
||||||
"dragstart",
|
|
||||||
"focusin",
|
|
||||||
"focusout",
|
|
||||||
"mousedown",
|
|
||||||
]);
|
|
||||||
|
|
||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRect(tx, ty) {
|
||||||
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
|
const [pageWidth, pageHeight] = this.parent.pageDimensions;
|
||||||
|
const shiftX = (pageWidth * tx) / parentWidth;
|
||||||
|
const shiftY = (pageHeight * ty) / parentHeight;
|
||||||
|
const x = this.x * pageWidth;
|
||||||
|
const y = this.y * pageHeight;
|
||||||
|
const width = this.width * pageWidth;
|
||||||
|
const height = this.height * pageHeight;
|
||||||
|
|
||||||
|
switch (this.rotation) {
|
||||||
|
case 0:
|
||||||
|
return [
|
||||||
|
x + shiftX,
|
||||||
|
pageHeight - y - shiftY - height,
|
||||||
|
x + shiftX + width,
|
||||||
|
pageHeight - y - shiftY,
|
||||||
|
];
|
||||||
|
case 90:
|
||||||
|
return [
|
||||||
|
x + shiftY,
|
||||||
|
pageHeight - y + shiftX,
|
||||||
|
x + shiftY + height,
|
||||||
|
pageHeight - y + shiftX + width,
|
||||||
|
];
|
||||||
|
case 180:
|
||||||
|
return [
|
||||||
|
x - shiftX - width,
|
||||||
|
pageHeight - y + shiftY,
|
||||||
|
x - shiftX,
|
||||||
|
pageHeight - y + shiftY + height,
|
||||||
|
];
|
||||||
|
case 270:
|
||||||
|
return [
|
||||||
|
x - shiftY - height,
|
||||||
|
pageHeight - y - shiftX - width,
|
||||||
|
x - shiftY,
|
||||||
|
pageHeight - y - shiftX,
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid rotation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executed once this editor has been rendered.
|
* Executed once this editor has been rendered.
|
||||||
*/
|
*/
|
||||||
onceAdded() {}
|
onceAdded() {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the current transform (zoom) to this editor.
|
|
||||||
* @param {Array<number>} transform
|
|
||||||
*/
|
|
||||||
transform(transform) {
|
|
||||||
const { style } = this.div;
|
|
||||||
const width = parseFloat(style.width);
|
|
||||||
const height = parseFloat(style.height);
|
|
||||||
|
|
||||||
const [x1, y1] = Util.applyTransform([this.x, this.y], transform);
|
|
||||||
|
|
||||||
if (!Number.isNaN(width)) {
|
|
||||||
const [x2] = Util.applyTransform([this.x + width, 0], transform);
|
|
||||||
this.div.style.width = `${x2 - x1}px`;
|
|
||||||
}
|
|
||||||
if (!Number.isNaN(height)) {
|
|
||||||
const [, y2] = Util.applyTransform([0, this.y + height], transform);
|
|
||||||
this.div.style.height = `${y2 - y1}px`;
|
|
||||||
}
|
|
||||||
this.setAt(x1, y1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the editor contains something.
|
* Check if the editor contains something.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
AnnotationEditorType,
|
AnnotationEditorType,
|
||||||
assert,
|
assert,
|
||||||
LINE_FACTOR,
|
LINE_FACTOR,
|
||||||
Util,
|
|
||||||
} from "../../shared/util.js";
|
} from "../../shared/util.js";
|
||||||
import { AnnotationEditor } from "./editor.js";
|
import { AnnotationEditor } from "./editor.js";
|
||||||
import { bindEvents } from "./tools.js";
|
import { bindEvents } from "./tools.js";
|
||||||
@ -72,11 +71,12 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
copy() {
|
copy() {
|
||||||
|
const [width, height] = this.parent.viewportBaseDimensions;
|
||||||
const editor = new FreeTextEditor({
|
const editor = new FreeTextEditor({
|
||||||
parent: this.parent,
|
parent: this.parent,
|
||||||
id: this.parent.getNextId(),
|
id: this.parent.getNextId(),
|
||||||
x: this.x,
|
x: this.x * width,
|
||||||
y: this.y,
|
y: this.y * height,
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.width = this.width;
|
editor.width = this.width;
|
||||||
@ -180,9 +180,10 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
this.#contentHTML = this.editorDiv.innerHTML;
|
this.#contentHTML = this.editorDiv.innerHTML;
|
||||||
this.#content = this.#extractText().trimEnd();
|
this.#content = this.#extractText().trimEnd();
|
||||||
|
|
||||||
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
const style = getComputedStyle(this.div);
|
const style = getComputedStyle(this.div);
|
||||||
this.width = parseFloat(style.width);
|
this.width = parseFloat(style.width) / parentWidth;
|
||||||
this.height = parseFloat(style.height);
|
this.height = parseFloat(style.height) / parentHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
@ -205,6 +206,12 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let baseX, baseY;
|
||||||
|
if (this.width) {
|
||||||
|
baseX = this.x;
|
||||||
|
baseY = this.y;
|
||||||
|
}
|
||||||
|
|
||||||
super.render();
|
super.render();
|
||||||
this.editorDiv = document.createElement("div");
|
this.editorDiv = document.createElement("div");
|
||||||
this.editorDiv.tabIndex = 0;
|
this.editorDiv.tabIndex = 0;
|
||||||
@ -232,7 +239,13 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
if (this.width) {
|
if (this.width) {
|
||||||
// This editor was created in using copy (ctrl+c).
|
// This editor was created in using copy (ctrl+c).
|
||||||
this.setAt(this.x + this.width, this.y + this.height);
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
|
this.setAt(
|
||||||
|
baseX * parentWidth,
|
||||||
|
baseY * parentHeight,
|
||||||
|
this.width * parentWidth,
|
||||||
|
this.height * parentHeight
|
||||||
|
);
|
||||||
// eslint-disable-next-line no-unsanitized/property
|
// eslint-disable-next-line no-unsanitized/property
|
||||||
this.editorDiv.innerHTML = this.#contentHTML;
|
this.editorDiv.innerHTML = this.#contentHTML;
|
||||||
}
|
}
|
||||||
@ -242,24 +255,17 @@ class FreeTextEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
serialize() {
|
serialize() {
|
||||||
const rect = this.editorDiv.getBoundingClientRect();
|
|
||||||
const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor;
|
const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor;
|
||||||
const [x1, y1] = Util.applyTransform(
|
const rect = this.getRect(padding, padding);
|
||||||
[this.x + padding, this.y + padding + rect.height],
|
|
||||||
this.parent.inverseViewportTransform
|
|
||||||
);
|
|
||||||
|
|
||||||
const [x2, y2] = Util.applyTransform(
|
|
||||||
[this.x + padding + rect.width, this.y + padding],
|
|
||||||
this.parent.inverseViewportTransform
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
annotationType: AnnotationEditorType.FREETEXT,
|
annotationType: AnnotationEditorType.FREETEXT,
|
||||||
color: [0, 0, 0],
|
color: [0, 0, 0],
|
||||||
fontSize: this.#fontSize,
|
fontSize: this.#fontSize,
|
||||||
value: this.#content,
|
value: this.#content,
|
||||||
pageIndex: this.parent.pageIndex,
|
pageIndex: this.parent.pageIndex,
|
||||||
rect: [x1, y1, x2, y2],
|
rect,
|
||||||
|
rotation: this.rotation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,10 @@ class InkEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
#observer = null;
|
#observer = null;
|
||||||
|
|
||||||
|
#realWidth = 0;
|
||||||
|
|
||||||
|
#realHeight = 0;
|
||||||
|
|
||||||
constructor(params) {
|
constructor(params) {
|
||||||
super({ ...params, name: "inkEditor" });
|
super({ ...params, name: "inkEditor" });
|
||||||
this.color = params.color || "CanvasText";
|
this.color = params.color || "CanvasText";
|
||||||
@ -79,6 +83,8 @@ class InkEditor extends AnnotationEditor {
|
|||||||
editor.#baseWidth = this.#baseWidth;
|
editor.#baseWidth = this.#baseWidth;
|
||||||
editor.#baseHeight = this.#baseHeight;
|
editor.#baseHeight = this.#baseHeight;
|
||||||
editor.#disableEditing = this.#disableEditing;
|
editor.#disableEditing = this.#disableEditing;
|
||||||
|
editor.#realWidth = this.#realWidth;
|
||||||
|
editor.#realHeight = this.#realHeight;
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
@ -135,7 +141,7 @@ class InkEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
disableEditMode() {
|
disableEditMode() {
|
||||||
if (!this.isInEditMode()) {
|
if (!this.isInEditMode() || this.canvas === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +165,20 @@ class InkEditor extends AnnotationEditor {
|
|||||||
return this.paths.length === 0;
|
return this.paths.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getInitialBBox() {
|
||||||
|
const { width, height, rotation } = this.parent.viewport;
|
||||||
|
switch (rotation) {
|
||||||
|
case 90:
|
||||||
|
return [0, width, width, height];
|
||||||
|
case 180:
|
||||||
|
return [width, height, width, height];
|
||||||
|
case 270:
|
||||||
|
return [height, 0, width, height];
|
||||||
|
default:
|
||||||
|
return [0, 0, width, height];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set line styles.
|
* Set line styles.
|
||||||
*/
|
*/
|
||||||
@ -257,9 +277,10 @@ class InkEditor extends AnnotationEditor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
const { ctx, height, width } = this;
|
const { ctx, height, width } = this;
|
||||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width * parentWidth, height * parentHeight);
|
||||||
this.#updateTransform();
|
this.#updateTransform();
|
||||||
for (const path of this.bezierPath2D) {
|
for (const path of this.bezierPath2D) {
|
||||||
ctx.stroke(path);
|
ctx.stroke(path);
|
||||||
@ -390,15 +411,30 @@ class InkEditor extends AnnotationEditor {
|
|||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.render();
|
let baseX, baseY;
|
||||||
this.#createCanvas();
|
if (this.width) {
|
||||||
|
baseX = this.x;
|
||||||
|
baseY = this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.render();
|
||||||
this.div.classList.add("editing");
|
this.div.classList.add("editing");
|
||||||
|
const [x, y, w, h] = this.#getInitialBBox();
|
||||||
|
this.setAt(x, y, 0, 0);
|
||||||
|
this.setDims(w, h);
|
||||||
|
|
||||||
|
this.#createCanvas();
|
||||||
|
|
||||||
if (this.width) {
|
if (this.width) {
|
||||||
// This editor was created in using copy (ctrl+c).
|
// This editor was created in using copy (ctrl+c).
|
||||||
this.setAt(this.x + this.width, this.y + this.height);
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
this.setDims(this.width, this.height);
|
this.setAt(
|
||||||
|
baseX * parentWidth,
|
||||||
|
baseY * parentHeight,
|
||||||
|
this.width * parentWidth,
|
||||||
|
this.height * parentHeight
|
||||||
|
);
|
||||||
|
this.setDims(this.width * parentWidth, this.height * parentHeight);
|
||||||
this.#setCanvasDims();
|
this.#setCanvasDims();
|
||||||
this.#redraw();
|
this.#redraw();
|
||||||
this.div.classList.add("disabled");
|
this.div.classList.add("disabled");
|
||||||
@ -410,8 +446,9 @@ class InkEditor extends AnnotationEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#setCanvasDims() {
|
#setCanvasDims() {
|
||||||
this.canvas.width = this.width;
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
this.canvas.height = this.height;
|
this.canvas.width = this.width * parentWidth;
|
||||||
|
this.canvas.height = this.height * parentHeight;
|
||||||
this.#updateTransform();
|
this.#updateTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,19 +460,28 @@ class InkEditor extends AnnotationEditor {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
setDimensions(width, height) {
|
setDimensions(width, height) {
|
||||||
if (this.width === width && this.height === height) {
|
const roundedWidth = Math.round(width);
|
||||||
|
const roundedHeight = Math.round(height);
|
||||||
|
if (
|
||||||
|
this.#realWidth === roundedWidth &&
|
||||||
|
this.#realHeight === roundedHeight
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.#realWidth = roundedWidth;
|
||||||
|
this.#realHeight = roundedHeight;
|
||||||
|
|
||||||
this.canvas.style.visibility = "hidden";
|
this.canvas.style.visibility = "hidden";
|
||||||
|
|
||||||
if (this.#aspectRatio) {
|
if (this.#aspectRatio) {
|
||||||
height = Math.ceil(width / this.#aspectRatio);
|
height = Math.ceil(width / this.#aspectRatio);
|
||||||
this.div.style.height = `${height}px`;
|
this.setDims(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.width = width;
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
this.height = height;
|
this.width = width / parentWidth;
|
||||||
|
this.height = height / parentHeight;
|
||||||
|
|
||||||
if (this.#disableEditing) {
|
if (this.#disableEditing) {
|
||||||
const padding = this.#getPadding();
|
const padding = this.#getPadding();
|
||||||
@ -682,8 +728,9 @@ class InkEditor extends AnnotationEditor {
|
|||||||
const width = Math.ceil(padding + this.#baseWidth * this.scaleFactor);
|
const width = Math.ceil(padding + this.#baseWidth * this.scaleFactor);
|
||||||
const height = Math.ceil(padding + this.#baseHeight * this.scaleFactor);
|
const height = Math.ceil(padding + this.#baseHeight * this.scaleFactor);
|
||||||
|
|
||||||
this.width = width;
|
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||||
this.height = height;
|
this.width = width / parentWidth;
|
||||||
|
this.height = height / parentHeight;
|
||||||
|
|
||||||
this.#aspectRatio = width / height;
|
this.#aspectRatio = width / height;
|
||||||
|
|
||||||
@ -704,16 +751,9 @@ class InkEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
serialize() {
|
serialize() {
|
||||||
const rect = this.div.getBoundingClientRect();
|
const rect = this.getRect(0, 0);
|
||||||
const [x1, y1] = Util.applyTransform(
|
const height =
|
||||||
[this.x, this.y + rect.height],
|
this.rotation % 180 === 0 ? rect[3] - rect[1] : rect[2] - rect[0];
|
||||||
this.parent.inverseViewportTransform
|
|
||||||
);
|
|
||||||
|
|
||||||
const [x2, y2] = Util.applyTransform(
|
|
||||||
[this.x + rect.width, this.y],
|
|
||||||
this.parent.inverseViewportTransform
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
annotationType: AnnotationEditorType.INK,
|
annotationType: AnnotationEditorType.INK,
|
||||||
@ -723,10 +763,11 @@ class InkEditor extends AnnotationEditor {
|
|||||||
this.scaleFactor / this.parent.scaleFactor,
|
this.scaleFactor / this.parent.scaleFactor,
|
||||||
this.translationX,
|
this.translationX,
|
||||||
this.translationY,
|
this.translationY,
|
||||||
y2 - y1
|
height
|
||||||
),
|
),
|
||||||
pageIndex: this.parent.pageIndex,
|
pageIndex: this.parent.pageIndex,
|
||||||
rect: [x1, y1, x2, y2],
|
rect,
|
||||||
|
rotation: this.rotation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1413,7 +1413,7 @@ describe("Interaction", () => {
|
|||||||
await closePages(pages);
|
await closePages(pages);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("must check that data-annotation-rotation is correct", async () => {
|
it("must check that data-main-rotation is correct", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
await page.waitForFunction(
|
await page.waitForFunction(
|
||||||
@ -1431,7 +1431,7 @@ describe("Interaction", () => {
|
|||||||
]) {
|
]) {
|
||||||
const rotation = await page.$eval(
|
const rotation = await page.$eval(
|
||||||
`[data-annotation-id='${ref}R']`,
|
`[data-annotation-id='${ref}R']`,
|
||||||
el => parseInt(el.getAttribute("data-annotation-rotation") || 0)
|
el => parseInt(el.getAttribute("data-main-rotation") || 0)
|
||||||
);
|
);
|
||||||
expect(rotation)
|
expect(rotation)
|
||||||
.withContext(`In ${browserName}`)
|
.withContext(`In ${browserName}`)
|
||||||
|
@ -6638,7 +6638,8 @@
|
|||||||
"fontSize": 10,
|
"fontSize": 10,
|
||||||
"value": "Hello World",
|
"value": "Hello World",
|
||||||
"pageIndex": 0,
|
"pageIndex": 0,
|
||||||
"rect": [67.5, 543, 119, 556.5]
|
"rect": [67.5, 543, 119, 556.5],
|
||||||
|
"rotation": 0
|
||||||
},
|
},
|
||||||
"pdfjs_internal_editor_1": {
|
"pdfjs_internal_editor_1": {
|
||||||
"annotationType": 15,
|
"annotationType": 15,
|
||||||
@ -6661,7 +6662,163 @@
|
|||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
"pageIndex": 0,
|
"pageIndex": 0,
|
||||||
"rect": [71.5, 534.5, 115, 562]
|
"rect": [71.5, 534.5, 115, 562],
|
||||||
|
"rotation": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tracemonkey-editor-rotation",
|
||||||
|
"file": "pdfs/tracemonkey.pdf",
|
||||||
|
"md5": "9a192d8b1a7dc652a19835f6f08098bd",
|
||||||
|
"rounds": 1,
|
||||||
|
"lastPage": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"print": true,
|
||||||
|
"annotationStorage": {
|
||||||
|
"pdfjs_internal_editor_3": {
|
||||||
|
"annotationType": 3,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"fontSize": 10,
|
||||||
|
"value": "Hello",
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
96.34615384615385, 554.8461538461538, 119.12498076923077,
|
||||||
|
568.3461538461538
|
||||||
|
],
|
||||||
|
"rotation": 0
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_4": {
|
||||||
|
"annotationType": 3,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"fontSize": 10,
|
||||||
|
"value": "PDF",
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
125.57692307692308, 533.5384615384615, 139.07692307692307,
|
||||||
|
553.5384807692308
|
||||||
|
],
|
||||||
|
"rotation": 90
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_5": {
|
||||||
|
"annotationType": 3,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"fontSize": 10,
|
||||||
|
"value": ".js",
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
105.9615576923077, 535.0769230769231, 115.96153846153847,
|
||||||
|
548.5769230769231
|
||||||
|
],
|
||||||
|
"rotation": 180
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_6": {
|
||||||
|
"annotationType": 3,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"fontSize": 10,
|
||||||
|
"value": "world!",
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
77.84615384615385, 531.682673076923, 91.34615384615385,
|
||||||
|
558.3461538461538
|
||||||
|
],
|
||||||
|
"rotation": 270
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_21": {
|
||||||
|
"annotationType": 15,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"thickness": 1,
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"bezier": [
|
||||||
|
0.5, 15.653846153846189, 0.5, 10.612792605955292,
|
||||||
|
2.221156193659856, 5.960961418318131, 2.221156193659856,
|
||||||
|
0.7371591421274406
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
0.5, 15.653846153846189, 2.221156193659856, 0.7371591421274406
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
416.53846153846155, 561.8076923076923, 419.41346388596753,
|
||||||
|
577.9615384615385
|
||||||
|
],
|
||||||
|
"rotation": 0
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_23": {
|
||||||
|
"annotationType": 15,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"thickness": 1,
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"bezier": [
|
||||||
|
0.5, 18.538461538461547, 0.5, 12.869221974582576,
|
||||||
|
3.9307267310416893, 5.207607308237302, 1.6538461538461537,
|
||||||
|
0.653846153846164
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
0.5, 18.538461538461547, 2.434116685812059, 4.572198481030599,
|
||||||
|
1.9307532933714027, 9.17784944259592, 1.6538461538461537,
|
||||||
|
0.653846153846164
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
390.00000000000006, 543.4615384615386, 409.0384615384616,
|
||||||
|
546.9134638859676
|
||||||
|
],
|
||||||
|
"rotation": 90
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_25": {
|
||||||
|
"annotationType": 15,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"thickness": 1,
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"bezier": [
|
||||||
|
0.5, 24.307692307692264, 0.5, 16.218230266280443,
|
||||||
|
1.6442331167367787, 8.976323168614734, 1.6442331167367787,
|
||||||
|
0.8509134145882982
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
0.5, 24.307692307692264, 1.6442331167367787, 0.8509134145882982
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
422.7788438063401, 515.7692307692307, 425.07692307692304,
|
||||||
|
540.576923076923
|
||||||
|
],
|
||||||
|
"rotation": 180
|
||||||
|
},
|
||||||
|
"pdfjs_internal_editor_27": {
|
||||||
|
"annotationType": 15,
|
||||||
|
"color": [0, 0, 0],
|
||||||
|
"thickness": 1,
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"bezier": [
|
||||||
|
0.5, 32.96153846153845, 4.262222952239026, 32.96153846153845,
|
||||||
|
2.8076923076923075, 4.355429108316972, 2.8076923076923075,
|
||||||
|
0.6538461538461462
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
0.5, 32.96153846153845, 2.9761779872739975, 7.263528385840449,
|
||||||
|
3.0646797609357885, 18.195785915618856, 2.8076923076923075,
|
||||||
|
0.6538461538461462
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pageIndex": 0,
|
||||||
|
"rect": [
|
||||||
|
425.6538461538462, 553.7403822678785, 459.11538461538464,
|
||||||
|
557.7692307692307
|
||||||
|
],
|
||||||
|
"rotation": 270
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4027,6 +4027,7 @@ describe("annotation", function () {
|
|||||||
{
|
{
|
||||||
annotationType: AnnotationEditorType.FREETEXT,
|
annotationType: AnnotationEditorType.FREETEXT,
|
||||||
rect: [12, 34, 56, 78],
|
rect: [12, 34, 56, 78],
|
||||||
|
rotation: 0,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: [0, 0, 0],
|
color: [0, 0, 0],
|
||||||
value: "Hello PDF.js World!",
|
value: "Hello PDF.js World!",
|
||||||
@ -4078,6 +4079,7 @@ describe("annotation", function () {
|
|||||||
{
|
{
|
||||||
annotationType: AnnotationEditorType.FREETEXT,
|
annotationType: AnnotationEditorType.FREETEXT,
|
||||||
rect: [12, 34, 56, 78],
|
rect: [12, 34, 56, 78],
|
||||||
|
rotation: 0,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: [0, 0, 0],
|
color: [0, 0, 0],
|
||||||
value: "A",
|
value: "A",
|
||||||
@ -4181,6 +4183,7 @@ describe("annotation", function () {
|
|||||||
{
|
{
|
||||||
annotationType: AnnotationEditorType.INK,
|
annotationType: AnnotationEditorType.INK,
|
||||||
rect: [12, 34, 56, 78],
|
rect: [12, 34, 56, 78],
|
||||||
|
rotation: 0,
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
color: [0, 0, 0],
|
color: [0, 0, 0],
|
||||||
paths: [
|
paths: [
|
||||||
@ -4239,6 +4242,7 @@ describe("annotation", function () {
|
|||||||
{
|
{
|
||||||
annotationType: AnnotationEditorType.INK,
|
annotationType: AnnotationEditorType.INK,
|
||||||
rect: [12, 34, 56, 78],
|
rect: [12, 34, 56, 78],
|
||||||
|
rotation: 0,
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
color: [0, 0, 0],
|
color: [0, 0, 0],
|
||||||
paths: [
|
paths: [
|
||||||
|
@ -20,14 +20,23 @@
|
|||||||
--freetext-padding: 2px;
|
--freetext-padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-editor-rotation="90"] {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
[data-editor-rotation="180"] {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
[data-editor-rotation="270"] {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
|
||||||
.annotationEditorLayer {
|
.annotationEditorLayer {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
font-size: calc(100px * var(--scale-factor));
|
font-size: calc(100px * var(--scale-factor));
|
||||||
|
transform-origin: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotationEditorLayer .freeTextEditor {
|
.annotationEditorLayer .freeTextEditor {
|
||||||
@ -38,6 +47,7 @@
|
|||||||
resize: none;
|
resize: none;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
transform-origin: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotationEditorLayer .freeTextEditor .internal {
|
.annotationEditorLayer .freeTextEditor .internal {
|
||||||
@ -100,6 +110,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
transform-origin: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotationEditorLayer .background {
|
.annotationEditorLayer .background {
|
||||||
|
@ -66,8 +66,9 @@ class AnnotationEditorLayerBuilder {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clonedViewport = viewport.clone({ dontFlip: true });
|
||||||
if (this.div) {
|
if (this.div) {
|
||||||
this.annotationEditorLayer.update({ viewport: viewport.clone() });
|
this.annotationEditorLayer.update({ viewport: clonedViewport });
|
||||||
this.show();
|
this.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -86,7 +87,7 @@ class AnnotationEditorLayerBuilder {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const parameters = {
|
const parameters = {
|
||||||
viewport: viewport.clone(),
|
viewport: clonedViewport,
|
||||||
div: this.div,
|
div: this.div,
|
||||||
annotations: null,
|
annotations: null,
|
||||||
intent,
|
intent,
|
||||||
|
@ -27,16 +27,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-annotation-rotation="90"] {
|
|
||||||
transform: rotate(90deg) translateY(-100%);
|
|
||||||
}
|
|
||||||
[data-annotation-rotation="180"] {
|
|
||||||
transform: rotate(180deg) translate(-100%, -100%);
|
|
||||||
}
|
|
||||||
[data-annotation-rotation="270"] {
|
|
||||||
transform: rotate(270deg) translateX(-100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.annotationLayer {
|
.annotationLayer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -35,6 +35,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-main-rotation="90"] {
|
||||||
|
transform: rotate(90deg) translateY(-100%);
|
||||||
|
}
|
||||||
|
[data-main-rotation="180"] {
|
||||||
|
transform: rotate(180deg) translate(-100%, -100%);
|
||||||
|
}
|
||||||
|
[data-main-rotation="270"] {
|
||||||
|
transform: rotate(270deg) translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
.pdfViewer {
|
.pdfViewer {
|
||||||
padding-bottom: var(--pdfViewer-padding-bottom);
|
padding-bottom: var(--pdfViewer-padding-bottom);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user