gruff 0.5.0-java → 0.9.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (612) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +14 -0
  3. data/.github/ISSUE_TEMPLATE.md +18 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +109 -0
  6. data/.rubocop_todo.yml +136 -0
  7. data/.travis.yml +24 -12
  8. data/.yardopts +1 -0
  9. data/{History.txt → CHANGELOG.md} +63 -24
  10. data/Gemfile +3 -7
  11. data/README.md +53 -25
  12. data/Rakefile +6 -201
  13. data/assets/plastik/blue.png +0 -0
  14. data/assets/plastik/green.png +0 -0
  15. data/assets/plastik/red.png +0 -0
  16. data/docker/Dockerfile +14 -0
  17. data/docker/build.sh +4 -0
  18. data/docker/launch.sh +4 -0
  19. data/gruff.gemspec +18 -14
  20. data/init.rb +2 -0
  21. data/lib/gruff.rb +25 -2
  22. data/lib/gruff/accumulator_bar.rb +7 -7
  23. data/lib/gruff/area.rb +12 -19
  24. data/lib/gruff/bar.rb +60 -44
  25. data/lib/gruff/base.rb +281 -585
  26. data/lib/gruff/bezier.rb +15 -18
  27. data/lib/gruff/bullet.rb +41 -62
  28. data/lib/gruff/dot.rb +26 -61
  29. data/lib/gruff/helper/bar_conversion.rb +47 -0
  30. data/lib/gruff/helper/bar_value_label_mixin.rb +30 -0
  31. data/lib/gruff/{stacked_mixin.rb → helper/stacked_mixin.rb} +8 -8
  32. data/lib/gruff/line.rb +126 -148
  33. data/lib/gruff/mini/bar.rb +8 -9
  34. data/lib/gruff/mini/legend.rb +24 -36
  35. data/lib/gruff/mini/pie.rb +10 -11
  36. data/lib/gruff/mini/side_bar.rb +9 -10
  37. data/lib/gruff/net.rb +37 -82
  38. data/lib/gruff/patch/rmagick.rb +33 -0
  39. data/lib/gruff/patch/string.rb +8 -0
  40. data/lib/gruff/photo_bar.rb +27 -30
  41. data/lib/gruff/pie.rb +185 -89
  42. data/lib/gruff/renderer/bezier.rb +21 -0
  43. data/lib/gruff/renderer/circle.rb +21 -0
  44. data/lib/gruff/renderer/dash_line.rb +22 -0
  45. data/lib/gruff/renderer/dot.rb +39 -0
  46. data/lib/gruff/renderer/ellipse.rb +21 -0
  47. data/lib/gruff/renderer/line.rb +34 -0
  48. data/lib/gruff/renderer/polygon.rb +23 -0
  49. data/lib/gruff/renderer/polyline.rb +21 -0
  50. data/lib/gruff/renderer/rectangle.rb +19 -0
  51. data/lib/gruff/renderer/renderer.rb +127 -0
  52. data/lib/gruff/renderer/text.rb +42 -0
  53. data/lib/gruff/scatter.rb +154 -179
  54. data/lib/gruff/scene.rb +31 -41
  55. data/lib/gruff/side_bar.rb +64 -63
  56. data/lib/gruff/side_stacked_bar.rb +61 -59
  57. data/lib/gruff/spider.rb +25 -49
  58. data/lib/gruff/stacked_area.rb +21 -29
  59. data/lib/gruff/stacked_bar.rb +77 -49
  60. data/lib/gruff/store/base_data.rb +34 -0
  61. data/lib/gruff/store/custom_data.rb +34 -0
  62. data/lib/gruff/store/store.rb +80 -0
  63. data/lib/gruff/store/xy_data.rb +55 -0
  64. data/lib/gruff/themes.rb +32 -33
  65. data/lib/gruff/version.rb +3 -1
  66. metadata +75 -1084
  67. data/Manifest.txt +0 -81
  68. data/RELEASE.md +0 -41
  69. data/assets/bubble.png +0 -0
  70. data/assets/city_scene/background/0000.png +0 -0
  71. data/assets/city_scene/background/0600.png +0 -0
  72. data/assets/city_scene/background/2000.png +0 -0
  73. data/assets/city_scene/clouds/cloudy.png +0 -0
  74. data/assets/city_scene/clouds/partly_cloudy.png +0 -0
  75. data/assets/city_scene/clouds/stormy.png +0 -0
  76. data/assets/city_scene/grass/default.png +0 -0
  77. data/assets/city_scene/haze/true.png +0 -0
  78. data/assets/city_scene/number_sample/1.png +0 -0
  79. data/assets/city_scene/number_sample/2.png +0 -0
  80. data/assets/city_scene/number_sample/default.png +0 -0
  81. data/assets/city_scene/sky/0000.png +0 -0
  82. data/assets/city_scene/sky/0200.png +0 -0
  83. data/assets/city_scene/sky/0400.png +0 -0
  84. data/assets/city_scene/sky/0600.png +0 -0
  85. data/assets/city_scene/sky/0800.png +0 -0
  86. data/assets/city_scene/sky/1000.png +0 -0
  87. data/assets/city_scene/sky/1200.png +0 -0
  88. data/assets/city_scene/sky/1400.png +0 -0
  89. data/assets/city_scene/sky/1500.png +0 -0
  90. data/assets/city_scene/sky/1700.png +0 -0
  91. data/assets/city_scene/sky/2000.png +0 -0
  92. data/assets/pc306715.jpg +0 -0
  93. data/lib/gruff/bar_conversion.rb +0 -46
  94. data/lib/gruff/deprecated.rb +0 -39
  95. data/test/gruff_test_case.rb +0 -154
  96. data/test/image_compare.rb +0 -58
  97. data/test/output/accum_bar.png +0 -0
  98. data/test/output/area_keynote.png +0 -0
  99. data/test/output/area_keynote_small.png +0 -0
  100. data/test/output/area_many.png +0 -0
  101. data/test/output/area_many_areas_small.png +0 -0
  102. data/test/output/area_tiny.png +0 -0
  103. data/test/output/area_wide.png +0 -0
  104. data/test/output/bar2_wrapped_legend_16_400.png +0 -0
  105. data/test/output/bar2_wrapped_legend_16_800.png +0 -0
  106. data/test/output/bar2_wrapped_legend_30_400.png +0 -0
  107. data/test/output/bar2_wrapped_legend_30_800.png +0 -0
  108. data/test/output/bar2_wrapped_legend_4_400.png +0 -0
  109. data/test/output/bar2_wrapped_legend_4_800.png +0 -0
  110. data/test/output/bar2_wrapped_legend__400.png +0 -0
  111. data/test/output/bar2_wrapped_legend__800.png +0 -0
  112. data/test/output/bar_background_gradient_bottom_top.png +0 -0
  113. data/test/output/bar_background_gradient_left_right.png +0 -0
  114. data/test/output/bar_background_gradient_right_left.png +0 -0
  115. data/test/output/bar_background_gradient_top_bottom.png +0 -0
  116. data/test/output/bar_background_gradient_topleft_bottomright.png +0 -0
  117. data/test/output/bar_background_gradient_topright_bottomleft.png +0 -0
  118. data/test/output/bar_formatted_numbers.png +0 -0
  119. data/test/output/bar_keynote.png +0 -0
  120. data/test/output/bar_keynote_small.png +0 -0
  121. data/test/output/bar_long_legend_text.png +0 -0
  122. data/test/output/bar_manual_colors.png +0 -0
  123. data/test/output/bar_marker_shadow.png +0 -0
  124. data/test/output/bar_nearly_zero_max_10.png +0 -0
  125. data/test/output/bar_no_legend.png +0 -0
  126. data/test/output/bar_no_line_markers.png +0 -0
  127. data/test/output/bar_no_title.png +0 -0
  128. data/test/output/bar_no_title_or_legend.png +0 -0
  129. data/test/output/bar_odeo.png +0 -0
  130. data/test/output/bar_one_value.png +0 -0
  131. data/test/output/bar_pos_neg.png +0 -0
  132. data/test/output/bar_rails_keynote.png +0 -0
  133. data/test/output/bar_set_absolute_trunc.png +0 -0
  134. data/test/output/bar_set_label_stagger_height.png +0 -0
  135. data/test/output/bar_set_legend_box_size_lg.png +0 -0
  136. data/test/output/bar_set_legend_box_size_sm.png +0 -0
  137. data/test/output/bar_set_marker.png +0 -0
  138. data/test/output/bar_set_trailing_dots_trunc.png +0 -0
  139. data/test/output/bar_spacing_full.png +0 -0
  140. data/test/output/bar_spacing_half.png +0 -0
  141. data/test/output/bar_spacing_none.png +0 -0
  142. data/test/output/bar_tall_graph.png +0 -0
  143. data/test/output/bar_tall_graph_small.png +0 -0
  144. data/test/output/bar_themed.png +0 -0
  145. data/test/output/bar_title_margin.png +0 -0
  146. data/test/output/bar_value_labels.png +0 -0
  147. data/test/output/bar_wide_graph.png +0 -0
  148. data/test/output/bar_wide_graph_small.png +0 -0
  149. data/test/output/bar_wrapped_legend_16_400.png +0 -0
  150. data/test/output/bar_wrapped_legend_16_800.png +0 -0
  151. data/test/output/bar_wrapped_legend_30_400.png +0 -0
  152. data/test/output/bar_wrapped_legend_30_800.png +0 -0
  153. data/test/output/bar_wrapped_legend_4_400.png +0 -0
  154. data/test/output/bar_wrapped_legend_4_800.png +0 -0
  155. data/test/output/bar_wrapped_legend__400.png +0 -0
  156. data/test/output/bar_wrapped_legend__800.png +0 -0
  157. data/test/output/bar_x_y_labels.png +0 -0
  158. data/test/output/bar_y_increment_1.png +0 -0
  159. data/test/output/bar_y_increment_2.0.png +0 -0
  160. data/test/output/bar_y_increment_20.png +0 -0
  161. data/test/output/bar_y_increment_5.png +0 -0
  162. data/test/output/bar_zero_marker_count.png +0 -0
  163. data/test/output/bar_zero_spacing.png +0 -0
  164. data/test/output/bezier.png +0 -0
  165. data/test/output/bezier_2.png +0 -0
  166. data/test/output/bezier_3.png +0 -0
  167. data/test/output/bullet_greyscale.png +0 -0
  168. data/test/output/bullet_no_options.png +0 -0
  169. data/test/output/dot.png +0 -0
  170. data/test/output/dot_manual_colors.png +0 -0
  171. data/test/output/dot_nearly_zero_max_10.png +0 -0
  172. data/test/output/dot_no_legend.png +0 -0
  173. data/test/output/dot_no_line_markers.png +0 -0
  174. data/test/output/dot_no_title.png +0 -0
  175. data/test/output/dot_no_title_or_legend.png +0 -0
  176. data/test/output/dot_one_value.png +0 -0
  177. data/test/output/dot_pos_neg.png +0 -0
  178. data/test/output/dot_set_legend_box_size_lg.png +0 -0
  179. data/test/output/dot_set_legend_box_size_sm.png +0 -0
  180. data/test/output/dot_set_marker.png +0 -0
  181. data/test/output/dot_small.png +0 -0
  182. data/test/output/dot_tall_graph.png +0 -0
  183. data/test/output/dot_tall_graph_small.png +0 -0
  184. data/test/output/dot_themed.png +0 -0
  185. data/test/output/dot_wide_graph.png +0 -0
  186. data/test/output/dot_wide_graph_small.png +0 -0
  187. data/test/output/dot_x_y_labels.png +0 -0
  188. data/test/output/dot_y_increment_1.png +0 -0
  189. data/test/output/dot_y_increment_2.0.png +0 -0
  190. data/test/output/dot_y_increment_20.png +0 -0
  191. data/test/output/dot_y_increment_5.png +0 -0
  192. data/test/output/enhancements-1.png +0 -0
  193. data/test/output/enhancements.png +0 -0
  194. data/test/output/line_all_neg.png +0 -0
  195. data/test/output/line_all_neg_400.png +0 -0
  196. data/test/output/line_all_neg_no_max.png +0 -0
  197. data/test/output/line_baseline.png +0 -0
  198. data/test/output/line_hang_value.png +0 -0
  199. data/test/output/line_hide_dots.png +0 -0
  200. data/test/output/line_hide_lines.png +0 -0
  201. data/test/output/line_jruby_error.png +0 -0
  202. data/test/output/line_large.png +0 -0
  203. data/test/output/line_large_baseline.png +0 -0
  204. data/test/output/line_legend_at_bottom.png +0 -0
  205. data/test/output/line_many.png +0 -0
  206. data/test/output/line_many_lines_small.png +0 -0
  207. data/test/output/line_many_numbers.png +0 -0
  208. data/test/output/line_marker_label_accuracy.png +0 -0
  209. data/test/output/line_more_sets_than_colors.png +0 -0
  210. data/test/output/line_no_data.png +0 -0
  211. data/test/output/line_no_data_msg.png +0 -0
  212. data/test/output/line_no_data_other.png +0 -0
  213. data/test/output/line_no_hide.png +0 -0
  214. data/test/output/line_no_legend.png +0 -0
  215. data/test/output/line_no_line_markers.png +0 -0
  216. data/test/output/line_no_title.png +0 -0
  217. data/test/output/line_nothing_but_the_graph.png +0 -0
  218. data/test/output/line_one_value.png +0 -0
  219. data/test/output/line_one_value_array.png +0 -0
  220. data/test/output/line_pos_neg.png +0 -0
  221. data/test/output/line_pos_neg_400.png +0 -0
  222. data/test/output/line_reference_lines.png +0 -0
  223. data/test/output/line_similar_high_end_values.png +0 -0
  224. data/test/output/line_similar_high_end_values_with_floor.png +0 -0
  225. data/test/output/line_small_small_zero.png +0 -0
  226. data/test/output/line_small_values.png +0 -0
  227. data/test/output/line_small_values_small.png +0 -0
  228. data/test/output/line_small_zero.png +0 -0
  229. data/test/output/line_some_nil_points.png +0 -0
  230. data/test/output/line_theme_37signals_.png +0 -0
  231. data/test/output/line_theme_37signals_400.png +0 -0
  232. data/test/output/line_theme_keynote_.png +0 -0
  233. data/test/output/line_theme_keynote_400.png +0 -0
  234. data/test/output/line_theme_odeo_.png +0 -0
  235. data/test/output/line_theme_odeo_400.png +0 -0
  236. data/test/output/line_theme_rails_keynote_.png +0 -0
  237. data/test/output/line_theme_rails_keynote_400.png +0 -0
  238. data/test/output/line_tiny.png +0 -0
  239. data/test/output/line_transparent.png +0 -0
  240. data/test/output/line_very_small.png +0 -0
  241. data/test/output/line_webp.webp +0 -0
  242. data/test/output/line_wide_graph.png +0 -0
  243. data/test/output/line_wide_graph_small.png +0 -0
  244. data/test/output/line_xy.png +0 -0
  245. data/test/output/line_xy_pairs.png +0 -0
  246. data/test/output/line_y_axis_increment.png +0 -0
  247. data/test/output/mini_bar.png +0 -0
  248. data/test/output/mini_pie.png +0 -0
  249. data/test/output/mini_pie_right_legend.png +0 -0
  250. data/test/output/mini_side_bar.png +0 -0
  251. data/test/output/mini_side_bar_multi_color.png +0 -0
  252. data/test/output/net_dots_tiny.png +0 -0
  253. data/test/output/net_large.png +0 -0
  254. data/test/output/net_many.png +0 -0
  255. data/test/output/net_many_nets_small.png +0 -0
  256. data/test/output/net_no_data.png +0 -0
  257. data/test/output/net_no_data_msg.png +0 -0
  258. data/test/output/net_no_data_other.png +0 -0
  259. data/test/output/net_no_legend.png +0 -0
  260. data/test/output/net_no_net_markers.png +0 -0
  261. data/test/output/net_no_title.png +0 -0
  262. data/test/output/net_nothing_but_the_graph.png +0 -0
  263. data/test/output/net_similar_high_end_values.png +0 -0
  264. data/test/output/net_small.png +0 -0
  265. data/test/output/net_small_small.png +0 -0
  266. data/test/output/net_small_small_zero.png +0 -0
  267. data/test/output/net_small_zero.png +0 -0
  268. data/test/output/net_wide_graph.png +0 -0
  269. data/test/output/net_wide_graph_small.png +0 -0
  270. data/test/output/pie_equal.png +0 -0
  271. data/test/output/pie_grey.png +0 -0
  272. data/test/output/pie_keynote.png +0 -0
  273. data/test/output/pie_keynote_small.png +0 -0
  274. data/test/output/pie_legend.png +0 -0
  275. data/test/output/pie_legend_small.png +0 -0
  276. data/test/output/pie_nearly_equal.png +0 -0
  277. data/test/output/pie_one_val.png +0 -0
  278. data/test/output/pie_pastel.png +0 -0
  279. data/test/output/pie_simple.png +0 -0
  280. data/test/output/pie_wide.png +0 -0
  281. data/test/output/pie_wrapped_legend_16_400.png +0 -0
  282. data/test/output/pie_wrapped_legend_16_800.png +0 -0
  283. data/test/output/pie_wrapped_legend_30_400.png +0 -0
  284. data/test/output/pie_wrapped_legend_30_800.png +0 -0
  285. data/test/output/pie_wrapped_legend_4_400.png +0 -0
  286. data/test/output/pie_wrapped_legend_4_800.png +0 -0
  287. data/test/output/pie_wrapped_legend__400.png +0 -0
  288. data/test/output/pie_wrapped_legend__800.png +0 -0
  289. data/test/output/pie_zero.png +0 -0
  290. data/test/output/scatter_all_neg.png +0 -0
  291. data/test/output/scatter_all_neg_400.png +0 -0
  292. data/test/output/scatter_basic.png +0 -0
  293. data/test/output/scatter_many.png +0 -0
  294. data/test/output/scatter_no_data.png +0 -0
  295. data/test/output/scatter_no_data_msg.png +0 -0
  296. data/test/output/scatter_no_data_other.png +0 -0
  297. data/test/output/scatter_no_hide.png +0 -0
  298. data/test/output/scatter_no_labels.png +0 -0
  299. data/test/output/scatter_no_legend.png +0 -0
  300. data/test/output/scatter_no_line_markers.png +0 -0
  301. data/test/output/scatter_no_title.png +0 -0
  302. data/test/output/scatter_nothing_but_the_graph.png +0 -0
  303. data/test/output/scatter_pos_neg.png +0 -0
  304. data/test/output/scatter_pos_neg_400.png +0 -0
  305. data/test/output/scatter_wide_graph.png +0 -0
  306. data/test/output/scatter_wide_graph_small.png +0 -0
  307. data/test/output/scene_hazy_night.png +0 -0
  308. data/test/output/scene_not_hazy_day.png +0 -0
  309. data/test/output/scene_partly_cloudy_day.png +0 -0
  310. data/test/output/scene_stormy_day.png +0 -0
  311. data/test/output/scene_stormy_night.png +0 -0
  312. data/test/output/side_bar.png +0 -0
  313. data/test/output/side_bar_data_range.png +0 -0
  314. data/test/output/side_bar_labels.png +0 -0
  315. data/test/output/side_bar_spacing_full.png +0 -0
  316. data/test/output/side_bar_spacing_half.png +0 -0
  317. data/test/output/side_bar_spacing_none.png +0 -0
  318. data/test/output/side_stacked_bar_keynote.png +0 -0
  319. data/test/output/side_stacked_bar_keynote_small.png +0 -0
  320. data/test/output/side_stacked_bar_labels.png +0 -0
  321. data/test/output/side_stacked_bar_long_label.png +0 -0
  322. data/test/output/side_stacked_bar_wide.png +0 -0
  323. data/test/output/spider_37signals.png +0 -0
  324. data/test/output/spider_equal.png +0 -0
  325. data/test/output/spider_keynote.png +0 -0
  326. data/test/output/spider_legend.png +0 -0
  327. data/test/output/spider_legend_small.png +0 -0
  328. data/test/output/spider_lots_of_data.png +0 -0
  329. data/test/output/spider_lots_of_data_normal_names.png +0 -0
  330. data/test/output/spider_nearly_equal.png +0 -0
  331. data/test/output/spider_no_axes.png +0 -0
  332. data/test/output/spider_no_background.png +0 -0
  333. data/test/output/spider_no_print.png +0 -0
  334. data/test/output/spider_overlay_1.png +0 -0
  335. data/test/output/spider_overlay_2.png +0 -0
  336. data/test/output/spider_rotation.png +0 -0
  337. data/test/output/spider_small.png +0 -0
  338. data/test/output/spider_wide.png +0 -0
  339. data/test/output/spider_zero.png +0 -0
  340. data/test/output/stacked_area_keynote.png +0 -0
  341. data/test/output/stacked_area_keynote_small.png +0 -0
  342. data/test/output/stacked_bar_keynote.png +0 -0
  343. data/test/output/stacked_bar_keynote_small.png +0 -0
  344. data/test/output_java/accum_bar.png +0 -0
  345. data/test/output_java/area_keynote.png +0 -0
  346. data/test/output_java/area_keynote_small.png +0 -0
  347. data/test/output_java/area_many.png +0 -0
  348. data/test/output_java/area_many_areas_small.png +0 -0
  349. data/test/output_java/area_tiny.png +0 -0
  350. data/test/output_java/area_wide.png +0 -0
  351. data/test/output_java/bar2_wrapped_legend_16_400.png +0 -0
  352. data/test/output_java/bar2_wrapped_legend_16_800.png +0 -0
  353. data/test/output_java/bar2_wrapped_legend_30_400.png +0 -0
  354. data/test/output_java/bar2_wrapped_legend_30_800.png +0 -0
  355. data/test/output_java/bar2_wrapped_legend_4_400.png +0 -0
  356. data/test/output_java/bar2_wrapped_legend_4_800.png +0 -0
  357. data/test/output_java/bar2_wrapped_legend__400.png +0 -0
  358. data/test/output_java/bar2_wrapped_legend__800.png +0 -0
  359. data/test/output_java/bar_background_gradient_bottom_top.png +0 -0
  360. data/test/output_java/bar_background_gradient_left_right.png +0 -0
  361. data/test/output_java/bar_background_gradient_right_left.png +0 -0
  362. data/test/output_java/bar_background_gradient_top_bottom.png +0 -0
  363. data/test/output_java/bar_background_gradient_topleft_bottomright.png +0 -0
  364. data/test/output_java/bar_background_gradient_topright_bottomleft.png +0 -0
  365. data/test/output_java/bar_formatted_numbers.png +0 -0
  366. data/test/output_java/bar_keynote.png +0 -0
  367. data/test/output_java/bar_keynote_small.png +0 -0
  368. data/test/output_java/bar_long_legend_text.png +0 -0
  369. data/test/output_java/bar_manual_colors.png +0 -0
  370. data/test/output_java/bar_marker_shadow.png +0 -0
  371. data/test/output_java/bar_nearly_zero_max_10.png +0 -0
  372. data/test/output_java/bar_no_legend.png +0 -0
  373. data/test/output_java/bar_no_line_markers.png +0 -0
  374. data/test/output_java/bar_no_title.png +0 -0
  375. data/test/output_java/bar_no_title_or_legend.png +0 -0
  376. data/test/output_java/bar_odeo.png +0 -0
  377. data/test/output_java/bar_one_value.png +0 -0
  378. data/test/output_java/bar_pos_neg.png +0 -0
  379. data/test/output_java/bar_rails_keynote.png +0 -0
  380. data/test/output_java/bar_set_absolute_trunc.png +0 -0
  381. data/test/output_java/bar_set_label_stagger_height.png +0 -0
  382. data/test/output_java/bar_set_legend_box_size_lg.png +0 -0
  383. data/test/output_java/bar_set_legend_box_size_sm.png +0 -0
  384. data/test/output_java/bar_set_marker.png +0 -0
  385. data/test/output_java/bar_set_trailing_dots_trunc.png +0 -0
  386. data/test/output_java/bar_spacing_full.png +0 -0
  387. data/test/output_java/bar_spacing_half.png +0 -0
  388. data/test/output_java/bar_spacing_none.png +0 -0
  389. data/test/output_java/bar_tall_graph.png +0 -0
  390. data/test/output_java/bar_tall_graph_small.png +0 -0
  391. data/test/output_java/bar_themed.png +0 -0
  392. data/test/output_java/bar_title_margin.png +0 -0
  393. data/test/output_java/bar_value_labels.png +0 -0
  394. data/test/output_java/bar_wide_graph.png +0 -0
  395. data/test/output_java/bar_wide_graph_small.png +0 -0
  396. data/test/output_java/bar_wrapped_legend_16_400.png +0 -0
  397. data/test/output_java/bar_wrapped_legend_16_800.png +0 -0
  398. data/test/output_java/bar_wrapped_legend_30_400.png +0 -0
  399. data/test/output_java/bar_wrapped_legend_30_800.png +0 -0
  400. data/test/output_java/bar_wrapped_legend_4_400.png +0 -0
  401. data/test/output_java/bar_wrapped_legend_4_800.png +0 -0
  402. data/test/output_java/bar_wrapped_legend__400.png +0 -0
  403. data/test/output_java/bar_wrapped_legend__800.png +0 -0
  404. data/test/output_java/bar_x_y_labels.png +0 -0
  405. data/test/output_java/bar_y_increment_1.png +0 -0
  406. data/test/output_java/bar_y_increment_2.0.png +0 -0
  407. data/test/output_java/bar_y_increment_20.png +0 -0
  408. data/test/output_java/bar_y_increment_5.png +0 -0
  409. data/test/output_java/bar_zero_marker_count.png +0 -0
  410. data/test/output_java/bar_zero_spacing.png +0 -0
  411. data/test/output_java/bezier.png +0 -0
  412. data/test/output_java/bezier_2.png +0 -0
  413. data/test/output_java/bezier_3.png +0 -0
  414. data/test/output_java/bullet_greyscale.png +0 -0
  415. data/test/output_java/bullet_no_options.png +0 -0
  416. data/test/output_java/dot.png +0 -0
  417. data/test/output_java/dot_manual_colors.png +0 -0
  418. data/test/output_java/dot_nearly_zero_max_10.png +0 -0
  419. data/test/output_java/dot_no_legend.png +0 -0
  420. data/test/output_java/dot_no_line_markers.png +0 -0
  421. data/test/output_java/dot_no_title.png +0 -0
  422. data/test/output_java/dot_no_title_or_legend.png +0 -0
  423. data/test/output_java/dot_one_value.png +0 -0
  424. data/test/output_java/dot_pos_neg.png +0 -0
  425. data/test/output_java/dot_set_legend_box_size_lg.png +0 -0
  426. data/test/output_java/dot_set_legend_box_size_sm.png +0 -0
  427. data/test/output_java/dot_set_marker.png +0 -0
  428. data/test/output_java/dot_small.png +0 -0
  429. data/test/output_java/dot_tall_graph.png +0 -0
  430. data/test/output_java/dot_tall_graph_small.png +0 -0
  431. data/test/output_java/dot_themed.png +0 -0
  432. data/test/output_java/dot_wide_graph.png +0 -0
  433. data/test/output_java/dot_wide_graph_small.png +0 -0
  434. data/test/output_java/dot_x_y_labels.png +0 -0
  435. data/test/output_java/dot_y_increment_1.png +0 -0
  436. data/test/output_java/dot_y_increment_2.0.png +0 -0
  437. data/test/output_java/dot_y_increment_20.png +0 -0
  438. data/test/output_java/dot_y_increment_5.png +0 -0
  439. data/test/output_java/enhancements-1.png +0 -0
  440. data/test/output_java/enhancements.png +0 -0
  441. data/test/output_java/line_all_neg.png +0 -0
  442. data/test/output_java/line_all_neg_400.png +0 -0
  443. data/test/output_java/line_all_neg_no_max.png +0 -0
  444. data/test/output_java/line_baseline.png +0 -0
  445. data/test/output_java/line_hang_value.png +0 -0
  446. data/test/output_java/line_hide_dots.png +0 -0
  447. data/test/output_java/line_hide_lines.png +0 -0
  448. data/test/output_java/line_jruby_error.png +0 -0
  449. data/test/output_java/line_large.png +0 -0
  450. data/test/output_java/line_large_baseline.png +0 -0
  451. data/test/output_java/line_legend_at_bottom.png +0 -0
  452. data/test/output_java/line_many.png +0 -0
  453. data/test/output_java/line_many_lines_small.png +0 -0
  454. data/test/output_java/line_many_numbers.png +0 -0
  455. data/test/output_java/line_marker_label_accuracy.png +0 -0
  456. data/test/output_java/line_more_sets_than_colors.png +0 -0
  457. data/test/output_java/line_no_data.png +0 -0
  458. data/test/output_java/line_no_data_msg.png +0 -0
  459. data/test/output_java/line_no_data_other.png +0 -0
  460. data/test/output_java/line_no_hide.png +0 -0
  461. data/test/output_java/line_no_legend.png +0 -0
  462. data/test/output_java/line_no_line_markers.png +0 -0
  463. data/test/output_java/line_no_title.png +0 -0
  464. data/test/output_java/line_nothing_but_the_graph.png +0 -0
  465. data/test/output_java/line_one_value.png +0 -0
  466. data/test/output_java/line_one_value_array.png +0 -0
  467. data/test/output_java/line_pos_neg.png +0 -0
  468. data/test/output_java/line_pos_neg_400.png +0 -0
  469. data/test/output_java/line_reference_lines.png +0 -0
  470. data/test/output_java/line_similar_high_end_values.png +0 -0
  471. data/test/output_java/line_similar_high_end_values_with_floor.png +0 -0
  472. data/test/output_java/line_small_small_zero.png +0 -0
  473. data/test/output_java/line_small_values.png +0 -0
  474. data/test/output_java/line_small_values_small.png +0 -0
  475. data/test/output_java/line_small_zero.png +0 -0
  476. data/test/output_java/line_some_nil_points.png +0 -0
  477. data/test/output_java/line_theme_37signals_.png +0 -0
  478. data/test/output_java/line_theme_37signals_400.png +0 -0
  479. data/test/output_java/line_theme_keynote_.png +0 -0
  480. data/test/output_java/line_theme_keynote_400.png +0 -0
  481. data/test/output_java/line_theme_odeo_.png +0 -0
  482. data/test/output_java/line_theme_odeo_400.png +0 -0
  483. data/test/output_java/line_theme_rails_keynote_.png +0 -0
  484. data/test/output_java/line_theme_rails_keynote_400.png +0 -0
  485. data/test/output_java/line_tiny.png +0 -0
  486. data/test/output_java/line_transparent.png +0 -0
  487. data/test/output_java/line_very_small.png +0 -0
  488. data/test/output_java/line_webp.webp +0 -0
  489. data/test/output_java/line_wide_graph.png +0 -0
  490. data/test/output_java/line_wide_graph_small.png +0 -0
  491. data/test/output_java/line_xy.png +0 -0
  492. data/test/output_java/line_xy_pairs.png +0 -0
  493. data/test/output_java/line_y_axis_increment.png +0 -0
  494. data/test/output_java/mini_bar.png +0 -0
  495. data/test/output_java/mini_pie.png +0 -0
  496. data/test/output_java/mini_pie_right_legend.png +0 -0
  497. data/test/output_java/mini_side_bar.png +0 -0
  498. data/test/output_java/mini_side_bar_multi_color.png +0 -0
  499. data/test/output_java/net_dots_tiny.png +0 -0
  500. data/test/output_java/net_large.png +0 -0
  501. data/test/output_java/net_many.png +0 -0
  502. data/test/output_java/net_many_nets_small.png +0 -0
  503. data/test/output_java/net_no_data.png +0 -0
  504. data/test/output_java/net_no_data_msg.png +0 -0
  505. data/test/output_java/net_no_data_other.png +0 -0
  506. data/test/output_java/net_no_legend.png +0 -0
  507. data/test/output_java/net_no_net_markers.png +0 -0
  508. data/test/output_java/net_no_title.png +0 -0
  509. data/test/output_java/net_nothing_but_the_graph.png +0 -0
  510. data/test/output_java/net_similar_high_end_values.png +0 -0
  511. data/test/output_java/net_small.png +0 -0
  512. data/test/output_java/net_small_small.png +0 -0
  513. data/test/output_java/net_small_small_zero.png +0 -0
  514. data/test/output_java/net_small_zero.png +0 -0
  515. data/test/output_java/net_wide_graph.png +0 -0
  516. data/test/output_java/net_wide_graph_small.png +0 -0
  517. data/test/output_java/pie_equal.png +0 -0
  518. data/test/output_java/pie_grey.png +0 -0
  519. data/test/output_java/pie_keynote.png +0 -0
  520. data/test/output_java/pie_keynote_small.png +0 -0
  521. data/test/output_java/pie_legend.png +0 -0
  522. data/test/output_java/pie_legend_small.png +0 -0
  523. data/test/output_java/pie_nearly_equal.png +0 -0
  524. data/test/output_java/pie_one_val.png +0 -0
  525. data/test/output_java/pie_pastel.png +0 -0
  526. data/test/output_java/pie_simple.png +0 -0
  527. data/test/output_java/pie_wide.png +0 -0
  528. data/test/output_java/pie_wrapped_legend_16_400.png +0 -0
  529. data/test/output_java/pie_wrapped_legend_16_800.png +0 -0
  530. data/test/output_java/pie_wrapped_legend_30_400.png +0 -0
  531. data/test/output_java/pie_wrapped_legend_30_800.png +0 -0
  532. data/test/output_java/pie_wrapped_legend_4_400.png +0 -0
  533. data/test/output_java/pie_wrapped_legend_4_800.png +0 -0
  534. data/test/output_java/pie_wrapped_legend__400.png +0 -0
  535. data/test/output_java/pie_wrapped_legend__800.png +0 -0
  536. data/test/output_java/pie_zero.png +0 -0
  537. data/test/output_java/scatter_all_neg.png +0 -0
  538. data/test/output_java/scatter_all_neg_400.png +0 -0
  539. data/test/output_java/scatter_basic.png +0 -0
  540. data/test/output_java/scatter_many.png +0 -0
  541. data/test/output_java/scatter_no_data.png +0 -0
  542. data/test/output_java/scatter_no_data_msg.png +0 -0
  543. data/test/output_java/scatter_no_data_other.png +0 -0
  544. data/test/output_java/scatter_no_hide.png +0 -0
  545. data/test/output_java/scatter_no_labels.png +0 -0
  546. data/test/output_java/scatter_no_legend.png +0 -0
  547. data/test/output_java/scatter_no_line_markers.png +0 -0
  548. data/test/output_java/scatter_no_title.png +0 -0
  549. data/test/output_java/scatter_nothing_but_the_graph.png +0 -0
  550. data/test/output_java/scatter_pos_neg.png +0 -0
  551. data/test/output_java/scatter_pos_neg_400.png +0 -0
  552. data/test/output_java/scatter_wide_graph.png +0 -0
  553. data/test/output_java/scatter_wide_graph_small.png +0 -0
  554. data/test/output_java/scene_hazy_night.png +0 -0
  555. data/test/output_java/scene_not_hazy_day.png +0 -0
  556. data/test/output_java/scene_partly_cloudy_day.png +0 -0
  557. data/test/output_java/scene_stormy_day.png +0 -0
  558. data/test/output_java/scene_stormy_night.png +0 -0
  559. data/test/output_java/side_bar.png +0 -0
  560. data/test/output_java/side_bar_data_range.png +0 -0
  561. data/test/output_java/side_bar_labels.png +0 -0
  562. data/test/output_java/side_bar_spacing_full.png +0 -0
  563. data/test/output_java/side_bar_spacing_half.png +0 -0
  564. data/test/output_java/side_bar_spacing_none.png +0 -0
  565. data/test/output_java/side_stacked_bar_keynote.png +0 -0
  566. data/test/output_java/side_stacked_bar_keynote_small.png +0 -0
  567. data/test/output_java/side_stacked_bar_labels.png +0 -0
  568. data/test/output_java/side_stacked_bar_long_label.png +0 -0
  569. data/test/output_java/side_stacked_bar_wide.png +0 -0
  570. data/test/output_java/spider_37signals.png +0 -0
  571. data/test/output_java/spider_equal.png +0 -0
  572. data/test/output_java/spider_keynote.png +0 -0
  573. data/test/output_java/spider_legend.png +0 -0
  574. data/test/output_java/spider_legend_small.png +0 -0
  575. data/test/output_java/spider_lots_of_data.png +0 -0
  576. data/test/output_java/spider_lots_of_data_normal_names.png +0 -0
  577. data/test/output_java/spider_nearly_equal.png +0 -0
  578. data/test/output_java/spider_no_axes.png +0 -0
  579. data/test/output_java/spider_no_background.png +0 -0
  580. data/test/output_java/spider_no_print.png +0 -0
  581. data/test/output_java/spider_overlay_1.png +0 -0
  582. data/test/output_java/spider_overlay_2.png +0 -0
  583. data/test/output_java/spider_rotation.png +0 -0
  584. data/test/output_java/spider_small.png +0 -0
  585. data/test/output_java/spider_wide.png +0 -0
  586. data/test/output_java/spider_zero.png +0 -0
  587. data/test/output_java/stacked_area_keynote.png +0 -0
  588. data/test/output_java/stacked_area_keynote_small.png +0 -0
  589. data/test/output_java/stacked_bar_keynote.png +0 -0
  590. data/test/output_java/stacked_bar_keynote_small.png +0 -0
  591. data/test/test_accumulator_bar.rb +0 -51
  592. data/test/test_area.rb +0 -134
  593. data/test/test_bar.rb +0 -505
  594. data/test/test_base.rb +0 -8
  595. data/test/test_bezier.rb +0 -33
  596. data/test/test_bullet.rb +0 -26
  597. data/test/test_dot.rb +0 -263
  598. data/test/test_legend.rb +0 -68
  599. data/test/test_line.rb +0 -657
  600. data/test/test_mini_bar.rb +0 -33
  601. data/test/test_mini_pie.rb +0 -25
  602. data/test/test_mini_side_bar.rb +0 -36
  603. data/test/test_net.rb +0 -231
  604. data/test/test_photo.rb +0 -41
  605. data/test/test_pie.rb +0 -154
  606. data/test/test_scatter.rb +0 -233
  607. data/test/test_scene.rb +0 -100
  608. data/test/test_side_bar.rb +0 -56
  609. data/test/test_sidestacked_bar.rb +0 -105
  610. data/test/test_spider.rb +0 -226
  611. data/test/test_stacked_area.rb +0 -52
  612. data/test/test_stacked_bar.rb +0 -52
