Class: SVG::Graph::C3js

Inherits:
Object
  • Object
show all
Defined in:
lib/SVG/Graph/C3js.rb

Overview

This class provides a lightweight generator for html code indluding c3js based graphs specified as javascript.

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ C3js

By default, the generated html code links the javascript and css dependencies to the d3 and c3 libraries in the <head> element. The latest versions of d3 and c3 available at the time of gem release are used through cdnjs. Custom versions of d3 and c3 can easily be used by specifying the corresponding keys in the optional Hash argument.

If the dependencies are http(s) urls a simple href / src link is inserted in the html header. If you want to create a fully offline capable html file, you can do this by downloading the (minified) versions of d3.js, c3.css, c3.js to disk and then point to the files instead of http links. This will then inline the complete script and css payload directly into the generated html page.

Examples:

create a simple graph

my_graph = SVG::Graph::C3js.new("my_funny_chart_var")

create a graph with custom version of C3 and D3

# use external dependencies
opts = {
  "d3_js"  => "https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js",
  "c3_css" => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.8/c3.min.css",
  "c3_js"  => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.8/c3.min.js"
}
# or inline dependencies into generated html
opts = {
  "inline_dependencies" => true,
  "d3_js"  => "/path/to/local/copy/of/d3.min.js",
  "c3_css" => "/path/to/local/copy/of/c3.min.css",
  "c3_js"  => "/path/to/local/copy/of/c3.min.js"
}
my_graph = SVG::Graph::C3js.new("my_funny_chart_var", opts)

Parameters:

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • "inline_dependencies" (String)

    if true will inline the script and css parts of d3 and c3 directly into html, otherwise they are referred as external dependencies. default: false

  • "d3_js" (String)

    url or path to local files. default: d3.js url via cdnjs

  • "c3_css" (String)

    url or path to local files. default: c3.css url via cdnjs

  • "c3_js" (String)

    url or path to local files. default: c3.js url via cdnjs



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/SVG/Graph/C3js.rb', line 48

def initialize(opts = {})
  default_opts = {
    "inline_dependencies" => false,
    "d3_js"  => "https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.min.js",
    "c3_css" => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.11/c3.min.css",
    "c3_js"  => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.11/c3.min.js"
  }
  @opts = default_opts.merge(opts)
  if @opts["inline_dependencies"]
    # we replace the values in the opts Hash by the referred file contents
    ["d3_js", "c3_css", "c3_js"].each do |key|
      if !File.file?(@opts[key])
        raise "opts[\"#{key}\"]: No such file - #{File.expand_path(@opts[key])}"
      end
      @opts[key] = File.read(@opts[key])
    end # ["d3_js", "c3_css", "c3_js"].each
  end # if @opts["inline_dependencies"]
  start_document()
end

Instance Method Details

#add_chart_spec(javascript, js_chart_variable_name = "") ⇒ Object

Adds a javascript/json C3js chart definition into the div tag

Examples:

# see http://c3js.org/examples.html
# since ruby 2.3 you can use string symbol keys:
chart_spec = {
  # bindto is mandatory
  "bindto": "#this_is_my_awesom_graph",
  "data": {
    "columns": [
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 50, 20, 10, 40, 15, 25]
    ]
}
# otherwise simply write plain javascript into a heredoc string:
# make sure to include the  var <chartname> = c3.generate() if using heredoc
chart_spec_string =<<-HEREDOC
var mychart1 = c3.generate({
  // bindto is mandatory
  "bindto": "#this_is_my_awesom_graph",
  "data": {
    "columns": [
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 50, 20, 10, 40, 15, 25]
    ]
});
HEREDOC
graph.add_chart_spec(chart_spec, "my_chart1")
# or
graph.add_chart_spec(chart_spec_string)

Parameters:

  • javascript (String, Hash)

    see example

  • js_chart_variable_name (String) (defaults to: "")

    only needed if the ‘javascript` parameter is a Hash. unique variable name representing the chart in javascript scope. Note this is a global javascript “var” so make sure to avoid name clashes with other javascript us might use on the same page.

Raises:



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/SVG/Graph/C3js.rb', line 104

def add_chart_spec(javascript, js_chart_variable_name = "")
  if javascript.kind_of?(Hash)
    if js_chart_variable_name.to_s.empty? || js_chart_variable_name.to_s.match(/\s/)
      raise "js_chart_variable_name ('#{js_chart_variable_name.to_s}') cannot be empty or contain spaces, " +
            "a valid javascript variable name is needed."
    end
    chart_spec = JSON(javascript)
    inline_script = "var #{js_chart_variable_name} = c3.generate(#{chart_spec});"
  elsif javascript.kind_of?(String)
    inline_script = javascript
    if !inline_script.match(/c3\.generate/)
      raise "var <chartname> = c3.generate({...}) statement is missing in javascript string"
    end
  else
    raise "Unsupported argument type: #{javascript.class}"
  end
  # (.+?)" means non-greedy match up to next double quote
  if m = inline_script.match(/"bindto":\s*"#(.+?)"/)
    @bindto = m[1]
  else
    raise "Missing chart specification is missing the mandatory \"bindto\" key/value pair."
  end
  add_div_element_for_graph()
  add_javascript() {inline_script}
end

#add_javascript(attrs = {}, &block) ⇒ REXML::Element

Appends a <script> element to the <div> element, this can be used to add additional animations but any script can also directly be part of the js_chart_specification in the #add_chart_spec method when you use a HEREDOC string as input.

Parameters:

  • attrs (Hash) (defaults to: {})

    attributes for the <script> element. The following attribute is added by default: type=“text/javascript”

Yield Returns:

  • (String)

    the actual javascript code to be added to the <script> element

Returns:

  • (REXML::Element)

    the Element which was just added



137
138
139
140
141
142
143
144
145
146
# File 'lib/SVG/Graph/C3js.rb', line 137

def add_javascript(attrs={}, &block)
  default_attrs = {"type" => "text/javascript"}
  attrs = default_attrs.merge(attrs)
  temp = REXML::Element.new("script")
  temp.add_attributes(attrs)
  @svg.add_element(temp)
  raise "Block argument is mandatory" unless block_given?
  script_content = block.call()
  cdata(script_content, temp)
end

#burnString

Returns the complete html file.

Returns:

  • (String)

    the complete html file



150
151
152
153
154
155
# File 'lib/SVG/Graph/C3js.rb', line 150

def burn
  f = REXML::Formatters::Pretty.new(0)
  out = ''
  f.write(@doc, out)
  out
end

#burn_svg_onlyString

Burns the graph but returns only the <div> node as String without the Doctype and XML / HTML Declaration. This allows easy integration into existing xml/html documents. The Javascript to create the C3js graph is inlined into the div tag.

You have to take care to refer the proper C3 and D3 dependencies in your html page.

Returns:

  • (String)

    the div element into which the graph will be rendered by C3.js



167
168
169
170
171
172
173
174
175
# File 'lib/SVG/Graph/C3js.rb', line 167

def burn_svg_only
  # initialize all instance variables by burning the graph
  burn
  f = REXML::Formatters::Pretty.new(0)
  f.compact = true
  out = ''
  f.write(@svg, out)
  return out
end