Robert B.: Frage zu Kreisdiagrammen im Wiki-Artikel „Balken-_und_Kreisdiagramme“

problematische Seite

Hallo Forum,

in o.g. genannten Abschnitt des Artikels ist ein Beispiel für ein Kreisdiagramm gegeben, das mir nicht einleuchtet:

<svg class="chart" width="420" height="150" aria-labelledby="chartinfo" >
  <desc id="chartinfo">Ein Diagramm unserer Ernte</desc>
  <defs>
  </defs>

<svg class="pie" width="200" height="200" viewBox="-100 -100 200 200" style="transform: rotate(-0.25turn)">     

  <circle id="background" r="50" />

  <g class="slice" tabindex="0">
    <path d="M 1 0 A 1 1 0 0 1 0.8 0.59 L 0 0 Z" />
    <text x="45" y="9.5">4 apples</text>
  </g>
</svg>
</svg>

Da ist erst einmal ein svg in einem svg – was soll das denn?

Weiterhin:

  1. Wenn ich das richtig sehe, muss ich die Koordinaten für den Kreisbogen/die weiteren Tortenstücke aus den Anteilen (prozentual zur Basis 360° bzw. 2π) berechnen.
  2. Die Vorschau des Kreisdiagramm-Beispiels „existiert nicht“.

Viele Grüße
Robert

