File: datagraf.tcl

package info (click to toggle)
moodss 5.0-2
  • links: PTS
  • area: main
  • in suites: slink
  • size: 1,104 kB
  • ctags: 430
  • sloc: tcl: 12,266; sh: 59; makefile: 43
file content (248 lines) | stat: -rw-r--r-- 12,450 bytes parent folder | download
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# copyright (C) 1997-98 Jean-Luc Fontaine (mailto:jfontain@mygale.org)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

set rcsId {$Id: datagraf.tcl,v 1.44 1998/10/11 09:27:20 jfontain Exp $}


class dataGraph {

if {$::officialBLT} {
    set (widget) stripchart
} else {
    set (widget) graph
}

    proc dataGraph {this parentPath args} composite {
        [new $dataGraph::(widget) $parentPath -title {} -topmargin 3 -bufferelements 0 -plotborderwidth 1 -plotbackground black]
        $args
    } blt2DViewer {$widget::($this,path)} {
        set path $widget::($this,path)
        $path xaxis configure -tickfont $font::(smallNormal) -title {} -rotate 90 -command dataGraph::axisTime
if {$::officialBLT} {
        $path xaxis configure -tickshadow {}
        $path pen create void -linewidth 0 -symbol none                                                       ;# pen for void values
}
        # track size updates (do not use Configure event since it leads to incorrect values for graph internal components)
        bind $path <Visibility> "dataGraph::resized $this"
        set dataGraph::($this,plotWidth) 0                                                                       ;# cache plot width
        composite::complete $this
    }

    proc ~dataGraph {this} {
        if {[string length $composite::($this,-deletecommand)]>0} {
            uplevel #0 $composite::($this,-deletecommand)                                   ;# always invoke command at global level
        }
    }

    proc iconData {} {
        return {
            R0lGODdhKAAoAKUAAHt5e87PzgAAANbX1v///zFhITFhGJTXa633e6X3e5znc6Xvc3u+Wpznazk4OZTfa4zPY3NJAPffSufHOda2Mc6mKVIIY2sYexBhe4wQ
            pa3X54S+zr0o1qUYvbUYzrUg1lKWrb0Y3t44/60Yzt5B/+dJ/+dR/9YY984Y7+dZ/+dh/94o/+9x/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAKAAoAAAG/kCAcEgsGo/IYQAgaDqf0Kh02lwKAthsYIDlbrVer3Y8ZgYI6DQaoG6z2+n3Gm09wwlyeN6t
            flsHd3iBgoF5fmZDBYpJAIoGBUaPj0Z1aAUHmAWEapeYB5ppBQgICQqghwKABJ2ZeYoLCwoLpYqKpbAMkISVqwyeC6CrsAoKDAzDCg3FC8aQbKhLQgW+BwsN
            tdUNzdMMxb7bDuFEf5zGyp4H2osOisbbAA5y0G3cD98QuUPxjbX6fXRMVHHi5s7ZHCNz4gC8gqTWIkYQAfCCs2/Iv0IXyd2JwJEjH4wKCUxMw1GCSZMRLt4x
            tDDakAgmJ8iUKSGCkY42GY2EKZNC/oWfFCbUTAmg5EmPLEUGJCmhZ4WOFYKihNl05tSMZtDwnOAzZ9GfNJv6/BlVaM2Qf4REoMD2abi3HKOy7Qo1aNeKErMS
            iEDWpgM3fPsSCfzT5i69ezkK+Qu4oyGcQg5f6ROZsZ54K/cltEKls2cpViyIvoCh9IXTqFOXNp2a9OrWF6xkmI1Bg20Ms3Pnrm1bA+7dvTdguMChOAcrHTx8
            wLChue8P0KGX1tDc+era1UEMDxFChAgrIzyMwACi+nPptpuDKL+hN/UN64dfCEGiPvgR0tm3X/0+Pnn98GknH3clFAgeByEg+J9z6cHHWmnr+Ycad/XZxwR3
            GIawYHUOXsJ23YQYmiCiCVZwhyCCGv4X4YAYwjbiiyOWeAIKM6KAQgiuvXZBCjz26OOPQFpRo41E4phaBiGooOSSTDbppJAoOCnllFQ2acUKK7Cg5ZZcdunl
            l18uQcaYZJZZZhAAOw==
        }
    }

    proc options {this} {
        set samples [expr {$configuration::(graphNumberOfIntervals)+1}]
        # force size and interval values
        return [list\
            [list -deletecommand {} {}]\
            [list -draggable draggable Draggable 0 0]\
            [list -height height Height 200]\
            [list -interval interval Interval 5]\
            [list -samples samples Samples $samples $samples]\
            [list -width width Width 300]\
        ]
    }

    proc set-deletecommand {this value} {}

    foreach option {-height -width} {
        proc set$option {this value} "\$widget::(\$this,path) configure $option \$value"
    }

    proc set-draggable {this value} {
        if {$composite::($this,complete)} {
            error {option -draggable cannot be set dynamically}
        }
        if {$value} {
            blt2DViewer::allowDrag $this
        }
    }

    proc set-interval {this value} {
        set dataGraph::($this,range) [expr {($composite::($this,-samples)-1)*$value}]
        updateGraduations $this
    }

    proc set-samples {this value} {                                                                     ;# stored at composite level
        if {$composite::($this,complete)} {
            error {option -samples cannot be set dynamically}
        }
        set dataGraph::($this,range) [expr {($value-1)*$composite::($this,-interval)}]
    }

    proc xAxisUpdate {this currentTime} {
        $widget::($this,path) xaxis configure -min [expr {$currentTime-$dataGraph::($this,range)}] -max $currentTime
    }

