Merge pull request #8228 from timvandermeij/line-annotations
Implement support for line annotations
This commit is contained in:
commit
32e01cda96
@ -115,6 +115,9 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
|
||||
case 'Popup':
|
||||
return new PopupAnnotation(parameters);
|
||||
|
||||
case 'Line':
|
||||
return new LineAnnotation(parameters);
|
||||
|
||||
case 'Highlight':
|
||||
return new HighlightAnnotation(parameters);
|
||||
|
||||
@ -955,6 +958,8 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentSubtype = parentItem.get('Subtype');
|
||||
this.data.parentType = isName(parentSubtype) ? parentSubtype.name : null;
|
||||
this.data.parentId = dict.getRaw('Parent').toString();
|
||||
this.data.title = stringToPDFString(parentItem.get('T') || '');
|
||||
this.data.contents = stringToPDFString(parentItem.get('Contents') || '');
|
||||
@ -983,15 +988,28 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
|
||||
return PopupAnnotation;
|
||||
})();
|
||||
|
||||
var LineAnnotation = (function LineAnnotationClosure() {
|
||||
function LineAnnotation(parameters) {
|
||||
Annotation.call(this, parameters);
|
||||
|
||||
this.data.annotationType = AnnotationType.LINE;
|
||||
|
||||
var dict = parameters.dict;
|
||||
this.data.lineCoordinates = Util.normalizeRect(dict.getArray('L'));
|
||||
this._preparePopup(dict);
|
||||
}
|
||||
|
||||
Util.inherit(LineAnnotation, Annotation, {});
|
||||
|
||||
return LineAnnotation;
|
||||
})();
|
||||
|
||||
var HighlightAnnotation = (function HighlightAnnotationClosure() {
|
||||
function HighlightAnnotation(parameters) {
|
||||
Annotation.call(this, parameters);
|
||||
|
||||
this.data.annotationType = AnnotationType.HIGHLIGHT;
|
||||
this._preparePopup(parameters.dict);
|
||||
|
||||
// PDF viewers completely ignore any border styles.
|
||||
this.data.borderStyle.setWidth(0);
|
||||
}
|
||||
|
||||
Util.inherit(HighlightAnnotation, Annotation, {});
|
||||
@ -1005,9 +1023,6 @@ var UnderlineAnnotation = (function UnderlineAnnotationClosure() {
|
||||
|
||||
this.data.annotationType = AnnotationType.UNDERLINE;
|
||||
this._preparePopup(parameters.dict);
|
||||
|
||||
// PDF viewers completely ignore any border styles.
|
||||
this.data.borderStyle.setWidth(0);
|
||||
}
|
||||
|
||||
Util.inherit(UnderlineAnnotation, Annotation, {});
|
||||
@ -1021,9 +1036,6 @@ var SquigglyAnnotation = (function SquigglyAnnotationClosure() {
|
||||
|
||||
this.data.annotationType = AnnotationType.SQUIGGLY;
|
||||
this._preparePopup(parameters.dict);
|
||||
|
||||
// PDF viewers completely ignore any border styles.
|
||||
this.data.borderStyle.setWidth(0);
|
||||
}
|
||||
|
||||
Util.inherit(SquigglyAnnotation, Annotation, {});
|
||||
@ -1037,9 +1049,6 @@ var StrikeOutAnnotation = (function StrikeOutAnnotationClosure() {
|
||||
|
||||
this.data.annotationType = AnnotationType.STRIKEOUT;
|
||||
this._preparePopup(parameters.dict);
|
||||
|
||||
// PDF viewers completely ignore any border styles.
|
||||
this.data.borderStyle.setWidth(0);
|
||||
}
|
||||
|
||||
Util.inherit(StrikeOutAnnotation, Annotation, {});
|
||||
|
@ -93,6 +93,9 @@ AnnotationElementFactory.prototype =
|
||||
case AnnotationType.POPUP:
|
||||
return new PopupAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.LINE:
|
||||
return new LineAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.HIGHLIGHT:
|
||||
return new HighlightAnnotationElement(parameters);
|
||||
|
||||
@ -119,7 +122,7 @@ AnnotationElementFactory.prototype =
|
||||
* @alias AnnotationElement
|
||||
*/
|
||||
var AnnotationElement = (function AnnotationElementClosure() {
|
||||
function AnnotationElement(parameters, isRenderable) {
|
||||
function AnnotationElement(parameters, isRenderable, ignoreBorder) {
|
||||
this.isRenderable = isRenderable || false;
|
||||
this.data = parameters.data;
|
||||
this.layer = parameters.layer;
|
||||
@ -131,7 +134,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
||||
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
||||
|
||||
if (isRenderable) {
|
||||
this.container = this._createContainer();
|
||||
this.container = this._createContainer(ignoreBorder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,10 +143,12 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
||||
* Create an empty container for the annotation's HTML element.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} ignoreBorder
|
||||
* @memberof AnnotationElement
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
_createContainer: function AnnotationElement_createContainer() {
|
||||
_createContainer:
|
||||
function AnnotationElement_createContainer(ignoreBorder) {
|
||||
var data = this.data, page = this.page, viewport = this.viewport;
|
||||
var container = document.createElement('section');
|
||||
var width = data.rect[2] - data.rect[0];
|
||||
@ -165,7 +170,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
||||
CustomStyle.setProp('transformOrigin', container,
|
||||
-rect[0] + 'px ' + -rect[1] + 'px');
|
||||
|
||||
if (data.borderStyle.width > 0) {
|
||||
if (!ignoreBorder && data.borderStyle.width > 0) {
|
||||
container.style.borderWidth = data.borderStyle.width + 'px';
|
||||
if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
|
||||
// Underline styles only have a bottom border, so we do not need
|
||||
@ -679,6 +684,10 @@ var ChoiceWidgetAnnotationElement = (
|
||||
* @alias PopupAnnotationElement
|
||||
*/
|
||||
var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
|
||||
// Do not render popup annotations for parent elements with these types as
|
||||
// they create the popups themselves (because of custom trigger divs).
|
||||
var IGNORE_TYPES = ['Line'];
|
||||
|
||||
function PopupAnnotationElement(parameters) {
|
||||
var isRenderable = !!(parameters.data.title || parameters.data.contents);
|
||||
AnnotationElement.call(this, parameters, isRenderable);
|
||||
@ -695,6 +704,10 @@ var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
|
||||
render: function PopupAnnotationElement_render() {
|
||||
this.container.className = 'popupAnnotation';
|
||||
|
||||
if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
var selector = '[data-annotation-id="' + this.data.parentId + '"]';
|
||||
var parentElement = this.layer.querySelector(selector);
|
||||
if (!parentElement) {
|
||||
@ -864,6 +877,69 @@ var PopupElement = (function PopupElementClosure() {
|
||||
return PopupElement;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @alias LineAnnotationElement
|
||||
*/
|
||||
var LineAnnotationElement = (function LineAnnotationElementClosure() {
|
||||
var SVG_NS = 'http://www.w3.org/2000/svg';
|
||||
|
||||
function LineAnnotationElement(parameters) {
|
||||
var isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
AnnotationElement.call(this, parameters, isRenderable,
|
||||
/* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
Util.inherit(LineAnnotationElement, AnnotationElement, {
|
||||
/**
|
||||
* Render the line annotation's HTML element in the empty container.
|
||||
*
|
||||
* @public
|
||||
* @memberof LineAnnotationElement
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render: function LineAnnotationElement_render() {
|
||||
this.container.className = 'lineAnnotation';
|
||||
|
||||
// Create an invisible line with the same starting and ending coordinates
|
||||
// that acts as the trigger for the popup. Only the line itself should
|
||||
// trigger the popup, not the entire container.
|
||||
var data = this.data;
|
||||
var width = data.rect[2] - data.rect[0];
|
||||
var height = data.rect[3] - data.rect[1];
|
||||
|
||||
var svg = document.createElementNS(SVG_NS, 'svg:svg');
|
||||
svg.setAttributeNS(null, 'version', '1.1');
|
||||
svg.setAttributeNS(null, 'width', width + 'px');
|
||||
svg.setAttributeNS(null, 'height', height + 'px');
|
||||
svg.setAttributeNS(null, 'preserveAspectRatio', 'none');
|
||||
svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
|
||||
|
||||
// PDF coordinates are calculated from a bottom left origin, so transform
|
||||
// the line coordinates to a top left origin for the SVG element.
|
||||
var line = document.createElementNS(SVG_NS, 'svg:line');
|
||||
line.setAttributeNS(null, 'x1', data.rect[2] - data.lineCoordinates[0]);
|
||||
line.setAttributeNS(null, 'y1', data.rect[3] - data.lineCoordinates[1]);
|
||||
line.setAttributeNS(null, 'x2', data.rect[2] - data.lineCoordinates[2]);
|
||||
line.setAttributeNS(null, 'y2', data.rect[3] - data.lineCoordinates[3]);
|
||||
line.setAttributeNS(null, 'stroke-width', data.borderStyle.width);
|
||||
line.setAttributeNS(null, 'stroke', 'transparent');
|
||||
|
||||
svg.appendChild(line);
|
||||
this.container.append(svg);
|
||||
|
||||
// Create the popup ourselves so that we can bind it to the line instead
|
||||
// of to the entire container (which is the default).
|
||||
this._createPopup(this.container, line, this.data);
|
||||
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
|
||||
return LineAnnotationElement;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @alias HighlightAnnotationElement
|
||||
@ -873,7 +949,8 @@ var HighlightAnnotationElement = (
|
||||
function HighlightAnnotationElement(parameters) {
|
||||
var isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
AnnotationElement.call(this, parameters, isRenderable);
|
||||
AnnotationElement.call(this, parameters, isRenderable,
|
||||
/* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
|
||||
@ -890,7 +967,6 @@ var HighlightAnnotationElement = (
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
@ -907,7 +983,8 @@ var UnderlineAnnotationElement = (
|
||||
function UnderlineAnnotationElement(parameters) {
|
||||
var isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
AnnotationElement.call(this, parameters, isRenderable);
|
||||
AnnotationElement.call(this, parameters, isRenderable,
|
||||
/* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
|
||||
@ -924,7 +1001,6 @@ var UnderlineAnnotationElement = (
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
@ -940,7 +1016,8 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
||||
function SquigglyAnnotationElement(parameters) {
|
||||
var isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
AnnotationElement.call(this, parameters, isRenderable);
|
||||
AnnotationElement.call(this, parameters, isRenderable,
|
||||
/* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
|
||||
@ -957,7 +1034,6 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
@ -974,7 +1050,8 @@ var StrikeOutAnnotationElement = (
|
||||
function StrikeOutAnnotationElement(parameters) {
|
||||
var isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
AnnotationElement.call(this, parameters, isRenderable);
|
||||
AnnotationElement.call(this, parameters, isRenderable,
|
||||
/* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
|
||||
@ -991,7 +1068,6 @@ var StrikeOutAnnotationElement = (
|
||||
if (!this.data.hasPopup) {
|
||||
this._createPopup(this.container, null, this.data);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -269,6 +269,7 @@
|
||||
!annotation-strikeout.pdf
|
||||
!annotation-squiggly.pdf
|
||||
!annotation-highlight.pdf
|
||||
!annotation-line.pdf
|
||||
!annotation-fileattachment.pdf
|
||||
!annotation-text-widget.pdf
|
||||
!annotation-choice-widget.pdf
|
||||
|
BIN
test/pdfs/annotation-line.pdf
Executable file
BIN
test/pdfs/annotation-line.pdf
Executable file
Binary file not shown.
@ -3370,6 +3370,13 @@
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "annotation-line",
|
||||
"file": "pdfs/annotation-line.pdf",
|
||||
"md5": "fde60608be2748f10fb6522cba425ca1",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "annotation-fileattachment",
|
||||
"file": "pdfs/annotation-fileattachment.pdf",
|
||||
"md5": "d20ecee4b53c81b2dd44c8715a1b4a83",
|
||||
|
@ -1287,6 +1287,27 @@ describe('annotation', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('LineAnnotation', function() {
|
||||
it('should set the line coordinates', function() {
|
||||
var lineDict = new Dict();
|
||||
lineDict.set('Type', Name.get('Annot'));
|
||||
lineDict.set('Subtype', Name.get('Line'));
|
||||
lineDict.set('L', [1, 2, 3, 4]);
|
||||
|
||||
var lineRef = new Ref(122, 0);
|
||||
var xref = new XRefMock([
|
||||
{ ref: lineRef, data: lineDict, }
|
||||
]);
|
||||
|
||||
var annotation = annotationFactory.create(xref, lineRef, pdfManagerMock,
|
||||
idFactoryMock);
|
||||
var data = annotation.data;
|
||||
expect(data.annotationType).toEqual(AnnotationType.LINE);
|
||||
|
||||
expect(data.lineCoordinates).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('FileAttachmentAnnotation', function() {
|
||||
it('should correctly parse a file attachment', function() {
|
||||
var fileStream = new StringStream(
|
||||
|
@ -143,6 +143,7 @@
|
||||
.annotationLayer .underlineAnnotation,
|
||||
.annotationLayer .squigglyAnnotation,
|
||||
.annotationLayer .strikeoutAnnotation,
|
||||
.annotationLayer .lineAnnotation svg line,
|
||||
.annotationLayer .fileAttachmentAnnotation {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user