schapht-gruff 0.3.5
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.
- data/History.txt +111 -0
- data/MIT-LICENSE +21 -0
- data/Manifest.txt +79 -0
- data/README.txt +40 -0
- data/Rakefile +55 -0
- data/assets/bubble.png +0 -0
- data/assets/city_scene/background/0000.png +0 -0
- data/assets/city_scene/background/0600.png +0 -0
- data/assets/city_scene/background/2000.png +0 -0
- data/assets/city_scene/clouds/cloudy.png +0 -0
- data/assets/city_scene/clouds/partly_cloudy.png +0 -0
- data/assets/city_scene/clouds/stormy.png +0 -0
- data/assets/city_scene/grass/default.png +0 -0
- data/assets/city_scene/haze/true.png +0 -0
- data/assets/city_scene/number_sample/1.png +0 -0
- data/assets/city_scene/number_sample/2.png +0 -0
- data/assets/city_scene/number_sample/default.png +0 -0
- data/assets/city_scene/sky/0000.png +0 -0
- data/assets/city_scene/sky/0200.png +0 -0
- data/assets/city_scene/sky/0400.png +0 -0
- data/assets/city_scene/sky/0600.png +0 -0
- data/assets/city_scene/sky/0800.png +0 -0
- data/assets/city_scene/sky/1000.png +0 -0
- data/assets/city_scene/sky/1200.png +0 -0
- data/assets/city_scene/sky/1400.png +0 -0
- data/assets/city_scene/sky/1500.png +0 -0
- data/assets/city_scene/sky/1700.png +0 -0
- data/assets/city_scene/sky/2000.png +0 -0
- data/assets/pc306715.jpg +0 -0
- data/assets/plastik/blue.png +0 -0
- data/assets/plastik/green.png +0 -0
- data/assets/plastik/red.png +0 -0
- data/init.rb +2 -0
- data/lib/gruff.rb +27 -0
- data/lib/gruff/accumulator_bar.rb +27 -0
- data/lib/gruff/area.rb +58 -0
- data/lib/gruff/bar.rb +84 -0
- data/lib/gruff/bar_conversion.rb +46 -0
- data/lib/gruff/base.rb +1112 -0
- data/lib/gruff/bullet.rb +109 -0
- data/lib/gruff/deprecated.rb +39 -0
- data/lib/gruff/line.rb +105 -0
- data/lib/gruff/mini/bar.rb +32 -0
- data/lib/gruff/mini/legend.rb +77 -0
- data/lib/gruff/mini/pie.rb +36 -0
- data/lib/gruff/mini/side_bar.rb +35 -0
- data/lib/gruff/net.rb +142 -0
- data/lib/gruff/photo_bar.rb +100 -0
- data/lib/gruff/pie.rb +124 -0
- data/lib/gruff/scene.rb +209 -0
- data/lib/gruff/side_bar.rb +115 -0
- data/lib/gruff/side_stacked_bar.rb +74 -0
- data/lib/gruff/spider.rb +130 -0
- data/lib/gruff/stacked_area.rb +67 -0
- data/lib/gruff/stacked_bar.rb +54 -0
- data/lib/gruff/stacked_mixin.rb +23 -0
- data/rails_generators/gruff/gruff_generator.rb +63 -0
- data/rails_generators/gruff/templates/controller.rb +32 -0
- data/rails_generators/gruff/templates/functional_test.rb +24 -0
- data/test/gruff_test_case.rb +123 -0
- data/test/test_accumulator_bar.rb +50 -0
- data/test/test_area.rb +134 -0
- data/test/test_bar.rb +283 -0
- data/test/test_base.rb +8 -0
- data/test/test_bullet.rb +26 -0
- data/test/test_legend.rb +68 -0
- data/test/test_line.rb +513 -0
- data/test/test_mini_bar.rb +32 -0
- data/test/test_mini_pie.rb +20 -0
- data/test/test_mini_side_bar.rb +37 -0
- data/test/test_net.rb +230 -0
- data/test/test_photo.rb +41 -0
- data/test/test_pie.rb +154 -0
- data/test/test_scene.rb +100 -0
- data/test/test_side_bar.rb +12 -0
- data/test/test_sidestacked_bar.rb +89 -0
- data/test/test_spider.rb +216 -0
- data/test/test_stacked_area.rb +52 -0
- data/test/test_stacked_bar.rb +52 -0
- metadata +160 -0
    
        data/lib/gruff/bullet.rb
    ADDED
    
    | @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/base'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Gruff::Bullet < Gruff::Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def initialize(target_width="400x40")
         | 
