SVG, XSLT and JSP/JSTL: Generating Digital Gauge or Speedometer Chart based on dynamic data

4
Share this on .. Tweet about this on TwitterShare on LinkedIn0Share on Facebook0Share on Google+0Email this to someoneShare on Tumblr0Buffer this page

Transform generic Measures into SVG Speedometer Graph

The stylesheet buildSVGSpeedometer.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 Digital Gauge chart. Here I will show a few sections from this stylesheet:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:math="http://xml.apache.org/xslt/java/java.lang.Math"
                xmlns:xlink="http://www.w3.org/2000/xlink/namespace/"
>
<!-- for oracle XDK: xmlns:math="http://www.oracle.com/XSL/Transform/java/java.lang.Math"
     for Xalan: xmlns:math="http://xml.apache.org/xslt/java/java.lang.Math"
     -->

<!-- center of the dial:  cx="2160" cy="2720" -->
  <xsl:output  omit-xml-declaration="yes"/>
  <xsl:template match="graphData">
    <xsl:variable name="degrees"> <!-- how far should the gauge extend; default is 180 degrees, a semi-circle -->
      <xsl:choose>
        <xsl:when test="degrees">
          <xsl:value-of select="degrees"/>
        </xsl:when>
        <xsl:otherwise>180</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <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="1100px" height="1850px" onload="getSVGDoc(evt)" onzoom="ZoomControl()">
    <defs>
            <script type="text/javascript">
          <![CDATA[
          /* this code was largely reused from the excellent website SVG - Learning by Coding (http://svglbc.datenverdrahten.de/) */
                var svgdoc,svgroot;
                function getSVGDoc(load_evt)
                {
                  svgdoc=load_evt.target.ownerDocument;
                  svgroot=svgdoc.documentElement;

                  texte=svgdoc.getElementById("tooltip").getElementsByTagName("text");
                }
                function ShowTooltip(mousemove_event,txt)
                {
                  var ttrelem,tttelem,posx,posy,curtrans,ctx,cty,txt;
                  var sollbreite,maxbreite,ges,anz,tmp,txl,neu,i,k,l
                  ttrelem=svgdoc.getElementById("ttr");
                  tttelem=svgdoc.getElementById("ttt");
                  posx=mousemove_event.clientX;
                  posy=mousemove_event.clientY;
                  for(i=1;i<=5;i++)texte.item(i).firstChild.data="";
                  sollbreite=150;
                  tttelem.childNodes.item(0).data=txt;
                  ges=tttelem.getComputedTextLength();
                  tttelem.childNodes.item(0).data="";
                  anz=Math.ceil(ges/sollbreite);
                  tmp=txt.split(" ");
                  txl=new Array(tmp.length);
                  neu=new Array(anz);
                  for(i=0;i<tmp.length;i++)
                  {
          tttelem.childNodes.item(0).data=tmp[i];
          txl[i]=tttelem.getComputedTextLength();
                  }
                  k=0;
                  maxbreite=0;
                  for(i=0;i<anz;i++)
                  {
          l=0,neu[i]="";
          while(l+txl[k]<1.1*sollbreite && k<tmp.length)
          {
            l+=txl[k];
            neu[i]+=tmp[k]+" ";
            k++;
            if(maxbreite<l)maxbreite=l;
          }
                  }
                  curtrans=svgroot.currentTranslate;
                  ctx=curtrans.x;
                  cty=curtrans.y;
                  ttrelem.setAttribute("x",posx-ctx+10);
                  ttrelem.setAttribute("y",posy-cty-20+10);
                  ttrelem.setAttribute("width",maxbreite+2*(maxbreite-sollbreite)+110);
                  ttrelem.setAttribute("height",anz*15+3);
                  ttrelem.setAttribute("style","fill: #FFC; stroke: #000; stroke-width: 0.5px");
                  for(i=1;i<=anz;i++)
                  {
          texte.item(i).firstChild.data=neu[i-1];
          texte.item(i).setAttribute("x",posx-ctx+15);
          texte.item(i).setAttribute("y",parseInt(i-1)*15+posy-cty+3);
          texte.item(i).setAttribute("style","fill: #00C; font-size: 11px");
                  }
                  svgdoc.getElementById("tooltip").style.setProperty("visibility","visible");
                }
                function HideTooltip()
                {
                  svgdoc.getElementById("tooltip").style.setProperty("visibility","hidden");
                }
                function ZoomControl()
                {
                  var curzoom;
                  curzoom=svgroot.currentScale;
                  svgdoc.getElementById("tooltip").setAttribute("transform","scale("+1/curzoom+")");
                }
                ]]>
        </script>
  <radialGradient id="GR63" gradientUnits="userSpaceOnUse" cx="2160" cy="2720" r="1940" >
   <stop offset="0.1" stop-color="#E7EAE9"/>
   <stop offset="0.95" stop-color="#9DACA8"/>
  </radialGradient>

    </defs>
    <g id='all' transform="scale(0.2)">
 <!-- create the background in gray -->
 <g stroke-width="12" stroke="#000000" fill="#556475">
  <rect x="40" y="40" width="4240" height="4160" rx="60" />
 </g>
 <g id="Heading" fill="#FFFF82" font-family="Arial" font-weight="bold" font-size="180" text-anchor="middle" pointer-events="none">
  <text x="2160" y="256"><xsl:value-of select="title"/></text>
 </g>
 <g id="Subhead" fill="#FFFF82" font-family="Times New Roman" font-size="100" text-anchor="middle" pointer-events="none">
  <text x="2160" y="451">
    <xsl:value-of select="subtitle"/>
  </text>
 </g>

