File Coverage

blib/lib/Tk/ForDummies/Graph/Areas.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 100.0


line stmt bran cond sub pod time code
1             package Tk::ForDummies::Graph::Areas;
2            
3 1     1   1941 use warnings;
  1         3  
  1         51  
4 1     1   6 use strict;
  1         2  
  1         31  
5 1     1   5 use Carp;
  1         2  
  1         85  
6            
7             #==================================================================
8             # Author : Djibril Ousmanou
9             # Copyright : 2010
10             # Update : 19/06/2010 22:47:48
11             # AIM : Create area graph
12             #==================================================================
13            
14 1     1   7 use vars qw($VERSION);
  1         2  
  1         52  
15             $VERSION = '1.10';
16            
17 1     1   6 use base qw/Tk::Derived Tk::Canvas::GradientColor/;
  1         1  
  1         672  
18             use Tk::Balloon;
19            
20             use Tk::ForDummies::Graph::Utils qw (:DUMMIES :DISPLAY);
21             use Tk::ForDummies::Graph qw (:DUMMIES);
22            
23             Construct Tk::Widget 'Areas';
24            
25             sub Populate {
26            
27             my ( $CompositeWidget, $RefParameters ) = @_;
28            
29             # Get initial parameters
30             $CompositeWidget->{RefInfoDummies} = _InitConfig();
31            
32             $CompositeWidget->SUPER::Populate($RefParameters);
33            
34             $CompositeWidget->Advertise( 'GradientColor' => $CompositeWidget );
35             $CompositeWidget->Advertise( 'canvas' => $CompositeWidget->SUPER::Canvas );
36             $CompositeWidget->Advertise( 'Canvas' => $CompositeWidget->SUPER::Canvas );
37            
38             # remove highlightthickness if necessary
39             unless ( exists $RefParameters->{-highlightthickness} ) {
40             $CompositeWidget->configure( -highlightthickness => 0 );
41             }
42            
43             # ConfigSpecs
44             $CompositeWidget->ConfigSpecs(
45             -title => [ 'PASSIVE', 'Title', 'Title', undef ],
46             -titlecolor => [ 'PASSIVE', 'Titlecolor', 'TitleColor', 'black' ],
47             -titlefont =>
48             [ 'PASSIVE', 'Titlefont', 'TitleFont', $CompositeWidget->{RefInfoDummies}->{Font}{DefaultTitle} ],
49             -titleposition => [ 'PASSIVE', 'Titleposition', 'TitlePosition', 'center' ],
50             -titleheight =>
51             [ 'PASSIVE', 'Titleheight', 'TitleHeight', $CompositeWidget->{RefInfoDummies}->{Title}{Height} ],
52            
53             -xlabel => [ 'PASSIVE', 'Xlabel', 'XLabel', undef ],
54             -xlabelcolor => [ 'PASSIVE', 'Xlabelcolor', 'XLabelColor', 'black' ],
55             -xlabelfont =>
56             [ 'PASSIVE', 'Xlabelfont', 'XLabelFont', $CompositeWidget->{RefInfoDummies}->{Font}{DefaultLabel} ],
57             -xlabelposition => [ 'PASSIVE', 'Xlabelposition', 'XLabelPosition', 'center' ],
58             -xlabelheight => [
59             'PASSIVE', 'Xlabelheight',
60             'XLabelHeight', $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{xlabelHeight}
61             ],
62             -xlabelskip => [ 'PASSIVE', 'Xlabelskip', 'XLabelSkip', 0 ],
63            
64             -xvaluecolor => [ 'PASSIVE', 'Xvaluecolor', 'XValueColor', 'black' ],
65             -xvaluevertical => [ 'PASSIVE', 'Xvaluevertical', 'XValueVertical', 0 ],
66             -xvaluespace => [
67             'PASSIVE', 'Xvaluespace',
68             'XValueSpace', $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{ScaleValuesHeight}
69             ],
70             -xvalueview => [ 'PASSIVE', 'Xvalueview', 'XValueView', 1 ],
71             -yvalueview => [ 'PASSIVE', 'Yvalueview', 'YValueView', 1 ],
72             -xvaluesregex => [ 'PASSIVE', 'Xvaluesregex', 'XValuesRegex', qr/.+/ ],
73            
74             -ylabel => [ 'PASSIVE', 'Ylabel', 'YLabel', undef ],
75             -ylabelcolor => [ 'PASSIVE', 'Ylabelcolor', 'YLabelColor', 'black' ],
76             -ylabelfont =>
77             [ 'PASSIVE', 'Ylabelfont', 'YLabelFont', $CompositeWidget->{RefInfoDummies}->{Font}{DefaultLabel} ],
78             -ylabelposition => [ 'PASSIVE', 'Ylabelposition', 'YLabelPosition', 'center' ],
79             -ylabelwidth => [
80             'PASSIVE', 'Ylabelwidth',
81             'YLabelWidth', $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{ylabelWidth}
82             ],
83            
84             -yvaluecolor => [ 'PASSIVE', 'Yvaluecolor', 'YValueColor', 'black' ],
85            
86             -labelscolor => [ 'PASSIVE', 'Labelscolor', 'LabelsColor', undef ],
87             -valuescolor => [ 'PASSIVE', 'Valuescolor', 'ValuesColor', undef ],
88             -textcolor => [ 'PASSIVE', 'Textcolor', 'TextColor', undef ],
89             -textfont => [ 'PASSIVE', 'Textfont', 'TextFont', undef ],
90            
91             -boxaxis => [ 'PASSIVE', 'Boxaxis', 'BoxAxis', 0 ],
92             -noaxis => [ 'PASSIVE', 'Noaxis', 'NoAxis', 0 ],
93             -zeroaxisonly => [ 'PASSIVE', 'Zeroaxisonly', 'ZeroAxisOnly', 0 ],
94             -zeroaxis => [ 'PASSIVE', 'Zeroaxis', 'ZeroAxis', 0 ],
95             -longticks => [ 'PASSIVE', 'Longticks', 'LongTicks', 0 ],
96            
97             -xtickheight => [
98             'PASSIVE', 'Xtickheight',
99             'XTickHeight', $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{TickHeight}
100             ],
101             -xtickview => [ 'PASSIVE', 'Xtickview', 'XTickView', 1 ],
102            
103             -yticknumber => [
104             'PASSIVE', 'Yticknumber',
105             'YTickNumber', $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{TickNumber}
106             ],
107             -ytickwidth =>
108             [ 'PASSIVE', 'Ytickwidth', 'YtickWidth', $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{TickWidth} ],
109             -ytickview => [ 'PASSIVE', 'Ytickview', 'YTickView', 1 ],
110            
111             -alltickview => [ 'PASSIVE', 'Alltickview', 'AllTickView', 1 ],
112            
113             -width => [ 'SELF', 'width', 'Width', $CompositeWidget->{RefInfoDummies}->{Canvas}{Width} ],
114             -height => [ 'SELF', 'height', 'Height', $CompositeWidget->{RefInfoDummies}->{Canvas}{Height} ],
115            
116             -linewidth => [ 'PASSIVE', 'Linewidth', 'LineWidth', 1 ],
117             -colordata =>
118             [ 'PASSIVE', 'Colordata', 'ColorData', $CompositeWidget->{RefInfoDummies}->{Legend}{Colors} ],
119             -viewsection => [ 'PASSIVE', 'Viewsection', 'ViewSection', 1 ],
120             -outlinearea => [ 'PASSIVE', 'Outlinearea', 'OutlineArea', 'black' ],
121             );
122            
123             $CompositeWidget->Delegates( DEFAULT => $CompositeWidget, );
124            
125             # recreate graph after widget resize
126             $CompositeWidget->enabled_automatic_redraw();
127             $CompositeWidget->disabled_gradientcolor();
128             }
129            
130             sub _Balloon {
131             my ($CompositeWidget) = @_;
132            
133             # balloon defined and user want to stop it
134             if ( defined $CompositeWidget->{RefInfoDummies}->{Balloon}{Obj}
135             and $CompositeWidget->{RefInfoDummies}->{Balloon}{State} == 0 )
136             {
137             $CompositeWidget->_DestroyBalloonAndBind();
138             return;
139             }
140            
141             # balloon not defined and user want to stop it
142             elsif ( $CompositeWidget->{RefInfoDummies}->{Balloon}{State} == 0 ) {
143             return;
144             }
145            
146             # balloon defined and user want to start it again (may be new option)
147             elsif ( defined $CompositeWidget->{RefInfoDummies}->{Balloon}{Obj}
148             and $CompositeWidget->{RefInfoDummies}->{Balloon}{State} == 1 )
149             {
150            
151             # destroy the balloon, it will be re create above
152             $CompositeWidget->_DestroyBalloonAndBind();
153             }
154            
155             # Balloon creation
156             $CompositeWidget->{RefInfoDummies}->{Balloon}{Obj} = $CompositeWidget->Balloon(
157             -statusbar => $CompositeWidget,
158             -background => $CompositeWidget->{RefInfoDummies}->{Balloon}{Background},
159             );
160             $CompositeWidget->{RefInfoDummies}->{Balloon}{Obj}->attach(
161             $CompositeWidget,
162             -balloonposition => 'mouse',
163             -msg => $CompositeWidget->{RefInfoDummies}->{Legend}{MsgBalloon},
164             );
165            
166             # no legend, no bind
167             unless ( my $LegendTextNumber = $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend} ) {
168             return;
169             }
170            
171             # bind legend and lines
172             for my $IndexLegend ( 1 .. $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend} ) {
173            
174             my $LegendTag = $IndexLegend . $CompositeWidget->{RefInfoDummies}->{TAGS}{Legend};
175             my $LineTag = $IndexLegend . $CompositeWidget->{RefInfoDummies}->{TAGS}{Line};
176            
177             $CompositeWidget->bind(
178             $LegendTag,
179             '',
180             sub {
181             my $OtherColor = $CompositeWidget->{RefInfoDummies}->{Balloon}{ColorData}->[0];
182            
183             # Change color if line have the same color
184             if ( $OtherColor eq $CompositeWidget->{RefInfoDummies}{Line}{$LineTag}{color} ) {
185             $OtherColor = $CompositeWidget->{RefInfoDummies}->{Balloon}{ColorData}->[1];
186             }
187             $CompositeWidget->itemconfigure(
188             $LineTag,
189             -fill => $OtherColor,
190             -width => $CompositeWidget->cget( -linewidth )
191             + $CompositeWidget->{RefInfoDummies}->{Balloon}{MorePixelSelected},
192             );
193             }
194             );
195            
196             $CompositeWidget->bind(
197             $LegendTag,
198             '',
199             sub {
200             $CompositeWidget->itemconfigure(
201             $LineTag,
202             -fill => $CompositeWidget->{RefInfoDummies}{Line}{$LineTag}{color},
203             -width => $CompositeWidget->cget( -linewidth )
204             );
205            
206             # Allow dash line to display
207             $CompositeWidget->itemconfigure( $CompositeWidget->{RefInfoDummies}->{TAGS}{DashLines},
208             -fill => 'black', );
209             }
210             );
211             }
212            
213             return;
214             }
215            
216             sub set_legend {
217             my ( $CompositeWidget, %InfoLegend ) = @_;
218            
219             my $RefLegend = $InfoLegend{-data};
220             unless ( defined $RefLegend ) {
221             $CompositeWidget->_error(
222             "Can't set -data in set_legend method. "
223             . "May be you forgot to set the value\n"
224             . "Ex : set_legend( -data => ['legend1', 'legend2', ...] );",
225             1
226             );
227             }
228            
229             unless ( defined $RefLegend and ref($RefLegend) eq 'ARRAY' ) {
230             $CompositeWidget->_error(
231             "Can't set -data in set_legend method. Bad data\n"
232             . "Ex : set_legend( -data => ['legend1', 'legend2', ...] );",
233             1
234             );
235             }
236            
237             if ( defined $InfoLegend{-title} ) {
238             $CompositeWidget->{RefInfoDummies}->{Legend}{title} = $InfoLegend{-title};
239             }
240             else {
241             undef $CompositeWidget->{RefInfoDummies}->{Legend}{title};
242             $CompositeWidget->{RefInfoDummies}->{Legend}{HeightTitle} = 5;
243             }
244             $CompositeWidget->{RefInfoDummies}->{Legend}{titlefont} = $InfoLegend{-titlefont}
245             || $CompositeWidget->{RefInfoDummies}->{Font}{DefaultLegendTitle};
246             $CompositeWidget->{RefInfoDummies}->{Legend}{legendfont} = $InfoLegend{-legendfont}
247             || $CompositeWidget->{RefInfoDummies}->{Font}{DefaultLegendTitle};
248            
249             if ( defined $InfoLegend{-box} and $InfoLegend{-box} =~ m{^\d+$} ) {
250             $CompositeWidget->{RefInfoDummies}->{Legend}{box} = $InfoLegend{-box};
251             }
252             if ( defined $InfoLegend{-titlecolors} ) {
253             $CompositeWidget->{RefInfoDummies}->{Legend}{titlecolors} = $InfoLegend{-titlecolors};
254             }
255             if ( defined $InfoLegend{-legendmarkerheight}
256             and $InfoLegend{-legendmarkerheight} =~ m{^\d+$} )
257             {
258             $CompositeWidget->{RefInfoDummies}->{Legend}{HCube} = $InfoLegend{-legendmarkerheight};
259             }
260             if ( defined $InfoLegend{-legendmarkerwidth}
261             and $InfoLegend{-legendmarkerwidth} =~ m{^\d+$} )
262             {
263             $CompositeWidget->{RefInfoDummies}->{Legend}{WCube} = $InfoLegend{-legendmarkerwidth};
264             }
265             if ( defined $InfoLegend{-heighttitle}
266             and $InfoLegend{-heighttitle} =~ m{^\d+$} )
267             {
268             $CompositeWidget->{RefInfoDummies}->{Legend}{HeightTitle} = $InfoLegend{-heighttitle};
269             }
270            
271             # Check legend and data size
272             if ( my $RefData = $CompositeWidget->{RefInfoDummies}->{Data}{RefAllData} ) {
273             $CompositeWidget->_CheckSizeLengendAndData( $RefData, $RefLegend );
274             }
275            
276             # Get the biggest length of legend text
277             my @LengthLegend = map { length; } @{$RefLegend};
278             my $BiggestLegend = _MaxArray( \@LengthLegend );
279            
280             # 100 pixel => 13 characters, 1 pixel => 0.13 pixels then 1 character = 7.69 pixels
281             $CompositeWidget->{RefInfoDummies}->{Legend}{WidthOneCaracter} = 7.69;
282            
283             # Max pixel width for a legend text for us
284             $CompositeWidget->{RefInfoDummies}->{Legend}{LengthTextMax}
285             = int( $CompositeWidget->{RefInfoDummies}->{Legend}{WidthText}
286             / $CompositeWidget->{RefInfoDummies}->{Legend}{WidthOneCaracter} );
287            
288             # We have free space
289             my $Diff = $CompositeWidget->{RefInfoDummies}->{Legend}{LengthTextMax} - $BiggestLegend;
290            
291             # Get new size width for a legend text with one pixel security
292             $CompositeWidget->{RefInfoDummies}->{Legend}{WidthText}
293             -= ( $Diff - 1 ) * $CompositeWidget->{RefInfoDummies}->{Legend}{WidthOneCaracter};
294            
295             # Store Reference data
296             $CompositeWidget->{RefInfoDummies}->{Legend}{DataLegend} = $RefLegend;
297             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend} = scalar @{$RefLegend};
298            
299             return 1;
300             }
301            
302             sub _Legend {
303             my ( $CompositeWidget, $RefLegend ) = @_;
304            
305             # One legend width
306             $CompositeWidget->{RefInfoDummies}->{Legend}{LengthOneLegend}
307             = +$CompositeWidget->{RefInfoDummies}->{Legend}{SpaceBeforeCube} # Espace entre chaque légende
308             + $CompositeWidget->{RefInfoDummies}->{Legend}{WCube} # Cube (largeur)
309             + $CompositeWidget->{RefInfoDummies}->{Legend}{SpaceAfterCube} # Espace apres cube
310             + $CompositeWidget->{RefInfoDummies}->{Legend}{WidthText} # longueur du texte de la légende
311             ;
312            
313             # Number of legends per line
314             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine}
315             = int( $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{Width}
316             / $CompositeWidget->{RefInfoDummies}->{Legend}{LengthOneLegend} );
317             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine} = 1
318             if ( $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine} == 0 );
319            
320             # How many legend we will have
321             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend}
322             = scalar @{ $CompositeWidget->{RefInfoDummies}->{Data}{RefAllData} } - 1;
323            
324             =for NumberLines
325             We calculate the number of lines set for the legend graph.
326             If wa can set 11 legends per line, then for 3 legend, we will need one line
327             and for 12 legends, we will need 2 lines
328             If NbrLeg / NbrPerLine = integer => get number of lines
329             If NbrLeg / NbrPerLine = float => int(float) + 1 = get number of lines
330            
331             =cut
332            
333             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine}
334             = $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend}
335             / $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine};
336             unless (
337             int( $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine} )
338             == $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine} )
339             {
340             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine}
341             = int( $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine} ) + 1;
342             }
343            
344             # Total Height of Legend
345             $CompositeWidget->{RefInfoDummies}->{Legend}{Height}
346             = $CompositeWidget->{RefInfoDummies}->{Legend}{HeightTitle} # Hauteur Titre légende
347             + $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine}
348             * $CompositeWidget->{RefInfoDummies}->{Legend}{HLine};
349            
350             # Get number legend text max per line to reajust our graph
351             if ( $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend}
352             < $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine} )
353             {
354             $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine}
355             = $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend};
356             }
357            
358             return;
359             }
360            
361             sub _ViewLegend {
362             my ($CompositeWidget) = @_;
363            
364             # legend option
365             my $LegendTitle = $CompositeWidget->{RefInfoDummies}->{Legend}{title};
366             my $legendmarkercolors = $CompositeWidget->cget( -colordata );
367             my $legendfont = $CompositeWidget->{RefInfoDummies}->{Legend}{legendfont};
368             my $titlecolor = $CompositeWidget->{RefInfoDummies}->{Legend}{titlecolors};
369             my $titlefont = $CompositeWidget->{RefInfoDummies}->{Legend}{titlefont};
370            
371             if ( defined $LegendTitle ) {
372             my $xLegendTitle = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin}
373             + $CompositeWidget->{RefInfoDummies}->{Legend}{SpaceBeforeCube};
374             my $yLegendTitle
375             = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin}
376             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{TickHeight}
377             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{ScaleValuesHeight}
378             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{xlabelHeight};
379            
380             $CompositeWidget->createText(
381             $xLegendTitle,
382             $yLegendTitle,
383             -text => $LegendTitle,
384             -anchor => 'nw',
385             -font => $titlefont,
386             -fill => $titlecolor,
387             -width => $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{Width},
388             -tags => [
389             $CompositeWidget->{RefInfoDummies}->{TAGS}{TitleLegend},
390             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
391             ],
392             );
393             }
394            
395             # Display legend
396             my $IndexColor = 0;
397             my $IndexLegend = 0;
398             $CompositeWidget->{RefInfoDummies}->{Legend}{GetIdLeg} = {};
399            
400             for my $NumberLine ( 0 .. $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLine} - 1 ) {
401             my $x1Cube = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin}
402             + $CompositeWidget->{RefInfoDummies}->{Legend}{SpaceBeforeCube};
403             my $y1Cube
404             = ( $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin}
405             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{TickHeight}
406             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{ScaleValuesHeight}
407             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{xlabelHeight}
408             + $CompositeWidget->{RefInfoDummies}->{Legend}{HeightTitle}
409             + $CompositeWidget->{RefInfoDummies}->{Legend}{HLine} / 2 )
410             + $NumberLine * $CompositeWidget->{RefInfoDummies}->{Legend}{HLine};
411            
412             my $x2Cube = $x1Cube + $CompositeWidget->{RefInfoDummies}->{Legend}{WCube};
413             my $y2Cube = $y1Cube - $CompositeWidget->{RefInfoDummies}->{Legend}{HCube};
414             my $xText = $x2Cube + $CompositeWidget->{RefInfoDummies}->{Legend}{SpaceAfterCube};
415             my $yText = $y2Cube;
416             my $MaxLength = $CompositeWidget->{RefInfoDummies}->{Legend}{LengthTextMax};
417            
418             LEGEND:
419             for my $NumberLegInLine ( 0 .. $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine} - 1 ) {
420            
421             my $LineColor = $legendmarkercolors->[$IndexColor];
422             unless ( defined $LineColor ) {
423             $IndexColor = 0;
424             $LineColor = $legendmarkercolors->[$IndexColor];
425             }
426            
427             # Cut legend text if too long
428             my $Legende = $CompositeWidget->{RefInfoDummies}->{Legend}{DataLegend}->[$IndexLegend];
429             next unless ( defined $Legende );
430             my $NewLegend = $Legende;
431            
432             if ( length $NewLegend > $MaxLength ) {
433             $MaxLength -= 3;
434             $NewLegend =~ s/^(.{$MaxLength}).*/$1/;
435             $NewLegend .= '...';
436             }
437            
438             my $Tag = ( $IndexLegend + 1 ) . $CompositeWidget->{RefInfoDummies}->{TAGS}{Legend};
439             $CompositeWidget->createRectangle(
440             $x1Cube, $y1Cube, $x2Cube, $y2Cube,
441             -fill => $LineColor,
442             -outline => $LineColor,
443             -tags => [ $Tag, $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph}, ],
444             );
445            
446             my $Id = $CompositeWidget->createText(
447             $xText, $yText,
448             -text => $NewLegend,
449             -anchor => 'nw',
450             -tags => [ $Tag, $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph}, ],
451             );
452             if ($legendfont) {
453             $CompositeWidget->itemconfigure( $Id, -font => $legendfont, );
454             }
455             $CompositeWidget->{RefInfoDummies}->{Legend}{GetIdLeg}{$Tag} = $IndexLegend;
456             $CompositeWidget->{RefInfoDummies}->{Legend}{GetIdLeg}{$Tag} = $IndexLegend;
457            
458             $IndexColor++;
459             $IndexLegend++;
460            
461             # cube
462             $x1Cube += $CompositeWidget->{RefInfoDummies}->{Legend}{LengthOneLegend};
463             $x2Cube += $CompositeWidget->{RefInfoDummies}->{Legend}{LengthOneLegend};
464            
465             # Text
466             $xText += $CompositeWidget->{RefInfoDummies}->{Legend}{LengthOneLegend};
467            
468             my $LineTag = $IndexLegend . $CompositeWidget->{RefInfoDummies}->{TAGS}{Line};
469             $CompositeWidget->{RefInfoDummies}->{Legend}{MsgBalloon}->{$Tag} = $Legende;
470             $CompositeWidget->{RefInfoDummies}->{Legend}{MsgBalloon}->{$LineTag} = $Legende;
471            
472             if ( $IndexLegend == $CompositeWidget->{RefInfoDummies}->{Legend}{NbrLegend} ) {
473             last LEGEND;
474             }
475             }
476            
477             }
478            
479             # box legend
480             my $x1Box = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin};
481             my $y1Box
482             = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin}
483             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{TickHeight}
484             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{ScaleValuesHeight}
485             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{xlabelHeight};
486             my $x2Box
487             = $x1Box
488             + ( $CompositeWidget->{RefInfoDummies}->{Legend}{NbrPerLine}
489             * $CompositeWidget->{RefInfoDummies}->{Legend}{LengthOneLegend} );
490            
491             # Reajuste box if width box < legend title text
492             my @InfoLegendTitle = $CompositeWidget->bbox( $CompositeWidget->{RefInfoDummies}->{TAGS}{TitleLegend} );
493             if ( $InfoLegendTitle[2] and $x2Box <= $InfoLegendTitle[2] ) {
494             $x2Box = $InfoLegendTitle[2] + 2;
495             }
496             my $y2Box = $y1Box + $CompositeWidget->{RefInfoDummies}->{Legend}{Height};
497             $CompositeWidget->createRectangle(
498             $x1Box, $y1Box, $x2Box, $y2Box,
499             -tags => [
500             $CompositeWidget->{RefInfoDummies}->{TAGS}{BoxLegend},
501             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
502             ],
503             );
504            
505             return;
506             }
507            
508             sub _axis {
509             my ($CompositeWidget) = @_;
510            
511             # x axis width
512             $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{Width}
513             = $CompositeWidget->{RefInfoDummies}->{Canvas}{Width}
514             - ( 2 * $CompositeWidget->{RefInfoDummies}->{Canvas}{WidthEmptySpace}
515             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{ylabelWidth}
516             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{ScaleValuesWidth}
517             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{TickWidth} );
518            
519             # get Height legend
520             if ( $CompositeWidget->{RefInfoDummies}->{Legend}{DataLegend} ) {
521             $CompositeWidget->_Legend( $CompositeWidget->{RefInfoDummies}->{Legend}{DataLegend} );
522             }
523            
524             # Height y axis
525             $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{Height}
526             = $CompositeWidget->{RefInfoDummies}->{Canvas}{Height} # Largeur canvas
527             - (
528             2 * $CompositeWidget->{RefInfoDummies}->{Canvas}{HeightEmptySpace} # 2 fois les espace vides
529             + $CompositeWidget->{RefInfoDummies}->{Title}{Height} # Hauteur du titre
530             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{TickHeight} # Hauteur tick (axe x)
531             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{ScaleValuesHeight} # Hauteur valeurs axe
532             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{xlabelHeight} # Hauteur x label
533             + $CompositeWidget->{RefInfoDummies}->{Legend}{Height} # Hauteur légende
534             );
535            
536             #===========================
537             # Y axis
538             # Set 2 points (CxMin, CyMin) et (CxMin, CyMax)
539             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin} # Coordonnées CxMin
540             = $CompositeWidget->{RefInfoDummies}->{Canvas}{WidthEmptySpace} # Largeur vide
541             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{ylabelWidth} # Largeur label y
542             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{ScaleValuesWidth} # Largeur valeur axe y
543             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{TickWidth}; # Largeur tick axe y
544            
545             $CompositeWidget->{RefInfoDummies}->{Axis}{CyMax} # Coordonnées CyMax
546             = $CompositeWidget->{RefInfoDummies}->{Canvas}{HeightEmptySpace} # Hauteur vide
547             + $CompositeWidget->{RefInfoDummies}->{Title}{Height} # Hauteur titre
548             ;
549            
550             $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin} # Coordonnées CyMin
551             = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMax} # Coordonnées CyMax (haut)
552             + $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{Height} # Hauteur axe Y
553             ;
554            
555             # display Y axis
556             $CompositeWidget->createLine(
557             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin},
558             $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin},
559             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin},
560             $CompositeWidget->{RefInfoDummies}->{Axis}{CyMax},
561             -tags => [
562             $CompositeWidget->{RefInfoDummies}->{TAGS}{yAxis},
563             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllAXIS},
564             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
565             ],
566             );
567            
568             #===========================
569             # X axis
570             # Set 2 points (CxMin,CyMin) et (CxMax,CyMin)
571             # ou (Cx0,Cy0) et (CxMax,Cy0)
572             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMax} # Coordonnées CxMax
573             = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin} # Coordonnées CxMin
574             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{Width} # Largeur axe x
575             ;
576            
577             # Bottom x axis
578             $CompositeWidget->createLine(
579             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin},
580             $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin},
581             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMax},
582             $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin},
583             -tags => [
584             $CompositeWidget->{RefInfoDummies}->{TAGS}{xAxis},
585             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllAXIS},
586             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
587             ],
588             );
589            
590             # POINT (0,0)
591             # min positive value >= 0
592             if ( $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue} >= 0 ) {
593             $CompositeWidget->{RefInfoDummies}->{Axis}{Cx0} = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin};
594             $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0} = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin};
595            
596             $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{HeightUnit}
597             = $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{Height}
598             / ( $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue} - 0 );
599             }
600            
601             # min positive value < 0
602             else {
603            
604             $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{HeightUnit}
605             = $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{Height}
606             / ( $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue}
607             - $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue} );
608             $CompositeWidget->{RefInfoDummies}->{Axis}{Cx0} = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin};
609             $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0}
610             = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin}
611             + ( $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{HeightUnit}
612             * $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue} );
613            
614             # X Axis (0,0)
615             $CompositeWidget->createLine(
616             $CompositeWidget->{RefInfoDummies}->{Axis}{Cx0},
617             $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0},
618             $CompositeWidget->{RefInfoDummies}->{Axis}{CxMax},
619             $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0},
620             -tags => [
621             $CompositeWidget->{RefInfoDummies}->{TAGS}{xAxis0},
622             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllAXIS},
623             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
624             ],
625             );
626             }
627            
628             return;
629             }
630            
631             sub _xtick {
632             my ($CompositeWidget) = @_;
633            
634             my $xvaluecolor = $CompositeWidget->cget( -xvaluecolor );
635             my $longticks = $CompositeWidget->cget( -longticks );
636            
637             # x coordinates y ticks on bottom x axis
638             my $Xtickx1 = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin};
639             my $Xticky1 = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin};
640            
641             # x coordinates y ticks on 0,0 x axis if the graph have only y value < 0
642             if ( $CompositeWidget->cget( -zeroaxisonly ) == 1
643             and $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue} > 0 )
644             {
645             $Xticky1 = $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0};
646             }
647            
648             my $Xtickx2 = $Xtickx1;
649             my $Xticky2 = $Xticky1 + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{TickHeight};
650            
651             # Coordinates of x values (first value)
652             my $XtickxValue = $CompositeWidget->{RefInfoDummies}->{Axis}{CxMin};
653             my $XtickyValue = $Xticky2 + ( $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{ScaleValuesHeight} / 2 );
654             my $NbrLeg = scalar( @{ $CompositeWidget->{RefInfoDummies}->{Data}{RefXLegend} } );
655            
656             my $xlabelskip = $CompositeWidget->cget( -xlabelskip );
657            
658             # index of tick and vlaues that will be skip
659             my %IndiceToSkip;
660             if ( defined $xlabelskip ) {
661             for ( my $i = 1; $i <= $NbrLeg; $i++ ) {
662             $IndiceToSkip{$i} = 1;
663             $i += $xlabelskip;
664             }
665             }
666            
667             for ( my $Indice = 1; $Indice <= $NbrLeg; $Indice++ ) {
668             my $data = $CompositeWidget->{RefInfoDummies}->{Data}{RefXLegend}->[ $Indice - 1 ];
669            
670             # tick
671             $Xtickx1 += $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{SpaceBetweenTick};
672             $Xtickx2 = $Xtickx1;
673            
674             # tick legend
675             $XtickxValue += $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{SpaceBetweenTick};
676             my $RegexXtickselect = $CompositeWidget->cget( -xvaluesregex );
677            
678             if ( $data =~ m{$RegexXtickselect} ) {
679             next unless ( defined $IndiceToSkip{$Indice} );
680            
681             # Long tick
682             if ( defined $longticks and $longticks == 1 ) {
683             $Xticky1 = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMax};
684             $Xticky2 = $CompositeWidget->{RefInfoDummies}->{Axis}{CyMin};
685             }
686            
687             $CompositeWidget->createLine(
688             $Xtickx1, $Xticky1, $Xtickx2, $Xticky2,
689             -tags => [
690             $CompositeWidget->{RefInfoDummies}->{TAGS}{xTick},
691             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTick},
692             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
693             ],
694             );
695             $CompositeWidget->createText(
696             $XtickxValue,
697             $XtickyValue,
698             -text => $data,
699             -fill => $xvaluecolor,
700             -tags => [
701             $CompositeWidget->{RefInfoDummies}->{TAGS}{xValues},
702             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllValues},
703             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
704             ],
705             );
706             }
707             }
708            
709             return;
710             }
711            
712             sub _ViewData {
713             my ($CompositeWidget) = @_;
714            
715             my $legendmarkercolors = $CompositeWidget->cget( -colordata );
716             my $viewsection = $CompositeWidget->cget( -viewsection );
717             my $outlinearea = $CompositeWidget->cget( -outlinearea );
718            
719             my $tag_area = $CompositeWidget->{RefInfoDummies}->{TAGS}{Area};
720            
721             # number of value for x axis
722             $CompositeWidget->{RefInfoDummies}->{Data}{xtickNumber}
723             = $CompositeWidget->{RefInfoDummies}->{Data}{NumberXValues};
724            
725             # Space between x ticks
726             $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{SpaceBetweenTick}
727             = $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{Width}
728             / ( $CompositeWidget->{RefInfoDummies}->{Data}{xtickNumber} + 1 );
729            
730             my $IdData = 0;
731             my $IndexColor = 0;
732             foreach my $RefArrayData ( @{ $CompositeWidget->{RefInfoDummies}->{Data}{RefAllData} } ) {
733             if ( $IdData == 0 ) {
734             $IdData++;
735             next;
736             }
737             my $NumberData = 1; # Number of data
738             my @PointsData; # coordinate x and y
739             my @DashPointsxLines;
740            
741             # First point, in x axis
742             my $Fisrtx = $CompositeWidget->{RefInfoDummies}->{Axis}{Cx0}
743             + $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{SpaceBetweenTick};
744             my $Fisrty = $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0};
745             push( @PointsData, ( $Fisrtx, $Fisrty ) );
746            
747             foreach my $data ( @{$RefArrayData} ) {
748             unless ( defined $data ) {
749             $NumberData++;
750             next;
751             }
752            
753             # coordinates x and y values
754             my $x = $CompositeWidget->{RefInfoDummies}->{Axis}{Cx0}
755             + $NumberData * $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{SpaceBetweenTick};
756             my $y = $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0}
757             - ( $data * $CompositeWidget->{RefInfoDummies}->{Axis}{Yaxis}{HeightUnit} );
758            
759             push( @PointsData, ( $x, $y ) );
760            
761             push( @DashPointsxLines, $x, $y );
762             $NumberData++;
763            
764             }
765            
766             # Last point, in x axis
767             my $Lastx = $CompositeWidget->{RefInfoDummies}->{Axis}{Cx0}
768             + ( $NumberData - 1 ) * $CompositeWidget->{RefInfoDummies}->{Axis}{Xaxis}{SpaceBetweenTick};
769            
770             my $Lastty = $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0};
771             push( @PointsData, ( $Lastx, $Lastty ) );
772            
773             my $LineColor = $legendmarkercolors->[$IndexColor];
774             unless ( defined $LineColor ) {
775             $IndexColor = 0;
776             $LineColor = $legendmarkercolors->[$IndexColor];
777             }
778             my $tag = $IdData . $CompositeWidget->{RefInfoDummies}->{TAGS}{Line};
779            
780             $CompositeWidget->createPolygon(
781             @PointsData,
782             -fill => $LineColor,
783             -tags => [
784             $tag_area, $tag,
785             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllData},
786             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
787             ],
788             -width => $CompositeWidget->cget( -linewidth ),
789             -outline => $outlinearea,
790             );
791            
792             # display Dash line
793             if ( defined $viewsection and $viewsection == 1 ) {
794            
795             # remove first and last points
796             for ( 1 .. 2 ) {
797             shift(@DashPointsxLines);
798             pop(@DashPointsxLines);
799             }
800            
801             for ( my $i = 0; $i < scalar(@DashPointsxLines); $i++ ) {
802             my $IndexX1 = $i;
803             my $IndexY1 = $i + 1;
804             my $IndexX2 = $i;
805             $CompositeWidget->createLine(
806             $DashPointsxLines[$IndexX1],
807             $DashPointsxLines[$IndexY1],
808             $DashPointsxLines[$IndexX2],
809             $CompositeWidget->{RefInfoDummies}->{Axis}{Cy0},
810             -dash => '.',
811             -width => $CompositeWidget->cget( -linewidth ),
812             -tags => [
813             $tag,
814             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllData},
815             $CompositeWidget->{RefInfoDummies}->{TAGS}{DashLines},
816             $CompositeWidget->{RefInfoDummies}->{TAGS}{AllTagsDummiesGraph},
817             ],
818             );
819             $i++;
820             }
821             }
822            
823             # Display values above each points of lines
824             my $LineNumber = $IdData - 1;
825             $CompositeWidget->_display_line( \@PointsData, $LineNumber );
826            
827             $CompositeWidget->{RefInfoDummies}{Line}{$tag}{color} = $LineColor;
828            
829             $IdData++;
830             $IndexColor++;
831             }
832            
833             return 1;
834             }
835            
836             sub plot {
837             my ( $CompositeWidget, $RefData, %option ) = @_;
838            
839             my $yticknumber = $CompositeWidget->cget( -yticknumber );
840            
841             if ( defined $option{-substitutionvalue}
842             and _isANumber( $option{-substitutionvalue} ) )
843             {
844             $CompositeWidget->{RefInfoDummies}->{Data}{SubstitutionValue} = $option{-substitutionvalue};
845             }
846            
847             unless ( defined $RefData ) {
848             $CompositeWidget->_error('data not defined');
849             return;
850             }
851            
852             unless ( scalar @{$RefData} > 1 ) {
853             $CompositeWidget->_error('You must have at least 2 arrays');
854             return;
855             }
856            
857             # Check legend and data size
858             if ( my $RefLegend = $CompositeWidget->{RefInfoDummies}->{Legend}{DataLegend} ) {
859             $CompositeWidget->_CheckSizeLengendAndData( $RefData, $RefLegend );
860             }
861            
862             # Check array size
863             $CompositeWidget->{RefInfoDummies}->{Data}{NumberXValues} = scalar @{ $RefData->[0] };
864             my $i = 0;
865             foreach my $RefArray ( @{$RefData} ) {
866             unless ( scalar @{$RefArray} == $CompositeWidget->{RefInfoDummies}->{Data}{NumberXValues} ) {
867             $CompositeWidget->_error( 'Make sure that every array has the same size in plot data method', 1 );
868             return;
869             }
870            
871             # Get min and max size
872             if ( $i != 0 ) {
873            
874             # substitute none real value
875             foreach my $data ( @{$RefArray} ) {
876             if ( defined $data and !_isANumber($data) ) {
877             $data = $CompositeWidget->{RefInfoDummies}->{Data}{SubstitutionValue};
878             }
879             }
880            
881             $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue}
882             = _MaxArray( [ $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue}, _MaxArray($RefArray) ] );
883             $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue}
884             = _MinArray( [ $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue}, _MinArray($RefArray) ] );
885             }
886             $i++;
887             }
888             $CompositeWidget->{RefInfoDummies}->{Data}{RefXLegend} = $RefData->[0];
889             $CompositeWidget->{RefInfoDummies}->{Data}{RefAllData} = $RefData;
890             $CompositeWidget->{RefInfoDummies}->{Data}{PlotDefined} = 1;
891            
892             if ( $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue} > 0 ) {
893             $CompositeWidget->{RefInfoDummies}->{Data}{MinYValue} = 0;
894             }
895            
896             while ( ( $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue} / $yticknumber ) % 5 != 0 ) {
897             $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue}
898             = int( $CompositeWidget->{RefInfoDummies}->{Data}{MaxYValue} + 1 );
899             }
900            
901             $CompositeWidget->_GraphForDummiesConstruction;
902             return 1;
903             }
904            
905             1;
906             __END__