| 6 | 
            +
                if not Numeric === target_width
         | 
| 7 | 
            +
                  geometric_width, geometric_height = target_width.split('x')
         | 
| 8 | 
            +
                  @columns = geometric_width.to_f
         | 
| 9 | 
            +
                  @rows = geometric_height.to_f
         | 
| 10 | 
            +
                else
         | 
| 11 | 
            +
                  @columns = target_width.to_f
         | 
| 12 | 
            +
                  @rows = target_width.to_f / 5.0
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                initialize_ivars
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                reset_themes
         | 
| 18 | 
            +
                theme_greyscale
         | 
| 19 | 
            +
                @title_font_size = 20
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def data(value, maximum_value, options={})
         | 
| 23 | 
            +
                @value = value.to_f
         | 
| 24 | 
            +
                @maximum_value = maximum_value.to_f
         | 
| 25 | 
            +
                @options = options
         | 
| 26 | 
            +
                @options.map { |k, v| @options[k] = v.to_f if v === Numeric }
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              # def setup_drawing
         | 
| 30 | 
            +
              #   # Maybe should be done in one of the following functions for more granularity.
         | 
| 31 | 
            +
              #   unless @has_data
         | 
| 32 | 
            +
              #     draw_no_data()
         | 
| 33 | 
            +
              #     return
         | 
| 34 | 
            +
              #   end
         | 
| 35 | 
            +
              #
         | 
| 36 | 
            +
              #   normalize()
         | 
| 37 | 
            +
              #   setup_graph_measurements()
         | 
| 38 | 
            +
              #   sort_norm_data() if @sort # Sort norm_data with avg largest values set first (for display)
         | 
| 39 | 
            +
              #
         | 
| 40 | 
            +
              #   draw_legend()
         | 
| 41 | 
            +
              #   draw_line_markers()
         | 
| 42 | 
            +
              #   draw_axis_labels()
         | 
| 43 | 
            +
              #   draw_title
         | 
| 44 | 
            +
              # end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              def draw
         | 
| 47 | 
            +
                # TODO Left label
         | 
| 48 | 
            +
                # TODO Bottom labels and markers
         | 
| 49 | 
            +
                # @graph_bottom
         | 
| 50 | 
            +
                # Calculations are off 800x???
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                @colors.reverse!
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                draw_title
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                @margin       = 30.0
         | 
| 57 | 
            +
                @thickness    = @raw_rows / 6.0
         | 
| 58 | 
            +
                @right_margin = @margin
         | 
| 59 | 
            +
                @graph_left   = @title_width * 1.3 rescue @margin # HACK Need to calculate real width
         | 
| 60 | 
            +
                @graph_width  = @raw_columns - @graph_left - @right_margin
         | 
| 61 | 
            +
                @graph_height = @thickness * 3.0
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                # Background
         | 
| 64 | 
            +
                @d = @d.fill @colors[0]
         | 
| 65 | 
            +
                @d = @d.rectangle(@graph_left, 0, @graph_left + @graph_width, @graph_height)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                [:high, :low].each_with_index do |indicator, index|
         | 
| 68 | 
            +
                  next unless @options.has_key?(indicator)
         | 
| 69 | 
            +
                  @d = @d.fill @colors[index + 1]
         | 
| 70 | 
            +
                  indicator_width_x  = @graph_left + @graph_width * (@options[indicator] / @maximum_value)
         | 
| 71 | 
            +
                  @d = @d.rectangle(@graph_left, 0, indicator_width_x, @graph_height)
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                if @options.has_key?(:target)
         | 
| 75 | 
            +
                  @d = @d.fill @font_color
         | 
| 76 | 
            +
                  target_x = @graph_left + @graph_width * (@options[:target] / @maximum_value)
         | 
| 77 | 
            +
                  half_thickness = @thickness / 2.0
         | 
| 78 | 
            +
                  @d = @d.rectangle(target_x, half_thickness, target_x + half_thickness, @thickness * 2 + half_thickness)
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                # Value
         | 
| 82 | 
            +
                @d = @d.fill @font_color
         | 
| 83 | 
            +
                @d = @d.rectangle(@graph_left, @thickness, @graph_left + @graph_width * (@value / @maximum_value), @thickness * 2)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                @d.draw(@base_image)
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              def draw_title
         | 
