288 lines
6.9 KiB
JavaScript
288 lines
6.9 KiB
JavaScript
/* Copyright 2022 Mozilla Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {
|
|
AnnotationEditorParamsType,
|
|
AnnotationEditorType,
|
|
shadow,
|
|
Util,
|
|
} from "../../shared/util.js";
|
|
import { DrawingEditor, DrawingOptions } from "./draw.js";
|
|
import { InkDrawOutline, InkDrawOutliner } from "./drawers/inkdraw.js";
|
|
import { AnnotationEditor } from "./editor.js";
|
|
import { InkAnnotationElement } from "../annotation_layer.js";
|
|
|
|
class InkDrawingOptions extends DrawingOptions {
|
|
constructor(viewerParameters) {
|
|
super();
|
|
this._viewParameters = viewerParameters;
|
|
|
|
super.updateProperties({
|
|
fill: "none",
|
|
stroke: AnnotationEditor._defaultLineColor,
|
|
"stroke-opacity": 1,
|
|
"stroke-width": 1,
|
|
"stroke-linecap": "round",
|
|
"stroke-linejoin": "round",
|
|
"stroke-miterlimit": 10,
|
|
});
|
|
}
|
|
|
|
updateSVGProperty(name, value) {
|
|
if (name === "stroke-width") {
|
|
value ??= this["stroke-width"];
|
|
value *= this._viewParameters.realScale;
|
|
}
|
|
super.updateSVGProperty(name, value);
|
|
}
|
|
|
|
clone() {
|
|
const clone = new InkDrawingOptions(this._viewParameters);
|
|
clone.updateAll(this);
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Basic draw editor in order to generate an Ink annotation.
|
|
*/
|
|
class InkEditor extends DrawingEditor {
|
|
static _type = "ink";
|
|
|
|
static _editorType = AnnotationEditorType.INK;
|
|
|
|
static _defaultDrawingOptions = null;
|
|
|
|
constructor(params) {
|
|
super({ ...params, name: "inkEditor" });
|
|
this._willKeepAspectRatio = true;
|
|
this.defaultL10nId = "pdfjs-editor-ink-editor";
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static initialize(l10n, uiManager) {
|
|
AnnotationEditor.initialize(l10n, uiManager);
|
|
this._defaultDrawingOptions = new InkDrawingOptions(
|
|
uiManager.viewParameters
|
|
);
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static getDefaultDrawingOptions(options) {
|
|
const clone = this._defaultDrawingOptions.clone();
|
|
clone.updateProperties(options);
|
|
return clone;
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static get supportMultipleDrawings() {
|
|
return true;
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static get typesMap() {
|
|
return shadow(
|
|
this,
|
|
"typesMap",
|
|
new Map([
|
|
[AnnotationEditorParamsType.INK_THICKNESS, "stroke-width"],
|
|
[AnnotationEditorParamsType.INK_COLOR, "stroke"],
|
|
[AnnotationEditorParamsType.INK_OPACITY, "stroke-opacity"],
|
|
])
|
|
);
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static createDrawerInstance(x, y, parentWidth, parentHeight, rotation) {
|
|
return new InkDrawOutliner(
|
|
x,
|
|
y,
|
|
parentWidth,
|
|
parentHeight,
|
|
rotation,
|
|
this._defaultDrawingOptions["stroke-width"]
|
|
);
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static deserializeDraw(
|
|
pageX,
|
|
pageY,
|
|
pageWidth,
|
|
pageHeight,
|
|
innerMargin,
|
|
data
|
|
) {
|
|
return InkDrawOutline.deserialize(
|
|
pageX,
|
|
pageY,
|
|
pageWidth,
|
|
pageHeight,
|
|
innerMargin,
|
|
data
|
|
);
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
static async deserialize(data, parent, uiManager) {
|
|
let initialData = null;
|
|
if (data instanceof InkAnnotationElement) {
|
|
const {
|
|
data: {
|
|
inkLists,
|
|
rect,
|
|
rotation,
|
|
id,
|
|
color,
|
|
opacity,
|
|
borderStyle: { rawWidth: thickness },
|
|
popupRef,
|
|
},
|
|
parent: {
|
|
page: { pageNumber },
|
|
},
|
|
} = data;
|
|
initialData = data = {
|
|
annotationType: AnnotationEditorType.INK,
|
|
color: Array.from(color),
|
|
thickness,
|
|
opacity,
|
|
paths: { points: inkLists },
|
|
boxes: null,
|
|
pageIndex: pageNumber - 1,
|
|
rect: rect.slice(0),
|
|
rotation,
|
|
annotationElementId: id,
|
|
id,
|
|
deleted: false,
|
|
popupRef,
|
|
};
|
|
}
|
|
|
|
const editor = await super.deserialize(data, parent, uiManager);
|
|
editor._initialData = initialData;
|
|
|
|
return editor;
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
onScaleChanging() {
|
|
if (!this.parent) {
|
|
return;
|
|
}
|
|
super.onScaleChanging();
|
|
const { _drawId, _drawingOptions, parent } = this;
|
|
_drawingOptions.updateSVGProperty("stroke-width");
|
|
parent.drawLayer.updateProperties(
|
|
_drawId,
|
|
_drawingOptions.toSVGProperties()
|
|
);
|
|
}
|
|
|
|
static onScaleChangingWhenDrawing() {
|
|
const parent = this._currentParent;
|
|
if (!parent) {
|
|
return;
|
|
}
|
|
super.onScaleChangingWhenDrawing();
|
|
this._defaultDrawingOptions.updateSVGProperty("stroke-width");
|
|
parent.drawLayer.updateProperties(
|
|
this._currentDrawId,
|
|
this._defaultDrawingOptions.toSVGProperties()
|
|
);
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
createDrawingOptions({ color, thickness, opacity }) {
|
|
this._drawingOptions = InkEditor.getDefaultDrawingOptions({
|
|
stroke: Util.makeHexColor(...color),
|
|
"stroke-width": thickness,
|
|
"stroke-opacity": opacity,
|
|
});
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
serialize(isForCopying = false) {
|
|
if (this.isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
if (this.deleted) {
|
|
return this.serializeDeleted();
|
|
}
|
|
|
|
const { lines, points, rect } = this.serializeDraw(isForCopying);
|
|
const {
|
|
_drawingOptions: {
|
|
stroke,
|
|
"stroke-opacity": opacity,
|
|
"stroke-width": thickness,
|
|
},
|
|
} = this;
|
|
const serialized = {
|
|
annotationType: AnnotationEditorType.INK,
|
|
color: AnnotationEditor._colorManager.convert(stroke),
|
|
opacity,
|
|
thickness,
|
|
paths: {
|
|
lines,
|
|
points,
|
|
},
|
|
pageIndex: this.pageIndex,
|
|
rect,
|
|
rotation: this.rotation,
|
|
structTreeParentId: this._structTreeParentId,
|
|
};
|
|
|
|
if (isForCopying) {
|
|
serialized.isCopy = true;
|
|
return serialized;
|
|
}
|
|
|
|
if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
|
|
return null;
|
|
}
|
|
|
|
serialized.id = this.annotationElementId;
|
|
return serialized;
|
|
}
|
|
|
|
#hasElementChanged(serialized) {
|
|
const { color, thickness, opacity, pageIndex } = this._initialData;
|
|
return (
|
|
this._hasBeenMoved ||
|
|
this._hasBeenResized ||
|
|
serialized.color.some((c, i) => c !== color[i]) ||
|
|
serialized.thickness !== thickness ||
|
|
serialized.opacity !== opacity ||
|
|
serialized.pageIndex !== pageIndex
|
|
);
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
renderAnnotationElement(annotation) {
|
|
const { points, rect } = this.serializeDraw(/* isForCopying = */ false);
|
|
annotation.updateEdited({
|
|
rect,
|
|
thickness: this._drawingOptions["stroke-width"],
|
|
points,
|
|
});
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export { InkDrawingOptions, InkEditor };
|