Thursday 5 August 2010

NSNumberformatter for special currency formats

Another day somebody asked me if it was possible with an NSNumberFormatter to format currency values like $1k , $1,02m etc.

So instead of displaying a value like $1,020,000 to display it as $1,02m

Now with a standard NSNumberFormatter its not possible, so you could create a custom formatter for that.

The following code snippet will do the job

- (NSString *) formatCurrencyValue: (double )doubleValue

{

NSNumberFormatter *nformat = [[NSNumberFormatter alloc] init];

[nformat setFormatterBehavior:NSNumberFormatterBehavior10_4];

[nformat setCurrencySymbol:[[NSLocale currentLocale] objectForKey: NSLocaleCurrencySymbol]];

[nformat setNumberStyle:NSNumberFormatterCurrencyStyle];

NSString *stringValue = nil;

NSArray *abbrevations = [NSArray arrayWithObjects:@"k", @"m", @"b", @"t", nil] ;

for (NSString *s in abbrevations)

{

doubleValue /= 1000.0 ;

if ( doubleValue < 1000.0 )

{

if ( (long long)doubleValue % (long long) 100 == 0 )

[nformat setMaximumFractionDigits:0];

else

[nformat setMaximumFractionDigits:2];

stringValue = [NSString stringWithFormat: @"%@%@", [nformat stringFromNumber: [NSNumber numberWithDouble: doubleValue]] , s] ;

break ;

}

}

[nformat release] ;

NSLog(@"Value = %@", stringValue);

return stringValue ;

}


Input :

[self formatCurrencyValue: 1235.0f] ;

[self formatCurrencyValue: 10351.0f] ;

[self formatCurrencyValue: 100522.0f] ;

[self formatCurrencyValue: 1235111.0f] ;

[self formatCurrencyValue: 12351234.0f] ;

[self formatCurrencyValue: 192351234.0f] ;

[self formatCurrencyValue: 1872351234.0f] ;

Output :

Value = £1.24k

Value = £10.35k

Value = £101k

Value = £1.24m

Value = £12.35m

Value = £192.35m

Value = £1.87b


Note : you can add additional parameters to the function like number of fraction digits

Telenet telemeter for iPhone/iPod

The telenet telemeter is now also available for the iPhone . Now also available for iPad
Some screenshots :



(Image below is from version 1.1, supports turbonet and fibernet)

Saturday 31 July 2010

Drawing text on a pie chart (Cocoa)

Drawing text along side a pie chart (see image below) is fairly simple :


You only need a bit of math.

Let's look a some code :

First you have your text :

NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"Helvetica" size:12], NSFontAttributeName,[NSColor blackColor], NSForegroundColorAttributeName, nil];

NSAttributedString * currentText=[[NSAttributedString alloc] initWithString: @"some text" attributes: attributes];


Then you need to figure out where you will put the text :

dot = NSMakePoint( size_x/2 + cos (PI * mid_angle / 180 ) * 50 , size_y/2 + sin ( PI * mid_angle / 180 ) * 50 ) ;

[greenPath appendBezierPathWithArcWithCenter: dot radius: 2 startAngle: 0 endAngle: 360 ] ;


(This is the dot you see in the picture above)


The mid_angle is the angle of slice divided by 2.


Then you draw the text :

textStartPoint = makeTextStartingPoint( [currentText size], bounds , mid_angle, 50 ) ;

[currentText drawAtPoint:textStartPoint];


The function makeTextStartingPoint looks like follows :


NSPoint makeTextStartingPoint( NSSize textSize, NSRect bounds , float angle, int offset )

{

NSPoint textStartPoint ;

float size_x = bounds.size.width ;

float size_y = bounds.size.height ;

float angle_radian = PI * angle / 180 ;

if ( angle <= 90 )

{

textStartPoint = NSMakePoint( size_x/2 + cos (angle_radian) * offset + 5 , size_y/2 + sin (angle_radian ) * offset ) ;

}

if ( angle > 90 && angle <= 180)

{

textStartPoint = NSMakePoint( size_x/2 + cos ( angle_radian ) * offset - textSize.width - 5 , size_y/2 + sin (angle_radian ) * offset ) ;

}

if ( angle > 180 && angle <= 270 )

{

textStartPoint = NSMakePoint( size_x/2 + cos ( angle_radian ) * offset - textSize.width - 5, size_y/2 + sin ( angle_radian ) * offset - textSize.height ) ;

}

if ( angle > 270 )

{

textStartPoint = NSMakePoint( size_x/2 + cos ( angle_radian ) * offset + 8 , size_y/2 + sin (angle_radian ) * offset - textSize.height ) ;

}

return textStartPoint ;

}


