class Fox::Enhancement::Xtras::Charting::Chart

Attributes

buffer[RW]
x_range[RW]
y_range[RW]

Public Class Methods

new(cos, canvas) click to toggle source
# File lib/fxruby-enhancement/xtras/charting.rb, line 33
def initialize cos, canvas
  @cos = cos
  @canvas = canvas
  as (:app) {
    @buffer = fx_image { opts IMAGE_KEEP }
  }
  # detailed chart parameters
  @x_ruler_width = 20
  @y_ruler_height = 20
  @font_title = nil
  @font_caption = nil
  @font_ledgend = nil
  @font_axis_name = nil

  # chart layout
  lytbox = ->(klass, **kv){ [kv[:name], klass.new(self, **kv)] }
  @layout = lyt = [
    lytbox.(NullBox, name: :null_left,    placement: :left),
    lytbox.(NullBox, name: :null_right,   placement: :right),
    lytbox.(NullBox, name: :null_top,     placement: :top),
    lytbox.(NullBox, name: :null_bottom,  placement: :bottom),
    lytbox.(Title,   name: :title,        float: true),
    lytbox.(Ruler,   name: :top_ruler,    orient: :horizontal, placement: :top),
    lytbox.(Ruler,   name: :bottom_ruler, orient: :horizontal, placement: :bottom),
    lytbox.(Ruler,   name: :left_ruler,   orient: :vertical,   placement: :left),
    lytbox.(Ruler,   name: :right_ruler,  orient: :vertical,   placement: :right),
    lytbox.(Caption, name: :caption,      float: true),
    lytbox.(Legend,  name: :legend,       float: true),
    lytbox.(Graph,   name: :graph)
  ].to_h
  
  # bottom connections
  lyt[:null_top].bottom_box     = lyt[:title]
  lyt[:title].bottom_box        = lyt[:top_ruler]
  lyt[:top_ruler].bottom_box    = lyt[:graph]
  lyt[:graph].bottom_box        = lyt[:bottom_ruler]
  lyt[:bottom_ruler].bottom_box = lyt[:caption]
  lyt[:caption].bottom_box      = lyt[:null_bottom]

  # right connections
  lyt[:null_left].right_box     = lyt[:left_ruler]
  lyt[:left_ruler].right_box    = lyt[:graph]
  lyt[:graph].right_box         = lyt[:right_ruler]
  lyt[:right_ruler].right_box   = lyt[:legend]
  lyt[:legend].right_box        = lyt[:null_right]
  
  backlink_boxes
end

Public Instance Methods

boxes_of_dominance(dom) click to toggle source

return all boxes with the proscribed dominance

# File lib/fxruby-enhancement/xtras/charting.rb, line 203
def boxes_of_dominance dom
  @layout.map{ |name, box| box }.select{ |box| box.dominance == dom }
end
clear_all_boxes() click to toggle source

All x,y,width,height are nilled for all boxes

# File lib/fxruby-enhancement/xtras/charting.rb, line 106
def clear_all_boxes
  @layout.each { |name, box|
    box.x = box.y = box.width = box.height = nil
  }
end
draw_dc(&block) click to toggle source
# File lib/fxruby-enhancement/xtras/charting.rb, line 207
def draw_dc &block
  @buffer.starten if @buffer.inst.nil?
  FXDCWindow.new(@buffer.inst) { |dc| block.(dc) }
end
layout_box(box) click to toggle source

Layout given box, as much as possible, given neighbors. may be called twice per box.

# File lib/fxruby-enhancement/xtras/charting.rb, line 121
def layout_box box
  if box.dominance == 0 # the only box with a dom of 0 are the null boxes
    case box.name
    when :null_left
      box.x = 0
      box.y = 0
      box.width = 0
      box.height = height
    when :null_right
      box.x = width
      box.y = 0
      box.width = 0
      box.height = height
    when :null_top
      box.x = 0
      box.y = 0
      box.width = width
      box.height = 0
    when :null_bottom
      box.x = 0
      box.y = height
      box.width = width
      box.height = 0
    end              
  else # we do what we can.
    box.calculate_dimensions
    subordinates(box).each { |sub|
      begin
        case sub
        when box.left_box
          box.x = sub.x + sub.width + sub.right_margin + box.left_margin
        when box.right_box
          box.x = sub.x - sub.left_margin - box.right_margin - box.width
        when box.top_box
          box.y = sub.y + sub.height + sub.bottom_margin + box.top_margin
        when box.bottom_box                  
          box.y = sub.y - sub.top_margin - box.bottom_margin - box.height
        end
      rescue NoMethodError, TypeError => e
        #puts "-->subortinate unresolved: #{e}"
      end
    }
    
    superiors(box).each { |sup|
      begin
        case sup
        when box.left_box
          box.height = sup.height 
          box.y = sup.y
          box.x = sup.x + sup.width + sup.right_margin + box.left_margin
        when box.right_box
          box.height = sup.height
          box.y = sup.y                                        
        when box.top_box
          box.width = sup.width
          box.x = sup.x
        when box.bottom_box
          box.width = sup.width
          box.x = sup.x
        end
      rescue NoMethodError, TypeError => e
        #puts "-->superior unresolved: #{e}"
      end unless box.floating?
    }
  end
end
layout_boxes() click to toggle source

call inially and when there's an update.

# File lib/fxruby-enhancement/xtras/charting.rb, line 90
def layout_boxes
  clear_all_boxes
  recalculate_dimensions
  
  # first pass -- out to in
  (0..Box::MAX_DOMINANCE).each do |dom|
    boxes_of_dominance(dom).each{ |box| layout_box box }
  end
  
  # second pass -- in to out
  (1..Box::MAX_DOMINANCE).to_a.reverse.each do |dom|
    boxes_of_dominance(dom).each{ |box| layout_box box }
  end
end
recalculate_dimensions() click to toggle source
# File lib/fxruby-enhancement/xtras/charting.rb, line 112
def recalculate_dimensions
  @layout.each { |name, box|
    box.calculate_dimensions
  }
end
subordinates(box) click to toggle source

Give a list of subordinates

# File lib/fxruby-enhancement/xtras/charting.rb, line 189
def subordinates box
  Box::NÄHE.map{ |b| box.send(b) }
    .compact
    .select { |nbox| box.dominance > nbox.dominance }            
end
superiors(box) click to toggle source

Give a list of superiors

# File lib/fxruby-enhancement/xtras/charting.rb, line 196
def superiors box
  Box::NÄHE.map{ |b| box.send(b) }
    .compact
    .select { |nbox| box.dominance < nbox.dominance }            
end
update_chart() click to toggle source
# File lib/fxruby-enhancement/xtras/charting.rb, line 212
def update_chart
  layout_boxes
  draw_dc { |dc|
    dc.setForeground white
    dc.fillRectangle 0, 0, width, height
    dc.drawImage @buffer.inst, 0, 0
    @layout.each{ |name, box| box.render(dc) }
  }
  @canvas.update
end