require 'tk' require 'tkextlib/blt' # left drag: expand # left click: autoscale off # right drag: shrink # right click: autoscale on # middle drag: move class GraphBlt include Tk def initialize(width=300,height=300,w=nil,side="top") @graph = Tk::BLT::Graph.new(w, :width=>width,:height=>height).pack('side'=>side) @graph.axis_configure('x',:ticklength=>5) @graph.axis_configure('x',:showticks=>true) @graph.gridline_on() @graph.legend_configure( :hide=>'yes') @graph.crosshairs_configure( :hide=>'no') @graph.bind('1',proc{|x,y| box_start(x,y)},'%x %y') @graph.bind('B1-Motion',proc{|x,y| box_resize(x,y)},'%x %y') @graph.bind('ButtonRelease-1',proc{|x,y| enlarge(x,y)},'%x %y') @graph.bind('3',proc{|x,y| box_start(x,y)},'%x %y') @graph.bind('B3-Motion',proc{|x,y| box_resize(x,y)},'%x %y') @graph.bind('ButtonRelease-3',proc{|x,y| shrink(x,y)},'%x %y') @graph.bind('2',proc{|x,y| move_start(x,y)},'%x %y') @graph.bind('B2-Motion',proc{|x,y| move(x,y)},'%x %y') @graph.bind('ButtonRelease-2',proc{|x,y| },'%x %y') @xdata=Tk::BLT::Vector.new() @ydata=Tk::BLT::Vector.new() @plot = Tk::BLT::PlotComponent::Element.new(@graph, 'plot1', :label=>'foo') @plot.configure( :xdata=>@xdata, :ydata=>@ydata) @plot.configure( :linewidth=>1) @plot.configure( :symbol=>'none',:pixels=>5) @xb,@yb=nil,nil #box end def add(x,y) # add new point @xdata.append(x) @ydata.append(y) end def xaxis(title) @graph.axis_configure('x',:title=>title) end def yaxis(title) @graph.title=title # @graph.axis_configure('y',:title=>title) # error on X end def mark=(symbol=true) symbols=["none","circle", "square", "diamond", "plus", "cross", "splus", "scross", "triangle", "arrow"] s=case symbol when *symbols symbol when true "splus" else "none" end @plot.configure( :symbol=>s,:pixels=>5) end def box_start(x,y) @xb,@yb=@graph.invtransform(x,y) autoscale(false) xx,yy=@xb,@yb @graph.marker_create('line', :name=>'box', :coords=>[@xb,@yb,@xb,yy,xx,yy,xx,@yb,@xb,@yb]) end def box_resize(x,y) xx,yy=@graph.invtransform(x,y) @graph.marker_configure('box', :coords=>[@xb,@yb,@xb,yy,xx,yy,xx,@yb,@xb,@yb]) end def enlarge(x,y,x0=@xb,y0=@yb) @graph.marker_delete('box') xx,yy=@graph.invtransform(x,y) x0,xx=[x0,xx].sort y0,yy=[y0,yy].sort unless xx>x0 and yy>y0 # autoscale off x0,xx=@graph.xaxis_limits() y0,yy=@graph.yaxis_limits() end @graph.xaxis_configure(:min=>x0,:max=>xx) @graph.yaxis_configure(:min=>y0,:max=>yy) end def shrink(x,y,x1=@xb,y1=@yb) @graph.marker_delete('box') x0,xx=@graph.xaxis_limits() y0,yy=@graph.yaxis_limits() x2,y2=@graph.invtransform(x,y) x1,x2=[x1,x2].sort y1,y2=[y1,y2].sort if x2>x1 and y2>y1 x0,xx=x0-(xx-x0)*(x1-x0)/(x2-x1),x0+(xx-x0)*(xx-x1)/(x2-x1) y0,yy=y0-(yy-y0)*(y1-y0)/(y2-y1),y0+(yy-y0)*(yy-y1)/(y2-y1) @graph.xaxis_configure(:min=>x0,:max=>xx) @graph.yaxis_configure(:min=>y0,:max=>yy) else # autoscale on autoscale() end end def move_start(x,y) @xb,@yb=x,y autoscale(false) end def move(x,y,x1=@xb,y1=@yb) @xb,@yb=x,y x,y=@graph.invtransform(x,y) x1,y1=@graph.invtransform(x1,y1) x0,xx=@graph.xaxis_limits() y0,yy=@graph.yaxis_limits() x0-=(x-x1) xx-=(x-x1) y0-=(y-y1) yy-=(y-y1) @graph.xaxis_configure(:min=>x0,:max=>xx) @graph.yaxis_configure(:min=>y0,:max=>yy) end def clear() end def autoscale(onoff=true) case onoff when true, "on", "ON" @graph.xaxis_configure(:min=>'',:max=>'') @graph.yaxis_configure(:min=>'',:max=>'') when false, "off", "OFF" x0,xx=@graph.xaxis_limits() y0,yy=@graph.yaxis_limits() @graph.xaxis_configure(:min=>x0,:max=>xx) @graph.yaxis_configure(:min=>y0,:max=>yy) end end end #class #2015.3.4 first version (expand,shrink,move) #2015.3.11 bugfix