Hallo,
ich habe Probleme mit dem Erstellen eines Textpfades mit Batik.
Die Forensuche nach textPath ergab keine Treffer, deswegen erstelle ich ein neues Thema.
Ich würde mich definitiv als Java-Neuling bezeichnen, deswegen entschuldigt bitte Anfänger-Fehler und -Fragen . Mit dem ganzen folgenden Post, SVG und Batik hätte ich vor einer Woche noch überhaupt nichts anfangen können.
Nun zur Sache:
Bei Beginn der Entwicklung meines Programms habe ich mich entschieden, die Grafik mit dem SVGGenerator zu erzeugen und nicht mit der DOM API. Die Grafik soll eine Art Kreisdiagramm sein. Wichtig an dieser Stelle ist, dass ich Teilabschnitte kreisförmig beschriften möchte.
Zuerst habe ich mich mit SVG beschäftigt und manuell folgendes erstellt:
[XML]
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="20cm" height="20cm" viewBox="0 0 2001 2001"
xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>test title</title>
<desc>test desc</desc>
<!-- Quadratische Umrandung -->
<rect x="1" y="1" width="2000" height="2000"
fill="lightgrey" stroke="black" stroke-width="1" />
<!-- Kreis -->
<circle cx="1000" cy="1000" r="1000"
fill="rgb(5,90,141)"/>
<!-- Pfade für Texte -->
<path id="Beschriftung1" fill="none" stroke="red" stroke-width="10"
d="M 1000,0 A 1000,1000 0 0,1 1642.7876096865393263226434099073,233.95555688102196479760734944458" />
<path id="Beschriftung2" fill="none" stroke="yellow" stroke-width="10"
d="M 1642.7876096865393263226434099073,233.95555688102196479760734944458 A 1000,1000 0 0,1 1866.0254037844386467637231707529,1500" />
<path id="Beschriftung3" fill="none" stroke="red" stroke-width="10"
d="M 1342.0201433256687330440996146823,1939.6926207859083840541092773247 A 1000,1000 0 0,0 1866.0254037844386467637231707529,1500" />
<path id="Beschriftung4" fill="none" stroke="yellow" stroke-width="10"
d="M 357.21239031346067367735659009274,1766.0444431189780352023926505554 A 1000,1000 0 0,0 1342.0201433256687330440996146823,1939.6926207859083840541092773247" />
<path id="Beschriftung5" fill="none" stroke="red" stroke-width="10"
d="M 15.192246987791940633256975410477,826.35182233306965114828337323069 A 1000,1000 0 0,0 357.21239031346067367735659009274,1766.0444431189780352023926505554" />
<path id="Beschriftung6" fill="none" stroke="yellow" stroke-width="10"
d="M 15.192246987791940633256975410477,826.35182233306965114828337323069 A 1000,1000 0 0,1 1000,0" />
<!-- Textpfade -->
<text font-family="Verdana" font-size="50" fill="white" text-anchor="middle" >
<textPath xlink:href="#Beschriftung1" startOffset="50%">
<tspan dy="60" >Beschriftung1</tspan>
</textPath>
<textPath xlink:href="#Beschriftung2" startOffset="50%">
<tspan dy="0" >Beschriftung2</tspan> <!-- warum dy="0" ? -->
</textPath>
<textPath xlink:href="#Beschriftung3" startOffset="50%">
<tspan dy="-90" >Beschriftung3</tspan>
</textPath>
<textPath xlink:href="#Beschriftung4" startOffset="50%">
<tspan dy="0" >Beschriftung4</tspan> <!-- warum dy="0" ? -->
</textPath>
<textPath xlink:href="#Beschriftung5" startOffset="50%">
<tspan dy="0" >Beschriftung5</tspan> <!-- warum dy="0" ? -->
</textPath>
<textPath xlink:href="#Beschriftung6" startOffset="50%">
<tspan dy="90" >Beschriftung6</tspan> <!-- warum dy="90" statt 60? -->
</textPath>
</text>
</svg>
[/XML]
Für die Erstellung der Pfade mit den Ellipsen-Befehlen (w3c Beschreibung) habe ich mich entschieden, da ich die Winkel zwischen den Linien kenne, welche quasi vom Kreismittelpunkt zum Rand verlaufen und "Tortenstücke" bilden. Zwischen den Endpunkten dieser Linien sollen die Pfade verlaufen. Die Pfade anhand einer Bézier-Kurve zu erstellen schien mir zu umständlich. Im obigen Fall habe ich die Endpunkte mit einem Hilfsdreieck und den guten alten sin(Winkel) = Gegenkathete/Hypotenuse etc. Sätzen errechnet. Je nach Viertel des Kreises ist die Berechnung ein bisschen anders und large-arc-flag und sweep-flag müssen unterschiedlich gesetzt sein. Später soll die Errechnung im Programm dynamisch erfolgen.
Nachdem ich Kreise und andere Elemente bereits mit dem SVGGenerator erzeugt hatte, habe ich dann nach Grafikelementen von Java gesucht, die mir bei der Darstellung der Pfade helfen und bin auf Path2D.Float gekommen. Hier fand ich jedoch nur die curveTo()-Methode, welche eine Bézier-Kurve erzeugt.
Da ich schnell zu einem vorzeitigen Ergebnis kommen wollte und wusste, wie man die Darstellung in SVG erzeugt, habe ich doch zur DOM API gegriffen und wollte erstmal beide Methoden mixen.
Die Erstellung des Pfades, der für den Textpfad benötigt wird, hat auch (fast - der Pfad ist zu lang, etwas muss bei der Berechnung noch nicht stimmen) wunderbar geklappt:
Aber dann ging es mit den Schwierigkeiten los. Hier versuche ich, den Textpfad zu erstellen:
Der Text wird jedoch nicht angezeigt.
Das Erstellen und Hinzufügen der Nodes müsste richtig sein, zumindest habe ich einige Beispiele im Internet (nicht auf der Batik-Webseite, die ist meiner Meinung nach nicht sehr umfangreich) gefunden, bei denen es so gemacht wird. Wahrscheinlich ist hier schlicht das setzen des Textes falsch.
Hier also meine erste Frage: Wie setze ich den Text, der zwischen XML-Tags sitzt?
Damit aber nicht genug. Der Mix aus der Nutzung des SVGGenerators und der DOM API führt mich zu einem weiteren Problem:
Bei der Anzeige auf einem JSVGCanvas wird der Pfad korrekt dargestellt, beim Export in ein SVG-Dokument jedoch nicht. Als Quelle des Fehlers erscheint mir folgender Befehl:
Diesen nutze ich nur beim Darstellen der Grafik auf dem Canvas-Objekt.
Ohne diesen Befehl wird die Grafik nicht auf dem Canvas-Objekt dargestellt. Beim Erzeugen des Dokuments ist es genau andersrum.
Falls es relevant ist: So stelle ich die Grafik auf dem Canvas dar:
Und so erzeuge ich das Dokument:
Damit lautet meine zweite Frage entweder: Wie sorge ich dafür, dass mit der Benutzung des SVGGenerators und der DOM API quasi an EINER Grafik gearbeitet wird?
oder: Wie vermeide ich die Nutzung der DOM API? / Mit welchem Objekt kann ich SVG Textpfade darstellen?
Ich habe mir schon Arc2D angesehen. Kann man mit getPathIterator() einen Pfad erzeugen? Wie kriege ich dann den Text auf diesen Pfad? Oder soll ich komplett mit der DOM API arbeiten?
Vielen Dank im Voraus!
Gruß,
Phil
ich habe Probleme mit dem Erstellen eines Textpfades mit Batik.
Die Forensuche nach textPath ergab keine Treffer, deswegen erstelle ich ein neues Thema.
Ich würde mich definitiv als Java-Neuling bezeichnen, deswegen entschuldigt bitte Anfänger-Fehler und -Fragen . Mit dem ganzen folgenden Post, SVG und Batik hätte ich vor einer Woche noch überhaupt nichts anfangen können.
Nun zur Sache:
Bei Beginn der Entwicklung meines Programms habe ich mich entschieden, die Grafik mit dem SVGGenerator zu erzeugen und nicht mit der DOM API. Die Grafik soll eine Art Kreisdiagramm sein. Wichtig an dieser Stelle ist, dass ich Teilabschnitte kreisförmig beschriften möchte.
Zuerst habe ich mich mit SVG beschäftigt und manuell folgendes erstellt:
[XML]
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="20cm" height="20cm" viewBox="0 0 2001 2001"
xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>test title</title>
<desc>test desc</desc>
<!-- Quadratische Umrandung -->
<rect x="1" y="1" width="2000" height="2000"
fill="lightgrey" stroke="black" stroke-width="1" />
<!-- Kreis -->
<circle cx="1000" cy="1000" r="1000"
fill="rgb(5,90,141)"/>
<!-- Pfade für Texte -->
<path id="Beschriftung1" fill="none" stroke="red" stroke-width="10"
d="M 1000,0 A 1000,1000 0 0,1 1642.7876096865393263226434099073,233.95555688102196479760734944458" />
<path id="Beschriftung2" fill="none" stroke="yellow" stroke-width="10"
d="M 1642.7876096865393263226434099073,233.95555688102196479760734944458 A 1000,1000 0 0,1 1866.0254037844386467637231707529,1500" />
<path id="Beschriftung3" fill="none" stroke="red" stroke-width="10"
d="M 1342.0201433256687330440996146823,1939.6926207859083840541092773247 A 1000,1000 0 0,0 1866.0254037844386467637231707529,1500" />
<path id="Beschriftung4" fill="none" stroke="yellow" stroke-width="10"
d="M 357.21239031346067367735659009274,1766.0444431189780352023926505554 A 1000,1000 0 0,0 1342.0201433256687330440996146823,1939.6926207859083840541092773247" />
<path id="Beschriftung5" fill="none" stroke="red" stroke-width="10"
d="M 15.192246987791940633256975410477,826.35182233306965114828337323069 A 1000,1000 0 0,0 357.21239031346067367735659009274,1766.0444431189780352023926505554" />
<path id="Beschriftung6" fill="none" stroke="yellow" stroke-width="10"
d="M 15.192246987791940633256975410477,826.35182233306965114828337323069 A 1000,1000 0 0,1 1000,0" />
<!-- Textpfade -->
<text font-family="Verdana" font-size="50" fill="white" text-anchor="middle" >
<textPath xlink:href="#Beschriftung1" startOffset="50%">
<tspan dy="60" >Beschriftung1</tspan>
</textPath>
<textPath xlink:href="#Beschriftung2" startOffset="50%">
<tspan dy="0" >Beschriftung2</tspan> <!-- warum dy="0" ? -->
</textPath>
<textPath xlink:href="#Beschriftung3" startOffset="50%">
<tspan dy="-90" >Beschriftung3</tspan>
</textPath>
<textPath xlink:href="#Beschriftung4" startOffset="50%">
<tspan dy="0" >Beschriftung4</tspan> <!-- warum dy="0" ? -->
</textPath>
<textPath xlink:href="#Beschriftung5" startOffset="50%">
<tspan dy="0" >Beschriftung5</tspan> <!-- warum dy="0" ? -->
</textPath>
<textPath xlink:href="#Beschriftung6" startOffset="50%">
<tspan dy="90" >Beschriftung6</tspan> <!-- warum dy="90" statt 60? -->
</textPath>
</text>
</svg>
[/XML]
Für die Erstellung der Pfade mit den Ellipsen-Befehlen (w3c Beschreibung) habe ich mich entschieden, da ich die Winkel zwischen den Linien kenne, welche quasi vom Kreismittelpunkt zum Rand verlaufen und "Tortenstücke" bilden. Zwischen den Endpunkten dieser Linien sollen die Pfade verlaufen. Die Pfade anhand einer Bézier-Kurve zu erstellen schien mir zu umständlich. Im obigen Fall habe ich die Endpunkte mit einem Hilfsdreieck und den guten alten sin(Winkel) = Gegenkathete/Hypotenuse etc. Sätzen errechnet. Je nach Viertel des Kreises ist die Berechnung ein bisschen anders und large-arc-flag und sweep-flag müssen unterschiedlich gesetzt sein. Später soll die Errechnung im Programm dynamisch erfolgen.
Nachdem ich Kreise und andere Elemente bereits mit dem SVGGenerator erzeugt hatte, habe ich dann nach Grafikelementen von Java gesucht, die mir bei der Darstellung der Pfade helfen und bin auf Path2D.Float gekommen. Hier fand ich jedoch nur die curveTo()-Methode, welche eine Bézier-Kurve erzeugt.
Da ich schnell zu einem vorzeitigen Ergebnis kommen wollte und wusste, wie man die Darstellung in SVG erzeugt, habe ich doch zur DOM API gegriffen und wollte erstmal beide Methoden mixen.
Die Erstellung des Pfades, der für den Textpfad benötigt wird, hat auch (fast - der Pfad ist zu lang, etwas muss bei der Berechnung noch nicht stimmen) wunderbar geklappt:
Java:
String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
Element svgRoot = document.getDocumentElement();
Element path = document.createElementNS(svgNS, "path");
path.setAttribute("id", "Gruppe1");
path.setAttribute("stroke", "yellow");
path.setAttribute("stroke-width", "10");
/*
x = 250 + (cos(50°) * 250) = 1642,7876096865393263226434099073
y = 250 - (sin(50°) * 250) = 233,95555688102196479760734944458
Textpath Verschiebung: 60
*/
path.setAttribute("d", "M 250,0 A 250,250 0 0,1 " + String.valueOf(250+Math.cos(50)*250) + "," + String.valueOf(250-Math.sin(50)*250));
svgRoot.appendChild(path);
Java:
/*
<text font-family="Verdana" font-size="50" fill="white" text-anchor="middle" >
<textPath xlink:href="#Beschriftung1" startOffset="50%">
<tspan dy="60" >Beschriftung1</tspan>
</textPath>
</text>
*/
Element tspan = document.createElementNS(svgNS, "tspan");
tspan.setAttribute("dy", "60");
tspan.setNodeValue("Beschriftung1");
Element textPath = document.createElementNS(svgNS, "textPath");
textPath.setAttribute("xlink:href", "#Beschriftung1");
textPath.setAttribute("startOffset", "50%");
System.out.println(textPath.getNodeValue()); //test
System.out.println(textPath.getTextContent()); //test
textPath.setNodeValue("Beschriftung1"); // wie setze ich den Text?
textPath.setTextContent("Beschriftung1"); // wie setze ich den Text?
textPath.appendChild(tspan);
Element text = document.createElementNS(svgNS, "path");
text.setAttribute("font-size", "50");
text.setAttribute("fill", "black");
text.setAttribute("text-anchor", "middle");
text.appendChild(textPath);
svgRoot.appendChild(text);
Das Erstellen und Hinzufügen der Nodes müsste richtig sein, zumindest habe ich einige Beispiele im Internet (nicht auf der Batik-Webseite, die ist meiner Meinung nach nicht sehr umfangreich) gefunden, bei denen es so gemacht wird. Wahrscheinlich ist hier schlicht das setzen des Textes falsch.
Hier also meine erste Frage: Wie setze ich den Text, der zwischen XML-Tags sitzt?
Damit aber nicht genug. Der Mix aus der Nutzung des SVGGenerators und der DOM API führt mich zu einem weiteren Problem:
Bei der Anzeige auf einem JSVGCanvas wird der Pfad korrekt dargestellt, beim Export in ein SVG-Dokument jedoch nicht. Als Quelle des Fehlers erscheint mir folgender Befehl:
Java:
svgGenerator.getRoot(document.getDocumentElement());
Ohne diesen Befehl wird die Grafik nicht auf dem Canvas-Objekt dargestellt. Beim Erzeugen des Dokuments ist es genau andersrum.
Falls es relevant ist: So stelle ich die Grafik auf dem Canvas dar:
Java:
svgGenerator.getRoot(document.getDocumentElement()); // wird für das Anzeigen benötigt
canvas.setSVGDocument(document);
Java:
//svgGenerator.getRoot(document.getDocumentElement()); // würde dazu führen, dass der folgende Stream nicht funktioniert
svgGenerator.stream(file.getAbsolutePath() + ".svg"); // Schreibt die SVG-Datei
Damit lautet meine zweite Frage entweder: Wie sorge ich dafür, dass mit der Benutzung des SVGGenerators und der DOM API quasi an EINER Grafik gearbeitet wird?
oder: Wie vermeide ich die Nutzung der DOM API? / Mit welchem Objekt kann ich SVG Textpfade darstellen?
Ich habe mir schon Arc2D angesehen. Kann man mit getPathIterator() einen Pfad erzeugen? Wie kriege ich dann den Text auf diesen Pfad? Oder soll ich komplett mit der DOM API arbeiten?
Vielen Dank im Voraus!
Gruß,
Phil
Zuletzt bearbeitet: