1 2 3 4 5 6 7 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 51 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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
# copyright (C) 1997-2005 Jean-Luc Fontaine (mailto:jfontain@free.fr)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu
# $Id: graph.tcl,v 2.60 2005/02/05 21:28:32 jfontain Exp $
class bltGraph { ;# this is common code for all BLT viewers of graph type (includes stripchart and barchart)
variable plotBackground black
set (graphs) {}
proc bltGraph {this path {graph 0}} { ;# graph object if graphing, as opposed to database ranges display
if {![info exists (menu,grid,label)]} {
set (menu,grid,label) [mc Grid]
set (menu,grid,help) [mc {whether a grid is displayed in the plot area}]
}
$path configure -plotborderwidth 1 -topmargin 3\
-bufferelements 1 ;# to avoid slowdowns when there are many data points (such as in database data)
$path xaxis configure -tickfont $blt2DViewer::(axisTickFont) -title {} -command bltGraph::axisTime\
-tickshadow {} -showticks 0 ;# delay showing ticks until step size is known to avoid BLT out of range errors
bind $path <Configure> "+ bltGraph::resized $this" ;# track size updates
if {$graph != 0} {
set ($this,marker) [$path marker create polygon -fill {} -coords {-Inf Inf Inf Inf Inf -Inf -Inf -Inf}]
$path crosshairs configure -color blue
lappend (graphs) [set ($this,graph) $graph] ;# remember graphs in order to ba able to globally set some options
}
set ($this,path) $path
set ($this,plotWidth) 0 ;# cache plot width
set ($this,range) 0
set ($this,crossHairs) 0
}
proc ~bltGraph {this} {
bind $($this,path) <Configure> {}
if {[info exists ($this,graph)]} {ldelete (graphs) $($this,graph)}
}
proc setRange {this value} {
set ($this,range) $value
}
proc xAxisUpdateRange {this {maximumTime {}}} { ;# maximum time is time at rightmost x axis position
if {$($this,range) == 0} return ;# wait till range is defined
if {[string length $maximumTime] == 0} {
set maximumTime [$($this,path) xaxis cget -max] ;# can be empty if no data displayed
if {[string length $maximumTime] > 0} {$($this,path) xaxis configure -min [expr {$maximumTime - $($this,range)}]}
} else {
$($this,path) xaxis configure -min [expr {$maximumTime - $($this,range)}] -max $maximumTime
}
}
proc axisTime {path value} {
set now [clock seconds]
if {[string length [set minimum [$path xaxis cget -min]]] == 0} {return ?} ;# graph has no minimum
set minimum [expr {round($minimum)}] ;# BLT passes a floating point value
if {[clock format $minimum -format %Y] < [clock format $now -format %Y]} { ;# spans more than a year
set format {%Y-%m-%d } ;# show year, month and day
} elseif {[clock format $minimum -format %j] < [clock format $now -format %j]} { ;# spans more than a day
set format {%m-%d } ;# show month and day
}
set value [expr {round($value)}] ;# BLT passes a floating point value
if {($value % 60) == 0} {
append format %R
} else {
append format %T ;# show seconds only when necessary
}
return [clock format $value -format $format]
}
proc xUpdateGraduations {this} {
if {($($this,plotWidth) == 0) || ($($this,range) == 0)} return ;# plot width or range are not known yet
# number = $division * ($range / $step) # number of divisions
# ($plotWidth / $number) > 2 # make sure that there is at least 1 pixel between neighbour divisions
# => $step > ((2 * $division * $range) / $plotWidth)
# use the maximum division in divisions discrete list
set minimum [expr {(2.0 * 6 * $($this,range)) / $($this,plotWidth)}] ;# use floating point to avoid integer overflowing
# choose among predefined discrete values (in seconds)
foreach step {10 60 300 600 1800 3600 18000 36000 86400 604800 2419200 31536000} division {5 6 5 5 5 6 5 5 4 7 4 12} {
if {$step > $minimum} break
}
$($this,path) xaxis configure -stepsize $step -subdivisions $division -showticks 1 ;# now that sizes are known, show ticks
}
proc resized {this} {
update idletasks ;# make sure sizes are correct
set path $($this,path)
set width [$path extents plotwidth]
if {$width != $($this,plotWidth)} {
set ($this,plotWidth) $width
xUpdateGraduations $this ;# optimize graduations for new plot width
}
}
proc enterPlotArea {this x y} {
set path $($this,path)
$path configure -cursor tcross
$path crosshairs on
set ($this,crossHairs) 1
bind $path <Any-Motion> "bltGraph::processMotion $this %x %y"
lifoLabel::push $global::messenger "[axisTime $path $x] $y"
}
proc leavePlotArea {this} {
set path $($this,path)
$path configure -cursor {}
$path crosshairs off
set ($this,crossHairs) 0
bind $path <Any-Motion> {}
lifoLabel::pop $global::messenger
}
proc processMotion {this x y} {
set path $($this,path)
$path crosshairs configure -position @$x,$y
foreach {x y} [$path invtransform $x $y] {}
lifoLabel::pop $global::messenger
lifoLabel::push $global::messenger "[axisTime $path $x] $y"
}
proc hideAxisAndCrossHair {this yesOrNo} {
set path $($this,path)
$path xaxis configure -hide $yesOrNo
$path yaxis configure -hide $yesOrNo
if {[info exists ($this,marker)]} {
if {$yesOrNo} {
$path marker bind $($this,marker) <Enter> {}
$path marker bind $($this,marker) <Leave> {}
} else {
$path marker bind $($this,marker) <Enter> "bltGraph::enterPlotArea $this %x %y"
$path marker bind $($this,marker) <Leave> "bltGraph::leavePlotArea $this"
}
}
}
proc allowDrag {this drag} {
dragSite::provide $drag DATETIME "bltGraph::dragData $this"
set ($this,validCommand) [switched::cget $drag -validcommand]
switched::configure $drag -validcommand "bltGraph::validateDrag $this" ;# override
}
proc validateDrag {this x y} {
if {$($this,crossHairs)} { ;# for date and time data
return 1
} else { ;# use enclosing object validation
return [eval $($this,validCommand) $x $y]
}
}
proc dragData {this format} { ;# sole supported fornat is DATETIME
return [expr {round(\
[lindex [eval $($this,path) invtransform [split [string trimleft [$($this,path) crosshairs cget -position] @] ,]] 0]\
)}] ;# BLT passes a floating point value
}
proc xRotateLabels {this value} {
$($this,path) xaxis configure -rotate $value
}
}
|