<!-- generate the markerareas or zones around the speedometer; each zone spans a certain value-range has a color and a tooltip -->
 <xsl:for-each select="markerarea">
    <xsl:call-template name="markerArea">
      <xsl:with-param name="startvalue" select="startvalue"/>
      <xsl:with-param name="endvalue" select="endvalue"/>
      <xsl:with-param name="min" select="$min"/>
      <xsl:with-param name="max" select="$max"/>
      <xsl:with-param name="degrees" select="$degrees" />
      <xsl:with-param name="color" select="color"/>
      <xsl:with-param name="title" select="title" />
    </xsl:call-template>
</xsl:for-each>

 <defs>
  <!-- define the gray gradient on the inside of the speedometer -->
  <radialGradient id="GR64" gradientUnits="userSpaceOnUse" cx="2160" cy="2720" r="1649" >
   <stop offset="0.1" stop-color="#E7EAE9"/>
   <stop offset="0.95" stop-color="#9DACA8"/>
  </radialGradient>
 </defs>

 <!-- inner axis area (gray semicircle)-->
 <g stroke="#FFFF82" stroke-width="0" stroke-linejoin="round" fill="url(#GR64)">
  <xsl:variable name="markerAngle"  select="math:toRadians((180 - $degrees) div 2 + $degrees)"/>
  <xsl:variable name="x1" select="math:cos($markerAngle) * -1* 1649 + 2160 "/>
  <xsl:variable name="y1" select="math:sin($markerAngle) * 1649 * -1 + 2720"/>
  <xsl:variable name="x2" select="math:cos($markerAngle) * 1* 1649 +2160 "/>
  <path>
    <xsl:attribute name="d"><xsl:text>M </xsl:text><xsl:value-of select="$x1"/><xsl:text> </xsl:text>
    <xsl:value-of select="$y1"/>
    <xsl:text> A 1649 1649 0 </xsl:text>
    <xsl:choose><xsl:when test="$degrees > 180">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose>
    <xsl:text> 0 </xsl:text>
    <xsl:value-of select="$x2"/><xsl:text> </xsl:text><xsl:value-of select="$y1"/>
    <xsl:text> L 2160 2720 </xsl:text>
    </xsl:attribute>
  </path>
</g> <!-- inner area -->