| 89 | 
            +
                return unless @title
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                @font_height = calculate_caps_height(scale_fontsize(@title_font_size))
         | 
| 92 | 
            +
                @title_width = calculate_width(@title_font_size, @title)
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                @d.fill        = @font_color
         | 
| 95 | 
            +
                @d.font        = @font if @font
         | 
| 96 | 
            +
                @d.stroke('transparent')
         | 
| 97 | 
            +
                @d.font_weight = NormalWeight
         | 
| 98 | 
            +
                @d.pointsize   = scale_fontsize(@title_font_size)
         | 
| 99 | 
            +
                @d.gravity     = NorthWestGravity
         | 
| 100 | 
            +
                @d             = @d.annotate_scaled(*[
         | 
| 101 | 
            +
                  @base_image,
         | 
| 102 | 
            +
                  1.0, 1.0,
         | 
| 103 | 
            +
                  @font_height/2, @font_height/2,
         | 
| 104 | 
            +
                  @title,
         | 
| 105 | 
            +
                  @scale
         | 
| 106 | 
            +
                ])
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            ##
         | 
| 3 | 
            +
            # A mixin for methods that need to be deleted or have been
         | 
| 4 | 
            +
            # replaced by cleaner code.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Gruff
         | 
| 7 | 
            +
              module Deprecated
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
                def scale_measurements
         | 
| 10 | 
            +
                  setup_graph_measurements
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                def total_height
         | 
| 14 | 
            +
                  @rows + 10
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                def graph_top
         | 
| 18 | 
            +
                  @graph_top * @scale
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                def graph_height
         | 
| 22 | 
            +
                  @graph_height * @scale
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                def graph_left 
         | 
| 26 | 
            +
                  @graph_left * @scale 
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                def graph_width
         | 
| 30 | 
            +
                  @graph_width * @scale
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                # TODO Should be calculate_graph_height
         | 
| 34 | 
            +
                # def setup_graph_height
         | 
| 35 | 
            +
                #   @graph_height = @graph_bottom - @graph_top
         | 
| 36 | 
            +
                # end
         | 
| 37 | 
            +
              
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
    
        data/lib/gruff/line.rb
    ADDED
    
    | @@ -0,0 +1,105 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            require File.dirname(__FILE__) + '/base'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            ##
         | 
| 5 | 
            +
            # Here's how to make a Line graph:
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #   g = Gruff::Line.new
         | 
| 8 | 
            +
            #   g.title = "A Line Graph"
         | 
| 9 | 
            +
            #   g.data 'Fries', [20, 23, 19, 8]
         | 
| 10 | 
            +
            #   g.data 'Hamburgers', [50, 19, 99, 29]
         | 
| 11 | 
            +
            #   g.write("test/output/line.png")
         | 
| 12 | 
            +
            #
         | 
| 13 | 
            +
            # There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots, and #hide_lines.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            class Gruff::Line < Gruff::Base
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              # Draw a dashed line at the given value
         | 
| 18 | 
            +
              attr_accessor :baseline_value
         | 
| 19 | 
            +
            	
         | 
| 20 | 
            +
              # Color of the baseline
         | 
| 21 | 
            +
              attr_accessor :baseline_color
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              # Hide parts of the graph to fit more datapoints, or for a different appearance.
         | 
| 24 | 
            +
              attr_accessor :hide_dots, :hide_lines
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              # Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
         | 
| 27 | 
            +
              #
         | 
| 28 | 
            +
              #  g = Gruff::Line.new(400) # 400px wide with lines
         | 
| 29 | 
            +
              #
         | 
| 30 | 
            +
              #  g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
         | 
| 31 | 
            +
              #
         | 
| 32 | 
            +
              #  g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
         | 
| 33 | 
            +
              # 
         | 
| 34 | 
            +
              # The preferred way is to call hide_dots or hide_lines instead.
         | 
| 35 | 
            +
              def initialize(*args)
         | 
| 36 | 
            +
                raise ArgumentError, "Wrong number of arguments" if args.length > 2
         | 
| 37 | 
            +
                if args.empty? or ((not Numeric === args.first) && (not String === args.first)) then
         | 
| 38 | 
            +
                  super()
         | 
| 39 | 
            +
                else
         | 
