在开发系统的时候有许多数据分析需要用图形的方式来表现出,这样更直观又清淅。如果我们使用高级去动态
生成统计图表的话不但编写起来非常困难,而且实用性不是很好,从美观的角度上讲也是很设计的。然而Microsoft公司提供了一个专们的矢量画图语言,这就是VML.
如果要用VML去画静态页面的话那是比较好看也好操作,但实用性不是很高。但要是画出来的图所表示的数据
是从数据库里面读取下来的可以动态表示要统计的内容的话,那实用性就不言而喻了。
最近我们也要做一个数据统计图表,我想如果能把VML画图做成一个控件那该多很,做自定义控件(本人才疏学浅)我不怎么会做,但我们公司有个.NET很牛 的人,我经常看到他重写.net里自带的控件使这些控件变得更好用,于是我也产生一种想法,看能不能把VML也嵌套进去.结果做的还是有点起色.下面跟大 家分享一下.
我是把VML图表用Lable控件显示出来的,给Lable类添加了一些自定义属性.(在下面的代码里面有的属性还没有用到用与以后扩展)
页面代码如下
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DrawTest.aspx.cs" Inherits="DrawTest" %>
xmlns="http://www.w3.org/1999/xhtml">
Page
这里面的.标签里的” xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"
”和. v":*{ behavior: url(#default#VML) }
o":*{ behavior: url(#default#VML) }
是必不可少的.
下面是CS代码部分
private int xposition;
private int yposition;
private int xwidth;
private int yheight;
private bool isdrawVML;
private int bgdistance;//背景距离(斜线之间的垂直距离)
private int zhuWidth;
private string lineColor;
private int yItemWidth;
private string xSign;//X轴标记
private string ySign;//Y轴标记
private List datasource;
private IszhuOrBing isZhuOrBing;
private int radii;//画饼图要用的半径
public IszhuOrBing IsZhuOrBing
{
get { return isZhuOrBing; }
set { isZhuOrBing = value; }
}
#region 属性的定义
///
/// 画饼图的半径
///
public int Redii
{
get { return radii; }
set { radii = value; }
}
///
/// X轴的位置
///
public int XPosition
{
get { return xposition; }
set { xposition = value; }
}
///
/// Y轴位置
///
public int YPosition
{
get { return yposition; }
set { yposition = value; }
}
//
///
/// X轴宽度
///
public int XWidth
{
get { return xwidth; }
set { xwidth = value; }
}
//
///
/// Y轴高度
///
public int YHeight
{
get { return yheight; }
set { yheight = value; }
}
///
/// 是否是画VML图
///
public bool IsDrawVML
{
get { return isdrawVML; }
set { isdrawVML = value; }
}
///
/// 背景距离(斜线之间的垂直距离)
///
public int BgDistance
{
get
{
return bgdistance;
}
set
{
if (value <= 0)
bgdistance = 10;
else
bgdistance = value;
}
}
///
/// 柱子的宽度
///
public int ZhuWidth
{
get { return zhuWidth; }
set { zhuWidth = value; }
}
///
/// 柱子的颜色
///
public string LineColor
{
get { return lineColor; }
set { lineColor = value; }
}
///
/// Y轴方向的间距
///
public int YItemWidth
{
get { return yItemWidth; }
set { yItemWidth = value; }
}
///
/// X轴标识
///
public string XSign
{
get { return xSign; }
set { xSign = value; }
}
///
/// Y轴标识
///
public string YSign
{
get { return ySign; }
set { ySign = value; }
}
///
/// 数据源(柱子高度)
///
public List DataSource
{
get { return datasource; }
set { datasource = value; }
}
#endregion
判断是画柱图还是饼图.
//画VML图
StringBuilder sbText = new StringBuilder();
string strHeight = "";
string strTop = "";
public void DrawVml()
{
if (isdrawVML == true)
{//
if (isZhuOrBing== IszhuOrBing.Bing)
{
DrawBingImage();
}
else if (isZhuOrBing == IszhuOrBing.Zhu)
{
DrawZhuImage();
}
}
}
***IsZhuOrBing是一个自定义的枚举类型.
//柱子一升的脚本
private string RegisterScript()
{
string m_strScript = " ";
return m_strScript;
}
上面的那段代码是要向客户端注册的JS脚本用于,画柱图时渐长效果的.
开始画VML图
//画柱图.
public void DrawZhuImage()
{
base.Text = "";
//画Div
//sbText.Append("
");
sbText.Append("
");
//base.Style.Value = "left:" + xposition + ";position:relative; top:" + yposition + "; width:" + (xwidth+20) + "; height:" + (20+yheight) + ";'";
//画X轴
sbText.Append(""
+ "" + xSign + "");
//画X轴方向的线条
int HaveData = ComputeX(xwidth);
//if (HaveData == 0)
//{
// sbText.Append("
");
// base.Text = sbText.ToString(0, sbText.Length);
// return;
//}
//画Y轴
sbText.Append("
" + ySign + "");
//画Y轴方向的线条
ComputeY(yheight);
//画DIV结束标记
sbText.Append("
");
//画隐形文本框
sbText.Append("");
sbText.Append("");
//给Lable控件的Text赋值
base.Text = sbText.ToString(0, sbText.Length);
Page.RegisterStartupScript("zhuup", RegisterScript());
}
//
private int ComputeX(int XWidth)
{ //柱子颜色数组
string[,] ZColor = new string[6, 2];
ZColor[0, 0] = "#666699"; ZColor[0, 1] = "#d9d9e5";
ZColor[1, 0] = "#00ff00"; ZColor[1, 1] = "#d1ffd1";
ZColor[2, 0] = "#ff0000"; ZColor[2, 1] = "#ffbbbb";
ZColor[3, 0] = "#ff9900"; ZColor[3, 1] = "#ffe3bb";
ZColor[4, 0] = "#33cccc"; ZColor[4, 1] = "#cff4f3";
ZColor[5, 0] = "#993300"; ZColor[5, 1] = "#ffc7ab";
XWidth -= 10;//箭头下面的长度
int ColorIndex = 0;
double height = 0;
int Zhuposition = 0;
int Count = this.DataSource==null?XWidth:this.DataSource.Count;
int num=1;
//Count = 0;
//if (Count == 0)
//{
// sbText.Append("暂无数据
");
// return 0;
//}
int UnitLength = XWidth / Count;//计算单位长度
foreach (VmlDataSource var in this.datasource)
{
//画X轴下标
sbText.Append(""
+ "" + var.Key + "");
height = var.value;
Zhuposition = ((num - 1) * UnitLength + UnitLength / 2) - (zhuWidth / 2);
if (ColorIndex >= ZColor.Length / 2)
{
ColorIndex = 0;
}
//sbText.Append(""
+ ""
+ ""
+ "" + height + "");
strHeight += height + ",";
strTop += (yheight - height) + ",";
ColorIndex++;
num++;
}
return 1;
}
//
private void ComputeY(int YHeight)
{
YHeight -= 10;//箭头下面的长度
if (yItemWidth > 0)
{
int Units = YHeight / yItemWidth;//计算单位长度
for (int i = 0; i <= Units; i++)
{
int areaLenght = yheight - (i * yItemWidth);
sbText.Append(""
+ ""
+ "" + i * yItemWidth + ""
+ "");
}
//画Y轴平行的线
sbText.Append("");
}
}
#endregion
#region 画饼图
private void DrawBingImage()
{
base.Text = "";
//定义颜色
string[] Colors = new string[6];
Colors[0] = "#666699";
Colors[1] = "#00ff00";
Colors[2] = "#ff0000";
Colors[3] = "#ff9900";
Colors[4] = "#33cccc";
Colors[5] = "#993300";
//开始标记
//sbText.Append("
");
//
double TotalCount = 0;
foreach (VmlDataSource vd in datasource)
{
TotalCount += vd.value;
}
//计算单位数字的角度
double UnitAngle = 360 / TotalCount;
//存储画下弧度的起点
double TempUnitArc=0.00;
//存储前面已有的角度
double TempUnitAngle=0.00;
int i = 0;
string ColorInfo = "";
sbText.Append("
");
sbText.Append("
");
sbText.Append("
");
foreach (VmlDataSource vd in datasource)
{
//计算弧度
double UnitArc = (vd.value * UnitAngle + TempUnitAngle) * Math.PI / 180;
//计算开始和结束位置
double sx = Math.Round(Math.Cos(TempUnitArc) * radii);//Math.Sign(
double sy = Math.Round(Math.Sin(TempUnitArc) * radii);
double ex = Math.Round(Math.Cos(UnitArc) * radii);
//double aa = Math.Sin(UnitArc) * radii;
//double bb = Math.Round(Math.Sin(UnitArc) * radii,4);
double ey = Math.Round(Math.Sin(UnitArc) * radii);
//所占百份比
double rate = Math.Round(vd.value * 100 / TotalCount, 2);
//开始画图
sbText.Append(" sbText.Append(" path='m0,0 l" + sx + "," + sy + " ar-" + radii + ",-" + radii + "," + radii + "," + radii + "," + ex + "," + ey + "," + sx + "," + sy + " l0,0 x e'");
sbText.Append("title='名称:" + vd.key + ""r数量:" + vd.value + ""r所占比例:" + rate + "%'>");
//给临时变量赋值
TempUnitAngle += vd.value * UnitAngle;
TempUnitArc = UnitArc;
//显示颜色说明框
ColorInfo += "
"
+ " " + vd.key + ":" + vd.value + " (" + rate + "%)
"
;
//如果颜色遍历完了,还有数据要显示那就重新再一次遍历。占:" + (Math.Round(vd.value * 100 / TotalCount, 2)) + "%
i = (i >= Colors.Length ? 0 : ++i);
}
sbText.Append("
");
sbText.Append("
");
//sbText.Append("
");
//总数
sbText.Append("
总数据:"+TotalCount+"
");
sbText.Append(ColorInfo);
sbText.Append("
");
this.Text = sbText.ToString();
}
#endregion
///
/// 控件加载时画图
/// ///
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e); // Page.RegisterStartupScript("HelloWord", "");
DrawVml();
//Page.RegisterStartupScript("", "");
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
Page.RegisterStartupScript("", "");
}
}
*注意里面的数据源类型和枚举在下面定义.
///
/// 画图时用的数据源
/// public class VmlDataSource
{
public VmlDataSource()
{
}
public string key;
public double value;
///
/// 键值
///
public string Key
{
get { return key; }
set { key = value; }
}
public double Value
{
get
{
if (this.value.GetType() != Type.GetType("System.Int32"))
return 0;
else
return this.value;
}
set
{
this.value = value;
}
}
}
///
/// 枚举画图的类型
///
public enum IszhuOrBing
{
//
Zhu=0,
//
Bing=1
}
}
整个过程就是这样了,不过这只是个粗略的过程里面还很多的BUG没有解觉掉.画数据统计的图表完成了.
效果图如下.
CIO之家 www.ciozj.com 公众号:imciow
关联的文档
也许您喜欢