write_xlsx 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (261) hide show
  1. data/.document +5 -0
  2. data/.gitattributes +1 -0
  3. data/Gemfile +12 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +82 -0
  6. data/Rakefile +78 -0
  7. data/VERSION +1 -0
  8. data/examples/a_simple.rb +45 -0
  9. data/examples/array_formula.rb +33 -0
  10. data/examples/autofilter.rb +235 -0
  11. data/examples/chart_area.rb +59 -0
  12. data/examples/chart_bar.rb +59 -0
  13. data/examples/chart_column.rb +58 -0
  14. data/examples/chart_line.rb +59 -0
  15. data/examples/chart_pie.rb +49 -0
  16. data/examples/chart_scatter.rb +59 -0
  17. data/examples/chart_stock.rb +65 -0
  18. data/examples/colors.rb +130 -0
  19. data/examples/comments1.rb +12 -0
  20. data/examples/comments2.rb +335 -0
  21. data/examples/conditional_format.rb +67 -0
  22. data/examples/data_validate.rb +279 -0
  23. data/examples/defined_name.rb +28 -0
  24. data/examples/demo.rb +104 -0
  25. data/examples/diag_border.rb +26 -0
  26. data/examples/headers.rb +119 -0
  27. data/examples/hide_sheet.rb +30 -0
  28. data/examples/hyperlink1.rb +58 -0
  29. data/examples/indent.rb +28 -0
  30. data/examples/merge1.rb +38 -0
  31. data/examples/merge2.rb +48 -0
  32. data/examples/merge3.rb +43 -0
  33. data/examples/merge4.rb +82 -0
  34. data/examples/merge5.rb +70 -0
  35. data/examples/merge6.rb +48 -0
  36. data/examples/outline.rb +252 -0
  37. data/examples/properties.rb +33 -0
  38. data/examples/protection.rb +34 -0
  39. data/examples/rich_strings.rb +42 -0
  40. data/examples/right_to_left.rb +24 -0
  41. data/examples/tab_colors.rb +26 -0
  42. data/lib/write_xlsx.rb +77 -0
  43. data/lib/write_xlsx/chart.rb +3027 -0
  44. data/lib/write_xlsx/chart/area.rb +52 -0
  45. data/lib/write_xlsx/chart/bar.rb +126 -0
  46. data/lib/write_xlsx/chart/column.rb +132 -0
  47. data/lib/write_xlsx/chart/line.rb +51 -0
  48. data/lib/write_xlsx/chart/pie.rb +210 -0
  49. data/lib/write_xlsx/chart/scatter.rb +252 -0
  50. data/lib/write_xlsx/chart/stock.rb +134 -0
  51. data/lib/write_xlsx/chartsheet.rb +173 -0
  52. data/lib/write_xlsx/colors.rb +65 -0
  53. data/lib/write_xlsx/compatibility.rb +71 -0
  54. data/lib/write_xlsx/drawing.rb +547 -0
  55. data/lib/write_xlsx/format.rb +683 -0
  56. data/lib/write_xlsx/package/app.rb +218 -0
  57. data/lib/write_xlsx/package/comments.rb +221 -0
  58. data/lib/write_xlsx/package/content_types.rb +189 -0
  59. data/lib/write_xlsx/package/core.rb +196 -0
  60. data/lib/write_xlsx/package/packager.rb +510 -0
  61. data/lib/write_xlsx/package/relationships.rb +98 -0
  62. data/lib/write_xlsx/package/shared_strings.rb +96 -0
  63. data/lib/write_xlsx/package/styles.rb +705 -0
  64. data/lib/write_xlsx/package/theme.rb +45 -0
  65. data/lib/write_xlsx/package/vml.rb +386 -0
  66. data/lib/write_xlsx/package/xml_writer_simple.rb +90 -0
  67. data/lib/write_xlsx/utility.rb +113 -0
  68. data/lib/write_xlsx/workbook.rb +1488 -0
  69. data/lib/write_xlsx/worksheet.rb +6578 -0
  70. data/lib/write_xlsx/zip_file_utils.rb +98 -0
  71. data/test/chart/test_add_series.rb +113 -0
  72. data/test/chart/test_process_names.rb +27 -0
  73. data/test/chart/test_write_auto.rb +15 -0
  74. data/test/chart/test_write_ax_id.rb +15 -0
  75. data/test/chart/test_write_ax_pos.rb +15 -0
  76. data/test/chart/test_write_chart_space.rb +15 -0
  77. data/test/chart/test_write_cross_ax.rb +15 -0
  78. data/test/chart/test_write_crosses.rb +15 -0
  79. data/test/chart/test_write_format_code.rb +15 -0
  80. data/test/chart/test_write_idx.rb +15 -0
  81. data/test/chart/test_write_label_align.rb +15 -0
  82. data/test/chart/test_write_label_offset.rb +15 -0
  83. data/test/chart/test_write_lang.rb +15 -0
  84. data/test/chart/test_write_layout.rb +15 -0
  85. data/test/chart/test_write_legend.rb +16 -0
  86. data/test/chart/test_write_legend_pos.rb +15 -0
  87. data/test/chart/test_write_major_gridlines.rb +15 -0
  88. data/test/chart/test_write_marker.rb +17 -0
  89. data/test/chart/test_write_marker_size.rb +15 -0
  90. data/test/chart/test_write_marker_value.rb +16 -0
  91. data/test/chart/test_write_num_cache.rb +16 -0
  92. data/test/chart/test_write_num_fmt.rb +16 -0
  93. data/test/chart/test_write_number_format.rb +15 -0
  94. data/test/chart/test_write_order.rb +15 -0
  95. data/test/chart/test_write_orientation.rb +15 -0
  96. data/test/chart/test_write_page_margins.rb +15 -0
  97. data/test/chart/test_write_page_setup.rb +15 -0
  98. data/test/chart/test_write_plot_vis_only.rb +15 -0
  99. data/test/chart/test_write_pt.rb +16 -0
  100. data/test/chart/test_write_pt_count.rb +16 -0
  101. data/test/chart/test_write_series_formula.rb +16 -0
  102. data/test/chart/test_write_style.rb +41 -0
  103. data/test/chart/test_write_symbol.rb +16 -0
  104. data/test/chart/test_write_tick_lbl_pos.rb +16 -0
  105. data/test/chart/test_write_v.rb +16 -0
  106. data/test/drawing/test_drawing_chart_01.rb +50 -0
  107. data/test/drawing/test_drawing_image_01.rb +59 -0
  108. data/test/helper.rb +90 -0
  109. data/test/package/app/test_app01.rb +44 -0
  110. data/test/package/app/test_app02.rb +46 -0
  111. data/test/package/app/test_app03.rb +53 -0
  112. data/test/package/comments/test_comments01.rb +36 -0
  113. data/test/package/comments/test_write_text_t.rb +44 -0
  114. data/test/package/content_types/test_content_types.rb +35 -0
  115. data/test/package/content_types/test_write_default.rb +13 -0
  116. data/test/package/content_types/test_write_override.rb +13 -0
  117. data/test/package/core/test_core01.rb +28 -0
  118. data/test/package/core/test_core02.rb +42 -0
  119. data/test/package/relationships/test_relationships.rb +28 -0
  120. data/test/package/relationships/test_sheet_rels.rb +22 -0
  121. data/test/package/shared_strings/test_shared_strings01.rb +30 -0
  122. data/test/package/shared_strings/test_shared_strings02.rb +30 -0
  123. data/test/package/shared_strings/test_write_si.rb +13 -0
  124. data/test/package/shared_strings/test_write_sst.rb +15 -0
  125. data/test/package/styles/test_styles_01.rb +69 -0
  126. data/test/package/styles/test_styles_02.rb +104 -0
  127. data/test/package/styles/test_styles_03.rb +90 -0
  128. data/test/package/styles/test_styles_04.rb +216 -0
  129. data/test/package/styles/test_styles_05.rb +150 -0
  130. data/test/package/styles/test_styles_06.rb +104 -0
  131. data/test/package/styles/test_styles_07.rb +104 -0
  132. data/test/package/styles/test_styles_08.rb +109 -0
  133. data/test/package/styles/test_styles_09.rb +95 -0
  134. data/test/package/vml/test_vml_01.rb +42 -0
  135. data/test/package/vml/test_write_anchor.rb +14 -0
  136. data/test/package/vml/test_write_auto_fill.rb +14 -0
  137. data/test/package/vml/test_write_column.rb +14 -0
  138. data/test/package/vml/test_write_div.rb +14 -0
  139. data/test/package/vml/test_write_fill.rb +14 -0
  140. data/test/package/vml/test_write_idmap.rb +14 -0
  141. data/test/package/vml/test_write_move_with_cells.rb +14 -0
  142. data/test/package/vml/test_write_path.rb +22 -0
  143. data/test/package/vml/test_write_row.rb +14 -0
  144. data/test/package/vml/test_write_shadow.rb +14 -0
  145. data/test/package/vml/test_write_shapelayout.rb +14 -0
  146. data/test/package/vml/test_write_shapetype.rb +14 -0
  147. data/test/package/vml/test_write_size_with_cells.rb +14 -0
  148. data/test/package/vml/test_write_stroke.rb +14 -0
  149. data/test/package/vml/test_write_textbox.rb +14 -0
  150. data/test/perl_output/a_simple.xlsx +0 -0
  151. data/test/perl_output/array_formula.xlsx +0 -0
  152. data/test/perl_output/autofilter.xlsx +0 -0
  153. data/test/perl_output/chart_area.xlsx +0 -0
  154. data/test/perl_output/chart_bar.xlsx +0 -0
  155. data/test/perl_output/chart_column.xlsx +0 -0
  156. data/test/perl_output/chart_line.xlsx +0 -0
  157. data/test/perl_output/chart_pie.xlsx +0 -0
  158. data/test/perl_output/chart_scatter.xlsx +0 -0
  159. data/test/perl_output/chart_stock.xlsx +0 -0
  160. data/test/perl_output/comments1.xlsx +0 -0
  161. data/test/perl_output/comments2.xlsx +0 -0
  162. data/test/perl_output/conditional_format.xlsx +0 -0
  163. data/test/perl_output/data_validate.xlsx +0 -0
  164. data/test/perl_output/defined_name.xlsx +0 -0
  165. data/test/perl_output/demo.xlsx +0 -0
  166. data/test/perl_output/diag_border.xlsx +0 -0
  167. data/test/perl_output/fit_to_pages.xlsx +0 -0
  168. data/test/perl_output/headers.xlsx +0 -0
  169. data/test/perl_output/hide_sheet.xlsx +0 -0
  170. data/test/perl_output/hyperlink.xlsx +0 -0
  171. data/test/perl_output/indent.xlsx +0 -0
  172. data/test/perl_output/merge1.xlsx +0 -0
  173. data/test/perl_output/merge2.xlsx +0 -0
  174. data/test/perl_output/merge3.xlsx +0 -0
  175. data/test/perl_output/merge4.xlsx +0 -0
  176. data/test/perl_output/merge5.xlsx +0 -0
  177. data/test/perl_output/merge6.xlsx +0 -0
  178. data/test/perl_output/outline.xlsx +0 -0
  179. data/test/perl_output/print_scale.xlsx +0 -0
  180. data/test/perl_output/properties.xlsx +0 -0
  181. data/test/perl_output/protection.xlsx +0 -0
  182. data/test/perl_output/rich_strings.xlsx +0 -0
  183. data/test/perl_output/right_to_left.xlsx +0 -0
  184. data/test/perl_output/tab_colors.xlsx +0 -0
  185. data/test/test_delete_files.rb +37 -0
  186. data/test/test_example_match.rb +2281 -0
  187. data/test/test_xml_writer_simple.rb +63 -0
  188. data/test/workbook/test_get_chart_range.rb +59 -0
  189. data/test/workbook/test_sort_defined_names.rb +77 -0
  190. data/test/workbook/test_workbook_01.rb +29 -0
  191. data/test/workbook/test_workbook_02.rb +31 -0
  192. data/test/workbook/test_workbook_03.rb +31 -0
  193. data/test/workbook/test_workbook_new.rb +18 -0
  194. data/test/workbook/test_write_defined_name.rb +17 -0
  195. data/test/workbook/test_write_defined_names.rb +41 -0
  196. data/test/worksheet/test_calculate_spans.rb +58 -0
  197. data/test/worksheet/test_convert_date_time_01.rb +439 -0
  198. data/test/worksheet/test_convert_date_time_02.rb +478 -0
  199. data/test/worksheet/test_convert_date_time_03.rb +435 -0
  200. data/test/worksheet/test_extract_filter_tokens.rb +109 -0
  201. data/test/worksheet/test_parse_filter_expression.rb +143 -0
  202. data/test/worksheet/test_position_object.rb +50 -0
  203. data/test/worksheet/test_repeat_formula.rb +55 -0
  204. data/test/worksheet/test_worksheet_01.rb +32 -0
  205. data/test/worksheet/test_worksheet_02.rb +38 -0
  206. data/test/worksheet/test_worksheet_03.rb +44 -0
  207. data/test/worksheet/test_worksheet_04.rb +45 -0
  208. data/test/worksheet/test_write_array_formula_01.rb +99 -0
  209. data/test/worksheet/test_write_autofilter.rb +260 -0
  210. data/test/worksheet/test_write_brk.rb +18 -0
  211. data/test/worksheet/test_write_cell.rb +49 -0
  212. data/test/worksheet/test_write_cell_value.rb +33 -0
  213. data/test/worksheet/test_write_col_breaks.rb +27 -0
  214. data/test/worksheet/test_write_col_info.rb +95 -0
  215. data/test/worksheet/test_write_conditional_formatting.rb +72 -0
  216. data/test/worksheet/test_write_custom_filter.rb +18 -0
  217. data/test/worksheet/test_write_custom_filters.rb +25 -0
  218. data/test/worksheet/test_write_data_validation_01.rb +113 -0
  219. data/test/worksheet/test_write_data_validation_02.rb +528 -0
  220. data/test/worksheet/test_write_dimension.rb +94 -0
  221. data/test/worksheet/test_write_ext.rb +18 -0
  222. data/test/worksheet/test_write_ext_lst.rb +18 -0
  223. data/test/worksheet/test_write_filter.rb +18 -0
  224. data/test/worksheet/test_write_filter_column.rb +18 -0
  225. data/test/worksheet/test_write_filters.rb +32 -0
  226. data/test/worksheet/test_write_header_footer.rb +53 -0
  227. data/test/worksheet/test_write_hyperlink.rb +39 -0
  228. data/test/worksheet/test_write_hyperlinks.rb +27 -0
  229. data/test/worksheet/test_write_legacy_drawing.rb +19 -0
  230. data/test/worksheet/test_write_merge_cell.rb +18 -0
  231. data/test/worksheet/test_write_merge_cells.rb +192 -0
  232. data/test/worksheet/test_write_methods.rb +353 -0
  233. data/test/worksheet/test_write_mx_plv.rb +19 -0
  234. data/test/worksheet/test_write_page_margins.rb +98 -0
  235. data/test/worksheet/test_write_page_set_up_pr.rb +19 -0
  236. data/test/worksheet/test_write_page_setup.rb +54 -0
  237. data/test/worksheet/test_write_pane.rb +123 -0
  238. data/test/worksheet/test_write_phonetic_pr.rb +19 -0
  239. data/test/worksheet/test_write_print_options.rb +77 -0
  240. data/test/worksheet/test_write_row_breaks.rb +27 -0
  241. data/test/worksheet/test_write_row_element.rb +69 -0
  242. data/test/worksheet/test_write_selection.rb +18 -0
  243. data/test/worksheet/test_write_sheet_calc_pr.rb +18 -0
  244. data/test/worksheet/test_write_sheet_data.rb +18 -0
  245. data/test/worksheet/test_write_sheet_format_pr.rb +18 -0
  246. data/test/worksheet/test_write_sheet_pr.rb +36 -0
  247. data/test/worksheet/test_write_sheet_protection.rb +174 -0
  248. data/test/worksheet/test_write_sheet_view.rb +62 -0
  249. data/test/worksheet/test_write_sheet_view1.rb +64 -0
  250. data/test/worksheet/test_write_sheet_view2.rb +56 -0
  251. data/test/worksheet/test_write_sheet_view3.rb +83 -0
  252. data/test/worksheet/test_write_sheet_view4.rb +83 -0
  253. data/test/worksheet/test_write_sheet_view5.rb +74 -0
  254. data/test/worksheet/test_write_sheet_view6.rb +51 -0
  255. data/test/worksheet/test_write_sheet_view7.rb +71 -0
  256. data/test/worksheet/test_write_sheet_view8.rb +51 -0
  257. data/test/worksheet/test_write_sheet_view9.rb +51 -0
  258. data/test/worksheet/test_write_tab_color.rb +23 -0
  259. data/test/worksheet/test_write_worksheet.rb +19 -0
  260. data/write_xlsx.gemspec +308 -0
  261. metadata +363 -0
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ ##############################################################################
5
+ #
6
+ # An example of adding document properties to a Excel::Writer::XLSX file.
7
+ #
8
+ # reverse('©'), August 2008, John McNamara, jmcnamara@cpan.org
9
+ # convert to ruby by Hideo NAKAMURA, cxn03651@msj.biglobe.ne.jp
10
+ #
11
+
12
+ require 'rubygems'
13
+ require 'write_xlsx'
14
+
15
+ workbook = WriteXLSX.new('properties.xlsx')
16
+ worksheet = workbook.add_worksheet
17
+
18
+ workbook.set_properties(
19
+ :title => 'This is an example spreadsheet',
20
+ :subject => 'With document properties',
21
+ :author => 'John McNamara',
22
+ :manager => 'Dr. Heinz Doofenshmirtz',
23
+ :company => 'of Wolves',
24
+ :category => 'Example spreadsheets',
25
+ :keywords => 'Sample, Example, Properties',
26
+ :comments => 'Created with Perl and Excel::Writer::XLSX',
27
+ :status => 'Quo'
28
+ )
29
+
30
+ worksheet.set_column('A:A', 70)
31
+ worksheet.write('A1', "Select 'Office Button -> Prepare -> Properties' to see the file properties.")
32
+
33
+ workbook.close
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'rubygems'
5
+ require 'write_xlsx'
6
+
7
+ workbook = WriteXLSX.new('protection.xlsx')
8
+ worksheet = workbook.add_worksheet
9
+
10
+ # Create some format objects
11
+ unlocked = workbook.add_format(:locked => 0)
12
+ hidden = workbook.add_format(:hidden => 1)
13
+
14
+ # Format the columns
15
+ worksheet.set_column('A:A', 45)
16
+ worksheet.set_selection('B3')
17
+
18
+ # Protect the worksheet
19
+ worksheet.protect
20
+
21
+ # Examples of cell locking and hiding.
22
+ worksheet.write('A1', 'Cell B1 is locked. It cannot be edited.')
23
+ worksheet.write_formula('B1', '=1+2', nil, 3) # Locked by default.
24
+
25
+ worksheet.write('A2', 'Cell B2 is unlocked. It can be edited.')
26
+ worksheet.write_formula('B2', '=1+2', unlocked, 3)
27
+
28
+ worksheet.write('A3', "Cell B3 is hidden. The formula isn't visible.")
29
+ worksheet.write_formula('B3', '=1+2', hidden, 3)
30
+
31
+ worksheet.write('A5', 'Use Menu->Tools->Protection->Unprotect Sheet')
32
+ worksheet.write('A6', 'to remove the worksheet protection.')
33
+
34
+ workbook.close
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ #######################################################################
5
+ #
6
+ # An Excel::Writer::XLSX example showing how to use "rich strings", i.e.,
7
+ # strings with multiple formatting.
8
+ #
9
+ # reverse(c), February 2011, John McNamara, jmcnamara@cpan.org
10
+ # convert to ruby by Hideo NAKAMURA, cxn03651@msj.biglobe.ne.jp
11
+ #
12
+
13
+ require 'rubygems'
14
+ require 'write_xlsx'
15
+
16
+ workbook = WriteXLSX.new('rich_strings.xlsx')
17
+ worksheet = workbook.add_worksheet
18
+
19
+ worksheet.set_column('A:A', 30)
20
+
21
+ # Set some formats to use.
22
+ bold = workbook.add_format(:bold => 1)
23
+ italic = workbook.add_format(:italic => 1)
24
+ red = workbook.add_format(:color => 'red')
25
+ blue = workbook.add_format(:color => 'blue')
26
+ center = workbook.add_format(:align => 'center')
27
+ superc = workbook.add_format(:font_script => 1)
28
+
29
+ # Write some strings with multiple formats.
30
+ worksheet.write_rich_string('A1',
31
+ 'This is ', bold, 'bold', ' and this is ', italic, 'italic')
32
+
33
+ worksheet.write_rich_string('A3',
34
+ 'This is ', red, 'red', ' and this is ', blue, 'blue')
35
+
36
+ worksheet.write_rich_string('A5',
37
+ 'Some ', bold, 'bold text', ' centered', center)
38
+
39
+ worksheet.write_rich_string('A7',
40
+ italic, 'j = k', superc, '(n-1)', center)
41
+
42
+ workbook.close
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #######################################################################
4
+ #
5
+ # Example of how to change the default worksheet direction from
6
+ # left-to-right to right-to-left as required by some eastern verions
7
+ # of Excel.
8
+ #
9
+ # reverse(c), January 2006, John McNamara, jmcnamara@cpan.org
10
+ # convert to ruby by Hideo NAKAMURA, cxn03651@msj.biglobe.ne.jp
11
+ #
12
+
13
+ require 'rubygems'
14
+ require 'write_xlsx'
15
+
16
+ workbook = WriteXLSX.new('right_to_left.xlsx')
17
+ worksheet1 = workbook.add_worksheet
18
+ worksheet2 = workbook.add_worksheet
19
+
20
+ worksheet2.right_to_left
21
+
22
+ worksheet1.write(0, 0, 'Hello') # A1, B1, C1, ...
23
+ worksheet2.write(0, 0, 'Hello') # ..., C1, B1, A1
24
+ workbook.close
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #######################################################################
4
+ #
5
+ # Example of how to set Excel worksheet tab colours.
6
+ #
7
+ # reverse(c), May 2006, John McNamara, jmcnamara@cpan.org
8
+ # convert to ruby by Hideo NAKAMURA, cxn03651@msj.biglobe.ne.jp
9
+ #
10
+
11
+ require 'rubygems'
12
+ require 'write_xlsx'
13
+
14
+ workbook = Excel::Writer::XLSX.new('tab_colors.xlsx')
15
+
16
+ worksheet1 = workbook.add_worksheet
17
+ worksheet2 = workbook.add_worksheet
18
+ worksheet3 = workbook.add_worksheet
19
+ worksheet4 = workbook.add_worksheet
20
+
21
+ # Worksheet1 will have the default tab colour.
22
+ worksheet2.set_tab_color('red')
23
+ worksheet3.set_tab_color('green')
24
+ worksheet4.set_tab_color(0x35) # Orange
25
+
26
+ workbook.close
data/lib/write_xlsx.rb ADDED
@@ -0,0 +1,77 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'write_xlsx/workbook'
4
+
5
+ #
6
+ # write_xlsx is gem to create a new file in the Excel 2007+ XLSX format,
7
+ # and you can use the same interface as writeexcel gem.
8
+ # write_xlsx is converted from Perl’s module github.com/jmcnamara/excel-writer-xlsx .
9
+ #
10
+ # == Description
11
+ # The WriteXLSX supports the following features:
12
+ #
13
+ # Multiple worksheets
14
+ # Strings and numbers
15
+ # Unicode text
16
+ # Rich string formats
17
+ # Formulas (including array formats)
18
+ # cell formatting
19
+ # Embedded images
20
+ # Charts
21
+ # Autofilters
22
+ # Data validation
23
+ # Hyperlinks
24
+ # Defined names
25
+ # Grouping/Outlines
26
+ # Cell comments
27
+ # Panes
28
+ # Page set-up and printing options
29
+ # WriteXLSX uses the same interface as WriteExcel gem.
30
+ #
31
+ # == Synopsis
32
+ # To write a string, a formatted string, a number and a formula to the
33
+ # first worksheet in an Excel XMLX spreadsheet called ruby.xlsx:
34
+ #
35
+ # require 'rubygems'
36
+ # require 'write_xlsx'
37
+ #
38
+ # # Create a new Excel workbook
39
+ # workbook = WriteXLSX.new('ruby.xlsx')
40
+ #
41
+ # # Add a worksheet
42
+ # worksheet = workbook.add_worksheet
43
+ #
44
+ # # Add and define a format
45
+ # format = workbook.add_format # Add a format
46
+ # format.set_bold
47
+ # format.set_color('red')
48
+ # format.set_align('center')
49
+ #
50
+ # # Write a formatted and unformatted string, row and column notation.
51
+ # col = row = 0
52
+ # worksheet.write(row, col, "Hi Excel!", format)
53
+ # worksheet.write(1, col, "Hi Excel!")
54
+ #
55
+ # # Write a number and a formula using A1 notation
56
+ # worksheet.write('A3', 1.2345)
57
+ # worksheet.write('A4', '=SIN(PI()/4)')
58
+ # workbook.close
59
+ #
60
+ # == Other Methods
61
+ #
62
+ # see Writexlsx::Workbook, Writexlsx::Worksheet, Writexlsx::Chart etc.
63
+ #
64
+ class WriteXLSX < Writexlsx::Workbook
65
+ if RUBY_VERSION < '1.9'
66
+ $KCODE = 'u'
67
+ end
68
+ end
69
+
70
+ class WriteXLSXInsufficientArgumentError < StandardError
71
+ end
72
+
73
+ class WriteXLSXDimensionError < StandardError
74
+ end
75
+
76
+ class WriteXLSXOptionParameterError < StandardError
77
+ end
@@ -0,0 +1,3027 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'write_xlsx/package/xml_writer_simple'
3
+ require 'write_xlsx/utility'
4
+
5
+ module Writexlsx
6
+ # ==SYNOPSIS
7
+ #
8
+ # To create a simple Excel file with a chart using WriteXLSX:
9
+ #
10
+ # require 'rubygems'
11
+ # require 'write_xlsx'
12
+ #
13
+ # workbook = WriteXLSX.new( 'chart.xlsx' )
14
+ # worksheet = workbook.add_worksheet
15
+ #
16
+ # # Add the worksheet data the chart refers to.
17
+ # data = [
18
+ # [ 'Category', 2, 3, 4, 5, 6, 7 ],
19
+ # [ 'Value', 1, 4, 5, 2, 1, 5 ]
20
+ # ]
21
+ #
22
+ # worksheet.write( 'A1', data )
23
+ #
24
+ # # Add a worksheet chart.
25
+ # chart = workbook.add_chart( type => 'column' )
26
+ #
27
+ # # Configure the chart.
28
+ # chart.add_series(
29
+ # :categories => '=Sheet1!$A$2:$A$7',
30
+ # :values => '=Sheet1!$B$2:$B$7'
31
+ # )
32
+ #
33
+ # workbook.close
34
+ #
35
+ # ==DESCRIPTION
36
+ #
37
+ # The Chart module is an abstract base class for modules that implement
38
+ # charts in WriteXLSX. The information below is applicable to all of
39
+ # the available subclasses.
40
+ #
41
+ # The Chart module isn't used directly. A chart object is created via
42
+ # the Workbook add_chart() method where the chart type is specified:
43
+ #
44
+ # chart = workbook.add_chart( :type => 'column' )
45
+ #
46
+ # Currently the supported chart types are:
47
+ #
48
+ # ===area
49
+ # Creates an Area (filled line) style chart. See Writexlsx::Chart::Area.
50
+ #
51
+ # ===bar
52
+ # Creates a Bar style (transposed histogram) chart. See Writexlsx::Chart::Bar.
53
+ #
54
+ # ===column
55
+ # Creates a column style (histogram) chart. See Writexlsx::Chart::Column.
56
+ #
57
+ # ===line
58
+ # Creates a Line style chart. See Writexlsx::Chart::Line.
59
+ #
60
+ # ===pie
61
+ # Creates an Pie style chart. See Writexlsx::Chart::Pie.
62
+ #
63
+ # ===scatter
64
+ # Creates an Scatter style chart. See Writexlsx::Chart::Scatter.
65
+ #
66
+ # ===stock
67
+ # Creates an Stock style chart. See Writexlsx::Chart::Stock.
68
+ #
69
+ # ==CHART FORMATTING
70
+ #
71
+ # The following chart formatting properties can be set for any chart object
72
+ # that they apply to (and that are supported by Excel::Writer::XLSX) such
73
+ # as chart lines, column fill areas, plot area borders, markers and other
74
+ # chart elements documented above.
75
+ #
76
+ # line
77
+ # border
78
+ # fill
79
+ # marker
80
+ # trendline
81
+ # data_labels
82
+ # Chart formatting properties are generally set using hash refs.
83
+ #
84
+ # chart.add_series(
85
+ # :values => '=Sheet1!$B$1:$B$5',
86
+ # :line => { color => 'blue' }
87
+ # )
88
+ # In some cases the format properties can be nested. For example a marker
89
+ # may contain border and fill sub-properties.
90
+ #
91
+ # chart.add_series(
92
+ # :values => '=Sheet1!$B$1:$B$5',
93
+ # :line => { color => 'blue' },
94
+ # :marker => {
95
+ # :type => 'square',
96
+ # :size => 5,
97
+ # :border => { color => 'red' },
98
+ # :fill => { color => 'yellow' }
99
+ # }
100
+ # )
101
+ # ===Line
102
+ #
103
+ # The line format is used to specify properties of line objects that appear
104
+ # in a chart such as a plotted line on a chart or a border.
105
+ #
106
+ # The following properties can be set for line formats in a chart.
107
+ #
108
+ # none
109
+ # color
110
+ # width
111
+ # dash_type
112
+ # The none property is uses to turn the line off (it is always on by default
113
+ # except in Scatter charts). This is useful if you wish to plot a series
114
+ # with markers but without a line.
115
+ #
116
+ # chart.add_series(
117
+ # :values => '=Sheet1!$B$1:$B$5',
118
+ # :line => { none => 1 }
119
+ # )
120
+ # The color property sets the color of the line.
121
+ #
122
+ # chart.add_series(
123
+ # :values => '=Sheet1!$B$1:$B$5',
124
+ # :line => { color => 'red' }
125
+ # )
126
+ # The available colors are shown in the main WriteXLSX documentation.
127
+ # It is also possible to set the color of a line with a HTML style RGB color:
128
+ #
129
+ # chart.add_series(
130
+ # :line => { color => '#FF0000' }
131
+ # )
132
+ # The width property sets the width of the line. It should be specified
133
+ # in increments of 0.25 of a point as in Excel.
134
+ #
135
+ # chart.add_series(
136
+ # :values => '=Sheet1!$B$1:$B$5',
137
+ # :line => { width => 3.25 }
138
+ # )
139
+ # The dash_type property sets the dash style of the line.
140
+ #
141
+ # chart->add_series(
142
+ # :values => '=Sheet1!$B$1:$B$5',
143
+ # :line => { dash_type => 'dash_dot' }
144
+ # )
145
+ # The following dash_type values are available. They are shown in the
146
+ # order that they appear in the Excel dialog.
147
+ #
148
+ # solid
149
+ # round_dot
150
+ # square_dot
151
+ # dash
152
+ # dash_dot
153
+ # long_dash
154
+ # long_dash_dot
155
+ # long_dash_dot_dot
156
+ # The default line style is solid.
157
+ #
158
+ # More than one line property can be specified at time:
159
+ #
160
+ # chart.add_series(
161
+ # :values => '=Sheet1!$B$1:$B$5',
162
+ # :line => {
163
+ # :color => 'red',
164
+ # :width => 1.25,
165
+ # :dash_type => 'square_dot'
166
+ # }
167
+ # )
168
+ # ===Border
169
+ #
170
+ # The border property is a synonym for line.
171
+ #
172
+ # It can be used as a descriptive substitute for line in chart types such
173
+ # as Bar and Column that have a border and fill style rather than a line
174
+ # style. In general chart objects with a border property will also have a
175
+ # fill property.
176
+ #
177
+ # ===Fill
178
+ #
179
+ # The fill format is used to specify filled areas of chart objects such
180
+ # as the interior of a column or the background of the chart itself.
181
+ #
182
+ # The following properties can be set for fill formats in a chart.
183
+ #
184
+ # none
185
+ # color
186
+ # The none property is uses to turn the fill property off (it is
187
+ # generally on by default).
188
+ #
189
+ # chart.add_series(
190
+ # :values => '=Sheet1!$B$1:$B$5',
191
+ # :fill => { none => 1 }
192
+ # )
193
+ # The color property sets the color of the fill area.
194
+ #
195
+ # chart.add_series(
196
+ # :values => '=Sheet1!$B$1:$B$5',
197
+ # :fill => { color => 'red' }
198
+ # )
199
+ # The available colors are shown in the main WriteXLSX documentation.
200
+ # It is also possible to set the color of a fill with a HTML style RGB color:
201
+ #
202
+ # chart.add_series(
203
+ # :fill => { color => '#FF0000' }
204
+ # )
205
+ # The fill format is generally used in conjunction with a border format
206
+ # which has the same properties as a line format.
207
+ #
208
+ # chart.add_series(
209
+ # :values => '=Sheet1!$B$1:$B$5',
210
+ # :border => { color => 'red' },
211
+ # :fill => { color => 'yellow' }
212
+ # )
213
+ # ===Marker
214
+ #
215
+ # The marker format specifies the properties of the markers used to
216
+ # distinguish series on a chart. In general only Line and Scatter
217
+ # chart types and trendlines use markers.
218
+ #
219
+ # The following properties can be set for marker formats in a chart.
220
+ #
221
+ # type
222
+ # size
223
+ # border
224
+ # fill
225
+ # The type property sets the type of marker that is used with a series.
226
+ #
227
+ # chart.add_series(
228
+ # :values => '=Sheet1!$B$1:$B$5',
229
+ # :marker => { type => 'diamond' }
230
+ # )
231
+ # The following type properties can be set for marker formats in a chart.
232
+ # These are shown in the same order as in the Excel format dialog.
233
+ #
234
+ # automatic
235
+ # none
236
+ # square
237
+ # diamond
238
+ # triangle
239
+ # x
240
+ # star
241
+ # short_dash
242
+ # long_dash
243
+ # circle
244
+ # plus
245
+ # The automatic type is a special case which turns on a marker using the
246
+ # default marker style for the particular series number.
247
+ #
248
+ # chart.add_series(
249
+ # :values => '=Sheet1!$B$1:$B$5',
250
+ # :marker => { type => 'automatic' }
251
+ # )
252
+ # If automatic is on then other marker properties such as size,
253
+ # border or fill cannot be set.
254
+ #
255
+ # The size property sets the size of the marker and is generally used in
256
+ # conjunction with type.
257
+ #
258
+ # chart.add_series(
259
+ # :values => '=Sheet1!$B$1:$B$5',
260
+ # :marker => { type => 'diamond', size => 7 }
261
+ # )
262
+ # Nested border and fill properties can also be set for a marker.
263
+ # These have the same sub-properties as shown above.
264
+ #
265
+ # chart.add_series(
266
+ # :values => '=Sheet1!$B$1:$B$5',
267
+ # :marker => {
268
+ # :type => 'square',
269
+ # :size => 5,
270
+ # :border => { color => 'red' },
271
+ # :fill => { color => 'yellow' }
272
+ # }
273
+ # )
274
+ # ===Trendline
275
+ #
276
+ # A trendline can be added to a chart series to indicate trends in the data
277
+ # such as a moving average or a polynomial fit.
278
+ #
279
+ # The following properties can be set for trendline formats in a chart.
280
+ #
281
+ # type
282
+ # order (for polynomial trends)
283
+ # period (for moving average)
284
+ # forward (for all except moving average)
285
+ # backward (for all except moving average)
286
+ # name
287
+ # line
288
+ # The type property sets the type of trendline in the series.
289
+ #
290
+ # chart.add_series(
291
+ # :values => '=Sheet1!$B$1:$B$5',
292
+ # :trendline => { type => 'linear' }
293
+ # )
294
+ # The available trendline types are:
295
+ #
296
+ # exponential
297
+ # linear
298
+ # log
299
+ # moving_average
300
+ # polynomial
301
+ # power
302
+ # A polynomial trendline can also specify the order of the polynomial.
303
+ # The default value is 2.
304
+ #
305
+ # chart.add_series(
306
+ # :values => '=Sheet1!$B$1:$B$5',
307
+ # :trendline => {
308
+ # :type => 'polynomial',
309
+ # :order => 3
310
+ # }
311
+ # )
312
+ # A moving_average trendline can also the period of the moving average.
313
+ # The default value is 2.
314
+ #
315
+ # chart.add_series(
316
+ # :values => '=Sheet1!$B$1:$B$5',
317
+ # :trendline => {
318
+ # :type => 'moving_average',
319
+ # :period => 3
320
+ # }
321
+ # )
322
+ # The forward and backward properties set the forecast period of the
323
+ # trendline.
324
+ #
325
+ # chart.add_series(
326
+ # :values => '=Sheet1!$B$1:$B$5',
327
+ # :trendline => {
328
+ # :type => 'linear',
329
+ # :forward => 0.5,
330
+ # :backward => 0.5
331
+ # }
332
+ # )
333
+ # The name property sets an optional name for the trendline that will
334
+ # appear in the chart legend. If it isn't specified the Excel default
335
+ # name will be displayed. This is usually a combination of the trendline
336
+ # type and the series name.
337
+ #
338
+ # chart.add_series(
339
+ # :values => '=Sheet1!$B$1:$B$5',
340
+ # :trendline => {
341
+ # :type => 'linear',
342
+ # :name => 'Interpolated trend'
343
+ # }
344
+ # )
345
+ # Several of these properties can be set in one go:
346
+ #
347
+ # chart.add_series(
348
+ # :values => '=Sheet1!$B$1:$B$5',
349
+ # :trendline => {
350
+ # :type => 'linear',
351
+ # :name => 'My trend name',
352
+ # :forward => 0.5,
353
+ # :backward => 0.5,
354
+ # :line => {
355
+ # :color => 'red',
356
+ # :width => 1,
357
+ # :dash_type => 'long_dash'
358
+ # }
359
+ # }
360
+ # )
361
+ # Trendlines cannot be added to series in a stacked chart or pie chart or
362
+ # (when implemented) to 3-D, radar, surface, or doughnut charts.
363
+ #
364
+ # ==Data Labels
365
+ #
366
+ # Data labels can be added to a chart series to indicate the values of
367
+ # the plotted data points.
368
+ #
369
+ # The following properties can be set for data_labels formats in a chart.
370
+ #
371
+ # value
372
+ # category
373
+ # series_name
374
+ # The value property turns on the Value data label for a series.
375
+ #
376
+ # chart.add_series(
377
+ # :values => '=Sheet1!$B$1:$B$5',
378
+ # :data_labels => { value => 1 }
379
+ # )
380
+ # The category property turns on the Category Name data label for a series.
381
+ #
382
+ # chart.add_series(
383
+ # :values => '=Sheet1!$B$1:$B$5',
384
+ # :data_labels => { category => 1 }
385
+ # )
386
+ # The series_name property turns on the Series Name data label for a series.
387
+ #
388
+ # chart.add_series(
389
+ # :values => '=Sheet1!$B$1:$B$5',
390
+ # :data_labels => { series_name => 1 }
391
+ # )
392
+ # Other formatting options
393
+ #
394
+ # Other formatting options will be added in time. If there is a feature that
395
+ # you would like to see included drop me a line.
396
+ #
397
+ class Chart
398
+ include Writexlsx::Utility
399
+
400
+ attr_accessor :id # :nodoc:
401
+ attr_writer :index, :palette # :nodoc:
402
+ attr_reader :embedded, :formula_ids, :formula_data # :nodoc:
403
+
404
+ #
405
+ # Factory method for returning chart objects based on their class type.
406
+ #
407
+ def self.factory(chart_subclass) # :nodoc:
408
+ case chart_subclass.downcase.capitalize
409
+ when 'Area'
410
+ require 'write_xlsx/chart/area'
411
+ Chart::Area.new
412
+ when 'Bar'
413
+ require 'write_xlsx/chart/bar'
414
+ Chart::Bar.new
415
+ when 'Column'
416
+ require 'write_xlsx/chart/column'
417
+ Chart::Column.new
418
+ when 'Line'
419
+ require 'write_xlsx/chart/line'
420
+ Chart::Line.new
421
+ when 'Pie'
422
+ require 'write_xlsx/chart/pie'
423
+ Chart::Pie.new
424
+ when 'Scatter'
425
+ require 'write_xlsx/chart/scatter'
426
+ Chart::Scatter.new
427
+ when 'Stock'
428
+ require 'write_xlsx/chart/stock'
429
+ Chart::Stock.new
430
+ end
431
+ end
432
+
433
+ def initialize(subtype) # :nodoc:
434
+ @writer = Package::XMLWriterSimple.new
435
+
436
+ @subtype = subtype
437
+ @sheet_type = 0x0200
438
+ @orientation = 0x0
439
+ @series = []
440
+ @embedded = 0
441
+ @id = ''
442
+ @style_id = 2
443
+ @axis_ids = []
444
+ @has_category = 0
445
+ @requires_category = 0
446
+ @legend_position = 'right'
447
+ @cat_axis_position = 'b'
448
+ @val_axis_position = 'l'
449
+ @formula_ids = {}
450
+ @formula_data = []
451
+ @horiz_cat_axis = 0
452
+ @horiz_val_axis = 1
453
+ @protection = 0
454
+ @x_axis = {}
455
+ @y_axis = {}
456
+
457
+ set_default_properties
458
+ end
459
+
460
+ def set_xml_writer(filename) # :nodoc:
461
+ @writer.set_xml_writer(filename)
462
+ end
463
+
464
+ #
465
+ # Assemble and write the XML file.
466
+ #
467
+ def assemble_xml_file # :nodoc:
468
+ @writer.xml_decl
469
+
470
+ # Write the c:chartSpace element.
471
+ write_chart_space
472
+
473
+ # Write the c:lang element.
474
+ write_lang
475
+
476
+ # Write the c:style element.
477
+ write_style
478
+
479
+ # Write the c:protection element.
480
+ write_protection
481
+
482
+ # Write the c:chart element.
483
+ write_chart
484
+
485
+ # Write the c:printSettings element.
486
+ write_print_settings if @embedded
487
+
488
+ # Close the worksheet tag.
489
+ @writer.end_tag( 'c:chartSpace')
490
+
491
+ # Close the XML writer object and filehandle.
492
+ @writer.crlf
493
+ @writer.close
494
+ end
495
+
496
+ #
497
+ # Add a series and it's properties to a chart.
498
+ #
499
+ # In an Excel chart a "series" is a collection of information such as
500
+ # values, x-axis labels and the formatting that define which data is
501
+ # plotted.
502
+ #
503
+ # With a WriteXLSX chart object the add_series() method is used to
504
+ # set the properties for a series:
505
+ #
506
+ # chart.add_series(
507
+ # :categories => '=Sheet1!$A$2:$A$10', # Optional.
508
+ # :values => '=Sheet1!$B$2:$B$10', # Required.
509
+ # :line => { color => 'blue' }
510
+ # )
511
+ #
512
+ # The properties that can be set are:
513
+ #
514
+ # ====:values
515
+ # This is the most important property of a series and must be set
516
+ # for every chart object. It links the chart with the worksheet data
517
+ # that it displays. A formula or array ref can be used for the
518
+ # data range, see below.
519
+ #
520
+ # ====:categories
521
+ # This sets the chart category labels. The category is more or less
522
+ # the same as the X-axis. In most chart types the categories property
523
+ # is optional and the chart will just assume a sequential series
524
+ # from 1 .. n.
525
+ #
526
+ # ====:name
527
+ # Set the name for the series. The name is displayed in the chart
528
+ # legend and in the formula bar. The name property is optional and
529
+ # if it isn't supplied it will default to Series 1 .. n.
530
+ #
531
+ # ====:line
532
+ # Set the properties of the series line type such as colour and
533
+ # width. See the "CHART FORMATTING" section below.
534
+ #
535
+ # ====:border
536
+ # Set the border properties of the series such as colour and style.
537
+ # See the "CHART FORMATTING" section below.
538
+ #
539
+ # ====:fill
540
+ # Set the fill properties of the series such as colour. See the
541
+ # "CHART FORMATTING" section below.
542
+ #
543
+ # ====:marker
544
+ # Set the properties of the series marker such as style and color.
545
+ # See the "CHART FORMATTING" section below.
546
+ #
547
+ # ====:trendline
548
+ # Set the properties of the series trendline such as linear,
549
+ # polynomial and moving average types. See the "CHART FORMATTING"
550
+ # section below.
551
+ #
552
+ # ====:data_labels
553
+ # Set data labels for the series. See the "CHART FORMATTING"
554
+ # section below.
555
+ #
556
+ # ====:invert_if_negative
557
+ # Invert the fill colour for negative values. Usually only applicable
558
+ # to column and bar charts.
559
+ #
560
+ # The categories and values can take either a range formula such
561
+ # as =Sheet1!$A$2:$A$7 or, more usefully when generating the range
562
+ # programmatically, an array ref with zero indexed row/column values:
563
+ #
564
+ # [ sheetname, row_start, row_end, col_start, col_end ]
565
+ # The following are equivalent:
566
+ #
567
+ # chart.add_series( categories => '=Sheet1!$A$2:$A$7' ) # Same as ...
568
+ # chart.add_series( categories => [ 'Sheet1', 1, 6, 0, 0 ] ) # Zero-indexed.
569
+ #
570
+ # You can add more than one series to a chart. In fact, some chart
571
+ # types such as stock require it. The series numbering and order in
572
+ # the Excel chart will be the same as the order in which that are added
573
+ # in Excel::Writer::XLSX.
574
+ #
575
+ # # Add the first series.
576
+ # chart.add_series(
577
+ # :categories => '=Sheet1!$A$2:$A$7',
578
+ # :values => '=Sheet1!$B$2:$B$7',
579
+ # :name => 'Test data series 1'
580
+ # )
581
+ #
582
+ # # Add another series. Same categories. Different range values.
583
+ # chart.add_series(
584
+ # :categories => '=Sheet1!$A$2:$A$7',
585
+ # :values => '=Sheet1!$C$2:$C$7',
586
+ # :name => 'Test data series 2'
587
+ # )
588
+ #
589
+ def add_series(params)
590
+ # Check that the required input has been specified.
591
+ unless params.has_key?(:values)
592
+ raise "Must specify ':values' in add_series"
593
+ end
594
+
595
+ if @requires_category != 0 && !params.has_key?(:categories)
596
+ raise "Must specify ':categories' in add_series for this chart type"
597
+ end
598
+
599
+ # Convert aref params into a formula string.
600
+ values = aref_to_formula(params[:values])
601
+ categories = aref_to_formula(params[:categories])
602
+
603
+ # Switch name and name_formula parameters if required.
604
+ name, name_formula = process_names(params[:name], params[:name_formula])
605
+
606
+ # Get an id for the data equivalent to the range formula.
607
+ cat_id = get_data_id(categories, params[:categories_data])
608
+ val_id = get_data_id(values, params[:values_data])
609
+ name_id = get_data_id(name_formula, params[:name_data])
610
+
611
+ # Set the line properties for the series.
612
+ line = get_line_properties(params[:line])
613
+
614
+ # Allow 'border' as a synonym for 'line' in bar/column style charts.
615
+ line = get_line_properties(params[:border]) if params[:border]
616
+
617
+ # Set the fill properties for the series.
618
+ fill = get_fill_properties(params[:fill])
619
+
620
+ # Set the marker properties for the series.
621
+ marker = get_marker_properties(params[:marker])
622
+
623
+ # Set the trendline properties for the series.
624
+ trendline = get_trendline_properties(params[:trendline])
625
+
626
+ # Set the labels properties for the series.
627
+ labels = get_labels_properties(params[:data_labels])
628
+
629
+ # Set the "invert if negative" fill property.
630
+ invert_if_neg = params[:invert_if_negative]
631
+
632
+ # Add the user supplied data to the internal structures.
633
+ @series << {
634
+ :_values => values,
635
+ :_categories => categories,
636
+ :_name => name,
637
+ :_name_formula => name_formula,
638
+ :_name_id => name_id,
639
+ :_val_data_id => val_id,
640
+ :_cat_data_id => cat_id,
641
+ :_line => line,
642
+ :_fill => fill,
643
+ :_marker => marker,
644
+ :_trendline => trendline,
645
+ :_labels => labels,
646
+ :_invert_if_neg => invert_if_neg
647
+ }
648
+ end
649
+
650
+ #
651
+ # Set the properties of the X-axis.
652
+ #
653
+ # The set_x_axis() method is used to set properties of the X axis.
654
+ #
655
+ # chart.set_x_axis( :name => 'Quarterly results' )
656
+ #
657
+ # The properties that can be set are:
658
+ #
659
+ # :name
660
+ # :min
661
+ # :max
662
+ # :minor_unit
663
+ # :major_unit
664
+ # :crossing
665
+ # :reverse
666
+ # :log_base
667
+ # :label_position
668
+ #
669
+ # These are explained below. Some properties are only applicable to value
670
+ # or category axes, as indicated. See "Value and Category Axes" for an
671
+ # explanation of Excel's distinction between the axis types.
672
+ #
673
+ # ====:name
674
+ # Set the name (title or caption) for the axis. The name is displayed
675
+ # below the X axis. The name property is optional. The default is to
676
+ # have no axis name. (Applicable to category and value axes).
677
+ #
678
+ # chart.set_x_axis( :name => 'Quarterly results' )
679
+ #
680
+ # The name can also be a formula such as =Sheet1!$A$1.
681
+ #
682
+ # ====:min
683
+ # Set the minimum value for the axis range.
684
+ # (Applicable to value axes only).
685
+ #
686
+ # chart.set_x_axis( :min => 20 )
687
+ # ====:max
688
+ # Set the maximum value for the axis range.
689
+ # (Applicable to value axes only).
690
+ #
691
+ # chart.set_x_axis( :max => 80 )
692
+ # ====:minor_unit
693
+ # Set the increment of the minor units in the axis range.
694
+ # (Applicable to value axes only).
695
+ #
696
+ # chart.set_x_axis( :minor_unit => 0.4 )
697
+ # ====:major_unit
698
+ # Set the increment of the major units in the axis range.
699
+ # (Applicable to value axes only).
700
+ #
701
+ # chart.set_x_axis( :major_unit => 2 )
702
+ # ====:crossing
703
+ # Set the position where the y axis will cross the x axis.
704
+ # (Applicable to category and value axes).
705
+ #
706
+ # The crossing value can either be the string 'max' to set the crossing
707
+ # at the maximum axis value or a numeric value.
708
+ #
709
+ # chart.set_x_axis( :crossing => 3 )
710
+ # # or
711
+ # chart.set_x_axis( :crossing => 'max' )
712
+ # For category axes the numeric value must be an integer to represent
713
+ # the category number that the axis crosses at. For value axes it can
714
+ # have any value associated with the axis.
715
+ #
716
+ # If crossing is omitted (the default) the crossing will be set
717
+ # automatically by Excel based on the chart data.
718
+ #
719
+ # ====:reverse
720
+ # Reverse the order of the axis categories or values.
721
+ # (Applicable to category and value axes).
722
+ #
723
+ # chart.set_x_axis( :reverse => 1 )
724
+ # ====:log_base
725
+ # Set the log base of the axis range.
726
+ # (Applicable to value axes only).
727
+ #
728
+ # chart.set_x_axis( :log_base => 10 )
729
+ # ====:label_position
730
+ # Set the "Axis labels" position for the axis.
731
+ # The following positions are available:
732
+ #
733
+ # next_to (the default)
734
+ # high
735
+ # low
736
+ # none
737
+ # More than one property can be set in a call to set_x_axis:
738
+ #
739
+ # chart.set_x_axis(
740
+ # :name => 'Quarterly results',
741
+ # :min => 10,
742
+ # :max => 80
743
+ # )
744
+ #
745
+ def set_x_axis(params)
746
+ @x_axis = convert_axis_args(params)
747
+ end
748
+
749
+ #
750
+ # Set the properties of the Y-axis.
751
+ #
752
+ # The set_y_axis() method is used to set properties of the Y axis.
753
+ # The properties that can be set are the same as for set_x_axis,
754
+ #
755
+ def set_y_axis(params)
756
+ @y_axis = convert_axis_args(params)
757
+ end
758
+
759
+ #
760
+ # Set the properties of the chart title.
761
+ #
762
+ # The set_title() method is used to set properties of the chart title.
763
+ #
764
+ # chart.set_title( :name => 'Year End Results' )
765
+ # The properties that can be set are:
766
+ #
767
+ # ====:name
768
+ # Set the name (title) for the chart. The name is displayed above the
769
+ # chart. The name can also be a formula such as =Sheet1!$A$1. The name
770
+ # property is optional. The default is to have no chart title.
771
+ #
772
+ def set_title(params)
773
+ name, name_formula = process_names(params[:name], params[:name_formula])
774
+
775
+ data_id = get_data_id(name_formula, params[:data])
776
+
777
+ @title_name = name
778
+ @title_formula = name_formula
779
+ @title_data_id = data_id
780
+ end
781
+
782
+ #
783
+ # Set the properties of the chart legend.
784
+ #
785
+ # The set_legend() method is used to set properties of the chart legend.
786
+ #
787
+ # chart.set_legend( :position => 'none' )
788
+ # The properties that can be set are:
789
+ #
790
+ # ====:position
791
+ # Set the position of the chart legend.
792
+ #
793
+ # chart.set_legend( :position => 'bottom' )
794
+ # The default legend position is right. The available positions are:
795
+ #
796
+ # none
797
+ # top
798
+ # bottom
799
+ # left
800
+ # right
801
+ # overlay_left
802
+ # overlay_right
803
+ # ====:delete_series
804
+ # This allows you to remove 1 or more series from the the legend
805
+ # (the series will still display on the chart). This property takes
806
+ # an array ref as an argument and the series are zero indexed:
807
+ #
808
+ # # Delete/hide series index 0 and 2 from the legend.
809
+ # chart.set_legend( :delete_series => [0, 2] )
810
+ #
811
+ def set_legend(params)
812
+ @legend_position = params[:position] || 'right'
813
+ @legend_delete_series = params[:delete_series]
814
+ end
815
+
816
+ #
817
+ # Set the properties of the chart plotarea.
818
+ #
819
+ # The set_plotarea() method is used to set properties of the plot area
820
+ # of a chart.
821
+ #
822
+ # This method isn't implemented yet and is only available in
823
+ # writeexcel gem. However, it can be simulated using the
824
+ # set_style() method.
825
+ #
826
+ def set_plotarea(params)
827
+
828
+ # TODO. Need to refactor for XLSX format.
829
+ return
830
+
831
+ return if params.empty?
832
+
833
+ area = @plotarea
834
+
835
+ # Set the plotarea visibility.
836
+ if params[:visible]
837
+ area[:_visible] = params[:visible]
838
+ return unless area[:_visible]
839
+ end
840
+
841
+ # TODO. could move this out of if statement.
842
+ area[:_bg_color_index] = 0x08
843
+
844
+ # Set the chart background colour.
845
+ if params[:color]
846
+ index, rgb = get_color_indices(params[:color])
847
+ if index
848
+ area[:_fg_color_index] = index
849
+ area[:_fg_color_rgb] = rgb
850
+ area[:_bg_color_index] = 0x08
851
+ area[:_bg_color_rgb] = 0x000000
852
+ end
853
+
854
+ end
855
+
856
+ # Set the border line colour.
857
+ if params[:line_color]
858
+ index, rgb = get_color_indices(params[:line_color])
859
+ if index
860
+ area[:_line_color_index] = index
861
+ area[:_line_color_rgb] = rgb
862
+ end
863
+ end
864
+
865
+ # Set the border line pattern.
866
+ if params[:line_pattern]
867
+ pattern = get_line_pattern(params[:line_pattern])
868
+ area[:_line_pattern] = pattern
869
+ end
870
+
871
+ # Set the border line weight.
872
+ if params[:line_weight]
873
+ weight = get_line_weight(params[:line_weight])
874
+ area[:_line_weight] = weight
875
+ end
876
+ end
877
+
878
+ #
879
+ # Set the properties of the chart chartarea.
880
+ #
881
+ # The set_chartarea() method is used to set the properties of the chart
882
+ # area.
883
+ #
884
+ # This method isn't implemented yet and is only available in
885
+ # writeexcel gem. However, it can be simulated using the
886
+ # set_style() method.
887
+ #
888
+ def set_chartarea(params)
889
+ # TODO. Need to refactor for XLSX format.
890
+ return
891
+
892
+ return if params.empty?
893
+
894
+ area = @chartarea
895
+
896
+ # Embedded automatic line weight has a different default value.
897
+ area[:_line_weight] = 0xFFFF if @embedded
898
+
899
+ # Set the chart background colour.
900
+ if params[:color]
901
+ index, rgb = get_color_indices(params[:color])
902
+ if index
903
+ area[:_fg_color_index] = index
904
+ area[:_fg_color_rgb] = rgb
905
+ area[:_bg_color_index] = 0x08
906
+ area[:_bg_color_rgb] = 0x000000
907
+ area[:_area_pattern] = 1
908
+ area[:_area_options] = 0x0000 if @embedded
909
+ area[:_visible] = 1
910
+ end
911
+ end
912
+
913
+ # Set the border line colour.
914
+ if params[:line_color]
915
+ index, rgb = get_color_indices(params[:line_color])
916
+ if index
917
+ area[:_line_color_index] = index
918
+ area[:_line_color_rgb] = rgb
919
+ area[:_line_pattern] = 0x00
920
+ area[:_line_options] = 0x0000
921
+ area[:_visible] = 1
922
+ end
923
+ end
924
+
925
+ # Set the border line pattern.
926
+ if params[:line_pattern]
927
+ pattern = get_line_pattern(params[:line_pattern])
928
+ area[:_line_pattern] = pattern
929
+ area[:_line_options] = 0x0000
930
+ area[:_line_color_index] = 0x4F unless params[:line_color]
931
+ area[:_visible] = 1
932
+ end
933
+
934
+ # Set the border line weight.
935
+ if params[:line_weight]
936
+ weight = get_line_weight(params[:line_weight])
937
+ area[:_line_weight] = weight
938
+ area[:_line_options] = 0x0000
939
+ area[:_line_pattern] = 0x00 unless params[:line_pattern]
940
+ area[:_line_color_index] = 0x4F unless params[:line_color]
941
+ area[:_visible] = 1
942
+ end
943
+ end
944
+
945
+ #
946
+ # Set on of the 42 built-in Excel chart styles. The default style is 2.
947
+ #
948
+ # The set_style() method is used to set the style of the chart to one
949
+ # of the 42 built-in styles available on the 'Design' tab in Excel:
950
+ #
951
+ # chart.set_style( 4 )
952
+ #
953
+ def set_style(style_id = 2)
954
+ style_id = 2 if style_id < 0 || style_id > 42
955
+ @style_id = style_id
956
+ end
957
+
958
+ #
959
+ # Setup the default configuration data for an embedded chart.
960
+ #
961
+ def set_embedded_config_data
962
+ @embedded = 1
963
+
964
+ # TODO. We may be able to remove this after refactoring.
965
+
966
+ @chartarea = {
967
+ :_visible => 1,
968
+ :_fg_color_index => 0x4E,
969
+ :_fg_color_rgb => 0xFFFFFF,
970
+ :_bg_color_index => 0x4D,
971
+ :_bg_color_rgb => 0x000000,
972
+ :_area_pattern => 0x0001,
973
+ :_area_options => 0x0001,
974
+ :_line_pattern => 0x0000,
975
+ :_line_weight => 0x0000,
976
+ :_line_color_index => 0x4D,
977
+ :_line_color_rgb => 0x000000,
978
+ :_line_options => 0x0009
979
+ }
980
+
981
+ end
982
+
983
+ private
984
+
985
+ #
986
+ # Convert user defined axis values into private hash values.
987
+ #
988
+ def convert_axis_args(params) # :nodoc:
989
+ name, name_formula = process_names(params[:name], params[:name_formula])
990
+
991
+ data_id = get_data_id(name_formula, params[:data])
992
+
993
+ axis = {
994
+ :_name => name,
995
+ :_formula => name_formula,
996
+ :_data_id => data_id,
997
+ :_reverse => params[:reverse],
998
+ :_min => params[:min],
999
+ :_max => params[:max],
1000
+ :_minor_unit => params[:minor_unit],
1001
+ :_major_unit => params[:major_unit],
1002
+ :_minor_unit_type => params[:minor_unit_type],
1003
+ :_major_unit_type => params[:major_unit_type],
1004
+ :_log_base => params[:log_base],
1005
+ :_crossing => params[:crossing],
1006
+ :_position => params[:position],
1007
+ :_label_position => params[:label_position]
1008
+ }
1009
+
1010
+ # Only use the first letter of bottom, top, left or right.
1011
+ axis[:_position] = axis[:_position].downcase[0, 1] if axis[:_position]
1012
+
1013
+ axis
1014
+ end
1015
+
1016
+ #
1017
+ # Convert and aref of row col values to a range formula.
1018
+ #
1019
+ def aref_to_formula(data) # :nodoc:
1020
+ # If it isn't an array ref it is probably a formula already.
1021
+ return data unless data.kind_of?(Array)
1022
+ xl_range_formula(*data)
1023
+ end
1024
+
1025
+ #
1026
+ # Switch name and name_formula parameters if required.
1027
+ #
1028
+ def process_names(name = nil, name_formula = nil) # :nodoc:
1029
+ # Name looks like a formula, use it to set name_formula.
1030
+ if name && name =~ /^=[^!]+!\$/
1031
+ name_formula = name
1032
+ name = ''
1033
+ end
1034
+
1035
+ [name, name_formula]
1036
+ end
1037
+
1038
+ #
1039
+ # Find the overall type of the data associated with a series.
1040
+ #
1041
+ # TODO. Need to handle date type.
1042
+ #
1043
+ def get_data_type(data) # :nodoc:
1044
+ # Check for no data in the series.
1045
+ return 'none' unless data
1046
+ return 'none' if data.empty?
1047
+
1048
+ # If the token isn't a number assume it is a string.
1049
+ data.each do |token|
1050
+ next unless token
1051
+ return 'str' unless token.kind_of?(Numeric)
1052
+ end
1053
+
1054
+ # The series data was all numeric.
1055
+ 'num'
1056
+ end
1057
+
1058
+ #
1059
+ # Assign an id to a each unique series formula or title/axis formula. Repeated
1060
+ # formulas such as for categories get the same id. If the series or title
1061
+ # has user specified data associated with it then that is also stored. This
1062
+ # data is used to populate cached Excel data when creating a chart.
1063
+ # If there is no user defined data then it will be populated by the parent
1064
+ # workbook in Workbook::_add_chart_data
1065
+ #
1066
+ def get_data_id(formula, data) # :nodoc:
1067
+ # Ignore series without a range formula.
1068
+ return unless formula
1069
+
1070
+ # Strip the leading '=' from the formula.
1071
+ formula = formula.sub(/^=/, '')
1072
+
1073
+ # Store the data id in a hash keyed by the formula and store the data
1074
+ # in a separate array with the same id.
1075
+ if !@formula_ids.has_key?(formula)
1076
+ # Haven't seen this formula before.
1077
+ id = @formula_data.size
1078
+
1079
+ @formula_data << data
1080
+ @formula_ids[formula] = id
1081
+ else
1082
+ # Formula already seen. Return existing id.
1083
+ id = @formula_ids[formula]
1084
+
1085
+ # Store user defined data if it isn't already there.
1086
+ @formula_data[id] = data unless @formula_data[id]
1087
+ end
1088
+
1089
+ id
1090
+ end
1091
+
1092
+
1093
+ #
1094
+ # Convert the user specified colour index or string to a rgb colour.
1095
+ #
1096
+ def get_color(color) # :nodoc:
1097
+ # Convert a HTML style #RRGGBB color.
1098
+ if color and color =~ /^#[0-9a-fA-F]{6}$/
1099
+ color = color.sub(/^#/, '')
1100
+ return color.upperca
1101
+ end
1102
+
1103
+ index = Format.get_color(color)
1104
+
1105
+ # Set undefined colors to black.
1106
+ unless index
1107
+ index = 0x08
1108
+ raise "Unknown color '#{color}' used in chart formatting."
1109
+ end
1110
+
1111
+ get_palette_color(index)
1112
+ end
1113
+
1114
+ #
1115
+ # Convert from an Excel internal colour index to a XML style #RRGGBB index
1116
+ # based on the default or user defined values in the Workbook palette.
1117
+ # Note: This version doesn't add an alpha channel.
1118
+ #
1119
+ def get_palette_color(index) # :nodoc:
1120
+ palette = @palette
1121
+
1122
+ # Adjust the colour index.
1123
+ index -= 8
1124
+
1125
+ # Palette is passed in from the Workbook class.
1126
+ rgb = palette[index]
1127
+
1128
+ sprintf("%02X%02X%02X", *rgb)
1129
+ end
1130
+
1131
+ #
1132
+ # Get the Excel chart index for line pattern that corresponds to the user
1133
+ # defined value.
1134
+ #
1135
+ def get_line_pattern(value) # :nodoc:
1136
+ value = value.downcase
1137
+ default = 0
1138
+
1139
+ patterns = {
1140
+ 0 => 5,
1141
+ 1 => 0,
1142
+ 2 => 1,
1143
+ 3 => 2,
1144
+ 4 => 3,
1145
+ 5 => 4,
1146
+ 6 => 7,
1147
+ 7 => 6,
1148
+ 8 => 8,
1149
+ 'solid' => 0,
1150
+ 'dash' => 1,
1151
+ 'dot' => 2,
1152
+ 'dash-dot' => 3,
1153
+ 'dash-dot-dot' => 4,
1154
+ 'none' => 5,
1155
+ 'dark-gray' => 6,
1156
+ 'medium-gray' => 7,
1157
+ 'light-gray' => 8
1158
+ }
1159
+
1160
+ if patterns.has_key(:value)
1161
+ pattern = patterns[:value]
1162
+ else
1163
+ pattern = default
1164
+ end
1165
+
1166
+ pattern
1167
+ end
1168
+
1169
+ #
1170
+ # Get the Excel chart index for line weight that corresponds to the user
1171
+ # defined value.
1172
+ #
1173
+ def get_line_weight(value) # :nodoc:
1174
+ value = value.downcase
1175
+ default = 0
1176
+
1177
+ weights = {
1178
+ 1 => -1,
1179
+ 2 => 0,
1180
+ 3 => 1,
1181
+ 4 => 2,
1182
+ 'hairline' => -1,
1183
+ 'narrow' => 0,
1184
+ 'medium' => 1,
1185
+ 'wide' => 2
1186
+ }
1187
+
1188
+ if weights[:value]
1189
+ weight = weights[:value]
1190
+ else
1191
+ weight = default
1192
+ end
1193
+
1194
+ weight
1195
+ end
1196
+
1197
+ #
1198
+ # Convert user defined line properties to the structure required internally.
1199
+ #
1200
+ def get_line_properties(line) # :nodoc:
1201
+ return { :_defined => 0 } unless line
1202
+
1203
+ dash_types = {
1204
+ :solid => 'solid',
1205
+ :round_dot => 'sysDot',
1206
+ :square_dot => 'sysDash',
1207
+ :dash => 'dash',
1208
+ :dash_dot => 'dashDot',
1209
+ :long_dash => 'lgDash',
1210
+ :long_dash_dot => 'lgDashDot',
1211
+ :long_dash_dot_dot => 'lgDashDotDot',
1212
+ :dot => 'dot',
1213
+ :system_dash_dot => 'sysDashDot',
1214
+ :system_dash_dot_dot => 'sysDashDotDot'
1215
+ }
1216
+
1217
+ # Check the dash type.
1218
+ dash_type = line[:dash_type]
1219
+
1220
+ if dash_type
1221
+ if dash_types[dash_type]
1222
+ line[dash_type] = dash_types[dash_type]
1223
+ else
1224
+ raise "Unknown dash type '#{dash_type}'\n"
1225
+ end
1226
+ end
1227
+
1228
+ line[:_defined] = 1
1229
+
1230
+ line
1231
+ end
1232
+
1233
+ #
1234
+ # Convert user defined fill properties to the structure required internally.
1235
+ #
1236
+ def get_fill_properties(fill) # :nodoc:
1237
+ return { :_defined => 0 } unless fill
1238
+
1239
+ fill[:_defined] = 1
1240
+
1241
+ fill
1242
+ end
1243
+
1244
+ #
1245
+ # Convert user defined marker properties to the structure required internally.
1246
+ #
1247
+ def get_marker_properties(marker) # :nodoc:
1248
+ return unless marker
1249
+
1250
+ types = {
1251
+ :automatic => 'automatic',
1252
+ :none => 'none',
1253
+ :square => 'square',
1254
+ :diamond => 'diamond',
1255
+ :triangle => 'triangle',
1256
+ :x => 'x',
1257
+ :star => 'start',
1258
+ :dot => 'dot',
1259
+ :short_dash => 'dot',
1260
+ :dash => 'dash',
1261
+ :long_dash => 'dash',
1262
+ :circle => 'circle',
1263
+ :plus => 'plus',
1264
+ :picture => 'picture'
1265
+ }
1266
+
1267
+ # Check for valid types.
1268
+ marker_type = marker[type]
1269
+
1270
+ if marker_type
1271
+ marker[automatic] = 1 if marker_type == 'automatic'
1272
+
1273
+ if types[marker_type]
1274
+ marker[type] = types[marker_type]
1275
+ else
1276
+ raise "Unknown marker type '#{marker_type}'\n"
1277
+ end
1278
+ end
1279
+
1280
+ # Set the line properties for the marker..
1281
+ line = get_line_properties(marker[line])
1282
+
1283
+ # Allow 'border' as a synonym for 'line'.
1284
+ line = get_line_properties(marker[border]) if marker[border]
1285
+
1286
+ # Set the fill properties for the marker.
1287
+ fill = get_fill_properties(marker[fill])
1288
+
1289
+ marker[:_line] = line
1290
+ marker[:_fill] = fill
1291
+
1292
+ marker
1293
+ end
1294
+
1295
+ #
1296
+ # Convert user defined trendline properties to the structure required internally.
1297
+ #
1298
+ def get_trendline_properties(trendline) # :nodoc:
1299
+ return unless trendline
1300
+
1301
+ types = {
1302
+ :exponential => 'exp',
1303
+ :linear => 'linear',
1304
+ :log => 'log',
1305
+ :moving_average => 'movingAvg',
1306
+ :polynomial => 'poly',
1307
+ :power => 'power'
1308
+ }
1309
+
1310
+ # Check the trendline type.
1311
+ trend_type = trendline[type]
1312
+
1313
+ if types[trend_type]
1314
+ trendline[type] = types[trend_type]
1315
+ else
1316
+ raise "Unknown trendline type '#{trend_type}'\n"
1317
+ end
1318
+
1319
+ # Set the line properties for the trendline..
1320
+ line = get_line_properties(trendline[line])
1321
+
1322
+ # Allow 'border' as a synonym for 'line'.
1323
+ line = get_line_properties(trendline[border]) if trendline[border]
1324
+
1325
+ # Set the fill properties for the trendline.
1326
+ fill = get_fill_properties(trendline[fill])
1327
+
1328
+ trendline[:_line] = line
1329
+ trendline[:_fill] = fill
1330
+
1331
+ return trendline
1332
+ end
1333
+
1334
+ #
1335
+ # Convert user defined labels properties to the structure required internally.
1336
+ #
1337
+ def get_labels_properties(labels) # :nodoc:
1338
+ return nil unless labels
1339
+
1340
+ return labels
1341
+ end
1342
+
1343
+ #
1344
+ # Add a unique id for an axis.
1345
+ #
1346
+ def add_axis_id # :nodoc:
1347
+ chart_id = 1 + @id
1348
+ axis_count = 1 + @axis_ids.size
1349
+
1350
+ axis_id = sprintf('5%03d%04d', chart_id, axis_count)
1351
+
1352
+ @axis_ids << axis_id
1353
+
1354
+ axis_id
1355
+ end
1356
+
1357
+ #
1358
+ # Setup the default properties for a chart.
1359
+ #
1360
+ def set_default_properties # :nodoc:
1361
+ @chartarea = {
1362
+ :_visible => 0,
1363
+ :_fg_color_index => 0x4E,
1364
+ :_fg_color_rgb => 0xFFFFFF,
1365
+ :_bg_color_index => 0x4D,
1366
+ :_bg_color_rgb => 0x000000,
1367
+ :_area_pattern => 0x0000,
1368
+ :_area_options => 0x0000,
1369
+ :_line_pattern => 0x0005,
1370
+ :_line_weight => 0xFFFF,
1371
+ :_line_color_index => 0x4D,
1372
+ :_line_color_rgb => 0x000000,
1373
+ :_line_options => 0x0008
1374
+ }
1375
+
1376
+ @plotarea = {
1377
+ :_visible => 1,
1378
+ :_fg_color_index => 0x16,
1379
+ :_fg_color_rgb => 0xC0C0C0,
1380
+ :_bg_color_index => 0x4F,
1381
+ :_bg_color_rgb => 0x000000,
1382
+ :_area_pattern => 0x0001,
1383
+ :_area_options => 0x0000,
1384
+ :_line_pattern => 0x0000,
1385
+ :_line_weight => 0x0000,
1386
+ :_line_color_index => 0x17,
1387
+ :_line_color_rgb => 0x808080,
1388
+ :_line_options => 0x0000
1389
+ }
1390
+ end
1391
+
1392
+ #
1393
+ # Write the <c:chartSpace> element.
1394
+ #
1395
+ def write_chart_space # :nodoc:
1396
+ schema = 'http://schemas.openxmlformats.org/'
1397
+ xmlns_c = schema + 'drawingml/2006/chart'
1398
+ xmlns_a = schema + 'drawingml/2006/main'
1399
+ xmlns_r = schema + 'officeDocument/2006/relationships'
1400
+
1401
+ attributes = [
1402
+ 'xmlns:c', xmlns_c,
1403
+ 'xmlns:a', xmlns_a,
1404
+ 'xmlns:r', xmlns_r
1405
+ ]
1406
+
1407
+ @writer.start_tag('c:chartSpace', attributes)
1408
+ end
1409
+
1410
+ #
1411
+ # Write the <c:lang> element.
1412
+ #
1413
+ def write_lang # :nodoc:
1414
+ val = 'en-US'
1415
+
1416
+ attributes = ['val', val]
1417
+
1418
+ @writer.empty_tag('c:lang', attributes)
1419
+ end
1420
+
1421
+ #
1422
+ # Write the <c:style> element.
1423
+ #
1424
+ def write_style # :nodoc:
1425
+ style_id = @style_id
1426
+
1427
+ # Don't write an element for the default style, 2.
1428
+ return if style_id == 2
1429
+
1430
+ attributes = ['val', style_id]
1431
+
1432
+ @writer.empty_tag('c:style', attributes)
1433
+ end
1434
+
1435
+ #
1436
+ # Write the <c:chart> element.
1437
+ #
1438
+ def write_chart # :nodoc:
1439
+ @writer.start_tag('c:chart')
1440
+
1441
+ # Write the chart title elements.
1442
+ if title = @title_formula
1443
+ write_title_formula(title, @title_data_id)
1444
+ elsif title = @title_name
1445
+ write_title_rich(title)
1446
+ end
1447
+
1448
+ # Write the c:plotArea element.
1449
+ write_plot_area
1450
+
1451
+ # Write the c:legend element.
1452
+ write_legend
1453
+
1454
+ # Write the c:plotVisOnly element.
1455
+ write_plot_vis_only
1456
+
1457
+ @writer.end_tag('c:chart')
1458
+ end
1459
+
1460
+ #
1461
+ # Write the <c:plotArea> element.
1462
+ #
1463
+ def write_plot_area # :nodoc:
1464
+ @writer.start_tag('c:plotArea')
1465
+
1466
+ # Write the c:layout element.
1467
+ write_layout
1468
+
1469
+ # Write the subclass chart type element.
1470
+ write_chart_type
1471
+
1472
+ # Write the c:catAx element.
1473
+ write_cat_axis
1474
+
1475
+ # Write the c:catAx element.
1476
+ write_val_axis
1477
+
1478
+ @writer.end_tag('c:plotArea')
1479
+ end
1480
+
1481
+ #
1482
+ # Write the <c:layout> element.
1483
+ #
1484
+ def write_layout # :nodoc:
1485
+ @writer.empty_tag('c:layout')
1486
+ end
1487
+
1488
+ #
1489
+ # Write the chart type element. This method should be overridden by the
1490
+ # subclasses.
1491
+ #
1492
+ def write_chart_type # :nodoc:
1493
+ end
1494
+
1495
+ #
1496
+ # Write the <c:grouping> element.
1497
+ #
1498
+ def write_grouping(val) # :nodoc:
1499
+ attributes = ['val', val]
1500
+ @writer.empty_tag('c:grouping', attributes)
1501
+ end
1502
+
1503
+ #
1504
+ # Write the series elements.
1505
+ #
1506
+ def write_series # :nodoc:
1507
+ # Write each series with subelements.
1508
+ index = 0
1509
+ @series.each do |series|
1510
+ write_ser(index, series)
1511
+ index += 1
1512
+ end
1513
+
1514
+ # Write the c:marker element.
1515
+ write_marker_value
1516
+
1517
+ # Generate the axis ids.
1518
+ add_axis_id
1519
+ add_axis_id
1520
+
1521
+ # Write the c:axId element.
1522
+ write_axis_id(@axis_ids[0])
1523
+ write_axis_id(@axis_ids[1])
1524
+ end
1525
+
1526
+ #
1527
+ # Write the <c:ser> element.
1528
+ #
1529
+ def write_ser(index, series) # :nodoc:
1530
+ @writer.start_tag('c:ser')
1531
+
1532
+ # Write the c:idx element.
1533
+ write_idx(index)
1534
+
1535
+ # Write the c:order element.
1536
+ write_order(index)
1537
+
1538
+ # Write the series name.
1539
+ write_series_name(series)
1540
+
1541
+ # Write the c:spPr element.
1542
+ write_sp_pr(series)
1543
+
1544
+ # Write the c:marker element.
1545
+ write_marker(series[:_marker])
1546
+
1547
+ # Write the c:invertIfNegative element.
1548
+ write_c_invert_if_negative(series[:_invert_if_neg])
1549
+
1550
+ # Write the c:dLbls element.
1551
+ write_d_lbls(series[:labels])
1552
+
1553
+ # Write the c:trendline element.
1554
+ write_trendline(series[:trendline])
1555
+
1556
+ # Write the c:cat element.
1557
+ write_cat(series)
1558
+
1559
+ # Write the c:val element.
1560
+ write_val(series)
1561
+
1562
+ @writer.end_tag('c:ser')
1563
+ end
1564
+
1565
+ #
1566
+ # Write the <c:idx> element.
1567
+ #
1568
+ def write_idx(val) # :nodoc:
1569
+ attributes = ['val', val]
1570
+
1571
+ @writer.empty_tag('c:idx', attributes)
1572
+ end
1573
+
1574
+ #
1575
+ # Write the <c:order> element.
1576
+ #
1577
+ def write_order(val) # :nodoc:
1578
+ attributes = ['val', val]
1579
+
1580
+ @writer.empty_tag('c:order', attributes)
1581
+ end
1582
+
1583
+ #
1584
+ # Write the series name.
1585
+ #
1586
+ def write_series_name(series) # :nodoc:
1587
+ if name = series[:_name_formula]
1588
+ write_tx_formula(name, series[:_name_id])
1589
+ elsif name = series[:_name]
1590
+ write_tx_value(name)
1591
+ end
1592
+ end
1593
+
1594
+ #
1595
+ # Write the <c:cat> element.
1596
+ #
1597
+ def write_cat(series) # :nodoc:
1598
+
1599
+ formula = series[:_categories]
1600
+ data_id = series[:_cat_data_id]
1601
+
1602
+ data = @formula_data[data_id] if data_id
1603
+
1604
+ # Ignore <c:cat> elements for charts without category values.
1605
+ return unless formula
1606
+
1607
+ @has_category = 1
1608
+
1609
+ @writer.start_tag('c:cat')
1610
+
1611
+ # Check the type of cached data.
1612
+ type = get_data_type(data)
1613
+
1614
+ if type == 'str'
1615
+ @has_category = 0
1616
+
1617
+ # Write the c:numRef element.
1618
+ write_str_ref(formula, data, type)
1619
+ else
1620
+ # Write the c:numRef element.
1621
+ write_num_ref(formula, data, type)
1622
+ end
1623
+
1624
+ @writer.end_tag('c:cat')
1625
+ end
1626
+
1627
+ #
1628
+ # Write the <c:val> element.
1629
+ #
1630
+ def write_val(series) # :nodoc:
1631
+ formula = series[:_values]
1632
+ data_id = series[:_val_data_id]
1633
+ data = @formula_data[data_id]
1634
+
1635
+ @writer.start_tag('c:val')
1636
+
1637
+ # Check the type of cached data.
1638
+ type = get_data_type(data)
1639
+
1640
+ if type == 'str'
1641
+ # Write the c:numRef element.
1642
+ write_str_ref(formula, data, type)
1643
+ else
1644
+ # Write the c:numRef element.
1645
+ write_num_ref(formula, data, type)
1646
+ end
1647
+
1648
+ @writer.end_tag('c:val')
1649
+ end
1650
+
1651
+ #
1652
+ # Write the <c:numRef> element.
1653
+ #
1654
+ def write_num_ref(formula, data, type) # :nodoc:
1655
+ @writer.start_tag('c:numRef')
1656
+
1657
+ # Write the c:f element.
1658
+ write_series_formula(formula)
1659
+
1660
+ if type == 'num'
1661
+ # Write the c:numCache element.
1662
+ write_num_cache(data)
1663
+ elsif type == 'str'
1664
+ # Write the c:strCache element.
1665
+ write_str_cache(data)
1666
+ end
1667
+
1668
+ @writer.end_tag('c:numRef')
1669
+ end
1670
+
1671
+ #
1672
+ # Write the <c:strRef> element.
1673
+ #
1674
+ def write_str_ref(formula, data, type) # :nodoc:
1675
+ @writer.start_tag('c:strRef')
1676
+
1677
+ # Write the c:f element.
1678
+ write_series_formula(formula)
1679
+
1680
+ if type == 'num'
1681
+ # Write the c:numCache element.
1682
+ write_num_cache(data)
1683
+ elsif type == 'str'
1684
+ # Write the c:strCache element.
1685
+ write_str_cache(data)
1686
+ end
1687
+
1688
+ @writer.end_tag('c:strRef')
1689
+ end
1690
+
1691
+ #
1692
+ # Write the <c:f> element.
1693
+ #
1694
+ def write_series_formula(formula) # :nodoc:
1695
+ # Strip the leading '=' from the formula.
1696
+ formula = formula.sub(/^=/, '')
1697
+
1698
+ @writer.data_element('c:f', formula)
1699
+ end
1700
+
1701
+ #
1702
+ # Write the <c:axId> element.
1703
+ #
1704
+ def write_axis_id(val) # :nodoc:
1705
+ attributes = ['val', val]
1706
+
1707
+ @writer.empty_tag('c:axId', attributes)
1708
+ end
1709
+
1710
+ #
1711
+ # Write the <c:catAx> element. Usually the X axis.
1712
+ #
1713
+ def write_cat_axis(position = nil) # :nodoc:
1714
+ position = @cat_axis_position
1715
+ horiz = @horiz_cat_axis
1716
+ x_axis = @x_axis
1717
+ y_axis = @y_axis
1718
+
1719
+ # Overwrite the default axis position with a user supplied value.
1720
+ position = x_axis[:_position] || position
1721
+
1722
+ @writer.start_tag('c:catAx')
1723
+
1724
+ write_axis_id(@axis_ids[0])
1725
+
1726
+ # Write the c:scaling element.
1727
+ write_scaling(x_axis[:_reverse])
1728
+
1729
+ # Write the c:axPos element.
1730
+ write_axis_pos(position, y_axis[:_reverse])
1731
+
1732
+ # Write the axis title elements.
1733
+ if title = @x_axis[:_formula]
1734
+ write_title_formula(title, @x_axis[:_data_id], horiz)
1735
+ elsif title = @x_axis[:_name]
1736
+ write_title_rich(title, horiz)
1737
+ end
1738
+
1739
+ # Write the c:numFmt element.
1740
+ write_num_fmt
1741
+
1742
+ # Write the c:tickLblPos element.
1743
+ write_tick_label_pos(x_axis[:_label_position])
1744
+
1745
+ # Write the c:crossAx element.
1746
+ write_cross_axis(@axis_ids[1])
1747
+
1748
+ # Note, the category crossing comes from the value axis.
1749
+ if y_axis[:_crossing].nil? || y_axis[:_crossing] == 'max'
1750
+ # Write the c:crosses element.
1751
+ write_crosses(y_axis[:_crossing])
1752
+ else
1753
+ # Write the c:crossesAt element.
1754
+ write_c_crosses(y_axis[:_crossing])
1755
+ end
1756
+
1757
+ # Write the c:auto element.
1758
+ write_auto(1)
1759
+
1760
+ # Write the c:labelAlign element.
1761
+ write_label_align('ctr')
1762
+
1763
+ # Write the c:labelOffset element.
1764
+ write_label_offset(100)
1765
+
1766
+ @writer.end_tag('c:catAx')
1767
+ end
1768
+
1769
+ #
1770
+ # Write the <c:valAx> element. Usually the Y axis.
1771
+ #
1772
+ # TODO. Maybe should have a _write_cat_val_axis method as well for scatter.
1773
+ #
1774
+ def write_val_axis(position = nil, hide_major_gridlines = nil) # :nodoc:
1775
+ position ||= @val_axis_position
1776
+ horiz = @horiz_val_axis
1777
+ x_axis = @x_axis
1778
+ y_axis = @y_axis
1779
+
1780
+ # Overwrite the default axis position with a user supplied value.
1781
+ position = y_axis[:_position] || position
1782
+
1783
+ @writer.start_tag('c:valAx')
1784
+
1785
+ write_axis_id(@axis_ids[1])
1786
+
1787
+ # Write the c:scaling element.
1788
+ write_scaling(y_axis[:_reverse], y_axis[:_min], y_axis[:_max], y_axis[:_log_base])
1789
+
1790
+ # Write the c:axPos element.
1791
+ write_axis_pos(position, x_axis[:_reverse])
1792
+
1793
+ # Write the c:majorGridlines element.
1794
+ write_major_gridlines unless hide_major_gridlines
1795
+
1796
+ # Write the axis title elements.
1797
+ if title = @y_axis[:_formula]
1798
+ write_title_formula(title, @y_axis[:_data_id], horiz)
1799
+ elsif title = @y_axis[:_name]
1800
+ write_title_rich(title, horiz)
1801
+ end
1802
+
1803
+ # Write the c:numberFormat element.
1804
+ write_number_format
1805
+
1806
+ # Write the c:tickLblPos element.
1807
+ write_tick_label_pos(y_axis[:_label_position])
1808
+
1809
+ # Write the c:crossAx element.
1810
+ write_cross_axis(@axis_ids[0])
1811
+
1812
+ # Note, the category crossing comes from the value axis.
1813
+ if x_axis[:crossing].nil? || x_axis[:_crossing] == 'max'
1814
+ # Write the c:crosses element.
1815
+ write_crosses(x_axis[:_crossing])
1816
+ else
1817
+ # Write the c:crossesAt element.
1818
+ write_c_crosses_at(x_axis[:_crossing])
1819
+ end
1820
+
1821
+ # Write the c:crossBetween element.
1822
+ write_cross_between
1823
+
1824
+ # Write the c:majorUnit element.
1825
+ write_c_major_unit(y_axis[:_major_unit])
1826
+
1827
+ # Write the c:minorUnit element.
1828
+ write_c_minor_unit(y_axis[:_minor_unit])
1829
+
1830
+ @writer.end_tag('c:valAx')
1831
+ end
1832
+
1833
+ #
1834
+ # Write the <c:valAx> element. This is for the second valAx in scatter plots.
1835
+ #
1836
+ # Usually the X axis.
1837
+ #
1838
+ def write_cat_val_axis(position, hide_major_gridlines) # :nodoc:
1839
+ position ||= @val_axis_position
1840
+ horiz = @horiz_val_axis
1841
+ x_axis = @x_axis
1842
+ y_axis = @y_axis
1843
+
1844
+ # Overwrite the default axis position with a user supplied value.
1845
+ position = x_axis[:_position] || position
1846
+
1847
+ @writer.start_tag('c:valAx')
1848
+
1849
+ write_axis_id(@axis_ids[0])
1850
+
1851
+ # Write the c:scaling element.
1852
+ write_scaling(x_axis[:_reverse], x_axis[:_min], x_axis[:_max], x_axis[:_log_base])
1853
+
1854
+ # Write the c:axPos element.
1855
+ write_axis_pos(position, y_axis[:_reverse])
1856
+
1857
+ # Write the c:majorGridlines element.
1858
+ write_major_gridlines unless hide_major_gridlines
1859
+
1860
+ # Write the axis title elements.
1861
+ if title = @x_axis[:_formula]
1862
+ write_title_formula(title, @y_axis[:_data_id], horiz)
1863
+ elsif title = @x_axis[:_name]
1864
+ write_title_rich(title, horiz)
1865
+ end
1866
+
1867
+ # Write the c:numberFormat element.
1868
+ write_number_format
1869
+
1870
+ # Write the c:tickLblPos element.
1871
+ write_tick_label_pos(x_axis[:_label_position])
1872
+
1873
+ # Write the c:crossAx element.
1874
+ write_cross_axis(@axis_ids[1])
1875
+
1876
+ # Note, the category crossing comes from the value axis.
1877
+ if y_axis[:_clossing].nil? || y_axis[:_crossing] == 'max'
1878
+ # Write the c:crosses element.
1879
+ write_crosses(y_axis[:_crossing])
1880
+ else
1881
+ # Write the c:crossesAt element.
1882
+ write_c_crosses_at(y_axis[:_crossing])
1883
+ end
1884
+
1885
+ # Write the c:crossBetween element.
1886
+ write_cross_between
1887
+
1888
+ # Write the c:majorunit element.
1889
+ write_c_major_unit(y_axis[:_major_unit])
1890
+
1891
+ # Write the c:minorUnit element.
1892
+ write_c_minor_unit(y_axis[:_minor_unit])
1893
+
1894
+ @writer.end_tag('c:valAx')
1895
+ end
1896
+
1897
+ #
1898
+ # Write the <c:dateAx> element. Usually the X axis.
1899
+ #
1900
+ def write_date_axis(position = nil) # :nodoc:
1901
+ position = @cat_axis_position
1902
+ x_axis = @x_axis
1903
+ y_axis = @y_axis
1904
+
1905
+ @writer.start_tag('c:dateAx')
1906
+
1907
+ write_axis_id(@axis_ids[0])
1908
+
1909
+ # Write the c:scaling element.
1910
+ write_scaling(x_axis[:reverse], x_axis[:_min], x_axis[:_max], x_axis[:_log_base])
1911
+
1912
+ # Write the c:axPos element.
1913
+ write_axis_pos(position, y_axis[:reverse])
1914
+
1915
+ # Write the axis title elements.
1916
+ if title = x_axis[:_formula]
1917
+ write_title_formula(title, x_axis[:_data_id])
1918
+ elsif title = x_axis[:_name]
1919
+ write_title_rich(title)
1920
+ end
1921
+
1922
+ # Write the c:numFmt element.
1923
+ write_num_fmt('dd/mm/yyyy')
1924
+
1925
+ # Write the c:tickLblPos element.
1926
+ write_tick_label_pos(x_axis[:_label_position])
1927
+
1928
+ # Write the c:crossAx element.
1929
+ write_cross_axis(@axis_ids[1])
1930
+
1931
+ # Note, the category crossing comes from the value axis.
1932
+ if y_axis[:_crossing].nil? || y_axis[:_crossing] == 'max'
1933
+ # Write the c:crossing element.
1934
+ write_crosses(y_axis[:_crossing])
1935
+ else
1936
+ # Write the c:crossesAt element.
1937
+ write_c_crosses_at(y_axis[:_crossing])
1938
+ end
1939
+
1940
+ # Write the c:auto element.
1941
+ write_auto(1)
1942
+
1943
+ # Write the c:labelOffset element.
1944
+ write_label_offset(100)
1945
+
1946
+ # Write the c:majorUnit element.
1947
+ write_c_major_unit(x_axis[:_major_unit])
1948
+
1949
+ # Write the c:majorTimeUnit element.
1950
+ if !x_axis[:_major_unit].nil?
1951
+ write_c_major_time_unit(x_axis[:_major_unit_type])
1952
+ end
1953
+
1954
+ # Write the c:minorUnit element.
1955
+ write_c_minor_unit(x_axis[:_minor_unit])
1956
+
1957
+ # Write the c:minorTimeUnit element.
1958
+ if !x_axis[:_minor_unit].nil?
1959
+ write_c_minor_time_unit(x_axis[:_minor_unit_type])
1960
+ end
1961
+
1962
+ @writer.end_tag('c:dateAx')
1963
+ end
1964
+
1965
+ #
1966
+ # Write the <c:scaling> element.
1967
+ #
1968
+ def write_scaling(reverse, min = nil, max = nil, log_base = nil) # :nodoc:
1969
+ @writer.start_tag('c:scaling')
1970
+
1971
+ # Write the c:logBase element.
1972
+ write_c_log_base(log_base)
1973
+
1974
+ # Write the c:orientation element.
1975
+ write_orientation(reverse)
1976
+
1977
+ # Write the c:max element.
1978
+ write_c_max(max)
1979
+
1980
+ # Write the c:min element.
1981
+ write_c_min(min)
1982
+
1983
+ @writer.end_tag('c:scaling')
1984
+ end
1985
+
1986
+ #
1987
+ # Write the <c:orientation> element.
1988
+ #
1989
+ def write_orientation(reverse = nil) # :nodoc:
1990
+ val = reverse ? 'maxMin' : 'minMax'
1991
+
1992
+ attributes = ['val', val]
1993
+
1994
+ @writer.empty_tag('c:orientation', attributes)
1995
+ end
1996
+
1997
+ #
1998
+ # Write the <c:logBase> element.
1999
+ #
2000
+ def write_c_log_base(val) # :nodoc:
2001
+ return if val == 0 || val.nil?
2002
+
2003
+ attributes = ['val', val]
2004
+
2005
+ @writer.empty_tag('c:logBase', attributes)
2006
+ end
2007
+
2008
+ #
2009
+ # Write the <c:orientation> element.
2010
+ #
2011
+ def write_orientation(reverse = 'maxMin') # :nodoc:
2012
+ val = 'minMax'
2013
+
2014
+ attributes = ['val', val]
2015
+
2016
+ @writer.empty_tag('c:orientation', attributes)
2017
+ end
2018
+
2019
+ #
2020
+ # Write the <c:max> element.
2021
+ #
2022
+ def write_c_max(max = nil) # :nodoc:
2023
+ return if max.nil?
2024
+
2025
+ attributes = ['val', max]
2026
+
2027
+ @writer.empty_tag('c:max', attributes)
2028
+ end
2029
+
2030
+ #
2031
+ # Write the <c:min> element.
2032
+ #
2033
+ def write_c_min(min = nil) # :nodoc:
2034
+ return if min.nil?
2035
+
2036
+ attributes = ['val', min]
2037
+
2038
+ @writer.empty_tag('c:min', attributes)
2039
+ end
2040
+
2041
+ #
2042
+ # Write the <c:axPos> element.
2043
+ #
2044
+ def write_axis_pos(val, reverse = false) # :nodoc:
2045
+ if reverse
2046
+ val = 'r' if val == 'l'
2047
+ val = 't' if val == 'b'
2048
+ end
2049
+
2050
+ attributes = ['val', val]
2051
+
2052
+ @writer.empty_tag('c:axPos', attributes)
2053
+ end
2054
+
2055
+ #
2056
+ # Write the <c:numFmt> element.
2057
+ #
2058
+ def write_num_fmt(format_code = nil) # :nodoc:
2059
+ format_code ||= 'General'
2060
+ source_linked = 1
2061
+
2062
+ # These elements are only required for charts with categories.
2063
+ return unless @has_category
2064
+
2065
+ attributes = [
2066
+ 'formatCode', format_code,
2067
+ 'sourceLinked', source_linked
2068
+ ]
2069
+
2070
+ @writer.empty_tag('c:numFmt', attributes)
2071
+ end
2072
+
2073
+ #
2074
+ # Write the <c:tickLblPos> element.
2075
+ #
2076
+ def write_tick_label_pos(val) # :nodoc:
2077
+ val ||= 'nextTo'
2078
+ val = 'nextTo' if val == 'next_to'
2079
+
2080
+ attributes = ['val', val]
2081
+
2082
+ @writer.empty_tag('c:tickLblPos', attributes)
2083
+ end
2084
+
2085
+ #
2086
+ # Write the <c:crossAx> element.
2087
+ #
2088
+ def write_cross_axis(val = 'autoZero') # :nodoc:
2089
+ attributes = ['val', val]
2090
+
2091
+ @writer.empty_tag('c:crossAx', attributes)
2092
+ end
2093
+
2094
+ #
2095
+ # Write the <c:crosses> element.
2096
+ #
2097
+ def write_crosses(val) # :nodoc:
2098
+ val ||= 'autoZero'
2099
+
2100
+ attributes = ['val', val]
2101
+
2102
+ @writer.empty_tag('c:crosses', attributes)
2103
+ end
2104
+
2105
+ #
2106
+ # Write the <c:crossesAt> element.
2107
+ #
2108
+ def write_c_crosses_at(val) # :nodoc:
2109
+ attributes = ['val', val]
2110
+
2111
+ @writer.empty_tag('c:crossesAt', attributes)
2112
+ end
2113
+
2114
+ #
2115
+ # Write the <c:auto> element.
2116
+ #
2117
+ def write_auto(val) # :nodoc:
2118
+ attributes = ['val', val]
2119
+
2120
+ @writer.empty_tag('c:auto', attributes)
2121
+ end
2122
+
2123
+ #
2124
+ # Write the <c:labelAlign> element.
2125
+ #
2126
+ def write_label_align(val) # :nodoc:
2127
+ attributes = ['val', val]
2128
+
2129
+ @writer.empty_tag('c:lblAlgn', attributes)
2130
+ end
2131
+
2132
+ #
2133
+ # Write the <c:labelOffset> element.
2134
+ #
2135
+ def write_label_offset(val) # :nodoc:
2136
+ attributes = ['val', val]
2137
+
2138
+ @writer.empty_tag('c:lblOffset', attributes)
2139
+ end
2140
+
2141
+ #
2142
+ # Write the <c:majorGridlines> element.
2143
+ #
2144
+ def write_major_gridlines # :nodoc:
2145
+ @writer.empty_tag('c:majorGridlines')
2146
+ end
2147
+
2148
+ #
2149
+ # Write the <c:numberFormat> element.
2150
+ #
2151
+ # TODO. Merge/replace with _write_num_fmt.
2152
+ #
2153
+ def write_number_format # :nodoc:
2154
+ format_code = 'General'
2155
+ source_linked = 1
2156
+
2157
+ attributes = [
2158
+ 'formatCode', format_code,
2159
+ 'sourceLinked', source_linked
2160
+ ]
2161
+
2162
+ @writer.empty_tag('c:numFmt', attributes)
2163
+ end
2164
+
2165
+ #
2166
+ # Write the <c:crossBetween> element.
2167
+ #
2168
+ def write_cross_between # :nodoc:
2169
+ val = @cross_between || 'between'
2170
+
2171
+ attributes = ['val', val]
2172
+
2173
+ @writer.empty_tag('c:crossBetween', attributes)
2174
+ end
2175
+
2176
+ #
2177
+ # Write the <c:majorUnit> element.
2178
+ #
2179
+ def write_c_major_unit(val = nil) # :nodoc:
2180
+ return unless val
2181
+
2182
+ attributes = ['val', val]
2183
+
2184
+ @writer.empty_tag('c:majorUnit', attributes)
2185
+ end
2186
+
2187
+ #
2188
+ # Write the <c:minorUnit> element.
2189
+ #
2190
+ def write_c_minor_unit(val = nil) # :nodoc:
2191
+ return unless val
2192
+
2193
+ attributes = ['val', val]
2194
+
2195
+ @writer.empty_tag('c:minorUnit', attributes)
2196
+ end
2197
+
2198
+ #
2199
+ # Write the <c:majorTimeUnit> element.
2200
+ #
2201
+ def write_c_major_time_unit(val = 'days') # :nodoc:
2202
+ attributes = ['val', val]
2203
+
2204
+ @writer.empty_tag('c:majorTimeUnit', attributes)
2205
+ end
2206
+
2207
+ #
2208
+ # Write the <c:minorTimeUnit> element.
2209
+ #
2210
+ def write_c_minor_time_unit(val = 'days') # :nodoc:
2211
+ attributes = ['val', val]
2212
+
2213
+ @writer.empty_tag('c:minorTimeUnit', attributes)
2214
+ end
2215
+
2216
+ #
2217
+ # Write the <c:legend> element.
2218
+ #
2219
+ def write_legend # :nodoc:
2220
+ position = @legend_position
2221
+ overlay = false
2222
+
2223
+ if @legend_delete_series && @legend_delete_series.kind_of?(Array)
2224
+ @delete_series = @legend_delete_series
2225
+ end
2226
+
2227
+ if position =~ /^overlay_/
2228
+ position.sub!(/^overlay_/, '')
2229
+ overlay = true if position
2230
+ end
2231
+
2232
+ allowed = {
2233
+ 'right' => 'r',
2234
+ 'left' => 'l',
2235
+ 'top' => 't',
2236
+ 'bottom' => 'b'
2237
+ }
2238
+
2239
+ return if position == 'none'
2240
+ return unless allowed.has_key?(position)
2241
+
2242
+ position = allowed[position]
2243
+
2244
+ @writer.start_tag('c:legend')
2245
+
2246
+ # Write the c:legendPos element.
2247
+ write_legend_pos(position)
2248
+
2249
+ # Remove series labels from the legend.
2250
+ @delete_series.each do |index|
2251
+ # Write the c:legendEntry element.
2252
+ write_legend_entry(index)
2253
+ end if @delete_series
2254
+
2255
+ # Write the c:layout element.
2256
+ write_layout
2257
+
2258
+ # Write the c:overlay element.
2259
+ write_overlay if overlay
2260
+
2261
+ @writer.end_tag('c:legend')
2262
+ end
2263
+
2264
+ #
2265
+ # Write the <c:legendPos> element.
2266
+ #
2267
+ def write_legend_pos(val) # :nodoc:
2268
+ attributes = ['val', val]
2269
+
2270
+ @writer.empty_tag('c:legendPos', attributes)
2271
+ end
2272
+
2273
+ #
2274
+ # Write the <c:legendEntry> element.
2275
+ #
2276
+ def write_legend_entry(index) # :nodoc:
2277
+ @writer.start_tag('c:legendEntry')
2278
+
2279
+ # Write the c:idx element.
2280
+ write_idx(index)
2281
+
2282
+ # Write the c:delete element.
2283
+ write_delete(1)
2284
+
2285
+ @writer.end_tag('c:legendEntry')
2286
+ end
2287
+
2288
+ #
2289
+ # Write the <c:overlay> element.
2290
+ #
2291
+ def write_overlay # :nodoc:
2292
+ val = 1
2293
+
2294
+ attributes = ['val', val]
2295
+
2296
+ @writer.empty_tag('c:overlay', attributes)
2297
+ end
2298
+
2299
+ #
2300
+ # Write the <c:plotVisOnly> element.
2301
+ #
2302
+ def write_plot_vis_only # :nodoc:
2303
+ val = 1
2304
+
2305
+ attributes = ['val', val]
2306
+
2307
+ @writer.empty_tag('c:plotVisOnly', attributes)
2308
+ end
2309
+
2310
+ #
2311
+ # Write the <c:printSettings> element.
2312
+ #
2313
+ def write_print_settings # :nodoc:
2314
+ @writer.start_tag('c:printSettings')
2315
+
2316
+ # Write the c:headerFooter element.
2317
+ write_header_footer
2318
+
2319
+ # Write the c:pageMargins element.
2320
+ write_page_margins
2321
+
2322
+ # Write the c:pageSetup element.
2323
+ write_page_setup
2324
+
2325
+ @writer.end_tag('c:printSettings')
2326
+ end
2327
+
2328
+ #
2329
+ # Write the <c:headerFooter> element.
2330
+ #
2331
+ def write_header_footer # :nodoc:
2332
+ @writer.empty_tag('c:headerFooter')
2333
+ end
2334
+
2335
+ #
2336
+ # Write the <c:pageMargins> element.
2337
+ #
2338
+ def write_page_margins # :nodoc:
2339
+ b = 0.75
2340
+ l = 0.7
2341
+ r = 0.7
2342
+ t = 0.75
2343
+ header = 0.3
2344
+ footer = 0.3
2345
+
2346
+ attributes = [
2347
+ 'b', b,
2348
+ 'l', l,
2349
+ 'r', r,
2350
+ 't', t,
2351
+ 'header', header,
2352
+ 'footer', footer
2353
+ ]
2354
+
2355
+ @writer.empty_tag('c:pageMargins', attributes)
2356
+ end
2357
+
2358
+ #
2359
+ # Write the <c:pageSetup> element.
2360
+ #
2361
+ def write_page_setup # :nodoc:
2362
+ @writer.empty_tag('c:pageSetup')
2363
+ end
2364
+
2365
+ #
2366
+ # Write the <c:title> element for a rich string.
2367
+ #
2368
+ def write_title_rich(title, horiz = nil) # :nodoc:
2369
+ @writer.start_tag('c:title')
2370
+
2371
+ # Write the c:tx element.
2372
+ write_tx_rich(title, horiz)
2373
+
2374
+ # Write the c:layout element.
2375
+ write_layout
2376
+
2377
+ @writer.end_tag('c:title')
2378
+ end
2379
+
2380
+ #
2381
+ # Write the <c:title> element for a rich string.
2382
+ #
2383
+ def write_title_formula(title, data_id, horiz) # :nodoc:
2384
+ @writer.start_tag('c:title')
2385
+
2386
+ # Write the c:tx element.
2387
+ write_tx_formula(title, data_id)
2388
+
2389
+ # Write the c:layout element.
2390
+ write_layout
2391
+
2392
+ # Write the c:txPr element.
2393
+ write_tx_pr(horiz)
2394
+
2395
+ @writer.end_tag('c:title')
2396
+ end
2397
+
2398
+ #
2399
+ # Write the <c:tx> element.
2400
+ #
2401
+ def write_tx_rich(title, horiz) # :nodoc:
2402
+ @writer.start_tag('c:tx')
2403
+
2404
+ # Write the c:rich element.
2405
+ write_rich(title, horiz)
2406
+
2407
+ @writer.end_tag('c:tx')
2408
+ end
2409
+
2410
+ #
2411
+ # Write the <c:tx> element with a simple value such as for series names.
2412
+ #
2413
+ def write_tx_value(title) # :nodoc:
2414
+ @writer.start_tag('c:tx')
2415
+
2416
+ # Write the c:v element.
2417
+ write_v(title)
2418
+
2419
+ @writer.end_tag('c:tx')
2420
+ end
2421
+
2422
+ #
2423
+ # Write the <c:tx> element.
2424
+ #
2425
+ def write_tx_formula(title, data_id) # :nodoc:
2426
+ data = @formula_data[data_id] if data_id
2427
+
2428
+ @writer.start_tag('c:tx')
2429
+
2430
+ # Write the c:strRef element.
2431
+ write_str_ref(title, data, 'str')
2432
+
2433
+ @writer.end_tag('c:tx')
2434
+ end
2435
+
2436
+ #
2437
+ # Write the <c:rich> element.
2438
+ #
2439
+ def write_rich(title, horiz) # :nodoc:
2440
+ @writer.start_tag('c:rich')
2441
+
2442
+ # Write the a:bodyPr element.
2443
+ write_a_body_pr(horiz)
2444
+
2445
+ # Write the a:lstStyle element.
2446
+ write_a_lst_style
2447
+
2448
+ # Write the a:p element.
2449
+ write_a_p_rich(title)
2450
+
2451
+ @writer.end_tag('c:rich')
2452
+ end
2453
+
2454
+ #
2455
+ # Write the <a:bodyPr> element.
2456
+ #
2457
+ def write_a_body_pr(horiz) # :nodoc:
2458
+ rot = -5400000
2459
+ vert = 'horz'
2460
+
2461
+ attributes = [
2462
+ 'rot', rot,
2463
+ 'vert', vert
2464
+ ]
2465
+
2466
+ attributes = [] if !horiz || horiz == 0
2467
+
2468
+ @writer.empty_tag('a:bodyPr', attributes)
2469
+ end
2470
+
2471
+ #
2472
+ # Write the <a:lstStyle> element.
2473
+ #
2474
+ def write_a_lst_style # :nodoc:
2475
+ @writer.empty_tag('a:lstStyle')
2476
+ end
2477
+
2478
+ #
2479
+ # Write the <a:p> element for rich string titles.
2480
+ #
2481
+ def write_a_p_rich(title) # :nodoc:
2482
+ @writer.start_tag('a:p')
2483
+
2484
+ # Write the a:pPr element.
2485
+ write_a_p_pr_rich
2486
+
2487
+ # Write the a:r element.
2488
+ write_a_r(title)
2489
+
2490
+ @writer.end_tag('a:p')
2491
+ end
2492
+
2493
+ #
2494
+ # Write the <a:p> element for formula titles.
2495
+ #
2496
+ def write_a_p_formula(title) # :nodoc:
2497
+ @writer.start_tag('a:p')
2498
+
2499
+ # Write the a:pPr element.
2500
+ write_a_p_pr_formula
2501
+
2502
+ # Write the a:endParaRPr element.
2503
+ write_a_end_para_rpr
2504
+
2505
+ @writer.end_tag('a:p')
2506
+ end
2507
+
2508
+ #
2509
+ # Write the <a:pPr> element for rich string titles.
2510
+ #
2511
+ def write_a_p_pr_rich # :nodoc:
2512
+ @writer.start_tag('a:pPr')
2513
+
2514
+ # Write the a:defRPr element.
2515
+ write_a_def_rpr
2516
+
2517
+ @writer.end_tag('a:pPr')
2518
+ end
2519
+
2520
+ #
2521
+ # Write the <a:pPr> element for formula titles.
2522
+ #
2523
+ def write_a_p_pr_formula # :nodoc:
2524
+ @writer.start_tag('a:pPr')
2525
+
2526
+ # Write the a:defRPr element.
2527
+ write_a_def_rpr
2528
+
2529
+ @writer.end_tag('a:pPr')
2530
+ end
2531
+
2532
+ #
2533
+ # Write the <a:defRPr> element.
2534
+ #
2535
+ def write_a_def_rpr # :nodoc:
2536
+ @writer.empty_tag('a:defRPr')
2537
+ end
2538
+
2539
+ #
2540
+ # Write the <a:endParaRPr> element.
2541
+ #
2542
+ def write_a_end_para_rpr # :nodoc:
2543
+ lang = 'en-US'
2544
+
2545
+ attributes = ['lang', lang]
2546
+
2547
+ @writer.empty_tag('a:endParaRPr', attributes)
2548
+ end
2549
+
2550
+ #
2551
+ # Write the <a:r> element.
2552
+ #
2553
+ def write_a_r(title) # :nodoc:
2554
+ @writer.start_tag('a:r')
2555
+
2556
+ # Write the a:rPr element.
2557
+ write_a_r_pr
2558
+
2559
+ # Write the a:t element.
2560
+ write_a_t(title)
2561
+
2562
+ @writer.end_tag('a:r')
2563
+ end
2564
+
2565
+ #
2566
+ # Write the <a:rPr> element.
2567
+ #
2568
+ def write_a_r_pr # :nodoc:
2569
+ lang = 'en-US'
2570
+
2571
+ attributes = ['lang', lang]
2572
+
2573
+ @writer.empty_tag('a:rPr', attributes)
2574
+ end
2575
+
2576
+ #
2577
+ # Write the <a:t> element.
2578
+ #
2579
+ def write_a_t(title) # :nodoc:
2580
+ @writer.data_element('a:t', title)
2581
+ end
2582
+
2583
+ #
2584
+ # Write the <c:txPr> element.
2585
+ #
2586
+ def write_tx_pr(horiz) # :nodoc:
2587
+ @writer.start_tag('c:txPr')
2588
+
2589
+ # Write the a:bodyPr element.
2590
+ write_a_body_pr(horiz)
2591
+
2592
+ # Write the a:lstStyle element.
2593
+ write_a_lst_style
2594
+
2595
+ # Write the a:p element.
2596
+ write_a_p_formula
2597
+
2598
+ @writer.end_tag('c:txPr')
2599
+ end
2600
+
2601
+ #
2602
+ # Write the <c:marker> element.
2603
+ #
2604
+ def write_marker(marker = nil) # :nodoc:
2605
+ marker ||= @default_marker
2606
+
2607
+ return if marker.nil? || marker == 0
2608
+ return if marker[:automatic] && marker[:automatic] != 0
2609
+
2610
+ @writer.start_tag('c:marker')
2611
+
2612
+ # Write the c:symbol element.
2613
+ write_symbol(marker[:type])
2614
+
2615
+ # Write the c:size element.
2616
+ size = marker[:size]
2617
+ write_marker_size(size) if !size.nil? && size != 0
2618
+
2619
+ # Write the c:spPr element.
2620
+ write_sp_pr(marker)
2621
+
2622
+ @writer.end_tag('c:marker')
2623
+ end
2624
+
2625
+ #
2626
+ # Write the <c:marker> element without a sub-element.
2627
+ #
2628
+ def write_marker_value # :nodoc:
2629
+ style = @default_marker
2630
+
2631
+ return unless style
2632
+
2633
+ attributes = ['val', 1]
2634
+
2635
+ @writer.empty_tag('c:marker', attributes)
2636
+ end
2637
+
2638
+ #
2639
+ # Write the <c:size> element.
2640
+ #
2641
+ def write_marker_size(val) # :nodoc:
2642
+ attributes = ['val', val]
2643
+
2644
+ @writer.empty_tag('c:size', attributes)
2645
+ end
2646
+
2647
+ #
2648
+ # Write the <c:symbol> element.
2649
+ #
2650
+ def write_symbol(val) # :nodoc:
2651
+ attributes = ['val', val]
2652
+
2653
+ @writer.empty_tag('c:symbol', attributes)
2654
+ end
2655
+
2656
+ #
2657
+ # Write the <c:spPr> element.
2658
+ #
2659
+ def write_sp_pr(series) # :nodoc:
2660
+ return if (!series.has_key?(:_line) || series[:_line][:_defined].nil? || series[:_line][:_defined]== 0) &&
2661
+ (!series.has_key?(:_fill) || series[:_fill][:_defined].nil? || series[:_fill][:_defined]== 0)
2662
+
2663
+ @writer.start_tag('c:spPr')
2664
+
2665
+ # Write the a:solidFill element for solid charts such as pie and bar.
2666
+ write_a_solid_fill(series[:_fill]) if series[:_fill] && series[:_fill][:_defined] != 0
2667
+
2668
+ # Write the a:ln element.
2669
+ write_a_ln(series[:_line]) if series[:_line] && series[:_line][:_defined]
2670
+
2671
+ @writer.end_tag('c:spPr')
2672
+ end
2673
+
2674
+ #
2675
+ # Write the <a:ln> element.
2676
+ #
2677
+ def write_a_ln(line) # :nodoc:
2678
+ attributes = []
2679
+
2680
+ # Add the line width as an attribute.
2681
+ if width = line[:width]
2682
+ # Round width to nearest 0.25, like Excel.
2683
+ width = ((width + 0.125) * 4).to_i / 4.0
2684
+
2685
+ # Convert to internal units.
2686
+ width = (0.5 + (12700 * width)).to_i
2687
+
2688
+ attributes = ['w', width]
2689
+ end
2690
+
2691
+ @writer.start_tag('a:ln', attributes)
2692
+
2693
+ # Write the line fill.
2694
+ if !line[:none].nil? && line[:none] != 0
2695
+ # Write the a:noFill element.
2696
+ write_a_no_fill
2697
+ else
2698
+ # Write the a:solidFill element.
2699
+ write_a_solid_fill(line)
2700
+ end
2701
+
2702
+ # Write the line/dash type.
2703
+ if type = line[:dash_type]
2704
+ # Write the a:prstDash element.
2705
+ write_a_prst_dash(type)
2706
+ end
2707
+
2708
+ @writer.end_tag('a:ln')
2709
+ end
2710
+
2711
+ #
2712
+ # Write the <a:noFill> element.
2713
+ #
2714
+ def write_a_no_fill # :nodoc:
2715
+ @writer.empty_tag('a:noFill')
2716
+ end
2717
+
2718
+ #
2719
+ # Write the <a:solidFill> element.
2720
+ #
2721
+ def write_a_solid_fill(line) # :nodoc:
2722
+ @writer.start_tag('a:solidFill')
2723
+
2724
+ if line[:color]
2725
+ color = get_color(line[:color])
2726
+
2727
+ # Write the a:srgbClr element.
2728
+ write_a_srgb_clr(color)
2729
+ end
2730
+
2731
+ @writer.end_tag('a:solidFill')
2732
+ end
2733
+
2734
+ #
2735
+ # Write the <a:srgbClr> element.
2736
+ #
2737
+ def write_a_srgb_clr(val) # :nodoc:
2738
+ attributes = ['val', val]
2739
+
2740
+ @writer.empty_tag('a:srgbClr', attributes)
2741
+ end
2742
+
2743
+ #
2744
+ # Write the <a:prstDash> element.
2745
+ #
2746
+ def write_a_prst_dash(val) # :nodoc:
2747
+ attributes = ['val', val]
2748
+
2749
+ @writer.empty_tag('a:prstDash', attributes)
2750
+ end
2751
+
2752
+ #
2753
+ # Write the <c:trendline> element.
2754
+ #
2755
+ def write_trendline(trendline) # :nodoc:
2756
+ return unless trendline
2757
+
2758
+ @writer.start_tag('c:trendline')
2759
+
2760
+ # Write the c:name element.
2761
+ write_name(trendline[name])
2762
+
2763
+ # Write the c:spPr element.
2764
+ write_sp_pr(trendline)
2765
+
2766
+ # Write the c:trendlineType element.
2767
+ write_trendline_type(trendline[type])
2768
+
2769
+ # Write the c:order element for polynomial trendlines.
2770
+ write_trendline_order(trendline[order]) if trendline[type] == 'poly'
2771
+
2772
+ # Write the c:period element for moving average trendlines.
2773
+ write_period(trendline[period]) if trendline[type] == 'movingAvg'
2774
+
2775
+
2776
+ # Write the c:forward element.
2777
+ write_forward(trendline[forward])
2778
+
2779
+ # Write the c:backward element.
2780
+ write_backward(trendline[backward])
2781
+
2782
+ @writer.end_tag('c:trendline')
2783
+ end
2784
+
2785
+ #
2786
+ # Write the <c:trendlineType> element.
2787
+ #
2788
+ def write_trendline_type(val) # :nodoc:
2789
+ attributes = ['val', val]
2790
+
2791
+ @writer.empty_tag('c:trendlineType', attributes)
2792
+ end
2793
+
2794
+ #
2795
+ # Write the <c:name> element.
2796
+ #
2797
+ def write_name(data) # :nodoc:
2798
+ return unless data
2799
+
2800
+ @writer.data_element('c:name', data)
2801
+ end
2802
+
2803
+ #
2804
+ # Write the <c:order> element.
2805
+ #
2806
+ def write_trendline_order(val = 2) # :nodoc:
2807
+ attributes = ['val', val]
2808
+
2809
+ @writer.empty_tag('c:order', attributes)
2810
+ end
2811
+
2812
+ #
2813
+ # Write the <c:period> element.
2814
+ #
2815
+ def write_period(val = 2) # :nodoc:
2816
+ attributes = ['val', val]
2817
+
2818
+ @writer.empty_tag('c:period', attributes)
2819
+ end
2820
+
2821
+ #
2822
+ # Write the <c:forward> element.
2823
+ #
2824
+ def write_forward(val) # :nodoc:
2825
+ return unless val
2826
+
2827
+ attributes = ['val', val]
2828
+
2829
+ @writer.empty_tag('c:forward', attributes)
2830
+ end
2831
+
2832
+ #
2833
+ # Write the <c:backward> element.
2834
+ #
2835
+ def write_backward(val) # :nodoc:
2836
+ return unless val
2837
+
2838
+ attributes = ['val', val]
2839
+
2840
+ @writer.empty_tag('c:backward', attributes)
2841
+ end
2842
+
2843
+ #
2844
+ # Write the <c:hiLowLines> element.
2845
+ #
2846
+ def write_hi_low_lines # :nodoc:
2847
+ @writer.empty_tag('c:hiLowLines')
2848
+ end
2849
+
2850
+ #
2851
+ # Write the <c:overlap> element.
2852
+ #
2853
+ def write_overlap # :nodoc:
2854
+ val = 100
2855
+
2856
+ attributes = ['val', val]
2857
+
2858
+ @writer.empty_tag('c:overlap', attributes)
2859
+ end
2860
+
2861
+ #
2862
+ # Write the <c:numCache> element.
2863
+ #
2864
+ def write_num_cache(data) # :nodoc:
2865
+ count = data.size
2866
+
2867
+ @writer.start_tag('c:numCache')
2868
+
2869
+ # Write the c:formatCode element.
2870
+ write_format_code('General')
2871
+
2872
+ # Write the c:ptCount element.
2873
+ write_pt_count(count)
2874
+
2875
+ (0 .. count - 1).each do |i|
2876
+
2877
+ # Write the c:pt element.
2878
+ write_pt(i, data[i])
2879
+ end
2880
+
2881
+ @writer.end_tag('c:numCache')
2882
+ end
2883
+
2884
+ #
2885
+ # Write the <c:strCache> element.
2886
+ #
2887
+ def write_str_cache(data) # :nodoc:
2888
+ count = data.size
2889
+
2890
+ @writer.start_tag('c:strCache')
2891
+
2892
+ # Write the c:ptCount element.
2893
+ write_pt_count(count)
2894
+
2895
+ (0 .. count - 1).each do |i|
2896
+
2897
+ # Write the c:pt element.
2898
+ write_pt(i, data[i])
2899
+ end
2900
+
2901
+ @writer.end_tag('c:strCache')
2902
+ end
2903
+
2904
+ #
2905
+ # Write the <c:formatCode> element.
2906
+ #
2907
+ def write_format_code(data) # :nodoc:
2908
+ @writer.data_element('c:formatCode', data)
2909
+ end
2910
+
2911
+ #
2912
+ # Write the <c:ptCount> element.
2913
+ #
2914
+ def write_pt_count(val) # :nodoc:
2915
+ attributes = ['val', val]
2916
+
2917
+ @writer.empty_tag('c:ptCount', attributes)
2918
+ end
2919
+
2920
+ #
2921
+ # Write the <c:pt> element.
2922
+ #
2923
+ def write_pt(idx, value) # :nodoc:
2924
+ return unless value
2925
+
2926
+ attributes = ['idx', idx]
2927
+
2928
+ @writer.start_tag('c:pt', attributes)
2929
+
2930
+ # Write the c:v element.
2931
+ write_v(value)
2932
+
2933
+ @writer.end_tag('c:pt')
2934
+ end
2935
+
2936
+ #
2937
+ # Write the <c:v> element.
2938
+ #
2939
+ def write_v(data) # :nodoc:
2940
+ @writer.data_element('c:v', data)
2941
+ end
2942
+
2943
+ #
2944
+ # Write the <c:protection> element.
2945
+ #
2946
+ def write_protection # :nodoc:
2947
+ return if @protection == 0
2948
+
2949
+ @writer.empty_tag('c:protection')
2950
+ end
2951
+
2952
+ #
2953
+ # Write the <c:dLbls> element.
2954
+ #
2955
+ def write_d_lbls(labels) # :nodoc:
2956
+ return unless labels
2957
+
2958
+ @writer.start_tag('c:dLbls')
2959
+
2960
+ # Write the c:showVal element.
2961
+ write_show_val if labels[value]
2962
+
2963
+ # Write the c:showCatName element.
2964
+ write_show_cat_name if labels[category]
2965
+
2966
+ # Write the c:showSerName element.
2967
+ write_show_ser_name if labels[series_name]
2968
+
2969
+ @writer.end_tag('c:dLbls')
2970
+ end
2971
+
2972
+ #
2973
+ # Write the <c:showVal> element.
2974
+ #
2975
+ def write_show_val # :nodoc:
2976
+ val = 1
2977
+
2978
+ attributes = ['val', val]
2979
+
2980
+ @writer.empty_tag('c:showVal', attributes)
2981
+ end
2982
+
2983
+ #
2984
+ # Write the <c:showCatName> element.
2985
+ #
2986
+ def write_show_cat_name # :nodoc:
2987
+ val = 1
2988
+
2989
+ attributes = ['val', val]
2990
+
2991
+ @writer.empty_tag('c:showCatName', attributes)
2992
+ end
2993
+
2994
+ #
2995
+ # Write the <c:showSerName> element.
2996
+ #
2997
+ def write_show_ser_name # :nodoc:
2998
+ val = 1
2999
+
3000
+ attributes = ['val', val]
3001
+
3002
+ @writer.empty_tag('c:showSerName', attributes)
3003
+ end
3004
+
3005
+ #
3006
+ # Write the <c:delete> element.
3007
+ #
3008
+ def write_delete(val) # :nodoc:
3009
+ attributes = ['val', val]
3010
+
3011
+ @writer.empty_tag('c:delete', attributes)
3012
+ end
3013
+
3014
+ #
3015
+ # Write the <c:invertIfNegative> element.
3016
+ #
3017
+ def write_c_invert_if_negative(invert = nil) # :nodoc:
3018
+ val = 1
3019
+
3020
+ return unless invert
3021
+
3022
+ attributes = ['val', val]
3023
+
3024
+ @writer.empty_tag('c:invertIfNegative', attributes)
3025
+ end
3026
+ end
3027
+ end