data/init.rb CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # For Rails
2
4
  require 'gruff'
@@ -1,8 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rmagick'
1
4
  require 'gruff/version'
2
5
 
3
6
  # Extra full path added to fix loading errors on some installations.
4
7
 
5
- %w(
8
+ %w[
9
+ patch/rmagick
10
+ patch/string
11
+
6
12
  themes
7
13
  base
8
14
  area
@@ -23,10 +29,27 @@ require 'gruff/version'
23
29
 
24
30
  scene
25
31
 
32
+ renderer/renderer
33
+ renderer/rectangle
34
+ renderer/circle
35
+ renderer/dash_line
36
+ renderer/line
37
+ renderer/polyline
38
+ renderer/polygon
39
+ renderer/bezier
40
+ renderer/ellipse
41
+ renderer/dot
42
+ renderer/text
43
+
44
+ store/store
45
+ store/base_data
46
+ store/custom_data
47
+ store/xy_data
48
+
26
49
  mini/legend
27
50
  mini/bar
28
51
  mini/pie
29
52
  mini/side_bar
30
- ).each do |filename|
53
+ ].each do |filename|
31
54
  require "gruff/#{filename}"
32
55
  end
@@ -1,18 +1,18 @@
1
- require File.dirname(__FILE__) + '/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'gruff/base'
2
4
 
