-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
" | ||
A numerical legend for a scale | ||
" | ||
Class { | ||
#name : #SBAxisNotation, | ||
#superclass : #Morph, | ||
#instVars : [ | ||
'scale', | ||
'numberTicks' | ||
], | ||
#category : #'Sandblocks-Watch' | ||
} | ||
|
||
{ #category : #'initialize-release' } | ||
SBAxisNotation class >> newFromScale: aSBScale ticking: aNumber [ | ||
|
||
^ self new | ||
scale: aSBScale | ||
numberTicks: aNumber | ||
] | ||
|
||
{ #category : #initialization } | ||
SBAxisNotation >> initialize [ | ||
|
||
super initialize. | ||
|
||
numberTicks := 3. | ||
scale := SBScale newLinearScaleWithDomain: (0 to: 100) forRange: (0 to: 100). | ||
|
||
self color: Color transparent; | ||
layoutPolicy: ProportionalLayout new; | ||
hResizing: #shrinkWrap; | ||
vResizing: #spaceFill | ||
] | ||
|
||
{ #category : #accessing } | ||
SBAxisNotation >> numberTicks [ | ||
|
||
^ numberTicks | ||
] | ||
|
||
{ #category : #accessing } | ||
SBAxisNotation >> numberTicks: aNumber [ | ||
|
||
numberTicks := aNumber. | ||
|
||
self visualize | ||
] | ||
|
||
{ #category : #visualization } | ||
SBAxisNotation >> relativeTickHeights [ | ||
|
||
| section adjustedTicks | | ||
(self numberTicks < 2) ifTrue: [^#()]. | ||
|
||
"Starting count from 0 here instead of 1" | ||
adjustedTicks := self numberTicks - 1. | ||
section := 1 / adjustedTicks. | ||
^ (0 to: adjustedTicks) collect: [:i | (section * i)] | ||
] | ||
|
||
{ #category : #accessing } | ||
SBAxisNotation >> scale [ | ||
|
||
^ scale | ||
] | ||
|
||
{ #category : #accessing } | ||
SBAxisNotation >> scale: aSBScale [ | ||
|
||
scale := aSBScale. | ||
|
||
self visualize | ||
] | ||
|
||
{ #category : #accessing } | ||
SBAxisNotation >> scale: aSBScale numberTicks: aNumber [ | ||
|
||
scale := aSBScale. | ||
numberTicks := aNumber. | ||
|
||
self visualize | ||
] | ||
|
||
{ #category : #visualization } | ||
SBAxisNotation >> visualize [ | ||
|
||
self submorphs copy do: #abandon. | ||
self relativeTickHeights withIndexDo: [:aFraction :i | | annotation | | ||
annotation := SBOwnTextMorph new | ||
contents: ((self scale scaledValueOfRelative: aFraction) asString); | ||
layoutFrame: (LayoutFrame new topFraction: aFraction). | ||
"Fraction 1 will result in the text being just underneath ourself, so substract height as offset" | ||
(aFraction = 1) ifTrue: [annotation layoutFrame topOffset: (-1*(annotation minExtent y))]. | ||
self addMorph: annotation.] | ||
|
||
|
||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
" | ||
A scale inspired by their usage in d3. Define a domain from which a set of numbers gets projected to your defined range. Both are Interval objects. As operations like min or array accesses don't work on reversed ordered Intervals (eg meaning they're sorted descendingly), only ascending intervals work. | ||
A scale behavior is a block accepting a domain and a value to scale. The output is a percentage [0;1] representing its relative position in your domain. It can scale the value linear, logarithmic, exponentially etc. For an example, view class > linearScale. | ||
" | ||
Class { | ||
#name : #SBScale, | ||
#superclass : #Object, | ||
#instVars : [ | ||
'range', | ||
'domain', | ||
'scaleBehavior' | ||
], | ||
#category : #'Sandblocks-Watch' | ||
} | ||
|
||
{ #category : #scaleBehaviors } | ||
SBScale class >> linearScaleBehavior [ | ||
|
||
^ [:domain :value | ((value - domain min) / {domain extent. 1} max) abs] | ||
] | ||
|
||
{ #category : #'initialize-release' } | ||
SBScale class >> newLinearScaleWithDomain: aDomainInterval forRange: aRangeInterval [ | ||
|
||
^ self new | ||
domain: ( | ||
{aDomainInterval start. aDomainInterval stop} min | ||
to: {aDomainInterval start. aDomainInterval stop} max); | ||
range: ( | ||
{aRangeInterval start. aRangeInterval stop} min | ||
to: {aRangeInterval start. aRangeInterval stop} max); | ||
scaleBehavior: self linearScaleBehavior; | ||
yourself | ||
] | ||
|
||
{ #category : #'initialize-release' } | ||
SBScale class >> newWithDomain: aDomainInterval forRange: aRangeInterval scalingLike: aScaleBehavior [ | ||
|
||
^ self new | ||
domain: aDomainInterval; | ||
range: aRangeInterval; | ||
scaleBehavior: aScaleBehavior; | ||
yourself. | ||
] | ||
|
||
{ #category : #accessing } | ||
SBScale >> domain [ | ||
|
||
^ domain | ||
] | ||
|
||
{ #category : #accessing } | ||
SBScale >> domain: anInterval [ | ||
|
||
domain := anInterval | ||
] | ||
|
||
{ #category : #accessing } | ||
SBScale >> range [ | ||
|
||
^ range | ||
] | ||
|
||
{ #category : #accessing } | ||
SBScale >> range: anInterval [ | ||
|
||
range := anInterval | ||
] | ||
|
||
{ #category : #accessing } | ||
SBScale >> scaleBehavior [ | ||
|
||
^ scaleBehavior | ||
] | ||
|
||
{ #category : #accessing } | ||
SBScale >> scaleBehavior: aBlock [ | ||
|
||
scaleBehavior := aBlock | ||
] | ||
|
||
{ #category : #calculating } | ||
SBScale >> scaledValueOf: aNumberInDomain [ | ||
|
||
"In case the given number is the start of the domain, meaning always at 0% of total range, | ||
we might get a ZeroDivide during calculations, so catch the case early by return." | ||
(aNumberInDomain = self domain first) ifTrue: [^ self range first]. | ||
|
||
^ self range at: (self scaleBehavior value: self domain value: aNumberInDomain) * self range extent +1 | ||
] | ||
|
||
{ #category : #calculating } | ||
SBScale >> scaledValueOfRelative: aNumberFrom0To1 [ | ||
|
||
"LERP the given number in domain before proceeding normally" | ||
^ self scaledValueOf: ((1 - aNumberFrom0To1) * self domain min + aNumberFrom0To1 * self domain max) | ||
] |