    proc axisTime {path value} {
        set value [expr {int($value)}]                                    ;### sometimes BLT passes a floating point value: bug? ###
        if {($value%60)==0} {
            return [clock format $value -format %H:%M]
        } else {
            return [clock format $value -format %T]                                              ;# show seconds only when necessary
        }
    }

    proc newElement {this path args} {                                                          ;# invoked from 2D viewer base class
        return [eval new element $path $args]
    }

    proc updateTimeDisplay {this seconds} {
        xAxisUpdate $this $seconds
    }

    proc updateElement {this element seconds value} {
        element::update $element $seconds $value
    }

    proc updateGraduations {this} {
        if {$dataGraph::($this,plotWidth)==0} return                                                  ;# plot width is 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*6*$dataGraph::($this,range))/$dataGraph::($this,plotWidth)}]
        # choose among predefined discrete values
        foreach step {10 60 300 600 1800 3600 18000 36000 86400} division {5 6 5 5 5 6 5 5 4} {
            if {$step>$minimum} break
        }
        $widget::($this,path) xaxis configure -stepsize $step -subdivisions $division
        xAxisUpdate $this [clock seconds]
    }

    proc resized {this} {
        set width [$widget::($this,path) extents plotwidth]
        if {$width!=$dataGraph::($this,plotWidth)} {
            set dataGraph::($this,plotWidth) $width
            updateGraduations $this                                                       ;# optimize graduations for new plot width
        }
    }

}

class dataGraph {

    class element {

        set (vectorIndex) 0                                               ;### remove with official BLT when #auto feature works ###

        proc element {this path args} switched {$args} {
            global [set ($this,xVector) vector[incr (vectorIndex)]] [set ($this,yVector) vector[incr (vectorIndex)]]

            $path element create $this -label {} -symbol none                         ;# use object identifier as element identifier
            set dots [expr {$configuration::(graphNumberOfIntervals)+1}]
if {$::officialBLT} {
            ### blt::vector create #auto($dots) should ultimately work ###
            global [set ($this,weights) vector[incr (vectorIndex)]]    ;### necessary? namespace variable automatically created? ###
            blt::vector create [set ($this,xVector)]($dots)                                                    ;# x axis data vector
            blt::vector create [set ($this,yVector)]($dots)                                                    ;# y axis data vector
            blt::vector create [set ($this,weights)]($dots)                                                   ;# weights data vector
            $path element configure $this -weight [set ($this,weights)] -styles {{void 0 0}}                   ;# handle void values
} else {
            blt::vector [set ($this,xVector)]($dots)
            blt::vector [set ($this,yVector)]($dots)
}
            $path element configure $this -xdata [set ($this,xVector)] -ydata [set ($this,yVector)]
            set ($this,path) $path
            switched::complete $this
        }

        proc ~element {this} {
            global [set ($this,xVector)] [set ($this,yVector)]

if {$::officialBLT} {
            global [set ($this,weights)]
            blt::vector destroy [set ($this,xVector)] [set ($this,yVector)] [set ($this,weights)]
} else {
            unset [set ($this,xVector)] [set ($this,yVector)]
}
            [set ($this,path)] element delete $this
            if {[string length $switched::($this,-deletecommand)]>0} {
                uplevel #0 $switched::($this,-deletecommand)                                ;# always invoke command at global level
            }
        }

        proc options {this} {
            return [list\
                [list -color black black]\
                [list -deletecommand {} {}]\
                [list -label {} {}]\
            ]
        }

        foreach option {-color -label} {
            proc set$option {this value} "\[set (\$this,path)\] element configure \$this $option \$value"
        }

        proc set-deletecommand {this value} {}                                                   ;# data is stored at switched level

if {$::officialBLT} {

        proc update {this x y} {
            global [set ($this,xVector)] [set ($this,yVector)] [set ($this,weights)]

            if {[set [set ($this,xVector)](end)]==0} {                                                               ;# first update
                if {[string length $y]==0} return                                            ;# do nothing till we get a valid value
                set [set ($this,xVector)](end) $x                                 ;# make 2 last points identical so a dot is traced
                set [set ($this,yVector)](end) $y
            }
            [set ($this,xVector)] delete 0                                            ;# achieve scrolling by deleting first element
            [set ($this,yVector)] delete 0
            [set ($this,weights)] delete 0
            [set ($this,xVector)] append $x                                                               ;# and appending new value
            if {[string length $y]==0} {                                                                           ;# void new value
                [set ($this,yVector)] append [set [set ($this,yVector)](end)]                             ;# append last known value
                [set ($this,weights)] append 0                                                        ;# and display with void style
                [set ($this,path)] element configure $this -label "$switched::($this,-label): ?"
            } else {                                                                                              ;# valid new valid
                [set ($this,yVector)] append $y
                [set ($this,weights)] append 1                                                                       ;# normal style
                [set ($this,path)] element configure $this -label "$switched::($this,-label): $y"
            }
        }

} else {

        proc update {this x y} {
            global [set ($this,xVector)] [set ($this,yVector)]

            if {[string length $y]==0} {                                                                           ;# void new value
                set y 0                                                                                   ;# cannot handle void type
                [set ($this,path)] element configure $this -label "$switched::($this,-label): ?"
            } else {
                [set ($this,path)] element configure $this -label "$switched::($this,-label): $y"
            }
            if {[set [set ($this,xVector)](end)]==0} {                                                               ;# first update
                set [set ($this,xVector)](:) $x          ;# make all points identical so curve seems to start from first valid value
                set [set ($this,yVector)](:) $y
            }
            [set ($this,xVector)] delete 0                                            ;# achieve scrolling by deleting first element
            [set ($this,yVector)] delete 0
            [set ($this,xVector)] append $x                                                               ;# and appending new value
            [set ($this,yVector)] append $y
        }

}

    }

}