| 40 | 
            +
                  super args.shift
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                @hide_dots = @hide_lines = false
         | 
| 44 | 
            +
                @baseline_color = 'red'
         | 
| 45 | 
            +
                @baseline_value = nil
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def draw
         | 
| 49 | 
            +
                super
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                return unless @has_data
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                # Check to see if more than one datapoint was given. NaN can result otherwise.  
         | 
| 54 | 
            +
                @x_increment = (@column_count > 1) ? (@graph_width / (@column_count - 1).to_f) : @graph_width
         | 
| 55 | 
            +
                 
         | 
| 56 | 
            +
                if (defined?(@norm_baseline)) then
         | 
| 57 | 
            +
                  level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
         | 
| 58 | 
            +
                  @d = @d.push
         | 
| 59 | 
            +
                  @d.stroke_color @baseline_color
         | 
| 60 | 
            +
                  @d.fill_opacity 0.0
         | 
| 61 | 
            +
                  @d.stroke_dasharray(10, 20)
         | 
| 62 | 
            +
                  @d.stroke_width 5
         | 
| 63 | 
            +
                  @d.line(@graph_left, level, @graph_left + @graph_width, level)
         | 
| 64 | 
            +
                  @d = @d.pop
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                @norm_data.each do |data_row|      
         | 
| 68 | 
            +
                  prev_x = prev_y = nil
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
         | 
| 71 | 
            +
                    new_x = @graph_left + (@x_increment * index)
         | 
| 72 | 
            +
                    next if data_point.nil?
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    draw_label(new_x, index)
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                    new_y = @graph_top + (@graph_height - data_point * @graph_height)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    # Reset each time to avoid thin-line errors
         | 
| 79 | 
            +
                    @d = @d.stroke data_row[DATA_COLOR_INDEX]
         | 
| 80 | 
            +
                    @d = @d.fill data_row[DATA_COLOR_INDEX]
         | 
| 81 | 
            +
                    @d = @d.stroke_opacity 1.0
         | 
| 82 | 
            +
                    @d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 4), 5.0)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    if !@hide_lines and !prev_x.nil? and !prev_y.nil? then          
         | 
| 85 | 
            +
                      @d = @d.line(prev_x, prev_y, new_x, new_y)
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                    circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
         | 
| 88 | 
            +
                    @d = @d.circle(new_x, new_y, new_x - circle_radius, new_y) unless @hide_dots
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    prev_x = new_x
         | 
| 91 | 
            +
                    prev_y = new_y
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                @d.draw(@base_image)
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              def normalize
         | 
| 100 | 
            +
                @maximum_value = [@maximum_value.to_f, @baseline_value.to_f].max
         | 
| 101 | 
            +
                super
         | 
| 102 | 
            +
                @norm_baseline = (@baseline_value.to_f / @maximum_value.to_f) if @baseline_value
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
              
         | 
| 105 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            ##
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # Makes a small bar graph suitable for display at 200px or even smaller.
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            module Gruff
         | 
| 6 | 
            +
              module Mini
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class Bar < Gruff::Bar
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  include Gruff::Mini::Legend
         | 
| 11 | 
            +
                  
         | 
| 12 | 
            +
                  def draw
         | 
| 13 | 
            +
                    @hide_legend = true
         | 
| 14 | 
            +
                    @hide_title = true
         | 
| 15 | 
            +
                    @hide_line_numbers = true
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    @marker_font_size = 50.0
         | 
| 18 | 
            +
                    @minimum_value = 0.0
         | 
| 19 | 
            +
                    @legend_font_size = 60.0
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    expand_canvas_for_vertical_legend
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    super
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    draw_vertical_legend
         | 
| 26 | 
            +
                    @d.draw(@base_image)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,77 @@ | |
| 1 | 
            +
            module Gruff
         | 
| 2 | 
            +
              module Mini
         | 
| 3 | 
            +
                module Legend
         | 
| 4 | 
            +
                  
         | 
| 5 | 
            +
                  ##
         | 
| 6 | 
            +
                  # The canvas needs to be bigger so we can put the legend beneath it.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def expand_canvas_for_vertical_legend
         | 
| 9 | 
            +
                    @original_rows = @raw_rows
         | 
| 10 | 
            +
                    @rows += @data.length * calculate_caps_height(scale_fontsize(@legend_font_size)) * 1.7
         | 
| 11 | 
            +
                    render_background
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  ##
         | 
