Dynamische Säulendiagramme mit Canvas

Bilder - und Säulendiagramme im Speziellen - sagen mehr als 1000 Worte. Schön, dass es mit HTML5 jetzt die Möglichkeit gibt, schnell und einfach Daten von einer schnöden Tabelle in ein ansehnliches und informatives Säulendiagramm zu verwandeln. In diesem Tutorial lernen Sie, wie man aus Daten per JavaScript ein Säulendiagramm auf einem Canvas erzeugt.

<script type="text/javascript">

// Grundvariablen
var chartheight = 300;
var yoffset = 30;
//document.getElementById('beschriftung').style.top = "300px";
values = new Array();

   values[1]   = [135 , 142, 184, 171, 196,201, 189, 182], // Online Werbeumsatz in MIO / Mon 2010 Dtl.
   values[2]  = [113, 116, 147, 137, 138, 132, 129, 121,0,0,0,0], // 2009
  beschriftung = ["Jan", "Feb", "M&auml;r", "Apr", "Mai", "Jun", "Jul" ,"Aug"];

   vmax = 0 ;    // zur Anpassung der values an die Canvashöhe
   // Höchsten Wert bestimmen   
        for(var i = 0; i < values[1].length; i++) {
          if (values[1][i] > vmax) { 
            vmax = values[1][i];
          }
        }

//Canvas - Balken
var bc = {
   canvas   : null,  // Canvas Element
   ctx      : null,  // 2D-Grafikkontext vom Canvas

   //values2    :   [19, 24, 25, 24, 42, 52, 47, 50],  // porzentale Veränderung zu 2009
   barWidth : 30,        // Breite der Balken
   barFill  : null,      // Farbverlauf für Säulen
   backgroundFill: null, // Farbverlauf für Hintergrund

   scale    : 1,         // Skalierungsfaktor während der Animation
   duration : 3,       // Dauer der Animation in Sekunden
   fps      : 25,        // Anzahl der Bilder pro Sekunde
   startTime: 0,         // Startzeitpunkt der Animation
   timer    : null,      // JavaScript Timer

  
   init: function() {
     //layer += 1;     
     //alert (layer);
       bc.canvas = document.getElementById('canvas1');
       if(bc.canvas && bc.canvas.getContext) {
           bc.ctx = bc.canvas.getContext('2d');

           // Farbverläufe
           bc.barFill = bc.ctx.createLinearGradient( 100, 0, 0, 120);
           bc.barFill.addColorStop(0.7, 'lightcyan');
           bc.barFill.addColorStop(.71, 'white');

     //if (layer <2 ) {
      // alert ("bg"+layer+" erzeugen");
           bc.backgroundFill = bc.ctx.createLinearGradient( 0, 0, 0, bc.canvas.height);
           bc.backgroundFill.addColorStop(0.0, '#666666');
           bc.backgroundFill.addColorStop(1.0, '#CCCCCC');
     //}

           // Start
           bc.animStart();
       }
   },

   draw: function() {
       // Hintergrund zeichnen
       bc.ctx.fillStyle = bc.backgroundFill;
       bc.ctx.fillRect(0, 0, bc.canvas.width, bc.canvas.height);

       // Status retten und Ursprung nach unten verschieben
       // sowie Koordinaten an der x-Achse spiegeln
       bc.ctx.save();

       bc.ctx.translate(20, bc.canvas.height - yoffset);
       bc.ctx.scale(1, -1);

     bc.ctx.fillStyle = "red";
    // xxx bc.ctx.fillRect = (0,);

   // Säulen zeichnen
      for(var i = 0; i < values[1].length; i++) {
        
         bc.ctx.fillStyle = bc.barFill;
         bc.ctx.fillRect(i * (bc.barWidth + 10), 0, bc.barWidth, bc.scale * values[1][i] * (chartheight-yoffset*2) / vmax);
         //          x1          y1      x2        y2            Höhe des Canvas - Doppelter Rand / Höchstwert (zur Skalierung) 
        
       }

       // Alten Status wiederherstellen
       bc.ctx.restore();
   },

   animate: function() {
       var diffTime = new Date().getTime() - bc.startTime;

       // Skalierungsfaktor (0.0 bis 1.0) für Säulen berechnen
       bc.scale = diffTime / (1000 * bc.duration);

       // Ende?
       if(diffTime >= 1000 * bc.duration) {
           bc.scale = 1.0; // Auf 1.0 setzen, damit die Säulen am Schluss mit
                           // Sicherheit mit dem richtigen Wert gezeichnet werden

      showData();
      
      clearInterval(bc.timer);
       

           // Neustart nach 10 Sekunden
           //setTimeout(bc.animStart, 1000 * 10);
      }

      bc.draw();
   },

   animStart: function() {
       bc.startTime = new Date().getTime();
       bc.timer = setInterval(bc.animate, 1000 / bc.fps);
   },
   
   
   // Make data output
};