<!-- draw markers and values around the outline of the speedometer -->
<xsl:for-each select="yvalues">
  <xsl:for-each select="yvalue">
    <xsl:call-template name="axisMarker">
      <xsl:with-param name="markerValue" select="value"/>
      <xsl:with-param name="markerLabel" select="label"/>
      <xsl:with-param name="max" select="$max"/>
      <xsl:with-param name="min" select="$min"/>
      <xsl:with-param name="degrees" select="$degrees"/>
    </xsl:call-template>
  </xsl:for-each>

    <xsl:for-each select="ymarkers">
      <!-- draw y-markers on the axis -->
      <xsl:call-template name="ymarker">
        <xsl:with-param name="start" select="minvalue"/>
        <xsl:with-param name="n" select="steps"/>
        <xsl:with-param name="stepsize"
                        select="(maxvalue - minvalue) div steps"/>
        <xsl:with-param name="min" select="$min"/>
        <xsl:with-param name="max" select="$max"/>
        <xsl:with-param name="gridline" select="gridline"/>
        <xsl:with-param name="degrees" select="$degrees"/>
        <xsl:with-param name="submarkers" select="submarkers"/>
        <xsl:with-param name="showsubmarkervalue" select="showsubmarkervalue"/>
      </xsl:call-template>
    </xsl:for-each>
</xsl:for-each> <!-- yvalues -->

<!-- display the counter in the middle of the speedometer -->
<xsl:if test="counter">
  <g id="counter" onmouseout="HideTooltip(evt)">
     <xsl:attribute name="onmouseover">ShowTooltip(evt,'<xsl:value-of select="counterlabel"/>')</xsl:attribute>
     <rect x="1910"  y="2100" width="500" height="120" fill="black" />
     <text stroke="ivory" fill="ivory"  font="Helvetica" text-anchor="middle" font-size="100" x="2160"  y="2200">
        <xsl:value-of select="counter"/>
     </text>
     <text stroke="steelblue" fill="steelblue"  font="Helvetica" text-anchor="middle" font-size="70" x="2160"  y="2295">
        <xsl:value-of select="counterunits"/>
     </text>
  </g>
</xsl:if>

<!-- display the daycounter in the middle of the speedometer -->
<xsl:if test="daycounter">
  <g id="daycounter" onmouseout="HideTooltip(evt)">
    <xsl:attribute name="onmouseover">ShowTooltip(evt,'<xsl:value-of select="daycounterlabel"/>')</xsl:attribute>
    <rect x="1970"  y="1500" width="380" height="120" fill="black" />
    <text stroke="ivory" fill="ivory"  font="Helvetica" text-anchor="middle" font-size="100" x="2160"  y="1600">
      <xsl:value-of select="daycounter"/>
    </text>
    <text stroke="steelblue" fill="steelblue"  font="Helvetica" text-anchor="middle" font-size="70" x="2160"  y="1690">
       <xsl:value-of select="daycounterunits"/>
    </text>
  </g>
</xsl:if>

<!-- Draw a dial for each set in the source document -->
<xsl:for-each select="sets/set">
  <xsl:variable name="color">
    <xsl:choose>
      <xsl:when test="@color"><xsl:value-of select="@color"/></xsl:when>
      <!-- if no color was defined, assign a color -->
      <xsl:when test="position()=1">#000080</xsl:when>
      <xsl:when test="position()=2">#800000</xsl:when>
      <xsl:when test="position()=3">green</xsl:when>
      <xsl:when test="position()=3">ivory</xsl:when>
    </xsl:choose>
  </xsl:variable>

