Skip to content

Commit

Permalink
Merge pull request #94 from Prakriti-nith/export_highchart
Browse files Browse the repository at this point in the history
Added export method to export highchart in different formats
  • Loading branch information
Shekharrajak authored Jul 14, 2018
2 parents 4b88756 + 2c4e273 commit 8d4f389
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 74 deletions.
4 changes: 4 additions & 0 deletions lib/daru/view/adapters/googlecharts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ def export_html_file(plot, path='./plot.html')
File.write(path, str)
end

def export(_plot, _export_type='png', _file_name='chart')
raise 'Not implemented yet'
end

def show_in_iruby(plot)
plot.show_in_iruby
end
Expand Down
15 changes: 15 additions & 0 deletions lib/daru/view/adapters/highcharts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,21 @@ def export_html_file(plot, path='./plot.html')
File.write(path, str)
end

# Exporting in web frameworks is completely offline. In IRuby notebook,
# offline-export supports only the exporting to png, jpeg and svg format.
# Export to PDF is not working (not even through the exporting button in
# highchart). So, online exporting is done in IRuby notebook. There is a
# problem in online exporting that if we run-all all the cells of IRuby
# notebook then only the last chart will be exported. Individually,
# running the cells works fine.
#
# @see #Daru::View::Plot.export
def export(plot, export_type='png', file_name='chart')
plot.export_iruby(export_type, file_name) if defined? IRuby
rescue NameError
plot.export(export_type, file_name)
end

def show_in_iruby(plot)
plot.show_in_iruby
end
Expand Down
95 changes: 95 additions & 0 deletions lib/daru/view/adapters/highcharts/display.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def self.init_script
end

class HighChart
# Holds a value only when to_html or to_html_iruby method is invoked
# @return [String] The ID of the DIV element that the HighChart should
# be rendered in
attr_accessor :div_id
# @example
#
# To display the html code of the chart, use `to_html`. To see the same
Expand All @@ -62,6 +66,7 @@ class HighChart
def to_html(placeholder=random_canvas_id)
chart_hash_must_be_present
script = load_dependencies('web_frameworks')
@div_id = placeholder
script << high_chart_css(placeholder)
# Helps to denote either of the three classes.
chart_class = extract_chart_class
Expand All @@ -88,6 +93,7 @@ def show_in_iruby(placeholder=random_canvas_id)
# `high_chart_iruby` which doesn't use `onload` in chart script.
def to_html_iruby(placeholder=random_canvas_id)
# TODO : placeholder pass, in plot#div
@div_id = placeholder
load_dependencies('iruby')
chart_hash_must_be_present
script = high_chart_css(placeholder)
Expand Down Expand Up @@ -160,6 +166,95 @@ def get_map_data_dependencies(dep_js)
end
end

# @see #Daru::View::Plot.export
def export(export_type='png', file_name='chart')
js = ''
js << to_html
js << extract_export_code(@div_id, export_type, file_name)
js
end

# Exports chart to different formats in IRuby notebook
#
# @param type [String] format to which chart has to be exported
# @param file_name [String] The name of the file after exporting the chart
# @return [void] loads the js code of chart along with the code to export
# in IRuby notebook
def export_iruby(export_type='png', file_name='chart')
js = ''
js << to_html_iruby
js << extract_export_code_iruby(@div_id, export_type, file_name)
IRuby.html js
end

# Returns the script to export the chart in different formats for
# web frameworks
#
# @param file_name [String] The name of the file after exporting the chart
# @param placeholder [String] The ID of the DIV element that
# the HighChart should be rendered in
# @param type [String] format to which chart has to be exported
# @return [String] the script to export the chart in web frameworks
def extract_export_code(
placeholder=random_canvas_id, export_type='png', file_name='chart'
)
js = ''
js << "\n <script>"
js << "\n (function() {"
js << "\n \tvar onload = window.onload;"
js << "\n \twindow.onload = function(){"
js << "\n \t\tif (typeof onload == 'function') onload();"
js << "\n \t\tvar chartDom = document.getElementById('#{placeholder}');"
js << "\n \t\tvar chart = Highcharts.charts[Highcharts.attr(chartDom,"
js << " 'data-highcharts-chart')]"
js << "\n \t\tchart.exportChartLocal({"
js << "\n \t\t\t" + append_chart_type(export_type)
js << "\n \t\t\tfilename: '#{file_name}'"
js << "\n \t\t});\n \t};\n })();"
js << "\n </script>"
js
end

