Object subclass: #Visualization instanceVariableNames: 'data bars names heights heightsMax ' classVariableNames: '' poolDictionaries: '' category: 'Visualization'! !Visualization methodsFor: 'showing'! show | window composite numberOfBars | "Create the bars" bars := OrderedCollection new. 1 to: heights size do: [:i | | aBar | aBar := Bar new. aBar name: (names at: i). aBar height: (heights at: i) max: heightsMax. aBar index: i - 1. bars add: aBar]. numberOfBars := bars size. "Create the window and prepare the UI component framework" window := ScheduledWindow new. window minimumSize: 500 @ 200. window label: 'Bar Chart'. composite := CompositePart new. window component: composite. window open. "Create the graphics" Bar showAxes: composite withSize: 500 @ 200. bars do: [:aBar | aBar showOn: composite withSize: 500 / numberOfBars @ 200].! ! !Visualization methodsFor: 'initialization'! data: aDictionary "Connect this visualizer to a dictionary" data := aDictionary! forHeight: anItem "Height values to be used in creating the bars" heights := data at: anItem. heightsMax := heights first. heights do: [:each | heightsMax < each ifTrue: [heightsMax := each]]! setName: anItem "Remember where the names of the bars come from" names := data at: anItem! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! Visualization class instanceVariableNames: ''! !Visualization class methodsFor: 'demo'! demo "Prepare the database" | world v | world := Dictionary new. world at: #countries put: #(#China #Canada #Mexico #Russia #USA). world at: #areas put: #(9596960 9976140 1972550 17075200 9372610). world at: #populations put: #(1210004956 28820671 95772462 148178487 266476278). "Create the visualization window" v := Visualization new data: world. v setName: #countries. v forHeight: #areas. "v forColor: #populations." v show! ! Object subclass: #Bar instanceVariableNames: 'name index height heightsMax ' classVariableNames: '' poolDictionaries: '' category: 'Visualization'! !Bar methodsFor: 'showing'! showOn: composite withSize: bound "Create graphical objects on the UI component" | boundWidth boundHeight zeroLineY barWidth barHeight barX barY aBarShape boundX boundY aLabel labelWidth labelHeight labelX labelY | boundWidth := bound x. boundHeight := bound y. zeroLineY := boundHeight * 4 / 5. barWidth := boundWidth / 2. barHeight := (boundHeight * 3 / 5) * (height / heightsMax). barX := boundWidth / 4. barY := zeroLineY - barHeight. aBarShape := Rectangle origin: barX @ barY extent: barWidth @ barHeight. boundX := index * boundWidth. boundY := 0. composite add: aBarShape asFiller at: boundX @ boundY. "Display centered strings" aLabel := name asComposedText. labelWidth := aLabel width. labelX := boundX + (boundWidth / 2) - (labelWidth / 2). labelY := zeroLineY. composite add: aLabel at: labelX @ labelY. aLabel := height printString asComposedText. labelWidth := aLabel width. labelHeight := aLabel height. labelX := boundX + (boundWidth / 2) - (labelWidth / 2). labelY := zeroLineY - barHeight - labelHeight. composite add: aLabel at: labelX @ labelY.! ! !Bar methodsFor: 'accessing'! height ^height! height: aValue max: mValue height := aValue. heightsMax := mValue! index: anIndex index := anIndex! name ^name! name: aValue name := aValue! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! Bar class instanceVariableNames: ''! !Bar class methodsFor: 'showing'! showAxes: composite withSize: bound | boundWidth boundHeight | boundWidth := bound x. boundHeight := bound y. composite add: (LineSegment from: 0 @ 0 to: boundWidth @ 0) asVisualComponent at: 0 @ (boundHeight * 4 / 5)! !