Merge pull request #8691 from timvandermeij/square-circle-annotations
Implement support for square and circle annotations
This commit is contained in:
commit
320779e6ed
@ -81,6 +81,12 @@ class AnnotationFactory {
|
||||
case 'Line':
|
||||
return new LineAnnotation(parameters);
|
||||
|
||||
case 'Square':
|
||||
return new SquareAnnotation(parameters);
|
||||
|
||||
case 'Circle':
|
||||
return new CircleAnnotation(parameters);
|
||||
|
||||
case 'Highlight':
|
||||
return new HighlightAnnotation(parameters);
|
||||
|
||||
@ -886,6 +892,24 @@ class LineAnnotation extends Annotation {
|
||||
}
|
||||
}
|
||||
|
||||
class SquareAnnotation extends Annotation {
|
||||
constructor(parameters) {
|
||||
super(parameters);
|
||||
|
||||
this.data.annotationType = AnnotationType.SQUARE;
|
||||
this._preparePopup(parameters.dict);
|
||||
}
|
||||
}
|
||||
|
||||
class CircleAnnotation extends Annotation {
|
||||
constructor(parameters) {
|
||||
super(parameters);
|
||||
|
||||
this.data.annotationType = AnnotationType.CIRCLE;
|
||||
this._preparePopup(parameters.dict);
|
||||
}
|
||||
}
|
||||
|
||||
class HighlightAnnotation extends Annotation {
|
||||
constructor(parameters) {
|
||||
super(parameters);
|
||||
|
@ -14,8 +14,8 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
addLinkAttributes, CustomStyle, getDefaultSetting, getFilenameFromUrl,
|
||||
LinkTarget
|
||||
addLinkAttributes, CustomStyle, DOMSVGFactory, getDefaultSetting,
|
||||
getFilenameFromUrl, LinkTarget
|
||||
} from './dom_utils';
|
||||
import {
|
||||
AnnotationBorderStyleType, AnnotationType, stringToPDFString, Util, warn
|
||||
@ -31,6 +31,7 @@ import {
|
||||
* @property {DownloadManager} downloadManager
|
||||
* @property {string} imageResourcesPath
|
||||
* @property {boolean} renderInteractiveForms
|
||||
* @property {Object} svgFactory
|
||||
*/
|
||||
|
||||
class AnnotationElementFactory {
|
||||
@ -73,6 +74,12 @@ class AnnotationElementFactory {
|
||||
case AnnotationType.LINE:
|
||||
return new LineAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.SQUARE:
|
||||
return new SquareAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.CIRCLE:
|
||||
return new CircleAnnotationElement(parameters);
|
||||
|
||||
case AnnotationType.HIGHLIGHT:
|
||||
return new HighlightAnnotationElement(parameters);
|
||||
|
||||
@ -105,6 +112,7 @@ class AnnotationElement {
|
||||
this.downloadManager = parameters.downloadManager;
|
||||
this.imageResourcesPath = parameters.imageResourcesPath;
|
||||
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
||||
this.svgFactory = parameters.svgFactory;
|
||||
|
||||
if (isRenderable) {
|
||||
this.container = this._createContainer(ignoreBorder);
|
||||
@ -590,7 +598,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'];
|
||||
const IGNORE_TYPES = ['Line', 'Square', 'Circle'];
|
||||
|
||||
this.container.className = 'popupAnnotation';
|
||||
|
||||
@ -771,8 +779,6 @@ class LineAnnotationElement extends AnnotationElement {
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||
|
||||
this.container.className = 'lineAnnotation';
|
||||
|
||||
// Create an invisible line with the same starting and ending coordinates
|
||||
@ -781,30 +787,122 @@ class LineAnnotationElement extends AnnotationElement {
|
||||
let data = this.data;
|
||||
let width = data.rect[2] - data.rect[0];
|
||||
let height = data.rect[3] - data.rect[1];
|
||||
|
||||
let 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);
|
||||
let svg = this.svgFactory.create(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.
|
||||
let 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');
|
||||
let line = this.svgFactory.createElement('svg:line');
|
||||
line.setAttribute('x1', data.rect[2] - data.lineCoordinates[0]);
|
||||
line.setAttribute('y1', data.rect[3] - data.lineCoordinates[1]);
|
||||
line.setAttribute('x2', data.rect[2] - data.lineCoordinates[2]);
|
||||
line.setAttribute('y2', data.rect[3] - data.lineCoordinates[3]);
|
||||
line.setAttribute('stroke-width', data.borderStyle.width);
|
||||
line.setAttribute('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);
|
||||
this._createPopup(this.container, line, data);
|
||||
|
||||
return this.container;
|
||||
}
|
||||
}
|
||||
|
||||
class SquareAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
let isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the square annotation's HTML element in the empty container.
|
||||
*
|
||||
* @public
|
||||
* @memberof SquareAnnotationElement
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'squareAnnotation';
|
||||
|
||||
// Create an invisible square with the same rectangle that acts as the
|
||||
// trigger for the popup. Only the square 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);
|
||||
|
||||
// The browser draws half of the borders inside the square and half of
|
||||
// the borders outside the square by default. This behavior cannot be
|
||||
// changed programmatically, so correct for that here.
|
||||
let borderWidth = data.borderStyle.width;
|
||||
let square = this.svgFactory.createElement('svg:rect');
|
||||
square.setAttribute('x', borderWidth / 2);
|
||||
square.setAttribute('y', borderWidth / 2);
|
||||
square.setAttribute('width', width - borderWidth);
|
||||
square.setAttribute('height', height - borderWidth);
|
||||
square.setAttribute('stroke-width', borderWidth);
|
||||
square.setAttribute('stroke', 'transparent');
|
||||
square.setAttribute('fill', 'none');
|
||||
|
||||
svg.appendChild(square);
|
||||
this.container.append(svg);
|
||||
|
||||
// Create the popup ourselves so that we can bind it to the square instead
|
||||
// of to the entire container (which is the default).
|
||||
this._createPopup(this.container, square, data);
|
||||
|
||||
return this.container;
|
||||
}
|
||||
}
|
||||
|
||||
class CircleAnnotationElement extends AnnotationElement {
|
||||
constructor(parameters) {
|
||||
let isRenderable = !!(parameters.data.hasPopup ||
|
||||
parameters.data.title || parameters.data.contents);
|
||||
super(parameters, isRenderable, /* ignoreBorder = */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the circle annotation's HTML element in the empty container.
|
||||
*
|
||||
* @public
|
||||
* @memberof CircleAnnotationElement
|
||||
* @returns {HTMLSectionElement}
|
||||
*/
|
||||
render() {
|
||||
this.container.className = 'circleAnnotation';
|
||||
|
||||
// Create an invisible circle with the same ellipse that acts as the
|
||||
// trigger for the popup. Only the circle 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);
|
||||
|
||||
// The browser draws half of the borders inside the circle and half of
|
||||
// the borders outside the circle by default. This behavior cannot be
|
||||
// changed programmatically, so correct for that here.
|
||||
let borderWidth = data.borderStyle.width;
|
||||
let circle = this.svgFactory.createElement('svg:ellipse');
|
||||
circle.setAttribute('cx', width / 2);
|
||||
circle.setAttribute('cy', height / 2);
|
||||
circle.setAttribute('rx', (width / 2) - (borderWidth / 2));
|
||||
circle.setAttribute('ry', (height / 2) - (borderWidth / 2));
|
||||
circle.setAttribute('stroke-width', borderWidth);
|
||||
circle.setAttribute('stroke', 'transparent');
|
||||
circle.setAttribute('fill', 'none');
|
||||
|
||||
svg.appendChild(circle);
|
||||
this.container.append(svg);
|
||||
|
||||
// Create the popup ourselves so that we can bind it to the circle instead
|
||||
// of to the entire container (which is the default).
|
||||
this._createPopup(this.container, circle, data);
|
||||
|
||||
return this.container;
|
||||
}
|
||||
@ -995,6 +1093,7 @@ class AnnotationLayer {
|
||||
imageResourcesPath: parameters.imageResourcesPath ||
|
||||
getDefaultSetting('imageResourcesPath'),
|
||||
renderInteractiveForms: parameters.renderInteractiveForms || false,
|
||||
svgFactory: new DOMSVGFactory(),
|
||||
});
|
||||
if (element.isRenderable) {
|
||||
parameters.div.appendChild(element.render());
|
||||
|
@ -14,12 +14,13 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
CMapCompressionType, createValidAbsoluteUrl, deprecated,
|
||||
assert, CMapCompressionType, createValidAbsoluteUrl, deprecated,
|
||||
removeNullCharacters, stringToBytes, warn
|
||||
} from '../shared/util';
|
||||
import globalScope from '../shared/global_scope';
|
||||
|
||||
var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
||||
const DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
|
||||
const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||
|
||||
class DOMCanvasFactory {
|
||||
create(width, height) {
|
||||
@ -109,6 +110,27 @@ class DOMCMapReaderFactory {
|
||||
}
|
||||
}
|
||||
|
||||
class DOMSVGFactory {
|
||||
create(width, height) {
|
||||
assert(width > 0 && height > 0, 'Invalid SVG dimensions');
|
||||
|
||||
let svg = document.createElementNS(SVG_NS, 'svg:svg');
|
||||
svg.setAttribute('version', '1.1');
|
||||
svg.setAttribute('width', width + 'px');
|
||||
svg.setAttribute('height', height + 'px');
|
||||
svg.setAttribute('preserveAspectRatio', 'none');
|
||||
svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
createElement(type) {
|
||||
assert(typeof type === 'string', 'Invalid SVG element type');
|
||||
|
||||
return document.createElementNS(SVG_NS, type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimised CSS custom property getter/setter.
|
||||
* @class
|
||||
@ -330,4 +352,5 @@ export {
|
||||
DEFAULT_LINK_REL,
|
||||
DOMCanvasFactory,
|
||||
DOMCMapReaderFactory,
|
||||
DOMSVGFactory,
|
||||
};
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNodeJS,
|
||||
isNum, OPS, Util, warn
|
||||
} from '../shared/util';
|
||||
import { DOMSVGFactory } from './dom_utils';
|
||||
|
||||
var SVGGraphics = function() {
|
||||
throw new Error('Not implemented: SVGGraphics');
|
||||
@ -403,6 +404,8 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
}
|
||||
|
||||
function SVGGraphics(commonObjs, objs, forceDataSchema) {
|
||||
this.svgFactory = new DOMSVGFactory();
|
||||
|
||||
this.current = new SVGExtraState();
|
||||
this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix
|
||||
this.transformStack = [];
|
||||
@ -418,7 +421,6 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
this.forceDataSchema = !!forceDataSchema;
|
||||
}
|
||||
|
||||
var NS = 'http://www.w3.org/2000/svg';
|
||||
var XML_NS = 'http://www.w3.org/XML/1998/namespace';
|
||||
var XLINK_NS = 'http://www.w3.org/1999/xlink';
|
||||
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
|
||||
@ -683,13 +685,13 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
this.current.y = this.current.lineY = 0;
|
||||
|
||||
current.xcoords = [];
|
||||
current.tspan = document.createElementNS(NS, 'svg:tspan');
|
||||
current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
||||
current.tspan.setAttributeNS(null, 'font-size',
|
||||
pf(current.fontSize) + 'px');
|
||||
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
||||
|
||||
current.txtElement = document.createElementNS(NS, 'svg:text');
|
||||
current.txtElement = this.svgFactory.createElement('svg:text');
|
||||
current.txtElement.appendChild(current.tspan);
|
||||
},
|
||||
|
||||
@ -698,9 +700,9 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
this.current.y = this.current.lineY = 0;
|
||||
this.current.textMatrix = IDENTITY_MATRIX;
|
||||
this.current.lineMatrix = IDENTITY_MATRIX;
|
||||
this.current.tspan = document.createElementNS(NS, 'svg:tspan');
|
||||
this.current.txtElement = document.createElementNS(NS, 'svg:text');
|
||||
this.current.txtgrp = document.createElementNS(NS, 'svg:g');
|
||||
this.current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||
this.current.txtElement = this.svgFactory.createElement('svg:text');
|
||||
this.current.txtgrp = this.svgFactory.createElement('svg:g');
|
||||
this.current.xcoords = [];
|
||||
},
|
||||
|
||||
@ -710,7 +712,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
this.current.y = this.current.lineY += y;
|
||||
|
||||
current.xcoords = [];
|
||||
current.tspan = document.createElementNS(NS, 'svg:tspan');
|
||||
current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
||||
current.tspan.setAttributeNS(null, 'font-size',
|
||||
pf(current.fontSize) + 'px');
|
||||
@ -810,7 +812,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
|
||||
addFontStyle: function SVGGraphics_addFontStyle(fontObj) {
|
||||
if (!this.cssStyle) {
|
||||
this.cssStyle = document.createElementNS(NS, 'svg:style');
|
||||
this.cssStyle = this.svgFactory.createElement('svg:style');
|
||||
this.cssStyle.setAttributeNS(null, 'type', 'text/css');
|
||||
this.defs.appendChild(this.cssStyle);
|
||||
}
|
||||
@ -852,7 +854,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
current.fontWeight = bold;
|
||||
current.fontStyle = italic;
|
||||
|
||||
current.tspan = document.createElementNS(NS, 'svg:tspan');
|
||||
current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
||||
current.xcoords = [];
|
||||
},
|
||||
@ -885,7 +887,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {
|
||||
var color = Util.makeCssRgb(r, g, b);
|
||||
this.current.fillColor = color;
|
||||
this.current.tspan = document.createElementNS(NS, 'svg:tspan');
|
||||
this.current.tspan = this.svgFactory.createElement('svg:tspan');
|
||||
this.current.xcoords = [];
|
||||
},
|
||||
setDash: function SVGGraphics_setDash(dashArray, dashPhase) {
|
||||
@ -896,7 +898,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
constructPath: function SVGGraphics_constructPath(ops, args) {
|
||||
var current = this.current;
|
||||
var x = current.x, y = current.y;
|
||||
current.path = document.createElementNS(NS, 'svg:path');
|
||||
current.path = this.svgFactory.createElement('svg:path');
|
||||
var d = [];
|
||||
var opLength = ops.length;
|
||||
|
||||
@ -967,7 +969,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
// Add current path to clipping path
|
||||
var clipId = 'clippath' + clipCount;
|
||||
clipCount++;
|
||||
var clipPath = document.createElementNS(NS, 'svg:clipPath');
|
||||
var clipPath = this.svgFactory.createElement('svg:clipPath');
|
||||
clipPath.setAttributeNS(null, 'id', clipId);
|
||||
clipPath.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
||||
var clipElement = current.element.cloneNode();
|
||||
@ -1110,7 +1112,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
paintSolidColorImageMask:
|
||||
function SVGGraphics_paintSolidColorImageMask() {
|
||||
var current = this.current;
|
||||
var rect = document.createElementNS(NS, 'svg:rect');
|
||||
var rect = this.svgFactory.createElement('svg:rect');
|
||||
rect.setAttributeNS(null, 'x', '0');
|
||||
rect.setAttributeNS(null, 'y', '0');
|
||||
rect.setAttributeNS(null, 'width', '1px');
|
||||
@ -1122,7 +1124,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
|
||||
paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {
|
||||
var imgObj = this.objs.get(objId);
|
||||
var imgEl = document.createElementNS(NS, 'svg:image');
|
||||
var imgEl = this.svgFactory.createElement('svg:image');
|
||||
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);
|
||||
imgEl.setAttributeNS(null, 'width', pf(w));
|
||||
imgEl.setAttributeNS(null, 'height', pf(h));
|
||||
@ -1149,14 +1151,14 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
var height = imgData.height;
|
||||
|
||||
var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema);
|
||||
var cliprect = document.createElementNS(NS, 'svg:rect');
|
||||
var cliprect = this.svgFactory.createElement('svg:rect');
|
||||
cliprect.setAttributeNS(null, 'x', '0');
|
||||
cliprect.setAttributeNS(null, 'y', '0');
|
||||
cliprect.setAttributeNS(null, 'width', pf(width));
|
||||
cliprect.setAttributeNS(null, 'height', pf(height));
|
||||
this.current.element = cliprect;
|
||||
this.clip('nonzero');
|
||||
var imgEl = document.createElementNS(NS, 'svg:image');
|
||||
var imgEl = this.svgFactory.createElement('svg:image');
|
||||
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);
|
||||
imgEl.setAttributeNS(null, 'x', '0');
|
||||
imgEl.setAttributeNS(null, 'y', pf(-height));
|
||||
@ -1180,10 +1182,10 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
var fillColor = current.fillColor;
|
||||
|
||||
current.maskId = 'mask' + maskCount++;
|
||||
var mask = document.createElementNS(NS, 'svg:mask');
|
||||
var mask = this.svgFactory.createElement('svg:mask');
|
||||
mask.setAttributeNS(null, 'id', current.maskId);
|
||||
|
||||
var rect = document.createElementNS(NS, 'svg:rect');
|
||||
var rect = this.svgFactory.createElement('svg:rect');
|
||||
rect.setAttributeNS(null, 'x', '0');
|
||||
rect.setAttributeNS(null, 'y', '0');
|
||||
rect.setAttributeNS(null, 'width', pf(width));
|
||||
@ -1208,7 +1210,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
var width = bbox[2] - bbox[0];
|
||||
var height = bbox[3] - bbox[1];
|
||||
|
||||
var cliprect = document.createElementNS(NS, 'svg:rect');
|
||||
var cliprect = this.svgFactory.createElement('svg:rect');
|
||||
cliprect.setAttributeNS(null, 'x', bbox[0]);
|
||||
cliprect.setAttributeNS(null, 'y', bbox[1]);
|
||||
cliprect.setAttributeNS(null, 'width', pf(width));
|
||||
@ -1225,24 +1227,17 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initialize: function SVGGraphics_initialize(viewport) {
|
||||
// Create the SVG element.
|
||||
var svg = document.createElementNS(NS, 'svg:svg');
|
||||
svg.setAttributeNS(null, 'version', '1.1');
|
||||
svg.setAttributeNS(null, 'width', viewport.width + 'px');
|
||||
svg.setAttributeNS(null, 'height', viewport.height + 'px');
|
||||
svg.setAttributeNS(null, 'preserveAspectRatio', 'none');
|
||||
svg.setAttributeNS(null, 'viewBox', '0 0 ' + viewport.width +
|
||||
' ' + viewport.height);
|
||||
_initialize(viewport) {
|
||||
let svg = this.svgFactory.create(viewport.width, viewport.height);
|
||||
|
||||
// Create the definitions element.
|
||||
var definitions = document.createElementNS(NS, 'svg:defs');
|
||||
let definitions = this.svgFactory.createElement('svg:defs');
|
||||
svg.appendChild(definitions);
|
||||
this.defs = definitions;
|
||||
|
||||
// Create the root group element, which acts a container for all other
|
||||
// groups and applies the viewport transform.
|
||||
var rootGroup = document.createElementNS(NS, 'svg:g');
|
||||
let rootGroup = this.svgFactory.createElement('svg:g');
|
||||
rootGroup.setAttributeNS(null, 'transform', pm(viewport.transform));
|
||||
svg.appendChild(rootGroup);
|
||||
|
||||
@ -1259,7 +1254,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
*/
|
||||
_ensureClipGroup: function SVGGraphics_ensureClipGroup() {
|
||||
if (!this.current.clipGroup) {
|
||||
var clipGroup = document.createElementNS(NS, 'svg:g');
|
||||
var clipGroup = this.svgFactory.createElement('svg:g');
|
||||
clipGroup.setAttributeNS(null, 'clip-path',
|
||||
this.current.activeClipUrl);
|
||||
this.svg.appendChild(clipGroup);
|
||||
@ -1273,7 +1268,7 @@ SVGGraphics = (function SVGGraphicsClosure() {
|
||||
*/
|
||||
_ensureTransformGroup: function SVGGraphics_ensureTransformGroup() {
|
||||
if (!this.tgrp) {
|
||||
this.tgrp = document.createElementNS(NS, 'svg:g');
|
||||
this.tgrp = this.svgFactory.createElement('svg:g');
|
||||
this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
||||
if (this.current.activeClipUrl) {
|
||||
this._ensureClipGroup().appendChild(this.tgrp);
|
||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -284,6 +284,7 @@
|
||||
!annotation-squiggly.pdf
|
||||
!annotation-highlight.pdf
|
||||
!annotation-line.pdf
|
||||
!annotation-square-circle.pdf
|
||||
!annotation-fileattachment.pdf
|
||||
!annotation-text-widget.pdf
|
||||
!annotation-choice-widget.pdf
|
||||
|
BIN
test/pdfs/annotation-square-circle.pdf
Executable file
BIN
test/pdfs/annotation-square-circle.pdf
Executable file
Binary file not shown.
@ -3560,6 +3560,13 @@
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "annotation-square-circle",
|
||||
"file": "pdfs/annotation-square-circle.pdf",
|
||||
"md5": "cfd3c302f68d61e1d55ed9c7896046c3",
|
||||
"rounds": 1,
|
||||
"type": "eq",
|
||||
"annotations": true
|
||||
},
|
||||
{ "id": "annotation-fileattachment",
|
||||
"file": "pdfs/annotation-fileattachment.pdf",
|
||||
"md5": "d20ecee4b53c81b2dd44c8715a1b4a83",
|
||||
|
@ -14,11 +14,72 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
getFilenameFromUrl, isExternalLinkTargetSet, LinkTarget
|
||||
DOMSVGFactory, getFilenameFromUrl, isExternalLinkTargetSet, LinkTarget
|
||||
} from '../../src/display/dom_utils';
|
||||
import { isNodeJS } from '../../src/shared/util';
|
||||
import { PDFJS } from '../../src/display/global';
|
||||
|
||||
describe('dom_utils', function() {
|
||||
describe('DOMSVGFactory', function() {
|
||||
let svgFactory;
|
||||
|
||||
beforeAll(function (done) {
|
||||
svgFactory = new DOMSVGFactory();
|
||||
done();
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
svgFactory = null;
|
||||
});
|
||||
|
||||
it('`create` should throw an error if the dimensions are invalid',
|
||||
function() {
|
||||
// Invalid width.
|
||||
expect(function() {
|
||||
return svgFactory.create(-1, 0);
|
||||
}).toThrow(new Error('Invalid SVG dimensions'));
|
||||
|
||||
// Invalid height.
|
||||
expect(function() {
|
||||
return svgFactory.create(0, -1);
|
||||
}).toThrow(new Error('Invalid SVG dimensions'));
|
||||
});
|
||||
|
||||
it('`create` should return an SVG element if the dimensions are valid',
|
||||
function() {
|
||||
if (isNodeJS()) {
|
||||
pending('Document is not supported in Node.js.');
|
||||
}
|
||||
|
||||
let svg = svgFactory.create(20, 40);
|
||||
|
||||
expect(svg instanceof SVGSVGElement).toBe(true);
|
||||
expect(svg.getAttribute('version')).toBe('1.1');
|
||||
expect(svg.getAttribute('width')).toBe('20px');
|
||||
expect(svg.getAttribute('height')).toBe('40px');
|
||||
expect(svg.getAttribute('preserveAspectRatio')).toBe('none');
|
||||
expect(svg.getAttribute('viewBox')).toBe('0 0 20 40');
|
||||
});
|
||||
|
||||
it('`createElement` should throw an error if the type is not a string',
|
||||
function() {
|
||||
expect(function() {
|
||||
return svgFactory.createElement(true);
|
||||
}).toThrow(new Error('Invalid SVG element type'));
|
||||
});
|
||||
|
||||
it('`createElement` should return an SVG element if the type is valid',
|
||||
function() {
|
||||
if (isNodeJS()) {
|
||||
pending('Document is not supported in Node.js.');
|
||||
}
|
||||
|
||||
let svg = svgFactory.createElement('svg:rect');
|
||||
|
||||
expect(svg instanceof SVGRectElement).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFilenameFromUrl', function() {
|
||||
it('should get the filename from an absolute URL', function() {
|
||||
var url = 'http://server.org/filename.pdf';
|
||||
|
@ -181,6 +181,8 @@
|
||||
.annotationLayer .squigglyAnnotation,
|
||||
.annotationLayer .strikeoutAnnotation,
|
||||
.annotationLayer .lineAnnotation svg line,
|
||||
.annotationLayer .squareAnnotation svg rect,
|
||||
.annotationLayer .circleAnnotation svg ellipse,
|
||||
.annotationLayer .fileAttachmentAnnotation {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user