| 15 | 
            +
                  # Draw the legend beneath the existing graph.
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def draw_vertical_legend
         | 
| 18 | 
            +
                            
         | 
| 19 | 
            +
                    @legend_labels = @data.collect {|item| item[Gruff::Base::DATA_LABEL_INDEX] }
         | 
| 20 | 
            +
                    
         | 
| 21 | 
            +
                    legend_square_width = 40.0 # small square with color of this item
         | 
| 22 | 
            +
                    legend_square_margin = 10.0
         | 
| 23 | 
            +
                    @legend_left_margin = 100.0
         | 
| 24 | 
            +
                    legend_top_margin = 40.0
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    # May fix legend drawing problem at small sizes
         | 
| 27 | 
            +
                    @d.font = @font if @font
         | 
| 28 | 
            +
                    @d.pointsize = @legend_font_size
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    current_x_offset = @legend_left_margin
         | 
| 31 | 
            +
                    current_y_offset = @original_rows + legend_top_margin
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    @legend_labels.each_with_index do |legend_label, index|        
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                      # Draw label
         | 
| 38 | 
            +
                      @d.fill = @font_color
         | 
| 39 | 
            +
                      @d.font = @font if @font
         | 
| 40 | 
            +
                      @d.pointsize = scale_fontsize(@legend_font_size)
         | 
| 41 | 
            +
                      @d.stroke = 'transparent'
         | 
| 42 | 
            +
                      @d.font_weight = Magick::NormalWeight
         | 
| 43 | 
            +
                      @d.gravity = Magick::WestGravity
         | 
| 44 | 
            +
                      @d = @d.annotate_scaled( @base_image, 
         | 
| 45 | 
            +
                                        @raw_columns, 1.0,
         | 
| 46 | 
            +
                                        current_x_offset + (legend_square_width * 1.7), current_y_offset, 
         | 
| 47 | 
            +
                                        truncate_legend_label(legend_label), @scale)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      # Now draw box with color of this dataset
         | 
| 50 | 
            +
                      @d = @d.stroke 'transparent'
         | 
| 51 | 
            +
                      @d = @d.fill @data[index][Gruff::Base::DATA_COLOR_INDEX]
         | 
| 52 | 
            +
                      @d = @d.rectangle(current_x_offset, 
         | 
| 53 | 
            +
                                        current_y_offset - legend_square_width / 2.0, 
         | 
| 54 | 
            +
                                        current_x_offset + legend_square_width, 
         | 
| 55 | 
            +
                                        current_y_offset + legend_square_width / 2.0)
         | 
| 56 | 
            +
                      
         | 
| 57 | 
            +
                      current_y_offset += calculate_caps_height(@legend_font_size) * 1.7
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                    @color_index = 0
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  ##
         | 
| 63 | 
            +
                  # Shorten long labels so they will fit on the canvas.
         | 
| 64 | 
            +
                  #
         | 
| 65 | 
            +
                  #   Department of Hu...
         | 
| 66 | 
            +
                  
         | 
| 67 | 
            +
                  def truncate_legend_label(label)
         | 
| 68 | 
            +
                    truncated_label = label.to_s
         | 
| 69 | 
            +
                    while calculate_width(scale_fontsize(@legend_font_size), truncated_label) > (@columns - @legend_left_margin - @right_margin) && (truncated_label.length > 1)
         | 
| 70 | 
            +
                      truncated_label = truncated_label[0..truncated_label.length-2]
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
                    truncated_label + (truncated_label.length < label.to_s.length ? "…" : '')
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                  
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            ##
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # Makes a small pie graph suitable for display at 200px or even smaller.
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            module Gruff
         | 
| 6 | 
            +
              module Mini
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class Pie < Gruff::Pie
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  include Gruff::Mini::Legend
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def initialize_ivars
         | 
| 13 | 
            +
                    super
         | 
| 14 | 
            +
                    
         | 
| 15 | 
            +
                    @hide_legend = true
         | 
| 16 | 
            +
                    @hide_title = true
         | 
| 17 | 
            +
                    @hide_line_numbers = true
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
                    @marker_font_size = 60.0
         | 
| 20 | 
            +
                    @legend_font_size = 60.0
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def draw
         | 
| 24 | 
            +
                    expand_canvas_for_vertical_legend
         | 
| 25 | 
            +
                    
         | 
| 26 | 
            +
                    super
         | 
