.net使用gdi+绘半饼图

本文介绍了一种使用GDI+在Web项目中绘制半饼图的方法。通过解析XML数据确定各扇区的颜色和大小,并计算每个区域的角度。文章还提供了具体的代码实现,包括如何绘制文字坐标。

前两天web项目中遇到要绘一个半饼图,图表控件中没有这样的图,就用gdi+简单的绘了一个。

实现思路:

基于xml进行半饼图的数据提供,格式如下:

<imagedraw><imagedata data=\"100\" color=\"#1B3C72\" /><imagedata data=\"200\" color=\"#1B3Cad\" /><imagedata data=\"200\" color=\"#ffccdd\" /></imagedraw>

半饼图中每个区域可以分别指定颜色。每个区域的大小由提供数据的data属性值决定。每个区域的角度大小为:

iCurrAngle = Convert.ToInt32(当前区域数据 / 所有区域数据和 * 180);,因为是半饼图所以*180度。对于每个区域上绘制文字坐标,使用放大半径求圆弧所在点的位置的方式。

具体实现如下:

BaseDraw:绘图基类

PartPieDraw:绘半饼图实现类,主要是 RenerImage方法

 

using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;

/// <summary>
/// BaseDraw 的摘要说明
/// </summary>
public  class BaseDraw
{
    private int imageWidth = 0;
    private int imageHeight = 0;
    private string xmlData = "";

    public BaseDraw()
    {
        //
        // TODO: 在此处添加构造函数逻辑
        //
    }

    public int ImageWidth
    {
        get { return this.imageWidth; }
        set { this.imageWidth = value; }
    }

    public int ImageHeight
    {
        get { return this.imageHeight; }
        set { this.imageHeight = value; }
    }

    public string XmlData
    {
        get { return this.xmlData; }
        set { this.xmlData = value; }
    }

    public byte[] Draw()
    {
        System.Drawing.Bitmap image = new System.Drawing.Bitmap(this.imageWidth,this.imageHeight);
        Graphics g = Graphics.FromImage(image);
        this.RenerImage(g);
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
        byte[] buffer = ms.ToArray();
        g.Dispose();
        image.Dispose();
        return buffer;
    }

    public virtual ArrayList ParseXmlData()
    {
        return null;
    }

    public virtual void RenerImage(Graphics g)
    {

    }
}

 

using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml;

/// <summary>
/// PartPieDraw 的摘要说明
/// </summary>
public class PartPieDraw:BaseDraw
{
    public PartPieDraw()
    {
        //
        // TODO: 在此处添加构造函数逻辑
        //
    }

    public override void RenerImage(System.Drawing.Graphics g)
    {
        ArrayList dataList = this.ParseXmlData();
        //开始计算总的数值
        double sumValue = 0.00;
        foreach (ImageData data in dataList)
        {
            sumValue += Convert.ToDouble(Math.Round(data.DrawData, 2));
        }
        sumValue = Convert.ToDouble(Math.Round(sumValue, 2));
        int iSumAngle = 180;    //总要绘的角度
        int iCurrAngle = 0;   //当前角度
        int iPosAngle = 180;   //当前角度的基值
        int iCurrSumAngle = 0;
        double dCurrBfb = 0;
        //定义半图所在的矩形区域大小,画缓的位置占整个图的2/3
        int iAreaX = Convert.ToInt32((this.ImageWidth - Convert.ToInt32(this.ImageWidth * 2 / 3)) / 2);
        int iAreaY = iAreaX;
        int iAreaWidth = Convert.ToInt32(this.ImageWidth * 2 / 3);    //长边
        int iAreaHeight = iAreaWidth;
        double r = iAreaWidth / 2;    //半径
        double rx = Convert.ToDouble(iAreaX) + r;    //圆心x
        double ry = Convert.ToDouble(iAreaY) + r;    //圆心y
        //重设置半径
        r += 20;
        g.Clear(Color.White); //清除背景
        g.SmoothingMode = SmoothingMode.AntiAlias;  //消除绘的时候的锯齿
        g.DrawRectangle(new System.Drawing.Pen(Color.Black, 1), 0, 0, this.ImageWidth, this.ImageHeight);
        for (int i = 0; i < dataList.Count; i++)
        {
            ImageData imageData = (ImageData)dataList[i];
            dCurrBfb += imageData.DrawData / sumValue * 100;
            dCurrBfb = Convert.ToDouble(Math.Round(dCurrBfb, 2));  //格式化两位小数
            if (i < dataList.Count - 1)
            {
                iCurrAngle = Convert.ToInt32(imageData.DrawData / sumValue * iSumAngle);
            }
            else
            {
                iCurrAngle = 360 - iPosAngle;
            }
            g.SmoothingMode = SmoothingMode.AntiAlias;  //消除绘的时候的锯齿
            g.FillPie(new SolidBrush(imageData.DrawColor), iAreaX, iAreaY, iAreaWidth, iAreaHeight, iPosAngle, iCurrAngle);
            g.DrawPie(new Pen(new SolidBrush(imageData.DrawColor)), iAreaX, iAreaY, iAreaWidth, iAreaHeight, iPosAngle, iCurrAngle);
            //计算绘数字
            //求圆弧所在点的位置,有偏差
            iCurrSumAngle += iCurrAngle;
            double pointX = Math.Cos(iCurrSumAngle * Math.PI / 180) * r;  //对边,
            double pointY = Math.Sin(iCurrSumAngle * Math.PI / 180) * r;  //邻边
            pointY = ry - pointY;

            pointX = rx - pointX;
            Font strFont=new Font("宋体", 12, FontStyle.Italic);
            //开始测试绘字符需要的位置
            SizeF sizeF = g.MeasureString(dCurrBfb.ToString(), strFont);

            pointX = pointX - sizeF.Width / 2;
            pointY = pointY + sizeF.Height / 2;

            g.DrawString(dCurrBfb.ToString(), strFont, new SolidBrush(Color.Red), Convert.ToInt32(pointX), Convert.ToInt32(pointY) - 20);

            iPosAngle += iCurrAngle;
            iCurrAngle = 0;
           
        }
    }

    public override ArrayList ParseXmlData()
    {
        //解析数据格式
        //<imagedraw>
        //   <imagedata data="100" color="#fff000">
        //</imagedraw>
        ArrayList dataList = new ArrayList();
        System.Xml.XmlDocument doc = new XmlDocument();
        doc.LoadXml(this.XmlData);
        System.Xml.XmlElement root = doc.DocumentElement;
        foreach (System.Xml.XmlNode node in root.ChildNodes)
        {
            string sData = node.Attributes["data"].Value;
            string sColor = node.Attributes["color"].Value;
            dataList.Add(new ImageData(sData, sColor));
        }
        return dataList;
    }

    public class ImageData
    {
        private double drawData = 0.00;
        private Color drawColor=Color.White;

        public ImageData(string data, string htmlColor)
        {
            this.drawData = Convert.ToDouble(data);
            drawColor = System.Drawing.ColorTranslator.FromHtml(htmlColor);
        }

        public double DrawData
        {
            get { return this.drawData; }
        }

        public Color DrawColor
        {
            get { return drawColor; }
        }

    }

}

 

内容概要:本文详细介绍了“秒杀商城”微服务架构的设计与实战全过程,涵盖系统从需求分析、服务拆分、技术选型到核心功能开发、分布式事务处理、容器化部署及监控链路追踪的完整流程。重点解决了高并发场景下的超卖问题,采用Redis预减库存、消息队列削峰、数据库乐观锁等手段保障数据一致性,并通过Nacos实现服务注册发现与配置管理,利用Seata处理跨服务分布式事务,结合RabbitMQ实现异步下单,提升系统吞吐能力。同时,项目支持Docker Compose快速部署和Kubernetes生产级编排,集成Sleuth+Zipkin链路追踪与Prometheus+Grafana监控体系,构建可观测性强的微服务系统。; 适合人群:具备Java基础和Spring Boot开发经验,熟悉微服务基本概念的中高级研发人员,尤其是希望深入理解高并发系统设计、分布式事务、服务治理等核心技术的开发者;适合工作2-5年、有志于转型微服务或提升架构能力的工程师; 使用场景及目标:①学习如何基于Spring Cloud Alibaba构建完整的微服务项目;②掌握秒杀场景下高并发、超卖控制、异步化、削峰填谷等关键技术方案;③实践分布式事务(Seata)、服务熔断降级、链路追踪、统一配置中心等企业级中间件的应用;④完成从本地开发到容器化部署的全流程落地; 阅读建议:建议按照文档提供的七个阶段循序渐进地动手实践,重点关注秒杀流程设计、服务间通信机制、分布式事务实现和系统性能优化部分,结合代码调试与监控工具深入理解各组件协作原理,真正掌握高并发微服务系统的构建能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值