lib/rubyvis/mark.rb in rubyvis-0.1.1 vs lib/rubyvis/mark.rb in rubyvis-0.1.2

- old
+ new

@@ -1,77 +1,75 @@ module Rubyvis - # Represents a data-driven graphical mark. The <tt>Mark</tt> class is - # the base class for all graphical marks in Protovis; it does not provide any - # specific rendering functionality, but together with {@link Panel} establishes - # the core framework. + # Represents a data-driven graphical mark. The <tt>Mark</tt> class is + # the base class for all graphical marks in Protovis; it does not provide any + # specific rendering functionality, but together with {@link Panel} establishes + # the core framework. class Mark - @properties={} - - def self.property_method(name,_def) - define_method(name) do |*arguments| - v,dummy = arguments - if _def and self.scene - if arguments.size>0 - defs[name]=OpenStruct.new({:id=>(v.nil?) ? 0 : Rubyvis.id, :value=> v}) - return self - end - return defs[name] - end - if arguments.size>0 - type=(!_def).to_i<<1 | (v.is_a? Proc).to_i - property_value(name,(type & 1 !=0) ? lambda {|*args| v.js_apply(self, args)} : v)._type=type - #@_properties_types[name]=type - return self - end - i=instance() - if i.nil? - raise "No instancia para #{name}" - else - #puts "Instancia para #{name}" - - i.send(name) - end - end - end - def property_value(name,v) - prop=Property.new({:name=>name, :id=>Rubyvis.id, :value=>v}) - @_properties.delete_if{|v| v.name==name} - @_properties.push(prop) - #@_properties_values[name]=v - return prop - end - def margin(n) - self.left(n).right(n).top(n).bottom(n) - end - def instance(default_index=nil) - scene=self.scene - scene||=self.parent.instance(-1).children[self.child_index] - if(default_index) - index=self.respond_to?(:index) ? self.index : default_index - else - index=scene.size-1 - end - #puts "index:#{index} , scene.size:#{scene.size}, default_index:#{default_index}" - scene[index] - end - - - def self.attr_accessor_dsl(*attr) + @properties={} + + def self.property_method(name,_def) + return if Mark.method_defined? name + Mark.send(:define_method, name) do |*arguments| + v,dummy = arguments + if _def and self.scene + if arguments.size>0 + defs[name]=OpenStruct.new({:id=>(v.nil?) ? 0 : Rubyvis.id, :value=> v}) + return self + end + return defs[name] + end + if arguments.size>0 + type=(!_def).to_i<<1 | (v.is_a? Proc).to_i + property_value(name,(type & 1 !=0) ? lambda {|*args| v.js_apply(self, args)} : v)._type=type + #@_properties_types[name]=type + return self + end + i=instance() + if i.nil? + raise "No instance for #{self} on #{name}" + else + #puts "Instancia para #{name}" + #puts "index:#{self.index}, name:#{name}, val:#{i.send(name)}" + i.send(name) + end + end + end + def property_value(name,v) + prop=Property.new({:name=>name, :id=>Rubyvis.id, :value=>v}) + @_properties.delete_if{|v1| v1.name==name} + @_properties.push(prop) + #@_properties_values[name]=v + return prop + end + def margin(n) + self.left(n).right(n).top(n).bottom(n) + end + def instance(default_index=nil) + scene=self.scene + scene||=self.parent.instance(-1).children[self.child_index] + + index = self.respond_to?(:index) ? self.index : default_index + #puts "type: #{type}, self.index: #{self.index}, index:#{index}" + scene[index<0 ? scene.length-1: index] + end + + + def self.attr_accessor_dsl(*attr) attr.each do |sym| @properties[sym]=true sym_w_sm=sym.to_s.gsub(":","") self.property_method(sym,false) define_method(sym.to_s+"=") {|v| self.send(sym,v) } end end - + attr_accessor :parent, :root, :index, :child_index, :scene, :proto, :target, :scale attr_reader :_properties - attr_accessor_dsl :data,:visible, :left, :right, :top, :bottom, :cursor, :title, :reverse, :antialias, :events, :id - + attr_accessor_dsl :data,:visible, :left, :right, :top, :bottom, :cursor, :title, :reverse, :antialias, :events, :id + @scene=nil @stack=[] @index=nil def self.properties @properties @@ -98,11 +96,11 @@ @stack end def Mark.stack=(v) @stack=v end - + def initialize(opts=Hash.new) #@_properties_values={} #@_properties_types={} @_properties=[] #@options=opts @@ -113,66 +111,70 @@ @defs={} @child_index=-1 @index=-1 @scale=1 @scene=nil - + end def type "mark" end - def self.defaults + def self.defaults Mark.new({:data=>lambda {|d| [d]}, :visible=>true, :antialias=>true, :events=>'painted'}) end def extend(proto) @proto=proto @target=proto.target self end - + def instances(source) - - mark = self - index = [] - scene=nil - while (!(scene = mark.scene)) do - source = source.parent; - index.push(OpenStruct.new({:index=>source.index, :child_index=>mark.child_index})) - mark = mark.parent - end - while (index.size>0) do - i = index.pop() - scene = scene[i.index].children[i.child_index] - end - # - # When the anchor target is also an ancestor, as in the case of adding - # to a panel anchor, only generate one instance per panel. Also, set - # the margins to zero, since they are offset by the enclosing panel. - # / - if (self.respond_to? :index and self.index) - - s = scene[self.index].dup - s.right = s.top = s.left = s.bottom = 0; - return [s]; - end - return scene; -end - - - - - - + mark = self + index = [] + scene=nil + while (!(scene = mark.scene)) do + source = source.parent; + index.push(OpenStruct.new({:index=>source.index, :child_index=>mark.child_index})) + mark = mark.parent + end + + while (index.size>0) do + i = index.pop() + scene = scene[i.index].children[i.child_index] + end + # + # When the anchor target is also an ancestor, as in the case of adding + # to a panel anchor, only generate one instance per panel. Also, set + # the margins to zero, since they are offset by the enclosing panel. + # / + if (self.respond_to? :index and self.index) + + s = scene[self.index].dup + s.right = s.top = s.left = s.bottom = 0; + return [s]; + end + return scene; + end + + + + + + + def add(type) parent.add(type).extend(self) end - def anchor(name="center") - + def anchor(name='center') + mark_anchor(name) + end + def mark_anchor(name="center") + anchor=Rubyvis::Anchor.new(self).name(name).data(lambda { self.scene.target.map {|s| s.data} }).visible(lambda { - self.scene.target[self.index].visible + self.scene.target[self.index].visible }).id(lambda {self.scene.target[self.index].id}).left(lambda { s = self.scene.target[self.index] w = s.width w||=0 if ['bottom','top','center'].include?(self.name) @@ -181,14 +183,14 @@ nil else s.left + w end }).top(lambda { - s = self.scene.target[self.index] - h = s.height - h||= 0 - if ['left','right','center'].include? self.name + s = self.scene.target[self.index] + h = s.height + h||= 0 + if ['left','right','center'].include? self.name s.top+h/2.0 elsif self.name=='top' nil else s.top + h @@ -198,36 +200,38 @@ self.name() == "left" ? s.right + (s.width ? s.width : 0) : nil; }).bottom(lambda { s = self.scene.target[self.index]; self.name() == "top" ? s.bottom + (s.height ? s.height : 0) : nil; }).text_align(lambda { - if ['bottom','top','center'].include? self.name - 'center' - elsif self.name=='right' - 'right' - else - 'left' - end + if ['bottom','top','center'].include? self.name + 'center' + elsif self.name=='right' + 'right' + else + 'left' + end }).text_baseline(lambda { - if ['right','left','center'].include? self.name - 'middle' - elsif self.name=='top' - 'top' - else - 'bottom' - end + if ['right','left','center'].include? self.name + 'middle' + elsif self.name=='top' + 'top' + else + 'bottom' + end }) - - + + return anchor end - - - - - + + + def build_implied(s) + mark_build_implied(s) + end + + def mark_build_implied(s) l=s.left r=s.right t=s.top b=s.bottom prop=self.properties @@ -241,22 +245,22 @@ r||=0 l||=0 w=width-r-l elsif r.nil? if l.nil? - + r=(width-w) / (2.0) l=r else r=width-w-l end elsif l.nil? l=width-w-r end - + height=self.parent ? self.parent.height(): (h+(t.nil? ? 0 : t )+(b.nil? ? 0 : b)) - + if h.nil? t||=0 b||=0 h=height-t-b elsif b.nil? @@ -267,20 +271,20 @@ b=height-h-t end elsif t.nil? t=height-h-b end - - - + + + s.left=l s.right=r s.top=t s.bottom=b - + # puts "#{l},#{r},#{t},#{b}" - + s.width=w if prop[:width] s.height=h if prop[:height] s.text_style=Rubyvis::Color.transparent if prop[:text_style] and !s.text_style s.fill_style=Rubyvis::Color.transparent if prop[:fill_style] and !s.fill_style s.stroke_style=Rubyvis::Color.transparent if prop[:stroke_style] and !s.stroke_style @@ -288,42 +292,42 @@ def render parent=self.parent @stack=Mark.stack if parent and !self.root.scene root.render() - return + return end @indexes=[] mark=self until mark.parent.nil? @indexes.unshift(mark.child_index) end - bind + bind while(parent and !parent.respond_to? :index) do parent=parent.parent end - + self.context( parent ? parent.scene : nil, parent ? parent.index : -1, lambda {render_render(self.root, 0,1)}) - + end - + def render_render(mark,depth,scale) mark.scale=scale - if (depth < @indexes.size) + if (depth < @indexes.size) @stack.unshift(nil) - if (mark.respond_to? :index and mark.index) - render_instance(mark, depth, scale); - else + if (mark.respond_to? :index and mark.index) + render_instance(mark, depth, scale); + else mark.scene.size.times {|i| mark.index = i; render_instance(mark, depth, scale); } - mark.index=nil + mark.index=nil end - stack.shift(); - else - mark.build(); + stack.shift + else + mark.build pv.Scene.scale = scale; pv.Scene.update_all(mark.scene); end mark.scale=nil end @@ -334,22 +338,22 @@ child=mark.children[child_index] child_index.times {|i| mark.children[i].scene=s.children[i] } Mark.stack[0]=s.data - + if (child.scene) render_render(child,depth+1,scale*s.transform.k) else child.scene=s.children[child_index] render_render(child, depth+1,scale*s.transform.k) child.scene=nil end child_index.times {|i| mark.children[i].scene=nil } - + end end private :render_render, :render_instance def bind_bind(mark) begin @@ -357,27 +361,29 @@ #p v.name k=v.name if !@seen.has_key?(k) @seen[k]=v case k - when :data - @_data=v - when :visible - @_required.push(v) - when :id - @_required.push(v) - else - @types[v._type].push(v) + when :data + @_data=v + when :visible + @_required.push(v) + when :id + @_required.push(v) + else + @types[v._type].push(v) end end } end while(mark = mark.proto) end - + attr_accessor :binds - - def bind() + def bind + mark_bind + end + def mark_bind() @seen={} @types={1=>[],2=>[],3=>[]} @_data=nil @_required=[] bind_bind(self) @@ -394,12 +400,12 @@ } end while(mark=mark.proto) @binds=OpenStruct.new({:properties=>@seen, :data=>@_data, :required=>@_required, :optional=>@types[1]+@types[2]+@types[3] }) end - - + + def context_apply(scene,index) Mark.scene=scene Mark.index=index return if(!scene) that=scene.mark @@ -419,19 +425,19 @@ mark=ancestors[i] mark.scale=k k=k*mark.scene[mark.index].transform.k } if (that.children) - n=than.children.size + n=that.children.size n.times {|i| mark=that.children[i] mark.scene=that.scene[that.index].children[i] mark.scale=k } - + end - + end def context_clear(scene,index) return if !scene that=scene.mark mark=nil @@ -439,11 +445,11 @@ that.children.size.times {|i| mark=that.children[i] mark.scene=nil mark.scale=nil } - + end mark=that begin Mark.stack.pop if(mark.parent) @@ -465,15 +471,15 @@ ensure context_clear(scene,index) context_apply(oscene,oindex) end end - + def build scene=self.scene stack=Mark.stack - + if(!scene) self.scene=SceneElement.new scene=self.scene scene.mark=self scene.type=self.type @@ -490,14 +496,14 @@ end #pp self.binds data=self.binds.data #puts "stack:#{stack}" #puts "data_value:#{data.value}" - + data=(data._type & 1)>0 ? data.value.js_apply(self, stack) : data.value #puts "data:#{data}" - + stack.unshift(nil) scene.size=data.size data.each_with_index {|d, i| Mark.index=self.index=i s=scene[i] @@ -511,11 +517,14 @@ Mark.index=-1 self.index=nil stack.shift() return self end - def build_instance(s1) + def build_instance(s) + mark_build_instance(s) + end + def mark_build_instance(s1) build_properties(s1, self.binds.required) if s1.visible build_properties(s1,self.binds.optional) build_implied(s1) end @@ -529,10 +538,10 @@ if prop._type==3 v=v.js_apply(self, Mark.stack) end ss.send((prop.name.to_s+"=").to_sym, v) end - #p ss + # p ss end end end require 'rubyvis/mark/anchor'