Class: Fretboards::Renderer::Svg
- Defined in:
- lib/fretboards/renderer/svg.rb
Instance Method Summary collapse
- #draw_barres(svg) ⇒ Object
- #draw_blue_note_symbol(svg, x, y, m) ⇒ Object
- #draw_dot(svg, x, y, m) ⇒ Object
- #draw_fret(svg, n) ⇒ Object
- #draw_frets(svg) ⇒ Object
- #draw_in_bottom(svg, name) ⇒ Object
- #draw_in_dots(svg, name) ⇒ Object
- #draw_labels(svg) ⇒ Object
- #draw_marks(svg) ⇒ Object
- #draw_mutes(svg) ⇒ Object
- #draw_nut(svg) ⇒ Object
- #draw_open(svg, m) ⇒ Object
- #draw_strings(svg) ⇒ Object
- #draw_title(svg) ⇒ Object
- #fret_attrs ⇒ Object
- #get_dot_position(string, fret) ⇒ Object
- #get_first_fret_size(gaps, factor, avail) ⇒ Object
- #get_fret_y(fret_number) ⇒ Object
- #get_string_x(sn) ⇒ Object
-
#initialize(opts = {}) ⇒ Svg
constructor
A new instance of Svg.
- #landscape_attributes ⇒ Object
- #nut_attrs ⇒ Object
- #render(fb) ⇒ Object
- #string_attrs ⇒ Object
- #string_spacing ⇒ Object
Methods inherited from Base
Constructor Details
#initialize(opts = {}) ⇒ Svg
Returns a new instance of Svg.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/fretboards/renderer/svg.rb', line 8 def initialize(opts = {}) # TODO configuration should merge recursively @opts = { :string_attrs => { :"stroke-width" => 1, :stroke => "#222" }, :fret_attrs => { :"stroke-width" => 1, :stroke => "#222", :"stroke-linecap" => "round" }, :rectangular_fret_attrs => { :height => 1.5, :fill => "#666", :stroke => "#666", :"stroke-width" => 1, :rx => 1, :ry => 1 }, :nut_attrs => { :"stroke-width" => 5, :stroke => "#222", :"stroke-linecap" => "round"}, :dot_attrs => { :fill => "#000", :r => 8 }, :open_attrs => { :"stroke-width" => 1, :stroke => "#000", :fill => "#fff", :r => 3 }, :open_root_symbol_attrs => { :"stroke-width" => 2, :r => 3 }, :open_phantom_root_symbol_attrs => { :"stroke-width" => 1, :r => 3, :"stroke-dasharray" => "1 1" }, :svg_attrs => { :xmlns => "http://www.w3.org/2000/svg", :version => "1.1" }, :in_dot_attrs => { :"text-anchor" => "middle", :fill => "#fff", :"font-size" => 10, :"font-family" => "sans-serif", :"font-weight" => "bold"}, :in_dot_root_symbol_attrs => { :fill => "#000", :"font-weight" => "bold" }, :in_bottom_attrs => { :"text-anchor" => "middle", :fill => "#000", :"font-weight" => "normal", :"font-size" => 8, :"font-family" => "sans-serif" }, :label_attrs => { :"text-anchor" => "end", :fill => "#000", :"font-size" => 10, :"font-family" => 'sans-serif' }, :root_symbol_attrs => { :fill => "#fff", :stroke => "#000", :r => 7, :"stroke-width" => 2 }, :phantom_root_symbol_attrs => { :fill => "#fff", :stroke => "#333", :r => 7, :"stroke-width" => 1, :"stroke-dasharray" => "1 1" }, :title_attrs => { :"text-anchor" => "middle", :fill => "#000", :"font-weight" => "bold", :"font-size" => 18, :"font-family" => "sans-serif" } , :mute_attrs => { :stroke => "#000"}, :barre_attrs => { :height => 20, :stroke => "#000", :fill => "#fff", :rx => 9, :ry => 9 }, :group_attrs => { }, :in_dot => :finger, :in_bottom => :function, :padding_left => 20, :padding_right => 15, :padding_top => 30, :padding_bottom => 20, :height => 180, :width => 108, :string_ext_bottom => 5, :string_ext_top => 5, :fret_ext_left => 2, :fret_ext_right => 2, :string_widths => [ 2, 2, 2, 2, 2, 2 ], # TODO calculate on demand if not passed :fret_reduction_factor => 0.95, :rectangular_frets => true, :fret_count => 4, :show_labels => true, :show_title => true, :open_margin_bottom => 4, }.deep_merge(opts) end |
Instance Method Details
#draw_barres(svg) ⇒ Object
294 295 296 297 298 299 300 301 302 303 |
# File 'lib/fretboards/renderer/svg.rb', line 294 def (svg) = @opts[:barre_attrs] @fb..each do |b| dot_pos = get_dot_position(b[:from], b[:fret]) w = get_string_x(b[:to]) - dot_pos[0] + [:height] x = dot_pos[0] - [:height] * 0.5 y = dot_pos[1] - [:height] * 0.5 svg.rect({:y => y, :x => x, :width => w, :class => :barre}.merge()) end end |
#draw_blue_note_symbol(svg, x, y, m) ⇒ Object
217 218 219 220 |
# File 'lib/fretboards/renderer/svg.rb', line 217 def draw_blue_note_symbol(svg, x, y, m) svg.rect(:x => x - 4, :y => y - 4, :width => 8, :height => 8, :fill => "#000", :stroke => "", :transform => "rotate(-45 #{x} #{y})") # svg.circle(:cx => x, :cy => y, :r => 3, :fill => "blue") end |
#draw_dot(svg, x, y, m) ⇒ Object
223 224 225 226 227 228 229 |
# File 'lib/fretboards/renderer/svg.rb', line 223 def draw_dot(svg, x, y, m) cnames = %w[dot] cnames << "dot-#{m[:symbol]}" if m[:symbol] attrs = @opts[:dot_attrs].merge(:cx => x, :cy => y, :class => cnames.join(' ')) attrs = attrs.merge(@opts[(m[:symbol].to_s + "_symbol_attrs").to_sym]) if (m[:symbol] && @opts[(m[:symbol].to_s + "_symbol_attrs").to_sym]) svg.circle(attrs) end |
#draw_fret(svg, n) ⇒ Object
159 160 161 162 163 164 165 166 |
# File 'lib/fretboards/renderer/svg.rb', line 159 def draw_fret(svg, n) y = get_fret_y(n) if @opts[:rectangular_frets] svg.rect({ :y => y - 1.25, :x => @opts[:padding_left] - @opts[:fret_ext_left], :width => @opts[:width] - @opts[:padding_left] - @opts[:padding_right] + @opts[:fret_ext_left] + @opts[:fret_ext_right], :class => 'fret' }.merge(@opts[:rectangular_fret_attrs])) else svg.line(fret_attrs.merge(:x1 => @opts[:padding_left], :x2 => @opts[:width] - @opts[:padding_right], :y1 => y, :y2 => y, :class => 'fret')) end end |
#draw_frets(svg) ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/fretboards/renderer/svg.rb', line 130 def draw_frets(svg) fret_range = @fb.fret_range(@opts[:fret_count]) total_frets = fret_range.last - fret_range.first + 1 # total_frets += 1 if (fret_range.first == 1) # nut / first line if fret_range.first == 1 draw_nut(svg) else draw_fret(svg, 0) end total_frets.times do |n| draw_fret(svg, n+1) end end |
#draw_in_bottom(svg, name) ⇒ Object
258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/fretboards/renderer/svg.rb', line 258 def draw_in_bottom(svg, name) # TODO allow rotating bottom text on rotated fretboards sym = name.to_sym sym_attrs = "in_bottom_attrs".to_sym @fb.marks.each do |m| if m[sym] x = get_string_x(m[:string]) y = @opts[:height] - @opts[:padding_bottom] + @opts[:in_bottom_attrs][:"font-size"] * 1.5 attrs = @opts[sym_attrs].merge(:x => x, :y => y, :class => 'text-at-bottom') svg.text(m[sym].to_s, attrs) end end end |
#draw_in_dots(svg, name) ⇒ Object
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/fretboards/renderer/svg.rb', line 240 def draw_in_dots(svg, name) # TODO allow rotating dot text on rotated fretboards sym = name.to_sym sym_attrs = "in_dot_attrs".to_sym @fb.marks.each do |m| if m[sym] && m[:fret] > 0 custom_attrs = ("in_dot_" + m[:symbol].to_s + "_symbol_attrs").to_sym x, y = *get_dot_position(m[:string], m[:fret]) y += @opts[sym_attrs][:"font-size"] / 3.0 attrs = @opts[sym_attrs] attrs = attrs.merge(@opts[custom_attrs]) if (m[:symbol] && @opts[custom_attrs]) attrs = attrs.merge(:x => x, :y => y) attrs = attrs.merge(:class => 'text-in-dot') svg.text(m[sym].to_s, attrs) end end end |
#draw_labels(svg) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/fretboards/renderer/svg.rb', line 145 def draw_labels(svg) fret_range = @fb.fret_range(@opts[:fret_count]) if fret_range.first > 1 y = get_dot_position(0, fret_range.first + @fb.label_offset)[1] + @opts[:label_attrs][:"font-size"] * 0.4 x = if !@opts[:label_attrs][:'x-offset'].nil? @opts[:padding_left] - @opts[:label_attrs][:'x-offset'] else @opts[:padding_left] - @opts[:label_attrs][:"font-size"] * 1.25 end # TODO allow rotating svg.text(fret_range.first + @fb.label_offset, { :y => y, :x => x, :class => 'label' }.merge(@opts[:label_attrs])) end end |
#draw_marks(svg) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/fretboards/renderer/svg.rb', line 201 def draw_marks(svg) @fb.marks.each do |m| if m[:fret] == 0 draw_open(svg, m) else x, y = *get_dot_position(m[:string], m[:fret]) method_name = ("draw_" + m[:symbol].to_s + "_symbol").to_sym if m[:symbol] && self.respond_to?(method_name) self.send(method_name, svg, x, y, m) else draw_dot(svg, x, y, m) end end end end |
#draw_mutes(svg) ⇒ Object
282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/fretboards/renderer/svg.rb', line 282 def draw_mutes(svg) margin_bottom = @opts[:open_margin_bottom] cy = @opts[:padding_top] - @opts[:open_attrs][:r] - @opts[:nut_attrs][:"stroke-width"] - margin_bottom @fb.mutes.each do |s| delta = 3 cx = get_string_x(s) svg.line({:x1 => cx - delta, :x2 => cx + delta, :y1 => cy - delta, :y2 => cy + delta}.merge(@opts[:mute_attrs])) svg.line({:x1 => cx - delta, :x2 => cx + delta, :y1 => cy + delta, :y2 => cy - delta}.merge(@opts[:mute_attrs])) # svg.text("x", { :x => cx, :y => cy }) end end |
#draw_nut(svg) ⇒ Object
168 169 170 171 172 173 |
# File 'lib/fretboards/renderer/svg.rb', line 168 def draw_nut(svg) y = @opts[:padding_top] - @opts[:nut_attrs][:"stroke-width"] * 0.5 extra_first = 0 # @opts[:string_widths][0] * 0.5 extra_last = 0 # @opts[:string_widths].last * 0.5 svg.line(nut_attrs.merge(:x1 => @opts[:padding_left] - extra_first, :x2 => @opts[:width] - @opts[:padding_right] + extra_last, :y1 => y, :y2 => y, :class => 'nut')) end |
#draw_open(svg, m) ⇒ Object
272 273 274 275 276 277 278 279 280 |
# File 'lib/fretboards/renderer/svg.rb', line 272 def draw_open(svg, m) margin_bottom = @opts[:open_margin_bottom] y = @opts[:padding_top] - @opts[:open_attrs][:r] - @opts[:nut_attrs][:"stroke-width"] - margin_bottom x = get_string_x(m[:string]) attrs = {:cx => x, :cy => y, :class => 'open'}.merge(@opts[:open_attrs]) symbol_attrs = "open_#{m[:symbol]}_symbol_attrs".to_sym attrs = attrs.merge(@opts[symbol_attrs]) if (m[:symbol] && @opts[symbol_attrs]) svg.circle(attrs) end |
#draw_strings(svg) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/fretboards/renderer/svg.rb', line 105 def draw_strings(svg) (0..@fb.string_count-1).each do |sn| # x = @opts[:padding_left] + sn * string_spacing(fb) x = get_string_x(@fb.index_to_string_number(sn)) y1 = @opts[:padding_top] y2 = @opts[:height] - @opts[:padding_bottom] attrs = string_attrs.merge(:x1 => x, :x2 => x, :y1 => y1, :y2 => y2, :class => 'string') if (!@opts[:string_widths].empty?) attrs = attrs.merge({ :"stroke-width" => @opts[:string_widths][sn] }) end svg.line(attrs) end end |
#draw_title(svg) ⇒ Object
119 120 121 122 123 |
# File 'lib/fretboards/renderer/svg.rb', line 119 def draw_title(svg) # TODO calculate ideal gap gap = @opts[:title_attrs][:"font-size"] svg.text(@fb.title, { :x => @opts[:width] * 0.5 + ((@opts[:padding_left] - @opts[:padding_right])*0.5), :y => @opts[:padding_top] - gap, :class => 'title' }.merge(@opts[:title_attrs])) end |
#fret_attrs ⇒ Object
93 94 95 |
# File 'lib/fretboards/renderer/svg.rb', line 93 def fret_attrs @opts[:fret_attrs] end |
#get_dot_position(string, fret) ⇒ Object
231 232 233 234 235 236 237 238 |
# File 'lib/fretboards/renderer/svg.rb', line 231 def get_dot_position(string, fret) fret_range = @fb.fret_range(@opts[:fret_count]) diff = fret_range.first == 1 ? 0 : fret_range.first - 1 fret -= diff x = get_string_x(string) y = 0.5 * (get_fret_y(fret - 1) + get_fret_y(fret)) [x, y] end |
#get_first_fret_size(gaps, factor, avail) ⇒ Object
192 193 194 195 196 197 198 |
# File 'lib/fretboards/renderer/svg.rb', line 192 def get_first_fret_size(gaps, factor, avail) sum = 0 (0..gaps-1).each do |t| sum += factor**t end avail.to_f/sum.to_f end |
#get_fret_y(fret_number) ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/fretboards/renderer/svg.rb', line 175 def get_fret_y(fret_number) fret_range = @fb.fret_range(@opts[:fret_count]) avail = @opts[:height] - @opts[:padding_top] - @opts[:padding_bottom] - @opts[:string_ext_bottom] avail -= @opts[:string_ext_top] if (fret_range.first != 1) total_frets = fret_range.last - fret_range.first + 1 # total_frets += 1 if (fret_range.first == 1) start = @opts[:padding_top] start += @opts[:string_ext_top] if (fret_range.first != 1) ff_size = get_first_fret_size(total_frets, @opts[:fret_reduction_factor], avail) # size_each = avail.to_f / total_frets # y = start y = (0..fret_number-1).inject(start) do |sum, f| sum + ff_size*@opts[:fret_reduction_factor]**f end y end |
#get_string_x(sn) ⇒ Object
125 126 127 128 |
# File 'lib/fretboards/renderer/svg.rb', line 125 def get_string_x(sn) sn = @fb.string_number_to_index(sn) @opts[:padding_left] + sn * string_spacing end |
#landscape_attributes ⇒ Object
79 80 81 82 83 84 85 86 87 |
# File 'lib/fretboards/renderer/svg.rb', line 79 def landscape_attributes if @opts[:landscape] { :transform => "rotate(-90 #{@opts[:width]} 0) translate(0 -#{@opts[:width]})" } else {} end end |
#nut_attrs ⇒ Object
97 98 99 |
# File 'lib/fretboards/renderer/svg.rb', line 97 def nut_attrs @opts[:nut_attrs] end |
#render(fb) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/fretboards/renderer/svg.rb', line 52 def render(fb) @fb = fb require "builder" xml = ::Builder::XmlMarkup.new(:indent => 2) xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8" view_box = [ @opts[:width], @opts[:height] ] view_box = view_box.reverse if @opts[:landscape] xml.svg(@opts[:svg_attrs].merge(:viewBox => "0 0 #{view_box.join(' ')}")) do |svg| svg.g(@opts[:group_attrs]) do svg.g(landscape_attributes) do draw_title(svg) unless @opts[:show_title] == false draw_frets(svg) draw_strings(svg) (svg) draw_marks(svg) draw_in_dots(svg, @opts[:in_dot]) if @opts[:in_dot] draw_in_bottom(svg, @opts[:in_bottom]) if @opts[:in_bottom] draw_labels(svg) unless @opts[:show_labels] == false # draw_open(svg) draw_mutes(svg) end end end # @svg # xml end |
#string_attrs ⇒ Object
89 90 91 |
# File 'lib/fretboards/renderer/svg.rb', line 89 def string_attrs @opts[:string_attrs] end |
#string_spacing ⇒ Object
101 102 103 |
# File 'lib/fretboards/renderer/svg.rb', line 101 def string_spacing (@opts[:width] - @opts[:padding_left] - @opts[:padding_right]) / ((@fb.string_count - 1).to_f) end |