File Coverage

blib/lib/SVG/TT/Graph/Pie.pm
Criterion Covered Total %
statement 19 19 100.0
branch 2 2 100.0
condition 4 6 66.6
subroutine 6 6 100.0
pod n/a
total 31 33 93.9


line stmt bran cond sub pod time code
1             package SVG::TT::Graph::Pie;
2              
3 3     3   3105 use strict;
  3         6  
  3         85  
4 3     3   14 use Carp;
  3         5  
  3         153  
5 3     3   15 use SVG::TT::Graph;
  3         5  
  3         60  
6 3     3   13 use base qw(SVG::TT::Graph);
  3         12  
  3         1070  
7              
8             our $VERSION = $SVG::TT::Graph::VERSION;
9             our $TEMPLATE_FH = \*DATA;
10              
11             =head1 NAME
12              
13             SVG::TT::Graph::Pie - Create presentation quality SVG pie graphs easily
14              
15             =head1 SYNOPSIS
16              
17             use SVG::TT::Graph::Pie;
18              
19             my @fields = qw(Jan Feb Mar);
20             my @data_sales_02 = qw(12 45 21);
21              
22             my $graph = SVG::TT::Graph::Pie->new({
23             'height' => '500',
24             'width' => '300',
25             'fields' => \@fields,
26             });
27              
28             $graph->add_data({
29             'data' => \@data_sales_02,
30             'title' => 'Sales 2002',
31             });
32              
33             print "Content-type: image/svg+xml\n\n";
34             print $graph->burn();
35              
36             =head1 DESCRIPTION
37              
38             This object aims to allow you to easily create high quality
39             SVG pie graphs. You can either use the default style sheet
40             or supply your own. Either way there are many options which can
41             be configured to give you control over how the graph is
42             generated - with or without a key, display percent on pie chart,
43             title, subtitle etc.
44              
45             =head1 METHODS
46              
47             =head2 new()
48              
49             use SVG::TT::Graph::Pie;
50              
51             # Field names along the X axis
52             my @fields = qw(Jan Feb Mar);
53              
54             my $graph = SVG::TT::Graph::Pie->new({
55             # Required
56             'fields' => \@fields,
57              
58             # Optional - defaults shown
59             'height' => '500',
60             'width' => '300',
61              
62             'show_graph_title' => 0,
63             'graph_title' => 'Graph Title',
64             'show_graph_subtitle' => 0,
65             'graph_subtitle' => 'Graph Sub Title',
66              
67             'show_shadow' => 1,
68             'shadow_size' => 1,
69             'shadow_offset' => 15,
70              
71             'key_placement' => 'R',
72              
73             # data by pie chart wedges:
74             'show_data_labels' => 0,
75             'show_actual_values' => 0,
76             'show_percent' => 1,
77             'rollover_values' => 0,
78             'show_path_title' => 0,
79             'show_title_fields' => 0,
80              
81             # data on key:
82             'show_key_data_labels' => 1,
83             'show_key_actual_values' => 1,
84             'show_key_percent' => 0,
85              
86             'expanded' => 0,
87             'expand_greatest' => 0,
88              
89             # Stylesheet defaults
90             'style_sheet' => '/includes/graph.css', # internal stylesheet
91             'style_sheet_field_names' => 0,
92             'random_colors' => 0,
93              
94             });
95              
96             The constructor takes a hash reference, fields (the name for each
97             slice on the pie) MUST be set, all other values are defaulted to those
98             shown above - with the exception of style_sheet which defaults
99             to using the internal style sheet.
100              
101             =head2 add_data()
102              
103             my @data_sales_02 = qw(12 45 21);
104              
105             $graph->add_data({
106             'data' => \@data_sales_02,
107             'title' => 'Sales 2002',
108             });
109              
110             This method allows you to add data to the graph object, only
111             the first data set added will be used!
112              
113             =head2 clear_data()
114              
115             my $graph->clear_data();
116              
117             This method removes all data from the object so that you can
118             reuse it to create a new graph but with the same config options.
119              
120             =head2 burn()
121              
122             print $graph->burn();
123              
124             This method processes the template with the data and
125             config which has been set and returns the resulting SVG.
126              
127             This method will croak unless at least one data set has
128             been added to the graph object.
129              
130             =head2 config methods
131              
132             my $value = $graph->method();
133             my $confirmed_new_value = $graph->method($value);
134              
135             The following is a list of the methods which are available
136             to change the config of the graph object after it has been
137             created.
138              
139             =over 4
140              
141             =item height()
142              
143             Set the height of the graph box, this is the total height
144             of the SVG box created - not the graph it self which auto
145             scales to fix the space.
146              
147             =item width()
148              
149             Set the width of the graph box, this is the total width
150             of the SVG box created - not the graph it self which auto
151             scales to fix the space.
152              
153             =item compress()
154              
155             Whether or not to compress the content of the SVG file (Compress::Zlib required).
156              
157             =item tidy()
158              
159             Whether or not to tidy the content of the SVG file (XML::Tidy required).
160              
161             =item style_sheet()
162              
163             Set the path to an external stylesheet, set to '' if
164             you want to revert back to using the defaut internal version.
165              
166             Set to "inline:<style>...</style>" with your CSS in between the tags.
167             You can thus override the default style without requireing an external URL.
168              
169             The default stylesheet handles up to 12 data sets. All data series over
170             the 12th will have no style and be in black. If you have over 12 data
171             sets you can assign them all random colors (see the random_color()
172             method) or create your own stylesheet and add the additional settings
173             for the extra data sets.
174              
175             To create an external stylesheet create a graph using the
176             default internal version and copy the stylesheet section to
177             an external file and edit from there.
178              
179             =item random_colors()
180              
181             Use random colors in the internal stylesheet
182              
183             =item style_sheet_field_names()
184              
185             If you use the style_sheet_field_names() option then you can
186             use the field names within your stylesheet. This allows
187             consistent use of styles. The names should be:
188              
189             =over 4
190              
191             =item <field>_dataPoint
192              
193             =item <field>_key
194              
195             =back
196              
197             =item show_graph_title()
198              
199             Whether to show a title on the graph, default is '0'.
200              
201             =item graph_title()
202              
203             What the title on the graph should be.
204              
205             =item show_graph_subtitle()
206              
207             Whether to show a subtitle on the graph, default is '0'.
208              
209             =item graph_subtitle()
210              
211             What the subtitle on the graph should be.
212              
213             =item show_shadow()
214              
215             Turn the shadow on and off, default to '1', set
216             to '0' if you don't want it. It is automatically
217             turned off if you extract one section of the pie.
218              
219             =item shadow_size()
220              
221             Size of the shadow if shown, measured as
222             percentage of pie chart radius, default of 1
223             being the same size as the pie.
224              
225             =item shadow_offset()
226              
227             Offset (in pixels) of shadow to bottom-right
228             in relation to the center of the pie chart.
229              
230             =item key()
231              
232             Whether to show a key, defaults to 0, set to
233             '1' if you want to show it.
234              
235             =item key_placement()
236              
237             Defaults to 'R' - right, can be
238             'R', 'L', 'T' or 'B'.
239              
240             =item show_data_labels()
241              
242             Show label on pie chart, defaults
243             to '0', can be set to '1'.
244              
245             =item show_actual_values()
246              
247             Show values on pie chart, defaults
248             to '0', can be set to '1'.
249              
250             =item show_percent()
251              
252             Show percent (rounded) on the pie chart, defaults
253             to '1', can be set to '0'.
254              
255             =item rollover_values()
256              
257             Shows data field and value when the mouse is over a piechart wedge.
258              
259             =item show_path_title()
260              
261             Whether to add the title attribute to the data path tags,
262             which will show "tooltips" when hovering over the bar area.
263              
264             =item show_title_fields()
265              
266             Whether to show field values as title elements in path tag,
267             defaults to 0, set to '1' to turn on. Suggest on single
268             add_data graphs, for overlapping graphs leave off to see
269             the title value used in the add_data call.
270              
271             =item show_key_data_labels()
272              
273             Show label on the key, defaults
274             to '1', can be set to '0'.
275              
276             =item show_key_actual_values()
277              
278             Show value on the key, defaults
279             to '1', can be set to '0'.
280              
281             =item show_key_percent()
282              
283             Show percent (rounded) on the key, defaults
284             to '0', can be set to '1'.
285              
286             =item expanded()
287              
288             All slices of pie are exploded out, defaults
289             to '0'. Do not set to '1' if you are going to
290             use expanded_greatest().
291              
292             =item expand_greatest()
293              
294             The largest slice of pie is exploded out
295             from the pie, defaults to '0'. Useful if you are
296             only showing the percentages (which are rounded) but
297             still want to visually show which slice was largest.
298              
299             Do not set to '1' if you are going to
300             use expanded().
301              
302             =back
303              
304             =head1 EXAMPLES
305              
306             For examples look at the project home page
307             http://leo.cuckoo.org/projects/SVG-TT-Graph/
308              
309             =head1 EXPORT
310              
311             None by default.
312              
313             =head1 SEE ALSO
314              
315             L<SVG::TT::Graph>,
316             L<SVG::TT::Graph::Line>,
317             L<SVG::TT::Graph::Bar>,
318             L<SVG::TT::Graph::BarHorizontal>,
319             L<SVG::TT::Graph::BarLine>,
320             L<SVG::TT::Graph::TimeSeries>,
321             L<SVG::TT::Graph::XY>,
322             L<Compress::Zlib>,
323             L<XML::Tidy>
324              
325             =cut
326              
327              
328             sub _init {
329 3     3   6 my $self = shift;
330             croak "fields was not supplied or is empty"
331             unless defined $self->{'config'}->{fields}
332             && ref($self->{'config'}->{fields}) eq 'ARRAY'
333 3 100 66     242 && scalar(@{$self->{'config'}->{fields}}) > 0;
  2   66     11  
334             }
335              
336             sub _set_defaults {
337 3     3   7 my $self = shift;
338              
339 3         54 my %default = (
340             'width' => '500',
341             'height' => '300',
342              
343             'style_sheet' => '',
344             'style_sheet_field_names' => 0,
345             'random_colors' => 0,
346              
347             'show_graph_title' => 0,
348             'graph_title' => 'Graph Title',
349             'show_graph_subtitle' => 0,
350             'graph_subtitle' => 'Graph Sub Title',
351              
352             'show_shadow' => 1,
353             'shadow_size' => 1,
354             'shadow_offset' => 15,
355              
356             'key_placement' => 'R',
357              
358             'show_data_labels' => 0,
359             'show_actual_values' => 0,
360             'show_percent' => 1,
361             'rollover_values' => 0,
362             'show_path_title' => 0,
363             'show_title_fields' => 0,
364              
365             'key' => 0,
366             'show_key_data_labels' => 1,
367             'show_key_actual_values' => 1,
368             'show_key_percent' => 0,
369              
370             'expanded' => 0,
371             'expand_greatest' => 0,
372             );
373              
374 3         22 while( my ($key,$value) = each %default ) {
375 75         182 $self->{config}->{$key} = $value;
376             }
377             }
378              
379             1;
380             __DATA__
381             <?xml version="1.0"?>
382             <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
383             "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
384             [% stylesheet = 'included' %]
385              
386             [% IF config.style_sheet && config.style_sheet != '' && config.style_sheet.substr(0,7) != 'inline:' %]
387             <?xml-stylesheet href="[% config.style_sheet %]" type="text/css"?>
388             [% ELSIF config.style_sheet && config.style_sheet.substr(0,7) == 'inline:'%]
389             [% stylesheet = 'inline'
390             style_inline = config.style_sheet.substr(7) %]
391             [% ELSE %]
392             [% stylesheet = 'excluded' %]
393             [% END %]
394              
395             <svg width="[% config.width %]" height="[% config.height %]" viewBox="0 0 [% config.width %] [% config.height %]" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
396              
397             <!-- \\\\\\\\\\\\\\\\\\\\\\\\\\\\ -->
398             <!-- Created with SVG::TT::Graph -->
399             <!-- Stephen Morgan / Leo Lapworth -->
400             <!-- //////////////////////////// -->
401             <defs>
402             <radialGradient id="shadow">
403             <stop offset="85%" style="stop-color: #ccc;"/>
404             <stop offset="100%" style="stop-color: #ccc;stop-opacity: 0"/>
405             </radialGradient>
406              
407             [% IF stylesheet == 'inline' %]
408             [% style_inline %]
409             [% ELSIF stylesheet == 'excluded' %]
410             <!-- include default stylesheet if none specified -->
411             <style type="text/css">
412             <![CDATA[
413             /* Copy from here for external style sheet */
414             .svgBackground{
415             fill:none;
416             }
417             .graphBackground{
418             fill:#f0f0f0;
419             }
420              
421             /* graphs titles */
422             .mainTitle{
423             text-anchor: middle;
424             fill: #000000;
425             font-size: 14px;
426             font-family: "Arial", sans-serif;
427             font-weight: normal;
428             }
429             .subTitle{
430             text-anchor: middle;
431             fill: #999999;
432             font-size: 12px;
433             font-family: "Arial", sans-serif;
434             font-weight: normal;
435             }
436              
437             .dataPointLabel{
438             fill: #000000;
439             text-anchor:middle;
440             font-size: 10px;
441             font-family: "Arial", sans-serif;
442             font-weight: normal;
443             }
444              
445             [% FOREACH field = config.fields %]
446             [% color = '' %]
447             [% IF config.random_colors %]
448             [% color = random_color() %]
449             [% ELSE %]
450             [% color = predefined_color(loop.count) %]
451             [% END %]
452              
453             .key[% loop.count %],.dataPoint[% loop.count %]{
454             fill: [% color %];
455             fill-opacity: 0.5;
456             stroke: none;
457             stroke-width: 1px;
458             }
459              
460             [% LAST IF (config.random_colors == 0 && loop.count == 12) %]
461             [% END %]
462              
463             .keyText{
464             fill: #000000;
465             text-anchor:start;
466             font-size: 10px;
467             font-family: "Arial", sans-serif;
468             font-weight: normal;
469             }
470             /* End copy for external style sheet */
471             ]]>
472             </style>
473             [% END %]
474             </defs>
475              
476             [% IF config.rollover_values %]
477             <!-- Script to toggle paths when their key is clicked on -->
478             <script language="JavaScript"><![CDATA[
479             function togglePath( series ) {
480             var text = document.getElementById('n' + series);
481             if ( text.getAttribute('opacity') == 0 ) {
482             text.setAttribute('opacity',1);
483             } else {
484             text.setAttribute('opacity',0);
485             }
486             }
487             ]]></script>
488             [% END %]
489              
490             <!-- svg bg -->
491             <rect x="0" y="0" width="[% config.width %]" height="[% config.height %]" class="svgBackground"/>
492              
493             <!-- ///////////////// CALCULATE GRAPH AREA AND BOUNDARIES //////////////// -->
494             <!-- get dimensions of actual graph area (NOT SVG area) -->
495             [% w = config.width %]
496             [% h = config.height %]
497             [% Pi = 3.14159 %]
498              
499             <!-- calc min and max values -->
500             [% total = 0 %]
501             [% count = 0 %]
502             [% min_value = 99999999999 %]
503             [% max_value = 0 %]
504             [% FOREACH field = config.fields %]
505             [% total = total + data.0.data.$field %]
506             [% count = count + 1 %]
507             [% IF min_value > data.0.data.$field && data.0.data.$field != '' %]
508             [% min_value = data.0.data.$field %]
509             [% END %]
510             [% IF max_value < data.0.data.$field && data.0.data.$field != '' %]
511             [% max_value = data.0.data.$field %]
512             [% END %]
513             [% END %]
514              
515             <!-- reduce height if graph has title or subtitle -->
516             [% IF config.show_graph_title %][% h = h - 25 %][% END %]
517             [% IF config.show_graph_subtitle %][% y = y + 10 %][% END %]
518             [% IF config.show_graph_subtitle %][% y = y + 10 %][% END %]
519              
520             <!-- set start/default coords of graph -->
521             [% x = w / 2 %]
522             [% y = h / 2 %]
523              
524             <!-- move centre of pie chart if title present -->
525             [% IF config.show_graph_title %][% y = y + 15 %][% END %]
526             [% IF config.show_graph_subtitle %][% y = y + 10 %][% END %]
527              
528             [% padding = 30 %]
529              
530             <!-- calc radius and check whether KEY will affect this -->
531             [% IF w >= h %]
532             [% r = (h / 2) - padding %]
533              
534             [% IF config.key %]
535             [% key_position = 'h' %]
536             [% x_key_start = 30 %]
537             [% IF config.key_placement == 'R' %]
538             <!-- if there is a key, move the pie chart -->
539             [% x = x - r / 3 %]
540             <!-- if the radius is too big, shrink it -->
541             [% IF x < r %]
542             [% r = r - (w / 8) %]
543             [% END %]
544             [% ELSE %]
545             <!-- if there is a key, move the pie chart -->
546             [% x = x + r / 3 %]
547             <!-- if the radius is too big, shrink it -->
548             [% IF r > (w - x) && x > (w / 2) %]
549             [% r = r - (w / 8) %]
550             [% END %]
551             [% END %]
552             [% END %]
553              
554             [% ELSE %]
555             [% r = (w / 2) - padding %]
556              
557             [% IF config.key %]
558             [% key_position = 'v' %]
559             [% y_key_start = 40 %]
560             [% IF config.key_placement == 'B' %]
561             <!-- if there is a key, move the pie chart -->
562             [% y = y - (r / 2) %]
563             <!-- if the radius is too big, shrink it -->
564             [% IF y < r %]
565             [% r = r - (h / 8) %]
566             [% END %]
567             [% ELSE %]
568             <!-- if there is a key, move the pie chart -->
569             [% y = y + (r / 2) %]
570             <!-- if the radius is too big, shrink it -->
571             [% IF r > (h - y) && y > (h / 2) %]
572             [% r = r - (h / 8) %]
573             [% END %]
574             [% END %]
575             [% END %]
576             [% END %]
577              
578             <!-- if chart expanded -->
579             [% IF config.expanded OR config.expand_greatest %]
580             [% e = 10 %]
581             [% ELSE %]
582             [% e = 0 %]
583             [% END %]
584              
585              
586             [% IF config.show_shadow %]
587             <!-- check if a shadow size has been entered -->
588             [% IF config.shadow_size && config.shadow_size != '' %]
589             [% shadow_size = r + ((r / 100) * config.shadow_size) %]
590             [% ELSE %]
591             [% shadow_size = r %]
592             [% END %]
593              
594             [% IF !config.expanded && !config.expand_greatest %]
595             <!-- only show shadow if not expanded -->
596             <circle cx="[% x + config.shadow_offset %]" cy="[% y + config.shadow_offset %]" r="[% shadow_size + e %]" style="fill: url(#shadow); stroke: none;"/>
597             [% END %]
598              
599             [% END %]
600              
601             <circle cx="[% x %]" cy="[% y %]" r="[% r + e %]" fill="#ffffff"/>
602              
603             [% px_start = x + r %]
604             [% pmin_scale_value = y %]
605              
606             [% values = 0 %]
607             <!-- half values used to show values next to wedges -->
608             [% values_half = 0 %]
609             [% last_value_half = 0 %]
610              
611             [% IF config.show_percent && config.show_data_labels %]
612             [% wedge_text_pad = 20 %]
613             [% ELSE %]
614             [% wedge_text_pad = 5 %]
615             [% END %]
616              
617             [% count = 1 %]
618             [% FOREACH field = config.fields %]
619             [% FOREACH dataset = data %]
620             [% value = data.0.data.$field %]
621             [% value_half = data.0.data.$field / 2 %]
622              
623             <!-- calc percentage -->
624             [% IF total == 0 %]
625             [% percent = 0 %]
626             [% ELSE %]
627             [% percent = (100 / total) * value FILTER format('%2.0f')%]
628             [% END %]
629              
630             [% values = values + value %]
631              
632             [% IF count == 1 %]
633             <!-- offset values at start to get mid point -->
634             [% values_half = values_half + value_half %]
635             [% ELSE %]
636             [% values_half = values_half + last_value_half + value_half %]
637             [% END %]
638              
639             [% IF total == 0 %]
640             [% degrees = 0 %]
641             [% degrees_half = 0 %]
642             [% ELSE %]
643             [% degrees = (values / total) * 360 %]
644             [% degrees_half = (values_half / total) * 360 %]
645             [% END %]
646              
647             [% radians = degrees * (Pi / 180) %]
648             [% radians_half = degrees_half * (Pi / 180) %]
649              
650             [% px_end = r * cos(radians) FILTER format('%02.10f') %]
651             [% py_end = r * sin(radians) FILTER format('%02.10f') %]
652              
653             [% px_mid = r * cos(radians_half) FILTER format('%02.10f') %]
654             [% py_mid = r * sin(radians_half) FILTER format('%02.10f') %]
655              
656              
657             <!-- segments displayed clockwise from ' 3 o'clock ' -->
658             [% IF config.expanded && !config.expand_greatest %]
659             [% re = r / e %]
660             [% xe = re * cos(radians_half) FILTER format('%02.10f') %]
661             [% ye = re * sin(radians_half) FILTER format('%02.10f') %]
662              
663             <path id="w[% count %]" d="M[% px_start + xe %] [% pmin_scale_value + ye %] A[% r %] [% r %] 0
664             [% IF percent >= 50 %]1[% ELSE %]0[% END %] 1 [% x + px_end + xe %] [% y + py_end + ye %] L[% x + xe %] [% y + ye %] Z" class="[% IF config.style_sheet_field_names %][% field %]_dataPoint[% ELSE %]dataPoint[% count %][% END %]" [% IF config.rollover_values %]onmouseover="togglePath([% count %]);" onmouseout="togglePath([% count %]);"[% END %]
665              
666             [% ELSIF !config.expanded && config.expand_greatest %]
667             [% IF data.0.data.$field == max_value %]
668             [% re = r / e %]
669             [% xe = re * cos(radians_half) FILTER format('%02.10f') %]
670             [% ye = re * sin(radians_half) FILTER format('%02.10f') %]
671             <path id="w[% count %]" d="M[% px_start + xe %] [% pmin_scale_value + ye %] A[% r %] [% r %] 0
672             [% IF percent >= 50 %]1[% ELSE %]0[% END %] 1 [% x + px_end + xe %] [% y + py_end + ye %] L[% x + xe %] [% y + ye %] Z" class="[% IF config.style_sheet_field_names %][% field %]_dataPoint[% ELSE %]dataPoint[% count %][% END %]" [% IF config.rollover_values %]onmouseover="togglePath([% count %]);" onmouseout="togglePath([% count %]);"[% END %]
673             [% ELSE %]
674             <path id="w[% count %]" d="M[% px_start %] [% pmin_scale_value %] A[% r %] [% r %] 0
675             [% IF percent >= 50 %]1[% ELSE %]0[% END %] 1 [% x + px_end %] [% y + py_end %] L[% x %] [% y %] Z" class="[% IF config.style_sheet_field_names %][% field %]_dataPoint[% ELSE %]dataPoint[% count %][% END %]" [% IF config.rollover_values %]onmouseover="togglePath([% count %]);" onmouseout="togglePath([% count %]);"[% END %]
676             [% END %]
677              
678             [% ELSE %]
679             <path id="w[% count %]" d="M[% px_start %] [% pmin_scale_value %] A[% r %] [% r %] 0
680             [% IF percent >= 50 %]1[% ELSE %]0[% END %] 1 [% x + px_end %] [% y + py_end %] L[% x %] [% y %] Z" class="[% IF config.style_sheet_field_names %][% field %]_dataPoint[% ELSE %]dataPoint[% count %][% END %]" [% IF config.rollover_values %]onmouseover="togglePath([% count %]);" onmouseout="togglePath([% count %]);"[% END %]
681             [% END %]
682              
683             [% IF config.show_path_title %]
684             [% IF config.show_title_fields %]
685             ><title>[% data.0.data.$field %] - [% field %]</title></path>
686             [% ELSE %]
687             ><title>[% data.0.data.$field %] - [% data.0.title %]</title></path>
688             [% END %]
689             [% ELSE %]
690             />
691             [% END %]
692              
693             <!-- show values next to wedges -->
694             [% text_x_offset = 0 %]
695             [% text_y_offset = 0 %]
696             [% IF px_mid >= x && px_mid <= y %]
697             [% text_x_offset = wedge_text_pad %]
698             [% text_y_offset = wedge_text_pad %]
699             [% ELSIF px_mid <= x && py_mid <= y %]
700             [% text_x_offset = 0-wedge_text_pad %]
701             [% text_y_offset = wedge_text_pad %]
702             [% ELSIF px_mid <= x && py_mid >= y %]
703             [% text_x_offset = wedge_text_pad %]
704             [% text_y_offset = 0-wedge_text_pad %]
705             [% ELSE %]
706             [% text_x_offset = 0-wedge_text_pad %]
707             [% text_y_offset = 0-wedge_text_pad %]
708             [% END %]
709             <text id="d[% count %]" x="[% x + px_mid + text_x_offset %]" y="[% y + py_mid + text_y_offset %]" class="dataPointLabel">[% IF config.show_data_labels %][% field %][% END %][% IF config.show_actual_values %][[% data.0.data.$field %]][% END %][% IF config.show_percent %][% percent %]%[% END %]</text>
710              
711             <!-- show rollover field names next to wedge values -->
712             [% IF config.rollover_values %]
713             <text id="n[% count %]" x="[% x %]" y="[% y + r + e + padding %]" class="subTitle" opacity="0">[% field %]</text>
714             [% END %]
715              
716             [% px_start = x + px_end %]
717             [% pmin_scale_value = y + py_end %]
718             [% last_value_half = value_half %]
719             [% count = count + 1 %]
720              
721             [% END %]
722             [% END %]
723              
724              
725             <!-- //////////////////////////////// KEY ////////////////////////////////// -->
726              
727             [% IF config.key %]
728              
729             [% key_box_size = 12 %]
730             [% key_count = 1 %]
731             [% key_padding = 5 %]
732             [% x_off = 0 %]
733             [% y_off = 0 %]
734              
735             [% IF key_position == 'h' %]
736             <!-- position key left or right -->
737             [% IF config.key_placement == 'R' %]
738             [% x_off = x + r + x_key_start %]
739             [% y_off = (y - r) %]
740             [% ELSE %]
741             [% x_off = x_key_start %]
742             [% y_off = (y - r) %]
743             [% END %]
744             [% ELSIF key_position == 'v' %]
745             <!-- only allow key under or over chart if the height dimensions are greatest -->
746             [% IF w < h && config.key_placement == 'R' OR config.key_placement == 'L' %]
747             [% config.key_placement = 'T' %]
748             [% END %]
749             <!-- calc y position of start of key -->
750             [% y_key = padding %]
751             [% x_key = padding %]
752             [% IF key_count == 7 || key_count == 13 %]
753             <!-- wrap key every 3 entries -->
754             [% x_key = x_key + (w / 3) %]
755             [% y_key = y_key - (key_box_size * 8) - 6 %]
756             [% END %]
757             [% IF config.key_placement == 'T' %]
758             [% x_off = x_key %]
759             [% y_off = y_key %]
760             [% ELSE %]
761             [% x_off = x_key %]
762             [% y_off = (r * 2) + (padding * 2) + y_key %]
763             [% END %]
764             [% END %]
765              
766             [% FOREACH field = config.fields %]
767             [% IF total == 0 %]
768             [% percent = 0 %]
769             [% ELSE %]
770             [% percent = (100 / total) * data.0.data.$field FILTER format('%2.0f')%]
771             [% END %]
772             <rect x="[% x_off %]" y="[% y_off + (key_box_size * key_count) + (key_count * key_padding) %]" width="[% key_box_size %]" height="[% key_box_size %]" class="[% IF config.style_sheet_field_names %][% field %]_key[% ELSE %]key[% key_count %][% END %]"/>
773             <text x="[% x_off + key_box_size + key_padding %]" y="[% y_off + (key_box_size * key_count) + (key_count * key_padding) + key_box_size %]" class="keyText">[% IF config.show_key_data_labels %][% field %][% END %] [% IF config.show_key_actual_values %][[% data.0.data.$field %]][% END %] [% IF config.show_key_percent %][% percent %]%[% END %]</text>
774             [% key_count = key_count + 1 %]
775             [% END %]
776              
777             [% END %]
778              
779              
780             <!-- //////////////////////////////// MAIN TITLES ////////////////////////// -->
781              
782             <!-- main graph title -->
783             [% IF config.show_graph_title %]
784             <text x="[% x %]" y="15" class="mainTitle">[% config.graph_title %]</text>
785             [% END %]
786              
787             <!-- graph sub title -->
788             [% IF config.show_graph_subtitle %]
789             [% IF config.show_graph_title %]
790             [% y_subtitle = 30 %]
791             [% ELSE %]
792             [% y_subtitle = 15 %]
793             [% END %]
794             <text x="[% x %]" y="[% y_subtitle %]" class="subTitle">[% config.graph_subtitle %]</text>
795             [% END %]
796              
797             </svg>