Index: modules/tkpiechart/README ================================================================== --- modules/tkpiechart/README +++ modules/tkpiechart/README @@ -1,11 +1,11 @@ -Some people have asked for a Tcl/Tk pie utility: so here is my little -implementation with Tcl, not as an extension. +Tkpiechart is a Tcl only library which allows the creation of pies +with labels in Tcl canvases. -This is version 5.3. It was tested with Tcl8.0/Tk8.0, Tcl8.1/Tk8.1 and -the netscape plug-in 2.0, on both Linux and Windows platforms (it -should work on all Tcl/Tk supported platforms). +This is version 5.4. It was tested with Tcl8.0/Tk8.0 and the netscape +plug-in 2.0, on both Linux and Windows platforms (it should work on +all Tcl/Tk supported platforms). It is object oriented using the stooop (Simple Tcl Only Object Oriented Programming) extension (version 3.7 or above, tcl file included). @@ -22,6 +22,6 @@ If you find a bug in the Tcl code and correct it yourself, please email the modified code so I can include it in the next release. The same goes for improvements. Jean-Luc Fontaine -(http://www.multimania.com/jfontain/, mailto:jfontain@multimania.com) +(http://jfontain.free.fr/, mailto:jfontain@free.fr) Index: modules/tkpiechart/boxlabel.tcl ================================================================== --- modules/tkpiechart/boxlabel.tcl +++ modules/tkpiechart/boxlabel.tcl @@ -1,6 +1,6 @@ -set rcsId {$Id: boxlabel.tcl,v 1.41 1999/03/27 21:41:06 jfontain Exp $} +set rcsId {$Id: boxlabel.tcl,v 1.41.1.1 2000/03/05 20:55:56 jfontain Exp $} class pieBoxLabeler { proc pieBoxLabeler {this canvas args} pieLabeler {$canvas $args} switched {$args} { ::set pieBoxLabeler::($this,array) [::new canvasLabelsArray $canvas] @@ -45,13 +45,24 @@ canvasLabelsArray::delete $pieBoxLabeler::($this,array) $label unset pieBoxLabeler::($this,selected,$label) } proc set {this label value} { - regsub {:.*$} [switched::cget $label -text] ": $value" text + regsub {:[^:]*$} [switched::cget $label -text] ": $value" text ;# update string part after last semi-column switched::configure $label -text $text } + + proc label {this label args} { + ::set text [switched::cget $label -text] + if {[llength $args]==0} { + regexp {^(.*):} $text dummy text + return $text + } else { + regsub {^.*:} $text [lindex $args 0]: text ;# update string part before last semi-column + switched::configure $label -text $text + } + } proc selectState {this label {selected {}}} { if {[string length $selected]==0} { ;# return current state if no argument return $pieBoxLabeler::($this,selected,$label) } DELETED modules/tkpiechart/canlabel.tcl Index: modules/tkpiechart/canlabel.tcl ================================================================== --- modules/tkpiechart/canlabel.tcl +++ /dev/null @@ -1,144 +0,0 @@ -set rcsId {$Id: canlabel.tcl,v 1.25 1999/03/30 20:11:01 jfontain Exp $} - -class canvasLabel { - - proc canvasLabel {this canvas args} switched {$args} { - set canvasLabel::($this,canvas) $canvas - # use an empty image as an origin marker with only 2 coordinates - set canvasLabel::($this,origin) [$canvas create image 0 0 -tags canvasLabel($this)] - set canvasLabel::($this,rectangle) [$canvas create rectangle 0 0 0 0 -tags canvasLabel($this)] - # select rectangle is on top for default box style - set canvasLabel::($this,selectRectangle) [$canvas create rectangle 0 0 0 0 -tags canvasLabel($this)] - set canvasLabel::($this,text) [$canvas create text 0 0 -tags canvasLabel($this)] - switched::complete $this - } - - proc ~canvasLabel {this} { - $canvasLabel::($this,canvas) delete canvasLabel($this) - } - - proc options {this} { - # force font for proper initialization - return [list\ - [list -anchor center center]\ - [list -background {} {}]\ - [list -bordercolor black black]\ - [list -borderwidth 1 1]\ - [list -bulletwidth 10 10]\ - [list -font {Helvetica -12}]\ - [list -foreground black black]\ - [list -justify left left]\ - [list -padding 2 2]\ - [list -scale {1 1} {1 1}]\ - [list -select 0 0]\ - [list -selectcolor white white]\ - [list -stipple {} {}]\ - [list -style box box]\ - [list -text {} {}]\ - [list -width 0 0]\ - ] - } - - proc set-background {this value} { - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -fill $value - } - proc set-bordercolor {this value} { - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -outline $value - if {[string compare $switched::($this,-style) box]==0} { - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,selectRectangle) -outline $value - } - } - proc set-borderwidth {this value} { - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,selectRectangle) -width $value - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -width $value - update $this - } - proc set-foreground {this value} { - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,text) -fill $value - } - proc set-scale {this value} { ;# value is a list of ratios of the horizontal and vertical axis - update $this ;# refresh display which takes new scale into account - } - proc set-stipple {this value} { - $canvasLabel::($this,canvas) itemconfigure $canvasLabel::($this,rectangle) -stipple $value - } - proc set-style {this value} { - switch $value { - box { - $canvasLabel::($this,canvas) raise $canvasLabel::($this,selectRectangle) $canvasLabel::($this,rectangle) - } - split { - $canvasLabel::($this,canvas) lower $canvasLabel::($this,selectRectangle) $canvasLabel::($this,rectangle) - } - default { - error "bad style value \"$value\": must be box or split" - } - } - update $this - } - foreach option {-anchor -bulletwidth -padding -select -selectcolor} { - proc set$option {this value} {update $this} - } - foreach option {-font -justify -text -width} { - proc set$option {this value} " - \$canvasLabel::(\$this,canvas) itemconfigure \$canvasLabel::(\$this,text) $option \$value - update \$this - " - } - - proc update {this} { - set canvas $canvasLabel::($this,canvas) - set rectangle $canvasLabel::($this,rectangle) - set selectRectangle $canvasLabel::($this,selectRectangle) - set text $canvasLabel::($this,text) - - foreach {x y} [$canvas coords $canvasLabel::($this,origin)] {} - - set border [$canvas itemcget $rectangle -width] - set textBox [$canvas bbox $text] - set padding [winfo fpixels $canvas $switched::($this,-padding)] - set bulletWidth [winfo fpixels $canvas $switched::($this,-bulletwidth)] - - $canvas itemconfigure $selectRectangle -fill {} -outline {} - set split [expr {[string compare $switched::($this,-style) split]==0}] - - # position rectangle and text as if anchor was center (the default) - if {$split} { ;# split style - set halfWidth [expr {($bulletWidth+$border+$padding+([lindex $textBox 2]-[lindex $textBox 0]))/2.0}] - set halfHeight [expr {(([lindex $textBox 3]-[lindex $textBox 1])/2.0)+$border}] - } else { ;# box style - set width [expr {$switched::($this,-width)==0?[lindex $textBox 2]-[lindex $textBox 0]:$switched::($this,-width)}] - set halfWidth [expr {$bulletWidth+$border+$padding+($width/2.0)}] - set halfHeight [expr {(([lindex $textBox 3]-[lindex $textBox 1])/2.0)+$border+$padding}] - } - set left [expr {$x-$halfWidth}] - set top [expr {$y-$halfHeight}] - set right [expr {$x+$halfWidth}] - set bottom [expr {$y+$halfHeight}] - $canvas coords $text [expr {$x+(($bulletWidth+$border+$padding)/2.0)}] $y - if {$split} { - $canvas coords $selectRectangle $left $top $right $bottom - $canvas coords $rectangle $left $top [expr {$left+$bulletWidth}] $bottom - if {$switched::($this,-select)} { - $canvas itemconfigure $selectRectangle\ - -fill $switched::($this,-selectcolor) -outline $switched::($this,-selectcolor) - } - } else { - $canvas coords $selectRectangle $left $top [expr {$left+$bulletWidth}] $bottom - $canvas coords $rectangle $left $top $right $bottom - $canvas itemconfigure $selectRectangle -outline $switched::($this,-bordercolor) - if {$switched::($this,-select)} { - $canvas itemconfigure $selectRectangle -fill $switched::($this,-selectcolor) - } - } - - set anchor $switched::($this,-anchor) ;# now move rectangle and text according to anchor - set xDelta [expr {([string match *w $anchor]-[string match *e $anchor])*$halfWidth}] - set yDelta [expr {([string match n* $anchor]-[string match s* $anchor])*$halfHeight}] - $canvas move $rectangle $xDelta $yDelta - $canvas move $selectRectangle $xDelta $yDelta - $canvas move $text $xDelta $yDelta - eval $canvas scale canvasLabel($this) $x $y $switched::($this,-scale) ;# finally apply scale - } - -} Index: modules/tkpiechart/labarray.tcl ================================================================== --- modules/tkpiechart/labarray.tcl +++ modules/tkpiechart/labarray.tcl @@ -1,6 +1,6 @@ -set rcsId {$Id: labarray.tcl,v 1.20 1998/06/07 13:47:02 jfontain Exp $} +set rcsId {$Id: labarray.tcl,v 1.20.1.2 2000/04/06 19:34:36 jfontain Exp $} class canvasLabelsArray { proc canvasLabelsArray {this canvas args} switched {$args} { set canvasLabelsArray::($this,canvas) $canvas @@ -62,43 +62,49 @@ } } proc position {this label index} { set canvas $canvasLabelsArray::($this,canvas) - foreach {x y} [$canvas coords $canvasLabelsArray::($this,origin)] {} - set coordinates [$canvas bbox canvasLabel($label)] - set y [expr {$y+(($index/2)*([lindex $coordinates 3]-[lindex $coordinates 1]))}] ;# take label height into account - + set column [expr {$index%2}] switch $switched::($this,-justify) { ;# arrange labels in two columns left { - set x [expr {$x+(($index%2)*($canvasLabelsArray::($this,width)/2.0))}] + set x [expr {$x+($column*($canvasLabelsArray::($this,width)/2.0))}] set anchor nw } right { - set x [expr {$x+((($index%2)+1)*($canvasLabelsArray::($this,width)/2.0))}] + set x [expr {$x+(($column+1)*($canvasLabelsArray::($this,width)/2.0))}] set anchor ne } default { ;# should be center - set x [expr {$x+((1.0+(2*($index%2)))*$canvasLabelsArray::($this,width)/4)}] + set x [expr {$x+((1.0+(2*$column))*$canvasLabelsArray::($this,width)/4)}] set anchor n } } + set y [expr {$y+[columnHeight $this $column [expr {$index/2}]]}] switched::configure $label -anchor $anchor foreach {xDelta yDelta} [$canvas coords canvasLabel($label)] {} ;# do an absolute positioning using label tag $canvas move canvasLabel($label) [expr {$x-$xDelta}] [expr {$y-$yDelta}] } proc labels {this} { return $canvasLabelsArray::($this,labels) } - proc height {this} { - set number [llength $canvasLabelsArray::($this,labels)] - if {$number==0} { - return 0 - } - set coordinates [$canvasLabelsArray::($this,canvas) bbox canvasLabel([lindex $canvasLabelsArray::($this,labels) 0])] - return [expr {(($number+1)/2)*([lindex $coordinates 3]-[lindex $coordinates 1])}] - } + proc columnHeight {this column {rows 2147483647}} { ;# column must be either 0 or 1 + set canvas $canvasLabelsArray::($this,canvas) + set length [llength $canvasLabelsArray::($this,labels)] + set height 0 + for {set index $column; set row 0} {($index<$length)&&($row<$rows)} {incr index 2; incr row} { + set coordinates [$canvas bbox canvasLabel([lindex $canvasLabelsArray::($this,labels) $index])] + incr height [expr {[lindex $coordinates 3]-[lindex $coordinates 1]}] + } + return $height + } + + proc height {this} { + return [maximum [columnHeight $this 0] [columnHeight $this 1]] + } + + proc maximum {a b} {return [expr {$a>$b?$a:$b}]} } DELETED modules/tkpiechart/objselec.tcl Index: modules/tkpiechart/objselec.tcl ================================================================== --- modules/tkpiechart/objselec.tcl +++ /dev/null @@ -1,32 +0,0 @@ -# copyright (C) 1997-98 Jean-Luc Fontaine (mailto:jfontain@multimania.com) -# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu - -set rcsId {$Id: objselec.tcl,v 1.7 1999/01/31 18:53:01 jfontain Exp $} - -# implements selection on a list of object identifiers (sortable list of integer), for a listbox implementation, for example - -class objectSelector { - - proc objectSelector {this args} selector {$args} {} - - proc ~objectSelector {this} {} - - ### public procedures follow: - - proc extend {this id} { - if {[info exists selector::($this,lastSelected)]} { - set list [lsort -integer [selector::list $this]] - set last [lsearch -exact $list $selector::($this,lastSelected)] - set index [lsearch -exact $list $id] - selector::clear $this - if {$index>$last} { - selector::set $this [lrange $list $last $index] 1 - } else { - selector::set $this [lrange $list $index $last] 1 - } - } else { - selector::select $this $id - } - } - -} Index: modules/tkpiechart/perilabel.tcl ================================================================== --- modules/tkpiechart/perilabel.tcl +++ modules/tkpiechart/perilabel.tcl @@ -1,6 +1,6 @@ -set rcsId {$Id: perilabel.tcl,v 1.47 1999/03/24 21:57:40 jfontain Exp $} +set rcsId {$Id: perilabel.tcl,v 1.47.1.1 2000/03/05 21:04:00 jfontain Exp $} class piePeripheralLabeler { variable PI 3.14159265358979323846 @@ -74,10 +74,18 @@ proc set {this label value} { ::set text $piePeripheralLabeler::($this,textItem,$label) position $this $text $piePeripheralLabeler::($this,slice,$label) $pieLabeler::($this,canvas) itemconfigure $text -text $value } + + proc label {this label args} { + if {[llength $args]==0} { + return [switched::cget $label -text] + } else { + switched::configure $label -text [lindex $args 0] + } + } proc position {this text slice} { ;# place the value text item next to the outter border of the corresponding slice variable PI slice::data $slice data ;# retrieve current slice position and dimensions Index: modules/tkpiechart/pie.tcl ================================================================== --- modules/tkpiechart/pie.tcl +++ modules/tkpiechart/pie.tcl @@ -1,8 +1,8 @@ -set rcsId {$Id: pie.tcl,v 1.85 1999/03/27 21:41:51 jfontain Exp $} +set rcsId {$Id: pie.tcl,v 1.85.1.3 2000/04/06 19:29:27 jfontain Exp $} -package provide tkpiechart 5.3 +package provide tkpiechart 5.4.1 class pie { set pie::(colors) {#7FFFFF #7FFF7F #FF7F7F #FFFF7F #7F7FFF #FFBF00 #BFBFBF #FF7FFF #FFFFFF} } @@ -199,10 +199,15 @@ set value [expr {-1*$growth}] ;# finally move the following slices foreach slice [lrange $pie::($this,slices) [incr index] end] { slice::rotate $slice $value } } + +proc pie::labelSlice {this slice text} { + pieLabeler::label $pie::($this,labeler) $pie::($this,sliceLabel,$slice) $text + update $this ;# necessary if number of lines in label changes +} proc pie::selectedSlices {this} { ;# return a list of currently selected slices set list {} foreach slice $pie::($this,slices) { if {[pieLabeler::selectState $pie::($this,labeler) $pie::($this,sliceLabel,$slice)]} { @@ -245,11 +250,11 @@ [expr {\ ($pie::($this,height)-$room(top)-$room(bottom)-$pie::($this,titleRoom))/\ ($pie::($this,initialHeight)+$pie::($this,thickness))\ }]\ ] - switched::configure $pie::($this,backgroundSlice) -scale $scale ;# update scale of background slice, + switched::configure $pie::($this,backgroundSlice) -scale $scale ;# update scale of background slice foreach slice $pie::($this,slices) { switched::configure $slice -scale $scale ;# and other slices } if {$pie::($this,titleRoom)>0} { ;# title exists $canvas coords $pie::($this,title) [expr {$x+($pie::($this,width)/2)}] $y ;# place text above pie and centered Index: modules/tkpiechart/pielabel.tcl ================================================================== --- modules/tkpiechart/pielabel.tcl +++ modules/tkpiechart/pielabel.tcl @@ -1,6 +1,6 @@ -set rcsId {$Id: pielabel.tcl,v 1.40 1998/06/07 10:07:30 jfontain Exp $} +set rcsId {$Id: pielabel.tcl,v 1.40.1.1 2000/03/05 20:54:00 jfontain Exp $} class pieLabeler { set pieLabeler::(default,font) {Helvetica -12} @@ -13,14 +13,16 @@ virtual proc new {this slice args} ;# must return a canvasLabel virtual proc delete {this label} virtual proc set {this label value} + + virtual proc label {this args} ;# set or get label if no arguments virtual proc selectState {this label {state {}}} # must be invoked only by pie, which knows when it is necessary to update (new or deleted label) virtual proc update {this left top right bottom} virtual proc room {this arrayName} } Index: modules/tkpiechart/selector.tcl ================================================================== --- modules/tkpiechart/selector.tcl +++ modules/tkpiechart/selector.tcl @@ -1,6 +1,6 @@ -set rcsId {$Id: selector.tcl,v 1.4 1999/08/16 20:59:03 jfontain Exp $} +set rcsId {$Id: selector.tcl,v 1.4.1.1 2000/07/30 19:47:35 jfontain Exp $} # implements generic selection on a list of unique identifiers class selector { @@ -98,12 +98,12 @@ ::set deselect {} foreach index $indices { if {[::set ${this}selected($index)]} { lappend deselect $index ::set ${this}selected($index) 0 - if {$index==$selector::($this,lastSelected)} { - ::unset selector::($this,lastSelected) ;# nothing is left selected + if {[info exists selector::($this,lastSelected)]&&($index==$selector::($this,lastSelected))} { + ::unset selector::($this,lastSelected) ;# too complicated to find out what was selected last } } else { lappend select $index ::set ${this}selected($index) 1 ::set selector::($this,lastSelected) $index ;# keep track of last selected object for extension DELETED modules/tkpiechart/slice.tcl Index: modules/tkpiechart/slice.tcl ================================================================== --- modules/tkpiechart/slice.tcl +++ /dev/null @@ -1,234 +0,0 @@ -set rcsId {$Id: slice.tcl,v 1.39 1998/06/07 10:19:25 jfontain Exp $} - - -class slice { - variable PI 3.14159265358979323846 -} - -proc slice::slice {this canvas xRadius yRadius args} switched {$args} { ;# all dimensions must be in pixels - # note: all slice elements are tagged with slice($this) - set slice::($this,canvas) $canvas - set slice::($this,xRadius) $xRadius - set slice::($this,yRadius) $yRadius - switched::complete $this - complete $this ;# wait till all options have been set for initial configuration - update $this -} - -proc slice::~slice {this} { - if {[string length $switched::($this,-deletecommand)]>0} { ;# always invoke command at global level - uplevel $switched::($this,-deletecommand) - } - $slice::($this,canvas) delete slice($this) -} - -proc slice::options {this} { - return [list\ - [list -bottomcolor {} {}]\ - [list -deletecommand {} {}]\ - [list -height 0 0]\ - [list -scale {1 1} {1 1}]\ - [list -startandextent {0 0} {0 0}]\ - [list -topcolor {} {}]\ - ] -} - -foreach option {-bottomcolor -height -topcolor} { ;# no dynamic options allowed: see complete - proc slice::set$option {this value} " - if {\$switched::(\$this,complete)} { - error {option $option cannot be set dynamically} - } - " -} - -proc slice::set-deletecommand {this value} {} ;# data is stored at switched level - -proc slice::set-scale {this value} { - if {$switched::($this,complete)} { - update $this ;# requires initialization to be complete - } -} - -proc slice::set-startandextent {this value} { - foreach {start extent} $value {} - set slice::($this,start) [normalizedAngle $start] - if {$extent<0} { - set slice::($this,extent) 0 ;# a negative extent is meaningless - } elseif {$extent>=360} { ;# get as close as possible to 360, which would not work as it is equivalent to 0 - set slice::($this,extent) [expr {360-pow(10,-$::tcl_precision+3)}] - } else { - set slice::($this,extent) $extent - } - if {$switched::($this,complete)} { - update $this ;# requires initialization to be complete - } -} - -proc slice::normalizedAngle {value} { ;# normalize value between -180 and 180 degrees (not included) - while {$value>=180} { - set value [expr {$value-360}] - } - while {$value<-180} { - set value [expr {$value+360}] - } - return $value -} - -proc slice::complete {this} { - set canvas $slice::($this,canvas) - set xRadius $slice::($this,xRadius) - set yRadius $slice::($this,yRadius) - set bottomColor $switched::($this,-bottomcolor) - # use an empty image as an origin marker with only 2 coordinates - set slice::($this,origin) [$canvas create image -$xRadius -$yRadius -tags slice($this)] - if {$switched::($this,-height)>0} { ;# 3D - set slice::($this,startBottomArcFill) [$canvas create arc\ - 0 0 0 0 -style chord -extent 0 -fill $bottomColor -outline $bottomColor -tags slice($this)\ - ] - set slice::($this,startPolygon) [$canvas create polygon 0 0 0 0 0 0 -fill $bottomColor -tags slice($this)] - set slice::($this,startBottomArc) [$canvas create arc 0 0 0 0 -style arc -extent 0 -fill black -tags slice($this)] - - set slice::($this,endBottomArcFill) [$canvas create arc\ - 0 0 0 0 -style chord -extent 0 -fill $bottomColor -outline $bottomColor -tags slice($this)\ - ] - set slice::($this,endPolygon) [$canvas create polygon 0 0 0 0 0 0 -fill $bottomColor -tags slice($this)] - set slice::($this,endBottomArc) [$canvas create arc 0 0 0 0 -style arc -extent 0 -fill black -tags slice($this)] - - set slice::($this,startLeftLine) [$canvas create line 0 0 0 0 -tags slice($this)] - set slice::($this,startRightLine) [$canvas create line 0 0 0 0 -tags slice($this)] - set slice::($this,endLeftLine) [$canvas create line 0 0 0 0 -tags slice($this)] - set slice::($this,endRightLine) [$canvas create line 0 0 0 0 -tags slice($this)] - } - set slice::($this,topArc) [$canvas create arc\ - -$xRadius -$yRadius $xRadius $yRadius -fill $switched::($this,-topcolor) -tags slice($this)\ - ] - $canvas move slice($this) $xRadius $yRadius ;# move slice so upper-left corner is at requested coordinates -} - -proc slice::update {this} { - set canvas $slice::($this,canvas) - set coordinates [$canvas coords $slice::($this,origin)] ;# first store slice position in case it was moved as a whole - set xRadius $slice::($this,xRadius) - set yRadius $slice::($this,yRadius) - $canvas coords $slice::($this,origin) -$xRadius -$yRadius - $canvas coords $slice::($this,topArc) -$xRadius -$yRadius $xRadius $yRadius - $canvas itemconfigure $slice::($this,topArc) -start $slice::($this,start) -extent $slice::($this,extent) - if {$switched::($this,-height)>0} { ;# 3D - updateBottom $this - } - # now position slice at the correct coordinates - $canvas move slice($this) [expr {[lindex $coordinates 0]+$xRadius}] [expr {[lindex $coordinates 1]+$yRadius}] - eval $canvas scale slice($this) $coordinates $switched::($this,-scale) ;# finally apply scale -} - -proc slice::updateBottom {this} { - variable PI - - set start $slice::($this,start) - set extent $slice::($this,extent) - - set canvas $slice::($this,canvas) - set xRadius $slice::($this,xRadius) - set yRadius $slice::($this,yRadius) - set height $switched::($this,-height) - - $canvas itemconfigure $slice::($this,startBottomArcFill) -extent 0 ;# first make all bottom parts invisible - $canvas coords $slice::($this,startBottomArcFill) -$xRadius -$yRadius $xRadius $yRadius - $canvas move $slice::($this,startBottomArcFill) 0 $height - $canvas itemconfigure $slice::($this,startBottomArc) -extent 0 - $canvas coords $slice::($this,startBottomArc) -$xRadius -$yRadius $xRadius $yRadius - $canvas move $slice::($this,startBottomArc) 0 $height - $canvas coords $slice::($this,startLeftLine) 0 0 0 0 - $canvas coords $slice::($this,startRightLine) 0 0 0 0 - $canvas itemconfigure $slice::($this,endBottomArcFill) -extent 0 - $canvas coords $slice::($this,endBottomArcFill) -$xRadius -$yRadius $xRadius $yRadius - $canvas move $slice::($this,endBottomArcFill) 0 $height - $canvas itemconfigure $slice::($this,endBottomArc) -extent 0 - $canvas coords $slice::($this,endBottomArc) -$xRadius -$yRadius $xRadius $yRadius - $canvas move $slice::($this,endBottomArc) 0 $height - $canvas coords $slice::($this,endLeftLine) 0 0 0 0 - $canvas coords $slice::($this,endRightLine) 0 0 0 0 - $canvas coords $slice::($this,startPolygon) 0 0 0 0 0 0 0 0 - $canvas coords $slice::($this,endPolygon) 0 0 0 0 0 0 0 0 - - set startX [expr {$xRadius*cos($start*$PI/180)}] - set startY [expr {-$yRadius*sin($start*$PI/180)}] - set end [normalizedAngle [expr {$start+$extent}]] - set endX [expr {$xRadius*cos($end*$PI/180)}] - set endY [expr {-$yRadius*sin($end*$PI/180)}] - - set startBottom [expr {$startY+$height}] - set endBottom [expr {$endY+$height}] - - if {(($start>=0)&&($end>=0))||(($start<0)&&($end<0))} { ;# start and end angles are on the same side of the 0 abscissa - if {$extent<=180} { ;# slice size is less than half pie - if {$start<0} { ;# slice is facing viewer, so bottom is visible - $canvas itemconfigure $slice::($this,startBottomArcFill) -start $start -extent $extent - $canvas itemconfigure $slice::($this,startBottomArc) -start $start -extent $extent - # only one polygon is needed - $canvas coords $slice::($this,startPolygon) $startX $startY $endX $endY $endX $endBottom $startX $startBottom - $canvas coords $slice::($this,startLeftLine) $startX $startY $startX $startBottom - $canvas coords $slice::($this,startRightLine) $endX $endY $endX $endBottom - } ;# else only top is visible - } else { ;# slice size is more than half pie - if {$start<0} { ;# slice opening is facing viewer, so bottom is in 2 parts - $canvas itemconfigure $slice::($this,startBottomArcFill) -start 0 -extent $start - $canvas itemconfigure $slice::($this,startBottomArc) -start 0 -extent $start - $canvas coords $slice::($this,startPolygon) $startX $startY $xRadius 0 $xRadius $height $startX $startBottom - $canvas coords $slice::($this,startLeftLine) $startX $startY $startX $startBottom - $canvas coords $slice::($this,startRightLine) $xRadius 0 $xRadius $height - - set bottomArcExtent [expr {$end+180}] - $canvas itemconfigure $slice::($this,endBottomArcFill) -start -180 -extent $bottomArcExtent - $canvas itemconfigure $slice::($this,endBottomArc) -start -180 -extent $bottomArcExtent - $canvas coords $slice::($this,endPolygon) -$xRadius 0 $endX $endY $endX $endBottom -$xRadius $height - $canvas coords $slice::($this,endLeftLine) -$xRadius 0 -$xRadius $height - $canvas coords $slice::($this,endRightLine) $endX $endY $endX $endBottom - } else { ;# slice back is facing viewer, so bottom occupies half the pie - $canvas itemconfigure $slice::($this,startBottomArcFill) -start 0 -extent -180 - $canvas itemconfigure $slice::($this,startBottomArc) -start 0 -extent -180 - # only one polygon is needed - $canvas coords $slice::($this,startPolygon) -$xRadius 0 $xRadius 0 $xRadius $height -$xRadius $height - $canvas coords $slice::($this,startLeftLine) -$xRadius 0 -$xRadius $height - $canvas coords $slice::($this,startRightLine) $xRadius 0 $xRadius $height - } - } - } else { ;# start and end angles are on opposite sides of the 0 abscissa - if {$start<0} { ;# slice start is facing viewer - $canvas itemconfigure $slice::($this,startBottomArcFill) -start 0 -extent $start - $canvas itemconfigure $slice::($this,startBottomArc) -start 0 -extent $start - # only one polygon is needed - $canvas coords $slice::($this,startPolygon) $startX $startY $xRadius 0 $xRadius $height $startX $startBottom - $canvas coords $slice::($this,startLeftLine) $startX $startY $startX $startBottom - $canvas coords $slice::($this,startRightLine) $xRadius 0 $xRadius $height - } else { ;# slice end is facing viewer - set bottomArcExtent [expr {$end+180}] - $canvas itemconfigure $slice::($this,endBottomArcFill) -start -180 -extent $bottomArcExtent - $canvas itemconfigure $slice::($this,endBottomArc) -start -180 -extent $bottomArcExtent - # only one polygon is needed - $canvas coords $slice::($this,endPolygon) -$xRadius 0 $endX $endY $endX $endBottom -$xRadius $height - $canvas coords $slice::($this,startLeftLine) -$xRadius 0 -$xRadius $height - $canvas coords $slice::($this,startRightLine) $endX $endY $endX $endBottom - } - } -} - -proc slice::rotate {this angle} { - if {$angle==0} return - set slice::($this,start) [normalizedAngle [expr {$slice::($this,start)+$angle}]] - update $this -} - -proc slice::data {this arrayName} { ;# return actual sizes and positions after scaling - upvar $arrayName data - - set data(start) $slice::($this,start) - set data(extent) $slice::($this,extent) - foreach {x y} $switched::($this,-scale) {} - set data(xRadius) [expr {$x*$slice::($this,xRadius)}] - set data(yRadius) [expr {$y*$slice::($this,yRadius)}] - set data(height) [expr {$y*$switched::($this,-height)}] - foreach {x y} [$slice::($this,canvas) coords $slice::($this,origin)] {} - set data(xCenter) [expr {$x+$data(xRadius)}] - set data(yCenter) [expr {$y+$data(yRadius)}] -}