pie.pm
上传用户:shbosideng
上传日期:2013-05-04
资源大小:1555k
文件大小:8k
源码类别:

SNMP编程

开发平台:

C/C++

  1. #==========================================================================
  2. #    Copyright (c) 1995-1998 Martien Verbruggen
  3. #--------------------------------------------------------------------------
  4. #
  5. # Name:
  6. # GIFgraph::pie.pm
  7. #
  8. # $Id: pie.pm,v 1.1.1.1 2002/02/26 10:16:37 oetiker Exp $
  9. #
  10. #==========================================================================
  11. package GIFgraph::pie;
  12. use strict qw(vars refs subs);
  13. use GIFgraph;
  14. use GIFgraph::legend;
  15. use GIFgraph::utils qw(:all);
  16. use GIFgraph::colour qw(:colours :lists);
  17. @GIFgraph::pie::ISA = qw( GIFgraph::legend GIFgraph );
  18. my $ANGLE_OFFSET = 90;
  19. my %Defaults = (
  20.  
  21. # Set the height of the pie.
  22. # Because of the dependency of this on runtime information, this
  23. # is being set in GIFgraph::pie::initialise
  24.  
  25. #   pie_height => _round(0.1*${'gifx'}),
  26.  
  27. # Do you want a 3D pie?
  28.  
  29. '3d'         => 1,
  30.  
  31. # The angle at which to start the first data set
  32. # 0 is at the front/bottom
  33.  
  34. start_angle => 0,
  35. );
  36. {
  37. # PUBLIC methods, documented in pod
  38. sub plot($) # (@data)
  39. {
  40. my $self = shift;
  41. my $data = shift;
  42. $self->check_data($data);
  43. $self->init_graph($self->{graph});
  44. $self->plot_legend($self->{graph});
  45. $self->setup_coords();
  46. $self->draw_text($self->{graph});
  47. $self->draw_pie($self->{graph});
  48. $self->draw_data($data, $self->{graph});
  49. return $self->{graph}->gif;
  50. }
  51.  
  52. sub set_label_font($) # (fontname)
  53. {
  54. my $self = shift;
  55. $self->{lf} = shift;
  56. $self->set( 
  57. lfw => $self->{lf}->width,
  58. lfh => $self->{lf}->height,
  59. );
  60. }
  61.  
  62. sub set_value_font($) # (fontname)
  63. {
  64. my $self = shift;
  65. $self->{vf} = shift;
  66. $self->set( 
  67. vfw => $self->{vf}->width,
  68. vfh => $self->{vf}->height,
  69. );
  70. }
  71.  
  72. # Inherit defaults() from GIFgraph
  73.  
  74. # PRIVATE
  75. # called on construction by new.
  76. sub initialise()
  77. {
  78. my $self = shift;
  79.  
  80. $self->SUPER::initialise();
  81.  
  82. my $key;
  83. foreach $key (keys %Defaults) 
  84. {
  85. $self->set( $key => $Defaults{$key} );
  86. }
  87.  
  88. $self->set( pie_height => _round(0.1 * $self->{gify}) );
  89.  
  90. $self->set_value_font(GD::gdTinyFont);
  91. $self->set_label_font(GD::gdSmallFont);
  92. }
  93. # inherit checkdata from GIFgraph
  94.  
  95. # Setup the coordinate system and colours, calculate the
  96. # relative axis coordinates in respect to the gif size.
  97.  
  98. sub setup_coords()
  99. {
  100. my $s = shift;
  101.  
  102. # Make sure we're not reserving space we don't need.
  103. $s->set(tfh => 0)  unless ( $s->{title} );
  104. $s->set(lfh => 0)  unless ( $s->{label} );
  105. $s->set('3d' => 0)  if     ( $s->{pie_height} <= 0 );
  106. $s->set(pie_height => 0) unless ( $s->{'3d'} );
  107.  
  108. # Calculate the bounding box for the pie, and
  109. # some width, height, and centre parameters
  110. $s->{bottom} = 
  111. $s->{gify} - $s->{pie_height} - $s->{b_margin} -
  112. ( $s->{lfh} ? $s->{lfh} + $s->{text_space} : 0 );
  113. $s->{top} = 
  114. $s->{t_margin} + ( $s->{tfh} ? $s->{tfh} + $s->{text_space} : 0 );
  115. $s->{left} = $s->{l_margin};
  116. $s->{right} = $s->{gifx} - $s->{r_margin};
  117. ( $s->{w}, $s->{h} ) = 
  118. ( $s->{right}-$s->{left}, $s->{bottom}-$s->{top} );
  119. ( $s->{xc}, $s->{yc} ) = 
  120. ( ($s->{right}+$s->{left})/2, ($s->{bottom}+$s->{top})/2 );
  121.  
  122. die "Vertical Gif size too small" 
  123. if ( ($s->{bottom} - $s->{top}) <= 0 );
  124. die "Horizontal Gif size too small"
  125. if ( ($s->{right} - $s->{left}) <= 0 );
  126. }
  127.  
  128. # inherit open_graph from GIFgraph
  129.  
  130. # Put the text on the canvas.
  131. sub draw_text($) # (GD::Image)
  132. {
  133. my $s = shift;
  134. my $g = shift;
  135.  
  136. if ( $s->{tfh} ) 
  137. {
  138. my $tx = $s->{xc} - length($s->{title}) * $s->{tfw}/2;
  139. $g->string($s->{tf}, $tx, $s->{t_margin}, $s->{title}, $s->{tci});
  140. }
  141. if ( $s->{lfh} ) 
  142. {
  143. my $tx = $s->{xc} - length($s->{label}) * $s->{lfw}/2;
  144. my $ty = $s->{gify} - $s->{b_margin} - $s->{lfh};
  145. $g->string($s->{lf}, $tx, $ty, $s->{label}, $s->{lci});
  146. }
  147. }
  148.  
  149. # draw the pie, without the data slices
  150.  
  151. sub draw_pie($) # (GD::Image)
  152. {
  153. my $s = shift;
  154. my $g = shift;
  155. my $left = $s->{xc} - $s->{w}/2;
  156. $g->arc(
  157. $s->{xc}, $s->{yc}, 
  158. $s->{w}, $s->{h},
  159. 0, 360, $s->{acci}
  160. );
  161. $g->arc(
  162. $s->{xc}, $s->{yc} + $s->{pie_height}, 
  163. $s->{w}, $s->{h},
  164. 0, 180, $s->{acci}
  165. ) if ( $s->{'3d'} );
  166. $g->line(
  167. $left, $s->{yc},
  168. $left, $s->{yc} + $s->{pie_height}, 
  169. $s->{acci}
  170. );
  171. $g->line(
  172. $left + $s->{w}, $s->{yc},
  173. $left + $s->{w}, $s->{yc} + $s->{pie_height}, 
  174. $s->{acci}
  175. );
  176. }
  177.  
  178. # Draw the data slices
  179.  
  180. sub draw_data($$) # (@data, GD::Image)
  181. {
  182. my $s = shift;
  183. my $data = shift;
  184. my $g = shift;
  185. my $total = 0;
  186. my $j = 1;  # for now, only one pie..
  187.  
  188. my $i;
  189. for $i ( 0 .. $s->{numpoints} ) 
  190. $total += $data->[$j][$i]; 
  191. }
  192. die "no Total" unless $total;
  193.  
  194. my $ac = $s->{acci}; # Accent colour
  195. my $pb = $s->{start_angle};
  196. my $val = 0;
  197. for $i ( 0..$s->{numpoints} ) 
  198. {
  199. # Set the data colour. Colours index from 1 not 0.
  200. my $dc = $s->set_clr( $g, $s->pick_data_clr($i+1) );
  201. # Set the angles of the pie slice
  202. my $pa = $pb;
  203. $pb += 360 * $data->[1][$i]/$total;
  204. # Calculate the end points of the lines at the boundaries of
  205. # the pie slice
  206. my ($xe, $ye) = 
  207. cartesian(
  208. $s->{w}/2, $pa, 
  209. $s->{xc}, $s->{yc}, $s->{h}/$s->{w}
  210. );
  211. $g->line($s->{xc}, $s->{yc}, $xe, $ye, $ac);
  212. # Draw the lines on the front of the pie
  213. $g->line($xe, $ye, $xe, $ye + $s->{pie_height}, $ac)
  214. if ( in_front($pa) && $s->{'3d'} );
  215. # Make an estimate of a point in the middle of the pie slice
  216. # And fill it
  217. ($xe, $ye) = 
  218. cartesian(
  219. 3 * $s->{w}/8, ($pa+$pb)/2,
  220. $s->{xc}, $s->{yc}, $s->{h}/$s->{w}
  221. );
  222. $g->fillToBorder($xe, $ye, $ac, $dc);
  223. # Horrible kludge by AF # $s->put_label($g, $xe, $ye, $data->[0][$i]);
  224. # If it's 3d, colour the front ones as well
  225. if ( $s->{'3d'} ) 
  226. {
  227. my ($xe, $ye) = $s->_get_pie_front_coords($pa, $pb);
  228. $g->fillToBorder($xe, $ye + $s->{pie_height}/2, $ac, $dc)
  229. if (defined($xe) && defined($ye));
  230. }
  231. }
  232. # More horrible kludge by AF
  233. $pb = $s->{start_angle};
  234. for $i ( 0..$s->{numpoints} ) 
  235. {
  236. my $pa = $pb;
  237. $pb += 360*$data->[1][$i]/$total;
  238. my ($xe, $ye) = 
  239. cartesian(
  240. 3 * $s->{w}/8, ($pa+$pb)/2,
  241. $s->{xc}, $s->{yc}, $s->{h}/$s->{w}
  242. );
  243. $s->put_label($g, $xe, $ye, $$data[0][$i]);
  244. }
  245. } #GIFgraph::pie::draw_data
  246. sub _get_pie_front_coords($$) # (angle 1, angle 2)
  247. {
  248. my $s = shift;
  249. my $pa = level_angle(shift);
  250. my $pb = level_angle(shift);
  251. if (in_front($pa))
  252. {
  253. if (in_front($pb))
  254. {
  255. # both in front
  256. # don't do anything
  257. }
  258. else
  259. {
  260. # start in front, end in back
  261. $pb = $ANGLE_OFFSET;
  262. }
  263. }
  264. else
  265. {
  266. if (in_front($pb))
  267. {
  268. # start in back, end in front
  269. $pa = $ANGLE_OFFSET - 180;
  270. }
  271. else
  272. {
  273. # both in back
  274. return;
  275. }
  276. }
  277. my ($x, $y) = 
  278. cartesian(
  279. $s->{w}/2, ($pa+$pb)/2,
  280. $s->{xc}, $s->{yc}, $s->{h}/$s->{w}
  281. );
  282. return ($x, $y);
  283. }
  284.  
  285. # return true if this angle is on the front of the pie
  286. sub in_front($) # (angle)
  287. {
  288. my $a = level_angle( shift );
  289. ( $a > ($ANGLE_OFFSET - 180) && $a < $ANGLE_OFFSET ) ? 1 : 0;
  290. }
  291.  
  292. # return a value for angle between -180 and 180
  293.  
  294. sub level_angle($) # (angle)
  295. {
  296. my $a = shift;
  297. return level_angle($a-360) if ( $a > 180 );
  298. return level_angle($a+360) if ( $a <= -180 );
  299. return $a;
  300. }
  301.  
  302. # put the label on the pie
  303.  
  304. sub put_label($) # (GD:Image)
  305. {
  306. my $s = shift;
  307. my $g = shift;
  308. my ($x, $y, $label) = @_;
  309. $x -= length($label) * $s->{vfw}/2;
  310. $y -= $s->{vfw}/2;
  311. $g->string($s->{vf}, $x, $y, $label, $s->{alci});
  312. }
  313.  
  314. # return x, y coordinates from input
  315. # radius, angle, center x and y and a scaling factor (height/width)
  316. #
  317. # $ANGLE_OFFSET is used to define where 0 is meant to be
  318. sub cartesian($$$$$) 
  319. {
  320. my ($r, $phi, $xi, $yi, $cr) = @_; 
  321. my $PI=4*atan2(1, 1);
  322. return (
  323. $xi + $r * cos($PI * ($phi + $ANGLE_OFFSET)/180), 
  324. $yi + $cr * $r * sin($PI * ($phi + $ANGLE_OFFSET)/180)
  325. );
  326. }
  327. } # End of package GIFgraph::pie
  328.  
  329. 1;