Core Plot提供了 CPTBarPlot 类用于柱状图的绘制。在1.0版本中,Core Plot终于提供了水平柱状图(如果你要绘制水平柱状图,[CPTBarPlot tubularBarPlotWithColor: horizontalBars:]方法的第2个参数设置为YES)。
本文的示例程序将演示如何绘制柱状图。1、 绘制基本的柱状图
这个程序中,数据点是动态加载的,当你点击工具栏按钮“加载数据”时,柱状图会逐渐显现,每隔一秒添加一点数据。这里我们用到了定时器源。
-(IBAction)loadData:(id)sender {
points=[[NSMutableArrayalloc]init];
if(timer)dispatch_source_cancel(timer);
timer =dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
__block int i=0;
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC,0);
dispatch_source_set_event_handler(timer, ^{
i++;
if(i<max_bar_num) {
id x = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:i];
id y = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:(i+ 1) * (i + 1)];
NSDictionary* point=[NSDictionary dictionaryWithObjectsAndKeys:x,@"x", y, @"y", nil];
[self addPoint:point];
}else{
NSLog(@"timer stop!");
dispatch_source_cancel(timer);
}
});
dispatch_resume(timer);
}
同散点图的例子一样,在绘制图形之前,我们需要配置图纸、图形空间、坐标系和CPTPlot的属性,我们把代码放到了viewDidLoad 方法里。这些代码有一点模式化了,你可以参考散点图的例子。
其中,CPTBarPlot实例由唯一工厂方法获得:
tubularBarPlotWithColor:horizontalBars:
第一个参数指定柱子的颜色,第二个参数指定是否绘制水平柱子,YES为绘制。默认为NO。
实例化 CPTBarPlot 之后,需要设置 CPTBarPlot 的属性,常见属性如下:
baseValue属性 - 柱子的基线值。大于这个值以上的点,柱子只从这个点开始画。小于此值的点,则是反向绘制的,即从基线值向下画,一直画到到数据点。
barWidth属性 - 柱子宽度。
barWidthScale属性 - 柱宽的缩放系数。
barOffset属性 - 柱子开始绘制的偏移位置。这个值非常有用。由于在横坐标上占据一定宽度,所以如果柱子从x坐标某个值开始画的话,柱子的中线就不再数据点上了。为了保持柱子中心线和数据点对齐,我们一般会把barOffset设置为-barWidth/2。
dataSource属性 - 这个当然是用来设置数据源的。数据源必须实现 CPTPlotDataSource 委托。
fill属性 - 这个属性用来设置柱子的填充风格(CPTFill)。如果设置为nil,则柱子不会填充。当然我们也可以用渐变色填充。
lineStyle属性 - 用于设置柱子外框的线型。
设置完 CPTBarPlot 的属性,我们需要在数据源实现 CPTPlotDataSource 委托方法。这些方法的实现同前面我们讲过的散点图的例子是一模一样的。
2、 固定坐标轴
从0.9版本开始,CorePlot改变了Constraints机制。 结构体 CPConstraints 被新的CPTConstraints类所取代,同时也取消了CPTMakeConstraints()函数的使用。
通过 CPTConstraints 类,我们可以指定坐标轴始终固定在屏幕的某个地方。将 CPTXYAxis 的 axisConstraints属性用一个CPTConstraints 对象指定,可以在拖动发生时使 x 或 y 轴不跟随图形移动。
CPTConstraints有三个重要的工厂方法,用于创建CPTConstraints实例:
constraintWithLowerOffset:
constraintWithRelativeOffset:
constraintWithUpperOffset:
三个方法的用于计算偏移量的方式略有不同。具体区别如下:
1、constraintWithLowerOffset:
根据指定的float,可以将坐标轴固定于图框(PlotFrame)近端的偏移量处。lower一词实际上是以x轴坐标代入的,意指屏幕下端。如果是y轴,则是指屏幕左端。偏移量以像素点为单位。
2、constraintWithUpperOffset:
与上面相反,将坐标轴固定于图框远端的偏移量处。upper一词对于x轴是指屏幕上端,对于y轴是指屏幕右端。
3、constraintWithRelativeOffset:
与上面两者不同,此偏移量以0-1之间的相对比例计算(从近端到远端)。0代表最左/下边,1代表最右/上边。0.5代表中间。
3、 显示数据点的值
有时候需要在曲线或柱子的顶点上显示数字(即Data Label)。如图所示。
CPTPlot提供默认的 Data Label,通过对一些属性的改变,你可以控制Data Label是否显示及显示的样式。
labelOffset:Data Label 显示的位置到顶点之间的距离。
labelRotation: DataLabel 的倾斜角。
labelTextStyle:Data Label 的文字样式,包括字体名、颜色、字体大小。labelFormatter: 可以用于设置 Data Label 的数字格式,提供一个NSNumberFormatter对象给这个属性。
labelShadow:Data Label 的阴影属性。
要想让默认的 Data Label 能够显示,起码要配置labelTextStyle属性。
CPTMutableTextStyle*textStyle=[CPTMutableTextStyle textStyle];
textStyle.color=[CPTColorgreenColor];
textStyle.fontSize=10;
barPlot.labelTextStyle=textStyle;
如果想提供自定义的 Data Label,则需要实现CPTPlotDataSource中的dataLabelForPlot:recordIndex:方法。以下代码演示在dataLabelForPlot:recordIndex:方法中,我们对Data Label 中的数字格式和文本颜色进行了定制。
- (CPTLayer *)dataLabelForPlot:(CPTPlot *) plot recordIndex: (NSUInteger) index{
NSNumber* num=[[pointsobjectAtIndex:index] valueForKey:@"y"];
CPTTextLayer *label = [[CPTTextLayer alloc] initWithText:[NSStringstringWithFormat:@"%d", [num intValue]]];
CPTMutableTextStyle *textStyle =[label.textStyle mutableCopy];
textStyle.color = [CPTColor lightGrayColor];
label.textStyle = textStyle;
[textStyle release];
return [label autorelease];
}
4、 显示网格线
网格线是大小刻度线的延伸。通过设置坐标轴的下列属性,我们可以在图形坐标轴上显示网格线:
. majorGridLineStyle
指定大刻度线上的网格线线段样式。为空则不显示网格线。
. minorGridLineStyle
指定小刻度线上的网格线线段样式。为空则不显示网格线。
. gridLinesRange
指定网格线的显示范围,包括网格线线段的起始及长度。
以下代码将在y坐标的大刻度线上显示网格线,并指定网格线线型和线段的范围:
CPTXYAxis *y =axisSet.yAxis;
CPTMutableLineStyle*lineStyle1 = [CPTMutableLineStyle lineStyle];
lineStyle1.lineWidth = 1.0f;
lineStyle1.lineColor = [CPTColor blueColor];
barPlot.lineStyle=lineStyle1;
y.majorGridLineStyle= lineStyle1;
CPTPlotRange*range=[CPTPlotRange plotRangeWithLocation:CPTDecimalFromString(@"5")
length:CPTDecimalFromString(@"5")];
y.gridLinesRange=range;