<g onmouseout="HideTooltip(evt)">
      <xsl:attribute name="onmouseover">ShowTooltip(evt,'<xsl:value-of select="measure[1]/label"/>')</xsl:attribute>

 <xsl:attribute name="transform">rotate(<xsl:value-of select="(180 - $degrees) div 2 + (measure[1]/xvalue - $min) div ($max - $min) * $degrees"/> ,2160, 2720)</xsl:attribute>
   <line fill="none"  stroke-width="44"  x1="2160"  y1="2720"   y2="2720">
     <xsl:attribute name="stroke"><xsl:value-of select="$color"/></xsl:attribute>
     <xsl:attribute name="x2"><xsl:value-of select="297 + (position() -1 ) * 550"/></xsl:attribute>
   </line>
   <g  stroke-width="42" >
     <xsl:attribute name="stroke"><xsl:value-of select="$color"/></xsl:attribute>
     <xsl:attribute name="fill"><xsl:value-of select="$color"/></xsl:attribute>
     <path >
       <xsl:attribute name="d">
         <xsl:text>M </xsl:text>
         <xsl:value-of select="297 + (position() -1 ) * 550"/>
         <xsl:text> 2720 L </xsl:text>
         <xsl:value-of select="414 + (position() -1 ) * 550"/>
         <xsl:text> 2804 </xsl:text>
         <xsl:value-of select="363 + (position() -1 ) * 550"/>
         <xsl:text> 2720 </xsl:text>
         <xsl:value-of select="414 + (position() -1 ) * 550"/>
         <xsl:text> 2636 z </xsl:text>
        </xsl:attribute>
     </path>
   </g>
 </g>
</xsl:for-each><!-- end dials -->


<!-- the outline for the gauge -->
 <g stroke="#000000" stroke-width="30" stroke-linejoin="round" fill="none">
  <xsl:variable name="markerAngle"  select="math:toRadians((180 - $degrees) div 2 + $degrees)"/>
  <xsl:variable name="x1" select="math:cos($markerAngle) * -1* 1940 + 2160 "/>
  <xsl:variable name="y1" select="math:sin($markerAngle) * 1940 * -1 + 2720"/>
  <xsl:variable name="x2" select="math:cos($markerAngle) * 1* 1940 +2160 "/>
  <path>
    <xsl:attribute name="d"><xsl:text>M </xsl:text><xsl:value-of select="$x1"/><xsl:text> </xsl:text>
    <xsl:value-of select="$y1"/>
    <xsl:text> A 1940 1940 0 </xsl:text>
    <xsl:choose><xsl:when test="$degrees>180">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose>
    <xsl:text> 0 </xsl:text>
    <xsl:value-of select="$x2"/><xsl:text> </xsl:text><xsl:value-of select="$y1"/></xsl:attribute>
  </path>
 </g>

 <!-- the inner circle ; the centre where the dials are 'connected'-->
 <g fill="#000000" stroke="#000000" stroke-width="12" >
  <circle cx="2160" cy="2720" r="60"/>
 </g>
 </g>
      <g id="tooltip" style="visibility: hidden">
        <!-- Tooltip - Beginn (ttr=Tooltip-Rechteck, ttt=Tooltip-Text) -->
        <rect id="ttr" x="0" y="0" rx="5" ry="5" width="150" height="16"/>
        <text id="ttt" x="0" y="0" style="visibility: hidden">dyn. Text</text>
        <text x="-10" y="-10">dyn. Text</text>
        <text x="-10" y="-10">dyn. Text</text>
        <text x="-10" y="-10">dyn. Text</text>
        <text x="-10" y="-10">dyn. Text</text>
        <text x="-10" y="-10">dyn. Text</text>
      </g>
      <!-- Tooltip - End -->
 </svg>
 </xsl:template>