akzeptierte Antworten

  1. problematische Seite

    Servus!

    Hallo Forum,

    in o.g. genannten Abschnitt des Artikels ist ein Beispiel für ein Kreisdiagramm gegeben, das mir nicht einleuchtet:

    <svg class="chart" width="420" height="150" aria-labelledby="chartinfo" >
      <desc id="chartinfo">Ein Diagramm unserer Ernte</desc>
      <defs>
      </defs>
    
    <svg class="pie" width="200" height="200" viewBox="-100 -100 200 200" style="transform: rotate(-0.25turn)">     
    
      <circle id="background" r="50" />
    
      <g class="slice" tabindex="0">
        <path d="M 1 0 A 1 1 0 0 1 0.8 0.59 L 0 0 Z" />
        <text x="45" y="9.5">4 apples</text>
      </g>
    </svg>
    </svg>
    

    Da ist erst einmal ein svg in einem svg – was soll das denn?

    Weiterhin:

    1. Wenn ich das richtig sehe, muss ich die Koordinaten für den Kreisbogen/die weiteren Tortenstücke aus den Anteilen (prozentual zur Basis 360° bzw. 2π) berechnen.
    2. Die Vorschau des Kreisdiagramm-Beispiels „existiert nicht“.

    Ja, das ist leider steckengeblieben.

    Da wollte ich mal einen kompletten Diagramm-Generator bauen, bei dem man dann das fertig generierte SVG als Grafik oder als eigene Datei (siehe deinen Osterei-Generator) ausgeben kann.

    Ich hoffe, dass ich Weihnachten dazu komme. :-(

    Herzliche Grüße

    Matthias Scharwies

    1. problematische Seite

      Moin Matthias,

      Ja, das ist leider steckengeblieben.

      ich bin ja nicht ohne eine Idee über die Seite gestolpert … 😉 Mir würde es fürs erste Verständnis reichen, wenn ich Antworten auf die folgenden Frage finde:

      Da ist erst einmal ein svg in einem svg – was soll das denn?

      Weiterhin:

      1. Wenn ich das richtig sehe, muss ich die Koordinaten für den Kreisbogen/die weiteren Tortenstücke aus den Anteilen (prozentual zur Basis 360° bzw. 2π) berechnen.

      Daraus ergäben sich Teile meiner Idee, die dann hierher zurückfließen könnten:

      Da wollte ich mal einen kompletten Diagramm-Generator bauen, bei dem man dann das fertig generierte SVG als Grafik oder als eigene Datei (siehe deinen Osterei-Generator) ausgeben kann.

      Viele Grüße
      Robert

      1. problematische Seite

        Servus!

        Moin Matthias,

        Ja, das ist leider steckengeblieben.

        ich bin ja nicht ohne eine Idee über die Seite gestolpert … 😉 Mir würde es fürs erste Verständnis reichen, wenn ich Antworten auf die folgenden Frage finde:

        Da ist erst einmal ein svg in einem svg – was soll das denn?

        Weiterhin:

        Das war mein Versuch, den Kreis, der skaliert werden muss, mit einer viewbox passend zu skalieren. Bei g geht das nicht.

        Irgendwie muss man sowohl den path mit dem Segment und dann den text (class="slice" ist blöd; besser wäre wohl label?) in das Diagramm kriegen.

        1. Wenn ich das richtig sehe, muss ich die Koordinaten für den Kreisbogen/die weiteren Tortenstücke aus den Anteilen (prozentual zur Basis 360° bzw. 2π) berechnen.

        Ja, genau! Und da war für mich die Frage,

        1. wie ich den Bogen berechne (meine Idee Umfang des Kreises berechnen, dort dann den Prozentwert des Anteils dazu und dann den Endpunkt des Bogens draufsetzen.

        2. ob ich alle Kreissegmente oben zeichne und dann entsprechend der bisherigen Anteile rotiere

        Daraus ergäben sich Teile meiner Idee, die dann hierher zurückfließen könnten:

        Da wollte ich mal einen kompletten Diagramm-Generator bauen, bei dem man dann das fertig generierte SVG als Grafik oder als eigene Datei (siehe deinen Osterei-Generator) ausgeben kann.

        vielen Dank im Voraus!!!

        Herzliche Grüße

        Matthias Scharwies

        --

        --
        Jemand interessiert? Ein Freund von uns will zum Forumstreffen, und hat bereits Hotelübernachtungen gebucht.
        Er hat vergessen, dass er im gleichen Zeitraum auch heiratet.
        Also für Interessierte: Du könntest am 25. November um 14 Uhr im Rathaus von Hannover heiraten.
        Ihr Name ist Sandra.
        1. problematische Seite

          Hallo Matthias,

          da steckt einiges an Hirnschmalz drin.

          Ein konischer Gradient ist am allereinfachsten und braucht vor allem überhaupt kein SVG, hat aber zwei Nachteile:

          • Keine Randlinie, die man je Slice unterschiedlich färben kann
          • Chrome und Firefox antialiasen nicht, d.h. die Übergänge sind auf einem non-retina Display stufig.

          Das Thema Randlinie kann man beheben, indem man das Diagramm zweimal übereinander zeichnet. Einmal mit der Farbe für die Randlinien, darüber dann, etwas kleiner, die Farbe für die Füllflächen.

          Die dasharray-Idee ist ebenfalls clever, aber mathematisch obskur. Man braucht den Radius des Kreises und muss daraus die Länge des Umfangs berechnen. Dann muss man die Pie-Größen darauf umrechnen und kennt nun die Längen für den sichtbaren Strichanteil. Die unsichtbare Strichlänge kann man einfach auf den Umfang setzen. Hier erhebt das Wiki den gleichen Einwand wie bei conic-gradient: Keine individuellen Randfarben möglich. Lösung wie dort: zwei Pies übereinander. Die Platzierung der Slices würde ich mit dashoffset machen, das ist am einfachsten.

          Malt man die Pies explizit mit path d="A...", hat man aber, was die Randfarben angeht, das gleiche Problem. Ein Stroke umrundet nämlich die ganze Slice, nicht nur den Außenrand. Entweder muss man mit dasharray nachhelfen, oder man zeichnet die Randlinie separat. Das ist also auch kein "it just works". Bei Arcs kommt hinzu, dass man die Koordinaten berechnen muss. Zumindest die des Arc-Endpunkts. Und man muss aufpassen, ob das Slice mehr als 50% des Pie einnimmt, weil man dann nämlich das large-arc Flag im A Befehl setzen muss. Um den Arc richtig zu positionieren, sollte man das tun, was Du überlegt hast: um den benötigten Winkel rotieren. Was bei Pies blöd ist: Man kann das d-Attribut nicht per CSS zusammenrechnen. Man kann es zwar im CSS festlegen, aber var() wird darin nicht verstanden. Man muss also per JS die jeweils benötigte d-Eigenschaft komplett zusammenstoppeln.

          Ich stell noch was in meinen User-Space im Wiki

          Rolf

          --
          sumpsi - posui - obstruxi
        2. problematische Seite

          Moin Matthias,

          1. Wenn ich das richtig sehe, muss ich die Koordinaten für den Kreisbogen/die weiteren Tortenstücke aus den Anteilen (prozentual zur Basis 360° bzw. 2π) berechnen.

          Ja, genau! Und da war für mich die Frage,

          1. wie ich den Bogen berechne (meine Idee Umfang des Kreises berechnen, dort dann den Prozentwert des Anteils dazu und dann den Endpunkt des Bogens draufsetzen.
          2. ob ich alle Kreissegmente oben zeichne und dann entsprechend der bisherigen Anteile rotiere

          Also nach meiner kurzen Feierabend-Spielerei (und -Geometrie) ist es gar nicht so kompliziert:

          • Koordinatenursprung in der Mitte des umrandenden circle definieren (entsprechende viewBox mit negativen x- und y-Koordinaten nötig).
          • Tortenstück als Pfad vom Ursprung ausgehend nach oben und dann den Kreisbogen entsprechend des Winkels entlang; Pfad schließen.
          • Tortenstücke entsprechend des summierten Winkels der Vorgänger rotieren.

          Das habe ich in https://www.robertbienert.de/self/torte.html einmal ausprobiert es macht fürs Erste einen guten Eindruck. Mit einer Beispieleingabe wie

          #39f .5
          #93f .3
          #f39 .25
          #f93 1
          #3f9 .4
          #9f3 .5
          

          kann man auch gleich einmal hübsche Farbpaletten ausprobieren.

          Neben dem Hinweis von @Rolf B mit dem large-arc sweep für Winkel > 180° habe ich auch eine Sonderbehandlung für Winkel = 180° enthalten, weil das ein einfacher Halbkreis ist, für den ich kein Dreieck der rechten Ecke berechnen könnte.

          Ich denke, dass wir darauf aufbauen können 😀

          Knifflig wird es noch beim Beschriften der Tortenstücke, weil die Beschriftung ja nicht mit-rotiert werden sollte.

          Viele Grüße
          Robert

    2. problematische Seite

      Moin Matthias,

      nachdem ich vergeblich versucht habe den Beispielcode funktionsfähig zu bekommen,

      <svg class="chart" width="420" height="150" aria-labelledby="chartinfo" >
        <desc id="chartinfo">Ein Diagramm unserer Ernte</desc>
        <defs>
        </defs>
      
      <svg class="pie" width="200" height="200" viewBox="-100 -100 200 200" style="transform: rotate(-0.25turn)">     
      
        <circle id="background" r="50" />
      
        <g class="slice" tabindex="0">
          <path d="M 1 0 A 1 1 0 0 1 0.8 0.59 L 0 0 Z" />
          <text x="45" y="9.5">4 apples</text>
        </g>
      </svg>
      </svg>
      

      habe ich jetzt mit einem anderen Ansatz angefangen und schon einmal das Funktionsprinzip visualisiert. Die Frage ist, wie ich jetzt weitermache, ob ich z.B. meinen Ansatz als separaten Absatz in den Wiki-Artikel einfüge oder erst einmal im Benutzer-Namensraum arbeite.

      Viele Grüße
      Robert

      1. problematische Seite

        Servus!

        Moin Matthias,

        nachdem ich vergeblich versucht habe den Beispielcode funktionsfähig zu bekommen,

        <svg class="chart" width="420" height="150" aria-labelledby="chartinfo" >
          <desc id="chartinfo">Ein Diagramm unserer Ernte</desc>
          <defs>
          </defs>
        
        <svg class="pie" width="200" height="200" viewBox="-100 -100 200 200" style="transform: rotate(-0.25turn)">     
        
          <circle id="background" r="50" />
        
          <g class="slice" tabindex="0">
            <path d="M 1 0 A 1 1 0 0 1 0.8 0.59 L 0 0 Z" />
            <text x="45" y="9.5">4 apples</text>
          </g>
        </svg>
        </svg>
        

        Ja, das schien in dem einen Tutorial so einfach zu sein, brachte mich aber auch zur Verzeiflung.

        habe ich jetzt mit einem anderen Ansatz angefangen und schon einmal das Funktionsprinzip visualisiert.

        Super! Vielen Dank!

        Die Frage ist, wie ich jetzt weitermache, ob ich z.B. meinen Ansatz als separaten Absatz in den Wiki-Artikel einfüge oder erst einmal im Benutzer-Namensraum arbeite.

        Theoretisch im Benutzernamnesraum. Da haben wir Aktiven aber das Problem, dass wir einige unserer Projekte "gleich weitermachen" wollten, und dnan nach Jahren auf 90%-fertige Tutorials stoßen, die wir selbst vergessen hatten.

        Meine persönlichee Meinung: Das was du jetzt hast ist besser als der Ist-Stand! Setz es doch in den Artikel und signalisiere mit einem `{{ToDo|--~~~~}} , dass du ab dieser Stelle noch am Arbeiten bist.

        Herzliche Grüße

        Matthias Scharwies

        --
        Die Signatur findet sich auf der Rückseite des Beitrags.
        1. problematische Seite

          Moin Matthias,

          Meine persönlichee Meinung: Das was du jetzt hast ist besser als der Ist-Stand! Setz es doch in den Artikel und signalisiere mit einem `{{ToDo|--~~~~}} , dass du ab dieser Stelle noch am Arbeiten bist.

          jetzt fehlen nur noch schöne Formeln und dann bin ich mit dem, was ich für unbedingt nötig halte, soweit fertig.

          Für einen Diagramm-Editor (oder dynamisches Erzeugen von Diagrammen z.B. mit Webservice-Daten) hat @Rolf B noch gute Hinweise geliefert – vielleicht lässt sich das sogar mit dem WebComponents-Ansatz kombinieren.

          Viele Grüße
          Robert

          1. problematische Seite

            Hallo Robert,

            jetzt fehlen nur noch schöne Formeln und dann bin ich mit dem, was ich für unbedingt nötig halte, soweit fertig.

            Super, vielen Dank!

            Ich hatte immer nur die Anzeige in den letzten Änderungen gesehen! Heute abend schau ich mir das ganz in Ruhe mal an!

            Für einen Diagramm-Editor (oder dynamisches Erzeugen von Diagrammen z.B. mit Webservice-Daten) hat @Rolf B noch gute Hinweise geliefert – vielleicht lässt sich das sogar mit dem WebComponents-Ansatz kombinieren.

            Ja, wobei eben der SVG-Download auch attraktiv klingt!

            Herzliche Grüße

            Matthias Scharwies

            --

            --
            Die Signatur findet sich auf der Rückseite des Beitrags.
            1. problematische Seite

              Servus!

              Hallo Robert,

              jetzt fehlen nur noch schöne Formeln und dann bin ich mit dem, was ich für unbedingt nötig halte, soweit fertig.

              Super, vielen Dank!

              Ja, das sieht alles super aus!

              Evtl. könnte man bei :hover anstatt der hellblauen Füllung die Randline verstärken und die Füllfarbe leuchten lassen.

              Hier würde das Element scheinbar vergrößert, weil die Randlinie die Füllfarbe verwendet. Den Schlagschatten müsste man optimieren.

              .segment:hover path,
              .segment:focus path {
              	filter: brightness(1.15) drop-shadow(2px 2px 4px black); 
              	stroke-width:2;
              	stroke: context-fill;
              }
              

              Für einen Diagramm-Editor (oder dynamisches Erzeugen von Diagrammen z.B. mit Webservice-Daten) hat @Rolf B noch gute Hinweise geliefert – vielleicht lässt sich das sogar mit dem WebComponents-Ansatz kombinieren.

              Ja, wobei eben der SVG-Download auch attraktiv klingt!

              Wenn Du Lust hast, kannst du die unteren ToDos überarbeiten oder löschen.

              Nochmals vielen Dank!

              Herzliche Grüße

              Matthias Scharwies

              --
              Die Signatur findet sich auf der Rückseite des Beitrags.
              1. problematische Seite

                Moin Matthias,

                Evtl. könnte man bei :hover anstatt der hellblauen Füllung die Randline verstärken und die Füllfarbe leuchten lassen.

                Hier würde das Element scheinbar vergrößert, weil die Randlinie die Füllfarbe verwendet. Den Schlagschatten müsste man optimieren.

                .segment:hover path,
                .segment:focus path {
                	filter: brightness(1.15) drop-shadow(2px 2px 4px black); 
                	stroke-width:2;
                	stroke: context-fill;
                }
                

                Sieh mal einer an, stroke: context-fill wird mittlerweile mindestens vom Firefox unterstützt. Vor einem Jahr war das noch nicht der Fall.

                Für einen Diagramm-Editor (oder dynamisches Erzeugen von Diagrammen z.B. mit Webservice-Daten) hat @Rolf B noch gute Hinweise geliefert – vielleicht lässt sich das sogar mit dem WebComponents-Ansatz kombinieren.

                Ja, wobei eben der SVG-Download auch attraktiv klingt!

                Kann man die HTML-Serialisierung aus dem Shadow-DOM kopieren oder gibt es keinen Zugriff darauf?

                Wenn Du Lust hast, kannst du die unteren ToDos überarbeiten oder löschen.

                Das schaue ich mir in nächster Zeit an, ja.

                Viele Grüße
                Robert

                1. problematische Seite

                  Servus!

                  Moin Matthias,

                  Evtl. könnte man bei :hover anstatt der hellblauen Füllung die Randline verstärken und die Füllfarbe leuchten lassen.

                  Hier würde das Element scheinbar vergrößert, weil die Randlinie die Füllfarbe verwendet. Den Schlagschatten müsste man optimieren.

                  .segment:hover path,
                  .segment:focus path {
                  	filter: brightness(1.15) drop-shadow(2px 2px 4px black); 
                  	stroke-width:2;
                  	stroke: context-fill;
                  }
                  

                  Sieh mal einer an, stroke: context-fill wird mittlerweile mindestens vom Firefox unterstützt. Vor einem Jahr war das noch nicht der Fall.

                  Sorry, ich glaub' ich bin der letzte Firefox-Nutzer.

                  https://caniuse.com/mdn-svg_attributes_presentation_fill_context-fill

                  2.69% klingen nicht gut! 😟

                  Für einen Diagramm-Editor (oder dynamisches Erzeugen von Diagrammen z.B. mit Webservice-Daten) hat @Rolf B noch gute Hinweise geliefert – vielleicht lässt sich das sogar mit dem WebComponents-Ansatz kombinieren.

                  Ja, wobei eben der SVG-Download auch attraktiv klingt!

                  Kann man die HTML-Serialisierung aus dem Shadow-DOM kopieren oder gibt es keinen Zugriff darauf?

                  Wenn Du Lust hast, kannst du die unteren ToDos überarbeiten oder löschen.

                  Das schaue ich mir in nächster Zeit an, ja.

                  Vielen Dank im Voraus!

                  Herzliche Grüße

                  Matthias Scharwies

                  --
                  Die Signatur findet sich auf der Rückseite des Beitrags.
      2. problematische Seite

        Hallo Robert B.,

        ich habe mir deinen Code angeschaut und bin vom Ergebnis erfreut, aber im Detail leicht unzufrieden.

        • onclick Attribute statt addEventListener
        • Die Table-Klasse ist nicht wirklich nützlich, eine einfache Funktion "showdata" oder so wäre besser
        • Die Piece-Klasse ist viel zu umfangreich, die meisten Dinge, die sie enthält, kann man beim erzeugen der Segmente berechnen. Ein Piece muss eigentlich nur die Farbe und den Wert enthalten. Den Prozentwert kann man als Optimierung hinzufügen. Den Rest braucht sie nicht.
        • newSvg heißt vermutlich besser createSvgElement und sollte konsequent genutzt werden
        • statt assert2Cols würde ich eine Funktion machen, die eine einzelne Zeile parsed und ein Piece liefert. Du verwendest ein Array um die geparsten Werte zu speichern und generierst dann Pieces daraus, ich finde das schwer nachvollziehbar. Das Parsen einer Zeile sollte auch funktionieren, wenn Spaces vorn oder hinten sind, oder mehr als ein Space zwischen Farbe und Wert steht. Wie wär's mit einer RegExp?
        • reduce funktioniert auch ohne Sonderbehandlung für length=1. Verwende den dritten Parameter (Anfangswert) und übergib 0.
        • die Sonderbehandlung für Pies mit 180° Größe braucht es auch nicht.
        • du verwendest sehr gerne .forEach, das macht es aber auch unübersichtlich. Hast Du Dir mal die for...of Schleife angeschaut?

        Woher bin ich so „schlau“? Ich habe mir den Code eine gute Stunde lang angeschaut und dran hin- und hergebaut. Das Ergebnis ist auch nicht unbedingt so wie ich es gern hätte, darum behalte ich es lieber noch für mich…

        Das Problem mit dem Rand bei :hover ist eins, für das ich aber auch noch keine Idee habe. SVG kennt keine z-order und die Hinweise, die man im Netz finden, besagen, dass man das zu hovernde Element im DOM nach hinten setzen müsse, damit es in der z-order vorne ist. Das braucht dann natürlich mousemove Handler und noch mehr JavaScript. Was ich eigentlich doof finde. Vielleicht bekommt man das Chart ja so hin, dass die Ränder sich nicht überlagern. Leider kennt SVG auch keine Option "male den Rand an der Innenseite", d.h. da muss man dann die Punkte für den Rand separat berechnen.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. problematische Seite

          Moin Rolf,

          ich hätte vielleicht dazu schreiben sollen (fehlendes javascript-Schlagwort im Forum ist vermutlich zu implizit), dass ich erst einmal nicht vorhabe etwas Interaktives ins Wiki zu schreiben, sondern nur eine Anleitung, wie man Tortendiagramme mit SVG konstruieren kann, also

          • die Mathematik dahinter
          • die SVG-Konstrukte

          Das ganze JavaScript-Geraffel war nur für mich zum Ausprobieren, ob meine Mathematik funktioniert. 😉

          Viele Grüße
          Robert

        2. problematische Seite

          Moin Rolf,

          • reduce funktioniert auch ohne Sonderbehandlung für length=1. Verwende den dritten Parameter (Anfangswert) und übergib 0.

          da ich die Summe über eine Array-Komponente bilde, muss der Aufruf von Array.prototype.reduce entsprechend aussehen und auch den passenden Startwert als Array haben:

          // Beispiel:
          const vals = [['red', 1], ['green', 2], ['black', 5]];
          
          // allgemeine Summe für leeres Array
          // oder mit beliebiger Anzahl an Elementen:
          const sum = vals.reduce((p,c) => [0, p[1] + c[1]], [0,0])[1];
          

          Viele Grüße
          Robert

          1. problematische Seite

            Hallo Robert B.,

            da ich die Summe über eine Array-Komponente bilde, muss der Aufruf von Array.prototype.reduce entsprechend aussehen und auch den passenden Startwert als Array haben:

            Nö. Ein Array als Summenelement durchzuschleifen ist kein muss. Es steht nirgends geschrieben, dass der Typ des Summenparameters zwingend vom gleichen Typ wie die Array-Einträge sein muss. Du hast den reduce-Eintrag im Wiki doch gelesen (weiß ich, weil Du daran etwas verbessert hast). Guck mal:

            // Beispiel:
            const vals = [['red', 1], ['green', 2], ['black', 5]];
            
            // allgemeine Summe für leeres Array
            // oder mit beliebiger Anzahl an Elementen:
            const sum = vals.reduce((sum,value) => sum+value[1], 0);
            //                                                 ▲▲▲
            

            Gibt man reduce keinen dritten Parameter, dann bildet das erste Arrayelement ("red") den initialen sum-Wert, und die reduce-Schleife beginnt erst beim zweiten Array-Element damit, den Callback aufzurufen.

            Wenn ich nur Zahlen im Array habe und der Callback für das erste Arrayelement nichts anderes tun würde, als dieses Element als neue Summe zurückzugeben, ist das unproblematisch.

            Wenn man aber komplexere Dinge tut, ist der dritte Parameter hilfreich. Er tut zweierlei:

            • er legt einen expliziten Startwert für die Reduktion fest
            • die reduce-Schleife beginnt nicht beim zweiten, sondern beim ersten Array-Eintrag mit den Callback-Aufrufen

            Ich habe das Beispiel aus diesem Thread mal ins Wiki übertragen.

            Rolf

            --
            sumpsi - posui - obstruxi