Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/delibero.git
xml/chart.xsl
xmlns:svg="http://www.w3.org/2000/svg">
- <!-- Globals -->
- <xsl:variable name="PI">3.14159265358979323846</xsl:variable>
- <xsl:variable name="precision">0.0001</xsl:variable>
+ <xsl:include href="math.xsl" />
+ <xsl:variable name="base_colour" select="'46A5E5'" />
+
<!-- Convert XML data into a Pie Chart. -->
<xsl:template match="dataset" mode="piechart">
-
<xsl:variable name="pie_width">100</xsl:variable>
<xsl:variable name="pie_height" select="$pie_width - $PI" />
<!-- Number of pie pieces -->
<xsl:variable name="pieces" select="count(data)" />
<!-- Calculate the total value for all pieces -->
<xsl:variable name="total" select="sum(//value)" />
-
+
<div class="chart">
<svg:svg width="30%" height="30%" viewBox="0 0 {$pie_width} {$pie_height}" version="1.1">
<svg:g stroke-width="0" fill="#000" stroke="#000">
<xsl:for-each select="data">
<xsl:variable name="piece" select="position()" />
- <!-- Calculate Fill Color -->
+ <!-- Calculate pie piece colour -->
<xsl:variable name="fill">
<xsl:call-template name="fill">
<xsl:with-param name="piece" select="$piece" />
<xsl:with-param name="pieces" select="$pieces" />
+ <xsl:with-param name="colour" select="$base_colour" />
</xsl:call-template>
</xsl:variable>
<!-- Fill the pie piece. -->
- <svg:path fill="{$fill}" title="{$percent}" stroke="none" d="{concat('M',$x+$rx,' ',$y+$ry,'L',$x+$rx+$rx*$c2,' ',$y+$ry+$ry*$s2,'A',$rx,' ',$ry,' 0 ',$opt,' 1 ',$x+$rx + $rx * $c,' ',$y+$ry +$ry*$s,'z')}" />
+ <svg:path fill="{$fill}" title="{$percent}" stroke="white" stroke-width="0.5" d="{concat('M',$x+$rx,' ',$y+$ry,'L',$x+$rx+$rx*$c2,' ',$y+$ry+$ry*$s2,'A',$rx,' ',$ry,' 0 ',$opt,' 1 ',$x+$rx + $rx * $c,' ',$y+$ry +$ry*$s,'z')}" />
</xsl:for-each>
</xsl:for-each>
<svg:svg width="30%" height="30%" viewBox="0 0 {$legend_width} {$legend_height}" version="1.1">
<xsl:for-each select="//name">
- <!-- Calculate Fill Color -->
+
+ <!-- Select legend colour for corresponding pie piece -->
<xsl:variable name="fill">
<xsl:call-template name="fill">
<xsl:with-param name="piece" select="position()" />
<xsl:with-param name="pieces" select="$pieces" />
+ <xsl:with-param name="colour" select="$base_colour" />
</xsl:call-template>
</xsl:variable>
</svg:svg>
</div>
-
</xsl:template>
- <xsl:template name="sine">
- <xsl:param name="deg" />
- <xsl:param name="radians">
- <xsl:value-of select="$deg div 180 * $PI" />
- </xsl:param>
- <xsl:param name="answer">
- <xsl:value-of select="$radians" />
- </xsl:param>
- <xsl:param name="loc">1</xsl:param>
- <xsl:param name="fract">
- <xsl:value-of select="$radians" />
- </xsl:param>
- <xsl:variable name="fract2" select="-1 * $fract * $radians * $radians div ($loc *2 * ($loc * 2 + 1))" />
- <xsl:choose>
- <xsl:when test="$fract2 &lt; $precision and $fract2 &gt; -$precision">
- <xsl:value-of select="$answer" />
- </xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="sine">
- <xsl:with-param name="radians" select="$radians" />
- <xsl:with-param name="answer" select="$answer + $fract2" />
- <xsl:with-param name="loc" select="$loc+1" />
- <xsl:with-param name="fract" select="$fract2" />
- </xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template name="fill">
+ <!-- http://en.wikipedia.org/wiki/HSL_and_HSV -->
+ <xsl:template name="fill">
<xsl:param name="piece" />
<xsl:param name="pieces" />
+ <xsl:param name="colour" select="'8A56E2'" />
+
+ <xsl:variable name="r">
+ <xsl:call-template name="hex2dec">
+ <xsl:with-param name="hex" select="substring( $colour, 1, 2 )" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="g">
+ <xsl:call-template name="hex2dec">
+ <xsl:with-param name="hex" select="substring( $colour, 3, 2 )" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="b">
+ <xsl:call-template name="hex2dec">
+ <xsl:with-param name="hex" select="substring( $colour, 5, 2 )" />
+ </xsl:call-template>
+ </xsl:variable>
- <xsl:variable name="range9">
- <xsl:choose>
- <xsl:when test="$pieces &gt; 9">9</xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$pieces" />
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:variable name="alpha" select="(2 * $r - $g - $b) * 0.5" />
+ <xsl:variable name="beta" select="0.86602540378 * ($g - $b)" />
+
+ <xsl:variable name="base_hue">
+ <xsl:call-template name="atan2">
+ <xsl:with-param name="x" select="$alpha" />
+ <xsl:with-param name="y" select="$beta" />
+ </xsl:call-template>
</xsl:variable>
- <xsl:variable name="hue" select="((($piece -1) mod $range9) div $range9 div 3.0 + (($piece -1) mod 3) div 3.0) * 0.85" />
- <xsl:variable name="saturation" select="1.0 - (floor(($piece -1) div $range9 * 0.5) mod 2) * 0.5 " />
- <xsl:variable name="brightness" select="0.8 - floor(($piece -1+$range9) div $range9 * 0.5) div (($pieces+$range9) div $range9 * 0.5) * 0.4" />
- <xsl:variable name="b" select="floor($brightness * 255 + 0.5)" />
- <xsl:variable name="h" select="floor(($hue - floor($hue)) * 6.0)" />
- <xsl:variable name="f" select="$h - floor($h)" />
- <xsl:variable name="p" select="floor($brightness * (1.0 - $saturation) * 255 + 0.5)" />
- <xsl:variable name="q" select="floor($brightness * (1.0 - $saturation * $f) * 255 + 0.5)" />
- <xsl:variable name="t" select="floor($brightness * (1.0 - ($saturation * (1.0 - $f))) * 255 + 0.5)" />
+
+ <xsl:variable name="chroma">
+ <xsl:call-template name="sqrt">
+ <xsl:with-param name="n" select="($alpha * $alpha) + ($beta * $beta)" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="value">
+ <xsl:variable name="max_rg">
+ <xsl:call-template name="max">
+ <xsl:with-param name="a" select="$r" />
+ <xsl:with-param name="b" select="$g" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="max_gb">
+ <xsl:call-template name="max">
+ <xsl:with-param name="a" select="$g" />
+ <xsl:with-param name="b" select="$b" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:call-template name="max">
+ <xsl:with-param name="a" select="$max_rg" />
+ <xsl:with-param name="b" select="$max_gb" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="saturation">
+ <xsl:if test="$value = 0">0</xsl:if>
+ <xsl:if test="$value != 0"><xsl:value-of select="$chroma div $value" /></xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="h_rotate" select="($base_hue + ((240 div $pieces) * $piece) mod 240)"></xsl:variable>
+ <xsl:variable name="h_prime" select="$h_rotate div 60.0" />
+ <xsl:variable name="h_mod" select="$h_prime mod 2 - 1" />
+ <xsl:variable name="h_abs" select="($h_mod &gt;= 0) * $h_mod - not($h_mod &gt;= 0) * $h_mod" />
+
+ <xsl:variable name="x" select="$chroma * (1 - $h_abs)" />
+ <xsl:variable name="m" select="$value - $chroma" />
+ <xsl:variable name="c" select="$chroma" />
+
+ <xsl:variable name="cm" select="round( $c + $m )" />
+ <xsl:variable name="xm" select="round( $x + $m )" />
+ <xsl:variable name="zm" select="round( 0 + $m )" />
+
<xsl:choose>
- <xsl:when test="$h = 0">rgb(<xsl:value-of select="$b" />,<xsl:value-of select="$t" />,<xsl:value-of select="$p" />)</xsl:when>
- <xsl:when test="$h = 1">rgb(<xsl:value-of select="$q" />,<xsl:value-of select="$b" />,<xsl:value-of select="$p" />)</xsl:when>
- <xsl:when test="$h = 2">rgb(<xsl:value-of select="$p" />,<xsl:value-of select="$b" />,<xsl:value-of select="$t" />)</xsl:when>
- <xsl:when test="$h = 3">rgb(<xsl:value-of select="$p" />,<xsl:value-of select="$q" />,<xsl:value-of select="$b" />)</xsl:when>
- <xsl:when test="$h = 4">rgb(<xsl:value-of select="$t" />,<xsl:value-of select="$p" />,<xsl:value-of select="$b" />)</xsl:when>
- <xsl:when test="$h = 5">rgb(<xsl:value-of select="$b" />,<xsl:value-of select="$p" />,<xsl:value-of select="$q" />)</xsl:when>
+ <xsl:when test="0 &lt;= $h_prime and $h_prime &lt; 1">
+ <xsl:value-of select="concat('rgb(', $cm, ',', $xm, ',', $zm, ')' )" />
+ </xsl:when>
+ <xsl:when test="1 &lt;= $h_prime and $h_prime &lt; 2">
+ <xsl:value-of select="concat('rgb(', $xm, ',', $cm, ',', $zm, ')' )" />
+ </xsl:when>
+ <xsl:when test="2 &lt;= $h_prime and $h_prime &lt; 3">
+ <xsl:value-of select="concat('rgb(', $zm, ',', $cm, ',', $xm, ')' )" />
+ </xsl:when>
+ <xsl:when test="3 &lt;= $h_prime and $h_prime &lt; 4">
+ <xsl:value-of select="concat('rgb(', $zm, ',', $xm, ',', $cm, ')' )" />
+ </xsl:when>
+ <xsl:when test="4 &lt;= $h_prime and $h_prime &lt; 5">
+ <xsl:value-of select="concat('rgb(', $xm, ',', $zm, ',', $cm, ')' )" />
+ </xsl:when>
+ <xsl:when test="5 &lt;= $h_prime and $h_prime &lt; 6">
+ <xsl:value-of select="concat('rgb(', $cm, ',', $zm, ',', $xm, ')' )" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat('rgb(', $cm, ',', $xm, ',', $zm, ')' )" />
+ </xsl:otherwise>
</xsl:choose>
</xsl:template>
+
</xsl:stylesheet>
xml/math.xsl
+<?xml version="1.0" encoding="UTF-8" ?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <xsl:variable name="PI">3.14159265358979323846</xsl:variable>
+ <xsl:variable name="DEGREES" select="180 div $PI" />
+ <xsl:variable name="PRECISION">0.0001</xsl:variable>
+
+ <xsl:template name="sqrt">
+ <!-- Find the square root of this number -->
+ <xsl:param name="n" select="0" />
+ <!-- Used internally -->
+ <xsl:param name="try" select="1" />
+ <!-- The current iteration, checked against maxiter to limit loop count -->
+ <xsl:param name="iter" select="1"/>
+ <!-- Used to avoid infinite loops (maximum iteration) -->
+ <xsl:param name="maxiter" select="20"/>
+
+ <!-- Nate Austin's implementation using Newton's method -->
+ <xsl:choose>
+ <xsl:when test="$try * $try = $n or $iter &gt; $maxiter">
+ <xsl:value-of select="$try" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="sqrt">
+ <xsl:with-param name="n" select="$n"/>
+ <xsl:with-param name="try" select="$try - (($try * $try - $n) div (2 * $try))"/>
+ <xsl:with-param name="iter" select="$iter + 1"/>
+ <xsl:with-param name="maxiter" select="$maxiter"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="sine">
+ <xsl:param name="deg" />
+ <xsl:param name="radians">
+ <xsl:value-of select="$deg div 180 * $PI" />
+ </xsl:param>
+ <xsl:param name="answer">
+ <xsl:value-of select="$radians" />
+ </xsl:param>
+ <xsl:param name="loc">1</xsl:param>
+ <xsl:param name="fract">
+ <xsl:value-of select="$radians" />
+ </xsl:param>
+ <xsl:variable name="fract2" select="-1 * $fract * $radians * $radians div ($loc *2 * ($loc * 2 + 1))" />
+ <xsl:choose>
+ <xsl:when test="$fract2 &lt; $PRECISION and $fract2 &gt; -$PRECISION">
+ <xsl:value-of select="$answer" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="sine">
+ <xsl:with-param name="radians" select="$radians" />
+ <xsl:with-param name="answer" select="$answer + $fract2" />
+ <xsl:with-param name="loc" select="$loc+1" />
+ <xsl:with-param name="fract" select="$fract2" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="atan2">
+ <xsl:param name="y"/>
+ <xsl:param name="x"/>
+ <!-- http://lists.apple.com/archives/PerfOptimization-dev/2005/Jan/msg00051.html -->
+ <!-- http://permalink.gmane.org/gmane.text.xml.xslt.extensions/840 -->
+ <xsl:variable name="PIBY2" select="$PI div 2.0"/>
+ <xsl:choose>
+ <xsl:when test="$x = 0.0">
+ <xsl:choose>
+ <xsl:when test="($y &gt; 0.0)">
+ <xsl:value-of select="$PIBY2"/>
+ </xsl:when>
+ <xsl:when test="($y &lt; 0.0)">
+ <xsl:value-of select="-$PIBY2"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="number(NaN)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="z" select="$y div $x"/>
+ <xsl:variable name="absZ">
+ <xsl:choose>
+ <xsl:when test="$z &lt; 0.0">
+ <xsl:value-of select="-number($z)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="number($z)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="($absZ &lt; 1.0)">
+ <xsl:variable name="f1Z" select="$z div (1.0 + 0.28*$z*$z)"/>
+ <xsl:choose>
+ <xsl:when test="($x &lt; 0.0) and ($y &lt; 0.0)">
+ <xsl:value-of select="$f1Z - $PI"/>
+ </xsl:when>
+ <xsl:when test="($x &lt; 0.0)">
+ <xsl:value-of select="$f1Z + $PI"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$f1Z"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="f2Z" select="$PIBY2 - ($z div ($z*$z + 0.28))"/>
+ <xsl:choose>
+ <xsl:when test="($y &lt; 0.0)">
+ <xsl:value-of select="$f2Z - $PI"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$f2Z"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="max">
+ <xsl:param name="a" select="0" />
+ <xsl:param name="b" select="0" />
+
+ <xsl:if test="$a &gt;= $b"><xsl:value-of select="$a" /></xsl:if>
+ <xsl:if test="$a &lt; $b"><xsl:value-of select="$b" /></xsl:if>
+ </xsl:template>
+
+ <xsl:template name="hex2dec">
+ <xsl:param name="hex" select="'00'" />
+
+ <xsl:variable name="digits" select="'0123456789ABCDEF'" />
+ <xsl:variable name="X" select="substring( $hex, 1, 1 )" />
+ <xsl:variable name="Y" select="substring( $hex, 2, 1 )" />
+ <xsl:variable name="Xval" select="string-length(substring-before($digits,$X))" />
+ <xsl:variable name="Yval" select="string-length(substring-before($digits,$Y))" />
+
+ <xsl:value-of select="16 * $Xval + $Yval" />
+ </xsl:template>
+
+</xsl:stylesheet>
xml/resources.css
}
+.legend {
+ margin-top: 0.5em;
+}
xml/resources.xml
<resources>
<expenses>
- <title>Federal Expenses</title>
+ <title>Expenses</title>
<dataset>
<data>

Colourful client-side pie chart.

Author Dave Jarvis <email>
Date 2014-07-31 20:38:57 GMT-0700
Commit b3c592067be189a12588189d03d98f2f204f2f5c
Parent 6e61d18
Delta 253 lines added, 61 lines removed, 192-line increase