3
- ##
4
5
  # A special bar graph that shows a single dataset as a set of
5
- # stacked bars. The bottom bar shows the running total and
6
+ # stacked bars. The bottom bar shows the running total and
6
7
  # the top bar shows the new value being added to the array.
7
-
8
8
  class Gruff::AccumulatorBar < Gruff::StackedBar
9
9
  def draw
10
- raise(Gruff::IncorrectNumberOfDatasetsException) unless @data.length == 1
10
+ raise(Gruff::IncorrectNumberOfDatasetsException) unless store.length == 1
11
11
 
12
- accum_array = @data.first[DATA_VALUES_INDEX][0..-2].inject([0]) { |a, v| a << a.last + v}
12
+ accum_array = store.data.first.points[0..-2].reduce([0]) { |a, v| a << a.last + v }
13
13
  data 'Accumulator', accum_array
14
14
  set_colors
15
- @data.reverse!
15
+ store.reverse!
16
16
  super
17
17
  end
18
18
  end
@@ -1,37 +1,33 @@
1
+ # frozen_string_literal: true
1
2
 
2
- require File.dirname(__FILE__) + '/base'
3
+ require 'gruff/base'
3
4
 
4
5
  class Gruff::Area < Gruff::Base
5
- def initialize(*)
6
+ def initialize_ivars
6
7
  super
7
8
  @sorted_drawing = true
8
9
  end
10
+ private :initialize_ivars
9
11
 
10
12
  def draw
11
13
  super
12
14
 
13
- return unless @has_data
15
+ return unless data_given?
14
16
 
15
- @x_increment = @graph_width / (@column_count - 1).to_f
16
- @d = @d.stroke 'transparent'
17
+ x_increment = @graph_width / (column_count - 1).to_f
17
18
 
18
- @norm_data.each do |data_row|
19
- poly_points = Array.new
20
- prev_x = prev_y = 0.0
21
- @d = @d.fill data_row[DATA_COLOR_INDEX]
19
+ store.norm_data.each do |data_row|
20
+ poly_points = []
22
21
 
23
- data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
22
+ data_row.points.each_with_index do |data_point, index|
24
23
  # Use incremented x and scaled y
25
- new_x = @graph_left + (@x_increment * index)
24
+ new_x = @graph_left + (x_increment * index)
26
25
  new_y = @graph_top + (@graph_height - data_point * @graph_height)
27
26
 
28
27
  poly_points << new_x
29
28
  poly_points << new_y
30
29
 
31
30
  draw_label(new_x, index)
32
-
33
- prev_x = new_x
34
- prev_y = new_y
35
31
  end
36
32
 
37
33
  # Add closing points, draw polygon
@@ -40,12 +36,9 @@ class Gruff::Area < Gruff::Base
40
36
  poly_points << @graph_left
41
37
  poly_points << @graph_bottom - 1
42
38
 
43
- @d = @d.polyline(*poly_points)
44
-
39
+ Gruff::Renderer::Polygon.new(color: data_row.color).render(poly_points)
45
40
  end
46
41
 
47
- @d.draw(@base_image)
42
+ Gruff::Renderer.finish
48
43
  end
49
-
50
-
51
44
  end
@@ -1,24 +1,39 @@
1
- require File.dirname(__FILE__) + '/base'
2
- require File.dirname(__FILE__) + '/bar_conversion'
1
+ # frozen_string_literal: true
3
2
 
4
- class Gruff::Bar < Gruff::Base
3
+ require 'gruff/base'
4
+ require 'gruff/helper/bar_conversion'
5
5
 
6
- # Spacing factor applied between bars
6
+ class Gruff::Bar < Gruff::Base
7
+ # Spacing factor applied between bars.
7
8
  attr_accessor :bar_spacing
8
9
 
9
- def initialize(*args)
10
+ # Spacing factor applied between a group of bars belonging to the same label.
11
+ attr_accessor :group_spacing
12
+
13
+ # Set the number output format for labels using sprintf.
14
+ # Default is +"%.2f"+.
15
+ attr_accessor :label_formatting
16
+
17
+ # Output the values for the bars on a bar graph.
18
+ # Default is +false+.
19
+ attr_accessor :show_labels_for_bar_values
20
+
21
+ def initialize_ivars
10
22
  super
11
23
  @spacing_factor = 0.9
24
+ @label_formatting = nil
25
+ @show_labels_for_bar_values = false
12
26
  end
27
+ private :initialize_ivars
13
28
 
14
29
  def draw
15
30
  # Labels will be centered over the left of the bar if
16
- # there are more labels than columns. This is basically the same
31
+ # there are more labels than columns. This is basically the same
17
32
  # as where it would be for a line graph.
18
- @center_labels_over_point = (@labels.keys.length > @column_count ? true : false)
19
-
33
+ @center_labels_over_point = (@labels.keys.length > column_count)
34
+
20
35
  super
21
- return unless @has_data
36
+ return unless data_given?
22
37
 
23
38
  draw_bars
24
39
  end
@@ -28,9 +43,10 @@ class Gruff::Bar < Gruff::Base
28
43
  # and 1 means that each bars' width is nearly 0 (so each bar is a simple
29
44
  # line with no x dimension).
30
45
  #
31
- # Default value is 0.9.
46
+ # Default value is +0.9+.
32
47
  def spacing_factor=(space_percent)
33
- raise ArgumentError, 'spacing_factor must be between 0.00 and 1.00' unless (space_percent >= 0 and space_percent <= 1)
48
+ raise ArgumentError, 'spacing_factor must be between 0.00 and 1.00' unless (space_percent >= 0) && (space_percent <= 1)
49
+
34
50
  @spacing_factor = (1 - space_percent)
35
51
  end
36
52
 
@@ -41,68 +57,68 @@ protected
41
57
  #
42
58
  # Columns sit side-by-side.
43
59
  @bar_spacing ||= @spacing_factor # space between the bars
44
- @bar_width = @graph_width / (@column_count * @data.length).to_f
45
- padding = (@bar_width * (1 - @bar_spacing)) / 2
60
+ @group_spacing ||= 10
46
61
 
47
- @d = @d.stroke_opacity 0.0
62
+ bar_width = (@graph_width - calculate_spacing) / (column_count * store.length).to_f
63
+ padding = (bar_width * (1 - @bar_spacing)) / 2
48
64
 
49
65
  # Setup the BarConversion Object
50
- conversion = Gruff::BarConversion.new()
66
+ conversion = Gruff::BarConversion.new
51
67
  conversion.graph_height = @graph_height
52
68
  conversion.graph_top = @graph_top
53
69
 
54
70
  # Set up the right mode [1,2,3] see BarConversion for further explanation
55
- if @minimum_value >= 0 then
56
- # all bars go from zero to positiv
71
+ if minimum_value >= 0
72
+ # all bars go from zero to positive
57
73
  conversion.mode = 1
74
+ elsif maximum_value <= 0
75
+ # all bars go from 0 to negative
76
+ conversion.mode = 2
58
77
  else
59
- # all bars go from 0 to negativ
60
- if @maximum_value <= 0 then
61
- conversion.mode = 2
62
- else
63
- # bars either go from zero to negativ or to positiv
64
- conversion.mode = 3
65
- conversion.spread = @spread
66
- conversion.minimum_value = @minimum_value
67
- conversion.zero = -@minimum_value/@spread
68
- end
78
+ # bars either go from zero to negative or to positive
79
+ conversion.mode = 3
80
+ conversion.spread = @spread
81
+ conversion.minimum_value = minimum_value
82
+ conversion.zero = -minimum_value / @spread
69
83
  end
70
84
 
71
85
  # iterate over all normalised data
72
- @norm_data.each_with_index do |data_row, row_index|
86
+ store.norm_data.each_with_index do |data_row, row_index|
87
+ data_row.points.each_with_index do |data_point, point_index|
88
+ group_spacing = @group_spacing * @scale * point_index
73
89
 
74
- data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
75
90
  # Use incremented x and scaled y
76
91
  # x
77
- left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index))) + padding
78
- right_x = left_x + @bar_width * @bar_spacing
92
+ left_x = @graph_left + (bar_width * (row_index + point_index + ((store.length - 1) * point_index))) + padding + group_spacing
93
+ right_x = left_x + bar_width * @bar_spacing
79
94
  # y
80
- conv = []
81
- conversion.get_left_y_right_y_scaled( data_point, conv )
95
+ left_y, right_y = conversion.get_left_y_right_y_scaled(data_point)
82
96
 
83
97
  # create new bar
84
- @d = @d.fill data_row[DATA_COLOR_INDEX]
85
- @d = @d.rectangle(left_x, conv[0], right_x, conv[1])
98
+ rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
99
+ rect_renderer.render(left_x, left_y, right_x, right_y)
86
100
 
87
101
  # Calculate center based on bar_width and current row
88
- label_center = @graph_left +
89
- (@data.length * @bar_width * point_index) +
90
- (@data.length * @bar_width / 2.0)
102
+ label_center = @graph_left + group_spacing + (store.length * bar_width * point_index) + (store.length * bar_width / 2.0)
91
103
 
92
104
  # Subtract half a bar width to center left if requested
93
- draw_label(label_center - (@center_labels_over_point ? @bar_width / 2.0 : 0.0), point_index)
105
+ draw_label(label_center, point_index)
94
106
  if @show_labels_for_bar_values
95
- val = (@label_formatting || '%.2f') % @norm_data[row_index][3][point_index]
96
- draw_value_label(left_x + (right_x - left_x)/2, conv[0]-30, val.commify, true)
107
+ raw_value = store.data[row_index].points[point_index]
108
+ val = (@label_formatting || '%.2f') % raw_value
109
+ y = raw_value >= 0 ? left_y - 30 : left_y + 12
110
+ draw_value_label(left_x + (right_x - left_x) / 2, y, val.commify, true)
97
111
  end
98
112
  end
99
-
100
113
  end
101
114
 
102
115
  # Draw the last label if requested
103
- draw_label(@graph_right, @column_count) if @center_labels_over_point
116
+ draw_label(@graph_right, column_count, Magick::NorthWestGravity) if @center_labels_over_point
104
117
 
105
- @d.draw(@base_image)
118
+ Gruff::Renderer.finish
106
119
  end
107
120
 
121
+ def calculate_spacing
122
+ @scale * @group_spacing * (column_count - 1)
123
+ end
108
124
  end
@@ -1,8 +1,7 @@
1
- require 'rubygems'
2
- require 'RMagick'
3
- require 'bigdecimal'
1
+ # frozen_string_literal: true
4
2
 
5
- require File.dirname(__FILE__) + '/deprecated'
3
+ require 'rmagick'
4
+ require 'bigdecimal'
6
5
 
7
6
  ##
8
7
  # = Gruff. Graphs.
@@ -16,48 +15,34 @@ require File.dirname(__FILE__) + '/deprecated'
16
15
  # David Stokar, Paul Rogers, Dave Woodward, Frank Oxener, Kevin Clark, Cies
17
16
  # Breijs, Richard Cowin, and a cast of thousands.
18
17
  #
19
- # See Gruff::Base#theme= for setting themes.
20
-
18
+ # See {Gruff::Base#theme=} for setting themes.
21
19
  module Gruff
22
20
  class Base
23
-
24
- include Magick
25
- include Deprecated
26
-
27
- # Draw extra lines showing where the margins and text centers are
28
- DEBUG = false
29
-
30
- # Used for navigating the array of data to plot
31
- DATA_LABEL_INDEX = 0
32
- DATA_VALUES_INDEX = 1
33
- DATA_COLOR_INDEX = 2
34
- DATA_VALUES_X_INDEX = 3
35
-
36
- # Space around text elements. Mostly used for vertical spacing
21
+ # Space around text elements. Mostly used for vertical spacing.
37
22
  LEGEND_MARGIN = TITLE_MARGIN = 20.0
