Generating SVG Graphics in JSPs using JSTL & XSL(T) – from MySQL to Bar Chart and Pie Chart
Transform generic Measures into SVG Line Graph
The stylesheet buildSVGLineChart.xsl will take a source document in the proper format – with a graphData root element, sets- and set-child elements and finally measure-elements that contain the actual graphdata – and transform it to a SVG object: a proper line chart. Here I will show a few sections from this stylesheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/2000/xlink/namespace/"
version="1.0">
<xsl:output method="image/svg+xml" omit-xml-declaration="yes"/>
<xsl:template match="/graphData">
<xsl:variable name="max">
<xsl:value-of select="maxy"/>
</xsl:variable>
<xsl:variable name="min">
<xsl:value-of select="miny"/>
</xsl:variable>
<xsl:variable name="maxx">
<xsl:value-of select="maxx"/>
</xsl:variable>
<xsl:variable name="minx">
<xsl:value-of select="minx"/>
</xsl:variable>
<svg width="1200" height="1200">
<defs>
<!-- definitions of different types of markers -->
<g id="star" transform="scale(0.21)">
<polyline points="48,16,16,96,96,48,0,48,80,96">
</polyline>
</g>
<g id="triangle" transform="scale(0.7)">
<path id="Triangle" d="M 0 25 L 10 15 L 20 25 z" style="stroke:none"/>
</g>
<g id="square" transform="scale(1)">
<rect width="18" height="18">
</rect>
</g>
<g id="rectangle" transform="scale(1)">
<rect width="7" height="22">
</rect>
</g>
</defs>
<!-- create some room around the graph (border of 150 wide to the left and 50 high on top) -->
<g transform="translate(150,50) scale(0.5)">
<!--Heading-->
<text x="5" y="-40" text-anchor="left" font-weight="bolder"
font-size="40" fill="maroon" text-decoration="underline">
<xsl:value-of select="title"/>
</text>
<!--Caption (Vertical)-->
<g transform="translate(-220, 80) rotate(270, 0, 0)">
<text x="0" y="0" text-anchor="middle" font-weight="bolder"
font-size="36" fill="black">
<xsl:value-of select="ytitle"/>
</text>
</g>
<!--Caption (Horizontal)-->
<text x="1070" y="1000" font-size="36" font-weight="bolder" fill="black">
<xsl:value-of select="xtitle"/>
</text>
<!-- Now Draw the main X and Y axis -->
<g style="stroke-width:5; stroke:black">
<!-- X Axis -->
<path d="M 0 1000 L 1000 1000 Z"/>
<!-- Y Axis -->
<path d="M 0 0 L 0 1000 Z"/>
</g>
<xsl:for-each select="sets/set"> <!-- match the /graphData/sets/set elements in the source document -->
... (left out: writing the markers and labels on the x-axis and y-axis )
<!-- go and draw the line of the chart itself -->
<g>
<xsl:attribute name="style">
stroke:<xsl:value-of select="@color"/>;stroke-width: 3; fill : none;
</xsl:attribute>
<!-- draw a line from the previous to each new point -->
<xsl:for-each select="measure">
<xsl:variable name="x">
<xsl:value-of select=" 1000* ((xvalue - ($minx)) div ($maxx - $minx))"/>
</xsl:variable>
<xsl:variable name="y">
<xsl:value-of select="1000 - 1000* ((yvalue - ($min)) div ($max - $min))"/>
</xsl:variable>
<xsl:if test="not(../@showline='false')">
<xsl:if test="(position() > 1)">
<line>
<xsl:attribute name="x1">
<xsl:value-of select=" 1000* ((preceding-sibling::measure[position()=1]/xvalue - ($minx)) div ($maxx - $minx))"/>
</xsl:attribute>
<xsl:attribute name="y1">
<xsl:value-of select="1000 - 1000* ((preceding-sibling::measure[position()=1]/yvalue - ($min)) div ($max - $min))"/>
</xsl:attribute>
<xsl:attribute name="x2">
<xsl:value-of select="$x"/>
</xsl:attribute>
<xsl:attribute name="y2">
<xsl:value-of select="$y"/>
</xsl:attribute>
</line>
</xsl:if>
</xsl:if>
<xsl:if test="xgrid = 'true'">
<xsl:call-template name="gridline">
<xsl:with-param name="x1" select="$x"/>
<xsl:with-param name="y1" select="$y"/>
<xsl:with-param name="type">vertical</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:if test="ygrid = 'true'">
<xsl:call-template name="gridline">
<xsl:with-param name="x1" select="$x"/>
<xsl:with-param name="y1" select="$y"/>
<xsl:with-param name="type">horizontal</xsl:with-param>
<xsl:with-param name="yaxis">
<xsl:choose>
<xsl:when test="yvalue">1</xsl:when>
<xsl:otherwise>2</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:for-each> <!-- measure -->
</g>
</xsl:for-each> <!-- sets -->
<!-- now again traverse all measures to place markers
by doing this in a second go, we ensure (according to the 'painters algoritm'
(see: http://wiki.svg.org/index.php/ChangingDrawingOrder)) that the annotations
and markers are on top of everything else.
-->
<xsl:for-each select="sets/set">
<xsl:for-each select="measure">
<xsl:variable name="x">
<xsl:value-of select=" 1000* ((xvalue - ($minx)) div ($maxx - $minx))"/>
</xsl:variable>
<xsl:variable name="y">
<xsl:value-of select="1000 - 1000* ((yvalue - ($min)) div ($max - $min))"/>
</xsl:variable>
<g >
<xsl:attribute name="style">stroke:<xsl:value-of select="../@color"/> stroke-width: 3; fill : none;</xsl:attribute>
<!-- draw a marker -->
<xsl:call-template name="marker">
<xsl:with-param name="x" select="$x"/>
<xsl:with-param name="y" select="$y"/>
<xsl:with-param name="marker" select="../@marker-type"/>
<xsl:with-param name="color" select="../@color"/>
</xsl:call-template>
</g>
</xsl:for-each> <!-- measures in set -->
</xsl:for-each> <!-- sets -->
... (left out: creation of the legend-box)
</g>
</svg>
</xsl:template>
... (left out: templates for labels and markers on the x-axis and y-axis)
<xsl:template name="marker">
<xsl:param name="x"/>
<xsl:param name="y"/>
<xsl:param name="marker">circle</xsl:param>
<xsl:param name="color">red</xsl:param>
<g transform="scale(1)">
<xsl:attribute name="style">
stroke:<xsl:value-of select="$color"/>;fill:<xsl:value-of select="$color"/>
</xsl:attribute>
<xsl:choose>
<xsl:when test="$marker='square'">
<use xlink:href="#square">
<xsl:attribute name="x">
<xsl:value-of select="$x -9"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="$y -9"/>
</xsl:attribute>
</use>
</xsl:when>
<xsl:when test="$marker='triangle'">
<use xlink:href="#triangle">
<xsl:attribute name="x">
<xsl:value-of select="$x -9"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="$y -9"/>
</xsl:attribute>
</use>
</xsl:when>
<xsl:when test="$marker='rectangle'">
<use xlink:href="#rectangle">
<xsl:attribute name="x">
<xsl:value-of select="$x -4"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="$y -4"/>
</xsl:attribute>
</use>
</xsl:when>
<xsl:when test="$marker='star'">
<use xlink:href="#star">
<xsl:attribute name="x">
<xsl:value-of select="$x -9"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="$y -9"/>
</xsl:attribute>
</use>
</xsl:when>
<xsl:when test="$marker='diamond'">
<!-- diamond is just a square rotated about its own center for 45 degrees -->
<use xlink:href="#square">
<xsl:attribute name="x">
<xsl:value-of select="$x -9"/>
</xsl:attribute>
<xsl:attribute name="y">
<xsl:value-of select="$y -9"/>
</xsl:attribute>
<xsl:attribute name="transform">
rotate(45,<xsl:value-of select="$x"/>,<xsl:value-of select="$y "/>)
</xsl:attribute>
</use>
</xsl:when>
<xsl:when test="$marker='circle'">
<circle r="9">
<xsl:attribute name="cx">
<xsl:value-of select="$x"/>
</xsl:attribute>
<xsl:attribute name="cy">
<xsl:value-of select="$y"/>
</xsl:attribute>
</circle>
</xsl:when>
<xsl:when test="$marker='smallcircle'">
<circle r="4">
<xsl:attribute name="cx">
<xsl:value-of select="$x"/>
</xsl:attribute>
<xsl:attribute name="cy">
<xsl:value-of select="$y"/>
</xsl:attribute>
</circle>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</g>
</xsl:template>
<xsl:template name="gridline">
<xsl:param name="x1"/>
<xsl:param name="y1"/>
<xsl:param name="type"/>
<xsl:param name="yaxis">1</xsl:param>
<line style="fill:none; stroke:#B0B0B0; stroke-width:2; stroke-dasharray:2 4">
<xsl:attribute name="x1">
<xsl:value-of select="$x1"/>
</xsl:attribute>
<xsl:choose>
<xsl:when test="$type='horizontal'">
<xsl:attribute name="x2"><xsl:value-of select="($yaxis -1)* 1000 "/></xsl:attribute>
<xsl:attribute name="y2">
<xsl:value-of select="$y1"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="y2">1000</xsl:attribute>
<xsl:attribute name="x2">
<xsl:value-of select="$x1"/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:attribute name="y1">
<xsl:value-of select="$y1"/>
</xsl:attribute>
</line>
</xsl:template>
<!-- end gridline -->
</xsl:stylesheet>
The result of the transformation with this stylesheet to the SVG object can be downloaded here:EmpSalLineGraph.svg. The graph that is displayed as a result from these transformations:

Please take a look at this chart
http://www.treebuilder.de/xslt1/examples/example14/example14.xml