基于
http://www.cnblogs.com/moshengren/archive/2010/10/19/1855241.html
点击柱状图中的 柱 可获取 该柱的编号(从左到右,0-n)
能自动调整 柱 的宽度以及各 柱 之间的间隔
由于CGRect是struct不能被放入容器中,所以自定义了一个类Rectangle,其 实现如下:
点击柱状图中的 柱 可获取 该柱的编号(从左到右,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
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
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