38
23
  LABEL_MARGIN = 10.0
39
24
  DEFAULT_MARGIN = 20.0
40
25
 
41
- DEFAULT_TARGET_WIDTH = 800
26
+ DEFAULT_TARGET_WIDTH = 800.0
42
27
 
43
28
  THOUSAND_SEPARATOR = ','
44
29
 
45
- # Blank space above the graph
30
+ # Blank space above the graph.
46
31
  attr_accessor :top_margin
47
32
 
48
- # Blank space below the graph
33
+ # Blank space below the graph.
49
34
  attr_accessor :bottom_margin
50
35
 
51
- # Blank space to the right of the graph
36
+ # Blank space to the right of the graph.
52
37
  attr_accessor :right_margin
53
38
 
54
- # Blank space to the left of the graph
39
+ # Blank space to the left of the graph.
55
40
  attr_accessor :left_margin
56
41
 
57
- # Blank space below the title
42
+ # Blank space below the title.
58
43
  attr_accessor :title_margin
59
44
 
60
- # Blank space below the legend
45
+ # Blank space below the legend.
61
46
  attr_accessor :legend_margin
62
47
 
63
48
  # A hash of names for the individual columns, where the key is the array
@@ -65,7 +50,8 @@ module Gruff
65
50
  #
66
51
  # Not all columns need to be named.
67
52
  #
68
- # Example: 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008
53
+ # @example
54
+ # { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
69
55
  attr_accessor :labels
70
56
 
71
57
  # Used internally for spacing.
@@ -76,100 +62,88 @@ module Gruff
76
62
  # Used internally for horizontal graph types.
77
63
  attr_accessor :has_left_labels
78
64
 
79
- # A label for the bottom of the graph
65
+ # A label for the bottom of the graph.
80
66
  attr_accessor :x_axis_label
81
67
 
82
- # A label for the left side of the graph
68
+ # A label for the left side of the graph.
83
69
  attr_accessor :y_axis_label
84
70
 
85
- # attr_accessor :x_axis_increment
71
+ # Manually set increment of the vertical marking lines.
72
+ attr_accessor :x_axis_increment
86
73
 
87
- # Manually set increment of the horizontal marking lines
74
+ # Manually set increment of the horizontal marking lines.
88
75
  attr_accessor :y_axis_increment
89
76
 
90
- # Height of staggering between labels (Bar graph only)
77
+ # Height of staggering between labels (Bar graph only).
91
78
  attr_accessor :label_stagger_height
92
79
 
93
- # Truncates labels if longer than max specified
80
+ # Truncates labels if longer than max specified.
94
81
  attr_accessor :label_max_size
95
82
 
96
- # How truncated labels visually appear if they exceed label_max_size
97
- # :absolute - does not show trailing dots to indicate truncation. This is
98
- # the default.
99
- # :trailing_dots - shows trailing dots to indicate truncation (note
100
- # that label_max_size must be greater than 3).
83
+ # How truncated labels visually appear if they exceed {#label_max_size}.
84
+ #
85
+ # - +:absolute+ - does not show trailing dots to indicate truncation. This is the default.
86
+ # - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size}
87
+ # must be greater than 3).
101
88
  attr_accessor :label_truncation_style
102
89
 
103
90
  # Get or set the list of colors that will be used to draw the bars or lines.
104
91
  attr_accessor :colors
105
92
 
106
- # The large title of the graph displayed at the top
93
+ # The large title of the graph displayed at the top.
107
94
  attr_accessor :title
108
95
 
109
96
  # Font used for titles, labels, etc. Works best if you provide the full
110
97
  # path to the TTF font file. RMagick must be built with the Freetype
111
98
  # libraries for this to work properly.
112
- #
113
- # Tries to find Bitstream Vera (Vera.ttf) in the location specified by
114
- # ENV['MAGICK_FONT_PATH']. Uses default RMagick font otherwise.
115
- #
116
- # The font= method below fulfills the role of the writer, so we only need
117
- # a reader here.
118
99
  attr_reader :font
119
100
 
101
+ # Same as font but for the title.
102
+ attr_accessor :title_font
103
+
104
+ # Specifies whether to draw the title bolded or not.
105
+ attr_accessor :bold_title
106
+
120
107
  attr_accessor :font_color
121
108
 
122
- # Prevent drawing of line markers
109
+ # Prevent drawing of line markers.
123
110
  attr_accessor :hide_line_markers
124
111
 
125
- # Prevent drawing of the legend
112
+ # Prevent drawing of the legend.
126
113
  attr_accessor :hide_legend
127
114
 
128
- # Prevent drawing of the title
115
+ # Prevent drawing of the title.
129
116
  attr_accessor :hide_title
130
117
 
131
- # Prevent drawing of line numbers
118
+ # Prevent drawing of line numbers.
132
119
  attr_accessor :hide_line_numbers
133
120
 
134
121
  # Message shown when there is no data. Fits up to 20 characters. Defaults
135
- # to "No Data."
122
+ # to +"No Data."+.
136
123
  attr_accessor :no_data_message
137
124
 
138
- # The font size of the large title at the top of the graph
125
+ # The font size of the large title at the top of the graph.
139
126
  attr_accessor :title_font_size
140
127
 
141
128
  # Optionally set the size of the font. Based on an 800x600px graph.
142
- # Default is 20.
129
+ # Default is +20+.
143
130
  #
144
131
  # Will be scaled down if the graph is smaller than 800px wide.
145
132
  attr_accessor :legend_font_size
146
133
 
147
- # Display the legend under the graph
134
+ # Display the legend under the graph.
148
135
  attr_accessor :legend_at_bottom
149
136
 
150
- # The font size of the labels around the graph
137
+ # The font size of the labels around the graph.
151
138
  attr_accessor :marker_font_size
152
139
 
153
- # The color of the auxiliary lines
140
+ # The color of the auxiliary lines.
154
141
  attr_accessor :marker_color
155
142
  attr_accessor :marker_shadow_color
156
143
 
157
- # The number of horizontal lines shown for reference
144
+ # The number of horizontal lines shown for reference.
158
145
  attr_accessor :marker_count
159
146
 
160
- # You can manually set a minimum value instead of having the values
161
- # guessed for you.
162
- #
163
- # Set it after you have given all your data to the graph object.
164
- attr_accessor :minimum_value
165
-
166
- # You can manually set a maximum value, such as a percentage-based graph
167
- # that always goes to 100.
168
- #
169
- # If you use this, you must set it after you have given all your data to
170
- # the graph object.
171
- attr_accessor :maximum_value
172
-
173
147
  # Set to true if you want the data sets sorted with largest avg values drawn
174
148
  # first.
175
149
  attr_accessor :sort
@@ -181,47 +155,35 @@ module Gruff
181
155
  # Experimental
182
156
  attr_accessor :additional_line_values
183
157
 
184
- # Experimental
185
- attr_accessor :stacked
186
-
187
158
  # Optionally set the size of the colored box by each item in the legend.
188
- # Default is 20.0
159
+ # Default is +20.0+.
189
160
  #
190
161
  # Will be scaled down if graph is smaller than 800px wide.
191
162
  attr_accessor :legend_box_size
192
163
 
193
- # Output the values for the bars on a bar graph
194
- # Default is false
195
- attr_accessor :show_labels_for_bar_values
196
-
197
- # Set the number output format for labels using sprintf
198
- # Default is "%.2f"
199
- attr_accessor :label_formatting
200
-
201
- # With Side Bars use the data label for the marker value to the left of the bar
202
- # Default is false
164
+ # With Side Bars use the data label for the marker value to the left of the bar.
165
+ # Default is +false+.
203
166
  attr_accessor :use_data_label
167
+
204
168
  # If one numerical argument is given, the graph is drawn at 4/3 ratio
205
169
  # according to the given width (800 results in 800x600, 400 gives 400x300,
206
170
  # etc.).
207
171
  #
208
172
  # Or, send a geometry string for other ratios ('800x400', '400x225').
209
- #
210
- # Looks for Bitstream Vera as the default font. Expects an environment var
211
- # of MAGICK_FONT_PATH to be set. (Uses RMagick's default font otherwise.)
212
- def initialize(target_width=DEFAULT_TARGET_WIDTH)
213
- if Numeric === target_width
214
- @columns = target_width.to_f
215
- @rows = target_width.to_f * 0.75
216
- else
173
+ def initialize(target_width = DEFAULT_TARGET_WIDTH)
174
+ if target_width.is_a?(String)
217
175
  geometric_width, geometric_height = target_width.split('x')
218
176
  @columns = geometric_width.to_f
219
177
  @rows = geometric_height.to_f
178
+ else
179
+ @columns = target_width.to_f
180
+ @rows = target_width.to_f * 0.75
220
181
  end
182
+ @columns.freeze
183
+ @rows.freeze
221
184
 
222
185
  initialize_ivars
223
186
 
224
- reset_themes
225
187
  self.theme = Themes::KEYNOTE
226
188
  end
227
189
 
@@ -233,22 +195,25 @@ module Gruff
233
195
  # developers to change this values in their program.
234
196
  def initialize_ivars
235
197
  # Internal for calculations
236
- @raw_columns = 800.0
237
- @raw_rows = 800.0 * (@rows/@columns)
238
- @column_count = 0
198
+ @raw_columns = DEFAULT_TARGET_WIDTH
199
+ @raw_rows = DEFAULT_TARGET_WIDTH * (@rows / @columns)
200
+ @raw_columns.freeze
201
+ @raw_rows.freeze
202
+
239
203
  @marker_count = nil
240
204
  @maximum_value = @minimum_value = nil
241
- @has_data = false
242
- @data = Array.new
243
- @labels = Hash.new
244
- @labels_seen = Hash.new
205
+ @increment = nil
206
+ @labels = {}
207
+ @labels_seen = {}
245
208
  @sort = false
209
+ @sorted_drawing = false
246
210
  @title = nil
211
+ @title_font = nil
247
212
 
248
213
  @scale = @columns / @raw_columns
249
214
 
250
- vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
251
- @font = File.exists?(vera_font_path) ? vera_font_path : nil
215
+ @font = nil
216
+ @bold_title = true
252
217
 
253
218
  @marker_font_size = 21.0
254
219
  @legend_font_size = 20.0
@@ -262,7 +227,7 @@ module Gruff
262
227
 
263
228
  @no_data_message = 'No Data'
264
229
 
265
- @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = @show_labels_for_bar_values = false
230
+ @hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = false
266
231
  @center_labels_over_point = true
267
232
  @has_left_labels = false
268
233
  @label_stagger_height = 0
@@ -273,11 +238,14 @@ module Gruff
273
238
  @additional_line_colors = []
274
239
  @theme_options = {}
275
240
 
241
+ @use_data_label = false
242
+ @x_axis_increment = nil
276
243
  @x_axis_label = @y_axis_label = nil
277
244
  @y_axis_increment = nil
278
- @stacked = nil
279
- @norm_data = nil
245
+
246
+ @store = Gruff::Store.new(Gruff::Store::BaseData)
280
247
  end
248
+ protected :initialize_ivars
281
249
 
282
250
  # Sets the top, bottom, left and right margins to +margin+.
283
251
  def margins=(margin)
@@ -287,46 +255,44 @@ module Gruff
287
255
  # Sets the font for graph text to the font at +font_path+.
288
256
  def font=(font_path)
289
257
  @font = font_path
290
- @d.font = @font
258
+ Gruff::Renderer.font = @font
291
259
  end
292
260
 
293
261
  # Add a color to the list of available colors for lines.
294
262
  #
295
- # Example:
296
- # add_color('#c0e9d3')
263
+ # @example
264
+ # add_color('#c0e9d3')
297
265
  def add_color(colorname)
298
266
  @colors << colorname
299
267
  end
300
268
 
301
269
  # Replace the entire color list with a new array of colors. Also
302
- # aliased as the colors= setter method.
270
+ # aliased as the {#colors=} setter method.
303
271
  #
304
272
  # If you specify fewer colors than the number of datasets you intend
305
- # to draw, 'increment_color' will cycle through the array, reusing
306
- # colors as needed.
273
+ # to draw, it will cycle through the array, reusing colors as needed.
307
274
  #
308
- # Note that (as with the 'theme' method), you should set up your color
309
- # list before you send your data (via the 'data' method). Calls to the
310
- # 'data' method made prior to this call will use whatever color scheme
275
+ # Note that (as with the {#theme=} method), you should set up your color
276
+ # list before you send your data (via the {#data} method). Calls to the
277
+ # {#data} method made prior to this call will use whatever color scheme
311
278
  # was in place at the time data was called.
312
279
  #
313
- # Example:
314
- # replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
315
- def replace_colors(color_list=[])
280
+ # @example
281
+ # replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
282
+ def replace_colors(color_list = [])
316
283
  @colors = color_list
317
- @color_index = 0
318
284
  end
319
285
 
320
286
  # You can set a theme manually. Assign a hash to this method before you
