Suche // Search:

25.03.2010

FormCalc Diagramme Teil 2 - Tortendiagramme (V1 & V2)
//
FormCalc Charts Pt.2 - Pie Charts (V1 & V2)

In der Vergangenheit habe ich schon einige Arten an Diagrammen entwickelt, die sich mit FormCalc innerhalb eines XFA-Formulars erstellen und bearbeiten lassen.
Da war eigentlich alles dabei, nur kein Tortendiagramm.
Das liegt an den sehr beschränkten Manipulationsmöglichkeiten für Kreise im LiveCycle Designer.
Ich habe nun aber eine Möglichkeit gefunden, wie man solche Diagramme doch erstellen kann.
Das ist zwar sehr experimentell aber es funktioniert.
Nur ist es sehr konstruktionsbedingt sehr ressourcenhungrig.

Für die Eingabe verwende ich eine Tabelle.
Für das Diagramm verwendet ich Bogenlinien, und zwar einige hundert davon.
Damit lässt sich ein mehrfarbiger Kreis simulieren.
Die Berechnung erfolgt über ein verstecktes Feld "Trigger", dass alle Bögen per for-Schleife ansteuert und deren Position, Länge und Farbe berechnet.

Je nach Anzahl der Eingabewerte sind dadurch mehrere Tausend Bögen zu berechnen, was die Berechnung mitunter stark verlangsamt.

In the past I already developed several kinds of charts with FormCalc that could be used in a XFA-form.
Only a pie chart was missing, because of the very limited capabilities of manipulation of cicles in LiveCycle Designer.
Now I fould a way to do this.
It's very experimental but it works so far.

For the data input I use a table and for the pie several hundred bows.
This bows simulate a multicolored cicle.
The calculation is done by a hidden field "trigger" that uses a for-loop to calculate the positions, legths and colors of every bow.

Depending on the number of values in the table, the script has to calculate thousands of bows so it becomes slower.

FormCalc-Skript – Version 1
//
FormCalc-Skript – Version 1
var nCharts = Input.Table.ChartValues.instanceManager.count
for i=0 upto nCharts -1 step 1 do
 var PieValue = Input.Table.ChartValues[i].Amount
 if(PieValue >= 0) then
  var Total = 0
  for j = 0 upto nCharts -1 do
   Total = Total + Input.Table.ChartValues[j].Amount
  endfor

  var Weighting = Round(100 / Total * PieValue, 2)
  var OneDegree = Round(360 / 100, 1)
  var Sweep = Weighting * OneDegree
  var StartDegree = 0
  Pie[i].Bow[*].value.arc.sweepAngle = Sweep

  if(i eq 0) then
   Pie[i].Bow[*].value.arc.startAngle = StartDegree
  elseif(i > 0) then
   StartDegree = Pie[i-1].Bow.value.arc.startAngle + Pie[i-1].Bow.value.arc.sweepAngle
   Pie[i].Bow[*].value.arc.startAngle = StartDegree
  endif

  var nColor = Choose(i+1, ;Instance (+1) = position in this list
    "238,0,0", ;Red
    "255,48,48", ;FireBrick
    "255,99,71", ;Tomato
    "255,127,80", ;Coral
    "255,140,0", ;DarkOrange
    "255,165,0", ;Orange
    "255,215,0", ;Gold
    "255,255,0", ;Yellow
    "238,238,0", ;Yellow2
    "154,205,50") ;YellowGreen

  Pie[i].Bow[*].value.arc.edge.color.value = nColor
  Input.Table.ChartValues[i].Color.Color.value.rectangle.fill.color.value = nColor
 endif
endfor

Tortendiagramm  – Version 1
//
Pie Chart – Version 1


Beispiel & XML-Daten – Version 1
//
Example & XML-Data  – Version 1
https://workspaces.acrobat.com/?d=8ISRovhkYV2lD9Fb5q1yPA
https://workspaces.acrobat.com/?d=aLgtLEY54EfFuWl02xeLMA


Aktualisierung: Die Version 2 bietet etwas mehr Flexibilität.
Zum einen braucht in Designer nun nur noch eine Instanz des Bogens vorhanden sein, da alle weiteren Instanzen über das Skript ermittelt und hinzugefügt werden.
Des Weiteren kann nun die Größe des Diagramms, des Lochs in der Mitte, sowie die Linienstärke je Bogen , der Abstand der Bögen zueinander und der Winkel verändert werden.

Je dünner die Bögen und je kleiner der Abstand zwischen den Bögen, desto besser sieht das Diagramm aus.
Aber, je nach Anzahl der Bögen im Diagramm ist der Berechnungsaufwand beträchtlich.
Seien Sie also vorsichtig damit.

Update: Version 2 offers more flexibility.
On the one hand you only need to define one instance of the bow in Designer because the script will determine and add all the rest.
On the other hand you can define the size of the chart, the hole in the middle, the line thickness of the bows and the gaps between them and even the angle by yourself.

Thinner the bows and and gaps will make the chart looking even better.
But, depending on the number of bows the overhead of calculations can be come extremly high.
So be careful.


FormCalc-Skript – Version 2 
//
FormCalc-Skript – Version 2 
var nCharts = Input.Table._ChartValues.count  
var MaxSize = 30         
var GapSize = 0.5         
var Line = 0.5          
var Hole = Round(20 / Sum(Line, GapSize)) 
var Bows = Round(MaxSize / GapSize) - Hole 
var Angle = 0
var Total = Sum(Input.Table.ChartValues[*].Amount) 