# Returns the script to export the chart in different formats in
# IRuby notebook
#
# @param (see #extract_export_code)
# @return [String] the script to export the chart in IRuby notebook
def extract_export_code_iruby(
placeholder=random_canvas_id, export_type='png', file_name='chart'
)
js = ''
js << "\n <script>"
js << "\n (function() {"
js << "\n \tvar chartDom = document.getElementById('#{placeholder}');"
js << "\n \tvar chart = Highcharts.charts[Highcharts.attr(chartDom,"
js << " 'data-highcharts-chart')]"
js << "\n \tchart.exportChart({"
js << "\n \t\t" + append_chart_type(export_type)
js << "\n \t\tfilename: '#{file_name}'"
js << "\n \t});"
js << "\n })();"
js << "\n </script>"
js
end

# @param type [String] format to which chart has to be exported
# @return [String] code stating the type to which chart has to be exported
def append_chart_type(export_type='png')
case export_type
when 'pdf'
"type: 'application/pdf',"
when 'png'
"type: 'image/png',"
when 'jpg', 'jpeg'
"type: 'image/jpeg',"
when 'svg'
"type: 'image/svg+xml',"
else
raise TypeError, 'Invalid format'
end
end

# @return [String] the class of the chart
def extract_chart_class
# Provided by user and can take two values ('stock' or 'map').
Expand Down
3 changes: 3 additions & 0 deletions lib/daru/view/adapters/highcharts/iruby_notebook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def self.init_iruby(
# , 'modules/exporting.js' : for the exporting button
# data.js for getting data as csv or html table.
# 'highcharts-more.js' : for arearange and some other chart type
# 'modules/offline-exporting.js': for enabling offline exporting. Used in
# #chart.extract_export_code method (to enable chart.exportChartLocal)
# to export the chart using code.
# Note: Don't reorder the dependent_js elements. It must be loaded in
# the same sequence. Otherwise some of the JS overlap and doesn't work.
js = generate_init_code(dependent_js)
Expand Down
4 changes: 4 additions & 0 deletions lib/daru/view/adapters/nyaplot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ def export_html_file(plot, path)
plot.export_html path
end

def export(_plot, _export_type='png', _file_name='chart')
raise 'Not implemented yet'
end

def show_in_iruby(plot)
plot.show
end
Expand Down
3 changes: 2 additions & 1 deletion lib/daru/view/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
EXPORTING = 'modules/exporting.js'.freeze
HIGHCHARTS_3D = 'highcharts-3d.js'.freeze
DATA = 'modules/data.js'.freeze
OFFLINE_EXPORTING = 'modules/offline-exporting.js'.freeze

# HighCharts IRuby notebook dependencies
HIGHCHARTS_DEPENDENCIES_IRUBY = [HIGHSTOCK, MAP, EXPORTING, HIGHCHARTS_3D,
DATA].freeze

# HighCharts Web Frameworks dependencies
HIGHCHARTS_DEPENDENCIES_WEB = [HIGHSTOCK_CSS, MAP_CSS, EXPORTING,
HIGHCHARTS_3D, DATA].freeze
HIGHCHARTS_3D, DATA, OFFLINE_EXPORTING].freeze

# HighCharts CSS dependencies
HIGHCHARTS_DEPENDENCIES_CSS = ['highcharts.css'].freeze
Expand Down
12 changes: 12 additions & 0 deletions lib/daru/view/plot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ def export_html_file(path='./plot.html')
@adapter.export_html_file(@chart, path)
end

# @param type [String] format to which chart has to be exported
# @param file_name [String] The name of the file after exporting the chart
# @return [String, void] js code of chart along with the code to export it
# and loads the js code to export it in IRuby.
# @example Export a HighChart
# data = Daru::Vector.new([5 ,3, 4])
# hchart = Daru::View::Plot.new(data)
# hchart.export('png', 'daru')
def export(export_type='png', file_name='chart')
@adapter.export(@chart, export_type, file_name)
end

