點擊柱狀圖中的 柱 可擷取 該柱的編號(從左至右,0-n)
能自動調整 柱 的寬度以及各 柱 之間的間隔
1 //
2 // NTChartView.m
3 // chart
4 //
5 // Created by wml on 11-04-10.
6 // Copyright 2009 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "NTChartView.h"
10 #import "Alerter.h"
11 #import "Rectangle.h"
12
13 static int MARGIN_LEFT = 50;
14 static int MARGIN_BOTTOM = 30;
15 static int MARGIN_TOP = 20;
16 static int SHOW_SCALE_NUM = 7;
17 static int WIDTH = 300;
18 static int HEIGHT = 300;
19
20 @interface NTChartView(private)
21 -(void)drawColumn:(CGContextRef)context rect:(CGRect)_rect;
22 -(void)drawScale:(CGContextRef)context rect:(CGRect)_rect;
23 -(void)calcScales:(CGRect)_rect;
24 @end
25
26 @implementation NTChartView
27 @synthesize groupData;
28 @synthesize groupRect;
29 @synthesize frstTouch;
30 @synthesize scndTouch;
31
32 - (void) dealloc
33 {
34 [groupRect release];
35 [groupData release];
36 [super dealloc];
37 }
38
39
40 -(void)drawRect:(CGRect)_rect{
41 WIDTH = _rect.size.width;
42 HEIGHT = _rect.size.height;
43 groupRect = [[NSMutableArray alloc] init];
44 MARGIN_LEFT = WIDTH/6.0;
45 MARGIN_BOTTOM = HEIGHT/10.0;
46 MARGIN_TOP = HEIGHT/15.0;
47
48 // the _rect is the Canvas on which the bar chart should be painted
49
50 //繪圖上下文
51 CGContextRef context = UIGraphicsGetCurrentContext();
52 //設定畫筆顏色
53 CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
54 //為該矩形填充顏色
55 CGContextFillRect(context, _rect);
56
57 //計算刻度
58 [self calcScales:_rect];
59 //畫刻度
60 [self drawScale:context rect:_rect];
61 //畫柱
62 [self drawColumn:context rect:_rect];
63
64 }
65
66 -(void)drawScale:(CGContextRef)context rect:(CGRect)_rect{
67
68 //the coordinate axis
69 CGPoint points[3];
70 // the top "end" of the y-axis
71 points[0] = CGPointMake(MARGIN_LEFT - WIDTH/30, MARGIN_TOP);
72 // the coordinate center
73 points[1] = CGPointMake(MARGIN_LEFT -WIDTH/30, _rect.size.height - MARGIN_BOTTOM + 1);
74 // the right "end" of x-axis
75 points[2] = CGPointMake(_rect.size.width - WIDTH/30, _rect.size.height - MARGIN_BOTTOM + 1);
76 CGContextSetAllowsAntialiasing(context, NO);
77 CGContextAddLines(context, points, 3);
78 //the color of the scale number
79 CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
80
81 for(int i=1;i<SHOW_SCALE_NUM + 1; i++){
82 maxScaleHeight = (_rect.size.height - MARGIN_BOTTOM) * ( i ) / (SHOW_SCALE_NUM + 1);
83 int vScal = ceil(1.0 * maxScaleValue / (SHOW_SCALE_NUM ) * (i ));
84 //the y-axis value of the current scale
85 float y = (_rect.size.height - MARGIN_BOTTOM) - maxScaleHeight;
86
87 NSString *scaleStr = [NSString stringWithFormat:@"%d",vScal];
88
89 [scaleStr drawAtPoint:CGPointMake(MARGIN_LEFT - WIDTH/15.0 - [scaleStr sizeWithFont:[UIFont systemFontOfSize:10]].width, y - 7) withFont:[UIFont systemFontOfSize:10]];
90 //the short line to the right of the scale number
91 points[0] = CGPointMake(MARGIN_LEFT - WIDTH/30.0, y);// one end of the line
92 points[1] = CGPointMake(MARGIN_LEFT - WIDTH/30.0-3, y);// another end
93 CGContextSetLineDash(context, 0, NULL, 0);
94 CGContextAddLines(context, points, 2);
95
96 //draw those defined before
97 CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
98 CGContextDrawPath(context, kCGPathStroke);
99
100 //the horizontal referring line
101 points[0] = CGPointMake(MARGIN_LEFT - WIDTH/30.0, y);
102 points[1] = CGPointMake(_rect.size.width - WIDTH/30.0 , y);
103 //the length of the painted line segments and unpainted
104 //{2,3} means a dotted line with the painted segments of length 2 pixel and ...
105 float partren[] = {2,3};
106 CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:.9 green:.3 blue:.3 alpha:1].CGColor);
107
108 CGContextSetLineDash(context, 0,partren , 2);
109 CGContextAddLines(context, points, 2);
110 //draw those defined after the last drawing
111 CGContextDrawPath(context, kCGPathStroke);
112
113 }
114
115 CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
116
117 CGContextDrawPath(context, kCGPathStroke);
118 CGContextSetAllowsAntialiasing(context, YES);
119
120
121 }
122
123 -(void)drawColumn:(CGContextRef)context rect:(CGRect)_rect{
124
125 int gNumber = 0, vNumber = 0;
126 int baseGroundY = HEIGHT - MARGIN_BOTTOM, baseGroundX = MARGIN_LEFT;
127 CGPoint points[4];
128
129 UIColor *columnColor = [UIColor redColor];
130 // the fill color(填充色)
131 CGContextSetFillColorWithColor(context, columnColor.CGColor);
132 // the stroke color (邊緣色)
133 CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
134
135 for(NSArray *g in groupData){
136 vNumber = 0;
137 for(NSNumber *v in g){
138
139 float columnHeight = [v floatValue] / maxScaleValue * maxScaleHeight ;
140
141 //改變各柱之間的緊湊狀況
142 float basex = vNumber * WIDTH/(3*[g count]) + baseGroundX + columnWidth * vNumber;
143
144 //畫正面
145 CGContextSetFillColorWithColor(context, columnColor.CGColor);
146
147 CGRect frontRect = CGRectMake(basex
148 , baseGroundY - columnHeight
149 , columnWidth
150 , columnHeight);
151
152 Rectangle* r = [[Rectangle alloc]initWith_Rect:frontRect];
153 [groupRect addObject:r];
154
155 CGContextAddRect(context, frontRect);
156 //draw the frontage of the rectangle
157 CGContextDrawPath(context, kCGPathFill);
158 //NSLog(@"columnHeight:%f, (_rect.size.height - MARGIN_TOP - MARGIN_BOTTOM ):%f",columnHeight,(_rect.size.height - MARGIN_TOP - MARGIN_BOTTOM ));
159
160 if(columnHeight < HEIGHT/30.0){//if the bar is too short
161 vNumber++;
162 continue;
163 }
164 //畫右側面
165 //reset the color of the side face of the rectangle, so it looks more stereoscopic
166 CGContextSetFillColorWithColor(context, [UIColor colorWithRed:.9 green:0 blue:0 alpha:1].CGColor);
167 points[0] = CGPointMake(basex + columnWidth, baseGroundY - columnHeight -HEIGHT/30.0);
168 points[1] = CGPointMake(basex + columnWidth + sideWidth, baseGroundY - columnHeight -HEIGHT/30.0 );
169 points[2] = CGPointMake(basex + columnWidth + sideWidth, baseGroundY-HEIGHT/30.0 );
170 points[3] = CGPointMake(basex + columnWidth, baseGroundY );
171
172 CGContextAddLines(context, points, 4);
173 CGContextDrawPath(context, kCGPathFill);
174
175 //畫上面
176 CGContextSetFillColorWithColor(context, [UIColor colorWithRed:1 green:.4 blue:.4 alpha:1].CGColor);
177 points[0] = CGPointMake(basex , baseGroundY - columnHeight );
178 points[1] = CGPointMake(basex + sideWidth, baseGroundY - columnHeight -HEIGHT/30.0 );
179 points[2] = CGPointMake(basex + columnWidth + sideWidth , baseGroundY - columnHeight -HEIGHT/30.0 );
180 points[3] = CGPointMake(basex + columnWidth, baseGroundY - columnHeight );
181
182 CGContextAddLines(context, points, 4);
183 CGContextDrawPath(context, kCGPathFill);
184
185 vNumber++;
186 }
187 gNumber ++;
188 }
189
190
191 }
192
193 -(void)calcScales:(CGRect)_rect{
194 int columnCount = 0;
195 for(NSArray *g in groupData){
196 for(NSNumber *v in g){
197 if(maxValue<[v floatValue]) maxValue = [v floatValue];
198 if(minValue>[v floatValue]) minValue = [v floatValue];
199 columnCount++;
200 }
201 }
202
203 maxScaleValue = ((int)ceil(maxValue) + (SHOW_SCALE_NUM - (int)ceil(maxValue) % SHOW_SCALE_NUM));
204
205 columnWidth = (WIDTH - MARGIN_LEFT * 2) / (columnCount + 1);
206 sideWidth = columnWidth *.2;
207 columnWidth *= .8;
208 }
209
210 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
211
212 UITouch *touch = [touches anyObject];
213 frstTouch = [touch locationInView:self];
214 scndTouch = [touch locationInView:self];
215 NSInteger index = [self touchToBarIndex:touch];
216 NSLog(@"began x:%f, y:%f, num:%d",frstTouch.x,frstTouch.y,index);
217
218 [self setNeedsDisplay];
219 }
220
221 -(NSInteger)touchToBarIndex:(UITouch*)touch{
222 CGPoint p = [touch locationInView:self];
223 int index = 0;
224
225 for (Rectangle *r in groupRect){
226 if(p.x>[r.x floatValue]&&p.x<[r.x floatValue]+[r.width floatValue]+WIDTH/30.0&&p.y>[r.y floatValue]-HEIGHT/30.0&&p.y<[r.y floatValue]+[r.height floatValue]){
227 return index;
228 }
229 index++;
230 }
231 return -1;
232 }
233
234 @end
由於CGRect是struct不能被放入容器中,所以自訂了一個類Rectangle,其 實現如下:
1 //
2 // Rectangle.m
3 // chart
4 //
5 // Created by user4 on 11-4-10.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "Rectangle.h"
10
11 @implementation Rectangle
12 @synthesize x;
13 @synthesize y;
14 @synthesize width;
15 @synthesize height;
16
17 -(id) initWith_Rect:(CGRect) r{
18 self = [super init];
19 if (self) {
20 self.x = [NSNumber numberWithFloat:r.origin.x];
21 self.y = [NSNumber numberWithFloat:r.origin.y];
22 self.width = [NSNumber numberWithFloat:r.size.width];
23 self.height = [NSNumber numberWithFloat:r.size.height];
24 }
25 return self;
26 }
27
28 - (void) dealloc
29 {
30 [x release];
31 [y release];
32 [width release];
33 [height release];
34 [super dealloc];
35 }
36 @end