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':
|
case 'Popup':
|
||||||
return new PopupAnnotation(parameters);
|
return new PopupAnnotation(parameters);
|
||||||
|
|
||||||
|
case 'Line':
|
||||||
|
return new LineAnnotation(parameters);
|
||||||
|
|
||||||
case 'Highlight':
|
case 'Highlight':
|
||||||
return new HighlightAnnotation(parameters);
|
return new HighlightAnnotation(parameters);
|
||||||
|
|
||||||
@ -955,6 +958,8 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parentSubtype = parentItem.get('Subtype');
|
||||||
|
this.data.parentType = isName(parentSubtype) ? parentSubtype.name : null;
|
||||||
this.data.parentId = dict.getRaw('Parent').toString();
|
this.data.parentId = dict.getRaw('Parent').toString();
|
||||||
this.data.title = stringToPDFString(parentItem.get('T') || '');
|
this.data.title = stringToPDFString(parentItem.get('T') || '');
|
||||||
this.data.contents = stringToPDFString(parentItem.get('Contents') || '');
|
this.data.contents = stringToPDFString(parentItem.get('Contents') || '');
|
||||||
@ -983,15 +988,28 @@ var PopupAnnotation = (function PopupAnnotationClosure() {
|
|||||||
return PopupAnnotation;
|
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() {
|
var HighlightAnnotation = (function HighlightAnnotationClosure() {
|
||||||
function HighlightAnnotation(parameters) {
|
function HighlightAnnotation(parameters) {
|
||||||
Annotation.call(this, parameters);
|
Annotation.call(this, parameters);
|
||||||
|
|
||||||
this.data.annotationType = AnnotationType.HIGHLIGHT;
|
this.data.annotationType = AnnotationType.HIGHLIGHT;
|
||||||
this._preparePopup(parameters.dict);
|
this._preparePopup(parameters.dict);
|
||||||
|
|
||||||
// PDF viewers completely ignore any border styles.
|
|
||||||
this.data.borderStyle.setWidth(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(HighlightAnnotation, Annotation, {});
|
Util.inherit(HighlightAnnotation, Annotation, {});
|
||||||
@ -1005,9 +1023,6 @@ var UnderlineAnnotation = (function UnderlineAnnotationClosure() {
|
|||||||
|
|
||||||
this.data.annotationType = AnnotationType.UNDERLINE;
|
this.data.annotationType = AnnotationType.UNDERLINE;
|
||||||
this._preparePopup(parameters.dict);
|
this._preparePopup(parameters.dict);
|
||||||
|
|
||||||
// PDF viewers completely ignore any border styles.
|
|
||||||
this.data.borderStyle.setWidth(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(UnderlineAnnotation, Annotation, {});
|
Util.inherit(UnderlineAnnotation, Annotation, {});
|
||||||
@ -1021,9 +1036,6 @@ var SquigglyAnnotation = (function SquigglyAnnotationClosure() {
|
|||||||
|
|
||||||
this.data.annotationType = AnnotationType.SQUIGGLY;
|
this.data.annotationType = AnnotationType.SQUIGGLY;
|
||||||
this._preparePopup(parameters.dict);
|
this._preparePopup(parameters.dict);
|
||||||
|
|
||||||
// PDF viewers completely ignore any border styles.
|
|
||||||
this.data.borderStyle.setWidth(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(SquigglyAnnotation, Annotation, {});
|
Util.inherit(SquigglyAnnotation, Annotation, {});
|
||||||
@ -1037,9 +1049,6 @@ var StrikeOutAnnotation = (function StrikeOutAnnotationClosure() {
|
|||||||
|
|
||||||
this.data.annotationType = AnnotationType.STRIKEOUT;
|
this.data.annotationType = AnnotationType.STRIKEOUT;
|
||||||
this._preparePopup(parameters.dict);
|
this._preparePopup(parameters.dict);
|
||||||
|
|
||||||
// PDF viewers completely ignore any border styles.
|
|
||||||
this.data.borderStyle.setWidth(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(StrikeOutAnnotation, Annotation, {});
|
Util.inherit(StrikeOutAnnotation, Annotation, {});
|
||||||
|
@ -93,6 +93,9 @@ AnnotationElementFactory.prototype =
|
|||||||
case AnnotationType.POPUP:
|
case AnnotationType.POPUP:
|
||||||
return new PopupAnnotationElement(parameters);
|
return new PopupAnnotationElement(parameters);
|
||||||
|
|
||||||
|
case AnnotationType.LINE:
|
||||||
|
return new LineAnnotationElement(parameters);
|
||||||
|
|
||||||
case AnnotationType.HIGHLIGHT:
|
case AnnotationType.HIGHLIGHT:
|
||||||
return new HighlightAnnotationElement(parameters);
|
return new HighlightAnnotationElement(parameters);
|
||||||
|
|
||||||
@ -119,7 +122,7 @@ AnnotationElementFactory.prototype =
|
|||||||
* @alias AnnotationElement
|
* @alias AnnotationElement
|
||||||
*/
|
*/
|
||||||
var AnnotationElement = (function AnnotationElementClosure() {
|
var AnnotationElement = (function AnnotationElementClosure() {
|
||||||
function AnnotationElement(parameters, isRenderable) {
|
function AnnotationElement(parameters, isRenderable, ignoreBorder) {
|
||||||
this.isRenderable = isRenderable || false;
|
this.isRenderable = isRenderable || false;
|
||||||
this.data = parameters.data;
|
this.data = parameters.data;
|
||||||
this.layer = parameters.layer;
|
this.layer = parameters.layer;
|
||||||
@ -131,7 +134,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
|||||||
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
||||||
|
|
||||||
if (isRenderable) {
|
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.
|
* Create an empty container for the annotation's HTML element.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
|
* @param {boolean} ignoreBorder
|
||||||
* @memberof AnnotationElement
|
* @memberof AnnotationElement
|
||||||
* @returns {HTMLSectionElement}
|
* @returns {HTMLSectionElement}
|
||||||
*/
|
*/
|
||||||
_createContainer: function AnnotationElement_createContainer() {
|
_createContainer:
|
||||||
|
function AnnotationElement_createContainer(ignoreBorder) {
|
||||||
var data = this.data, page = this.page, viewport = this.viewport;
|
var data = this.data, page = this.page, viewport = this.viewport;
|
||||||
var container = document.createElement('section');
|
var container = document.createElement('section');
|
||||||
var width = data.rect[2] - data.rect[0];
|
var width = data.rect[2] - data.rect[0];
|
||||||
@ -165,7 +170,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
|||||||
CustomStyle.setProp('transformOrigin', container,
|
CustomStyle.setProp('transformOrigin', container,
|
||||||
-rect[0] + 'px ' + -rect[1] + 'px');
|
-rect[0] + 'px ' + -rect[1] + 'px');
|
||||||
|
|
||||||
if (data.borderStyle.width > 0) {
|
if (!ignoreBorder && data.borderStyle.width > 0) {
|
||||||
container.style.borderWidth = data.borderStyle.width + 'px';
|
container.style.borderWidth = data.borderStyle.width + 'px';
|
||||||
if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
|
if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
|
||||||
// Underline styles only have a bottom border, so we do not need
|
// Underline styles only have a bottom border, so we do not need
|
||||||
@ -679,6 +684,10 @@ var ChoiceWidgetAnnotationElement = (
|
|||||||
* @alias PopupAnnotationElement
|
* @alias PopupAnnotationElement
|
||||||
*/
|
*/
|
||||||
var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
|
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) {
|
function PopupAnnotationElement(parameters) {
|
||||||
var isRenderable = !!(parameters.data.title || parameters.data.contents);
|
var isRenderable = !!(parameters.data.title || parameters.data.contents);
|
||||||
AnnotationElement.call(this, parameters, isRenderable);
|
AnnotationElement.call(this, parameters, isRenderable);
|
||||||
@ -695,6 +704,10 @@ var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
|
|||||||
render: function PopupAnnotationElement_render() {
|
render: function PopupAnnotationElement_render() {
|
||||||
this.container.className = 'popupAnnotation';
|
this.container.className = 'popupAnnotation';
|
||||||
|
|
||||||
|
if (IGNORE_TYPES.indexOf(this.data.parentType) >= 0) {
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
|
||||||
var selector = '[data-annotation-id="' + this.data.parentId + '"]';
|
var selector = '[data-annotation-id="' + this.data.parentId + '"]';
|
||||||
var parentElement = this.layer.querySelector(selector);
|
var parentElement = this.layer.querySelector(selector);
|
||||||
if (!parentElement) {
|
if (!parentElement) {
|
||||||
@ -864,6 +877,69 @@ var PopupElement = (function PopupElementClosure() {
|
|||||||
return PopupElement;
|
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
|
* @class
|
||||||
* @alias HighlightAnnotationElement
|
* @alias HighlightAnnotationElement
|
||||||
@ -873,7 +949,8 @@ var HighlightAnnotationElement = (
|
|||||||
function HighlightAnnotationElement(parameters) {
|
function HighlightAnnotationElement(parameters) {
|
||||||
var isRenderable = !!(parameters.data.hasPopup ||
|
var isRenderable = !!(parameters.data.hasPopup ||
|
||||||
parameters.data.title || parameters.data.contents);
|
parameters.data.title || parameters.data.contents);
|
||||||
AnnotationElement.call(this, parameters, isRenderable);
|
AnnotationElement.call(this, parameters, isRenderable,
|
||||||
|
/* ignoreBorder = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
|
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
|
||||||
@ -890,7 +967,6 @@ var HighlightAnnotationElement = (
|
|||||||
if (!this.data.hasPopup) {
|
if (!this.data.hasPopup) {
|
||||||
this._createPopup(this.container, null, this.data);
|
this._createPopup(this.container, null, this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -907,7 +983,8 @@ var UnderlineAnnotationElement = (
|
|||||||
function UnderlineAnnotationElement(parameters) {
|
function UnderlineAnnotationElement(parameters) {
|
||||||
var isRenderable = !!(parameters.data.hasPopup ||
|
var isRenderable = !!(parameters.data.hasPopup ||
|
||||||
parameters.data.title || parameters.data.contents);
|
parameters.data.title || parameters.data.contents);
|
||||||
AnnotationElement.call(this, parameters, isRenderable);
|
AnnotationElement.call(this, parameters, isRenderable,
|
||||||
|
/* ignoreBorder = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
|
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
|
||||||
@ -924,7 +1001,6 @@ var UnderlineAnnotationElement = (
|
|||||||
if (!this.data.hasPopup) {
|
if (!this.data.hasPopup) {
|
||||||
this._createPopup(this.container, null, this.data);
|
this._createPopup(this.container, null, this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -940,7 +1016,8 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
|||||||
function SquigglyAnnotationElement(parameters) {
|
function SquigglyAnnotationElement(parameters) {
|
||||||
var isRenderable = !!(parameters.data.hasPopup ||
|
var isRenderable = !!(parameters.data.hasPopup ||
|
||||||
parameters.data.title || parameters.data.contents);
|
parameters.data.title || parameters.data.contents);
|
||||||
AnnotationElement.call(this, parameters, isRenderable);
|
AnnotationElement.call(this, parameters, isRenderable,
|
||||||
|
/* ignoreBorder = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
|
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
|
||||||
@ -957,7 +1034,6 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
|||||||
if (!this.data.hasPopup) {
|
if (!this.data.hasPopup) {
|
||||||
this._createPopup(this.container, null, this.data);
|
this._createPopup(this.container, null, this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -974,7 +1050,8 @@ var StrikeOutAnnotationElement = (
|
|||||||
function StrikeOutAnnotationElement(parameters) {
|
function StrikeOutAnnotationElement(parameters) {
|
||||||
var isRenderable = !!(parameters.data.hasPopup ||
|
var isRenderable = !!(parameters.data.hasPopup ||
|
||||||
parameters.data.title || parameters.data.contents);
|
parameters.data.title || parameters.data.contents);
|
||||||
AnnotationElement.call(this, parameters, isRenderable);
|
AnnotationElement.call(this, parameters, isRenderable,
|
||||||
|
/* ignoreBorder = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
|
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
|
||||||
@ -991,7 +1068,6 @@ var StrikeOutAnnotationElement = (
|
|||||||
if (!this.data.hasPopup) {
|
if (!this.data.hasPopup) {
|
||||||
this._createPopup(this.container, null, this.data);
|
this._createPopup(this.container, null, this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -269,6 +269,7 @@
|
|||||||
!annotation-strikeout.pdf
|
!annotation-strikeout.pdf
|
||||||
!annotation-squiggly.pdf
|
!annotation-squiggly.pdf
|
||||||
!annotation-highlight.pdf
|
!annotation-highlight.pdf
|
||||||
|
!annotation-line.pdf
|
||||||
!annotation-fileattachment.pdf
|
!annotation-fileattachment.pdf
|
||||||
!annotation-text-widget.pdf
|
!annotation-text-widget.pdf
|
||||||
!annotation-choice-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",
|
"type": "eq",
|
||||||
"annotations": true
|
"annotations": true
|
||||||
},
|
},
|
||||||
|
{ "id": "annotation-line",
|
||||||
|
"file": "pdfs/annotation-line.pdf",
|
||||||
|
"md5": "fde60608be2748f10fb6522cba425ca1",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq",
|
||||||
|
"annotations": true
|
||||||
|
},
|
||||||
{ "id": "annotation-fileattachment",
|
{ "id": "annotation-fileattachment",
|
||||||
"file": "pdfs/annotation-fileattachment.pdf",
|
"file": "pdfs/annotation-fileattachment.pdf",
|
||||||
"md5": "d20ecee4b53c81b2dd44c8715a1b4a83",
|
"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() {
|
describe('FileAttachmentAnnotation', function() {
|
||||||
it('should correctly parse a file attachment', function() {
|
it('should correctly parse a file attachment', function() {
|
||||||
var fileStream = new StringStream(
|
var fileStream = new StringStream(
|
||||||
|
@ -143,6 +143,7 @@
|
|||||||
.annotationLayer .underlineAnnotation,
|
.annotationLayer .underlineAnnotation,
|
||||||
.annotationLayer .squigglyAnnotation,
|
.annotationLayer .squigglyAnnotation,
|
||||||
.annotationLayer .strikeoutAnnotation,
|
.annotationLayer .strikeoutAnnotation,
|
||||||
|
.annotationLayer .lineAnnotation svg line,
|
||||||
.annotationLayer .fileAttachmentAnnotation {
|
.annotationLayer .fileAttachmentAnnotation {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user