The reason I use an attributed string is because now I get the length of the text in pixels. You also see that the starting point is different from quadrant to quadrant.


Monday 21 June 2010

iSignals v2.0.2

Version 2.0.2 of iSignals is finally landed !

It's now compatible with iOS4, contains a subscription store, contains a lot of technical analysis charts etc.

It still has the possibility to follow more than 17000 instruments on 28 markets. You can receive buy/sell signals (with paid subscription) but you can do your own technical analysis.

The application supports MACD, MFI, EMA, SMA,TMA, Parabolic SAR, Bollingerbands,ROC, RSI, Slow and fast stochastic, Williams %R and the Chaikin Osscilator?

Some screenshots :






Instruction video of iSignals : http://www.youtube.com/watch?v=fd9nrEr-r7E




Friday 15 January 2010

a UISegmentedControl subclass that simulates checkboxes

I would like to share a small , possible, implementation of checkboxes on the iPhone using a UISegmentedControl subclass.

The UISegmentedControl is in fact a radiobutton over multiple possibilities, now in certain circumstances it could be usefull that you can select multiple items.
One possibility is to use a tableview, however in some cases this is overkill.

Suppose you have the following selection list :

In this list you want to be able to select multiple values like this (for example) :

Now to be able to do this , I wrote a small subclass of UISegmentedControl :

#import



@interface UIMultipleSelectionSegmentControl : UISegmentedControl  {


NSMutableSet  *indices ;

}

 @property( nonatomic,retain)   NSMutableSet *indices ;

  

@end



Now the trick is that you cannot use the private variables of the UISegmentedControl class, so the only possibility that one can use is to override the setSelectedSegmentIndex: and their do the actual implementation of multiple selections .

#import "UIMultipleSelectionSegmentControl.h"



@implementation UIMultipleSelectionSegmentControl


 

@synthesize indices ;

 

 


- (NSSet *) selectedSegmentIndices

{

return self.indices ;

}


- (void) setSelectedSegmentIndices: (NSSet *) aSet

{

NSEnumerator *enumerator = [aSet objectEnumerator];

NSNumber *value;

while ((value = [enumerator nextObject])) 

{

[self setSelectedSegmentIndex: [value integerValue]] ;

}

 

}




- (void) setSelectedSegmentIndex: (NSInteger) anIndex

{

 

if ( self.indices == nil ) self.indices = [NSMutableSet set] ;

 

if ( anIndex >= 0 )

{

NSNumber *indexNumber ;

UIImage *myImage ;

indexNumber = [NSNumber numberWithInt: anIndex] ;

 

if ( ! [self.indices containsObject: indexNumber] )

{

[self.indices addObject: indexNumber] ;

switch( anIndex )

{

case 0 :myImage = [UIImage imageNamed: @"segment-5-sel.png"] ; break ;

case 1 :myImage = [UIImage imageNamed: @"segment-10-sel.png"] ; break ;

case 2 :myImage = [UIImage imageNamed: @"segment-20-sel.png"] ; break ;

case 3 :myImage = [UIImage imageNamed: @"segment-50-sel.png"] ; break ;

case 4 :myImage = [UIImage imageNamed: @"segment-100-sel.png"] ; break ;

case 5: myImage = [UIImage imageNamed: @"segment-200-sel.png"] ; break ;

}

[super setSelectedSegmentIndex: anIndex] ;


}

else

{

  [self.indices removeObject: indexNumber] ;

[super setSelectedSegmentIndex: -indexNumber] ;

switch( anIndex )

{

case 0 :myImage = [UIImage imageNamed: @"segment-5.png"] ; break ;

case 1 :myImage = [UIImage imageNamed: @"segment-10.png"] ; break ;

case 2 :myImage = [UIImage imageNamed: @"segment-20.png"] ; break ;

case 3 :myImage = [UIImage imageNamed: @"segment-50.png"] ; break ;

case 4 :myImage = [UIImage imageNamed: @"segment-100.png"] ; break ;

case 5: myImage = [UIImage imageNamed: @"segment-200.png"] ; break ;

}

}


[self setImage: myImage forSegmentAtIndex: anIndex] ;

 

    }

}


- (void)dealloc {

    [indices release] ;

    [super dealloc];

}



@end



In this case I made images of each segment, one that represent the unselected image and one the represent the selected image.
(the images in my case are 24x24 pixels in size).

This subclass will still send UIControlChangeEvents, so it acts as a normal UIControl class.
To get the indices you have to call the method selectedSegmentIndices and to set them you use setSelectedSegmentIndices:.
(note that the indices are a NSSet).