Skip to content

Commit

Permalink
Merge pull request #2054 from scireum/feature/jvo/OX-9272-SVG-Charts
Browse files Browse the repository at this point in the history
SVG Charts for PDFs (OX-9272)
  • Loading branch information
jakobvogel authored Dec 12, 2024
2 parents fbd95d6 + 09fccfd commit 2883f89
Show file tree
Hide file tree
Showing 7 changed files with 1,199 additions and 2 deletions.
11 changes: 9 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
<url>https://www.sirius-lib.net</url>

<properties>
<sirius.kernel>dev-43.1.0</sirius.kernel>
<sirius.web>dev-84.5.0</sirius.web>
<sirius.kernel>dev-43.2.1</sirius.kernel>
<sirius.web>dev-85.5.0</sirius.web>
<sirius.db>dev-58.3.0</sirius.db>
</properties>

Expand Down Expand Up @@ -160,5 +160,12 @@
<artifactId>sevenzipjbinding-all-platforms</artifactId>
<version>16.02-2.01</version>
</dependency>

<!-- Used to render diagrams into SVG -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-all</artifactId>
<version>1.18</version>
</dependency>
</dependencies>
</project>
181 changes: 181 additions & 0 deletions src/main/java/sirius/biz/charts/Chart.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/

package sirius.biz.charts;

import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.w3c.dom.Element;

import java.awt.Dimension;

/**
* Provides an interface for charts that can be rendered as SVG.
*/
public abstract class Chart {

/**
* Contains the tag name for circle elements, {@value}.
*/
protected static final String TAG_CIRCLE = "circle";

/**
* Contains the tag name for group elements, {@value}.
*/
protected static final String TAG_GROUP = "g";

/**
* Contains the tag name for path elements, {@value}.
*/
protected static final String TAG_PATH = "path";

/**
* Contains the tag name for SVG root elements, {@value}.
*/
protected static final String TAG_SVG = "svg";

/**
* Contains the tag name for text elements, {@value}.
*/
protected static final String TAG_TEXT = "text";

/**
* Contains the attribute name for the center x coordinate, {@value}.
*/
protected static final String ATTRIBUTE_CENTER_X = "cx";

/**
* Contains the attribute name for the center y coordinate, {@value}.
*/
protected static final String ATTRIBUTE_CENTER_Y = "cy";

/**
* Contains the attribute name for path definitions, {@value}.
*/
protected static final String ATTRIBUTE_DEFINITION = "d";

/**
* Contains the attribute name for the fill colour, {@value}.
*/
protected static final String ATTRIBUTE_FILL = "fill";

/**
* Contains the attribute name for the fill opacity, {@value}.
*/
protected static final String ATTRIBUTE_FILL_OPACITY = "fill-opacity";

/**
* Contains the attribute name for the font size, {@value}.
*/
protected static final String ATTRIBUTE_FONT_SIZE = "font-size";

/**
* Contains the attribute name for the radius, {@value}.
*/
protected static final String ATTRIBUTE_RADIUS = "r";

/**
* Contains the attribute name for the stroke colour, {@value}.
*/
protected static final String ATTRIBUTE_STROKE = "stroke";

/**
* Contains the attribute name for the stroke width, {@value}.
*/
protected static final String ATTRIBUTE_STROKE_WIDTH = "stroke-width";

/**
* Contains the attribute name for the text anchor, {@value}.
*/
protected static final String ATTRIBUTE_TEXT_ANCHOR = "text-anchor";

/**
* Contains the attribute name for the view box, {@value}.
*/
protected static final String ATTRIBUTE_VIEW_BOX = "viewBox";

/**
* Contains the attribute name for the x coordinate, {@value}.
*/
protected static final String ATTRIBUTE_X = "x";

/**
* Contains the attribute name for the y coordinate, {@value}.
*/
protected static final String ATTRIBUTE_Y = "y";

/**
* Contains the value for the {@linkplain #ATTRIBUTE_FILL fill attribute} to avoid filling, {@value}.
*/
protected static final String VALUE_FILL_NONE = "none";

/**
* Contains the value for the {@linkplain #ATTRIBUTE_TEXT_ANCHOR text anchor attribute} to align text at the start,
* {@value}.
*/
protected static final String VALUE_TEXT_ANCHOR_START = "start";

/**
* Contains the value for the {@linkplain #ATTRIBUTE_TEXT_ANCHOR text anchor attribute} to align text centered,
* {@value}.
*/
protected static final String VALUE_TEXT_ANCHOR_MIDDLE = "middle";

/**
* Contains the value for the {@linkplain #ATTRIBUTE_TEXT_ANCHOR text anchor attribute} to align text at the end,
* {@value}.
*/
protected static final String VALUE_TEXT_ANCHOR_END = "end";

/**
* Contains the black colour as hex-string, {@value}. The value is used as primary colour for charts.
*/
protected static final String COLOR_BLACK = "#000000";

/**
* Contains a dark gray colour as hex-string, {@value}. Its design system equivalent is {@code sirius-gray-dark}.
* <p>
* The value is used as secondary colour for charts.
*/
protected static final String COLOR_GRAY_DARK = "#808080";

/**
* Contains the light gray colour as hex-string, {@value}. Its design system equivalent is {@code sirius-gray-light}.
* <p>
* The value is used as secondary colour for charts.
*/
protected static final String COLOR_GRAY_LIGHT = "#c7c7c7";

/**
* Renders the chart as SVG.
*
* @param bounds the dimensions of the viewport
* @return the SVG representation of the chart
*/
public abstract Element toSvg(Dimension bounds);

/**
* Creates an empty SVG element with the view box centered.
*
* @param bounds the dimensions of the viewport
* @return an empty SVG element with the view box centered
*/
protected Element createSvgElementWithCenteredViewbox(Dimension bounds) {
Element svgElement = SVGDOMImplementation.getDOMImplementation()
.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI,
Chart.TAG_SVG,
null)
.getDocumentElement();
svgElement.setAttribute(Chart.ATTRIBUTE_VIEW_BOX,
String.format("%f %f %f %f",
-0.5 * bounds.width,
-0.5 * bounds.height,
(double) bounds.width,
(double) bounds.height));
return svgElement;
}
}
46 changes: 46 additions & 0 deletions src/main/java/sirius/biz/charts/Charts.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/

package sirius.biz.charts;

import com.lowagie.text.xml.XmlDomWriter;
import org.w3c.dom.Element;
import sirius.kernel.di.std.Register;
import sirius.web.templates.pdf.TagliatellePDFContentHandler;

import java.awt.Dimension;
import java.io.StringWriter;

/**
* Provides helpers to work with charts.
*/
@Register(classes = Charts.class)
public class Charts {

/**
* Exports a chart as SVG string that is compatible with {@linkplain TagliatellePDFContentHandler PDF rendering}.
*
* @param chart the chart to export
* @param bounds the dimensions of the viewport
* @return the SVG string representing the chart
*/
public String exportChartForPdf(Chart chart, Dimension bounds) {
// we need to clean the SVG code a bit to make it compatible with the PDF renderer
Element element = chart.toSvg(bounds);
element.setAttribute("style",
String.format("display: block; width: 100%%; height: %dmm; page-break-inside: avoid;",
bounds.height));

// note that the string writer uses a string buffer internally; no additional buffering or flushing is required
StringWriter writer = new StringWriter();
XmlDomWriter xmlWriter = new XmlDomWriter();
xmlWriter.setOutput(writer);
xmlWriter.write(element);
return writer.toString();
}
}
Loading

0 comments on commit 2883f89

Please sign in to comment.