Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for polyline and polygon annotations #8950

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ class AnnotationFactory {
case 'Circle':
return new CircleAnnotation(parameters);

case 'PolyLine':
return new PolylineAnnotation(parameters);

case 'Polygon':
return new PolygonAnnotation(parameters);

case 'Highlight':
return new HighlightAnnotation(parameters);

Expand Down Expand Up @@ -913,6 +919,39 @@ class CircleAnnotation extends Annotation {
}
}

class PolylineAnnotation extends Annotation {
constructor(parameters) {
super(parameters);

this.data.annotationType = AnnotationType.POLYLINE;

// The vertices array is an array of numbers representing the alternating
// horizontal and vertical coordinates, respectively, of each vertex.
// Convert this to an array of objects with x and y coordinates.
let dict = parameters.dict;
let rawVertices = dict.getArray('Vertices');

this.data.vertices = [];
for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
this.data.vertices.push({
x: rawVertices[i],
y: rawVertices[i + 1],
});
}

this._preparePopup(dict);
}
}

class PolygonAnnotation extends PolylineAnnotation {
constructor(parameters) {
// Polygons are specific forms of polylines, so reuse their logic.
super(parameters);

this.data.annotationType = AnnotationType.POLYGON;
}
}

class HighlightAnnotation extends Annotation {
constructor(parameters) {
super(parameters);
Expand Down
77 changes: 76 additions & 1 deletion src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ class AnnotationElementFactory {
case AnnotationType.CIRCLE:
return new CircleAnnotationElement(parameters);

case AnnotationType.POLYLINE:
return new PolylineAnnotationElement(parameters);

case AnnotationType.POLYGON:
return new PolygonAnnotationElement(parameters);

case AnnotationType.HIGHLIGHT:
return new HighlightAnnotationElement(parameters);

Expand Down Expand Up @@ -601,7 +607,7 @@ class PopupAnnotationElement extends AnnotationElement {
render() {
// Do not render popup annotations for parent elements with these types as
// they create the popups themselves (because of custom trigger divs).
const IGNORE_TYPES = ['Line', 'Square', 'Circle'];
const IGNORE_TYPES = ['Line', 'Square', 'Circle', 'PolyLine', 'Polygon'];

this.container.className = 'popupAnnotation';

Expand Down Expand Up @@ -911,6 +917,75 @@ class CircleAnnotationElement extends AnnotationElement {
}
}

class PolylineAnnotationElement extends AnnotationElement {
constructor(parameters) {
let isRenderable = !!(parameters.data.hasPopup ||
parameters.data.title || parameters.data.contents);
super(parameters, isRenderable, /* ignoreBorder = */ true);

this.containerClassName = 'polylineAnnotation';
this.svgElementName = 'svg:polyline';
}

/**
* Render the polyline annotation's HTML element in the empty container.
*
* @public
* @memberof PolylineAnnotationElement
* @returns {HTMLSectionElement}
*/
render() {
this.container.className = this.containerClassName;

// Create an invisible polyline with the same points that acts as the
// trigger for the popup. Only the polyline itself should trigger the
// popup, not the entire container.
let data = this.data;
let width = data.rect[2] - data.rect[0];
let height = data.rect[3] - data.rect[1];
let svg = this.svgFactory.create(width, height);

// Convert the vertices array to a single points string that the SVG
// polyline element expects ("x1,y1 x2,y2 ..."). PDF coordinates are
// calculated from a bottom left origin, so transform the polyline
// coordinates to a top left origin for the SVG element.
let vertices = data.vertices;
let points = [];
for (let i = 0, ii = vertices.length; i < ii; i++) {
let x = vertices[i].x - data.rect[0];
let y = data.rect[3] - vertices[i].y;
points.push(x + ',' + y);
}
points = points.join(' ');

let borderWidth = data.borderStyle.width;
let polyline = this.svgFactory.createElement(this.svgElementName);
polyline.setAttribute('points', points);
polyline.setAttribute('stroke-width', borderWidth);
polyline.setAttribute('stroke', 'transparent');
polyline.setAttribute('fill', 'none');

svg.appendChild(polyline);
this.container.append(svg);

// Create the popup ourselves so that we can bind it to the polyline
// instead of to the entire container (which is the default).
this._createPopup(this.container, polyline, data);

return this.container;
}
}

class PolygonAnnotationElement extends PolylineAnnotationElement {
constructor(parameters) {
// Polygons are specific forms of polylines, so reuse their logic.
super(parameters);

this.containerClassName = 'polygonAnnotation';
this.svgElementName = 'svg:polygon';
}
}

class HighlightAnnotationElement extends AnnotationElement {
constructor(parameters) {
let isRenderable = !!(parameters.data.hasPopup ||
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@
!annotation-text-widget.pdf
!annotation-choice-widget.pdf
!annotation-button-widget.pdf
!annotation-polyline-polygon.pdf
!zero_descent.pdf
!operator-in-TJ-array.pdf
!issue7878.pdf
Expand Down
Binary file added test/pdfs/annotation-polyline-polygon.pdf
Binary file not shown.
7 changes: 7 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3639,6 +3639,13 @@
"type": "eq",
"forms": true
},
{ "id": "annotation-polyline-polygon",
"file": "pdfs/annotation-polyline-polygon.pdf",
"md5": "e68611602f58c8ca70cc40575ba3b04e",
"rounds": 1,
"type": "eq",
"annotations": true
},
{ "id": "issue6108",
"file": "pdfs/issue6108.pdf",
"md5": "8961cb55149495989a80bf0487e0f076",
Expand Down
2 changes: 2 additions & 0 deletions web/annotation_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@
.annotationLayer .lineAnnotation svg line,
.annotationLayer .squareAnnotation svg rect,
.annotationLayer .circleAnnotation svg ellipse,
.annotationLayer .polylineAnnotation svg polyline,
.annotationLayer .polygonAnnotation svg polygon,
.annotationLayer .stampAnnotation,
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
Expand Down