func SetBows(nPie, nBow) do
 if (Pie[nPie]._Bow.count ne nBow) then
  Pie[nPie].layout = "tb"
     Pie[nPie]._Bow.setInstances(nBow)
     Pie[nPie].layout = "position"
    endif
endfunc

func SetPies(nChart) do
 if (Output._Pie.count ne nChart) then
  Output.layout = "tb"
     Output._Pie.setInstances(nChart)
     Output.layout = "position"
    endif
endfunc

func ModifyBows(nPie, Bows, MaxSize, GapSize) do
 for m = Bows -1 downto 0 step 1 do
  var Diameter = GapSize * m 
  var Offset = Diameter / 2
  var NewDiameter = Concat(MaxSize - Diameter, "mm")
  var NewOffset = Concat(Offset, "mm")
  Pie[nPie].Bow[m].Bow.h = NewDiameter
  Pie[nPie].Bow[m].Bow.w = NewDiameter
  Pie[nPie].Bow[m].Bow.x = NewOffset
  Pie[nPie].Bow[m].Bow.y = NewOffset
 endfor
endfunc

func CalcPies(nPie, nPieValue, nCharts, Total, Bows, Angle) do
 if(nPieValue ge 0) then
  var Weighting = Round(100 / Total * nPieValue, 2)
  var Sweep = Weighting * 3.6
  Pie[nPie].Bow[*].Bow.value.arc.sweepAngle = Sweep 
  var StartAngle = Angle
  if(nPie eq 0) then
   Pie[nPie].Bow[*].Bow.value.arc.startAngle = StartAngle
  elseif(nPie gt 0) then
   StartAngle = Sum(Pie[nPie-1].Bow[0].Bow.value.arc.startAngle, Pie[nPie-1].Bow[0].Bow.value.arc.sweepAngle)
   Pie[nPie].Bow[*].Bow.value.arc.startAngle = StartAngle
  endif
 endif
endfunc

func ShapePies(nPie, Line) do
 var nColor = Choose(nPie+1,  
       "255,255,0",   
       "255,211,13",  
       "255,161,0",  
       "255,107,13",  
       "255,32,0",  
       "255,13,130",  
       "200,0,255",  
       "83,13,255",  
       "0,51,255",  
       "13,177,255",
       "0,255,212",
       "13,255,89",
       "62,255,0",
       "149,255,13",
       "255,217,0")  
 
 Pie[nPie].Bow[*].Bow.value.arc.edge.color.value = nColor
 Pie[nPie].Bow[*].Bow.value.arc.edge.thickness = UnitValue(Concat(Line,"mm"), "in")
 Input.Table.ChartValues[nPie].Color.Color.value.rectangle.fill.color.value = nColor
endfunc

if (RenderChart.value eq 1) then
 for n=0 upto nCharts -1 step 1 do
  var nPieValue = Input.Table.ChartValues[n].Amount
  SetPies(nCharts)
  SetBows(n, Bows)
  ModifyBows(n, Bows, MaxSize, GapSize)
  CalcPies(n, nPieValue, nCharts, Total, Bows, Angle)
  ShapePies(n, Line)
 endfor
RenderChart.value = 0
endif

Tortendiagramm  – Version 2 mit variabler Größe, Bogenanzahl und Winkel
//
Pie Chart – Version 2 with variable size, bow number and angle





Beispiel – Version 2
//
Example  – Version 2
https://files.acrobat.com/a/preview/78c3b72c-f81c-47fd-84f4-1078630963b7

8 Kommentare:

  1. Links are not working. Could you please put another reference to the PDF samples?

    JC

    AntwortenLöschen
  2. Hi JC,

    I've updated the links to the samples.

    AntwortenLöschen
  3. Hi.

    I've just had a little play with this (though not actually run the code yet) and I think you can do it nicely with just one arc for each section of the pie chart.

    Simply set the line thickness to be the required diameter of the circle - and then add the cap="butt" attribute to the edge element of the arc.

    A sample XML is below:











    AntwortenLöschen
  4. Hi Dan,

    you're absolutely right with the cap property! Together with the hand property it's very useful for pie charts. I didn't think of it when developed the pie chart as it's one of those properties you cannot set through Designers GUI but only from the XML source (given that you have ever read the XFA specs to know about those elements). I took you tip as a reason to update my pie chart example. I'll will post it soon here.

    AntwortenLöschen
  5. Can this be done in Acrobat forms?

    AntwortenLöschen
  6. Hi Pete,

    this solution is only usable in XFA-forms, as it requires a dynamic form.

    AntwortenLöschen
  7. Hallo,

    super Script!!!
    Deine Tabelle beinhaltet Kategorie, Wert und Farbe.
    Was für ein Typ hat die Farbe?
    Muss dort eine Zahl stehen oder eine Farbe ausgeschrieben, wie z.B. "rot"?

    Liebe Grüße

    AntwortenLöschen
  8. Die RGB-Farben werden jeweils über ein Array aus drei Zahlen zwischen 0–255 festgelegt. "238,0,0" ergibt zum Beispiel ein schönes Rot.

    AntwortenLöschen