321
287
  # send your data.
322
288
  #
323
- # graph.theme = {
324
- # :colors => %w(orange purple green white red),
325
- # :marker_color => 'blue',
326
- # :background_colors => ['black', 'grey', :top_bottom]
327
- # }
289
+ # graph.theme = {
290
+ # colors: %w(orange purple green white red),
291
+ # marker_color: 'blue',
292
+ # background_colors: ['black', 'grey', :top_bottom]
293
+ # }
328
294
  #
329
- # :background_image => 'squirrel.png' is also possible.
295
+ # +background_image: 'squirrel.png'+ is also possible.
330
296
  #
331
297
  # (Or hopefully something better looking than that.)
332
298
  #
@@ -334,13 +300,13 @@ module Gruff
334
300
  reset_themes
335
301
 
336
302
  defaults = {
337
- :colors => %w(black white),
338
- :additional_line_colors => [],
339
- :marker_color => 'white',
340
- :marker_shadow_color => nil,
341
- :font_color => 'black',
342
- :background_colors => nil,
343
- :background_image => nil
303
+ colors: %w[black white],
304
+ additional_line_colors: [],
305
+ marker_color: 'white',
306
+ marker_shadow_color: nil,
307
+ font_color: 'black',
308
+ background_colors: nil,
309
+ background_image: nil
344
310
  }
345
311
  @theme_options = defaults.merge options
346
312
 
@@ -350,7 +316,7 @@ module Gruff
350
316
  @font_color = @theme_options[:font_color] || @marker_color
351
317
  @additional_line_colors = @theme_options[:additional_line_colors]
352
318
 
353
- render_background
319
+ Gruff::Renderer.setup(@columns, @rows, @font, @scale, @theme_options)
354
320
  end
355
321
 
356
322
  def theme_keynote
@@ -386,62 +352,57 @@ module Gruff
386
352
  # If the color argument is nil, the next color from the default theme will
387
353
  # be used.
388
354
  #
389
- # NOTE: If you want to use a preset theme, you must set it before calling
390
- # data().
355
+ # @note
356
+ # If you want to use a preset theme, you must set it before calling {#data}.
391
357
  #
392
- # Example:
358
+ # @example
393
359
  # data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
394
- def data(name, data_points=[], color=nil)
395
- data_points = Array(data_points) # make sure it's an array
396
- @data << [name, data_points, color]
397
- # Set column count if this is larger than previous counts
398
- @column_count = (data_points.length > @column_count) ? data_points.length : @column_count
399
-
400
- # Pre-normalize
401
- data_points.each do |data_point|
402
- next if data_point.nil?
403
-
404
- # Setup max/min so spread starts at the low end of the data points
405
- if @maximum_value.nil? && @minimum_value.nil?
406
- @maximum_value = @minimum_value = data_point
407
- end
360
+ def data(name, data_points = [], color = nil)
361
+ store.add(name, data_points, color)
362
+ end
408
363
 
409
- # TODO Doesn't work with stacked bar graphs
410
- # Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
411
- @maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value
412
- @has_data = true if @maximum_value >= 0
364
+ # You can manually set a minimum value instead of having the values
365
+ # guessed for you.
366
+ #
367
+ # Set it after you have given all your data to the graph object.
368
+ def minimum_value
369
+ @minimum_value || store.min
370
+ end
371
+ attr_writer :minimum_value
413
372
 
414
- @minimum_value = less_than_min?(data_point) ? data_point : @minimum_value
415
- @has_data = true if @minimum_value < 0
416
- end
373
+ # You can manually set a maximum value, such as a percentage-based graph
374
+ # that always goes to 100.
375
+ #
376
+ # If you use this, you must set it after you have given all your data to
377
+ # the graph object.
378
+ def maximum_value
379
+ @maximum_value || store.max
417
380
  end
381
+ attr_writer :maximum_value
418
382
 
419
- # Writes the graph to a file. Defaults to 'graph.png'
383
+ # Writes the graph to a file. Defaults to +'graph.png'+
420
384
  #
421
- # Example:
385
+ # @example
422
386
  # write('graphs/my_pretty_graph.png')
423
- def write(filename='graph.png')
387
+ def write(file_name = 'graph.png')
424
388
  draw
425
- @base_image.write(filename)
389
+ Gruff::Renderer.write(file_name)
426
390
  end
427
391
 
428
392
  # Return the graph as a rendered binary blob.
429
- def to_blob(fileformat='PNG')
393
+ def to_blob(file_format = 'PNG')
430
394
  draw
431
- @base_image.to_blob do
432
- self.format = fileformat
433
- end
395
+ Gruff::Renderer.to_blob(file_format)
434
396
  end
435
397
 
436
-
437
- protected
398
+ protected
438
399
 
439
400
  # Overridden by subclasses to do the actual plotting of the graph.
440
401
  #
441
402
  # Subclasses should start by calling super() for this method.
442
403
  def draw
443
404
  # Maybe should be done in one of the following functions for more granularity.
444
- unless @has_data
405
+ unless data_given?
445
406
  draw_no_data
446
407
  return
447
408
  end
@@ -449,14 +410,6 @@ module Gruff
449
410
  setup_data
450
411
  setup_drawing
451
412
 
452
- debug {
453
- # Outer margin
454
- @d.rectangle(@left_margin, @top_margin,
455
- @raw_columns - @right_margin, @raw_rows - @bottom_margin)
456
- # Graph area box
457
- @d.rectangle(@graph_left, @graph_top, @graph_right, @graph_bottom)
458
- }
459
-
460
413
  draw_legend
461
414
  draw_line_markers
462
415
  draw_axis_labels
@@ -466,10 +419,9 @@ module Gruff
466
419
  # Perform data manipulation before calculating chart measurements
467
420
  def setup_data # :nodoc:
468
421
  if @y_axis_increment && !@hide_line_markers
469
- @maximum_value = [@y_axis_increment, @maximum_value, (@maximum_value.to_f / @y_axis_increment).round * @y_axis_increment].max
470
- @minimum_value = [@minimum_value, (@minimum_value.to_f / @y_axis_increment).round * @y_axis_increment].min
422
+ self.maximum_value = [@y_axis_increment, maximum_value, (maximum_value.to_f / @y_axis_increment).round * @y_axis_increment].max
423
+ self.minimum_value = [minimum_value, (minimum_value.to_f / @y_axis_increment).round * @y_axis_increment].min
471
424
  end
472
- make_stacked if @stacked
473
425
  end
474
426
 
475
427
  # Calculates size of drawable area and generates normalized data.
@@ -479,6 +431,7 @@ module Gruff
479
431
  # * title
480
432
  def setup_drawing
481
433
  calculate_spread
434
+ calculate_increment
482
435
  sort_data if @sort # Sort data with avg largest values set first (for display)
483
436
  set_colors
484
437
  normalize
@@ -486,32 +439,29 @@ module Gruff
486
439
  sort_norm_data if @sorted_drawing # Sort norm_data with avg largest values set first (for display)
487
440
  end
488
441
 
489
- # Make copy of data with values scaled between 0-100
490
- def normalize(force=false)
491
- if @norm_data.nil? || force
492
- @norm_data = []
493
- return unless @has_data
494
-
495
- @data.each do |data_row|
496
- norm_data_points = []
497
- data_row[DATA_VALUES_INDEX].each do |data_point|
498
- if data_point.nil?
499
- norm_data_points << nil
500
- else
501
- norm_data_points << ((data_point.to_f - @minimum_value.to_f) / @spread)
502
- end
503
- end
504
- if @show_labels_for_bar_values
505
- @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX], data_row[DATA_VALUES_INDEX]]
506
- else
507
- @norm_data << [data_row[DATA_LABEL_INDEX], norm_data_points, data_row[DATA_COLOR_INDEX]]
508
- end
442
+ attr_reader :store
443
+
444
+ def data_given?
445
+ @data_given ||= begin
446
+ if store.empty?
447
+ false
448
+ else
449
+ minimum_value <= store.min || maximum_value >= store.max
509
450
  end
510
451
  end
511
452
  end
512
453
 
454
+ def column_count
455
+ store.columns
456
+ end
457
+
458
+ # Make copy of data with values scaled between 0-100
459
+ def normalize
460
+ store.normalize(minimum: minimum_value, spread: @spread)
461
+ end
462
+
513
463
  def calculate_spread # :nodoc:
514
- @spread = @maximum_value.to_f - @minimum_value.to_f
464
+ @spread = maximum_value.to_f - minimum_value.to_f
515
465
  @spread = @spread > 0 ? @spread : 1
516
466
  end
517
467
 
@@ -519,45 +469,37 @@ module Gruff
519
469
  # Calculates size of drawable area, general font dimensions, etc.
520
470
 
521
471
  def setup_graph_measurements
522
- @marker_caps_height = @hide_line_markers ? 0 :
523
- calculate_caps_height(@marker_font_size)
524
- @title_caps_height = (@hide_title || @title.nil?) ? 0 :
525
- calculate_caps_height(@title_font_size) * @title.lines.to_a.size
526
- @legend_caps_height = @hide_legend ? 0 :
527
- calculate_caps_height(@legend_font_size)
472
+ @marker_caps_height = @hide_line_markers ? 0 : calculate_caps_height(@marker_font_size)
473
+ @title_caps_height = (@hide_title || @title.nil?) ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
474
+ @legend_caps_height = @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
528
475
 
529
476
  if @hide_line_markers
