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

4

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

1 2 3
Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

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