line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SVGGraph; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
11409
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
4
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
33
|
|
5
|
1
|
|
|
1
|
|
1045
|
use utf8; |
|
1
|
|
|
|
|
14
|
|
|
1
|
|
|
|
|
6
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
sub new() |
9
|
|
|
|
|
|
|
{ |
10
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
11
|
0
|
|
|
|
|
|
return bless {}, $self; |
12
|
|
|
|
|
|
|
} |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub CreateGraph() |
15
|
|
|
|
|
|
|
{ |
16
|
|
|
|
|
|
|
### First element of @_ is a reference to the element that called this subroutine |
17
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
18
|
|
|
|
|
|
|
### Second is a reference to a hash with options |
19
|
0
|
|
|
|
|
|
my $options = shift; |
20
|
|
|
|
|
|
|
### The options passed in the anonymous hash are optional so create a default value first |
21
|
0
|
|
|
|
|
|
my $horiUnitDistance = 20; |
22
|
0
|
0
|
|
|
|
|
if ($$options{'horiunitdistance'}) |
23
|
|
|
|
|
|
|
{ |
24
|
0
|
|
|
|
|
|
$horiUnitDistance = $$options{'horiunitdistance'}; |
25
|
|
|
|
|
|
|
} |
26
|
0
|
|
|
|
|
|
my $graphType = 'spline'; |
27
|
0
|
0
|
|
|
|
|
if ($$options{'graphtype'}) |
28
|
|
|
|
|
|
|
{ |
29
|
0
|
|
|
|
|
|
$graphType = $$options{'graphtype'}; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
### The rest are references to arrays with references to arrays with x and y values |
32
|
0
|
|
|
|
|
|
my @xyArrayRefs = @_; |
33
|
|
|
|
|
|
|
### Check if the color ($xyArrayRefs[$i]->[3]) is provided. If not, choose black |
34
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @xyArrayRefs; $i++) |
35
|
|
|
|
|
|
|
{ |
36
|
0
|
0
|
|
|
|
|
unless ($xyArrayRefs[$i]->[3]) |
37
|
|
|
|
|
|
|
{ |
38
|
0
|
|
|
|
|
|
$xyArrayRefs[$i]->[3] = '#000000'; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
### Declare the $minX as the lowest value of x in the arrays, same for $minY, $maxX and $maxY |
42
|
0
|
|
|
|
|
|
my $minX = $xyArrayRefs[0]->[0]->[0]; ### Equivalent to ${${$xyArrayRefs[0]}[0]}[0]; |
43
|
0
|
|
|
|
|
|
my $minY = $xyArrayRefs[0]->[1]->[0]; |
44
|
0
|
|
|
|
|
|
my $maxX = $minX; |
45
|
0
|
|
|
|
|
|
my $maxY = $minY; |
46
|
|
|
|
|
|
|
### Then really search for the lowest and highest value of x and y |
47
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @xyArrayRefs; $i++) |
48
|
|
|
|
|
|
|
{ |
49
|
0
|
|
|
|
|
|
for (my $j = 0; $j < @{$xyArrayRefs[$i]->[0]}; $j++) |
|
0
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
{ |
51
|
0
|
0
|
|
|
|
|
if ($xyArrayRefs[$i]->[0]->[$j] > $maxX) |
52
|
|
|
|
|
|
|
{ |
53
|
0
|
|
|
|
|
|
$maxX = $xyArrayRefs[$i]->[0]->[$j]; |
54
|
|
|
|
|
|
|
} |
55
|
0
|
0
|
|
|
|
|
if ($xyArrayRefs[$i]->[0]->[$j] < $minX) |
56
|
|
|
|
|
|
|
{ |
57
|
0
|
|
|
|
|
|
$minX = $xyArrayRefs[$i]->[0]->[$j]; |
58
|
|
|
|
|
|
|
} |
59
|
0
|
0
|
|
|
|
|
if ($xyArrayRefs[$i]->[1]->[$j] > $maxY) |
60
|
|
|
|
|
|
|
{ |
61
|
0
|
|
|
|
|
|
$maxY = $xyArrayRefs[$i]->[1]->[$j]; |
62
|
|
|
|
|
|
|
} |
63
|
0
|
0
|
|
|
|
|
if ($xyArrayRefs[$i]->[1]->[$j] < $minY) |
64
|
|
|
|
|
|
|
{ |
65
|
0
|
|
|
|
|
|
$minY = $xyArrayRefs[$i]->[1]->[$j]; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
### If max equals min, change them artificially |
70
|
0
|
0
|
|
|
|
|
if ($maxX == $minX) |
71
|
|
|
|
|
|
|
{ |
72
|
0
|
|
|
|
|
|
$maxX += 1; |
73
|
|
|
|
|
|
|
} |
74
|
0
|
0
|
|
|
|
|
if ($maxY == $minY) |
75
|
|
|
|
|
|
|
{ |
76
|
0
|
|
|
|
|
|
$maxY += 1; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
### Calculate all dimensions neccessary to create the Graph |
79
|
|
|
|
|
|
|
### Height of the total svg image in pixels: |
80
|
0
|
|
|
|
|
|
my $imageHeight = 400; |
81
|
0
|
0
|
|
|
|
|
if ($$options{'imageheight'}) |
82
|
|
|
|
|
|
|
{ |
83
|
0
|
|
|
|
|
|
$imageHeight = $$options{'imageheight'}; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
### Width of the verticabar or dots in the graph |
86
|
0
|
|
|
|
|
|
my $barWidth = 3; |
87
|
0
|
0
|
|
|
|
|
if ($$options{'barwidth'}) |
88
|
|
|
|
|
|
|
{ |
89
|
0
|
|
|
|
|
|
$barWidth = $$options{'barwidth'}; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
### Distance between the sides of the gris and the sides of the image: |
92
|
0
|
|
|
|
|
|
my $cornerDistance = 50; |
93
|
|
|
|
|
|
|
### Since svg counts from the top left corner of the image, we translate all coordinates vertically in pixels: |
94
|
0
|
|
|
|
|
|
my $vertTranslate = $imageHeight - $cornerDistance; |
95
|
|
|
|
|
|
|
### The width of the grid in pixels: |
96
|
0
|
|
|
|
|
|
my $gridWidth = $horiUnitDistance * ($maxX - $minX); |
97
|
|
|
|
|
|
|
### The height of the grid in pixels: |
98
|
0
|
|
|
|
|
|
my $gridHeight = $imageHeight - 2 * $cornerDistance; |
99
|
|
|
|
|
|
|
### The width of the whole svg image: |
100
|
0
|
|
|
|
|
|
my $imageWidth = $gridWidth + (4 * $cornerDistance); |
101
|
|
|
|
|
|
|
### The horizontal space between vertical gridlines in pixels: |
102
|
0
|
|
|
|
|
|
my $xGridDistance = 20; |
103
|
|
|
|
|
|
|
### The vertical space between horizontal gridlines in pixels: |
104
|
0
|
|
|
|
|
|
my $yGridDistance = 30; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
### Now initiate the svg graph by declaring some general stuff. |
107
|
0
|
|
|
|
|
|
my $svg .= <<" EOF"; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
EOF |
113
|
0
|
0
|
|
|
|
|
if ($graphType eq 'spline') |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @xyArrayRefs; $i++) |
116
|
|
|
|
|
|
|
{ |
117
|
0
|
|
|
|
|
|
$svg .= $self->CreateDot(0, 0, $barWidth, $xyArrayRefs[$i]->[3], $i); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} |
120
|
0
|
|
|
|
|
|
$svg .= <<" EOF"; |
121
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
EOF |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
### make x- and y axes |
145
|
0
|
|
|
|
|
|
$svg .= "\n"; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
### print numbers on y axis and horizontal gridlines |
148
|
|
|
|
|
|
|
### First calculate the width between the gridlines in y-units, not in pixels |
149
|
0
|
|
|
|
|
|
my $deltaYUnits = $self->NaturalRound ($yGridDistance * ($maxY - $minY) / $gridHeight); |
150
|
|
|
|
|
|
|
### Adjust $minX and $maxX so the gridlines and numbers startand end in a whole and nice number. |
151
|
0
|
|
|
|
|
|
$minY = int ($minY / $deltaYUnits - 0.999999999999) * $deltaYUnits; |
152
|
0
|
|
|
|
|
|
$maxY = int ($maxY / $deltaYUnits + 0.999999999999) * $deltaYUnits; |
153
|
|
|
|
|
|
|
### Calculate the number of pixels each units stands for. |
154
|
0
|
|
|
|
|
|
my $yPixelsPerUnit = ($gridHeight / ($maxY - $minY)); |
155
|
0
|
|
|
|
|
|
my $deltaYPixels = $deltaYUnits * $yPixelsPerUnit; |
156
|
|
|
|
|
|
|
### Calculate the amount of gridlines and therefore the amount of numbers on the y-axis |
157
|
0
|
|
|
|
|
|
my $yNumberOfNumbers = int ($gridHeight / $deltaYPixels) + 1; |
158
|
|
|
|
|
|
|
### Draw the numbers and the gridlines |
159
|
0
|
|
|
|
|
|
for (my $i = 0; $i < $yNumberOfNumbers; $i++) |
160
|
|
|
|
|
|
|
{ |
161
|
0
|
|
|
|
|
|
my $YValue = sprintf ("%1.2f", (-1 * $i * $deltaYPixels)) + 0; |
162
|
|
|
|
|
|
|
### numbers |
163
|
0
|
|
|
|
|
|
$svg .= "" . ($minY + $i * $deltaYUnits) . "\n"; |
164
|
|
|
|
|
|
|
### gridline |
165
|
0
|
0
|
|
|
|
|
if ($i != 0) |
166
|
|
|
|
|
|
|
{ |
167
|
0
|
|
|
|
|
|
$svg .= "\n"; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
### print numbers on x axis and vertical gridlines |
172
|
0
|
|
|
|
|
|
my $deltaXUnits = $self->NaturalRound ($xGridDistance * ($maxX - $minX) / $gridWidth); |
173
|
0
|
|
|
|
|
|
my $xPixelsPerUnit = ($gridWidth / ($maxX - $minX)); |
174
|
0
|
|
|
|
|
|
my $deltaXPixels = $deltaXUnits * $xPixelsPerUnit; |
175
|
0
|
|
|
|
|
|
my $xNumberOfNumbers = int ($gridWidth / $deltaXPixels) + 1; |
176
|
0
|
|
|
|
|
|
for (my $i = 0; $i < $xNumberOfNumbers; $i++) |
177
|
|
|
|
|
|
|
{ |
178
|
0
|
|
|
|
|
|
my $XValue = sprintf ("%1.2f", ($i * $deltaXPixels)) + 0; |
179
|
|
|
|
|
|
|
### numbers |
180
|
0
|
|
|
|
|
|
$svg .= "" . ($minX + $i * $deltaXUnits) . "\n"; |
181
|
|
|
|
|
|
|
### gridline |
182
|
0
|
0
|
|
|
|
|
if ($i != 0) |
183
|
|
|
|
|
|
|
{ |
184
|
0
|
|
|
|
|
|
$svg .= "\n"; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
### print measurepoints (dots) (data) (coordinates) |
189
|
|
|
|
|
|
|
### Spline |
190
|
0
|
0
|
|
|
|
|
if ($graphType eq 'spline') |
|
|
0
|
|
|
|
|
|
191
|
|
|
|
|
|
|
{ |
192
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @xyArrayRefs; $i++) |
193
|
|
|
|
|
|
|
{ |
194
|
0
|
|
|
|
|
|
my $dots; |
195
|
0
|
|
|
|
|
|
for (my $dotNumber = 0; $dotNumber < @{$xyArrayRefs[$i]->[0]}; $dotNumber++) |
|
0
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
{ |
197
|
0
|
|
|
|
|
|
my $dotX = $horiUnitDistance * ($xyArrayRefs[$i]->[0]->[$dotNumber] - $minX); |
198
|
0
|
|
|
|
|
|
my $dotY = sprintf ("%1.2f", -1 * $yPixelsPerUnit * ($xyArrayRefs[$i]->[1]->[$dotNumber] - $minY)) + 0; |
199
|
0
|
|
|
|
|
|
$dots .= "\n"; |
200
|
0
|
0
|
|
|
|
|
if ($dotNumber == 0) |
201
|
|
|
|
|
|
|
{ |
202
|
0
|
|
|
|
|
|
$svg .= "
|
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
else |
205
|
|
|
|
|
|
|
{ |
206
|
0
|
|
|
|
|
|
$svg .= " L$dotX $dotY"; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
} |
209
|
0
|
|
|
|
|
|
$svg .= "\" style=\"fill: none; stroke: " . $xyArrayRefs[$i]->[3] . "; stroke-width:2\"/>\n$dots"; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
### Vertical Bars |
213
|
|
|
|
|
|
|
elsif ($graphType eq 'verticalbars') |
214
|
|
|
|
|
|
|
{ |
215
|
0
|
|
|
|
|
|
for (my $dotNumber = 0; $dotNumber < @{$xyArrayRefs[0]->[0]}; $dotNumber++) |
|
0
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
{ |
217
|
|
|
|
|
|
|
### The longest bars must be drawn first, so that the shorter bars are drwan on top of the longer. |
218
|
|
|
|
|
|
|
### So we sort $i (the number of the graph) to the length of the bar for each point. |
219
|
0
|
|
|
|
|
|
foreach my $i (sort {$xyArrayRefs[$b]->[1]->[$dotNumber] <=> $xyArrayRefs[$a]->[1]->[$dotNumber]} (0 .. $#xyArrayRefs)) |
|
0
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
{ |
221
|
0
|
|
|
|
|
|
my $lineX = $horiUnitDistance * ($xyArrayRefs[$i]->[0]->[$dotNumber] - $minX); |
222
|
0
|
|
|
|
|
|
my $lineY1 = 0; |
223
|
0
|
0
|
0
|
|
|
|
if (($minY < 0) && ($maxY > 0)) |
|
|
0
|
|
|
|
|
|
224
|
|
|
|
|
|
|
{ |
225
|
0
|
|
|
|
|
|
$lineY1 = $yPixelsPerUnit * $minY; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
elsif ($maxY < 0) |
228
|
|
|
|
|
|
|
{ |
229
|
0
|
|
|
|
|
|
$lineY1 = -1 * 1; |
230
|
|
|
|
|
|
|
} |
231
|
0
|
|
|
|
|
|
my $lineY2 = sprintf ("%1.2f", -1 * $yPixelsPerUnit * ($xyArrayRefs[$i]->[1]->[$dotNumber] - $minY)) + 0; |
232
|
0
|
|
|
|
|
|
$svg .= "[3] . ";stroke-width:$barWidth;\"/>\n"; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
### print Title, Labels and Legend |
238
|
|
|
|
|
|
|
### Title |
239
|
0
|
0
|
|
|
|
|
if ($$options{'title'}) |
240
|
|
|
|
|
|
|
{ |
241
|
0
|
|
|
|
|
|
my $titleStyle = 'font-size:24;'; |
242
|
0
|
0
|
|
|
|
|
if ($$options{'titlestyle'}) |
243
|
|
|
|
|
|
|
{ |
244
|
0
|
|
|
|
|
|
$titleStyle = $self->XMLEscape($$options{'titlestyle'}); |
245
|
|
|
|
|
|
|
} |
246
|
0
|
|
|
|
|
|
$svg .= "" . $self->XMLEscape($$options{'title'}) . "\n"; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
### x-axis label |
249
|
0
|
0
|
|
|
|
|
if ($$options{'xlabel'}) |
250
|
|
|
|
|
|
|
{ |
251
|
0
|
|
|
|
|
|
my $xLabelStyle = 'font-size:16;'; |
252
|
0
|
0
|
|
|
|
|
if ($$options{'xlabelstyle'}) |
253
|
|
|
|
|
|
|
{ |
254
|
0
|
|
|
|
|
|
$xLabelStyle = $self->XMLEscape($$options{'xlabelstyle'}); |
255
|
|
|
|
|
|
|
} |
256
|
0
|
|
|
|
|
|
$svg .= "" . $self->XMLEscape($$options{'xlabel'}) . "\n"; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
### y-axis label |
259
|
0
|
0
|
|
|
|
|
if ($$options{'ylabel'}) |
260
|
|
|
|
|
|
|
{ |
261
|
0
|
|
|
|
|
|
my $yLabelStyle = 'font-size:16;'; |
262
|
0
|
0
|
|
|
|
|
if ($$options{'ylabelstyle'}) |
263
|
|
|
|
|
|
|
{ |
264
|
0
|
|
|
|
|
|
$yLabelStyle = $self->XMLEscape($$options{'ylabelstyle'}); |
265
|
|
|
|
|
|
|
} |
266
|
0
|
|
|
|
|
|
$svg .= "" . $self->XMLEscape($$options{'ylabel'}) . "\n"; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
### Legend |
269
|
0
|
|
|
|
|
|
my $legendOffset = ($cornerDistance + $gridWidth + 10) . ", $cornerDistance"; |
270
|
0
|
0
|
|
|
|
|
if ($$options{'legendoffset'}) |
271
|
|
|
|
|
|
|
{ |
272
|
0
|
|
|
|
|
|
$legendOffset = $self->XMLEscape($$options{'legendoffset'}); |
273
|
|
|
|
|
|
|
} |
274
|
0
|
|
|
|
|
|
$svg .= "\n\n"; |
275
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @xyArrayRefs; $i++) |
276
|
|
|
|
|
|
|
{ |
277
|
0
|
0
|
|
|
|
|
if ($xyArrayRefs[$i]->[2]) |
278
|
|
|
|
|
|
|
{ |
279
|
0
|
|
|
|
|
|
my $y = 12 * $i; |
280
|
0
|
0
|
|
|
|
|
if ($graphType eq 'spline') |
281
|
|
|
|
|
|
|
{ |
282
|
|
|
|
|
|
|
### The line |
283
|
0
|
|
|
|
|
|
$svg .= "[3] . "\"/>\n"; |
284
|
|
|
|
|
|
|
### The dot |
285
|
0
|
|
|
|
|
|
$svg .= $self->CreateDot(8, $y, 3, $xyArrayRefs[$i]->[3], $i); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
### The text |
288
|
0
|
|
|
|
|
|
$svg .= "[3] . "\">" . $xyArrayRefs[$i]->[2] . "\n"; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
} |
291
|
0
|
|
|
|
|
|
$svg .= "\n\n"; |
292
|
0
|
|
|
|
|
|
return $svg; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
### CreateDot is a subroutine that creates the svg code for different |
296
|
|
|
|
|
|
|
### kinds of dots used in the spline graph type: circles, squares, triangles and more. |
297
|
|
|
|
|
|
|
sub CreateDot($$$$$) |
298
|
|
|
|
|
|
|
{ |
299
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
300
|
0
|
|
|
|
|
|
my $x = shift; |
301
|
0
|
|
|
|
|
|
my $y = shift; |
302
|
0
|
|
|
|
|
|
my $r = shift; |
303
|
0
|
|
|
|
|
|
my $color = shift; |
304
|
0
|
|
|
|
|
|
$color = $self->DarkenHexRGB($color); |
305
|
0
|
|
|
|
|
|
my $dotNumber = shift; |
306
|
0
|
|
|
|
|
|
my $d = 2 * $r; |
307
|
0
|
|
|
|
|
|
my $negr = -1 * $r; |
308
|
0
|
|
|
|
|
|
my $svg; |
309
|
|
|
|
|
|
|
### Circle |
310
|
0
|
0
|
|
|
|
|
if ($dotNumber == 0) |
311
|
|
|
|
|
|
|
{ |
312
|
0
|
|
|
|
|
|
$svg = "\n"; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
### Stars |
315
|
|
|
|
|
|
|
else |
316
|
|
|
|
|
|
|
{ |
317
|
0
|
|
|
|
|
|
$svg .= "
|
318
|
0
|
|
|
|
|
|
for (my $i = 1; $i <= (2*$dotNumber+2); $i++) |
319
|
|
|
|
|
|
|
{ |
320
|
0
|
0
|
|
|
|
|
my $radius = ($i % 2) ? $r*1.5 : $r/2; |
321
|
0
|
|
|
|
|
|
my $pi = atan2(1,1) * 4; |
322
|
0
|
|
|
|
|
|
my $alpha = $i * ($pi / ($dotNumber + 1)); |
323
|
0
|
|
|
|
|
|
my $xi = $x + $radius * cos($alpha); |
324
|
0
|
|
|
|
|
|
my $yi = $y + $radius * sin($alpha); |
325
|
0
|
0
|
|
|
|
|
$svg .= ($i == 1) ? "M" : "L"; |
326
|
0
|
|
|
|
|
|
$svg .= sprintf (" %1.3f ", $xi) . (sprintf (" %1.3f ", $yi) + 0); |
327
|
|
|
|
|
|
|
} |
328
|
0
|
|
|
|
|
|
$svg .= "z\" style=\"fill: $color; stroke: $color;\"/>\n"; |
329
|
|
|
|
|
|
|
} |
330
|
0
|
|
|
|
|
|
return $svg; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
### NaturalRound is a subroutine that rounds a number to 1, 2, 5 or 10 times its order |
334
|
|
|
|
|
|
|
### So 110.34 becomes 100 |
335
|
|
|
|
|
|
|
### 3.1234 becomes 2 |
336
|
|
|
|
|
|
|
### 40 becomes 50 |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub NaturalRound($) |
339
|
|
|
|
|
|
|
{ |
340
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
341
|
0
|
|
|
|
|
|
my $numberToRound = shift; |
342
|
0
|
|
|
|
|
|
my $rounded; |
343
|
0
|
|
|
|
|
|
my $order = int (log ($numberToRound) / log (10)); |
344
|
0
|
|
|
|
|
|
my $remainder = $numberToRound / 10**$order; |
345
|
0
|
0
|
|
|
|
|
if ($remainder < 1.4) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
346
|
|
|
|
|
|
|
{ |
347
|
0
|
|
|
|
|
|
$rounded = 10**$order; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
elsif ($remainder < 3.2) |
350
|
|
|
|
|
|
|
{ |
351
|
0
|
|
|
|
|
|
$rounded = 2 * 10**$order; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
elsif ($remainder < 7.1) |
354
|
|
|
|
|
|
|
{ |
355
|
0
|
|
|
|
|
|
$rounded = 5 * 10**$order; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
else |
358
|
|
|
|
|
|
|
{ |
359
|
0
|
|
|
|
|
|
$rounded = 10 * 10**$order; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
### DarkenHexRGB is a subroutine that makes a rgb color value darker |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub DarkenHexRGB($) |
366
|
|
|
|
|
|
|
{ |
367
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
368
|
0
|
|
|
|
|
|
my $hexString = shift; |
369
|
0
|
|
|
|
|
|
my $darkHexString; |
370
|
0
|
0
|
|
|
|
|
if ($hexString =~ m/^\#/) |
371
|
|
|
|
|
|
|
{ |
372
|
0
|
|
|
|
|
|
$darkHexString = '#'; |
373
|
|
|
|
|
|
|
} |
374
|
0
|
0
|
|
|
|
|
if ($hexString =~ m/^\#?[0-9a-f]{6}$/i) |
375
|
|
|
|
|
|
|
{ |
376
|
0
|
|
|
|
|
|
while ($hexString =~ m/([0-9a-f][0-9a-f])/ig) |
377
|
|
|
|
|
|
|
{ |
378
|
0
|
|
|
|
|
|
$darkHexString .= sprintf "%02lx", int(hex($1)/2); |
379
|
|
|
|
|
|
|
} |
380
|
0
|
|
|
|
|
|
return $darkHexString; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
else |
383
|
|
|
|
|
|
|
{ |
384
|
0
|
|
|
|
|
|
return $hexString; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub NegateHexadecimalRGB($) |
389
|
|
|
|
|
|
|
{ |
390
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
391
|
0
|
|
|
|
|
|
my $hexString = shift; |
392
|
0
|
|
|
|
|
|
my $negHexString; |
393
|
0
|
0
|
|
|
|
|
if ($hexString =~ m/^\#/) |
394
|
|
|
|
|
|
|
{ |
395
|
0
|
|
|
|
|
|
$negHexString = '#'; |
396
|
|
|
|
|
|
|
} |
397
|
0
|
|
|
|
|
|
while ($hexString =~ m/([0-9a-f]{2})/ig) |
398
|
|
|
|
|
|
|
{ |
399
|
0
|
|
|
|
|
|
$negHexString .= sprintf "%02lx", (255 - hex($1)); |
400
|
|
|
|
|
|
|
} |
401
|
0
|
|
|
|
|
|
return $negHexString; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
### XMLEscape is a subroutine that converts special XML characters to their xml encoding character. |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub XMLEscape($) |
407
|
|
|
|
|
|
|
{ |
408
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
409
|
0
|
|
|
|
|
|
my $string = shift; |
410
|
0
|
0
|
|
|
|
|
unless (defined ($string)) |
411
|
|
|
|
|
|
|
{ |
412
|
0
|
|
|
|
|
|
$string = ''; |
413
|
|
|
|
|
|
|
} |
414
|
0
|
|
|
|
|
|
$string =~ s/\&/&/g; |
415
|
0
|
|
|
|
|
|
$string =~ s/>/>/g; |
416
|
0
|
|
|
|
|
|
$string =~ s/</g; |
417
|
0
|
|
|
|
|
|
$string =~ s/\"/"/g; |
418
|
0
|
|
|
|
|
|
$string =~ s/\'/'/g; |
419
|
|
|
|
|
|
|
#$string =~ s/([\x00-\x1f])/sprintf('%02X;', ord($1))/ge; |
420
|
0
|
|
|
|
|
|
$string =~ s/([\x{80}-\x{ffff}])/sprintf('%04X;', ord($1))/ge; |
|
0
|
|
|
|
|
|
|
421
|
0
|
|
|
|
|
|
return $string; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
1; |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
__END__ |