530
- (@graph_left,
531
- @graph_right_margin,
532
- @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
477
+ @graph_left = @left_margin
478
+ @graph_right_margin = @right_margin
479
+ @graph_bottom_margin = @bottom_margin
533
480
  else
534
481
  if @has_left_labels
535
482
  longest_left_label_width = calculate_width(@marker_font_size,
536
- labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
483
+ labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
537
484
  else
538
485
  longest_left_label_width = calculate_width(@marker_font_size,
539
- label(@maximum_value.to_f, @increment))
486
+ label(maximum_value.to_f, @increment))
540
487
  end
541
488
 
542
489
  # Shift graph if left line numbers are hidden
543
- line_number_width = @hide_line_numbers && !@has_left_labels ?
544
- 0.0 :
545
- (longest_left_label_width + LABEL_MARGIN * 2)
490
+ line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
546
491
 
547
- @graph_left = @left_margin +
548
- line_number_width +
549
- (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
492
+ @graph_left = @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
550
493
 
551
494
  # Make space for half the width of the rightmost column label.
552
495
  # Might be greater than the number of columns if between-style bar markers are used.
553
- last_label = @labels.keys.sort.last.to_i
554
- extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ?
555
- calculate_width(@marker_font_size, @labels[last_label]) / 2.0 :
556
- 0
496
+ last_label = @labels.keys.max.to_i
497
+ extra_room_for_long_label = begin
498
+ (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
499
+ end
557
500
  @graph_right_margin = @right_margin + extra_room_for_long_label
558
501
 
559
- @graph_bottom_margin = @bottom_margin +
560
- @marker_caps_height + LABEL_MARGIN
502
+ @graph_bottom_margin = @bottom_margin + @marker_caps_height + LABEL_MARGIN
561
503
  end
562
504
 
563
505
  @graph_right = @raw_columns - @graph_right_margin
@@ -565,12 +507,17 @@ module Gruff
565
507
 
566
508
  # When @hide title, leave a title_margin space for aesthetics.
567
509
  # Same with @hide_legend
568
- @graph_top = @legend_at_bottom ? @top_margin : (@top_margin +
569
- (@hide_title ? title_margin : @title_caps_height + title_margin) +
570
- (@hide_legend ? legend_margin : @legend_caps_height + legend_margin))
510
+ @graph_top = begin
511
+ if @legend_at_bottom
512
+ @top_margin
513
+ else
514
+ @top_margin +
515
+ (@hide_title ? title_margin : @title_caps_height + title_margin) +
516
+ (@hide_legend ? legend_margin : @legend_caps_height + legend_margin)
517
+ end
518
+ end
571
519
 
572
- x_axis_label_height = @x_axis_label.nil? ? 0.0 :
573
- @marker_caps_height + LABEL_MARGIN
520
+ x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
574
521
  # FIXME: Consider chart types other than bar
575
522
  @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height - @label_stagger_height
576
523
  @graph_height = @graph_bottom - @graph_top
@@ -578,34 +525,21 @@ module Gruff
578
525
 
579
526
  # Draw the optional labels for the x axis and y axis.
580
527
  def draw_axis_labels
581
- unless @x_axis_label.nil?
528
+ if @x_axis_label
582
529
  # X Axis
583
530
  # Centered vertically and horizontally by setting the
584
531
  # height to 1.0 and the width to the width of the graph.
585
532
  x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height
586
533
 
587
- # TODO Center between graph area
588
- @d.fill = @font_color
589
- @d.font = @font if @font
590
- @d.stroke('transparent')
591
- @d.pointsize = scale_fontsize(@marker_font_size)
592
- @d.gravity = NorthGravity
593
- @d = @d.annotate_scaled(@base_image,
594
- @raw_columns, 1.0,
595
- 0.0, x_axis_label_y_coordinate,
596
- @x_axis_label, @scale)
597
- debug { @d.line 0.0, x_axis_label_y_coordinate, @raw_columns, x_axis_label_y_coordinate }
534
+ # TODO: Center between graph area
535
+ text_renderer = Gruff::Renderer::Text.new(@x_axis_label, font: @font, size: @marker_font_size, color: @font_color)
536
+ text_renderer.render(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
598
537
  end
599
538
 
600
- unless @y_axis_label.nil?
539
+ if @y_axis_label
601
540
  # Y Axis, rotated vertically
602
- @d.rotation = -90.0
603
- @d.gravity = CenterGravity
604
- @d = @d.annotate_scaled(@base_image,
605
- 1.0, @raw_rows,
606
- @left_margin + @marker_caps_height / 2.0, 0.0,
607
- @y_axis_label, @scale)
608
- @d.rotation = 90.0
541
+ text_renderer = Gruff::Renderer::Text.new(@y_axis_label, font: @font, size: @marker_font_size, color: @font_color, rotation: -90)
542
+ text_renderer.render(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
609
543
  end
610
544
  end
611
545
 
@@ -613,127 +547,53 @@ module Gruff
613
547
  def draw_line_markers
614
548
  return if @hide_line_markers
615
549
 
616
- @d = @d.stroke_antialias false
617
-
618
- if @y_axis_increment.nil?
619
- # Try to use a number of horizontal lines that will come out even.
620
- #
621
- # TODO Do the same for larger numbers...100, 75, 50, 25
622
- if @marker_count.nil?
623
- (3..7).each do |lines|
624
- if @spread % lines == 0.0
625
- @marker_count = lines
626
- break
627
- end
628
- end
629
- @marker_count ||= 4
630
- end
631
- @increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
632
- else
633
- # TODO Make this work for negative values
634
- @marker_count = (@spread / @y_axis_increment).to_i
635
- @increment = @y_axis_increment
636
- end
637
- @increment_scaled = @graph_height.to_f / (@spread / @increment)
550
+ increment_scaled = @graph_height.to_f / (@spread / @increment)
638
551
 
639
552
  # Draw horizontal line markers and annotate with numbers
640
553
  (0..@marker_count).each do |index|
641
- y = @graph_top + @graph_height - index.to_f * @increment_scaled
554
+ y = @graph_top + @graph_height - index.to_f * increment_scaled
642
555
 
643
- @d = @d.fill(@marker_color)
644
-
645
- # FIXME(uwe): Workaround for Issue #66
646
- # https://github.com/topfunky/gruff/issues/66
647
- # https://github.com/rmagick/rmagick/issues/82
648
- # Remove if the issue gets fixed.
649
- y += 0.001 unless defined?(JRUBY_VERSION)
650
- # EMXIF
651
-
652
- @d = @d.line(@graph_left, y, @graph_right, y)
556
+ Gruff::Renderer::Line.new(color: @marker_color).render(@graph_left, y, @graph_right, y)
653
557
  #If the user specified a marker shadow color, draw a shadow just below it
654
- unless @marker_shadow_color.nil?
655
- @d = @d.fill(@marker_shadow_color)
656
- @d = @d.line(@graph_left, y + 1, @graph_right, y + 1)
558
+ if @marker_shadow_color
559
+ Gruff::Renderer::Line.new(color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1)
657
560
  end
658
561
 
659
- marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) +
660
- BigDecimal(@minimum_value.to_s)
562
+ marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
661
563
 
662
564
  unless @hide_line_numbers
663
- @d.fill = @font_color
664
- @d.font = @font if @font
665
- @d.stroke('transparent')
666
- @d.pointsize = scale_fontsize(@marker_font_size)
667
- @d.gravity = EastGravity
668
-
669
- # Vertically center with 1.0 for the height
670
- @d = @d.annotate_scaled(@base_image,
671
- @graph_left - LABEL_MARGIN, 1.0,
672
- 0.0, y,
673
- label(marker_label, @increment), @scale)
565
+ label = label(marker_label, @increment)
566
+ text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color)
567
+ text_renderer.render(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
674
568
  end
675
569
  end
676
-
677
- # # Submitted by a contibutor...the utility escapes me
678
- # i = 0
679
- # @additional_line_values.each do |value|
680
- # @increment_scaled = @graph_height.to_f / (@maximum_value.to_f / value)
681
- #
682
- # y = @graph_top + @graph_height - @increment_scaled
683
- #
684
- # @d = @d.stroke(@additional_line_colors[i])
685
- # @d = @d.line(@graph_left, y, @graph_right, y)
686
- #
687
- #
688
- # @d.fill = @additional_line_colors[i]
689
- # @d.font = @font if @font
690
- # @d.stroke('transparent')
691
- # @d.pointsize = scale_fontsize(@marker_font_size)
692
- # @d.gravity = EastGravity
693
- # @d = @d.annotate_scaled( @base_image,
694
- # 100, 20,
695
- # -10, y - (@marker_font_size/2.0),
696
- # "", @scale)
697
- # i += 1
698
- # end
699
-
700
- @d = @d.stroke_antialias true
701
570
  end
702
571
 
703
- ##
704
572
  # Return the sum of values in an array.
705
573
  #
706
574
  # Duplicated to not conflict with active_support in Rails.
707
-
708
575
  def sum(arr)
709
- arr.inject(0) { |i, m| m + i }
576
+ arr.reduce(0) { |i, m| m + i }
710
577
  end
711
578
 
712
- ##
713
579
  # Return a calculation of center
714
-
715
580
  def center(size)
716
581
  (@raw_columns - size) / 2
717
582
  end
718
583
 
719
- ##
720
584
  # Draws a legend with the names of the datasets matched
721
585
  # to the colors used to draw them.
722
-
723
586
  def draw_legend
724
587
  return if @hide_legend
725
588
 
726
- @legend_labels = @data.collect { |item| item[DATA_LABEL_INDEX] }
589
+ legend_labels = store.data.map(&:label)
727
590
 
728
591
  legend_square_width = @legend_box_size # small square with color of this item
729
592
 
730
593
  # May fix legend drawing problem at small sizes
731
- @d.font = @font if @font
732
- @d.pointsize = @legend_font_size
733
-
734
594
  label_widths = [[]] # Used to calculate line wrap
735
- @legend_labels.each do |label|
736
- metrics = @d.get_type_metrics(@base_image, label.to_s)
595
+ legend_labels.each do |label|
596
+ metrics = Renderer::Text.metrics(label, @legend_font_size)
737
597
  label_width = metrics.width + legend_square_width * 2.7
738
598
  label_widths.last.push label_width
739
599
 
@@ -743,45 +603,36 @@ module Gruff
743
603
  end
744
604
 
745
605
  current_x_offset = center(sum(label_widths.first))
746
- current_y_offset = @legend_at_bottom ? @graph_height + title_margin : (@hide_title ?
747
- @top_margin + title_margin :
748
- @top_margin + title_margin + @title_caps_height)
749
-
750
- @legend_labels.each_with_index do |legend_label, index|
606
+ current_y_offset = begin
607
+ if @legend_at_bottom
608
+ @graph_height + title_margin
609
+ else
610
+ @hide_title ? @top_margin + title_margin : @top_margin + title_margin + @title_caps_height
611
+ end
612
+ end
751
613
 
614
+ legend_labels.each_with_index do |legend_label, index|
752
615
  # Draw label
753
- @d.fill = @font_color
754
- @d.font = @font if @font
755
- @d.pointsize = scale_fontsize(@legend_font_size)
756
- @d.stroke('transparent')
757
- @d.font_weight = NormalWeight
758
- @d.gravity = WestGravity
759
- @d = @d.annotate_scaled(@base_image,
760
- @raw_columns, 1.0,
761
- current_x_offset + (legend_square_width * 1.7), current_y_offset,
762
- legend_label.to_s, @scale)
616
+ text_renderer = Gruff::Renderer::Text.new(legend_label, font: @font, size: @legend_font_size, color: @font_color)
617
+ text_renderer.render(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
763
618
 
764
619
  # Now draw box with color of this dataset
765
- @d = @d.stroke('transparent')
766
- @d = @d.fill @data[index][DATA_COLOR_INDEX]
767
- @d = @d.rectangle(current_x_offset,
768
- current_y_offset - legend_square_width / 2.0,
769
- current_x_offset + legend_square_width,
770
- current_y_offset + legend_square_width / 2.0)
771
-
772
- @d.pointsize = @legend_font_size
773
- metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
620
+ rect_renderer = Gruff::Renderer::Rectangle.new(color: store.data[index].color)
621
+ rect_renderer.render(current_x_offset,
622
+ current_y_offset - legend_square_width / 2.0,
623
+ current_x_offset + legend_square_width,
624
+ current_y_offset + legend_square_width / 2.0)
625
+
626
+ metrics = Renderer::Text.metrics(legend_label, legend_font_size)
774
627
  current_string_offset = metrics.width + (legend_square_width * 2.7)
775
628
 
776
629
  # Handle wrapping
777
630
  label_widths.first.shift
778
631
  if label_widths.first.empty?
779
- debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
780
-
781
632
  label_widths.shift
782
633
  current_x_offset = center(sum(label_widths.first)) unless label_widths.empty?
783
634
  line_height = [@legend_caps_height, legend_square_width].max + legend_margin
784
- if label_widths.length > 0
635
+ unless label_widths.empty?
785
636
  # Wrap to next line and shrink available graph dimensions
786
637
  current_y_offset += line_height
787
638
  @graph_top += line_height
@@ -791,32 +642,29 @@ module Gruff
791
642
  current_x_offset += current_string_offset
792
643
  end
793
644
  end
794
- @color_index = 0
795
645
  end
796
646
 
797
647
  # Draws a title on the graph.
798
648
  def draw_title
799
- return if (@hide_title || @title.nil?)
800
-
801
- @d.fill = @font_color
802
- @d.font = @font if @font
803
- @d.stroke('transparent')
804
- @d.pointsize = scale_fontsize(@title_font_size)
805
- @d.font_weight = BoldWeight
806
- @d.gravity = NorthGravity
807
- @d = @d.annotate_scaled(@base_image,
808
- @raw_columns, 1.0,
809
- 0, @top_margin,
810
- @title, @scale)
649
+ return if @hide_title || @title.nil?
650
+
651
+ font = (@title_font || @font) if @title_font || @font
652
+ font_weight = @bold_title ? Magick::BoldWeight : Magick::NormalWeight
653
+ font_size = @title_font_size
654
+
655
+ metrics = Renderer::Text.metrics(@title, font_size, font_weight)
656
+ if metrics.width > @raw_columns
657
+ font_size = font_size * (@raw_columns / metrics.width) * 0.95
658
+ end
659
+ text_renderer = Gruff::Renderer::Text.new(@title, font: font, size: font_size, color: @font_color, weight: font_weight)
660
+ text_renderer.render(@raw_columns, 1.0, 0, @top_margin)
811
661
  end
812
662
 
813
663
  # Draws column labels below graph, centered over x_offset
814
664
  #--
815
665
  # TODO Allow WestGravity as an option
816
- def draw_label(x_offset, index)
817
- return if @hide_line_markers
818
-
819
- if !@labels[index].nil? && @labels_seen[index].nil?
666
+ def draw_label(x_offset, index, gravity = Magick::NorthGravity)
667
+ draw_unique_label(index) do
820
668
  y_offset = @graph_bottom + LABEL_MARGIN
821
669
 
822
670
  # TESTME
@@ -824,7 +672,7 @@ module Gruff
824
672
  # TODO: See if index.odd? is the best stragegy
825
673
  y_offset += @label_stagger_height if index.odd?
826
674
 
827
- label_text = @labels[index]
675
+ label_text = labels[index].to_s
828
676
 
829
677
  # TESTME
830
678
  # FIXME: Consider chart types other than bar
@@ -832,130 +680,47 @@ module Gruff
832
680
  if @label_truncation_style == :trailing_dots
833
681
  if @label_max_size > 3
834
682
  # 4 because '...' takes up 3 chars
835
- label_text = "#{label_text[0 .. (@label_max_size - 4)]}..."
683
+ label_text = "#{label_text[0..(@label_max_size - 4)]}..."
836
684
  end
837
685
  else # @label_truncation_style is :absolute (default)
838
- label_text = label_text[0 .. (@label_max_size - 1)]
686
+ label_text = label_text[0..(@label_max_size - 1)]
839
687
  end
840
-
841
688
  end
842
689
 
843
690
  if x_offset >= @graph_left && x_offset <= @graph_right
844
- @d.fill = @font_color
845
- @d.font = @font if @font
846
- @d.stroke('transparent')
847
- @d.font_weight = NormalWeight
848
- @d.pointsize = scale_fontsize(@marker_font_size)
849
- @d.gravity = NorthGravity
850
- @d = @d.annotate_scaled(@base_image,
851
- 1.0, 1.0,
852
- x_offset, y_offset,
853
- label_text, @scale)
691
+ text_renderer = Gruff::Renderer::Text.new(label_text, font: @font, size: @marker_font_size, color: @font_color)
692
+ text_renderer.render(1.0, 1.0, x_offset, y_offset, gravity)
854
693
  end
694
+ end
695
+ end
696
+
697
+ def draw_unique_label(index)
698
+ return if @hide_line_markers
699
+
700
+ if !@labels[index].nil? && @labels_seen[index].nil?
701
+ yield
855
702
  @labels_seen[index] = 1
856
- debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
857
703
  end
858
704
  end
859
705
 
860
706
  # Draws the data value over the data point in bar graphs
861
- def draw_value_label(x_offset, y_offset, data_point, bar_value=false)
707
+ def draw_value_label(x_offset, y_offset, data_point, bar_value = false)
862
708
  return if @hide_line_markers && !bar_value
863
709
 
864
- #y_offset = @graph_bottom + LABEL_MARGIN
865
-
866
- @d.fill = @font_color
867
- @d.font = @font if @font
868
- @d.stroke('transparent')
869
- @d.font_weight = NormalWeight
870
- @d.pointsize = scale_fontsize(@marker_font_size)
871
- @d.gravity = NorthGravity
872
- @d = @d.annotate_scaled(@base_image,
873
- 1.0, 1.0,
874
- x_offset, y_offset,
875
- data_point.to_s, @scale)
876
-
877
- debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
710
+ text_renderer = Gruff::Renderer::Text.new(data_point, font: @font, size: @marker_font_size, color: @font_color)
711
+ text_renderer.render(1.0, 1.0, x_offset, y_offset)
878
712
  end
879
713
 
880
714
  # Shows an error message because you have no data.
881
715
  def draw_no_data
882
- @d.fill = @font_color
883
- @d.font = @font if @font
884
- @d.stroke('transparent')
885
- @d.font_weight = NormalWeight
886
- @d.pointsize = scale_fontsize(80)
887
- @d.gravity = CenterGravity
888
- @d = @d.annotate_scaled(@base_image,
889
- @raw_columns, @raw_rows/2.0,
890
- 0, 10,
891
- @no_data_message, @scale)
892
- end
893
-
894
- # Finds the best background to render based on the provided theme options.
895
- #
896
- # Creates a @base_image to draw on.
897
- def render_background
898
- case @theme_options[:background_colors]
899
- when Array
900
- @base_image = render_gradiated_background(@theme_options[:background_colors][0], @theme_options[:background_colors][1], @theme_options[:background_direction])
901
- when String
902
- @base_image = render_solid_background(@theme_options[:background_colors])
903
- else
904
- @base_image = render_image_background(*@theme_options[:background_image])
905
- end
906
- end
907
-
908
- # Make a new image at the current size with a solid +color+.
909
- def render_solid_background(color)
910
- Image.new(@columns, @rows) {
911
- self.background_color = color
912
- }
913
- end
914
-
915
- # Use with a theme definition method to draw a gradiated background.
916
- def render_gradiated_background(top_color, bottom_color, direct = :top_bottom)
917
- case direct
918
- when :bottom_top
919
- gradient_fill = GradientFill.new(0, 0, 100, 0, bottom_color, top_color)
920
- when :left_right
921
- gradient_fill = GradientFill.new(0, 0, 0, 100, top_color, bottom_color)
922
- when :right_left
923
- gradient_fill = GradientFill.new(0, 0, 0, 100, bottom_color, top_color)
924
- when :topleft_bottomright
925
- gradient_fill = GradientFill.new(0, 100, 100, 0, top_color, bottom_color)
926
- when :topright_bottomleft
927
- gradient_fill = GradientFill.new(0, 0, 100, 100, bottom_color, top_color)
928
- else
929
- gradient_fill = GradientFill.new(0, 0, 100, 0, top_color, bottom_color)
930
- end
931
- Image.new(@columns, @rows, gradient_fill)
932
- end
933
-
934
- # Use with a theme to use an image (800x600 original) background.
935
- def render_image_background(image_path)
936
- image = Image.read(image_path)
937
- if @scale != 1.0
938
- image[0].resize!(@scale) # TODO Resize with new scale (crop if necessary for wide graph)
939
- end
940
- image[0]
941
- end
942
-
943
- # Use with a theme to make a transparent background
944
- def render_transparent_background
945
- Image.new(@columns, @rows) do
946
- self.background_color = 'transparent'
947
- end
716
+ text_renderer = Gruff::Renderer::Text.new(@no_data_message, font: @font, size: 80, color: @font_color)
717
+ text_renderer.render(@raw_columns, @raw_rows / 2.0, 0, 10, Magick::CenterGravity)
948
718
  end
949
719
 
950
720
  # Resets everything to defaults (except data).
951
721
  def reset_themes
952
- @color_index = 0
953
722
  @labels_seen = {}
954
723
  @theme_options = {}
955
-
956
- @d = Draw.new
957
- # Scale down from 800x600 used to calculate drawing.
958
- @d = @d.scale(@scale, @scale)
959
724
  end
960
725
 
961
726
  def scale(value) # :nodoc:
@@ -971,17 +736,9 @@ module Gruff
971
736
  (value > max_value) ? max_value : value
972
737
  end
973
738
 
974
- # Overridden by subclasses such as stacked bar.
975
- def larger_than_max?(data_point) # :nodoc:
976
- data_point > @maximum_value
977
- end
978
-
979
- def less_than_min?(data_point) # :nodoc:
980
- data_point < @minimum_value
981
- end
982
-
983
739
  def significant(i) # :nodoc:
984
740
  return 1.0 if i == 0 # Keep from going into infinite loop
741
+
985
742
  inc = BigDecimal(i.to_s)
986
743
  factor = BigDecimal('1.0')
987
744
  while inc < 10
@@ -997,6 +754,8 @@ module Gruff
997
754
  res = inc.floor * factor
998
755
  if res.to_i.to_f == res
999
756
  res.to_i
757
+ elsif res.to_f == res
758
+ res.to_f
1000
759
  else
1001
760
  res
1002
761
  end
@@ -1004,70 +763,21 @@ module Gruff
1004
763
 
1005
764
  # Sort with largest overall summed value at front of array.
1006
765
  def sort_data
1007
- @data = @data.sort_by { |a| -a[DATA_VALUES_INDEX].inject(0) { |sum, num| sum + num.to_f } }
766
+ store.sort_data!
1008
767
  end
1009
768
 
1010
- # Set the color for each data set unless it was gived in the data(...) call.
769
+ # Set the color for each data set unless it was given in the data(...) call.
1011
770
  def set_colors
1012
- @data.each { |a| a[DATA_COLOR_INDEX] ||= increment_color }
771
+ store.set_colors!(@colors)
1013
772
  end
1014
773
 
1015
774
  # Sort with largest overall summed value at front of array so it shows up
1016
775
  # correctly in the drawn graph.
1017
776
  def sort_norm_data
1018
- @norm_data =
1019
- @norm_data.sort_by { |a| -a[DATA_VALUES_INDEX].inject(0) { |sum, num| sum + num.to_f } }
1020
- end
1021
-
1022
- # Used by StackedBar and child classes.
1023
- #
1024
- # May need to be moved to the StackedBar class.
1025
- def get_maximum_by_stack
1026
- # Get sum of each stack
1027
- max_hash = {}
1028
- @data.each do |data_set|
1029
- data_set[DATA_VALUES_INDEX].each_with_index do |data_point, i|
1030
- max_hash[i] = 0.0 unless max_hash[i]
1031
- max_hash[i] += data_point.to_f
1032
- end
1033
- end
1034
-
1035
- # @maximum_value = 0
1036
- max_hash.keys.each do |key|
1037
- @maximum_value = max_hash[key] if max_hash[key] > @maximum_value
1038
- end
1039
- @minimum_value = 0
1040
- end
1041
-
1042
- def make_stacked # :nodoc:
1043
- stacked_values = Array.new(@column_count, 0)
1044
- @data.each do |value_set|
1045
- value_set[DATA_VALUES_INDEX].each_with_index do |value, index|
1046
- stacked_values[index] += value
1047
- end
1048
- value_set[DATA_VALUES_INDEX] = stacked_values.dup
1049
- end
1050
- end
1051
-
1052
- private
1053
-
1054
- # Takes a block and draws it if DEBUG is true.
1055
- #
1056
- # Example:
1057
- # debug { @d.rectangle x1, y1, x2, y2 }
1058
- def debug
1059
- if DEBUG
1060
- @d = @d.fill 'transparent'
1061
- @d = @d.stroke 'turquoise'
1062
- @d = yield
1063
- end
777
+ store.sort_norm_data!
1064
778
  end
1065
779
 
1066
- # Returns the next color in your color list.
1067
- def increment_color
1068
- @color_index = (@color_index + 1) % @colors.length
1069
- @colors[@color_index - 1]
1070
- end
780
+ private
1071
781
 
1072
782
  # Return a formatted string representing a number value that should be
1073
783
  # printed as a label.
@@ -1086,7 +796,7 @@ module Gruff
1086
796
  else
1087
797
  value.to_s
1088
798
  end
1089
- elsif (@spread.to_f % (@marker_count.to_f==0 ? 1 : @marker_count.to_f) == 0) || !@y_axis_increment.nil?
799
+ elsif (@spread.to_f % (@marker_count.to_f == 0 ? 1 : @marker_count.to_f) == 0) || !@y_axis_increment.nil?
1090
800
  value.to_i.to_s
1091
801
  elsif @spread > 10.0
1092
802
  sprintf('%0i', value)
@@ -1107,9 +817,8 @@ module Gruff
1107
817
  # Not scaled since it deals with dimensions that the regular scaling will
1108
818
  # handle.
1109
819
  def calculate_caps_height(font_size)
1110
- @d.pointsize = font_size
1111
- @d.font = @font if @font
1112
- @d.get_type_metrics(@base_image, 'X').height
820
+ metrics = Renderer::Text.metrics('X', font_size)
821
+ metrics.height
1113
822
  end
1114
823
 
1115
824
  # Returns the width of a string at this pointsize.
@@ -1118,52 +827,39 @@ module Gruff
1118
827
  # scaling will handle.
1119
828
  def calculate_width(font_size, text)
1120
829
  return 0 if text.nil?
1121
- @d.pointsize = font_size
1122
- @d.font = @font if @font
1123
- @d.get_type_metrics(@base_image, text.to_s).width
1124
- end
1125
-
1126
- end # Gruff::Base
1127
-
1128
- class IncorrectNumberOfDatasetsException < StandardError;
1129
- end
1130
830
 
1131
- end # Gruff
1132
-
1133
- module Magick
1134
-
1135
- class Draw
1136
-
1137
- # Additional method to scale annotation text since Draw.scale doesn't.
1138
- def annotate_scaled(img, width, height, x, y, text, scale)
1139
- scaled_width = (width * scale) >= 1 ? (width * scale) : 1
1140
- scaled_height = (height * scale) >= 1 ? (height * scale) : 1
1141
-
1142
- self.annotate(img,
1143
- scaled_width, scaled_height,
1144
- x * scale, y * scale,
1145
- text.gsub('%', '%%'))
831
+ metrics = Renderer::Text.metrics(text, font_size)
832
+ metrics.width
1146
833
  end
1147
834
 
1148
- if defined? JRUBY_VERSION
1149
- # FIXME(uwe): We should NOT need to implement this method.
1150
- # Remove this method as soon as RMagick4J Issue #16 is fixed.
1151
- # https://github.com/Serabe/RMagick4J/issues/16
1152
- def fill=(fill)
1153
- fill = {:white => '#FFFFFF'}[fill.to_sym] || fill
1154
- @draw.fill = Magick4J.ColorDatabase.query_default(fill)
1155
- self
835
+ def calculate_increment
836
+ if @y_axis_increment.nil?
837
+ # Try to use a number of horizontal lines that will come out even.
838
+ #
839
+ # TODO Do the same for larger numbers...100, 75, 50, 25
840
+ if @marker_count.nil?
841
+ (3..7).each do |lines|
842
+ if @spread % lines == 0.0
843
+ @marker_count = lines
844
+ break
845
+ end
846
+ end
847
+ @marker_count ||= 4
848
+ end
849
+ @increment = (@spread > 0 && @marker_count > 0) ? significant(@spread / @marker_count) : 1
850
+ else
851
+ # TODO: Make this work for negative values
852
+ @marker_count = (@spread / @y_axis_increment).to_i
853
+ @increment = @y_axis_increment
1156
854
  end
1157
- # EMXIF
1158
855
  end
1159
856
 
857
+ # Used for degree => radian conversions
858
+ def deg2rad(angle)
859
+ angle * (Math::PI / 180.0)
860
+ end
1160
861
  end
1161
862
 
1162
- end # Magick
1163
-
1164
- class String
1165
- #Taken from http://codesnippets.joyent.com/posts/show/330
1166
- def commify(delimiter=',')
1167
- self.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
863
+ class IncorrectNumberOfDatasetsException < StandardError
1168
864
  end
1169
865
  end