JSReports
Este proyecto está orientado a crear Reports (Informes) directamente desde JS cliente desde un
navegador. Dichos informes se entiende como resultados de información en texto como PDF, DOC, etc.
Así como tablas de datos.
Proyecto
El proyecto viene siendo una librería Core que permite, desde un cliente JS (Navegador), junto con
sus dependencias, en caso de requerirlo, crear informes en múltiples formatos como PDF y DOC,
pasando como formato visual HTML y CSS, así como generación de archivos multiplataforma compatibles
con Excel y Calc como es el formato CSV. También se baraja la idea de poder gestionar la descarga de
información directa en XML, JSON, etc.
La librería final es la siguiente:
https://jsreports.k3y.pw/ecma/JSReports.ecma.js
Proyectos y dependencias
Este proyecto depende de una serie de librerías externas las cuales son:
Por otro lado, hay proyectos desarrollados por KyMAN o en los que KyMAN también participó tales
como:
Finalmente, este proyecto es usado en los proyectos:
Notas
Notas para no olvidarme del proyecto.
El proyecto se basa en una librería ECMA/JS la cual se llama JSReports como nombre de clase. Hay que
crear un objecto JSReports para poder trabajar con ella. En el caso de PDF depende de las librerías:
Para poder empezar a trabajar con esta librería hay que esperar asíncronamente a que termine de
cargar mediante un Callback "on_ready"
-
Language
js
-
Lines
1
-
Characters
117
(js_reports = new JSReports(/* PARAMETROS DE ENTRADA */)).on_ready(() => console.log("Ya terminó de cargar xD"));
NOTA: La librería requiere de un sitio donde poner componentes de forma temporal a modo
de caché. No le vale un DocumentFragment. Si no se le establece se pondrá por defecto BODY.
PDF y DOC
El trabajo con esta librería cara los PDF y DOC es exactamente igual. Hay que llamar a un método
llamado "create" el cual permite crear este tipo de documentos. La librería se centra en que crees
un HTML4 y CSS2, aunque pueden ser adjuntadas cosas de HTML5 y XHTML, así como algunos parámetros
CSS3 y customizados cara cualquier a de las dos plataformas. La idea es construir plantillas para
cabeceras, pies y cuerpos en HTML y una única hoja de estilos general en CSS, lo que cubriría el 99%
del informe, luego hay ciertos parámetros que son necesarios establecer mediante valores.
Con esta información tenemos como parámetros de entrada un único valor que vendrá siendo un
diccionario el cual tiene los siguientes elementos:
NOTA: Todas las medidas se toma en mm (Milímetros).
- header: Cabecera HTML.
- body: Cuerpo HTML.
- footer: Pié HTML.
- css: Estilos CSS.
- type: Extensión que determina si es "doc" o "pdf".
- margin: Margen general para cualquier lado.
- margin_top: Margen superior.
- margin_right: Margen derecho.
- margin_bottom: Margen inferior.
- margin_left: Margen izquierdo.
- variables: Variables para cubrir dentro de los HTML.
- header_height: Alto de la cabecera.
- footer_height: Alto del pié.
- margin_header: Margen de la cabecera.
- margin_footer: Margen del pié.
- dpi: DPI para marcar tamaños digitales en PX.
- page_format: Formato de página (A4, A3, A5, C5, Letter (L), etc.); o tamaño (alto y ancho).
El formato PDF requiere de embedar las fuentes con las que se vaya a trabajar en formato TTF, que es
el formato por defecto cara los OS. Dicho formato requiere de un archivo por estilo (Regular o
normal, Light, Bold, Italic, etc). Para embedar fuentes es necesario cubrir la variable "fonts" en
el diccionario de parámetros de entrada del objeto y se compone de un Array bidimensional donde el
primer nivel es conjunto de fuentes y el segundo se compone de:
- Nombre de la fuente.
- Link del estilo.
- Nombre del estilo.
En ambos casos, las imágenes se embedarán mediante URI Base64, pasando a formar parte del documento.
Las imágenes, por defecto, suelen estar protegidas por CORS. Para saltarse dicha restricción es
importante hacer uso de un Proxy. Para establecer el Proxy hemos de establecer el parámetro global
"proxy" que vendrá siendo una URL contra el Proxy donde la variable String "{url}" determinará donde
colocar la URL de la imagen.
-
Language
js
-
Lines
3
-
Characters
137
js_reports = new JSReports({
proxy : "https://proxycors.local/api/DHkwPBhzp78Gz8g3BmG4VFnDgnt5kU9J6XQPjWMGDKwjr6s3f9nV7545B/{url}"
})
NOTA: Si el Proxy no retorna las cabeceras del CORS, éste no servirá de nada. Se puede
hacer uso del proyecto ProxyCORS, proyecto en el que está basado el
ejemplo también desarrollado por KyMAN. El Git del proyecto es https://git.k3y.pw/KyMAN/ProxyCORS.
IMPORTANTE: El link del ProxyCORS posiblemente no funcione por el hecho de que con
dicho Hash podrían usar mi servidor como salto anónimo para saltarse el CORS entre otros fines por
lo que el Hash quede deshabilitado.
También se le pueden agregar componentes especiales al documento como tablas o listas programas
directamente como objetos o Arrays a partir de un objeto que determina su tipo y el contenido del
mismo. A continuación se titularán los tipos de objetos especiales que hay actualmente.
Tablas (Grids)
Los documentos DOC y PDF permiten la generación de tablas dinámicas a partir de la idea de un Grid,
es decir, un objeto que determina la cabecera y los datos y automáticamente, el programa embedará
una tabla con dichos datos. La estructura del objeto es la siguiente:
- type: Tipo (puede ser "table" o "grid").
- header : Array de textos, cada uno será la cabecera de esa columna concreta.
- body: Cuerpo de la tabla o datos. Array bidimensional con los valores por cada tupla y columna.
Un ejemplo de una tabla puede ser el siguiente:
-
Language
js
-
Lines
14
-
Characters
622
const table = {
type : "table",
header : ["Cabecera 1", "Cabecera 2", "Cabecera 3", "...", "Cabecera N"],
body : [
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"],
["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"]
]
};
Listas
Los documentos DOC y PDF permiten la generación de listas dinámicas a partir de un Array el cual
puede anidar otros Array para hacer Listas de múltiples niveles. Admiten tantos listas ordenadas
como desordenadas, y su estructura es la siguiente:
- type: Tipo (Siempre será "list"),
- mode: El modo en que se mostrarán los datos. Éste puede ser:
- ol o ordered: Para mostrar los datos con un valor que representa su posición autoincremental.
- ul o unordered: Para mostrar los datos con puntos, guiones o como se establezca por CSS.
- start: Para los elementos ordenados autoincrementalmente, valor numérico de inicio.
- items: Array de elementos ordenados. Puede contener objetos que anidan otras listas.
Un ejemplo de una tabla puede ser el siguiente:
-
Language
js
-
Lines
25
-
Characters
479
const list = {
type : "list",
mode : "ordered",
start : 12,
items : [
"cosa 1",
"cosa 2",
"cosa 3",
"...",
["jojo", {
mode : "unordered",
items : [
"pasa A",
["pasa B", {
items : [
"otro xD"
]
}],
"pasa C"
]
}],
"juas",
"jiji"
]
};
Bugs
En esta sección se catalogarán todos los Bugs y el estado conforme a si están o no arreglados o si
se están tratando.
Cabeceras y pies dispares en UDF
Las cabeceras y pies de página salen en las páginas impares en UDF. El problema recae principalmente
en que los etiquetados y marcas de MS no son compatibles con las de UDF, siendo para UDF el
'title="header"' para la cabecera y el 'title="footer"' para el pie; mientras que en MS sería el
atributo Style "mso-element:header;" para la cabecera y "mso-elemento:footer;" para el pie. Está
globalizado, pero el método UDF sólo muestra las cabeceras y los pies en las páginas impares.
-
Arreglar el fallo para que salgan en todas las páginas.
Hay una pseudosolución que aportaron en la respuesta del Link que se muestra a continuación se
muestra una pseudosolución (Digo pseudo porque no es una cabecera ni pié real, sino que se usa una
tabla que contiene ambas cosas la cual repite su THEAD y su TFOOT en todas las páginas) pero al no
ser una cabecera y pié reales no lo establecí, pero decir que en caso de extrema necesidad, ésta
puede ser aplicada perfectamente.
https://stackoverflow.com/questions/1360869/how-to-use-html-to-print-header-and-footer-on-every-printed-page-of-a-document#answer-51371081
Problemas cabeceras y piés PDF
El jsPDF no fue diseñado para trabajar en profundidad el HTML de hecho, no es capaz ni de
interpretar CSS ni de adjuntar las fuentes de forma autónoma, pero el problema viene a la hora de
establecer un elemento HTML pues, aunque establezcas la página donde quieras establecerlo, éste
siempre irá a la primera página, y si estableces un margen o posición "top" muy alto, éste
desaparece si no es nativo para estar ahí. El HTML se superpondrá a lo que ya hay en el documento y
no permite establecer márgenes diferentes a distintos HTML, por lo que el tema de las cabeceras
queda totalmente descartado mediante HTML nativo.
IMPORTANTE: Actualmente, este sistema funciona pero es a partir de la creación de
una imagen contra el HTML y CSS dado lo que impide seleccionar texto entre otros problemas. No me
preocupan los sistemas que migran de PDF a DOC por los OCR.
NOTA: Para arreglar este problema se optó por hacer uso de la dependencia del propio
jsPDF: html2canvas, y de ahí se extrae una imagen en URI Base64 que es la que se usa para dichos
fines.
Problemas con CSS
En los documentos DOC, la etiqueta STYLE que contiene el CSS, tiene órdenes y sentencias muy
específicas que no pueden ser flexibilizadas por lo que hay que hacer una adaptación de la misma
para que funcionen.
-
Crear adaptación para que se generen.
Básicamente se reutilizó el sistema hecho para los PDF.
Corregir tamaños IMG
Las imágenes, en os documentos DOC tienen el problema del valor de atributo "width" y "height" auto,
que cogen como valor su ancho o alto, consecutivamente.
-
Conseguir proporcionar las imágenes.
Para arreglar dicho fallo se hice un análisis del CSS contra las imágenes en su precarga y
establecer un tamaño relativo con respecto al formato de página, tamaño de la misma y el tamaño de
la imagen.
Tamaños de tabla
En los DOC, las tablas no hacen caso de los atributos de tamaño de CSS, requiriendo de hacer uso del
atributo WIDTH.
Por otro lado, las celdas tampoo hacen caso de su ancho, teniendo que usar la etiqueta COLGROUP y
sus subetiquetas COL.
IMPORTANTE: Los COL, en los DOC UDF ignora la unidad del atributo y no respeta la
proporción de peso, quedando sobre una proporción a 50000. Automáticamente lo tramita desde los DPI
en medidas por pixel; y por el tamaño de página en mm, cm, in, etc; así como por los propios
porcentajes. Creo que es algo que hay que mejorar, pero que para salir del paso llega.
Medidas mm en DOC UDF
Cuando tratabajamos los márgenes CSS de las cabeceras y los pies de página, éstos se establecen en
mm de forma forzada aunque le pongas otra unidad de medida.
NOTA: Al ser un atributo CSS especial para MS puede ser que se condicione forzadamente
en mm? No hay información a penas acerca de ello.
-
Arreglar el Bug, o al menos, adaptarlo para que salga en otras unidades establecidas en CSS.
NOTA: Actualmente está trabajando en mm, de la misma forma que trabaja esta librería.
PDF en Chrome
Por algún motivo, en Chrome no crea el PDF. Queda como totalmente apagado y sin terminar el proceso.
-
Arreglar el Bug.
El Bug parece ser que era porque el evento OnLoad del IFRAME que gestiona los html2canvas no existe
en Chrome salvo que éste venga con una URL, por lo que se decidió hacer un Timeout para solventar la
precarga del objeto.
Objetivos
Aquí se pondrán los objetivos del proyecto JSReports.