# load the corresponding JS files in IRuby notebook.
# This is done automatically when plotting library is set using
# Daru::View.plotting_library = :new_library
Expand Down
77 changes: 77 additions & 0 deletions spec/adapters/highcharts/display_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,83 @@
end
end

describe "#export" do
it "should generate the valid script to export the chart in different"\
" formats" do
js = @hc.chart.export('jpg','daru')
expect(js).to match(/\s+new\s+Highcharts.Chart/)
expect(js).to match(/var\s+options\s+=/)
expect(js).to match(/window.chart_/)
expect(js).to match(/\"chart\": \{ \"type\": \"bar\"/)
expect(js).to match(/\"data\": \[ \[ 5,2,3 \],\[ 3,2,4 \],\[ 4,3,4 \]/)
expect(js).to match(/script/)
expect(js).to match(/image\/jpeg/)
expect(js).to match(/daru/)
expect(js).to match(/chart.exportChartLocal/)
end
end

describe "#extract_export_code" do
it "should generate the valid script to export the chart in different"\
" formats in web frameworks" do
js = @hc.chart.extract_export_code(@placeholder)
expect(js).to match(/script/)
expect(js).to match(/var onload = window.onload/)
expect(js).to match(/window.onload = function()/)
expect(js).to match(/typeof onload == 'function'/)
expect(js).to match(
/var chartDom = document.getElementById\('placeholder'\)/
)
expect(js).to match(
/Highcharts.charts\[Highcharts.attr\(chartDom, 'data-highcharts-chart'\)/
)
expect(js).to match(/image\/png/)
expect(js).to match(/chart.exportChartLocal/)
end
end

describe "#extract_export_code_iruby" do
it "should generate the valid script to export the chart in different"\
" formats in IRuby notebook" do
js = @hc.chart.extract_export_code_iruby(@placeholder, 'png', 'daru')
expect(js).to match(/script/)
expect(js).to match(
/var chartDom = document.getElementById\('placeholder'\)/
)
expect(js).to match(
/Highcharts.charts\[Highcharts.attr\(chartDom, 'data-highcharts-chart'\)/
)
expect(js).to match(/image\/png/)
expect(js).to match(/filename: 'daru'/)
expect(js).to match(/chart.exportChart/)
end
end

describe "#append_chart_type" do
it "should return correct code stating the type to which chart has"\
" to be exported" do
expect(@hc.chart.append_chart_type).to eq("type: 'image/png',")
expect(@hc.chart.append_chart_type(
'pdf')
).to eq("type: 'application/pdf',")
expect(@hc.chart.append_chart_type(
'png')
).to eq("type: 'image/png',")
expect(@hc.chart.append_chart_type(
'jpg')
).to eq("type: 'image/jpeg',")
expect(@hc.chart.append_chart_type(
'jpeg')
).to eq("type: 'image/jpeg',")
expect(@hc.chart.append_chart_type(
'svg')
).to eq("type: 'image/svg+xml',")
expect{@hc.chart.append_chart_type(
'daru')
}.to raise_error(TypeError, 'Invalid format')
end
end

describe "#extract_chart_class" do
it "should return Map class when chart_class is set to map" do
@hc.options[:chart_class] = "map";
Expand Down
13 changes: 13 additions & 0 deletions spec/adapters/highcharts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -447,4 +447,17 @@
expect(html).to match(/series": \[\[ 1,15 \],\[ 2,30 \],\[ 4,40 \]\]/)
end
end

describe "#export" do
it "should generate the valid script to export the chart" do
js = @chart_bar.adapter.export(@chart_bar.chart, 'png')
expect(js).to match(/\s+new\s+Highcharts.Chart/)
expect(js).to match(/var\s+options\s+=/)
expect(js).to match(/window.chart_/)
expect(js).to match(/\"chart\": \{ \"type\": \"bar\"/)
expect(js).to match(/script/)
expect(js).to match(/image\/png/)
expect(js).to match(/chart.exportChartLocal/)
end
end
end
Loading

0 comments on commit 8d4f389

Please sign in to comment.