gruff 0.5.0-java → 0.9.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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