diff --git a/.rubocop.yml b/.rubocop.yml index f9fcc56..c030391 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -31,3 +31,5 @@ Metrics/CyclomaticComplexity: Enabled: false Metrics/BlockLength: Enabled: false +Gemspec/RequiredRubyVersion: + Enabled: false diff --git a/asciidoctor-chart.gemspec b/asciidoctor-chart.gemspec index 08b6ad3..e3b9339 100644 --- a/asciidoctor-chart.gemspec +++ b/asciidoctor-chart.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + begin require_relative 'lib/asciidoctor/chart/version' rescue LoadError @@ -8,28 +10,32 @@ Gem::Specification.new do |s| s.name = 'asciidoctor-chart' s.version = Asciidoctor::Chart::VERSION s.summary = 'Adds a chart block and block macro to AsciiDoc' - s.description = 'A set of Asciidoctor extensions that add a chart block and block macro to AsciiDoc for including charts in your AsciiDoc document.' + s.description = "A set of Asciidoctor extensions that add a chart block and block macro to AsciiDoc +for including charts in your AsciiDoc document." s.authors = ['Guillaume Grossetie'] s.email = 'ggrossetie@gmail.com' s.homepage = 'https://asciidoctor.org' s.license = 'MIT' - # NOTE required ruby version is informational only; it's not enforced since it can't be overridden and can cause builds to break - #s.required_ruby_version = '>= 2.5.0' + # NOTE: required ruby version is informational only; + # it's not enforced since it can't be overridden and can cause builds to break + # s.required_ruby_version = '>= 2.7.0' s.metadata = { 'bug_tracker_uri' => 'https://github.com/asciidoctor/asciidoctor-chart/issues', - #'changelog_uri' => 'https://github.com/asciidoctor/asciidoctor-chart/blob/master/CHANGELOG.adoc', - 'mailing_list_uri' => 'http://discuss.asciidoctor.org', - 'source_code_uri' => 'https://github.com/asciidoctor/asciidoctor-chart' + # 'changelog_uri' => 'https://github.com/asciidoctor/asciidoctor-chart/blob/master/CHANGELOG.adoc', + 'community_chat_uri' => 'https://asciidoctor.zulipchat.com', + 'source_code_uri' => 'https://github.com/asciidoctor/asciidoctor-chart', + 'rubygems_mfa_required' => 'true' } - # NOTE the logic to build the list of files is designed to produce a usable package even when the git command is not available + # NOTE: the logic to build the list of files is designed to produce a usable package + # even when the git command is not available begin - files = (result = `git ls-files -z`.split ?\0).empty? ? Dir['**/*'] : result - rescue + files = (result = `git ls-files -z`.split "\0").empty? ? Dir['**/*'] : result + rescue StandardError files = Dir['**/*'] end - s.files = files.grep %r/^(?:(?:data|lib)\/.+|(?:CHANGELOG|LICENSE|NOTICE|README)\.adoc|\.yardopts|#{s.name}\.gemspec)$/ - s.executables = (files.grep %r/^bin\//).map {|f| File.basename f } + s.files = files.grep %r{^(?:(?:data|lib)/.+|(?:CHANGELOG|LICENSE|NOTICE|README)\.adoc|\.yardopts|#{s.name}\.gemspec)$} + s.executables = (files.grep %r{^bin/}).map {|f| File.basename f } s.require_paths = ['lib'] s.add_runtime_dependency 'asciidoctor', '~> 2.0' diff --git a/examples/chart-chartjs.png b/examples/chart-chartjs.png index bb4c55f..d66c79c 100644 Binary files a/examples/chart-chartjs.png and b/examples/chart-chartjs.png differ diff --git a/lib/asciidoctor/chart/chartjs/chart_builder.rb b/lib/asciidoctor/chart/chartjs/chart_builder.rb index ab702ba..9654239 100644 --- a/lib/asciidoctor/chart/chartjs/chart_builder.rb +++ b/lib/asciidoctor/chart/chartjs/chart_builder.rb @@ -3,62 +3,90 @@ module Asciidoctor module Chart module Chartjs + CSS_VALUE_UNIT_RX = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/.freeze + class ChartBuilder - def self.line data, labels, attrs - default_colors = [{ r: 220, g: 220, b: 220 }, { r: 151, g: 187, b: 205 }] - datasets = data.map do |set| - color = default_colors[data.index(set) % 2] - color_rgba = "rgba(#{color[:r]},#{color[:g]},#{color[:b]},1.0)" - <<~EOS - { - fillColor: "#{color_rgba.gsub('1.0', '0.2')}", - strokeColor: "#{color_rgba}", - pointColor: "#{color_rgba}", - pointHighlightStroke: "#{color_rgba}", - pointStrokeColor: "#fff", - pointHighlightFill: "#fff", - data: #{set.to_s} - } - EOS - end.join ',' - chart_id = attrs.fetch('id', "chart#{PlainRubyRandom.uuid}") - chart_height = get_chart_height attrs - chart_width = get_chart_width attrs - chart_canvas = %(
) # rubocop:disable Layout/LineLength - chart_init_ctx_script = %(var ctx = document.getElementById("#{chart_id}").getContext("2d");) - chart_init_data_script = <<~EOS - var data = { - labels: #{labels.to_s}, - datasets: [ - #{datasets} - ] - }; - EOS - chart_init_script = 'var chart = new Chart(ctx).Line(data, {responsive : true});' - <<~EOS - #{chart_canvas} - - EOS - end + class << self + def line data, labels, attrs + default_colors = [{ r: 220, g: 220, b: 220 }, { r: 151, g: 187, b: 205 }] + datasets = data.map do |set| + color = default_colors[data.index(set) % 2] + color_rgba = "rgba(#{color[:r]},#{color[:g]},#{color[:b]},1.0)" + <<~JSON + { + borderColor: "#{color_rgba}", + backgroundColor: "#{color_rgba}", + fill: false, + tension: 0.1, + data: #{set.to_s} + } + JSON + end.join ',' + chart_id = attrs.fetch('id', "chart#{PlainRubyRandom.uuid}") + inline_styles = ['position: relative'] + if (chart_height = get_height attrs) + inline_styles.push("height: #{chart_height}") + end + if (chart_width = get_width attrs) + inline_styles.push("max-width: #{chart_width}") + end + maintain_aspect_ratio = chart_height.nil? && chart_width.nil? + <<~HTML + + + HTML + end - def self.prepare_data raw_data - labels = raw_data[0] - raw_data.shift - [raw_data, labels] - end + def prepare_data raw_data + labels = raw_data[0] + raw_data.shift + [raw_data, labels] + end - def self.get_chart_height attrs - attrs.fetch 'height', '400' - end + private + + def get_height attrs + return unless (height = (attrs.fetch 'height', nil)) + + to_css_size height + end + + def get_width attrs + return unless (width = (attrs.fetch 'width', nil)) + + to_css_size width + end + + def to_css_size str + return str unless (parts = str.match(CSS_VALUE_UNIT_RX)) - def self.get_chart_width attrs - attrs.fetch 'width', '600' + value, unit = parts.captures + unit = 'px' if unit == '' + "#{value}#{unit}" + end end end end diff --git a/lib/asciidoctor/chart/docinfo_processor.rb b/lib/asciidoctor/chart/docinfo_processor.rb index 4712d72..d77f6f7 100644 --- a/lib/asciidoctor/chart/docinfo_processor.rb +++ b/lib/asciidoctor/chart/docinfo_processor.rb @@ -6,14 +6,14 @@ class DocinfoProcessor < ::Asciidoctor::Extensions::DocinfoProcessor use_dsl # at_location :head - C3JS_STYLESHEET = '' - D3JS_SCRIPT = '' - C3JS_SCRIPT = '' + C3JS_STYLESHEET = '' + D3JS_SCRIPT = '' + C3JS_SCRIPT = '' - CHARTIST_STYLESHEET = '' - CHARTIST_SCRIPT = '' + CHARTIST_STYLESHEET = '' + CHARTIST_SCRIPT = '' - CHARTJS_SCRIPT = '' + CHARTJS_SCRIPT = '' def process _doc # TODO: Import only the required engines diff --git a/spec/chartjs_chart_builder_spec.rb b/spec/chartjs_chart_builder_spec.rb new file mode 100644 index 0000000..0a3bc25 --- /dev/null +++ b/spec/chartjs_chart_builder_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'asciidoctor' +require_relative '../lib/asciidoctor-chart' + +describe 'Asciidoctor::Chart::Chartjs::ChartBuilder' do + it 'should use px unit when no unit is defined' do + data = [ + [28, 48, 40, 19, 86, 27, 90], + [65, 59, 80, 81, 56, 55, 40] + ] + labels = %w[January February March April May June July] + attrs = { + 'width' => '600', + 'height' => '400' + } + html = Asciidoctor::Chart::Chartjs::ChartBuilder.line data, labels, attrs + (expect html).to include %(