<!-- draw markers along the outside of the speedometer; also display labels (usually values) -->
<xsl:template name="axisMarker">
    <xsl:param name="markerValue"/>
    <xsl:param name="markerLabel"><xsl:value-of select="$markerValue"/></xsl:param>
    <xsl:param name="max"/>
    <xsl:param name="min"/>
    <xsl:param name="degrees">180</xsl:param>
    <xsl:param name="sub">0</xsl:param>

  <xsl:variable name="markerAngle"  select="math:toRadians((180 - $degrees) div 2 + ($markerValue - $min) div ($max - $min) * $degrees)"/>
      <!-- if submarker then value should be more pushed out -->
      <xsl:variable name="x1">
         <xsl:choose>
         <xsl:when test="$sub = 1">
          <xsl:value-of select="math:cos($markerAngle) * -1* 1640  + 2160 "/>
          </xsl:when>
         <xsl:otherwise>
          <xsl:value-of select="math:cos($markerAngle) * -1* 1580  + 2160 "/>
        </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
      <xsl:variable name="y1">
         <xsl:choose>
         <xsl:when test="$sub = 1">
          <xsl:value-of select="math:sin($markerAngle) * 1500 * -1 + 2735 "/>
          </xsl:when>
         <xsl:otherwise>
          <xsl:value-of select="math:sin($markerAngle) * 1480 * -1 + 2755 "/>
        </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
  <text font-family="Arial" font-weight="bold"  >
     <xsl:attribute name="font-size">
       <xsl:choose>
         <xsl:when test="$sub = 1">100</xsl:when>
         <xsl:otherwise>160</xsl:otherwise>
         </xsl:choose>
     </xsl:attribute>
    <xsl:attribute name="text-anchor">
      <xsl:choose>
        <xsl:when test="$markerAngle < 1 ">start</xsl:when>
        <xsl:when test="($markerAngle > 2) ">end</xsl:when>
        <xsl:otherwise>middle</xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:attribute name="x"><xsl:value-of select="$x1"/></xsl:attribute>
    <xsl:attribute name="y"><xsl:value-of select="$y1"/></xsl:attribute>
    <xsl:value-of select="$markerLabel"/>
  </text>
  <g fill="blue" stroke="#000000"  >
     <xsl:attribute name="stroke-width">
       <xsl:choose>
         <xsl:when test="$sub = 1">15</xsl:when>
         <xsl:otherwise>22</xsl:otherwise>
         </xsl:choose>
     </xsl:attribute>
    <xsl:attribute name="transform">rotate(<xsl:value-of select="(180- $degrees) div 2 + ($markerValue - $min) div ($max - $min) * $degrees"/>, 2160, 2720)</xsl:attribute>
    <line x1="220" y1="2720"  y2="2720">
         <xsl:attribute name="x2">
       <xsl:choose>
         <xsl:when test="$sub = 1">350</xsl:when>
         <xsl:otherwise>558</xsl:otherwise>
         </xsl:choose>
     </xsl:attribute>
    </line>
  </g>
  </xsl:template><!-- axisMarker -->

  <xsl:template name="ymarker">
    <xsl:param name="n"/>
    <xsl:param name="i">0</xsl:param>
    <xsl:param name="stepsize"/>
    <xsl:param name="min"/>
    <xsl:param name="max"/>
    <xsl:param name="gridline">false</xsl:param>
    <xsl:param name="start">
      <xsl:value-of select="$min"/>
    </xsl:param>
    <xsl:param name="axis">1</xsl:param>
    <xsl:param name="degrees">180</xsl:param>
    <xsl:param name="submarkers">0</xsl:param>
    <xsl:param name="showsubmarkervalue">no</xsl:param>
    <xsl:variable name="value">
      <xsl:value-of select="(($start + $i* $stepsize ) )"/>
    </xsl:variable>

    <xsl:call-template name="axisMarker">
      <xsl:with-param name="markerValue" select="$value"/>
      <xsl:with-param name="markerLabel" select="$value"/>
      <xsl:with-param name="max" select="$max"/>
      <xsl:with-param name="min" select="$min"/>
      <xsl:with-param name="degrees" select="$degrees"/>
    </xsl:call-template>

    <xsl:if test="$i < $n">
      <xsl:call-template name="ymarker">
        <xsl:with-param name="i" select="$i+1"/>
        <xsl:with-param name="n" select="$n"/>
        <xsl:with-param name="stepsize" select="$stepsize"/>
        <xsl:with-param name="min" select="$min"/>
        <xsl:with-param name="max" select="$max"/>
        <xsl:with-param name="start" select="$start"/>
        <xsl:with-param name="gridline" select="$gridline"/>
        <xsl:with-param name="axis" select="$axis"/>
        <xsl:with-param name="submarkers" select="$submarkers"/>
        <xsl:with-param name="showsubmarkervalue" select="$showsubmarkervalue"/>
        <xsl:with-param name="degrees" select="$degrees"/>
      </xsl:call-template>

      <!-- if so desired and still within the range set up by the y-markers then draw submarkers -->
     <xsl:if test="$submarkers > 0">
     <xsl:call-template name="submarkers">
        <xsl:with-param name="i" select="1"/>
        <xsl:with-param name="n" select="$submarkers"/>
        <xsl:with-param name="stepsize" select="$stepsize div ($submarkers +1)"/>
        <xsl:with-param name="min" select="$min"/>
        <xsl:with-param name="max" select="$max"/>
        <xsl:with-param name="start" select="$value"/>
        <xsl:with-param name="gridline" select="$gridline"/>
        <xsl:with-param name="axis" select="$axis"/>
        <xsl:with-param name="showsubmarkervalue" select="$showsubmarkervalue"/>
        <xsl:with-param name="degrees" select="$degrees"/>
     </xsl:call-template>
     </xsl:if>
    </xsl:if>
  </xsl:template>
  <!-- ymarker -->

  <!-- show the smaller markers (submarkers) -->
  <xsl:template name="submarkers">
    <xsl:param name="n"/>
    <xsl:param name="i">0</xsl:param>
    <xsl:param name="stepsize"/>
    <xsl:param name="min"/>
    <xsl:param name="max"/>
    <xsl:param name="gridline">false</xsl:param>
    <xsl:param name="start">
      <xsl:value-of select="$min"/>
    </xsl:param>
    <xsl:param name="axis">1</xsl:param>
    <xsl:param name="degrees">180</xsl:param>
    <xsl:param name="submarkers">0</xsl:param>
    <xsl:param name="showsubmarkervalue">no</xsl:param>
    <xsl:variable name="value">
      <xsl:value-of select="(($start +  $stepsize ) )"/>
    </xsl:variable>

    <xsl:call-template name="axisMarker">
      <xsl:with-param name="markerValue" select="$value"/>
      <xsl:with-param name="markerLabel">
        <xsl:choose>
          <xsl:when test="showsubmarkervalue='yes'"><xsl:value-of select="$value" />
          </xsl:when>
        </xsl:choose>
      </xsl:with-param>
      <xsl:with-param name="max" select="$max"/>
      <xsl:with-param name="min" select="$min"/>
      <xsl:with-param name="degrees" select="$degrees"/>
      <xsl:with-param name="sub">1</xsl:with-param>
    </xsl:call-template>


