UNPKG

lichen-annotate-pdf

Version:

Annotation layer for pdf.js in vue fork of Aaron Leong pdf-annotate-vue

224 lines (199 loc) 6.94 kB
import objectAssign from 'object-assign'; import renderLine from './renderLine'; import renderPath from './renderPath'; import renderPoint from './renderPoint'; import renderRect from './renderRect'; import renderText from './renderText'; import renderCircle from './renderCircle'; import renderArrow from './renderArrow'; import renderImage from './renderImage'; const isFirefox = /firefox/i.test(navigator.userAgent); /** * Get the x/y translation to be used for transforming the annotations * based on the rotation of the viewport. * * @param {Object} viewport The viewport data from the page * @return {Object} */ export function getTranslation(viewport) { let x; let y; // Modulus 360 on the rotation so that we only // have to worry about four possible values. switch (viewport.rotation % 360) { case 0: x = y = 0; break; case 90: x = 0; y = (viewport.width / viewport.scale) * -1; break; case 180: x = (viewport.width / viewport.scale) * -1; y = (viewport.height / viewport.scale) * -1; break; case 270: x = (viewport.height / viewport.scale) * -1; y = 0; break; } return { x, y }; } /** * Transform the rotation and scale of a node using SVG's native transform attribute. * * @param {Node} node The node to be transformed * @param {Object} viewport The page's viewport data * @return {Node} */ function transform(node, viewport) { let trans = getTranslation(viewport); // Let SVG natively transform the element node.setAttribute('transform', `scale(${viewport.scale}) rotate(${viewport.rotation}) translate(${trans.x}, ${trans.y})`); // Manually adjust x/y for nested SVG nodes if (!isFirefox && node.nodeName.toLowerCase() === 'svg') { node.setAttribute('x', parseInt(node.getAttribute('x'), 10) * viewport.scale); node.setAttribute('y', parseInt(node.getAttribute('y'), 10) * viewport.scale); let x = parseInt(node.getAttribute('x', 10)); let y = parseInt(node.getAttribute('y', 10)); let width = parseInt(node.getAttribute('width'), 10); let height = parseInt(node.getAttribute('height'), 10); let path = node.querySelector('path'); let svg = path.parentNode; // Scale width/height [node, svg, path, node.querySelector('rect')].forEach((n) => { n.setAttribute('width', parseInt(n.getAttribute('width'), 10) * viewport.scale); n.setAttribute('height', parseInt(n.getAttribute('height'), 10) * viewport.scale); }); // Transform path but keep scale at 100% since it will be handled natively transform(path, objectAssign({}, viewport, { scale: 1 })); switch (viewport.rotation % 360) { case 90: node.setAttribute('x', viewport.width - y - width); node.setAttribute('y', x); svg.setAttribute('x', 1); svg.setAttribute('y', 0); break; case 180: node.setAttribute('x', viewport.width - x - width); node.setAttribute('y', viewport.height - y - height); svg.setAttribute('y', 2); break; case 270: node.setAttribute('x', y); node.setAttribute('y', viewport.height - x - height); svg.setAttribute('x', -1); svg.setAttribute('y', 0); break; } } return node; } /** * Append an annotation as a child of an SVG. * * @param {SVGElement} svg The SVG element to append the annotation to * @param {Object} annotation The annotation definition to render and append * @param {Object} viewport The page's viewport data * @return {SVGElement} A node that was created and appended by this function */ export function appendChild(svg, annotation, viewport) { if (!viewport) { viewport = JSON.parse(svg.getAttribute('data-pdf-annotate-viewport')); } let child; switch (annotation.type) { case 'area': case 'highlight': child = renderRect(annotation); break; case 'circle': case 'fillcircle': case 'emptycircle': child = renderCircle(annotation); break; case 'strikeout': child = renderLine(annotation); break; case 'point': child = renderPoint(annotation); break; case 'textbox': child = renderText(annotation); break; case 'drawing': child = renderPath(annotation); break; case 'arrow': child = renderArrow(annotation); break; case 'image': child = renderImage(annotation); break; } // If no type was provided for an annotation it will result in node being null. // Skip appending/transforming if node doesn't exist. if (child) { // Set attributes child.setAttribute('data-pdf-annotate-id', annotation.uuid); child.setAttribute('aria-hidden', true); // Dynamically set any other attributes associated with annotation that is not related to drawing it Object.keys(annotation).filter((key) => { return ['color', 'x', 'y', 'cx', 'cy', 'color', 'documentId', 'lines', 'page', 'width', 'class', 'content', 'size', 'rotation', 'r'].indexOf(key) === -1; }).forEach((key) => { child.setAttribute(`data-pdf-annotate-${key}`, annotation[key]); }); svg.appendChild(transform(child, viewport)); // if (annotation.type === 'textbox') { // console.log('une ostie de boite', child.g, child.getBBox()) // var box = child.getBBox() // // let textElem = child.getElementsbyTagName('text') // // console.log('textElem', textElem) // var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); // rect.setAttribute("fill", "red"); // rect.setAttribute("stroke", "black"); // rect.setAttribute("stroke-width", "1") // rect.setAttribute("x", box.x); // rect.setAttribute("y", box.y); // rect.setAttribute("width", box.width); // rect.setAttribute("height", box.height); // child.appendChild(rect, child.text); // } } return child; } /** * Transform a child annotation of an SVG. * * @param {SVGElement} svg The SVG element with the child annotation * @param {Object} child The SVG child to transform * @param {Object} viewport The page's viewport data * @return {SVGElement} A node that was transformed by this function */ export function transformChild(svg, child, viewport) { if (!viewport) { viewport = JSON.parse(svg.getAttribute('data-pdf-annotate-viewport')); } // If no type was provided for an annotation it will result in node being null. // Skip transforming if node doesn't exist. if (child) { child = transform(child, viewport); } return child; } export default { /** * Get the x/y translation to be used for transforming the annotations * based on the rotation of the viewport. */ getTranslation, /** * Append an SVG child for an annotation */ appendChild, /** * Transform an existing SVG child */ transformChild };