有网友发了张图,问我实现的方法。 与一般的柱形图不一样,这张图很特别,相信他要找到现成的,对得上号的图表将不是件易事。
通常图表库实现的不是通常意义上的柱形图,就是单纯的堆积图,很少有这种混在一起展现的情况出现。没得法,要定制才能实现的了。
网友的原图(应当没侵权吧)
利用XCL-Charts实现的效果图:
网友的这张表面看起来,是同一个标签,两个堆积柱形并排放在一起,但依我的经验,要原汁原味让图表库提供这种图是很难的,
参数及数据位置计算很难处理。只能利用现有图表,采用混合方式实现。仔细观察了下,发现实际上只要将两个柱形图并在一起,在柱形高
度上做点手脚就能达到这个效果了。
即,先画高一点那一些柱形图,再绘数据低一层的柱形图。 当然如果数据是变化的,现在高的到时有可能变低,就不能采用这种方法了,
但这张图暂不用考虑这个问题。
定制程序的部份代码如下:
private String TAG = "MultiBarchart201View";
private BarChart chart = new BarChart();
private BarChart chart2 = new BarChart();
//标签轴
private List<String> chartLabels = new LinkedList<String>();
private List<BarData> chartData = new LinkedList<BarData>();
private List<BarData> chartData2 = new LinkedList<BarData>();
private int axisColor = Color.rgb(125, 223, 252);
public MultiBarChart01View(Context context) {
super(context);
// TODO Auto-generated constructor stub
initView();
}
public MultiBarChart01View(Context context, AttributeSet attrs){
super(context, attrs);
initView();
}
public MultiBarChart01View(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView()
{
chartLabels();
chartDataSet();
chartDataSet2();
chartRender();
chartRender2();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//图所占范围大小
chart.setChartRange(w,h);
chart2.setChartRange(w,h);
}
private void chartRender()
{
try {
//设置绘图区默认缩进px值,留置空间显示Axis,Axistitle....
int [] ltrb = getBarLnDefaultSpadding();
chart.setPadding(ltrb[0], ltrb[1], DensityUtil.dip2px(getContext(), 45), ltrb[3]);
//数据源
chart.setDataSource(chartData);
chart.setCategories(chartLabels);
//数据轴
chart.getDataAxis().setAxisMax(2500);
chart.getDataAxis().setAxisMin(0);
chart.getDataAxis().setAxisSteps(500);
//让柱子间没空白
chart.getBar().setBarInnerMargin(0d);
//隐藏轴
chart.getDataAxis().setVisible(false);
chart.getCategoryAxis().setVisible(false);
//将Bar风格设为Fill
chart.getBar().setBarStyle(XEnum.BarStyle.FILL);
chart.setApplyBackgroundColor(true);
chart.setBackgroundColor(Color.rgb(19, 163, 224));
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, e.toString());
}
}
private void chartRender2()
{
try {
//设置绘图区默认缩进px值,留置空间显示Axis,Axistitle....
int [] ltrb = getBarLnDefaultSpadding();
chart2.setPadding(ltrb[0], ltrb[1], DensityUtil.dip2px(getContext(), 45), ltrb[3]);
//显示边框
//chart2.showRoundBorder();
chart2.getBar().setBarStyle(XEnum.BarStyle.FILL);
//标题
chart2.setTitle("负债率标准备: 40%~60%");
chart2.addSubtitle("(XCL-Charts Demo)");
chart2.getPlotTitle().getTitlePaint().setColor(axisColor);
chart2.getPlotTitle().getSubtitlePaint().setColor(axisColor);
//数据源
chart2.setDataSource(chartData2);
chart2.setCategories(chartLabels);
//轴标题
chart2.getAxisTitle().setLeftAxisTitle("金额");
chart2.getAxisTitle().setLowerAxisTitle("资产负债率");
//数据轴
chart2.getDataAxis().setAxisMax(2500);
chart2.getDataAxis().setAxisMin(0);
chart2.getDataAxis().setAxisSteps(500);
//定义数据轴标签显示格式
chart2.getDataAxis().setLabelFormatter(new IFormatterTextCallBack(){
@Override
public String textFormatter(String value) {
// TODO Auto-generated method stub
Double tmp = Double.parseDouble(value);
DecimalFormat df=new DecimalFormat("#0");
String label = df.format(tmp).toString();
return (label);
}
});
//让柱子间没空白
chart2.getBar().setBarInnerMargin(0d);
//轴颜色
chart2.getDataAxis().getAxisPaint().setColor(axisColor);
chart2.getCategoryAxis().getAxisPaint().setColor(axisColor);
chart2.getDataAxis().getTickMarksPaint().setColor(axisColor);
chart2.getCategoryAxis().getTickMarksPaint().setColor(axisColor);
chart2.getDataAxis().getTickLabelPaint().setColor(axisColor);
chart2.getCategoryAxis().getTickLabelPaint().setColor(axisColor);
chart2.getAxisTitle().getLeftAxisTitlePaint().setColor(axisColor);
chart2.getAxisTitle().getLowerAxisTitlePaint().setColor(axisColor);
//隐藏图例
chart2.getPlotLegend().hideLegend();
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, e.toString());
}
}
private void chartDataSet()
{
//标签对应的柱形数据集
List<Double> dataSeriesA= new LinkedList<Double>();
dataSeriesA.add(2400d);
dataSeriesA.add(2400d);
dataSeriesA.add(2400d);
dataSeriesA.add(2400d);
dataSeriesA.add(2400d);
BarData BarDataA = new BarData("流动资产",dataSeriesA,(int)Color.rgb(58, 191, 247));
List<Double> dataSeriesB= new LinkedList<Double>();
dataSeriesB.add(2000d);
dataSeriesB.add(2000d);
dataSeriesB.add(2000d);
dataSeriesB.add(2000d);
dataSeriesB.add(2000d);
BarData BarDataB = new BarData("非流动资产",dataSeriesB,(int)Color.rgb(20, 181, 251));
chartData.add(BarDataA);
chartData.add(BarDataB);
List<Double> dataSeriesAA= new LinkedList<Double>();
dataSeriesAA.add(0d);
BarData BarDataAA = new BarData("负债",dataSeriesAA,(int)Color.rgb(38, 137, 176));
List<Double> dataSeriesBB= new LinkedList<Double>();
dataSeriesBB.add(0d);
BarData BarDataBB = new BarData("所有者权益",dataSeriesBB,(int)Color.rgb(13, 116, 161));
chartData.add(BarDataAA);
chartData.add(BarDataBB);
}
private void chartDataSet2()
{
//标签对应的柱形数据集
List<Double> dataSeriesA= new LinkedList<Double>();
dataSeriesA.add(1600d);
dataSeriesA.add(1700d);
dataSeriesA.add(1800d);
dataSeriesA.add(1800d);
dataSeriesA.add(1500d);
BarData BarDataA = new BarData("负债",dataSeriesA,(int)Color.rgb(38, 137, 176));
List<Double> dataSeriesB= new LinkedList<Double>();
dataSeriesB.add(1500d);
dataSeriesB.add(1300d);
dataSeriesB.add(1400d);
dataSeriesB.add(1200d);
dataSeriesB.add(1600d);
BarData BarDataB = new BarData("所有者权益",dataSeriesB,(int)Color.rgb(13, 116, 161));
chartData2.add(BarDataA);
chartData2.add(BarDataB);
}
private void chartLabels()
{
chartLabels.add("20%");
chartLabels.add("40%");
chartLabels.add("60%");
chartLabels.add("80%");
chartLabels.add("100%");
}
@Override
public void render(Canvas canvas) {
try{
chart.render(canvas);
chart2.render(canvas);
//绘制轴点
float radius = 10f;
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(this.axisColor);
canvas.drawCircle(chart2.getPlotArea().getLeft(), chart2.getPlotArea().getBottom(), radius, paint);
canvas.drawCircle(chart2.getPlotArea().getRight(), chart2.getPlotArea().getBottom(), radius, paint);
canvas.drawCircle(chart2.getPlotArea().getLeft(), chart2.getPlotArea().getTop(), radius, paint);
} catch (Exception e){
Log.e(TAG, e.toString());
}
}
至此,图就绘制出来了。 代码不长,相信基本能看懂。
特别要说一下代码中的绘制轴点。 在原图中,轴的两端和交叉处都有一个白点。XCL-Charts默认是没有这个功能,但这三个点的位置,
在XCL-Charts中都能取得出来,所以直接在render()中,直接加上三个绘制制circle的代码就行了。图例和轴标题风格有点不同,但这已不是什么大问题了。如果
还要求一样,可从XCL-Charts中依相关函数得到位置后,自定义一个图例和轴标题也不是难事。
发现现在有个性的图太多了,各式各样,好多都没见过,很难考虑得到这些情况,所以图表库的灵活性与定制化越发重要,但我发现很少有人认真去看图表库,
都喜欢瞄瞄有没原样的,没有继续到处找。图表真的很特别时,等着哭吧。 哈哈。
这个例子已收录在XCL-Charts图表库的demo中,有兴趣的可以去看看。
MAIL: xcl_168@aliyun.com
BLOG: http://blog.csdn.net/xcl168