Filename | /var/www/foswiki11/lib/Foswiki/Plugins/ChartPlugin.pm |
Statements | Executed 55 statements in 2.73ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
13 | 1 | 1 | 170µs | 170µs | commonTagsHandler | Foswiki::Plugins::ChartPlugin::
1 | 1 | 1 | 28µs | 188µs | initPlugin | Foswiki::Plugins::ChartPlugin::
1 | 1 | 1 | 14µs | 27µs | BEGIN@39 | Foswiki::Plugins::ChartPlugin::
1 | 1 | 1 | 10µs | 142µs | BEGIN@42 | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | ChartPlugin | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _Parameters | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _init_defaults | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _makeChart | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _make_error | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _make_filename | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _max | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _min | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _setParameters | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _setTables | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _setTopicContents | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _tables | Foswiki::Plugins::ChartPlugin::
0 | 0 | 0 | 0s | 0s | _timeit | Foswiki::Plugins::ChartPlugin::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # ChartPlugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/ | ||||
2 | # | ||||
3 | # Copyright (C) 2004-2006 Peter Thoeny, Peter@Thoeny.org | ||||
4 | # Plugin written by http://TWiki.org/cgi-bin/view/Main/TaitCyrus | ||||
5 | # Copyright (C) 2008-2011 Foswiki Contributors | ||||
6 | # | ||||
7 | # For licensing info read LICENSE file in the Foswiki root. | ||||
8 | # This program is free software; you can redistribute it and/or | ||||
9 | # modify it under the terms of the GNU General Public License | ||||
10 | # as published by the Free Software Foundation; either version 2 | ||||
11 | # of the License, or (at your option) any later version. | ||||
12 | # | ||||
13 | # This program is distributed in the hope that it will be useful, | ||||
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
16 | # GNU General Public License for more details, published at | ||||
17 | # http://www.gnu.org/copyleft/gpl.html | ||||
18 | # | ||||
19 | # As per the GPL, removal of this notice is prohibited. | ||||
20 | # | ||||
21 | # ========================= | ||||
22 | # | ||||
23 | # This file contains routines for producing PNG graphic files containing | ||||
24 | # chart information, useful for building dashboards. | ||||
25 | # NOTE: ONLY in the case where an old version of GD (1.19 or earlier) is | ||||
26 | # available will GIF's be created. If the GD version is > 1.19, then | ||||
27 | # PNG's are created. | ||||
28 | # | ||||
29 | # This plugin uses Perl object oriented programming. The ChartPlugin | ||||
30 | # object contains several other Perl objects: | ||||
31 | # Table | ||||
32 | # Parameters | ||||
33 | # Chart | ||||
34 | # In addition to having it's own getter/setters. | ||||
35 | |||||
36 | # ========================= | ||||
37 | package Foswiki::Plugins::ChartPlugin; | ||||
38 | |||||
39 | 2 | 56µs | 2 | 40µs | # spent 27µs (14+13) within Foswiki::Plugins::ChartPlugin::BEGIN@39 which was called:
# once (14µs+13µs) by Foswiki::Plugin::BEGIN@2.6 at line 39 # spent 27µs making 1 call to Foswiki::Plugins::ChartPlugin::BEGIN@39
# spent 13µs making 1 call to strict::import |
40 | |||||
41 | # ========================= | ||||
42 | 1 | 6µs | 1 | 132µs | # spent 142µs (10+132) within Foswiki::Plugins::ChartPlugin::BEGIN@42 which was called:
# once (10µs+132µs) by Foswiki::Plugin::BEGIN@2.6 at line 50 # spent 132µs making 1 call to vars::import |
43 | $installWeb $VERSION $RELEASE $debug | ||||
44 | $pluginInitialized $initError | ||||
45 | $defaultType @defaultAreaColors @defaultLineColors | ||||
46 | $defaultWidth $defaultHeight $defaultBGcolor $defaultNumYGrids | ||||
47 | $defaultDataValue $defaultScale $defaultGridColor $defaultPointSize | ||||
48 | $defaultLineWidth | ||||
49 | $defaultBarLeadingSpace $defaultBarTrailingSpace $defaultBarSpace | ||||
50 | 1 | 165µs | 1 | 142µs | ); # spent 142µs making 1 call to Foswiki::Plugins::ChartPlugin::BEGIN@42 |
51 | |||||
52 | 1 | 500ns | our $VERSION = '$Rev: 11481 (2011-04-17) $'; | ||
53 | 1 | 400ns | our $RELEASE = '1.6.0'; | ||
54 | 1 | 300ns | our $SHORT_DESCRIPTION = 'Create area, bar, line and scatter charts to visualize table data'; | ||
55 | |||||
56 | 1 | 100ns | $pluginInitialized = 0; | ||
57 | 1 | 200ns | $initError = ''; | ||
58 | |||||
59 | # ========================= | ||||
60 | # spent 188µs (28+160) within Foswiki::Plugins::ChartPlugin::initPlugin which was called:
# once (28µs+160µs) by Foswiki::Plugin::__ANON__[/var/www/foswiki11/lib/Foswiki/Plugin.pm:241] at line 234 of /var/www/foswiki11/lib/Foswiki/Plugin.pm | ||||
61 | 1 | 4µs | ( my $topic, my $web, my $user, $installWeb ) = @_; | ||
62 | |||||
63 | # check for Plugins.pm versions | ||||
64 | 1 | 18µs | 1 | 9µs | if( $Foswiki::Plugins::VERSION < 1 ) { # spent 9µs making 1 call to version::vxs::VCMP |
65 | &Foswiki::Func::writeWarning( "Version mismatch between ChartPlugin and Plugins.pm" ); | ||||
66 | return 0; | ||||
67 | } | ||||
68 | |||||
69 | # Get plugin debug flag | ||||
70 | 1 | 3µs | 1 | 151µs | $debug = &Foswiki::Func::getPreferencesFlag( "CHARTPLUGIN_DEBUG" ) || 0; # spent 151µs making 1 call to Foswiki::Func::getPreferencesFlag |
71 | |||||
72 | 1 | 400ns | &Foswiki::Func::writeDebug( "- Foswiki::Plugins::ChartPlugin::initPlugin($web.$topic) is OK" ) if $debug; | ||
73 | |||||
74 | # Mark that we are not fully initialized yet. Only get the default | ||||
75 | # values from the plugin topic page iff a CHART is found in a topic | ||||
76 | 1 | 300ns | $pluginInitialized = 0; | ||
77 | 1 | 6µs | return 1; | ||
78 | } | ||||
79 | |||||
80 | # ========================= | ||||
81 | |||||
82 | # Initialize all default values from the plugin topic page. | ||||
83 | sub _init_defaults { | ||||
84 | return if $pluginInitialized; | ||||
85 | $pluginInitialized = 1; | ||||
86 | require Exporter; | ||||
87 | foreach my $module qw( GD POSIX | ||||
88 | Foswiki::Plugins::ChartPlugin::Chart | ||||
89 | Foswiki::Plugins::ChartPlugin::Parameters | ||||
90 | 1 | 2.32ms | 1 | 236µs | Foswiki::Plugins::ChartPlugin::Table) { # spent 236µs making 1 call to CGI::Carp::warn |
91 | eval "require $module"; | ||||
92 | if ($@) { | ||||
93 | $initError = "Required Perl module '$module' not found: $@"; | ||||
94 | return; | ||||
95 | } | ||||
96 | } | ||||
97 | |||||
98 | # Get default chart type | ||||
99 | $defaultType = Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_TYPE" ) || 'line'; | ||||
100 | # Get default chart values | ||||
101 | $defaultWidth = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_WIDTH" ) || 60; | ||||
102 | $defaultHeight = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_HEIGHT" ) || 16; | ||||
103 | my $defaultAreaColors = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_AREA_COLORS" ) | ||||
104 | || "#FF0000 #FFFF00 #00FF00"; | ||||
105 | @defaultAreaColors = split(/[\s,]+/, $defaultAreaColors); | ||||
106 | my $defaultLineColors = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_LINE_COLORS" ) | ||||
107 | || "#FFFF00 #FF00FF #00FFFF"; | ||||
108 | @defaultLineColors = split(/[\s,]+/, $defaultLineColors); | ||||
109 | # Get default chart bgcolor | ||||
110 | $defaultBGcolor = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_BGCOLOR" ) || '#FFFFFF #FFFFFF'; | ||||
111 | # Get default number of Y axis grids | ||||
112 | $defaultNumYGrids = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_NUMYGRIDS" ) || 10; | ||||
113 | # Get default value to use if there is no data seen in the table | ||||
114 | $defaultDataValue = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_DEFAULTDATA" ); | ||||
115 | # Get default value for the scale (linear/semilog) | ||||
116 | $defaultScale = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_SCALE" ); | ||||
117 | # Get default grid color. | ||||
118 | $defaultGridColor = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_GRIDCOLOR" ) || '#000000'; | ||||
119 | # Get default value for the size, in pixels, of drawn data points | ||||
120 | $defaultPointSize = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_POINTSIZE" ) || 2; | ||||
121 | # Get default value for the width, in pixels, of drawn lines | ||||
122 | $defaultLineWidth = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_LINEWIDTH" ) || 3; | ||||
123 | # Get default value for the leading space before the first bar. | ||||
124 | $defaultBarLeadingSpace = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_BARLEADINGSPACE" ) || 0; | ||||
125 | # Get default value for the trailing space after the last bar. | ||||
126 | $defaultBarTrailingSpace = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_BARTRAILINGSPACE" ) || 0; | ||||
127 | # Get default value for the space between bars. | ||||
128 | $defaultBarSpace = &Foswiki::Func::getPreferencesValue( "CHARTPLUGIN_BARSPACE" ) || 0; | ||||
129 | } | ||||
130 | |||||
131 | # Object constructor for creating a ChartPlugin Perl object. The object is | ||||
132 | # initialized with the current web.topic. | ||||
133 | sub ChartPlugin { | ||||
134 | my ($currentTopic, $currentWeb, $currentTopicContents) = @_; | ||||
135 | my $this = {}; | ||||
136 | bless $this; | ||||
137 | $this->{CURRENT_TOPIC} = $currentTopic; | ||||
138 | $this->{CURRENT_WEB} = $currentWeb; | ||||
139 | $this->{CURRENT_TOPICONTENTS} = $currentTopicContents; | ||||
140 | return $this; | ||||
141 | } | ||||
142 | |||||
143 | # Setter for storing the Table object | ||||
144 | sub _setTables { my ($this, $table) = @_; $this->{TABLES} = $table; } | ||||
145 | # Getter for Table object | ||||
146 | sub _tables { my ($this) = @_; return $this->{TABLES}; } | ||||
147 | |||||
148 | # Setter for storing the Parameters object | ||||
149 | sub _setParameters { | ||||
150 | my ($this, $args) = @_; | ||||
151 | $this->{PARAMETERS} = Foswiki::Plugins::ChartPlugin::Parameters->new($args); | ||||
152 | } | ||||
153 | |||||
154 | # Getter for Parameters object | ||||
155 | sub _Parameters { my ($this) = @_; return $this->{PARAMETERS}; } | ||||
156 | |||||
157 | # This routine sets the specified web.topic as the location from where to | ||||
158 | # get the table information. If the specified web.topic happen to be the | ||||
159 | # same as the web.topic from which the %CHART% was found, then the | ||||
160 | # web.topic contents is already part of the ChartPlugin object so there is | ||||
161 | # nothing to do. Otherwise, this routine will read in the specified | ||||
162 | # web.topic getting its contents and using that as the source to parse out | ||||
163 | # table information. | ||||
164 | sub _setTopicContents { | ||||
165 | my ($this, $inWeb, $inTopic) = @_; | ||||
166 | my $topicContents; | ||||
167 | # If $inWeb and $inTopic match the current web/topic, then we already | ||||
168 | # have the topic contents in the object so there is nothing to do. | ||||
169 | # Otherwise, we need to open the specified web/topic and read in its | ||||
170 | # contents. | ||||
171 | if ( ($inWeb eq $this->{CURRENT_WEB}) && ($inTopic eq $this->{CURRENT_TOPIC}) ) { | ||||
172 | $topicContents = $this->{CURRENT_TOPICONTENTS}; | ||||
173 | } else { | ||||
174 | # A difference, so read in the topic. | ||||
175 | (my $meta, $topicContents) = Foswiki::Func::readTopic( $inWeb, $inTopic ); | ||||
176 | # Check to make sure the web.topic actually exists. If not, return | ||||
177 | # undef so the caller can catch the error. | ||||
178 | return undef if (!defined($topicContents) || $topicContents eq ""); | ||||
179 | $topicContents = Foswiki::Func::expandCommonVariables($topicContents, $inTopic, $inWeb); | ||||
180 | } | ||||
181 | |||||
182 | # Lets parse the specified topic contents looking for tables. | ||||
183 | $this->_setTables(Foswiki::Plugins::ChartPlugin::Table->new($topicContents)); | ||||
184 | return 1; | ||||
185 | } | ||||
186 | |||||
187 | # Return the maximum value of the two specified numbers. | ||||
188 | sub _max { | ||||
189 | my ( $v1, $v2 ) = @_; | ||||
190 | return $v1 if( $v1 > $v2 ); | ||||
191 | return $v2; | ||||
192 | } | ||||
193 | |||||
194 | # Return the minimum value of the two specified numbers. | ||||
195 | sub _min { | ||||
196 | my ( $v1, $v2 ) = @_; | ||||
197 | return $v1 if( $v1 < $v2 ); | ||||
198 | return $v2; | ||||
199 | } | ||||
200 | |||||
201 | # Generate the file name in which the graphic file will be placed. | ||||
202 | sub _make_filename { | ||||
203 | my ( $type, $name ) = @_; | ||||
204 | # Generate the file name to be created | ||||
205 | my $fullname; | ||||
206 | # If GD version 1.19 or earlier, then create gif files else png files. | ||||
207 | if( $GD::VERSION > 1.19 ) { | ||||
208 | $fullname = "_ChartPlugin_${type}_${name}.png"; | ||||
209 | } else { | ||||
210 | $fullname = "_ChartPlugin_${type}_${name}.gif"; | ||||
211 | } | ||||
212 | |||||
213 | return $fullname; | ||||
214 | } | ||||
215 | |||||
216 | # This routine returns an red colored error message. | ||||
217 | sub _make_error { | ||||
218 | my ( $msg ) = @_; | ||||
219 | return "<font color=red>ChartPlugin error: $msg</font>"; | ||||
220 | } | ||||
221 | |||||
222 | # Actually construct the chart by parsing out each of the %CHART% | ||||
223 | # parameters, putting the parameters into the chart object, and then | ||||
224 | # creating the chart. | ||||
225 | sub _makeChart { | ||||
226 | my ( $this, $args, $topic, $web ) = @_; | ||||
227 | |||||
228 | # Check to see if the GD module was found. If not, then create an | ||||
229 | # error message to display back to the user. | ||||
230 | if( $initError ) { | ||||
231 | # It appears that a library wasn't found so we return a | ||||
232 | # different type of error that is just plain text. | ||||
233 | return _make_error($initError); | ||||
234 | } | ||||
235 | # Set/parse the %CHART% parameters putting into the ChartPlugin object | ||||
236 | $this->_setParameters ($args); | ||||
237 | |||||
238 | # Make a chart object in which we will place user specified parameters | ||||
239 | my $chart = Foswiki::Plugins::ChartPlugin::Chart->new(); | ||||
240 | |||||
241 | # See if the parameter 'type' is available. This is a required | ||||
242 | # parameter. If it is missing, then generate an error message. | ||||
243 | my $type = $this->_Parameters->getParameter( "type", $defaultType); | ||||
244 | return _make_error("parameter *type* must be specified") if( ! defined $type ); | ||||
245 | my @unknownTypes = grep(!/area|line|bar|arealine|combo|scatter/, ($type)); | ||||
246 | # Check for a valid type | ||||
247 | return _make_error("Invalid value of *$type* for parameter *type* ") if (@unknownTypes); | ||||
248 | $chart->setType($type); | ||||
249 | |||||
250 | # See if the parameter 'subtype' (old name 'datatype') is available. | ||||
251 | my $dataType = $this->_Parameters->getParameter( "datatype", undef); | ||||
252 | my $subType = $this->_Parameters->getParameter( "subtype", undef); | ||||
253 | return _make_error("paramters *datatype* and *subtype* can't both be specified") if (defined $dataType && defined $subType); | ||||
254 | $subType = $dataType if (defined $dataType); | ||||
255 | if (defined $subType) { | ||||
256 | my @subTypes = split(/[\s,]+/, $subType); | ||||
257 | # Check for valid subtypes | ||||
258 | my @unknownSubTypes = grep(!/area|line|point|pline|scatter|bar/, @subTypes); | ||||
259 | return _make_error("unknown subtypes: " . join(", ", @unknownSubTypes)) if (@unknownSubTypes); | ||||
260 | # Now check to make sure that the subtypes specified are valid for the | ||||
261 | # specified type. | ||||
262 | ### Check 'line' type | ||||
263 | if ($type eq "line") { | ||||
264 | @unknownSubTypes = grep(!/line|point|pline/, @subTypes); | ||||
265 | return _make_error("unsupported subtypes: " . join(", ", @unknownSubTypes) . " for type line") if (@unknownSubTypes); | ||||
266 | } | ||||
267 | |||||
268 | ### Check 'area' type | ||||
269 | if ($type eq "area") { | ||||
270 | @unknownSubTypes = grep(!/area/, @subTypes); | ||||
271 | return _make_error("unsupported subtypes: " . join(", ", @unknownSubTypes) . " for type area") if (@unknownSubTypes); | ||||
272 | } | ||||
273 | |||||
274 | ### Check 'scatter' type | ||||
275 | if ($type eq "scatter") { | ||||
276 | @unknownSubTypes = grep(!/area|line|point|pline|bar/, @subTypes); | ||||
277 | return _make_error("unsupported subtypes: " . join(", ", @unknownSubTypes) . " for type scatter") if (@unknownSubTypes); | ||||
278 | } | ||||
279 | |||||
280 | ### Check 'combo' type | ||||
281 | if ($type eq "combo") { | ||||
282 | @unknownSubTypes = grep(!/area|line|point|pline|bar/, @subTypes); | ||||
283 | return _make_error("unsupported subtypes: " . join(", ", @unknownSubTypes) . " for type combo") if (@unknownSubTypes); | ||||
284 | } | ||||
285 | |||||
286 | # All OK so set the subtype. | ||||
287 | $chart->setSubTypes(@subTypes); | ||||
288 | } | ||||
289 | |||||
290 | # See if the parameter 'scale' is available. | ||||
291 | my $scale = $this->_Parameters->getParameter( "scale", $defaultScale); | ||||
292 | if ($scale ne "base10" and $scale ne "linear" and $scale ne "semilog") { | ||||
293 | return _make_error("Invalid value of *$scale* for parameter *scale* "); | ||||
294 | } | ||||
295 | $chart->setScale($scale); | ||||
296 | |||||
297 | # See if the parameter 'name' is available. This is a required | ||||
298 | # parameter. If it is missing, then generate an error message. | ||||
299 | my $name = $this->_Parameters->getParameter( "name", undef); | ||||
300 | return _make_error("parameter *name* must be specified") if( ! defined $name ); | ||||
301 | |||||
302 | # See if the parameter 'web' is available. If not, then default to | ||||
303 | # looking for tables in the current web. | ||||
304 | my $inWeb = $this->_Parameters->getParameter( "web", $web); | ||||
305 | |||||
306 | # See if the parameter 'topic' is available. If not, then default to | ||||
307 | # looking for tables in the current topic. | ||||
308 | my $inTopic = $this->_Parameters->getParameter( "topic", $topic); | ||||
309 | |||||
310 | # Before we parse any further parameters, lets get the contents of the | ||||
311 | # specified web/topic. | ||||
312 | if (! $this->_setTopicContents($inWeb, $inTopic)) { | ||||
313 | return _make_error("Error retrieving Foswiki topic $inWeb<nop>.$inTopic"); | ||||
314 | } | ||||
315 | |||||
316 | # Determine which table the user wants to chart | ||||
317 | my $tableName = $this->_Parameters->getParameter( "table", 1); | ||||
318 | # Verify that the table name is valid. | ||||
319 | if (! $this->_tables->checkTableExists($tableName) ) { | ||||
320 | return _make_error("parameter *table* is not valid table; the specified table '$tableName' does not exist."); | ||||
321 | } | ||||
322 | |||||
323 | # See if the parameter 'title' is available. | ||||
324 | $chart->setTitle($this->_Parameters->getParameter( "title", undef)); | ||||
325 | |||||
326 | # See if the parameter 'xlabel' is available. | ||||
327 | $chart->setXlabel($this->_Parameters->getParameter( "xlabel", undef)); | ||||
328 | |||||
329 | # See if the parameter 'ylabel' is available. | ||||
330 | $chart->setYlabel($this->_Parameters->getParameter( "ylabel", undef)); | ||||
331 | |||||
332 | # See if the parameter 'data' is available. This is a required | ||||
333 | # parameter. If it is missing, then generate an error message. | ||||
334 | my $data = $this->_Parameters->getParameter( "data", undef); | ||||
335 | return _make_error("parameter *data* must be specified") if( ! defined $data ); | ||||
336 | |||||
337 | # See if the parameter 'xaxis' is available. | ||||
338 | my $xAxis = $this->_Parameters->getParameter( "xaxis", undef); | ||||
339 | |||||
340 | # See if the parameter 'yaxis' is available. | ||||
341 | my $yAxis = $this->_Parameters->getParameter( "yaxis", "off"); | ||||
342 | $chart->setYaxis($yAxis); | ||||
343 | |||||
344 | # See if the parameter 'ytic' is available. | ||||
345 | my $yTic = $this->_Parameters->getParameter( "ytics", -1); | ||||
346 | $chart->setNumYTics($yTic); | ||||
347 | |||||
348 | # See if the parameter 'xaxisangle' is available. | ||||
349 | my $xaxisangle = $this->_Parameters->getParameter( "xaxisangle", 0); | ||||
350 | $chart->setXaxisAngle($xaxisangle); | ||||
351 | |||||
352 | # See if the parameter 'ymin' is available. | ||||
353 | my $yMin = $this->_Parameters->getParameter( "ymin", undef); | ||||
354 | if (defined $yMin) { | ||||
355 | if ($scale eq "semilog" && $yMin <= 0) { | ||||
356 | return _make_error("user set ymin=$yMin is <= 0 which is not valid when scale=semilog"); | ||||
357 | } | ||||
358 | } | ||||
359 | $chart->setYmin( $yMin ); | ||||
360 | |||||
361 | # See if the parameter 'ymax' is available. | ||||
362 | my $yMax = $this->_Parameters->getParameter( "ymax", undef); | ||||
363 | if (defined $yMax) { | ||||
364 | if ($scale eq "semilog" && $yMax <= 0) { | ||||
365 | return _make_error("user set ymax=$yMax is <= 0 which is not valid when scale=semilog"); | ||||
366 | } | ||||
367 | } | ||||
368 | $chart->setYmax( $yMax ); | ||||
369 | |||||
370 | # See if the parameter 'numygrids' is available. | ||||
371 | $chart->setNumYGrids( $this->_Parameters->getParameter( "numygrids", $defaultNumYGrids) ); | ||||
372 | |||||
373 | # See if the parameter 'numxgrids' is available. | ||||
374 | my $numxgrids = $this->_Parameters->getParameter( "numxgrids", 10); | ||||
375 | $chart->setNumXGrids($numxgrids); | ||||
376 | |||||
377 | # See if the parameter 'xgrid' is available. | ||||
378 | my $xGrid = $this->_Parameters->getParameter( "xgrid", "dot"); | ||||
379 | $chart->setXgrid($xGrid); | ||||
380 | |||||
381 | # See if the parameter 'ygrid' is available. | ||||
382 | my $yGrid = $this->_Parameters->getParameter( "ygrid", "dot"); | ||||
383 | $chart->setYgrid($yGrid); | ||||
384 | |||||
385 | # See if the parameter 'datalabel' is available. | ||||
386 | my $dataLabels = $this->_Parameters->getParameter( "datalabel", "off"); | ||||
387 | $chart->setDataLabels(split(/[\s,]+/, $dataLabels)) if (defined $dataLabels); | ||||
388 | |||||
389 | # See if the parameter 'legend' is available. | ||||
390 | my $legend = $this->_Parameters->getParameter( "legend", undef); | ||||
391 | |||||
392 | # Get the chart width and height | ||||
393 | $chart->setImageWidth( $this->_Parameters->getParameter( "width", $defaultWidth) ); | ||||
394 | $chart->setImageHeight( $this->_Parameters->getParameter( "height", $defaultHeight) ); | ||||
395 | |||||
396 | # Get the chart IMG 'alt' text. | ||||
397 | my $alt = $this->_Parameters->getParameter( "alt", ""); | ||||
398 | |||||
399 | # Get the chart 'bgcolor' color. | ||||
400 | my $bgcolor = $this->_Parameters->getParameter( "bgcolor", $defaultBGcolor); | ||||
401 | $chart->setBGcolor(split(/[\s,]+/, $bgcolor)); | ||||
402 | |||||
403 | # Set line/area colors. If the parameter 'colors' is defined, then the | ||||
404 | # chart will be made with the user specified colors. Otherwise the | ||||
405 | # chart will be made with the default colors, and then it will depend | ||||
406 | # on if an 'area' or 'line' is being drawn which will determine which | ||||
407 | # set of colors to use. | ||||
408 | $chart->setLineColors(@defaultLineColors); | ||||
409 | $chart->setAreaColors(@defaultAreaColors); | ||||
410 | # See if the parameter 'colors' is available. | ||||
411 | my $colors = $this->_Parameters->getParameter( "colors", undef); | ||||
412 | $chart->setColors(split(/[\s,]+/, $colors)) if (defined $colors); | ||||
413 | |||||
414 | # Get the chart grid color. | ||||
415 | my $gridColor = $this->_Parameters->getParameter( "gridcolor", $defaultGridColor); | ||||
416 | $chart->setGridColor(split(/[\s,]+/, $gridColor)); | ||||
417 | |||||
418 | # See if the parameter 'defaultdata' is available. | ||||
419 | my $DataValueDefault = $this->_Parameters->getParameter( "defaultdata", $defaultDataValue); | ||||
420 | $DataValueDefault = '' if ($DataValueDefault eq "none"); | ||||
421 | $chart->setDefaultDataValue($DataValueDefault); | ||||
422 | |||||
423 | # Get the filename in which to create the graphics file. | ||||
424 | my $filename = _make_filename($type, $name); | ||||
425 | $chart->setAttachmentName($web, $topic, $filename); | ||||
426 | |||||
427 | # Validate the legend data making sure it only specifies a single row | ||||
428 | # or a single column. | ||||
429 | my @legend; | ||||
430 | if ($legend) { | ||||
431 | my $cnt = my @d = $this->_tables->getData($tableName, $legend); | ||||
432 | if ($cnt > 1) { | ||||
433 | @d = Foswiki::Plugins::ChartPlugin::Table::transpose( @d ); | ||||
434 | $cnt = scalar(@d); | ||||
435 | } | ||||
436 | if ($cnt > 1) { | ||||
437 | return _make_error("parameter *legend* specifies multiple ($cnt) rows."); | ||||
438 | } | ||||
439 | if ($cnt == 0) { | ||||
440 | return _make_error("parameter *legend* contains an invalid value '$legend'."); | ||||
441 | } | ||||
442 | @legend = @{$d[0]}; | ||||
443 | #die Data::Dumper->Dump([\@legend]); | ||||
444 | $chart->setLegend(@legend); | ||||
445 | } | ||||
446 | |||||
447 | # If the user specified an X axis range, then extract from the X axis | ||||
448 | # data the starting and ending row/columns. This defines whether the | ||||
449 | # data is row ordered or column ordered. If there is no X axis | ||||
450 | # information specified, then assume that the data is in column order. | ||||
451 | my $columnOrdered = 0; | ||||
452 | my $rowOrdered = 0; | ||||
453 | if (defined ($xAxis)) { | ||||
454 | my ($xAxisRows, $xAxisColumns) = | ||||
455 | $this->_tables->getRowColumnCount($tableName, $xAxis); | ||||
456 | return _make_error("parameter *xaxis* value of '$xAxis' is not valid") | ||||
457 | if (! defined($xAxisRows)); | ||||
458 | if (abs($xAxisRows) > 1) { | ||||
459 | if ($xAxisColumns > 1) { | ||||
460 | return _make_error("parameter *xaxis* specifies multiple (${xAxisRows}X$xAxisColumns) rows and columns."); | ||||
461 | } | ||||
462 | $columnOrdered = 1; | ||||
463 | } else { | ||||
464 | $rowOrdered = 1; | ||||
465 | } | ||||
466 | my @d = $this->_tables->getData($tableName, $xAxis, $columnOrdered); | ||||
467 | return _make_error("no X axis data found in specified area of table [$xAxis]") if (! @d); | ||||
468 | $chart->setXaxis(@{$d[0]}); | ||||
469 | } else { | ||||
470 | $columnOrdered = 1; | ||||
471 | } | ||||
472 | |||||
473 | # Validate the data range as valid | ||||
474 | #my ($dataRows, $dataColumns) = | ||||
475 | # $this->_tables->getRowColumnCount($tableName, $data); | ||||
476 | #return _make_error("parameter *data* value of '$data' is not valid") if (! defined($dataRows)); | ||||
477 | |||||
478 | # Get the actual area data. | ||||
479 | my @data = (); | ||||
480 | @data = $this->_tables->getData($tableName, $data, $columnOrdered ); | ||||
481 | # Validate that there is real data returned. | ||||
482 | return _make_error("no data found in specified area of table [$data]") if (! @data); | ||||
483 | #my @ranges = $this->_tables->getTableRanges($tableName, $data); | ||||
484 | #die $data, ' ', Data::Dumper->Dump([\@ranges]); | ||||
485 | $yMin = $chart->setData(@data); | ||||
486 | # If scale=semilog and any data is <= 0, then error | ||||
487 | if ($scale eq "semilog" && $yMin <= 0) { | ||||
488 | return _make_error("data ($yMin) <= 0 not valid when scale=semilog"); | ||||
489 | } | ||||
490 | |||||
491 | # Make sure that there are enough legends to go with all specified | ||||
492 | # data sets (if legends were specified) | ||||
493 | if ($legend) { | ||||
494 | my $numLegends = @legend; | ||||
495 | my $numDataSets = @data; | ||||
496 | if ($numDataSets != $numLegends) { | ||||
497 | return _make_error("parameter *legend* contains an invalid value '$legend' since it specifies $numLegends legends and there are $numDataSets data sets."); | ||||
498 | } | ||||
499 | } | ||||
500 | |||||
501 | # Set the default point size | ||||
502 | $chart->setPointSize( $this->_Parameters->getParameter( "pointsize", $defaultPointSize ) ); | ||||
503 | |||||
504 | # Set the default line width | ||||
505 | $chart->setLineWidth( $this->_Parameters->getParameter( "linewidth", $defaultLineWidth ) ); | ||||
506 | |||||
507 | # Set default bar graph values | ||||
508 | $chart->setBarLeadingSpace($defaultBarLeadingSpace); | ||||
509 | $chart->setBarTrailingSpace($defaultBarTrailingSpace); | ||||
510 | $chart->setBarSpace($defaultBarSpace); | ||||
511 | |||||
512 | # Create the actual chart. | ||||
513 | my $err = $chart->makeChart(); | ||||
514 | return _make_error("chart error: name=$name: $err") if ($err); | ||||
515 | |||||
516 | # Get remaining parameters and pass to <img ... /> | ||||
517 | my $options = ""; | ||||
518 | my %parameters = $this->_Parameters->getAllParameters(); | ||||
519 | foreach my $k (keys %parameters) { | ||||
520 | $options .= "$k=\"$parameters{$k}\" "; | ||||
521 | } | ||||
522 | # Make a unique value to append to the image name that forces a web | ||||
523 | # browser to reload the image each time the image is viewed. This is | ||||
524 | # done so changes to the values used to generate the chart, or the | ||||
525 | # chart layout specifications, are seen immediately and not ignored | ||||
526 | # because the browser has cached the image. Eventually a hash value | ||||
527 | # should be used such that the user's browser CAN cache the image iff | ||||
528 | # none of the values/parameters used in creating the chart have changed. | ||||
529 | my $timestamp = time(); | ||||
530 | return "<img src=\"%ATTACHURL%/$filename?t=$timestamp\" alt=\"$alt\" $options />"; | ||||
531 | } | ||||
532 | |||||
533 | # The following is really for debugging and timing purposes and is not an | ||||
534 | # advertised interface. This routine basically creates a number of charts | ||||
535 | # and (roughly) times how long it took to create them. | ||||
536 | # Usage: %CHART_TIMER{### <parameters>}% | ||||
537 | # where ### is the number of charts to create and <parameters> are valid | ||||
538 | # %CHART% parameters ('name' is overridden by the timer so is ignored if | ||||
539 | # specified in <parameters> | ||||
540 | sub _timeit { | ||||
541 | my ( $this, $loops, $params, $topic, $web ) = @_; | ||||
542 | my $removeFiles = 0; # Flag on whether to remove the test graphics or not | ||||
543 | my $start_time = time(); | ||||
544 | for (my $i = 0; $i < $loops; $i++) { | ||||
545 | my $str = "$params name=\"timeit_$i\""; | ||||
546 | $this->_makeChart( $str, $topic, $web ); | ||||
547 | } | ||||
548 | my $finish_time = time(); | ||||
549 | my $diff = $finish_time - $start_time; | ||||
550 | # Remove the just created test files. | ||||
551 | if ($removeFiles) { | ||||
552 | for (my $i = 0; $i < $loops; $i++) { | ||||
553 | my ($dir, $filename) = _make_filename("area", "timeit_$i", $topic, $web); | ||||
554 | unlink("$dir/$filename"); | ||||
555 | } | ||||
556 | } | ||||
557 | return "To make $loops charts it (roughly) took $diff seconds.<BR>"; | ||||
558 | } | ||||
559 | |||||
560 | # ========================= | ||||
561 | # spent 170µs within Foswiki::Plugins::ChartPlugin::commonTagsHandler which was called 13 times, avg 13µs/call:
# 13 times (170µs+0s) by Foswiki::Plugin::invoke at line 294 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 13µs/call | ||||
562 | ### my ( $text ) = @_; # do not uncomment, use $_[0] instead | ||||
563 | 13 | 15µs | my $topic = $_[1]; | ||
564 | 13 | 5µs | my $web = $_[2]; | ||
565 | |||||
566 | # If no %CHART%s on this page, then there is nothing to do so just | ||||
567 | # return. | ||||
568 | 13 | 121µs | if ( $_[0] !~ m/%CHART.*{.*}%/) { | ||
569 | # nothing to do | ||||
570 | return; | ||||
571 | } | ||||
572 | _init_defaults(); | ||||
573 | my $chart = ChartPlugin($topic, $web, $_[0]); | ||||
574 | $_[0] =~ s/%CHART{(.*?)}%/$chart->_makeChart($1, $topic, $web)/eog; | ||||
575 | $_[0] =~ s/%CHART_TIMER{(\d+) (.*)}%/$chart->_timeit($1, $2, $topic, $web)/eog; | ||||
576 | } | ||||
577 | |||||
578 | 1 | 4µs | 1; |