ASP.NET 中的 3D 饼图






3.48/5 (27投票s)
2003 年 4 月 28 日
4分钟阅读

341093
讨论了在 ASP.NET 中实现 3D 饼图。
引言
我决定记录我制作的这个小小的 3D 饼图演示,并可能将其提交给 CodeProject。我必须指出,我在图形编程方面做得很少。
一切都始于我曾思考过一个饼图扇形在给定半径和扇形角度的情况下,其圆弧的长度。我从未找到公式,但我认为你可以取整个圆的周长,然后将其除以八等份,如果角度是 45 度,如上图所示。等等,这就是答案!
不管怎样,然后我开始问自己如何以编程方式绘制一个饼图。这可能给了我一些想法。我在 CodeProject 上找到了一个用户 blong 制作的复杂的 WebChart 控件。我还从 MSDN 2002 年 8 月的 Jeff Prosise 那里得到了一些简单的 ASHX 代码。
Graphics 方法 FillPie 可以绘制一个饼图扇形,给定中点、椭圆的长度和宽度、起始角度和扫过角度。中点是“设备上下文”将放置椭圆中心的图形坐标。将其视为 x, y 坐标系统中的 0, 0,角度如附图 2 所示。
我创建了一个 VB.NET 项目来演示 FillPie 方法、一个 DrawPieChart 示例和一个 Draw3DPieChart 演示,而这个 ASP.NET (ASPX 页面) 演示就来源于此。不幸的是,我没有可供 Internet 访问的 IIS 服务器,但 Windows 应用程序可以 在此处 下载。
扫过角度不言自明,但一开始让我困惑。如果起始角度是 35 度,并且你想让一个饼图扇形到达 90 度,你应该将扫过角度设置为 55 而不是 90。
为了绘制简单的饼图,我创建了一个循环,从 0 开始,每隔 45 度跳一次,直到 315 度。注意:我随机选择了画笔颜色,而且我没有想到 360 和 0 是同一个点,直到我做了 3D 演示才发现这个问题。
接下来是 3D 测试。对于小于 180 度的饼图扇形,要求我使用 System.Drawing.Drawing2D.HatchBrush
,其颜色与为该扇形随机选择的颜色相同,并绘制 10 个扇形,在每次调用 FillPie 方法时降低 y 坐标,以产生深度错觉。
绘制分离的饼图扇形是一个额外的挑战。我不记得没有分离扇形时代码的功能是什么,但为了绘制图 1 中的图表,我注意到从 180 度开始的饼图扇形并环绕(0 到 315,参见下面的代码),将能正确绘制图表。为了简单起见,我“煞费苦心地”将角度保持在 360 度以下。
就这样;很简单。我认为如果项目不值得花时间设计一个更好、可重用的版本。哪种格式最好?下面列出的这个 ASPX 吗?像 Jeff 那样使用 ASHX 文件?图例、图表标题呢?这需要比我简单的探究更多的时间和意愿。而且,你最好还是使用上面提到的 WebChart 控件。它已经写好了!
假设我花时间编写一个可重用的图表,以下是我将用于算法的步骤。将元素数组或列表(测试分数、投票数等)从最大数排序到最小数。在此演示中,所有扇形的角度均为 45 度。
要确定每个扇形的角度,我会将元素相加,然后取一个元素的值除以总和,再乘以 360。以 .NET 平台用户为例,采用简单的任意样本数据:
- J# 用户:5%
- C# 用户:80%
- VB.NET 用户:15%
排序结果将是 {80, 15, 5},从 180 度开始,遍历列表。“C# 用户”扇形的扫过角度为 (80/100*360) 即 288 度;“VB.NET 用户”为 54 度;分离的“J# 用户”扇形为 18 度。
在我的演示中,我只是使用 RGB 值随机选择颜色。已知实色会更具吸引力。另一个令人愉悦的特性是这个
objGraphics.SmoothingMode = SmoothingMode.AntiAlias;
与没有这行代码创建的锯齿状图像进行比较。我想就是这样了。希望它对某人有所价值。也许这份文档只是我多年后回顾代码的自我记录。
图表无法直接从 Internet Explorer 打印。我想知道这是否是因为我没有从 HTML 图像标签中引用 (href) 该页面——而从图像标签引用的页面是可以打印的。
<%@ Import Namespace="System.Drawing"%>
<%@ Import Namespace="System.Drawing.Imaging"%>
<%@ Import Namespace="System.Drawing.Drawing2D" %>
<script language="C#" runat="server">
void Page_Load(Object sender, EventArgs e)
{
// Since we are outputting a Jpeg, set the ContentType appropriately
Response.ContentType = "image/jpeg";
// Create a Bitmap instance that's 468x60, and a
Graphics instance
const int width = 300, height = 300;
Bitmap objBitmap = new Bitmap(width, height);
Graphics objGraphics = Graphics.FromImage(objBitmap);
// Create a black background for the border
objGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0,
width, height);
Draw3DPieChart(ref objGraphics);
// Save the image to a file
objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
// clean up...
objGraphics.Dispose();
objBitmap.Dispose();
}
// Draws a 3D pie chart where ever slice is 45 degrees in value
void Draw3DPieChart(ref Graphics objGraphics)
{
int iLoop, iLoop2;
// Create location and size of ellipse.
int x = 50;
int y = 20;
int width = 200;
int height = 100;
// Create start and sweep angles.
int startAngle = 0;
int sweepAngle = 45;
SolidBrush oibjBrush = new SolidBrush(Color.Aqua);
Random rand = new Random();
objGraphics.SmoothingMode = SmoothingMode.AntiAlias;
//Loop through 180 back around to 135 degress so it gets drawn
// correctly.
for( iLoop = 0; iLoop <= 315; iLoop += 45)
{
startAngle = (iLoop + 180) % 360;
objBrush.Color = Color.FromArgb(rand.Next(255), rand.Next(255),
rand.Next(255));
// On degrees from 0 to 180 draw 10 Hatched brush slices to show
// depth
if((startAngle < 135) || (startAngle == 180))
{
for(iLoop2 = 0; iLoop2 < 10; iLoop2++)
objGraphics.FillPie(new HatchBrush(HatchStyle.Percent50,
objBrush.Color), x,
y + iLoop2, width, height, startAngle, sweepAngle);
}
// Displace this pie slice from pie.
if(startAngle == 135)
{
// Show Depth
for(iLoop2 = 0; iLoop2 < 10; iLoop2++)
objGraphics.FillPie(new HatchBrush(HatchStyle.Percent50,
objBrush.Color), x - 30,
y + iLoop2 + 15, width, height, startAngle,
sweepAngle);
objGraphics.FillPie(objBrush, x - 30, y + 15,
width, height, startAngle, sweepAngle);
}
else // Draw normally
objGraphics.FillPie(objBrush, x, y, width,
height, startAngle, sweepAngle);
}
}
</script>