function showData () {  
         // Balken in Datenmaske erstellen
      for(var i = 0; i < values[1].length; i++) {

           var x1 = i * (bc.barWidth + 10) + 20;
           var y1 = chartheight - yoffset - bc.scale * values[1][i] * (chartheight-yoffset*2) / vmax;
           var x2 = i * (bc.barWidth + 10) + 20 + bc.barWidth;
           var y2 = chartheight - yoffset;
        
        balken = document.createElement('area');
          balken.setAttribute("title", beschriftung[i] + ": EUR " + values[1][i] + " Mio.");
          balken.setAttribute("shape", "rect");        
          balken.setAttribute("coords", x1 + "," + y1 + "," + x2 + "," + y2);
          balken.setAttribute("href", "#");
        document.getElementById('data').appendChild(balken);
      
      // Titel einblenden
        var yTitle = y1;
        titel = document.createElement('div');
          titel.setAttribute("style", "left:" + x1 + "px; top:" + yTitle + "px;" );
          titel.innerHTML = values[1][i] ;        // +beschriftung[i]
        document.getElementById('titel').appendChild(titel);
        
      // Beschriftung einblenden
        yBeschriftung = chartheight - 22;
        beschr = document.createElement('div');
          beschr.setAttribute("style", "left:" + x1 + "px; top:" + yBeschriftung + "px;" );
          beschr.innerHTML = beschriftung[i] ;        // +beschriftung[i]
        document.getElementById('beschriftung').appendChild(beschr);
  
        
      }
  }

</script>

<style type="text/css">
<!--

ul {
  list-style-type: none;
}

ul li {
  width: 30px;
  margin-right: 10px;
  float: left;
  background-color: #DDD;
  text-align: center;
}

img {border: none}

#titel div, #beschriftung div {
  position: absolute; 
  padding: 2px 0;
  text-align: center;
  font-family: Arial, Helvetica, sans-serif;
  text-transform: uppercase;
  font-size: 9px;
  background-color: #EEE;
  border: 2px solid #FFF;
  height: 11px;
  width: 26px;
  opacity: .70;
  filter:alpha(opacity=70);
  filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
}
  
  
/*area {border: 1px solid #F00} */
  
  }
-->
</style>

<div id="chartwrapper" style="position: relative;">

    <canvas id="canvas1" width="510" height="300">
      <p>Dieses Beispiel benötigt einen Webbrowser mit 
      <a href="http://de.wikipedia.org/wiki/Canvas_(HTML-Element)">HTML Canvas</a>-Unterstützung.</p>
    </canvas>
 
<!--     <canvas id="canvas2" width="510" height="300" style="z-index:10; position: absolute; left:0; top:0">
      <p>Dieses Beispiel benötigt einen Webbrowser mit 
      <a href="http://de.wikipedia.org/wiki/Canvas_(HTML-Element)">HTML Canvas</a>-Unterstützung.</p>
    </canvas>-->

 
    
  <div id="datascreen" style="position:absolute; top: 0; width: 510px; height:300px; z-index: 20">
        <img name="bild" width="500" height="300" lt="" usemap="#data" src="http://app-entwickler-verzeichnis.de/images/transparent.png" />
        <map id="data" name="data">
        </map>
    </div>
    
  <div id="titel" style="position:absolute; top: 0; width: 510px; height:300px; z-index: 10" >
  
  </div>
    
    <div id="beschriftung" style="position:absolute; top: 0; width: 510px; height:300px; z-index: 10">
         
    </div>
    

<br />

<div style="small">
Quelle:<a href="http://www.nielsen-media.de/pages/default.aspx"> Nielsen Media Research GmbH </a><br/>
Stark erweiterte Version auf Anregung von: <a href="http://www.drweb.de/magazin/javascript-animiertes-saulendiagramm-mit-html-canvas/">drWeb</a>,
IAB</div>

<noscript>
<p>Dieses Beispiel benötigt einen Webbrowser mit aktivierter
  <a href="http://de.wikipedia.org/wiki/JavaScript">JavaScript</a>-Unterstützung.</p>
</noscript>

<script type="text/javascript">
  window.onload = bc.init;
</script>
Dieser Beitrag wurde unter HTML5 veröffentlicht. Setze ein Lesezeichen auf den Permalink.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert