English version English version English version
DHTML, JavaScript: Ellipse, Oval, Kreis, Polygon, Dreieck, Rechteck, Linie zeichnenHome DHTML-Bibliothek Tooltips-Script Funktionsgraph-Plotter
DHTML, JavaScript
Linie, Ellipse, Kreis, Rechteck, Polygon zeichnen.

Schnelle JavaScript Vektorgraphik Bibliothek.

Entwickler: Walter Zorn
 
DHTML, JavaScript: Ellipsen, Ovale, Kreise, Polygone, Dreiecke, Rechtecke, schräge Linien zeichnen  
Performance
 
Welche Browser?
 
Dokumentation
 
Download
 
 
 
JavaScript ist eine Programmiersprache, die eigentlich keine Grafik-Fähigkeit mitbringt. Diese JavaScript-Vektorgrafikbibliothek implementiert Funktionen für Grafik-Grundelemente wie Linien, Kreise, Ellipsen (Ovale), Polygone (auch Dreiecke, Rechtecke) und Polylinien (geknickte Linien), und kann solche Elemente dynamisch in eine Webseite zeichnen. Ziele der Entwicklung waren nebenbei auch optimierte Performance und optimal gezeichneten Pixeltreppchen (Pixeloptimierung). Die Verwendung dieser Vector-Grafik -Bibliothek ist selbst bei nicht vorhandener JavaScript-Erfahrung relativ einfach. Der Testbereich und, weiter unten auf dieser Seite die Dokumentation, machen Ihnen hoffentlich Mut zum Experimentieren.
 
Hier testen:
x1  y1  x2  y2 

x  y  w  h 

x  y  w  h 

x y
x  y  w  h 

x  y  w  h 

x  y  w  h  arc begin° arc end°
setColor("#") setStroke() setStroke(Stroke.DOTTED)
Test-Zeichenfläche
Hier noch ein Beispiel für eine animierte Vektorgrafik.
 
Und so kann man direkt auf ein Bild zeichnen, und das Bild selbst als Zeichenfläche (Canvas) benutzen (dieses Beispiel verwendet auch meine DHTML-Drag&Drop-Bibliothek).

 
 
 
Performance
DHTML, JavaScript: Ellipsen, Ovale, Kreise, Polygone, Dreiecke, Rechtecke, schräge Linien zeichnen  
Seitenanfang
 
Performance
 
Welche Browser?
 
Dokumentation
 
Download
 
 
 
In HTML selbst gibt es keine schrägen Linien, Kreise, Ellipsen oder andere nicht-rechteckig begrenzten Elemente. Als Work-around könnte man entsprechend viele kleine farbige DIV-Elemente (Layer) erzeugen und passend aneinanderreihen[1]. Da jedes DIV zwangsläufig seinen gesamten browserinternen Objekt-Overhead mitbringt, wäre es allerdings suboptimal, für jedes Pixel ein eigenes DIV zu erzeugen.
 
Diese Vektorgrafik-Bibliothek versucht nun, diesen Overhead möglichst gering zu halten. Neben schnellen Algorithmen zur Berechnung der Formen (hauptsächlich aufgebaut auf Bresenham-Algorithmen) besteht der Trick vor allem darin, jeweils möglichst viele Pixel zu einem DIV zusammenzufassen. Die Anzahl benötigter Layer sinkt[2] (bei 1 Pixel breiten bzw. geraden Linien) auf einen pro Pixeltreppchenstufe, wie in der Grafik links anhand eines Kreissegments im Maßstab 11/1 veranschaulicht, und die Performance steigt entsprechend, i.d.R. sogar überproportional. Noch größer werden die Vorteile dieses Lösungsansatzes bei gefüllten Flächen - siehe als Illustration die bunte Ellipse unterhalb dieses Abschnitts, und stellen Sie sich zum Vergleich ein Oval vor, das aus 1*1-Pixel-DIVs besteht.
 
Trotzdem: Die Performance kann nicht mit Java oder einem Stand-Alone-Programm vergleichbar sein! Layer (DIV-Elemente) zu erzeugen ist langsamer als direkt Pixel einzufärben [3]. Mit diesem JavaScript-Programm habe ich lediglich versucht, aus dieser webtechnologie-bedingten Einschränkung das Bestmögliche an Performance herauszuholen. Anhaltspunkt: Zu zeichnende Formen sollten nicht in beiden Dimensionen größer als 600 bis 1000 Pixel sein (genauer: die Summe der Pixeltreppchenstufen aller Elemente einer Grafik sollte nicht größer als 1000 sein).
 
Alternative zu SVG? Derzeit sind SVG-fähige Browser, bzw. Browser, in die ein SVG-Plugin korrekt eingebunden wurde, noch rar. Diese Vektorgraphik -Bibliothek dürfte als nicht-proprietäre Alternative für kleine oder wenig komplexe Grafikelemente in den Browsern von mehr als 95% aller Internetbesucher laufen. Außerdem kann sie an beliebigen Stellen in ein HTML-Dokument zeichnen, weil die Grafik über den Rand von "Zeichenflächen" hinausfließen darf.
JavaScript Vector Graphics Library: fillEllipse()
 
 
 
 
Welche Browser?
Linux:
Browser mit Gecko-Engine (Mozilla, Galeon, Netscape 6+), Konqueror, Opera 5, 6 und 7+.
 
Windows:
Gecko-Browser, IE 4, 5, 6, Opera 5, 6 und 7+.
 
Mac:
Safari, Gecko-Browser, Opera, teilweise IE.
 
Die Funktionalität "Beim Laden in die Seite zeichnen" ist cross-browser-tauglich. "Nachträglich in bestimmte HTML-Elemente zeichnen" hingegen funktioniert im Opera erst ab Version 7.
 
 
 
 
 
jsGraphics-Bibliothek einbinden

1. Bibliothek in die HTML-Datei einbinden
Folgenden Codeschnipsel am besten im Kopfbereich der HTML-Datei (irgendwo zwischen <head> und </head>) einfügen:

<script type="text/javascript" src="wz_jsgraphics.js">
</script>

 
2. DIV-Bereich(e) als Fläche(n) zum Zeichnen

Dieser Schritt ist nicht erforderlich, wenn beim Laden der Seite direkt in das Dokument gezeichnet werden soll. Ansonsten: Sowohl relativ (räumliche Eingliederung dort, wo im HTML-Quelltext definiert) als auch absolut positionierte DIV-Bereiche sind geeignet. Die zum Zeichnen vorgesehenen DIV-Bereiche müssen je eine eindeutige (nur einmal vergebene) ID haben:
<div id="myCanvas" style="position:relative;height:250px;width:100%;"></div>
...
<div id="anotherCanvas" style="position:relative;height:100px;width:300px;"></div>

 
3. Bibliothek speichern

Die JavaScript-Datei downloaden und entzippen. Entweder im gleichen Verzeichnis wie die HTML-Datei speichern, oder den Pfad src="wz_jsgraphics.js" im HEAD-Bereich der HTML-Datei anpassen.

 
 
 
 
 
 
Dokumentation: Verwendung der Zeichenmethoden
DHTML, JavaScript: Ellipsen, Ovale, Kreise, Polygone, Dreiecke, Rechtecke, schräge Linien zeichnen  
Seitenanfang
 
Performance
 
Welche Browser?
 
Dokumentation
 
Download
 
 
 
1. jsGraphics-Objekt erzeugen
 
a) In Layer (DIV) zeichnen:
Ist auch nach Abschluss des Ladevorgangs möglich, funktioniert aber nicht im Opera älter als Version 7. Folgendes Beispiel zeigt, wie ein jsGraphics-Objekt instanziiert werden kann. Der Code sollte irgendwo nach dem als Zeichenfläche dienenden DIV, aber noch vor dem schließenden </body>-Tag eingefügt werden. Als Parameter erwartet new jsGraphics() entweder die ID des DIVs in Anführungszeichen oder Hochkommata, oder eine direkte Referenz auf das DIV:
<script type="text/javascript">
<!--
var jg = new jsGraphics("myCanvas");
//-->
</script>


oder

<script type="text/javascript">
<!--
var cnv = document.getElementById("myCanvas");
var jg = new jsGraphics(cnv);
//-->
</script>
Falls Sie mehrere DIVs als jeweils eigenständige Zeichenflächen definieren wollen, müssen Sie für jedes ein eigenes jsGraphics-Objekt erzeugen:
<script type="text/javascript">
<!--

var jg = new jsGraphics("myCanvas");
var jg2 = new jsGraphics("anotherCanvas");

//-->
</script>

 
 
b) Beim Laden direkt in das Dokument zeichnen:
Funktioniert auch im uralten Opera 5/6. Übergeben Sie dem Konstuktor anstatt einer DIV-ID einfach nichts (oder den Wert null).

<script type="text/javascript">
<!--

var jg_doc = new jsGraphics();

//-->
</script>

Statt jg, jg2 oder jg_doc können Sie Ihre jsGraphics-Instanzen natürlich auch anders nennen, sofern die Regeln für Variablennamen eingehalten werden.
 
 
 
2. Zeichenmethoden aufrufen

Nachdem Sie nun eine Objekt-Instanz beispielsweise namens jg erzeugt haben, können Sie die Methoden jederzeit wie in folgendem funktionsfähigen Beispiel verwenden, auch nach Abschluss des Ladevorgangs (Anmerkung: Wenn die Objekt-Instanz außerhalb von Funktionen (global) deklariert wurde, bleibt sie erhalten, solange die Webseite im Browser geladen ist):

<script type="text/javascript">
<!--
function myDrawFunction()
{
  jg_doc.setColor("#00ff00"); // grün
  jg_doc.fillEllipse(100, 200, 100, 180); // Koordinaten auf document bezogen
  jg_doc.setColor("maroon");
  jg_doc.drawPolyline(new Array(50, 10, 120), new Array(10, 50, 70));
  jg_doc.paint(); // zeichnet in diesem Fall direkt in's document

  jg.setColor("#ff0000"); // rot
  jg.drawLine(10, 113, 220, 55); // Koordinaten auf Zeichenfläche bezogen
  jg.setColor("#0000ff"); // blau
  jg.fillRect(110, 120, 30, 60);
  jg.paint();

  jg2.setColor("#0000ff"); // blau
  jg2.drawEllipse(10, 50, 30, 100);
  jg2.drawRect(400, 10, 100, 50);
  jg2.paint();
}

var jg_doc = new jsGraphics(); // direkt in's document zeichnen
var jg = new jsGraphics("myCanvas");
var jg2 = new jsGraphics("anotherCanvas");

myDrawFunction();

//-->
</script>

Wie man sieht, sollte zuerst für jede Fläche eine Malfarbe gesetzt werden, andernfalls wird alles in der Standardfarbe Schwarz gezeichnet. Die Koordinaten beziehen sich im Modus "In document zeichnen" auf die linke obere Ecke des Dokuments, im Modus "In DIV zeichnen" auf die linke obere Ecke des Layers. Da die Zeichenmethoden die Grafik zunächst intern erzeugen, muss zur Ausgabe in die jeweilige Malfläche explizit die Methode paint() aufgerufen werden.
 
Name der Methode
(Bildchen selbstverständlich von der Vektorgraphik-Bibliothek in die Tabelle gezeichnet)
Codebeispiel (am Beispiel von jg)
Allgemeine Hinweise
 
1.) Zahlen, die den Funktionen übergeben werden, müssen Ganzzahlen (Integers) sein. Zeichenketten (Strings) und Nicht-Ganzzahlen (Fließkommazahlen) müssen mit den JavaScript-Standardfunktionen parseInt() bzw. Math.round() in Integers umgewandelt werden. JavaScript-Berechnungen beispielsweise haben überwiegend Fließkommazahlen als Ergebnis, Werte von Formulareingabefeldern sind immer Strings, auch wenn Zahlen eingegeben wurden. Codebeispiel:
jg.setStroke(parseInt(document.MyForm.Linewidth.value));
 
2.) Falls Sie gezeichnete Elemente sehr genau positionieren müssen/wollen: Beachten Sie, dass Koordinaten zwischen Pixeln liegen, nicht auf ihnen, und dass der "Malstift" die Pixel rechts unterhalb des durch die Koordinaten vorgegebenen Pfades färbt, auch bei Linien dicker als 1 px.
setColor("#Hexfarbwert");
 
Setzt Malfarbe für die nachfolgend aufgerufenen Zeichenmethoden, und zwar so lange, bis sie durch einen erneuten Aufruf von setColor() geändert wird. Der Farbwert muss in Anführungszeichen stehen. Mit Rücksicht auf Cross-Browser-Funktionalität sollte er hexadezimal, nach dem in HTML üblichen Schema "#rrggbb", angegeben werden. Erlaubt sind aber auch die in HTML zulässigen Farbnamen.
jg.setColor("#ff0000");
 
oder mit identischem Ergebnis
 
jg.setColor("red");
setStroke(Zahl);
 
Kann optional aufgerufen werden und setzt die Liniendicke für die nachfolgend aufgerufenen Zeichenmethoden, und zwar so lange, bis sie durch einen erneuten Aufruf von setStroke() geändert wird. Voreingestellte Dicke, solange .setStroke() nicht aufgerufen wurde, ist 1 px.
 
Um eine gepunktete Linie (gültig auch für Umrandungen von Ellipsen, Polygonen etc.) zu erzeugen, können Sie setStroke() als Parameter die Konstante Stroke.DOTTED übergeben. Die Liniendicke wird automatisch auf 1 Pixel gesetzt, andere Dicken sind nicht möglich.
jg.setStroke(3);
 
oder
 
jg.setStroke(Stroke.DOTTED)
drawLine(X1, Y1, X2, Y2);
1 Pixel breite Linie (Gerade) von Anfangs- zu Endkoordinaten. Um die Linienstärke zu ändern, kann zuvor die Methode .setStroke(Zahl) aufgerufen werden. Diese Einstellung bleibt für alle nachfolgend aufgerufenen Linienmethoden erhalten, bis .setStroke() erneut aufgerufen wird.
jg.drawLine(0, 11, 40, 0);
drawPolyline(X-Werte Anfang/Knicke/Ende, Y-Werte);
(Mehrfach) geknickte Linie, beginnend beim ersten X- und Y-Wert. X- und Y-Werte sind Arrays. Sie können entweder direkt im Methodenaufruf definiert, oder vorher nach folgendem Schema angelegt werden:
var xWerte = new Array(x1,x2,x3,x4,x5);
var yWerte = new Array(y1,y2,y3,y4,y5);

 
Liniendicke entweder, wie per .setStroke() eingestellt, oder 1px.
jg.drawPolyline(new Array(10,85,93,60), new Array(50,10,105,87));
 
oder alternativ
 
var xWerte = new Array(10,85,93,60);
var yWerte = new Array(50,10,105,87);
jg.drawPolyline(xWerte,yWerte);
drawRect(X,Y,Breite,Höhe);
Rechteck, nicht gefüllt, aus 1 px dicken Linien. Koordinaten beziehen sich auf die linke obere Ecke. Die Liniendicke kann mit .setStroke(Dicke) geändert werden.
jg.drawRect(0, 0, 40, 11);
fillRect(X,Y,Breite,Höhe);
Gefülltes Rechteck. Koordinaten beziehen sich auf linke obere Ecke.
jg.fillRect(0, 0, 40, 11);
drawPolygon(X-Werte Ecken, zugehörige Y-Werte);
Vieleck. X- und Y-Werte sind Arrays. Sie können entweder direkt im Methodenaufruf definiert, oder vorher nach folgendem Schema angelegt werden:
var xWerte = new Array(x1,x2,x3,x4,x5);
var yWerte = new Array(y1,y2,y3,y4,y5);

Falls das letzte X-/Y-Wertepaar nicht identisch mit dem ersten ist, schließt das Programm von sich aus das Polygon, indem es eine Linie vom letzten zum ersten Koordinatenpaar zieht.
 
Liniendicke entweder, wie per .setStroke() eingestellt, oder 1px.
jg.drawPolygon(new Array(10,85,93,60), new Array(50,10,105,87));
 
oder alternativ
 
var xWerte = new Array(10,85,93,60);
var yWerte = new Array(50,10,105,87);
jg.drawPolygon(xWerte,yWerte);

Statt "xWerte" bzw. "yWerte" können Sie natürlich andere Variablennamen verwenden.
fillPolygon(X-Werte Ecken, zugehörige Y-Werte);
Gefülltes Polygon. Parameter analog zu drawPolygon()
jg.fillPolygon(new Array(10,85,93,60), new Array(50,10,105,87));
drawEllipse(X,Y,Breite,Höhe);
Ellipse. Liniendicke entweder, wie per .setStroke() eingestellt, oder 1px. Koordinaten beziehen sich auf das virtuelle Rechteck, das die Ellipse (genauer: den Pfad, dem der Malstift folgt) umfasst.
jg.drawEllipse(0, 0, 40, 12);
oder
jg.drawOval(0, 0, 40, 12);
fillEllipse(X, Y, Breite, Höhe);
Gefüllte Ellipse. Koordinaten beziehen sich auf das virtuelle Rechteck, das die Ellipse exakt umfasst.
jg.fillEllipse(0, 0, 41, 13);
oder
jg.fillOval(0, 0, 41, 13);
fillArc(X, Y, width, height, Startwinkel, Endwinkel);
Füllt ein Ellipsen-Segment. Die Werte für Start- und Endwinkel dürfen hier ausnahmsweise auch Dezimalpunkt-Zahlen sein. Wie bei den anderen ...Ellipse()-Funktionen geben X und Y nicht den Mittelpunkt, sondern die linke obere Ecke des umfassenden Recktecks an.
jg.fillArc(20,20,41,12,270.0,220.0);
drawString("Text", X, Y);
Text an definierte Position schreiben. Die Koordinaten X und Y beziehen sich auch hier, anders als bei Java, auf die linke obere Ecke der (ersten) Textzeile. Der Text muss in Anführungszeichen gesetzt werden. Enthaltene HTML-Tags werden interpretiert. Ein (nicht maskiertes) <br> würde also tatsächlich einen Zeilenumbruch bewirken.
 
setFont("Schiftfamilie", "Größe+Einheit", Stil);
 
Damit können Sie zuvor auch die Schriftart und -Größe setzen oder ändern. Schriftfamilie und Größenangabe in Anführungszeichen.
 
Mögliche Stilangaben:
Font.PLAIN für normale Schrift
Font.BOLD für fette Schrift
Font.ITALIC für Kursivschrift
Font.ITALIC_BOLD oder Font.BOLD_ITALIC, um letztere zu kombinieren
jg.setFont("arial","15px",Font.BOLD);
jg.drawString("Geschwalle",20,50);
drawStringRect("Text", X, Y, Breite, Ausrichtung);
Wie drawString. Zusätzlich können die Breite des Text-"Containers" und die Textausrichtung innerhalb dieses Rechtecks festgelegt werden. Textausrichungswert muss ein String sein (d.h. in Anführungszeichen oder Apostrophe eingeschlossen sein) und kann entweder "left", "center", "right" or "justify" sein.
jg.setFont("verdana","11px",Font.BOLD);
jg.drawStringRect("Text",20,50,300,"right");
drawImage("Pfad", X, Y, Breite, Höhe);
Bild exakt an definierter Position in angegebener Größe darstellen.
 
"Pfad"-Angabe wie in HTML. Die Parameter Breite und Höhe sind optional (können auch 0 oder null sein oder weggelassen werden, das Bild wird dann in seiner Normalgröße dargestellt), erlauben aber nahezu beliebig verzerrte Darstellung.
 
Optional kann als fünfter Parameter ein Eventhandler definiert werden, der dann automatisch in das erzeugte <img>-Tag eingefügt wird. Beispiel: jg.drawImage('anImg.jpg',8,5,95,70,'onmouseover="YourFunc()"');
jg.drawImage("DerTutNix.jpg", 20,50,100,150);
paint();
 
Die mit den obigen Methoden zunächst nur intern erzeugte Grafik wird ausgegeben. Für optimale Performance empfiehlt es sich, paint() nicht unnötig oft (in unnötig kleinen Intervallen zwischen den einzelnen Zeichenmethoden) aufzurufen, sondern erst zum Abschluss der internen Grafikerzeugung.
 
Vermeiden Sie also
jg.drawEllipse(0, 0, 100, 100);
jg.paint();
jg.drawLine(200, 10, 400, 40);
jg.paint();
...

 
sondern schreiben Sie besser
jg.drawEllipse(0, 0, 100, 100);
jg.drawLine(200, 10, 400, 40);
/* ...weitere Zeichenmethoden... */
jg.paint();
jg.paint();
clear();
 
Alle vom jsGraphics-JavaScript gezeichneten Inhalte der betreffenden Malfläche werden gelöscht. Der ursprüngliche Inhalt bleibt aber erhalten, also Text oder Bilder innerhalb des <div>-Elements, die im HTML-Quelltext definiert waren.
jg.clear();
 
Alle script-generierten Inhalte in "myCanvas" werden gelöscht.
setPrintable(true);
 
Normalerweise werden die gezeichneten Elemente beim Drucken nicht sichtbar, weil die Browser unter den Standard-Druckereinstellungen keine Hintergrundfarben mitdrucken. Mit setPrintable() und dem Parameter true werden die nachfolgend gezeichneten Elemente drucker-wiedergabefähig (zumindest im Mozilla/Netscape 6+ und IE). Allerdings auf Kosten der Darstellungsgeschwindigkeit auf dem Bildschirm, die je nach Browser um 10% bis 25% langsamer wird.
jg.setPrintable(false);
 
Setzt die Zeichenmethoden auf "nicht-druckerfähig" zurück.
 
 
 
 
 
 
Download
DHTML, JavaScript: Ellipsen, Ovale, Kreise, Polygone, Dreiecke, Rechtecke, schräge Linien zeichnen  
Seitenanfang
 
Performance
 
Welche Browser?
 
Dokumentation
 
Download
 
 
 
wz_jsgraphics.js 3.05, Lizenz LGPL:
wz_jsgraphics.zip (7 KB)
 
Geschichte der Updates (unbedingt lesen, jedenfalls wenn Sie eine frühere Version verwenden und wissen wollen, ob sich ein Update lohnt).
 
 

 
 
 
 
Fußnoten
[1]
Eine Lösung mit farbigen 1x1-Pixel-Bildchen würde die Farbauswahl einschränken, es sei denn, beim Seitenaufruf würden 16777216 verschiedenfarbige Bildchen (656 MB Datenvolumen) für 24 Bit Farbauswahl mitgeladen, oder die Bildchen lägen wenigstens auf dem Server bereit, oder das Script selbst würde sich jedesmal, wenn eine Malfarbe definiert wird, ein PNG schreiben...
Zurück
 
[2]
Unter der Annahme, dass Winkel- und Längenverteilung der Linien gleichmäßig sind, gilt für 1 px breite Linien:
Die Lösung "Pro Pixel ein Layer" erfordert im Durchschnitt sin(45°) / (1 - sin(45°)) = 2.41 mal mehr Layer als die Lösung "Pro Pixeltreppchenstufe ein Layer". Dies gilt unter der Voraussetzung, dass sich in beiden Fällen die Pixeltreppchenstufen Ecke an Ecke berühren. Dann bleibt die Zahl einzufärbender Pixel minimal, und damit auch die Zahl der Layer, die von der "Pro Pixel ein Layer"-Lösung erzeugt werden muss; andernfalls wäre ihr Performance-Nachteil noch größer.
Zurück
 
[3]
Ein wirklich leichtgewichtiges <pixel color="#ff9900" left="127" top="63">-Tag wäre nett.
Zurück

Walter Zorn, München
Impressum und über diese Seite