File: graph.tcl

package info (click to toggle)
moomps 4.6-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 2,444 kB
  • ctags: 2,307
  • sloc: tcl: 34,882; sh: 167; makefile: 91
file content (159 lines) | stat: -rw-r--r-- 8,342 bytes parent folder | download | duplicates (2)
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
    }

}