| 27 | 
            +
                    
         | 
| 28 | 
            +
                    draw_vertical_legend
         | 
| 29 | 
            +
                    
         | 
| 30 | 
            +
                    @d.draw(@base_image)
         | 
| 31 | 
            +
                  end # def draw
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                end # class Pie
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            ##
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # Makes a small pie graph suitable for display at 200px or even smaller.
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            module Gruff
         | 
| 6 | 
            +
              module Mini
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class SideBar < Gruff::SideBar
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  include Gruff::Mini::Legend
         | 
| 11 | 
            +
                  
         | 
| 12 | 
            +
                  def initialize_ivars
         | 
| 13 | 
            +
                    super
         | 
| 14 | 
            +
                    @hide_legend = true
         | 
| 15 | 
            +
                    @hide_title = true
         | 
| 16 | 
            +
                    @hide_line_numbers = true
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    @marker_font_size = 50.0
         | 
| 19 | 
            +
                    @legend_font_size = 50.0
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                  
         | 
| 22 | 
            +
                  def draw
         | 
| 23 | 
            +
                    expand_canvas_for_vertical_legend
         | 
| 24 | 
            +
                    
         | 
| 25 | 
            +
                    super
         | 
| 26 | 
            +
                    
         | 
| 27 | 
            +
                    draw_vertical_legend
         | 
| 28 | 
            +
                    
         | 
| 29 | 
            +
                    @d.draw(@base_image)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                  
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
    
        data/lib/gruff/net.rb
    ADDED
    
    | @@ -0,0 +1,142 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            require File.dirname(__FILE__) + '/base'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # Experimental!!! See also the Spider graph.
         | 
| 5 | 
            +
            class Gruff::Net < Gruff::Base
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              # Hide parts of the graph to fit more datapoints, or for a different appearance.
         | 
| 8 | 
            +
              attr_accessor :hide_dots
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def initialize(*args)
         | 
| 11 | 
            +
                super
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                @hide_dots = false
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def draw
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                super
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                return unless @has_data
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                @radius = @graph_height / 2.0
         | 
| 23 | 
            +
                @center_x = @graph_left + (@graph_width / 2.0)
         | 
| 24 | 
            +
                @center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                @x_increment = @graph_width / (@column_count - 1).to_f
         | 
| 27 | 
            +
                circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                @d = @d.stroke_opacity 1.0
         | 
| 30 | 
            +
                @d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 4), 5.0)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                if (defined?(@norm_baseline)) then
         | 
| 33 | 
            +
                  level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
         | 
| 34 | 
            +
                  @d = @d.push
         | 
| 35 | 
            +
                  @d.stroke_color @baseline_color
         | 
| 36 | 
            +
                  @d.fill_opacity 0.0
         | 
| 37 | 
            +
                  @d.stroke_dasharray(10, 20)
         | 
| 38 | 
            +
                  @d.stroke_width 5
         | 
| 39 | 
            +
                  @d.line(@graph_left, level, @graph_left + @graph_width, level)
         | 
| 40 | 
            +
                  @d = @d.pop
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                @norm_data.each do |data_row|
         | 
| 44 | 
            +
                  prev_x = prev_y = nil
         | 
| 45 | 
            +
                  @d = @d.stroke data_row[DATA_COLOR_INDEX]
         | 
| 46 | 
            +
                  @d = @d.fill data_row[DATA_COLOR_INDEX]
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
         | 
| 49 | 
            +
                    next if data_point.nil?
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    rad_pos = index * Math::PI * 2 / @column_count
         | 
| 52 | 
            +
                    point_distance = data_point * @radius
         | 
| 53 | 
            +
                    start_x = @center_x + Math::sin(rad_pos) * point_distance
         | 
| 54 | 
            +
                    start_y = @center_y - Math::cos(rad_pos) * point_distance
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    next_index = index + 1 < data_row[DATA_VALUES_INDEX].length ? index + 1 : 0
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    next_rad_pos = next_index * Math::PI * 2 / @column_count
         | 
| 59 | 
            +
                    next_point_distance = data_row[DATA_VALUES_INDEX][next_index] * @radius
         | 
| 60 | 
            +
                    end_x = @center_x + Math::sin(next_rad_pos) * next_point_distance
         | 
| 61 | 
            +
                    end_y = @center_y - Math::cos(next_rad_pos) * next_point_distance
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    @d = @d.line(start_x, start_y, end_x, end_y)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    @d = @d.circle(start_x, start_y, start_x - circle_radius, start_y) unless @hide_dots
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                @d.draw(@base_image)
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
             | 
| 74 | 
            +
              # the lines connecting in the center, with the first line vertical
         | 
| 75 | 
            +
              def draw_line_markers
         | 
| 76 | 
            +
                return if @hide_line_markers
         | 
| 77 | 
            +
             | 
| 78 | 
            +
             | 
| 79 | 
            +
                # have to do this here (AGAIN)... see draw() in this class
         | 
| 80 | 
            +
                # because this funtion is called before the @radius, @center_x and @center_y are set
         | 
| 81 | 
            +
                @radius = @graph_height / 2.0
         | 
| 82 | 
            +
                @center_x = @graph_left + (@graph_width / 2.0)
         | 
| 83 | 
            +
                @center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
         | 
| 84 | 
            +
             | 
| 85 | 
            +
             | 
| 86 | 
            +
                # Draw horizontal line markers and annotate with numbers
         | 
| 87 | 
            +
                @d = @d.stroke(@marker_color)
         | 
| 88 | 
            +
                @d = @d.stroke_width 1
         | 
| 89 | 
            +
             | 
| 90 | 
            +
             | 
| 91 | 
            +
                (0..@column_count-1).each do |index|
         | 
| 92 | 
            +
                  rad_pos = index * Math::PI * 2 / @column_count
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  @d = @d.line(@center_x, @center_y, @center_x + Math::sin(rad_pos) * @radius, @center_y - Math::cos(rad_pos) * @radius)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
             | 
| 97 | 
            +
                  marker_label = labels[index] ? labels[index].to_s : '000'
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius, marker_label)
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            private
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              def draw_label(center_x, center_y, angle, radius, amount)
         | 
| 106 | 
            +
                r_offset = 1.1
         | 
| 107 | 
            +
                x_offset = center_x # + 15 # The label points need to be tweaked slightly
         | 
| 108 | 
            +
                y_offset = center_y # + 0  # This one doesn't though
         | 
| 109 | 
            +
                x = x_offset + (radius * r_offset * Math.sin(angle.deg2rad))
         | 
| 110 | 
            +
                y = y_offset - (radius * r_offset * Math.cos(angle.deg2rad))
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                # Draw label
         | 
| 113 | 
            +
                @d.fill = @marker_color
         | 
| 114 | 
            +
                @d.font = @font if @font
         | 
| 115 | 
            +
                @d.pointsize = scale_fontsize(20)
         | 
| 116 | 
            +
                @d.stroke = 'transparent'
         | 
| 117 | 
            +
                @d.font_weight = BoldWeight
         | 
| 118 | 
            +
                s = angle.deg2rad / (2*Math::PI)
         | 
| 119 | 
            +
                @d.gravity = SouthGravity     if s >= 0.96 or s < 0.04
         | 
| 120 | 
            +
                @d.gravity = SouthWestGravity if s >= 0.04 or s < 0.21
         | 
| 121 | 
            +
                @d.gravity = WestGravity      if s >= 0.21 or s < 0.29
         | 
| 122 | 
            +
                @d.gravity = NorthWestGravity if s >= 0.29 or s < 0.46
         | 
| 123 | 
            +
                @d.gravity = NorthGravity     if s >= 0.46 or s < 0.54
         | 
| 124 | 
            +
                @d.gravity = NorthEastGravity if s >= 0.54 or s < 0.71
         | 
| 125 | 
            +
                @d.gravity = EastGravity      if s >= 0.71 or s < 0.79
         | 
| 126 | 
            +
                @d.gravity = SouthEastGravity if s >= 0.79 or s < 0.96
         | 
| 127 | 
            +
            #     @d.gravity = NorthGravity
         | 
| 128 | 
            +
                @d.annotate_scaled(@base_image, 0, 0, x, y, amount, @scale)
         | 
| 129 | 
            +
              end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            # # This method is already in Float
         | 
| 134 | 
            +
            # class Float
         | 
| 135 | 
            +
            #   # Used for degree => radian conversions
         | 
| 136 | 
            +
            #   def deg2rad
         | 
| 137 | 
            +
            #     self * (Math::PI/180.0)
         | 
| 138 | 
            +
            #   end
         | 
| 139 | 
            +
            # end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
             | 
| 142 | 
            +
             |