asciidoctor-chart 1.0.0.alpha.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Chart
5
+ module Converter
6
+ class Html5ChartjsConverter < Asciidoctor::Chart::Converter::Base
7
+ CSS_VALUE_UNIT_RX = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/.freeze
8
+ DEFAULT_COLORS = [{ r: 220, g: 220, b: 220 }, { r: 151, g: 187, b: 205 }].freeze
9
+
10
+ def convert_line_chart node
11
+ data, labels = prepare_data node
12
+ datasets = data.map do |set|
13
+ color = DEFAULT_COLORS[data.index(set) % 2]
14
+ color_rgba = "rgba(#{color[:r]},#{color[:g]},#{color[:b]},1.0)"
15
+ <<~JSON
16
+ {
17
+ borderColor: "#{color_rgba}",
18
+ backgroundColor: "#{color_rgba}",
19
+ fill: false,
20
+ tension: 0.1,
21
+ data: #{set.to_s}
22
+ }
23
+ JSON
24
+ end.join ','
25
+
26
+ chart_id = node.attr 'id'
27
+ inline_styles = []
28
+ if (chart_height = get_height node)
29
+ inline_styles.push("height: #{chart_height}")
30
+ end
31
+ if (chart_width = get_width node)
32
+ inline_styles.push("max-width: #{chart_width}")
33
+ end
34
+ maintain_aspect_ratio = chart_height.nil? && chart_width.nil?
35
+ title_element = node.title? ? %(\n <div class="title">#{node.captioned_title}</div>) : ''
36
+ <<~HTML
37
+ <div class="chartblock">
38
+ <div class="content chartjs-content" style="#{inline_styles.join('; ')}">
39
+ <canvas id="#{chart_id}"></canvas>
40
+ </div>#{title_element}
41
+ </div>
42
+ <script>
43
+ window.addEventListener('load', function(event) {
44
+ var data = {
45
+ labels: #{labels.to_s},
46
+ datasets: [#{datasets}]
47
+ }
48
+ var chart = new Chart(document.getElementById("#{chart_id}").getContext("2d"), {
49
+ type: 'line',
50
+ data: data,
51
+ options: {
52
+ interaction: {
53
+ mode: 'index'
54
+ },
55
+ responsive : true,
56
+ maintainAspectRatio: #{maintain_aspect_ratio},
57
+ plugins: {
58
+ legend: {
59
+ display: false
60
+ }
61
+ }
62
+ }
63
+ })
64
+ })
65
+ </script>
66
+ HTML
67
+ end
68
+
69
+ def prepare_data node
70
+ raw_data = node.attr 'data-raw', []
71
+ return [[], []] if raw_data.length <= 1 # question: should we warn?
72
+
73
+ labels = raw_data[0]
74
+ raw_data.shift
75
+ [raw_data, labels]
76
+ end
77
+
78
+ private
79
+
80
+ def get_height node
81
+ return unless (height = node.attr 'height')
82
+
83
+ to_css_size height
84
+ end
85
+
86
+ def get_width node
87
+ return unless (width = node.attr 'width')
88
+
89
+ to_css_size width
90
+ end
91
+
92
+ def to_css_size str
93
+ return str unless (parts = str.match(CSS_VALUE_UNIT_RX))
94
+
95
+ value, unit = parts.captures
96
+ unit = 'px' if unit == ''
97
+ "#{value}#{unit}"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Chart
5
+ module Converter
6
+ class Base
7
+ def handles? type
8
+ respond_to? %(convert_#{type}_chart)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -6,26 +6,75 @@ module Asciidoctor
6
6
  use_dsl
7
7
  # at_location :head
8
8
 
9
- C3JS_STYLESHEET = '<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/c3/0.3.0/c3.min.css">'
10
- D3JS_SCRIPT = '<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js" charset="utf-8"></script>'
11
- C3JS_SCRIPT = '<script src="http://cdnjs.cloudflare.com/ajax/libs/c3/0.3.0/c3.min.js"></script>'
12
-
13
- CHARTIST_STYLESHEET = '<link rel="stylesheet" href="http://cdn.jsdelivr.net/chartist.js/latest/chartist.min.css">'
14
- CHARTIST_SCRIPT = '<script src="http://cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>'
15
-
16
- CHARTJS_SCRIPT = '<script src="http://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>'
17
-
18
- def process _doc
19
- # TODO: Import only the required engines
20
- # TODO: Honor linkcss and copycss
21
- <<~EOS
22
- #{C3JS_STYLESHEET}
23
- #{D3JS_SCRIPT}
24
- #{C3JS_SCRIPT}
25
- #{CHARTIST_STYLESHEET}
26
- #{CHARTIST_SCRIPT}
27
- #{CHARTJS_SCRIPT})
28
- EOS
9
+ C3JS_DIR_ATTR = 'c3jsdir'
10
+ C3JS_DEFAULT_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/'
11
+
12
+ CHARTJS_DIR_ATTR = 'chartjsdir'
13
+ CHARTJS_DEFAULT_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/'
14
+
15
+ CHARTIST_DIR_ATTR = 'chartistdir'
16
+ CHARTIST_DEFAULT_PATH = 'https://cdn.jsdelivr.net/npm/chartist@0.11.x/dist/'
17
+
18
+ D3JS_DIR_ATTR = 'd3jsdir'
19
+ D3JS_DEFAULT_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/'
20
+
21
+ DEFAULT_STYLE = <<~HTML.chomp
22
+ <style>
23
+ .chartblock {
24
+ margin-bottom: 1.25em;
25
+ }
26
+ .chartblock > .title {
27
+ text-rendering: optimizeLegibility;
28
+ text-align: left;
29
+ font-size: 1rem;
30
+ font-style: italic;
31
+ line-height: 1.45;
32
+ color: #7a2518;
33
+ font-weight: 400;
34
+ }
35
+ .chartblock > .chartjs-content {
36
+ position: relative;
37
+ margin-bottom: 0.25em;
38
+ }
39
+ </style>
40
+ HTML
41
+
42
+ def process(doc)
43
+ engines = doc.x_chart[:engines]
44
+ (engines.map {|engine| send(engine, doc) }.to_a + [DEFAULT_STYLE]).join "\n"
45
+ end
46
+
47
+ private
48
+
49
+ def get_path(doc, attr_name, default_path, asset_to_include)
50
+ doc.normalize_web_path asset_to_include, (doc.attr attr_name, default_path), false
51
+ end
52
+
53
+ def create_script_directive(doc, attr_name, default_path, asset_to_include)
54
+ %(<script src="#{get_path doc, attr_name, default_path, asset_to_include}"></script>)
55
+ end
56
+
57
+ def create_link_css_directive(doc, attr_name, default_path, asset_to_include)
58
+ %(<link rel="stylesheet" href="#{get_path doc, attr_name, default_path, asset_to_include}">)
59
+ end
60
+
61
+ def chartjs(doc)
62
+ create_script_directive(doc, CHARTJS_DIR_ATTR, CHARTJS_DEFAULT_PATH, 'chart.min.js')
63
+ end
64
+
65
+ def chartist(doc)
66
+ result = []
67
+ result << create_link_css_directive(doc, CHARTIST_DIR_ATTR, CHARTIST_DEFAULT_PATH, 'chartist.min.css')
68
+ result << create_script_directive(doc, CHARTIST_DIR_ATTR, CHARTIST_DEFAULT_PATH, 'chartist.min.js')
69
+ result
70
+ end
71
+
72
+ def c3js(doc)
73
+ result = []
74
+ result << create_link_css_directive(doc, C3JS_DIR_ATTR, C3JS_DEFAULT_PATH, 'c3.min.css')
75
+ result << create_script_directive(doc, D3JS_DIR_ATTR, D3JS_DEFAULT_PATH, 'd3.min.js')
76
+ result << create_script_directive(doc, C3JS_DIR_ATTR, C3JS_DEFAULT_PATH, 'c3.min.js')
77
+ result
29
78
  end
30
79
  end
31
80
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Chart
5
+ module Html5ChartConverterExt
6
+ def convert_chart node
7
+ chart_engine = node.attr 'engine'
8
+ chart_type = node.attr 'type'
9
+ chart_converter = Asciidoctor::Chart::Registry.for chart_engine
10
+
11
+ if chart_converter
12
+ if chart_converter.handles? chart_type
13
+ chart_converter.send "convert_#{chart_type}_chart", node
14
+ else
15
+ logger.warn %(missing chart convert handler for type '#{chart_type}' in #{chart_converter})
16
+ nil
17
+ end
18
+ else
19
+ logger.warn %(missing chart convert for engine '#{chart_engine}')
20
+ nil
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Chart
5
+ class Preprocessor < Asciidoctor::Extensions::Preprocessor
6
+ def process document, reader
7
+ document.extend(ChartBlockTracker)
8
+
9
+ reader
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module Chart
5
+ module Registry
6
+ @registry = {}
7
+
8
+ def self.register converter, engine
9
+ @registry[engine] = converter
10
+ end
11
+
12
+ def self.for engine
13
+ @registry[engine]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Chart
5
- VERSION = '1.0.0.alpha.1'
5
+ VERSION = '1.0.0'
6
6
  end
7
7
  end
@@ -1,19 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'asciidoctor/extensions'
4
+ require 'tilt'
5
+ require_relative 'chart/html5_chart_converter_ext'
6
+ require_relative 'chart/registry'
7
+ require_relative 'chart/preprocessor'
4
8
  require_relative 'chart/block_macro_processor'
5
9
  require_relative 'chart/block_processor'
6
10
  require_relative 'chart/docinfo_processor'
7
- require_relative 'chart/backend'
11
+ require_relative 'chart/chart_block'
8
12
  require_relative 'chart/plain_ruby_csv'
9
13
  require_relative 'chart/plain_ruby_random'
10
- require_relative 'chart/c3js/chart_builder'
11
- require_relative 'chart/chartjs/chart_builder'
12
- require_relative 'chart/chartist/chart_builder'
14
+ require_relative 'chart/converter'
15
+ require_relative 'chart/converter/c3js'
16
+ require_relative 'chart/converter/chartist'
17
+ require_relative 'chart/converter/chartjs'
18
+
19
+ CHART_HTML_TEMPLATE = Tilt.new('chart.html.erb', format: :html5, pretty: true, disable_escape: true) do |_t|
20
+ <<-ERB
21
+ <%= Class.new.extend(Asciidoctor::Chart::Html5ChartConverterExt).convert_chart self %>
22
+ ERB
23
+ end
24
+
25
+ # providers
26
+ Asciidoctor::Chart::Registry.register Asciidoctor::Chart::Converter::Html5ChartjsConverter.new, 'chartjs'
27
+ Asciidoctor::Chart::Registry.register Asciidoctor::Chart::Converter::Html5ChartistConverter.new, 'chartist'
28
+ Asciidoctor::Chart::Registry.register Asciidoctor::Chart::Converter::Html5C3jsConverter.new, 'c3js'
29
+
30
+ def register_chart_converter converter
31
+ if (converter.instance_of? Asciidoctor::Converter::TemplateConverter) || (converter.respond_to? 'register')
32
+ # Template based converter
33
+ converter.register 'chart', CHART_HTML_TEMPLATE
34
+ else
35
+ converter.extend(Asciidoctor::Chart::Html5ChartConverterExt)
36
+ end
37
+ end
13
38
 
14
39
  Asciidoctor::Extensions.register do
15
40
  return unless document.basebackend? 'html'
16
41
 
42
+ converter = document.converter
43
+ if converter.instance_of? Asciidoctor::Converter::CompositeConverter
44
+ register_chart_converter(converter.converters[0])
45
+ else
46
+ register_chart_converter(converter)
47
+ end
48
+ preprocessor Asciidoctor::Chart::Preprocessor
17
49
  block_macro Asciidoctor::Chart::BlockMacroProcessor
18
50
  block Asciidoctor::Chart::BlockProcessor
19
51
  docinfo_processor Asciidoctor::Chart::DocinfoProcessor
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-chart
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillaume Grossetie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-15 00:00:00.000000000 Z
11
+ date: 2022-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tilt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,35 +66,42 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: 3.9.0
55
- description: A set of Asciidoctor extensions that add a chart block and block macro
56
- to AsciiDoc for including charts in your AsciiDoc document.
69
+ description: |-
70
+ A set of Asciidoctor extensions that add a chart block and block macro to AsciiDoc
71
+ for including charts in your AsciiDoc document.
57
72
  email: ggrossetie@gmail.com
58
73
  executables: []
59
74
  extensions: []
60
75
  extra_rdoc_files: []
61
76
  files:
77
+ - CHANGELOG.adoc
62
78
  - LICENSE.adoc
63
79
  - README.adoc
64
80
  - asciidoctor-chart.gemspec
65
81
  - lib/asciidoctor-chart.rb
66
82
  - lib/asciidoctor/chart.rb
67
- - lib/asciidoctor/chart/backend.rb
68
83
  - lib/asciidoctor/chart/block_macro_processor.rb
69
84
  - lib/asciidoctor/chart/block_processor.rb
70
- - lib/asciidoctor/chart/c3js/chart_builder.rb
71
- - lib/asciidoctor/chart/chartist/chart_builder.rb
72
- - lib/asciidoctor/chart/chartjs/chart_builder.rb
85
+ - lib/asciidoctor/chart/chart_block.rb
86
+ - lib/asciidoctor/chart/converter.rb
87
+ - lib/asciidoctor/chart/converter/c3js.rb
88
+ - lib/asciidoctor/chart/converter/chartist.rb
89
+ - lib/asciidoctor/chart/converter/chartjs.rb
73
90
  - lib/asciidoctor/chart/docinfo_processor.rb
91
+ - lib/asciidoctor/chart/html5_chart_converter_ext.rb
74
92
  - lib/asciidoctor/chart/plain_ruby_csv.rb
75
93
  - lib/asciidoctor/chart/plain_ruby_random.rb
94
+ - lib/asciidoctor/chart/preprocessor.rb
95
+ - lib/asciidoctor/chart/registry.rb
76
96
  - lib/asciidoctor/chart/version.rb
77
97
  homepage: https://asciidoctor.org
78
98
  licenses:
79
99
  - MIT
80
100
  metadata:
81
101
  bug_tracker_uri: https://github.com/asciidoctor/asciidoctor-chart/issues
82
- mailing_list_uri: http://discuss.asciidoctor.org
102
+ community_chat_uri: https://asciidoctor.zulipchat.com
83
103
  source_code_uri: https://github.com/asciidoctor/asciidoctor-chart
104
+ rubygems_mfa_required: 'true'
84
105
  post_install_message:
85
106
  rdoc_options: []
86
107
  require_paths:
@@ -92,11 +113,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
113
  version: '0'
93
114
  required_rubygems_version: !ruby/object:Gem::Requirement
94
115
  requirements:
95
- - - ">"
116
+ - - ">="
96
117
  - !ruby/object:Gem::Version
97
- version: 1.3.1
118
+ version: '0'
98
119
  requirements: []
99
- rubygems_version: 3.0.3
120
+ rubygems_version: 3.0.3.1
100
121
  signing_key:
101
122
  specification_version: 4
102
123
  summary: Adds a chart block and block macro to AsciiDoc
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Asciidoctor
4
- module Chart
5
- class Backend
6
- def self.resolve_engine attrs, document
7
- if attrs.key? 'engine'
8
- attrs['engine'].downcase
9
- elsif document.attributes.key? 'chart-engine'
10
- document.attributes['chart-engine'].downcase
11
- else
12
- 'c3js'
13
- end
14
- end
15
-
16
- def self.process engine, attrs, raw_data
17
- # TODO: Check that the engine can process the required type (bar, line, step...)
18
- type = attrs['type']
19
- case engine
20
- when 'c3js'
21
- if type == 'pie'
22
- C3js::ChartBuilder.pie raw_data, attrs
23
- else
24
- data, labels = C3js::ChartBuilder.prepare_data raw_data
25
- case type
26
- when 'bar'
27
- C3js::ChartBuilder.bar data, labels, attrs
28
- when 'line'
29
- C3js::ChartBuilder.line data, labels, attrs
30
- when 'step'
31
- C3js::ChartBuilder.step data, labels, attrs
32
- when 'spline'
33
- C3js::ChartBuilder.spline data, labels, attrs
34
- else
35
- # By default chart line
36
- C3js::ChartBuilder.line data, labels, attrs
37
- end
38
- end
39
- when 'chartist'
40
- data, labels = Chartist::ChartBuilder.prepare_data raw_data
41
- case type
42
- when 'bar'
43
- Chartist::ChartBuilder.bar data, labels, attrs
44
- when 'line'
45
- Chartist::ChartBuilder.line data, labels, attrs
46
- else
47
- # By default chart line
48
- Chartist::ChartBuilder.line data, labels, attrs
49
- end
50
- when 'chartjs'
51
- data, labels = Chartjs::ChartBuilder.prepare_data raw_data
52
- # By default chart line
53
- Chartjs::ChartBuilder.line data, labels, attrs
54
- end
55
- end
56
- end
57
- end
58
- end