Der Martin: horizontales Balkendiagramm erstellen

Beitrag lesen

Schönen Abend auch,

wer gackert, muss auch legen, sagt man. Also wenn ich schon Versprechungen mache, sollte ich auch dazu stehen.

sehr gut, ich krempel dann genauso meine Arme hoch :) dann kann das ja nur gut werden. Ich bin allerdings heute den ganzen Tag auf der Bauma in München gewesen und morgen beim DFB-Pokal-Halbfinale.

geht's da nicht um dieses seltsame Spiel, bei dem ungefähr zwanzig Männer hinter nur einem Ball herrennen?

Also, Balkendiagramme.

Mein Ansatz sieht zunächst vor, möglichst viel mit HTML/CSS zu machen und Javascript wirklich nur für die Dynamik zu verwenden. Ich würde also die Diagramme komplett im HTML definieren, und ihre visuellen Grundeigenschaften in CSS.

<div class="chart" id="activity">  
<p>Besucherzahlen im Vergleich zum Vormonat</p>  
<div class="bar"></div>  
<p>Zahl der Beiträge im Vergleich zum Vormonat</p>  
<div class="bar"></div>  
</div>  
  
<p>Betrachten wir dazu die Kostenentwicklung:</p>  
  
<div class="chart" id="cost">  
<p>Kostenentwicklung insgesamt</p>  
<div class="bar"></div>  
<p>Kostenentwicklung je Beitrag</p>  
<div class="bar"></div>  
</div>

Dieses inhaltlich sinnfreie Codefragment definiert zwei Bargraph-Felder mit jeweils zwei Balken. Ich verzichte jetzt auf ein Styling für die Containerelemente div.chart sowie für die p-Elemente, und konzentriere mich stattdessen auf die eigentlichen Balken, die als div.bar selektierbar sind. Ich lege hier Position und Größe der Balken für den Wert 0 fest.

div.bar  
 { height: 8px;  
   border: 1px solid #000;  
   margin-left: 50%;  
   width: 0;  
 }

Dazu kommt nun ein Javascript, das in einer komplexen Struktur definiert, welche Elemente als Bargraph agieren sollen, und welchen Wertebereich sie abdecken sollen.

var bargraph =  
 [ { range: 5000, elem: document.getElementById("activity").getElementByClassName("bar")[0] },  
   { range:  100, elem: document.getElementById("activity").getElementByClassName("bar")[1] },  
   { range: 2000, elem: document.getElementById("cost").getElementByClassName("bar")[0] },  
   { range:  200, elem: document.getElementById("cost").getElementByClassName("bar")[1] }  
 ];

Das ist ein Array mit vier Elementen, jedes davon ein Object mit den zwei Feldern range und elem. An dieser Stelle ist es mir völlig egal, wo die zugehörigen Balken im Dokument stehen und wie sie gruppiert sind, da sie durch die Referenz elem eindeutig adressiert werden. Allerdings muss man darauf achten, dass dieser Script-Abschnitt erst ausgeführt wird, nachdem die Elemente, auf die er sich bezieht, auch bekannt sind - er muss also entweder am Ende des Dokuments oder in einem onload-Handler stehen.

Jetzt fehlt nur noch ein Stückchen Script, das die Balken anhand aktueller Werte breiter oder schmaler macht bzw. richtig positioniert. Dafür definiere ich eine Funktion, die den Index des Balkens und den aktuellen Wert bekommt, aus dem range-Feld der Definitionen die richtige Breite und Position errechnet, und dann das in der Definition benannte Element mit den entsprechenden CSS-Eigenschaften versorgt.

function UpdateBar(n, val)  
 { if (n<0 || n>bargraph.length) // bezeichnet n eine gültige Balken-Definition?  
      return;                    // nein, dann ignorieren  
  
   val *= 50/bargraph[n].range;  // Normierung: range wird auf 50 (Prozent) abgebildet  
   var el = bargraph[n].elem;    // Referenz auf das zugehörige Element aus der Definition  
  
   if (val>0)                               // Wert positiv und nicht 0  
    { el.style.marginLeft = "50%";          // Balken beginnt bei 50%  
      el.style.width      = val + "%";      // und hat die vorher berechnete Länge  
    }  
   else  
   if (val<0)                               // Wert negativ  
    { val = -val;                           // dann mach ihn positiv  
      el.style.marginLeft = (50-val)+"%";   // Balken beginnt zwischen linkem Rand und 50%  
      el.style.width      = val + "%";      // und hat die vorher berechnete Länge  
    }  
   else                                     // Wert genau 0  
    { el.style.marginLeft = "50%";          // Balken sitzt in der Mitte  
      el.style.width      = "0";            // und hat Länge 0  
    }  
 }

Das ist mal nur ein erster Entwurf, den man natürlich noch beliebig verfeinern kann. Vor allem habe ich bisher auf die Berücksichtigung von Fehlern wie etwa Bereichsüberschreitungen verzichtet. Wenn man mit UpdateBar() also Werte setzt, die über den mit range definierten Bereich hinausgehen, wird das möglicherweise die Darstellung sprengen. Aber das soll auch zunächst nur ein Anfang sein, von dem aus man weiter vorgehen kann. Dass man diesen Ansatz beliebig ausbauen kann, dürfte auch klar sein.

So long,
 Martin

--
F: Wer waren die ersten modernen Politiker?
A: Die Heiligen drei Könige. Sie legten die Arbeit nieder, zogen teure Klamotten an und gingen auf Reisen.
Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(