<!-- if submarkers > 0
     then substepsize = divide stepsize by submarkers;
     -->
    <xsl:if test="$i < $n">
     <xsl:call-template name="submarkers">
        <xsl:with-param name="i" select="$i + 1"/>
        <xsl:with-param name="n" select="$n"/>
        <xsl:with-param name="stepsize" select="$stepsize"/>
        <xsl:with-param name="min" select="$min"/>
        <xsl:with-param name="max" select="$max"/>
        <xsl:with-param name="start" select="$value"/>
        <xsl:with-param name="gridline" select="$gridline"/>
        <xsl:with-param name="axis" select="$axis"/>
        <xsl:with-param name="submarkers" select="$submarkers"/>
        <xsl:with-param name="showsubmarkervalue" select="$showsubmarkervalue"/>
        <xsl:with-param name="degrees" select="$degrees"/>
     </xsl:call-template>
     </xsl:if>


  </xsl:template>
  <!-- submarkers -->

<!-- draw the markerareas - the zones on the outside of the speedometer -->
<xsl:template name="markerArea">
  <xsl:param name="startvalue" />
  <xsl:param name="endvalue" />
  <xsl:param name="min" />
  <xsl:param name="max" />
  <xsl:param name="degrees">180</xsl:param>
  <xsl:param name="color">blue</xsl:param>
  <xsl:param name="title">myArea</xsl:param>

   <!-- startvalue to endvalue -->
   <g  stroke-width="0" stroke-linejoin="round" onmouseout="HideTooltip(evt)">
    <xsl:attribute name="onmouseover">ShowTooltip(evt,'<xsl:value-of select="$title"/>')</xsl:attribute>
    <xsl:attribute name="stroke"><xsl:value-of select="$color"/></xsl:attribute>
    <xsl:attribute name="fill"><xsl:value-of select="$color"/></xsl:attribute>
    <xsl:variable name="startvalue" select="$startvalue"/>
    <xsl:variable name="endvalue" select="$endvalue"/>
    <xsl:variable name="firstAngle"  select="math:toRadians((180 - $degrees) div 2 + ($endvalue - $min) div ($max - $min) * $degrees)"/>
    <xsl:variable name="secondAngle"  select="math:toRadians((180 - $degrees) div 2 + ($startvalue - $min) div ($max - $min) * $degrees)"/>
    <xsl:variable name="x1" select="math:cos($firstAngle) * -1* 1940 +2160 "/>
    <xsl:variable name="y1" select="math:sin($firstAngle) * 1940 * -1 + 2720"/>
    <xsl:variable name="x2" select="math:cos($secondAngle) * -1* 1940 +2160 "/>
    <xsl:variable name="y2" select="math:sin($secondAngle) * 1940 * -1 + 2720"/>
    <path  >
    <xsl:attribute name="angle"><xsl:value-of select="$firstAngle"/></xsl:attribute>
      <xsl:attribute name="d"><xsl:text>M 2160 2720 L </xsl:text><xsl:value-of select="$x1"/><xsl:text> </xsl:text>
      <xsl:value-of select="$y1"/>
      <xsl:text> A 1940 1940 0 </xsl:text>
      <xsl:choose><xsl:when test="($secondAngle - $firstAngle) > 180">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose>
      <xsl:text> 0 </xsl:text>
      <xsl:value-of select="$x2"/><xsl:text> </xsl:text><xsl:value-of select="$y2"/>
      <xsl:text> z </xsl:text>
      </xsl:attribute>
    </path>
   </g>
</xsl:template>

</xsl:stylesheet>

The result of the transformation with this stylesheet to the SVG object can be downloaded here:DepSalSpeedometer.svg. The graph that is displayed as a result from these transformations:
Speed-o-meter or Digital Gauge - Salary Sum per Department

Share this on .. Tweet about this on TwitterShare on LinkedIn0Share on Facebook0Share on Google+0Email this to someoneShare on Tumblr0Buffer this page
1 2 3

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director and Oracle Developer Champion. Solution architect and developer on diverse areas including SQL, JavaScript, Docker, Machine Learning, Java, SOA and microservices, events in various shapes and forms and many other things. Author of the Oracle Press books: Oracle SOA Suite 11g Handbook and Oracle SOA Suite 12c Handbook. Frequent presenter on community events and conferences such as JavaOne, Oracle Code and Oracle OpenWorld.

4 Comments

  1. I can understand the report in PDF,XML,HTML.
    I want to do the report in XL.How I can proceed please give a idea.

  2. all information resides here are good.i need some information regardingg migration.i.e, can i get sorce code & front end design for migrating data from excel to oracle.reply soon…plz…

  3. I have drawn up a list of to do’s: new features I would like to add to the Speedometer chart:
    – animation (show the movement of the dials over time)
    – support for multiple axes
    – better markersupport: set markercolor, markerdash and markerlength; gridlines
    – display images (icons) as (part of) markervalues
    – display a legend indicating the meaning of each dial
    – implement a clock using the speedometer stylesheet as demonstration

    I hope to add these features in the new couple of weeks and update the post accordingly.

  4. Pingback: » Enable SVG with Firefox