File Coverage

blib/lib/SVG/Template/Graph.pm
Criterion Covered Total %
statement 94 344 27.3
branch 8 140 5.7
condition 9 89 10.1
subroutine 20 40 50.0
pod 28 28 100.0
total 159 641 24.8


line stmt bran cond sub pod time code
1             package SVG::Template::Graph;
2              
3 7     7   156261 use 5.006;
  7         27  
  7         257  
4 7     7   36 use strict;
  7         15  
  7         235  
5 7     7   45 use warnings;
  7         17  
  7         199  
6 7     7   34 use Carp;
  7         18  
  7         1095  
7 7     7   6445 use SVG::Parser;
  7         4444  
  7         43  
8 7     7   501995 use Exporter;
  7         18  
  7         396  
9 7     7   6799 use Transform::Canvas;
  7         12534  
  7         288  
10 7     7   6719 use POSIX qw(strftime);
  7         61335  
  7         168  
11              
12             our $VERSION = '1.0';
13              
14 7     7   8903 use vars qw($VERSION @ISA ); #$AUTOLOAD);
  7         26  
  7         41256  
15              
16             our @ISA = qw(SVG::Parser Exporter );
17              
18             =head1 NAME
19              
20             SVG::Template::Graph - Perl extension for generating template-driven graphs with SVG
21              
22             =head1 SYNOPSIS
23              
24             use SVG::Template::Graph;
25             $data = [
26             {
27             barGraph=>1,#
28             barSpace=>20,
29             'title'=> '1: Trace 1',
30             'data' => #hash ref containing x-val and y-val array refs
31             {
32             'x_val' =>
33             [50,100,150,200,250,
34             300,350,400,450,500,550],
35             'y_val' =>
36             [100,150,100,126,100,
37             175,100,150,120,125,100],
38              
39             },
40             'format' =>
41             { #note that these values could change for *each* trace
42             'lineGraph' => 1,
43             'x_min' => 0,
44             'x_max' => 600,
45             'y_min' => 50,
46             'y_max' => 200,
47             'x_axis' => 1, #draw x-axis
48             'y_axis' => 1, #draw y-axis
49            
50             #define the labels that provide the data context.
51             'labels' =>
52             {
53             #for year labels, we have to center the axis markers
54             'x_ticks' =>
55             {
56             'label' =>[2002,2003,2004],
57             'position'=>[100,300,500],
58             },
59             'y_ticks' =>
60             {
61             #tick mark labels
62             'label' => [ -250, 0, 250, 500],
63             #tick mark location in the data space
64             'position' => [50, 100, 150, 200],
65             },
66             },
67             },
68             },
69             ];
70              
71              
72             #construct a new SVG::Template::Graph object with a file handle
73             my $tt = SVG::Template::Graph->new($file);
74              
75             #set up the titles for the graph
76             $tt->setGraphTitle(['Hello svg graphing world','I am a subtitle']);
77            
78             #generate the traces.
79             $tt->drawTraces($data,$anchor_rectangle_id);
80             #serialize and print
81             print $tt->burn();
82              
83             =head1 DESCRIPTION
84              
85             Template::Graph:SVG is a module for the generation of template-driven
86             graphs using Scalable Vector Graphics (SVG). Using this module, it is possible
87             to define a template SVG document with containers which are populated with
88             correctly scaled plot images.
89              
90             =head2 EXPORT
91              
92             None by default.
93              
94             =head2 EXAMPLES
95              
96             Refer to the examples directory inside this distribution for working examples.
97              
98             =cut
99              
100             # Items to export into callers namespace by default. Note: do not export
101             # names by default without a very good reason. Use EXPORT_OK instead.
102             # Do not simply export all your public functions/methods/constants.
103              
104             # This allows declaration use SVG::Template::Graph ':all';
105             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
106             # will save memory.
107              
108             #our %EXPORT_TAGS = ( 'all' => [ qw() ] );
109              
110             #our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
111              
112             #our @EXPORT = qw(
113             #);
114              
115             $VERSION = eval $VERSION; # see L
116              
117             =head2 new()
118              
119             #construct a new SVG::Template::Graph object with a file handle
120             my $tt = SVG::Template::Graph->new($file);
121              
122             The constructor for the class. Takes a template file name as an argument
123              
124             =cut
125              
126             sub new ($;$;@) {
127 7     7 1 6458 my ( $proto, $file, %attrs ) = @_;
128 7   33     64 my $class = ref $proto || $proto;
129 7         18 my $self;
130              
131 7         28 my %default_attributes = %SUPER::default_attributes;
132              
133 7         30 $self->{_config_} = {};
134 7         22 $self->{_svgTree_} = {};
135 7         23 $self->{_IDCACHE_} = {};
136 7         19 $self->{graphTarget} = undef;
137              
138             # establish defaults for unspecified attributes
139 7         112 $self = $class->SUPER::new();
140 7         769758 $self->{_svgTree_} = $self->parse_uri($file);
141 7         910989 $self->{_IDMap_} = {};
142 7         157 return $self;
143             }
144              
145             =head2 burn()
146              
147             serialise the image. See SVG::xmlify for more details
148              
149             =cut
150              
151             sub burn ($;@) {
152              
153 7     7 1 30 my ( $self, %attrs ) = @_;
154 7         39 return $self->D()->xmlify(%attrs);
155             }
156              
157             =head2 setGraphTitle
158              
159             my $svg_element_ref = $tt->setGraphTitle ($string|\@strings, %attributes)
160              
161             Generate the text for the Graph Title
162             Returns the reference to the text element
163              
164             =cut
165              
166             sub setGraphTitle ($$;@) {
167 3     3 1 8 my $self = shift;
168 3         9 my $text = shift;
169 3         19 return $self->_setAxisText($self->mapTemplateId("group.graph.title"), $text, @_ );
170             }
171              
172             =head2 setTraceTitle
173              
174             set the title of a trace
175              
176             $tt->setTraceTitle( $string|\@strings, %attributes )
177              
178              
179             =cut
180              
181             sub setTraceTitle ($$$;@) {
182 2     2 1 5 my $self = shift;
183 2         4 my $ti = shift;
184 2         3 my $text = shift;
185 2         9 return $self->_setAxisText($self->mapTemplateId("group.trace.title.$ti"), $text, @_ );
186             }
187              
188             =head2 setXAxisTitle
189              
190             Generate the text for the Graph X-Axis Titles
191             Returns the reference to the text element
192              
193             $tt->setXAxisTitle($axis_number, $string, %attributes)
194             $tt->setXAxisTitle($axis_number, \@strings, %attributes)
195              
196             =cut
197              
198             sub setXAxisTitle ($$$;@) {
199 6     6 1 13 my $self = shift;
200              
201             #the trace index
202 6         11 my $ti = shift;
203 6         11 my $text = shift;
204 6         26 return $self->_setAxisText($self->mapTemplateId("group.trace.axes.title.x.$ti"), $text, @_ );
205             }
206              
207             =head2 setYAxisTitle
208              
209             Generate the text for the Graph Y-Axis Titles
210             Returns the reference to the text element
211              
212              
213             $tt->setYAxisTitle($axis_number, $string,%attributes)
214             $tt->setYAxisTitle($axis_number, \@strings,%attributes)
215              
216             =cut
217              
218             sub setYAxisTitle ($$$;@) {
219 6     6 1 14 my $self = shift;
220              
221             #the trace index
222 6         11 my $ti = shift;
223 6         8 my $text = shift;
224 6         25 return $self->_setAxisText($self->mapTemplateId("group.trace.axes.title.y.$ti"), $text, @_ );
225             }
226              
227             =head2 _gg
228              
229             Check that a group exists (is a valid, defined group in the SVG DOM) and create a group in the document if id does not exist. Return the group element
230             This ensures that even if a designer failed to generate a group ID in the drawing, you will get a drawing with the right group names.
231             If type is defined, an element of $type with %attributes is defined.
232              
233              
234             my $svg_element = $tt->_gg ($id)
235             my $svg_element = $tt->_gg ($id,'rect',width=>10,height=>10,
236             x=>10,y=>10,fill=>'none',stroke=>'red')
237              
238             =cut
239              
240             sub _gg ($$;@) {
241 18     18   27 my $self = shift;
242 18   50     52 my $id = shift || 'abc';
243 18   100     78 my $type = shift || 'group';
244 18         29 my %attrs = @_;
245 18 50       64 return $self->{_IDCACHE_}->{$id} if $self->{_IDCACHE_}->{$id};
246 18   33     49 my $d = $self->D()
247             || confess("E1000: Supplied SVG input not properly parsed!!");
248 18         143 my $tg = $d->getElementByID($id);
249 18 50       198 unless ($tg) {
250              
251 0         0 carp("element $type with id '$id' not found in document when setting a text field.");
252 0         0 $d->getRootElement()->comment("missing group $id added by pid $$ $0");
253 0         0 $tg = $d->getRootElement()->element( $type, id => $id, %attrs );
254              
255             # carp("element $type with id '$id' created under root element ");
256             }
257 18         41 $self->{_IDCACHE_}->{$id} = $tg;
258              
259             #print STDERR "Saving $tg to IDCACHE $id\n";
260 18         44 return $tg;
261             }
262              
263             =head2 _setAxisText
264              
265             Internal method called by setGraphTitle and setAxisTitle to do the actual work. Not really intended to be accessed from the outside but available for advanced users.
266              
267             $tt->_setAxisText ($id,$text|\@text,%attributes)
268              
269             =cut
270              
271             sub _setAxisText ($$$;@) {
272 17     17   74 my $self = shift;
273 17         24 my $id = shift;
274 17         21 my $text = shift;
275 17         21 my %attrs;
276 17         29 %attrs = @_;
277              
278             #check if we have an array of strings
279 17 100       58 $text = [$text] unless ( ref($text) eq 'ARRAY' );
280              
281 17 50       42 carp(
282             "No text was supplied. Either supply a string or an array reference containing strings"
283             )
284             unless scalar @$text;
285 17         45 my $tg = $self->_gg($id);
286 17   33     75 my $to = $tg->text(%attrs)
287             || carp("Failed to generate an Axis text element within group '$id'.");
288 17         1055 my %args = ( x => 0 );
289              
290 17         35 foreach my $line (@$text) {
291 28 50       115 $to->tspan(%args)->cdata($line)
292             || carp(
293             "Failed to generate an Axis tspan element within group '$id'.");
294              
295             #set the dy spacing for multi-line text
296 28         1531 $args{dy} = '1em';
297             }
298 17         102 return $to;
299             }
300              
301             =head2 struct $struct
302              
303             the input structure required by sub drawTraces to generate the graph.
304             Refer to the examples included in this distribution in the examples
305             directory for working samples.
306              
307             $struct = [{
308             'tracetype' => 'linegraph',
309             'title'=> '1: Trace 1',
310             'data' => #hash ref containing x-val and y-val array refs
311             {
312             'x_val' =>
313             [0, 2, 4,
314             6, 8, 10,
315             12,14,16,
316             18,20],
317             'y_val' =>
318             [4, 2, 5,
319             3, 7, 4 ,
320             9, 9, 2,
321             4, 3],
322             },
323             'format' =>
324             {
325             'x_max' => 600, #or for your case, the date value of the 1st point
326             'x_min' => 0, #or for your case, the date value of the last point
327             'y_max' => 0.35,
328             'y_min' => -0.1,
329             'x_title' => 'Calendar Year',
330             'y_title' => '% Annual Performance',
331             'x_axis' => 0, # do not automatically draw an x-axis
332             'y_axis' => 1, #automatically draw a y-axis
333            
334             #define the labels that provide
335             #the data context.
336             'labels' =>
337             {
338             #for year labels, we have to center the axis markers
339             'x_ticks' =>
340             {
341             'label' =>[2002,2003,2004],
342             'position' =>[100,300,500],
343             },
344             y_ticks =>
345             {
346             #tick mark label
347             'label' => [ '-10.00%', '-5.00%', '0.00%',
348             '5.00%', '10.00%', '15.00%',
349             '20.00%', '25.00%', '30.00%',
350             '35.00%' ],
351             #tick mark location in the data space
352             'position' => [-0.10,-0.5,0,
353             -.5,.10,.15,
354             .20,.25,.30,
355             .35],
356             },
357             },
358             },
359             legend_title => 'Some Interesting Data',
360             },
361             ];
362              
363             =cut
364              
365             =head2 getCanvasBoxBoundaries()
366              
367             if $id_anchor_data is an array reference, then it uses it to describe the extents of the viewbox into which the current drawing will happen.
368             If $id_anchor_data is a string then its associated xml element is assumed to be a rectangle and getCanvasBoxBoundaries uses the rectangle geometry.to define the plot bounding box.
369             hash references are not supported.
370              
371             Action: set the boundary box data in the object and returns the array reference:
372            
373             [xmin, ymin, xmax, ymax]
374              
375             =cut
376              
377             sub getCanvasBoxBoundaries ($) {
378              
379 0     0 1 0 my $self = shift;
380 0         0 my $id = $self->getGraphTarget;
381              
382 0 0       0 unless ( defined $self->{_config_}->{xmin_p} ) {
383              
384 0 0       0 if ( ref($id) eq 'ARRAY' ) {
    0          
385             (
386 0         0 $self->{_config_}->{xmin_p}, $self->{_config_}->{ymin_p},
387             $self->{_config_}->{xmax_p}, $self->{_config_}->{ymax_p}
388             )
389             = @$id;
390             } elsif ( ref($id) eq 'HASH' ) {
391 0         0 croak('getCanvasBoxBoundaries does not yet support hashes');
392              
393             } else {
394 0   0     0 my $r = $self->D()->getElementByID($id)
395             || croak("Could not find rectangle with id='$id'");
396              
397             #define the configuration data for the paperspace.
398 0         0 $self->{_config_}->{xmin_p} = $r->getAttribute('x');
399 0         0 $self->{_config_}->{xmax_p} =
400             $self->{_config_}->{xmin_p} + $r->getAttribute('width');
401 0         0 $self->{_config_}->{ymin_p} = $r->getAttribute('y');
402 0         0 $self->{_config_}->{ymax_p} =
403             $self->{_config_}->{ymin_p} + $r->getAttribute('height');
404             }
405              
406             }
407              
408             #return the reference to the array as expected by Transform::Canvas
409             return [
410 0         0 $self->{_config_}->{xmin_p}, $self->{_config_}->{ymin_p},
411             $self->{_config_}->{xmax_p}, $self->{_config_}->{ymax_p},
412             ];
413             }
414              
415             =head2 getDataBoxBoundaries (\%struct)
416              
417             returns the value of the boundary box of the data set which places the graph in the image
418             as an array reference:
419              
420             [xmin, ymin, xmax, ymax]
421              
422             =cut
423              
424             sub getDataBoxBoundaries ($$) {
425              
426 0     0 1 0 my $self = shift;
427 0         0 my $p = shift;
428              
429             return [
430 0         0 $p->{format}->{x_min}, $p->{format}->{y_min},
431             $p->{format}->{x_max}, $p->{format}->{y_max},
432             ];
433              
434             }
435              
436             =head2 drawAxis(,[x|y|undef]))
437              
438             draw one or both of axes (zero-value line) of the drawing data space. Draws both axes unless one of the axes is passed as a string.
439              
440             drawAxis('somegroupid','x') draws the x-axis line into group 'somegroupid'.
441             drawAxis('somegroupid','y') draws the y-axis line indo group 'somegroupid'
442             drawAxis('somegroupid') draws both x- and y- axis lines into group 'somegroupid'
443              
444             construction detail: draws the content into a group.
445              
446             =cut
447              
448             sub drawAxis ($$$) {
449 0     0 1 0 my $self = shift;
450 0         0 my $id = shift; #anchor id
451 0   0     0 my $o = shift || ''; #orientation
452 0         0 my $g;
453 0 0 0     0 if ( !$o || ( $o eq 'x' || $o eq 'y' ) ) {
      0        
454 0         0 $g = $self->_gg($id);
455              
456             #draw the x-axis if it appears in the canvas window
457 0 0       0 $g->line(
458             id => "x axis zero line",
459             x1 => $self->T->mapX(0),
460             y1 => $self->T->mapY( $self->T->dy0 ),
461             x2 => $self->T->mapX(0),
462             y2 => $self->T->mapY( $self->T->dy1 ),
463             )
464             if $o eq 'x';
465 0 0       0 $g->line(
466             id => "y axis zero line",
467             x1 => $self->T->mapX( $self->T->dx0 ),
468             y1 => $self->T->mapY(0),
469             x2 => $self->T->mapX( $self->T->dx1 ),
470             y2 => $self->T->mapY(0),
471             )
472             if $o eq 'y';
473 0         0 return $g;
474             }
475 0         0 return undef;
476             }
477              
478             =head2 drawTraces ($data_structure,$insertion_anchor_id)
479              
480             given a structure describing the incoming drawing parameters, generates the SVG lines, axes, and ticks and returns the number of traces that were handled.
481             If $anchor_id is defined and is a rectangle ID, then the drawing will take place in id.if $anchor_point is defined and it is an array of 4 real numbers,
482             then this will be taken to be the location where the insertion box goes.
483              
484             The format for the array is: [x0 y0 x1 y1]. in canvas dimension
485              
486             =cut
487              
488             sub drawTraces ($$) {
489 0     0 1 0 my $self = shift;
490 0         0 my $struct = shift;
491 0         0 my $insert_anchor_id = shift;
492 0 0       0 unless ($insert_anchor_id) {
493 0         0 $self->setGraphTarget;
494 0         0 $insert_anchor_id = $self->getGraphTarget;
495             }
496              
497             #make sure we got an array ref for $struct
498             croak(
499 0 0       0 "drawTrace error: expected an array at drawTraces but got something called '"
500             . ref($struct)
501             . "' with content $struct." )
502             unless ref($struct) eq 'ARRAY';
503              
504             #take the hash struct for each trace and run it through the grinder.
505             #past this point, the code goes to hell as of 2004.09.21.
506             #but this is the way to go...
507              
508 0         0 my $ti = 0;
509 0         0 foreach my $trace (@$struct) {
510 0         0 $ti++;
511 0 0       0 $self->getTracePointMap( $ti, 'path', $trace, $insert_anchor_id )
512             || croak("Failed to build trace $ti");
513             }
514              
515 0         0 return $ti;
516             }
517              
518             =head2 getTracePointMap $index, polyline|[path]|polygon, $p, $anchor_data, %args
519              
520             scales the points for lines appropriately and generates
521             the correct polyline or path or polygon element,
522             scaled and inverted to match paper space.
523              
524             if $anchor_data is defined, then it is either the id of a rectangle whose geometry will contain the results, or it is an array reference which contains the viewbox defilition [x0,y0,x1,y1] where the graph is to be placed.
525              
526             this is the method in which the generation of the graph is handled
527              
528             returns the reference of the polyline/path/polygon tag that was generated.
529              
530             =cut
531              
532             sub getTracePointMap ($$$$;@) {
533 0     0 1 0 my $self = shift;
534 0         0 my $ti = shift;
535 0         0 my $type = shift;
536 0         0 my $p = shift;
537 0         0 my $insert_anchor_id = shift;
538 0         0 my %args = @_;
539              
540 0         0 my $canvas = $self->getCanvasBoxBoundaries;
541              
542             #assign a default line drawing type
543 0 0       0 $p->{lineGraph} = 1 unless $p->{barGraph};
544 0         0 $self->{map} = Transform::Canvas->new(
545              
546             #the canvas extents limits
547             canvas => $canvas,
548              
549             #the data scape mapping to the above canvas geometry
550             data => $self->getDataBoxBoundaries($p),
551             );
552              
553 0 0       0 confess("Failed to create Canvas Transform object")
554             unless ref( $self->{map} ) eq 'Transform::Canvas';
555 0         0 my @pr = $self->{map}->map( $p->{data}->{x_val}, $p->{data}->{y_val} );
556              
557             #draw the gridlines
558 0 0       0 $self->drawGridLines( $ti, $p->{format} )
559             || warn("Error building the gridlines");
560              
561 0 0       0 $self->lineGraph( $ti, $type, \@pr, $canvas, %args ) if $p->{lineGraph};
562              
563 0 0       0 delete $args{closed} if $args{closed};
564              
565 0 0       0 if ( $p->{barGraph} ) {
566 0 0       0 $p->{data}->{x_val} =
567             ref $p->{data}->{x_val}
568             ? $p->{data}->{x_val}
569             : [ $p->{data}->{x_val} ];
570 0 0       0 $p->{data}->{y_val} =
571             ref $p->{data}->{y_val}
572             ? $p->{data}->{y_val}
573             : [ $p->{data}->{y_val} ];
574 0         0 $self->barGraph( $ti, [ $p->{data}->{x_val}, $p->{data}->{y_val} ],
575             $p->{barSpace}, %args );
576             }
577              
578 0 0       0 $self->drawAxis($self->mapTemplateId("group.trace.axes.x.$ti"), 'x' )
579             if $p->{format}->{x_axis};
580 0 0       0 $self->drawAxis($self->mapTemplateId("group.trace.axes.y.$ti"), 'y' )
581             if $p->{format}->{y_axis};
582              
583             #set the trace titles if they are specified
584 0 0       0 $self->setXAxisTitle( $ti, $p->{format}->{x_title} )
585             if defined $p->{format}->{x_title};
586 0 0       0 $self->setYAxisTitle( $ti, $p->{format}->{y_title} )
587             if defined $p->{format}->{y_title};
588 0 0       0 $self->setTraceTitle( $ti, $p->{title} ) if defined $p->{title};
589 0         0 return 1;
590             }
591              
592             =head2 lineGraph index, type, [\@x,\@y], $canvas, %styling_attributes
593              
594             draw a line graph trace
595              
596             =cut
597              
598             #draw the line graph
599             sub lineGraph ($$$$@) {
600 0     0 1 0 my $self = shift;
601 0         0 my $ti = shift;
602 0         0 my $type = shift;
603 0         0 my $points = shift;
604 0         0 my $canvas = shift;
605 0         0 my %args = @_;
606              
607 0 0 0     0 $type = 'path'
      0        
608             unless ( $type eq 'polyline'
609             || $type eq 'polygon'
610             || $type eq 'scatter' );
611 0         0 my %closed = ();
612 0 0       0 %closed = ( '-closed' => 'true' ) if ( lc( $args{closed} ) eq 'true' );
613              
614 0 0       0 delete $args{closed} if $args{closed};
615              
616             #draw the trace in the container
617 0         0 my $c_points = $self->D()->get_path(
618             x => $points->[0],
619             y => $points->[1],
620             -type => $type,
621             %closed,
622             );
623              
624             #invoke the transformation from data space to canvas space
625 0         0 my ( $min_x, $min_y, $max_x, $max_y ) = @$canvas;
626 0         0 my $id_string =$self->mapTemplateId("group.trace.data.$ti");
627 0   0     0 my $traceBase = $self->_gg($id_string)
628             || confess(
629             "Failed to find required element
630             id '$id_string'"
631             );
632 0         0 return $traceBase->$type( %$c_points, id => "trace.$ti", %args );
633             }
634              
635             #draw the bar graph
636              
637             =head2 barGraph()
638              
639             $g->barGraph( $index, [\@x,\@y], \@canvas, $barSpace, %styling_attributes)
640              
641             draw a bar graph trace
642              
643             =cut
644              
645             sub barGraph ($$$$@) {
646 0     0 1 0 my $self = shift;
647 0         0 my $ti = shift;
648              
649             #the raw points.
650 0         0 my $points = shift;
651 0         0 my $barSpace = shift;
652 0         0 my %args = @_;
653              
654 0         0 my $out = $self->getCanvasBoxBoundaries;
655              
656 0         0 my ( $min_x, $min_y, $max_x, $max_y ) = @$out;
657              
658 0         0 my $Points = scalar @{ $points->[0] };
  0         0  
659              
660 0   0     0 my $traceBase = $self->_gg("group.trace.data.$ti")
661             || confess("Failed to find required element id group.trace.data.$ti");
662              
663             #we do a simple width linerization which falls down
664             #when the bars do not span the image.
665 0 0       0 $barSpace = $barSpace ? $barSpace : $Points + 1;
666 0         0 my $width = ( $max_x - $min_x ) / $barSpace;
667              
668             #draw a rectangle for each point, with the
669             #rectangle centered on the point at the X midpoint
670             #of the rectangle.
671             #
672             #watch out for paper space inversion tricks.
673             #min_y is the bottom of the drawing (max_canvas_value)
674             #we are working in paper space
675 0         0 foreach my $index ( 0 .. $Points - 1 ) {
676              
677 0         0 my $x = $self->T->mapX( $points->[0]->[$index] ) - 0.5 * $width;
678              
679             #my $y = $self->T->mapY($points->[1]->[$index]);
680 0         0 my $y = $self->T->mapY(0);
681              
682 0         0 my $height =
683             $self->T->mapY( $points->[1]->[$index] ) - $self->T->mapY(0);
684              
685             #handle negative rectangle height
686 0 0       0 if ( $height < 0 ) {
687 0         0 $height = -$height;
688 0         0 $y = $y - $height;
689             }
690             $traceBase->rect(
691 0         0 x => $x,
692             y => $y,
693             width => $width,
694             height => $height,
695             %args
696             );
697              
698             #this is the correct top position
699             #zeros position. do not mess with this!!
700              
701             }
702             }
703              
704             =head2 drawGridLines()
705              
706             $p->drawGridLines ($target_svg_element_ref,$transformation_ref,$format_structure_ref)
707              
708             draw the gridlines for a graph as defined in the formatting data structure for each trace.
709              
710             =cut
711              
712             sub drawGridLines ($$$) {
713 0     0 1 0 my $self = shift;
714 0         0 my $ti = shift;
715 0         0 my $f = shift; #formatting data structure ($in->{format})
716              
717 0         0 my $gid = undef;
718 0         0 $gid =$self->mapTemplateId("group.trace.axes.x.$ti");
719 0   0     0 my $g_x = $self->_gg($gid)
720             || confess("Failed to find required element ID '$gid'");
721 0         0 $gid =$self->mapTemplateId("group.trace.axes.y.$ti");
722 0   0     0 my $g_y = $self->_gg($gid)
723             || confess("Failed to find required element ID '$gid'");
724              
725 0         0 $gid =$self->mapTemplateId("group.trace.axes.values.x.$ti");
726 0   0     0 my $t_x = $self->_gg($gid)
727             || confess("Failed to find required element ID '$gid'");
728 0         0 $gid =$self->mapTemplateId("group.trace.axes.values.y.$ti");
729 0   0     0 my $t_y = $self->_gg($gid)
730             || confess("Failed to find required element ID '$gid'");
731              
732 0         0 $gid =$self->mapTemplateId("group.trace.tick.$ti");
733 0   0     0 my $tk_y = $self->_gg($gid)
734             || confess("Failed to find required element ID '$gid'");
735 0   0     0 my $tk_x = $self->_gg($gid)
736             || confess("Failed to find required element ID '$gid'");
737              
738 0 0       0 croak("Format not correctly passed to drawGrid: not a hash reference")
739             unless ref($f) eq 'HASH';
740              
741             #
742             #handle labels if we have a gridlines label
743 0 0       0 if ( defined $f->{labels} ) {
744              
745             #Grid positions
746 0   0     0 $self->{grid}->{y_p} = $f->{labels}->{y_ticks}->{position} || [];
747 0   0     0 $self->{grid}->{x_p} = $f->{labels}->{x_ticks}->{position} || [];
748              
749             #grid label units
750 0   0     0 $self->{grid}->{x_u} = $f->{labels}->{x_ticks}->{unit} || '';
751 0   0     0 $self->{grid}->{y_u} = $f->{labels}->{y_ticks}->{unit} || '';
752              
753             #grid axes labels
754 0   0     0 $self->{grid}->{y_l} = $f->{labels}->{y_ticks}->{label} || [];
755 0   0     0 $self->{grid}->{x_l} = $f->{labels}->{x_ticks}->{label} || [];
756              
757             #grid count
758 0   0     0 $self->{grid}->{y_c} = scalar @{ $self->{grid}->{y_p} } || 0;
759 0   0     0 $self->{grid}->{x_c} = scalar @{ $self->{grid}->{x_p} } || 0;
760              
761 0         0 $self->handleFurnishings( 'x', $f,
762             { line => $g_x, label => $t_x, tick => $tk_x } );
763              
764             #cut line here
765 0         0 $self->handleFurnishings( 'y', $f,
766             { line => $g_y, label => $t_y, tick => $tk_y } );
767              
768             #cut line here
769             }
770 0         0 return 1;
771             }
772              
773             =head2 handleFurnishings()
774              
775              
776             $p->handleFurnishings( $orientation, $format, \%anchor_refs);
777              
778             single point for handling grid lines, gridline lables, and gridline tickmarks
779             this method is a factory method for generating vertical or horizontal furnishings for the trace
780             the anchor hash reference contains the following keys:
781            
782             line
783             label
784             tick
785              
786             parameters
787              
788             gridline orientation
789              
790             $orientation = 'x' or 'y'
791              
792             Gridline context-format hash reference
793            
794             $format - hash reference
795              
796             defines what is shown and what is not.
797              
798             whose values are svg element object references where the respective entities are to be appended as children.
799              
800             =cut
801              
802              
803             sub handleFurnishings ($$$$$) {
804              
805 0     0 1 0 my $self = shift;
806 0         0 my $o = shift;
807 0         0 my $f = shift;
808 0         0 my $anchor = shift;
809              
810 0 0 0     0 croak "Orientation should be 'x' or 'y'" unless ( $o eq 'x' or $o eq 'y' );
811 0 0       0 croak "gridPosition entry '"
812             . $self->{grid}->{"${o}_p"}
813             . "' is not an array reference"
814             unless ref $self->{grid}->{"${o}_p"} eq 'ARRAY';
815 0 0       0 croak "anchor entry is not a hash reference" unless ref $anchor eq 'HASH';
816 0 0       0 croak "formatting hash reference is not a hash reference"
817             unless ref $f eq 'HASH';
818 0 0       0 croak "gridCount '" . $self->{grid}->{"${o}_c"} . "' should be an integer"
819             if $self->{grid}->{"${o}_c"} =~ /\D+/;
820              
821             #handle each grid position one at a time
822 0         0 my $i = 0;
823 0         0 my $tick = $self->getTick( $f->{labels}, $o );
824              
825 0         0 foreach $i ( 0 .. $self->{grid}->{"${o}_c"} - 1 ) {
826              
827             #we only draw if the position data is defined
828 0 0       0 last unless defined $self->{grid}->{"${o}_p"}->[$i];
829              
830             #y-value of the constant-y grid line
831 0         0 $anchor->{line}->comment("Gridlines $i for $o");
832 0         0 $self->drawGridLine( $o, $i, { anchor => $anchor->{line}, }, );
833 0         0 $anchor->{label}->comment("Labels $i for $o");
834 0         0 $self->drawGridLabel( $o, $i, { anchor => $anchor->{label}, }, );
835 0         0 $anchor->{tick}->comment("Tick marks $i for $o");
836 0         0 $self->drawTick( $o, $i, $tick, { anchor => $anchor->{tick}, }, );
837             }
838 0         0 return $i;
839             }
840              
841             =head2 drawGridLine()
842              
843             draw a single grid line
844              
845             =cut
846              
847             sub drawGridLine ($$$$) {
848 0     0 1 0 my $self = shift;
849 0   0     0 my $o = shift || 'x';
850 0         0 my $i = shift;
851 0         0 my $args = shift;
852              
853             #set the data values into the object for future use
854             # $self->{grid}->{line}->{dx}
855             # $self->{grid}->{line}->{dy}
856 0 0       0 $self->{grid}->{line}->{"d$o"} =
857             defined $self->{grid}->{"${o}_p"}
858             ? $self->{grid}->{"${o}_p"}->[$i]
859             : ( $self->T->dy1 - $self->T->dy0 ) * $i / $self->{grid}->{"${o}_c"};
860              
861             #convert to canvas values and define:
862             # $self->{grid}->{line}->{cx}
863             # $self->{grid}->{line}->{cy}
864 0 0       0 $self->{grid}->{line}->{"c$o"} =
865             $o eq 'y'
866             ? $self->T->mapY( $self->{grid}->{line}->{"d$o"} )
867             : $self->T->mapX( $self->{grid}->{line}->{"d$o"} );
868              
869 0 0       0 $args->{anchor}->line(
    0          
    0          
    0          
870             y1 => $o eq 'y' ? $self->{grid}->{line}->{cy} : $self->T->cy0,
871             x1 => $o eq 'y' ? $self->T->cx0 : $self->{grid}->{line}->{cx},
872             y2 => $o eq 'y' ? $self->{grid}->{line}->{cy} : $self->T->cy1,
873             x2 => $o eq 'y' ? $self->T->cx1 : $self->{grid}->{line}->{cx},
874             );
875             }
876              
877             =head2 drawTick()
878              
879             $p->drawTick( ['x'|'y'], $index, $tick, $args, %attrs);
880              
881             tickmark-generation handler
882              
883             =cut
884              
885             sub drawTick ($$$$$;@) {
886 0     0 1 0 my $self = shift;
887 0   0     0 my $o = shift || 'x';
888 0         0 my $i = shift;
889 0         0 my $tick = shift;
890 0         0 my $args = shift;
891 0         0 my %attrs = @_;
892              
893             #do nothing unless the tickmarks are required,
894 0 0       0 return undef unless defined $tick;
895              
896             #$self->{grid}->{line}->{"d$o"} = defined $args->{GridPosition} ?
897             # $self->{GridPosition}->[$i] :
898             # ($t->dy1 - $t->dy0)*$i/$args->{GridCount};
899              
900             #convert to canvas values
901             #$self->{grid}->{line}->{"c$o"} = $o eq 'y' ?
902             # $t->mapY($self->{grid}->{line}->{"d$o"} :
903             # $t->mapX($x_line);
904              
905             #handle the front and back ticks
906 0         0 my %hash;
907 0 0       0 if ( $tick->[0] ) {
908 0         0 my ( $x, $y ) = ( $self->T->cx0, $self->T->cy0 );
909 0 0       0 %hash = (
    0          
    0          
    0          
910              
911             y1 => $o eq 'y' ? $self->{grid}->{line}->{cy} : $y,
912             y2 => $o eq 'y' ? $self->{grid}->{line}->{cy} : $y - $tick->[0],
913             x1 => $o eq 'y' ? $x : $self->{grid}->{line}->{cx},
914             x2 => $o eq 'y' ? $x - $tick->[0] : $self->{grid}->{line}->{cx},
915             );
916 0         0 $args->{anchor}->line( %hash, %attrs );
917             }
918 0 0       0 if ( $tick->[1] ) {
919 0         0 my ( $x, $y ) = ( $self->T->cx1, $self->T->cy1 );
920 0 0       0 %hash = (
    0          
    0          
    0          
921              
922             y1 => $o eq 'y' ? $self->{grid}->{line}->{cy} : $y,
923             y2 => $o eq 'y' ? $self->{grid}->{line}->{cy} : $y + $tick->[1],
924             x1 => $o eq 'y' ? $x : $self->{grid}->{line}->{cx},
925             x2 => $o eq 'y' ? $x + $tick->[1] : $self->{grid}->{line}->{cx},
926             );
927 0         0 $args->{anchor}->line( %hash, %attrs );
928             }
929             }
930              
931             =head2 drawGridLabel()
932              
933             grid lable generator
934              
935             =cut
936              
937             sub drawGridLabel ($$$$) {
938 0     0 1 0 my $self = shift;
939 0         0 my $o = shift;
940 0         0 my $i = shift;
941 0         0 my $args = shift;
942              
943 0         0 my $c = $self->{grid}->{line}->{"c$o"};
944 0         0 my $d = $self->{grid}->{line}->{"d$o"};
945 0 0       0 my $string =
946             defined $args->{grid}->{"${o}_u"}
947             ? $self->{grid}->{"${o}_l"}->[$i] . " " . $args->{grid}->{"${o}_u"}
948             : $self->{grid}->{"${o}_l"}->[$i];
949              
950             #decide what to print as a gridline label
951 0 0       0 my $thistext = defined $self->{grid}->{"${o}_l"}
952             ? #if labels are defined
953             $string
954             : $self->{grid}->{line}->{"d$o"}; #use data positions instead
955 0         0 $thistext =~ s/\s$//;
956              
957 0 0       0 return $o eq 'y'
958             ? $args->{anchor}
959             ->text( y => $self->{grid}->{line}->{cy}, x => $self->T->cx0, )
960             ->cdata($thistext)
961             : $args->{anchor}
962             ->text( x => $self->{grid}->{line}->{cx}, y => $self->T->cy0, )
963             ->cdata($thistext);
964              
965             # $args->{anchor}->line(
966             # y1=> $o eq 'y' ? $self->{grid}->{line}->{cy} : $t->cy0,
967             # x1=> $o eq 'y' ? $t->cx0 : $self->{grid}->{line}->{cx},
968             # y2=> $o eq 'y' ? $self->{grid}->{line}->{cy} : $t->cy1,
969             # x2=> $o eq 'y' ? $t->cx1 : $self->{grid}->{line}->{y},
970             # );
971              
972             }
973              
974             =head2 getTick($label_ref $oation)
975              
976             return the front and back extensions to lines based on the definition (or lack of) tickmarks in the label construct
977              
978             Example of a label definition:
979              
980             $label = {
981             'y_ticks' => {
982             'style' => {
983             'right' => '10'
984             },
985             'position' => [
986             '150',
987             '100',
988             '0',
989             '-75'
990             ],
991             'label' => [
992             'Much',
993             'Some',
994             'None',
995             'Lost'
996             ]
997             },
998             'x_ticks' => {}
999             };
1000              
1001             =cut
1002              
1003             sub getTick($$$) {
1004 0     0 1 0 my $self = shift;
1005 0         0 my $l = shift;
1006 0         0 my $o = shift;
1007 0         0 $o = lc($o);
1008 0 0       0 $o = 'x' unless $o eq 'y';
1009              
1010 0         0 my $extender = [ 0, 0 ];
1011              
1012 0 0       0 return undef unless defined $l->{"${o}_ticks"}->{style};
1013              
1014 0         0 my %map = (
1015             x => [ 'top', 'bottom' ],
1016             y => [ 'left', 'right' ]
1017             );
1018              
1019 0         0 my $one = $map{$o}->[0];
1020 0         0 my $two = $map{$o}->[1];
1021              
1022             #handle constant-x (vertical) gridlines
1023 0 0       0 $extender->[0] =
1024             defined $l->{"${o}_ticks"}->{style}->{$one}
1025             ? $l->{"${o}_ticks"}->{style}->{$one}
1026             : 0;
1027 0 0       0 $extender->[1] =
1028             defined $l->{"${o}_ticks"}->{style}->{$two}
1029             ? $l->{"${o}_ticks"}->{style}->{$two}
1030             : 0;
1031 0         0 return $extender;
1032             }
1033              
1034             =head2 D
1035              
1036             $self->D()
1037              
1038             returns the SVG Document object
1039              
1040             =cut
1041              
1042             sub D ($) {
1043 25     25 1 38 my $self = shift;
1044 25         146 return $self->{_svgTree_};
1045             }
1046              
1047             =head2 T($name)
1048              
1049             $self->T($name)
1050              
1051             returns the currently invoked transformation object. Returns transformation object $name if requested by name
1052              
1053             =cut
1054              
1055             sub T ($;$) {
1056 0     0 1 0 my $self = shift;
1057 0         0 my $name = shift;
1058 0 0       0 return $self->{maps}->{$name} if defined $name;
1059 0         0 return $self->{map};
1060             }
1061              
1062             =head2 setGraphTarget $targetid, $elementType , %element_attributes
1063              
1064             define the graph target (currently only rectangles are accepted) on top of which the data will be drawn
1065              
1066             =cut
1067              
1068             sub setGraphTarget ($$;@) {
1069 1     1 1 3 my $self = shift;
1070 1   33     9 $self->{graphTarget} = shift || $self->mapTemplateId('rectangle.graph.data.space');
1071 1   50     7 my $type = shift || 'rect';
1072 1         7 return $self->_gg( $self->{graphTarget}, $type, @_ );
1073             }
1074              
1075             =head2 getGraphTarget
1076              
1077             returns the current graph target
1078              
1079             =cut
1080              
1081             sub getGraphTarget ($) {
1082 0     0 1 0 my $self = shift;
1083 0         0 return $self->{graphTarget};
1084             }
1085              
1086             =head2 autoGrid (int $min, int $max, int $count)
1087              
1088             generates a reference to an array of $count+1 evenly distributed values ranging between $min and $max
1089              
1090             $tt->autoGrid(0,100,10);
1091              
1092             =cut
1093              
1094             sub autoGrid ($$$) {
1095 0     0 1 0 my $self = shift;
1096 0         0 my ( $min, $max, $count ) = @_;
1097 0         0 my @array = ( 0 .. $count );
1098 0         0 map { $_ = ( $max - $min ) / ($count) * $_ } @array;
  0         0  
1099              
1100             #print STDERR Dumper \@array;
1101 0         0 return \@array;
1102             }
1103              
1104             =head2 Format
1105              
1106             format an array of values according to formatting rules
1107              
1108             $tt->Format \@array,$format,$format_attribute[,@more_format_attributes]
1109              
1110             $format can be 'time' or 'printf'
1111              
1112             for 'time', uses the Time::localtime
1113              
1114             example 1: formatting to print the verbose date
1115              
1116             $a = [
1117             '0',
1118             '2.75',
1119             '5.5',
1120             '8.25',
1121             '11'
1122             ];
1123              
1124             my $b = $tt->Format($a,'time',"%a %b %e %H:%M:%S %Y");
1125            
1126             returns
1127              
1128             $b = [
1129             'Thu Jan 1 01:00:00 1970',
1130             'Thu Jan 1 01:00:02 1970',
1131             'Thu Jan 1 01:00:05 1970',
1132             'Thu Jan 1 01:00:08 1970',
1133             'Thu Jan 1 01:00:11 1970'
1134             ];
1135              
1136             Format uses POSIX function b
1137             Refer to L for more information on time formating.
1138            
1139             example 2: formatting to print to three decimal places using sprintf
1140            
1141             $tt->Format([1.123,2.1234,3.12345,4.123456],'sprintf','%.3f');
1142              
1143             example 3: formatting to print a percent sign
1144            
1145             $tt->Format([1.123,2.1234,3.12345,4.123456],'sprintf','%%');
1146              
1147              
1148             =cut
1149              
1150             sub Format ($$$;@) {
1151 0     0 1 0 my $self = shift;
1152 0         0 my $array = shift;
1153 0   0     0 my $format = shift || 'sprintf';
1154 0   0     0 my $fmt = shift || '%.3f';
1155 0         0 my @attrs = @_;
1156 0 0       0 if ( $format eq 'time' ) {
    0          
    0          
1157 0         0 map { $_ = strftime( $fmt, _getLocalTime($_) ) } @$array;
  0         0  
1158             } elsif ( $format eq 'printf' ) {
1159 0         0 map { $_ = printf( $fmt, $_ ) } @$array;
  0         0  
1160             } elsif ( $format eq 'sprintf' ) {
1161 0         0 map { $_ = sprintf( $fmt, $_ ) } @$array;
  0         0  
1162             } else {
1163 0         0 print STDERR "processing default\n";
1164             }
1165 0         0 return $array;
1166             }
1167              
1168             sub _getLocalTime ($) {
1169 0     0   0 my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
1170             localtime(shift @_);
1171 0         0 return ( $sec, $min, $hour, $mday, $mon, $year , $wday, $yday,
1172             $isdst );
1173             }
1174              
1175             =head2 mapTemplateId string $id
1176              
1177             =cut
1178              
1179             sub mapTemplateId ($$) {
1180 17     17 1 30 my $self = shift;
1181 17         25 my $myid = shift;
1182 17 50       51 unless (defined $myid) {
1183 0         0 carp "undefined xml ID! Setting to 'unknown'" . join (":",caller()) ;
1184 0         0 $myid = 'unknown';
1185 0         0 $self->{_IDMap_}->{$myid} = $myid;
1186             }
1187 17 50       64 unless ($self->{_IDMap_}->{$myid}) {
1188 17         3882 carp "Undeclared xml ID $myid! Adding to ID list";
1189 17         2185 $self->{_IDMap_}->{$myid} = $myid;
1190             }
1191             # getIdMap unless $self->{_IDMap_};
1192 17         957 print STDERR "$myid = $self->{_IDMap_}->{$myid}\n";
1193 17   33     168 return $self->{_IDMap_}->{$myid} || $myid;
1194             }
1195              
1196             =head2 setTemplateIdMap hash template_pairs
1197              
1198             assign the definitions between the internal keys and the ids in the template at hand.
1199             This method need not be called as all IDs automatically get run through if the default IDs specified below are used.
1200              
1201             =cut
1202              
1203              
1204             sub setTemplateIdMap ($@) {
1205 0     0 1   my $self = shift;
1206 0           my %TemplateMap = @_;
1207 0           $self->{_IDMap_} = \%TemplateMap;
1208             }
1209              
1210             =head2 simpleGraph string $id, string $type, hash %attrs
1211              
1212             =cut
1213              
1214             sub simpleGraph ($$$@) {
1215 0     0 1   my $self = shift;
1216 0           my $id = shift;
1217 0           my $type = shift;
1218 0           my %attrs = @_;
1219 0           my $d = $self->D;
1220              
1221 0           my $g = $d->group( id => $id, 'text-anchor' => 'middle' );
1222 0           $g->comment(
1223             "drawing element which defines the graph boundaries for graph $id");
1224 0           my $graph = $g->rect(%attrs);
1225 0           my $cy = $graph->getAttribute('x') + $graph->getAttribute('width') / 2;
1226 0           my $cx = $graph->getAttribute('y') / 2;
1227 0           $g->group(
1228             id =>$self->mapTemplateId("group.graph.title"),
1229             class =>$self->mapTemplateId("group.graph.title"),
1230             transform => "translate($cx,$cy)",
1231             )->comment("the graph title");
1232 0           my $t = $g->group( id =>$self->mapTemplateId("group.trace"), );
1233 0           $t->comment("the trace group");
1234 0           $t->group(
1235             id =>$self->mapTemplateId("group.trace.1"),
1236             class =>$self->mapTemplateId("group.trace"),
1237             transform => "translate($cx,$cy)",
1238             )->comment("trace 1");
1239              
1240 0           $t->group(
1241             id =>$self->mapTemplateId("group.trace.title.1"),
1242             class =>$self->mapTemplateId("group.trace.title"),
1243             )->comment("the trace title");
1244 0           $t->group(
1245             id =>$self->mapTemplateId("group.trace.tick.1"),
1246             class =>$self->mapTemplateId("group.trace.tick"),
1247             )->comment("the trace ticks");
1248 0           my $a = $t->group(
1249             id =>$self->mapTemplateId("group.trace.axes.1"),
1250             class =>$self->mapTemplateId("group.trace.axes"),
1251             );
1252 0           $a->group(
1253             id =>$self->mapTemplateId("group.trace.axes.x.1"),
1254             class =>$self->mapTemplateId("group.trace.axes.x"),
1255             )->comment("the trace x axes");
1256 0           $a->group(
1257             id =>$self->mapTemplateId("group.trace.axes.y.1"),
1258             class =>$self->mapTemplateId("group.trace.axes.y"),
1259             )->comment("the trace y axes");
1260 0           $a->group(
1261             id =>$self->mapTemplateId("group.trace.axes.values.x.1"),
1262             class =>$self->mapTemplateId("group.trace.axes.values.x"),
1263             )->comment("the trace axes values in y axis");
1264 0           $a->group(
1265             id =>$self->mapTemplateId("group.trace.axes.values.y.1"),
1266             class =>$self->mapTemplateId("group.trace.axes.values.y"),
1267             )->comment("the trace axes values in y axis");
1268              
1269 0           $a->group(
1270             id =>$self->mapTemplateId("group.trace.axes.titles.x.1"),
1271             class =>$self->mapTemplateId("group.trace.axes.titles.x"),
1272             )->comment("the trace axes titles in x axis");
1273 0           $a->group(
1274             id =>$self->mapTemplateId("group.trace.axes.titles.y.1"),
1275             class =>$self->mapTemplateId("group.trace.axes.titles.y"),
1276             )->comment("the trace axes titles in y axis");
1277             }
1278              
1279             my $dump = qq {
1280            
1281            
1282            
1283             stroke="black" stroke-width="2">
1284            
1285            
1286            
1287             stroke="#333333" stroke-width="0.5"
1288             fill="#411DA4"/>
1289            
1290             stroke="gray" stroke-width="1"/>
1291            
1292             stroke="black" stroke-width="1.5"/>
1293            
1294             stroke="none" fill="black">
1295            
1296             fill="none" stroke-width="1"/>
1297            
1298             fill="none" stroke-width="1"/>
1299            
1300             stroke="none" fill="black" transform="translate(0,265)"/>
1301            
1302             fill="black" text-anchor="start" transform="translate(-40,0)"/>
1303            
1304             transform="translate(365,370)" font-size="12"
1305             fill="#411DA4" font-weight="Bold"/>
1306            
1307             transform="translate(40,200)">
1308            
1309             transform="rotate(-90)" font-weight="Bold"
1310             font-size="12" fill="#411DA4"/>
1311            
1312            
1313            
1314            
1315              
1316             };
1317              
1318             #module placeholder
1319             1;
1320              
1321             =head2 TEMPLATE
1322              
1323             To draw a graph, a template is required which contains two key datasets: a rectangle which will contain the inserted graph data and a group containing child group elements with the IDs expected by SVG::Template::Graph
1324              
1325              
1326             =head3 REQUIRED RECT ELEMENT
1327              
1328              
1329              
1330             =head3 REQUIRED GRAPH TRACE HANDLER
1331              
1332             The svg snippet below provides the required groups for the generation of the first trace (trace intex 0)
1333              
1334             Because SVG uses the Painter's model, the image rendering order
1335             follows the XML document order. For the snippet below,
1336             the rendering order is the following:
1337              
1338             data,grid,ticks,
1339             axes:x,y,
1340             axes values:
1341             x,y,
1342             axes text:
1343             x,y,
1344             axes titles:
1345             x,y
1346              
1347             Trace generation snippet
1348              
1349            
1350            
1351             stroke="black" stroke-width="2">
1352            
1353            
1354             stroke="#333333" stroke-width="0.5"
1355             fill="#411DA4"/>
1356            
1357             stroke="gray" stroke-width="1"/>
1358            
1359             stroke="black" stroke-width="1.5"/>
1360            
1361             stroke="none" fill="black">
1362            
1363             fill="none" stroke-width="1"/>
1364            
1365             fill="none" stroke-width="1"/>
1366            
1367             stroke="none" fill="black" transform="translate(0,265)"/>
1368            
1369             fill="black" text-anchor="start" transform="translate(-40,0)"/>
1370            
1371             transform="translate(365,370)" font-size="12"
1372             fill="#411DA4" font-weight="Bold"/>
1373            
1374             transform="translate(40,200)">
1375            
1376             transform="rotate(-90)" font-weight="Bold"
1377             font-size="12" fill="#411DA4"/>
1378            
1379            
1380            
1381            
1382              
1383             In order to show the trace in front of the gridlines, the above snippet changes to:
1384              
1385            
1386            
1387             stroke="black" stroke-width="2">
1388            
1389             stroke="gray" stroke-width="1"/>
1390            
1391             stroke="black" stroke-width="1.5"/>
1392            
1393             stroke="none" fill="black">
1394            
1395             fill="none" stroke-width="1"/>
1396            
1397             fill="none" stroke-width="1"/>
1398            
1399             stroke="none" fill="black" transform="translate(0,265)"/>
1400            
1401             fill="black" text-anchor="start" transform="translate(-40,0)"/>
1402            
1403             transform="translate(365,370)" font-size="12"
1404             fill="#411DA4" font-weight="Bold"/>
1405            
1406             transform="translate(40,200)">
1407            
1408             transform="rotate(-90)" font-weight="Bold"
1409             font-size="12" fill="#411DA4"/>
1410            
1411            
1412            
1413            
1414            
1415            
1416              
1417              
1418             =head2 EXAMPLES
1419              
1420             Refer to the examples directory inside this distribution for working examples.
1421              
1422             =head1 SEE ALSO
1423              
1424             L L L L L L
1425             L L
1426              
1427             =head1 AUTHOR
1428              
1429             Ronan Oger, Eronan.oger@roitsystems.com L L
1430              
1431             =head1 CREDITS
1432              
1433             This library was developed and written by Ronan Oger, ROIT Systems Gmbh, under contract to Digital Craftsmen.
1434              
1435             =head1 COPYRIGHT
1436              
1437             Copyright (C) 2004 by Ronan Oger, ROIT Systems GmbH, Zurich, Switzerland
1438              
1439             Copyright (C) 2004 by Digital Craftsmen Ltd, London, UK
1440              
1441             =head1 LICENSE
1442              
1443             This library is free software; you can redistribute it and/or modify
1444             it under the same terms as Perl itself, either Perl version 5.8.3 or,
1445             at your option, any later version of Perl 5 you may have available.
1446              
1447             =cut
1448              
1449             1;
1450              
1451             __END__