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
|
# 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: datapie.tcl,v 1.26 1998/10/11 09:27:20 jfontain Exp $}
class dataPieChart {
proc dataPieChart {this parentPath thickness args} composite {
[new canvas $parentPath -highlightthickness 0 -borderwidth 2] $args
} viewer {} {
set path $widget::($this,path)
set dataPieChart::($this,slices) {}
# allow dropping of data cells
set dataPieChart::($this,drop) [new dropSite\
-path $path -formats DATACELLS -command "viewer::view $this \$dragSite::data(DATACELLS)"\
]
composite::complete $this
# wait till completion to create pie since -selectable option is not dynamically settable
set padding [$path cget -borderwidth]
set dataPieChart::($this,pie) [new pie $path $padding $padding\
-title {} -thickness $thickness -selectable $composite::($this,-draggable)\
-labeler [new piePeripheralLabeler $path\
-font $font::(mediumNormal) -smallfont $font::(smallNormal) -widestvaluetext {00.0 %}\
]\
]
set padding [expr {2*$padding}] ;# width and height are diminished by twice the padding
bind $path <Configure>\
"switched::configure $dataPieChart::($this,pie) -width \[expr {%w-$padding}\] -height \[expr {%h-$padding}\]"
}
proc ~dataPieChart {this} {
delete $dataPieChart::($this,pie) $dataPieChart::($this,drop)
catch {delete $dataPieChart::($this,drag)}
if {[string length $composite::($this,-deletecommand)]>0} {
uplevel #0 $composite::($this,-deletecommand) ;# always invoke command at global level
}
}
proc options {this} {
# force size values
return [list\
[list -deletecommand {} {}]\
[list -draggable draggable Draggable 0 0]\
[list -height height Height 200]\
[list -width width Width 300]\
]
}
proc set-deletecommand {this value} {}
proc set-draggable {this value} {
if {$composite::($this,complete)} {
error {option -draggable cannot be set dynamically}
}
if {!$value} return ;# no dragging
set dataPieChart::($this,drag) [new dragSite -path $widget::($this,path) -validcommand "dataPieChart::validateDrag $this"]
dragSite::provide $dataPieChart::($this,drag) OBJECTS "dataPieChart::dragData $this"
dragSite::provide $dataPieChart::($this,drag) DATACELLS "dataPieChart::dragData $this"
}
foreach option {-height -width} {
proc set$option {this value} "\$widget::(\$this,path) configure $option \$value"
}
proc dragData {this format} {
set slices [slice::selected $dataPieChart::($this,pie)]
switch $format {
OBJECTS {
if {[llength $slices]>0} {
return $slices ;# return selected slices if there are any
} elseif {[llength $dataPieChart::($this,slices)]==0} {
return $this ;# return pie itself if it contains no slices
} else {
return {} ;# return nothing otherwise
}
}
DATACELLS {
return [cellsFromSlices $this $slices]
}
}
}
proc validateDrag {this x y} {
if {[llength $dataPieChart::($this,slices)]==0} {
return 1 ;# allow drag of empty viewer
}
# allow dragging if only from a selected slice
return [expr {\
[lsearch -exact [slice::selected $dataPieChart::($this,pie)] [slice::current $dataPieChart::($this,pie)]]>=0\
}]
}
proc supportedTypes {this} {
return {integer real}
}
proc monitorCell {this array row column} {
viewer::registerTrace $this $array
set cell ${array}($row,$column)
if {[lsearch -exact [cellsFromSlices $this $dataPieChart::($this,slices)] $cell]>=0} return ;# already charted, abort
set slice [new slice $dataPieChart::($this,pie) [viewer::label $array $row $column]]
lappend dataPieChart::($this,slices) $slice
switched::configure $slice -deletecommand "dataPieChart::deletedSlice $this $array $slice" ;# keep track of slice existence
set dataPieChart::($this,cell,$slice) $cell
}
proc update {this array args} { ;# update display using cells data. ignore eventual trace arguments
set cells [cellsFromSlices $this $dataPieChart::($this,slices)]
set sum 0.0 ;# force floating point calculations
foreach cell $cells {
catch {set sum [expr {$sum+[set $cell]}]} ;# ignore errors as data cell may no longer exist
}
foreach slice $dataPieChart::($this,slices) cell $cells {
if {[catch {set $cell} value]||($sum==0)} { ;# handle invalid cells and divide by zero errors
slice::update $slice 0 ?
} else {
set value [expr {[set $cell]/$sum}]
slice::update $slice $value "[format %.1f [expr {$value*100}]] %"
}
}
}
proc deletedSlice {this array slice} {
viewer::unregisterTrace $this $array ;# trace may no longer be needed on this array
ldelete dataPieChart::($this,slices) $slice
unset dataPieChart::($this,cell,$slice)
if {[llength $dataPieChart::($this,slices)]==0} {
delete $this ;# self destruct when there are no more elements
}
}
proc cellsFromSlices {this slices} {
set cells {}
foreach slice $slices {
lappend cells $dataPieChart::($this,cell,$slice)
}
return $cells
}
proc cells {this} {
return [cellsFromSlices $this $dataPieChart::($this,slices)]
}
}
class dataPieChart {
class slice { ;# provide wrapper for pie slice so that deletion through drag and drop works
proc slice {this pie label args} switched {$args} {
set ($this,pie) $pie
set slice [pie::newSlice $pie $label]
set ($this,slice) $slice
set (this,$slice) $this ;# keep track of slice wrapper object
switched::complete $this
}
proc ~slice {this} {
pie::deleteSlice [set ($this,pie)] [set ($this,slice)]
unset (this,[set ($this,slice)])
if {[string length $switched::($this,-deletecommand)]>0} {
uplevel #0 $switched::($this,-deletecommand) ;# always invoke command at global level
}
}
proc options {this} {
return [list\
[list -deletecommand {} {}]\
]
}
proc set-deletecommand {this value} {} ;# data is stored at switched level
proc update {this value string} {
pie::sizeSlice [set ($this,pie)] [set ($this,slice)] $value $string
}
proc selected {pie} { ;# return selected slices for specified pie
set list {}
foreach slice [pie::selectedSlices $pie] {
lappend list [set (this,$slice)]
}
return $list
}
proc current {pie} { ;# return current object (whose canvas slice is under the mouse cursor) if any
set slice [pie::currentSlice $pie]
if {$slice==0} {
return 0 ;# no current slice
} else {
return [set (this,$slice)] ;# return object corresponding with slice
}
}
}
}
class data2DPieChart {
proc data2DPieChart {this parentPath args} dataPieChart {$parentPath 0 -width 200 -height 220 $args} {}
proc ~data2DPieChart {this} {}
proc iconData {} {
return {
R0lGODdhKAAoAKUAAHt5e87PzgAAANbX1v///zFhIXNJAKX3e/ffSpznc+/XQozPY+fHOXvHWta2Mc6mKUJJQhBhe63X54y+1pTH3lKWrWumvVIIY2sYe4wQ
pb0o1qUYvbUYzq0Yzr0Y3t44/95B/+dJ/+dR/+dZ/9YY9+dh/94o/+9x/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAKAAoAAAG/kCAcEgsGo/IYQAgaDqf0Kh02lwKAthsYIDlbrVer3Y8ZgYI6DQaoG6z2+n3Gm09wwlyeN6t
flsHd3iBgoF5fmZJRAWLBQaOiUZ1hWiLB5YFCJkIjnxxdEyAdwCVlpeampxzngSSdwWlBwkJB5inCrcGqqp1R6+wsgu1t8MMDAZJf3C+lsALwcO3xdLHfZ9X
bcuxCc4JDQXR0g7i4rmryWq+stsL698K0uHk1ayIQ8vq3c7e8PEODw/l8AhpRSmWtgYN9O0rNq7hv4CHBIQikK7ZOoQFGDb09+/hLjNpXqljl3ABQm8OO6oE
+PGKvVj6TCpEubImQAhECL7iNvNk/iNHQIMGZRNxYgGeJk+ejCChadMJEqBSmDChQgSi1uxQPJBQqVKmTqE2nUrVglWs9CTaQ9jNK0KwTqNGpTrBbAScSkCG
bOsWrty5dO0KIUSQotulT5/SLSsYbWHDff8uDty4ZZQCh+FOZlzBqhQrFy5gGD0as1emmzlbJc0ag5UMsGPDNv12AtnFFnJ3jsBag2/fVjZwEE6cQwfaESbn
Xr6bdAcPHz5A/2Clg/Hr1jscLxBhuXfdVnmP7gCivHkQ1bWrX689QoTO8OG7Z00eRIj7+Ktr6LC/P4jnHniAgXsEEkhffeeZZ0WAIHjQoAggiCDhhB205px2
E2aY4YIiQHgA4YcaasheiCSKsOAIKKao4oostuiiFSSUIOOMNNZo4404wojjjjzuaIUJJpwg5JBEFmnkkUcuQcaSTDbZZBAAOw==
}
}
}
class data3DPieChart {
proc data3DPieChart {this parentPath args} dataPieChart {$parentPath 20 -width 250 -height 180 $args} {}
proc ~data3DPieChart {this} {}
proc iconData {} {
return {
R0lGODdhKAAoAKUAAHt5e87PzgAAANbX1v///zFhIXNJAKX3e/ffSu/XQufHOZznc9a2MY7PYc6mKRBhe63X55TH3oy+1lKWrUJJQk2SMDF5lFIIY2sYe4wQ
pb0o1qUYvbUYzr0Y3t44/60Yzt5B/+dJ/+dR/+dZ/9YY9+dh/94o/+9x/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAKAAoAAAG/kCAcEgsGo/IYQAgaDqf0Kh02lwKAthsYIDlbrVer3Y8ZgYI6DQaoG6z2+n3Gm09wwlyeN6t
flsHd3iBgoF5fmZJRAWLBQaOBolFdYMEjAeXBQiaCI99ngR/gYuXpAeZmwgJCo5zcXRmdwWlpAunmqoKCgwGhK11RrKzCwsNtrm6DMmQR6FqwbTDDbWpx8jJ
u5+Tac8H0sQN4Jm51+QMDry+TIDb0N/fBdblDvPohL9Cz9HE+8Xy8//0JMFCEwwcP34FzAFcSC+dgHWVLumTBi7co4sYWdkbWCkaRXfgHkAYSXJkhAgQJEx4
4HAJvo8wQ5YkeTKChJsrKRDR1tFb/sWfImfWvKlSwgM2hx5uK/DzW8WgKYcSnaDy6MYrSyn+lGny5E2bRVdaTTpgSIEKTLfKlOo17AMLD3Qq4XgWrdoGIonq
pUr1LVykr7ASrEA4LVC9YYv6/XvVzuDChh8k5qvYguWjgEExgVIX8qIHlPk+GL0YbhQrFy5gWI2hM2HCpGOXtgyXtW0rGXLrzuAaNu3fwGuv1kCcuJUNHJAr
57DodYXZwYVj6ODBA3UPVj5w0M6dA/PO0H+PZt0BhPnz2T+oX7++A6PwpG2fD0GffnYNH/Dr78CfPwbZ8dlW3nkEgmAFfyCU14EIIIjg4IO2sfYBeQ9WWOGB
IizYYIMWPlYIAnsfcNihhQeOYOKJKKao4oosWkFCCTDGKOOMNNZoo4s25qhjjlaYYMIJQAYp5JBEFlnkEmQkqeSSSwYBADs=
}
}
}
|