C#绘制成比例缩放的折线图

参照http://xxp5310776.blog.sohu.com/58914721.html 

    /// <summary>
    /// 绘制双折线图
    /// </summary>
    /// <param name="bmap">空白位图</param>
    /// <param name="iScaleX">X轴比例</param>
    /// <param name="iScaleY">Y轴比例</param>
    /// <param name="arrX">X轴数组</param>
    /// <param name="arrY1">Y轴数组</param>
    /// <param name="arrY2">Y轴数组</param>
    /// <param name="strTitle">标题</param>
    /// <param name="strXUnitName">X轴单位名称</param>
    /// <param name="strYUnitName">Y周轴单位名称</param>
    /// <param name="strY1Name">第1条折线图例名称</param>
    /// <param name="strY2Name">第2条折线图例名称</param>
    /// <param name="gph">返回绘制的折线图</param>

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Drawing;  
  6. using System.Drawing.Imaging;  
  7.  
  8. /// <summary>  
  9. ///ClassDrawing 的摘要说明  
  10. /// </summary>  
  11. public class ClassDrawing  
  12. {  
  13.     public ClassDrawing()  
  14.     {  
  15.         //  
  16.         //TODO: 在此处添加构造函数逻辑  
  17.         //  
  18.     }  
  19.  
  20.     /// <summary>  
  21.     /// 绘制双折线图  
  22.     /// </summary>  
  23.     /// <param name="bmap">空白位图</param>  
  24.     /// <param name="iScaleX">X轴比例</param>  
  25.     /// <param name="iScaleY">Y轴比例</param>  
  26.     /// <param name="arrX">X轴数组</param>  
  27.     /// <param name="arrY1">Y轴数组</param>  
  28.     /// <param name="arrY2">Y轴数组</param>  
  29.     /// <param name="strTitle">标题</param>  
  30.     /// <param name="strXUnitName">X轴单位名称</param>  
  31.     /// <param name="strYUnitName">Y周轴单位名称</param>  
  32.     /// <param name="strY1Name">第1条折线图例名称</param>  
  33.     /// <param name="strY2Name">第2条折线图例名称</param>  
  34.     /// <param name="gph">返回绘制的折线图</param>  
  35.     public void drawLineGraphY2(ref Bitmap bmap, ref int iScaleX, ref int iScaleY, ref double[] arrX, ref double[] arrY1, ref double[] arrY2, ref string strTitle, ref string strXUnitName, ref string strYUnitName, ref string strY1Name, ref string strY2Name, out Graphics gph)  
  36.     {  
  37.         gph = Graphics.FromImage(bmap);  
  38.         gph.Clear(Color.White);  
  39.  
  40.         if (arrX.Length != arrY1.Length)  
  41.         {  
  42.             return;  
  43.         }  
  44.         if (arrX.Length != arrY2.Length)  
  45.         {  
  46.             return;  
  47.         }  
  48.         double xMax = 0;  
  49.         double xUnit = 0;  
  50.         float[] arrXUnit = new float[arrX.Length];  
  51.  
  52.         double yMax = 0;  
  53.         double yUnit = 0;  
  54.         float[] arrY1Unit = new float[arrY1.Length];  
  55.         float[] arrY2Unit = new float[arrY2.Length];  
  56.  
  57.         // 按X从小到大进行排序  
  58.         for (int i = 0; i < arrX.Length; i++)  
  59.         {  
  60.             if (arrX[i] < 0)  
  61.             {  
  62.                 return;  
  63.             }  
  64.  
  65.             for (int j = i + 1; j < arrX.Length; j++)  
  66.             {  
  67.                 if (arrX[i] > arrX[j])  
  68.                 {  
  69.                     double dTempX = arrX[i];  
  70.                     double dTempY1 = arrY1[i];  
  71.                     double dTempY2 = arrY2[i];  
  72.                     arrX[i] = arrX[j];  
  73.                     arrY1[i] = arrY1[j];  
  74.                     arrY2[i] = arrY2[j];  
  75.                     arrX[j] = dTempX;  
  76.                     arrY1[j] = dTempY1;  
  77.                     arrY2[j] = dTempY2;  
  78.                 }  
  79.             }  
  80.         }  
  81.  
  82.         // X轴数组的最大值  
  83.         xMax = arrX[arrX.Length - 1];  
  84.  
  85.         if (xMax < 1)  
  86.         {  
  87.             for (int i = 0; i < 10; i++)  
  88.             {  
  89.                 if ((xMax <= Math.Pow(10, -i)) && (xMax > Math.Pow(10, -(i + 1))))  
  90.                 {  
  91.                     if (xMax <= 5 * Math.Pow(10, -(i + 1)))  
  92.                     {  
  93.                         xMax = (5 * Math.Pow(10, -(i + 1)));  
  94.  
  95.                     }  
  96.                     else 
  97.                     {  
  98.                         xMax = Math.Pow(10, -i);  
  99.                     }  
  100.                     break;  
  101.                 }  
  102.             }  
  103.  
  104.         }  
  105.         else 
  106.         {  
  107.             for (int i = 0; i < 10; i++)  
  108.             {  
  109.                 if ((xMax > Math.Pow(10, i)) && (xMax <= Math.Pow(10, (i + 1))))  
  110.                 {  
  111.                     if (xMax <= 5 * Math.Pow(10, i))  
  112.                     {  
  113.                         xMax = (5 * Math.Pow(10, i));  
  114.  
  115.                     }  
  116.                     else 
  117.                     {  
  118.                         xMax = Math.Pow(10, (i + 1));  
  119.                     }  
  120.                     break;  
  121.                 }  
  122.             }  
  123.         }  
  124.  
  125.         // X轴一个单位的大小  
  126.         xUnit = xMax / 10;  
  127.         for (int i = 0; i < arrX.Length; i++)  
  128.         {  
  129.             arrXUnit[i] = (float)(arrX[i] / xUnit);  
  130.         }  
  131.  
  132.         // Y轴数组的最大值  
  133.         for (int i = 0; i < arrY1.Length; i++)  
  134.         {  
  135.             if (arrY1[i] < 0)  
  136.             {  
  137.                 return;  
  138.             }  
  139.  
  140.             if (yMax < arrY1[i])  
  141.             {  
  142.                 yMax = arrY1[i];  
  143.             }  
  144.         }  
  145.         for (int i = 0; i < arrY2.Length; i++)  
  146.         {  
  147.             if (arrY2[i] < 0)  
  148.             {  
  149.                 return;  
  150.             }  
  151.  
  152.             if (yMax < arrY2[i])  
  153.             {  
  154.                 yMax = arrY2[i];  
  155.             }  
  156.         }  
  157.  
  158.         if (yMax < 1)  
  159.         {  
  160.             for (int i = 0; i < 10; i++)  
  161.             {  
  162.                 if ((yMax <= Math.Pow(10, -i)) && (yMax > Math.Pow(10, -(i + 1))))  
  163.                 {  
  164.                     if (yMax <= 5 * Math.Pow(10, -(i + 1)))  
  165.                     {  
  166.                         yMax = (5 * Math.Pow(10, -(i + 1)));  
  167.  
  168.                     }  
  169.                     else 
  170.                     {  
  171.                         yMax = Math.Pow(10, -i);  
  172.                     }  
  173.                     break;  
  174.                 }  
  175.             }  
  176.  
  177.         }  
  178.         else 
  179.         {  
  180.             for (int i = 0; i < 10; i++)  
  181.             {  
  182.                 if ((yMax > Math.Pow(10, i)) && (yMax <= Math.Pow(10, (i + 1))))  
  183.                 {  
  184.                     if (yMax <= 5 * Math.Pow(10, i))  
  185.                     {  
  186.                         yMax = (5 * Math.Pow(10, i));  
  187.  
  188.                     }  
  189.                     else 
  190.                     {  
  191.                         yMax = Math.Pow(10, (i + 1));  
  192.                     }  
  193.                     break;  
  194.                 }  
  195.             }  
  196.         }  
  197.  
  198.         // Y轴一个单位的大小  
  199.         yUnit = yMax / 10;  
  200.         for (int i = 0; i < arrX.Length; i++)  
  201.         {  
  202.             arrY1Unit[i] = (float)(arrY1[i] / yUnit);  
  203.             arrY2Unit[i] = (float)(arrY2[i] / yUnit);  
  204.         }  
  205.  
  206.         PointF cpt = new PointF(iScaleX + 10, iScaleX + iScaleY * 13);//中心点  
  207.         PointF[] xpt = new PointF[3] { new PointF(iScaleX * 15 + 15, cpt.Y), new PointF(iScaleX * 15, cpt.Y - 8), new PointF(iScaleX * 15, cpt.Y + 8) };//x轴三角形  
  208.         PointF[] ypt = new PointF[3] { new PointF(cpt.X, cpt.X - 15), new PointF(cpt.X - 8, cpt.X), new PointF(cpt.X + 8, cpt.X) };//y轴三角形  
  209.         gph.DrawString(strTitle, new Font("宋体", 14), Brushes.Black, new PointF(cpt.X + iScaleX * 2, cpt.X));//图表标题  
  210.  
  211.         // 第一条折线的图例  
  212.         gph.DrawLine(Pens.Red, iScaleX * 13, cpt.X + 5 + 10, iScaleX * 13 + 10, cpt.X + 5 + 10);  
  213.         gph.DrawString(strY1Name, new Font("宋体", 11), Brushes.Red, new PointF(iScaleX * 13 + 10, cpt.X + 10));//Y1  
  214.  
  215.         // 第二条折线的图例  
  216.         gph.DrawLine(Pens.Blue, iScaleX * 13, cpt.X + 5 + 40, iScaleX * 13 + 10, cpt.X + 5 + 40);  
  217.         gph.DrawString(strY2Name, new Font("宋体", 11), Brushes.Blue, new PointF(iScaleX * 13 + 10, cpt.X + 40));//Y2  
  218.  
  219.         //画x轴  
  220.         gph.DrawLine(Pens.Black, cpt.X, cpt.Y, iScaleX * 15, cpt.Y);  
  221.         gph.DrawPolygon(Pens.Black, xpt);  
  222.         gph.FillPolygon(new SolidBrush(Color.Black), xpt);  
  223.         gph.DrawString(strXUnitName, new Font("宋体", 12), Brushes.Black, new PointF(iScaleX * 15 + 10, cpt.Y + 10));  
  224.  
  225.         //画y轴  
  226.         float fStartX = 0;  
  227.         if (iScaleX > 30)  
  228.         {  
  229.             fStartX = iScaleX - 30;  
  230.         }  
  231.         gph.DrawLine(Pens.Black, cpt.X, cpt.Y, cpt.X, cpt.X);  
  232.         gph.DrawPolygon(Pens.Black, ypt);  
  233.         gph.FillPolygon(new SolidBrush(Color.Black), ypt);  
  234.         gph.DrawString(strYUnitName, new Font("宋体", 12), Brushes.Black, new PointF(fStartX, 7));  
  235.  
  236.         //画x轴项目  
  237.         for (int i = 1; i <= 12; i++)  
  238.         {  
  239.             gph.DrawString(Convert.ToString(i * xUnit), new Font("宋体", 11), Brushes.Black, new PointF(cpt.X + i * iScaleX - 5, cpt.Y + 10));  
  240.             gph.DrawLine(Pens.Black, cpt.X + i * iScaleX, cpt.Y, cpt.X + i * iScaleX, cpt.Y + 3);  
  241.         }  
  242.  
  243.         //画y轴刻度  
  244.         for (int i = 1; i <= 10; i++)  
  245.         {  
  246.             gph.DrawString(Convert.ToString(i * yUnit), new Font("宋体", 11), Brushes.Black, new PointF(fStartX, cpt.Y - i * iScaleY - 6));  
  247.             gph.DrawLine(Pens.Black, cpt.X - 3, cpt.Y - i * iScaleY, cpt.X, cpt.Y - i * iScaleY);  
  248.         }  
  249.  
  250.         for (int i = 1; i <= arrX.Length; i++)  
  251.         {  
  252.  
  253.             /*  
  254.              * 第一条折线  
  255.              */ 
  256.             //画点  
  257.             gph.DrawEllipse(Pens.Black, cpt.X + arrXUnit[i - 1] * iScaleX - 1.5f, cpt.Y - arrY1Unit[i - 1] * iScaleY - 1.5f, 3, 3);  
  258.             gph.FillEllipse(new SolidBrush(Color.Black), cpt.X + arrXUnit[i - 1] * iScaleX - 1.5f, cpt.Y - arrY1Unit[i - 1] * iScaleY - 1.5f, 3, 3);  
  259.  
  260.             //画数值  
  261.             gph.DrawString(arrY1[i - 1].ToString(".00"), new Font("宋体", 11), Brushes.Red, new PointF(cpt.X + arrXUnit[i - 1] * iScaleX, cpt.Y - arrY1Unit[i - 1] * iScaleY));  
  262.  
  263.             //画折线  
  264.             if (i > 1)  
  265.             {  
  266.                 gph.DrawLine(Pens.Red, cpt.X + arrXUnit[i - 2] * iScaleX, cpt.Y - (float)arrY1Unit[i - 2] * iScaleY, cpt.X + arrXUnit[i - 1] * iScaleX, cpt.Y - arrY1Unit[i - 1] * iScaleY);  
  267.             }  
  268.             /*  
  269.              * 第二条折线  
  270.              */ 
  271.             //画点  
  272.             gph.DrawEllipse(Pens.Black, cpt.X + arrXUnit[i - 1] * iScaleX - 1.5f, cpt.Y - arrY2Unit[i - 1] * iScaleY - 1.5f, 3, 3);  
  273.             gph.FillEllipse(new SolidBrush(Color.Black), cpt.X + arrXUnit[i - 1] * iScaleX - 1.5f, cpt.Y - arrY2Unit[i - 1] * iScaleY - 1.5f, 3, 3);  
  274.  
  275.             //画数值  
  276.             gph.DrawString(arrY2[i - 1].ToString(".00"), new Font("宋体", 11), Brushes.Blue, new PointF(cpt.X + arrXUnit[i - 1] * iScaleX, cpt.Y - arrY2Unit[i - 1] * iScaleY));  
  277.  
  278.             //画折线  
  279.             if (i > 1)  
  280.             {  
  281.                 gph.DrawLine(Pens.Blue, cpt.X + arrXUnit[i - 2] * iScaleX, cpt.Y - (float)arrY2Unit[i - 2] * iScaleY, cpt.X + arrXUnit[i - 1] * iScaleX, cpt.Y - arrY2Unit[i - 1] * iScaleY);  
  282.             }  
  283.  
  284.         }  
  285.     }  
调用代码:
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Drawing;  
  4. using System.Drawing.Imaging;  
  5. using System.Linq;  
  6. using System.Web;  
  7. using System.Web.UI;  
  8. using System.Web.UI.WebControls;  
  9.  
  10. public partial class Default3 : System.Web.UI.Page  
  11. {  
  12.     protected void Page_Load(object sender, EventArgs e)  
  13.     {  
  14.  
  15.         /*  
  16.          * 画图初始化  
  17.          */ 
  18.         int iScaleX = 20;  
  19.         int iScaleY = 20;  
  20.         // 空白位图  
  21.         Bitmap bmap = new System.Drawing.Bitmap(iScaleX * 16 + 100, iScaleY * 16 + 50);  
  22.         // X轴数组   
  23.         double[] arrX = new double[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };  
  24.         // Y轴数组  
  25.         double[] arrY1 = new double[10] { 20.5f, 60, 10.8f, 15.6f, 30, 70.9f, 50.3f, 30.7f, 70, 50.4f };  
  26.         double[] arrY2 = new double[10] { 40.5f, 80, 20.8f, 30.6f, 15, 30.9f, 20.3f, 60.7f, 50, 80.4f };  
  27.         // 标题             
  28.         string strTitle = "某工厂某产品月生产量图表";  
  29.         // X轴单位名称          
  30.         string strXUnitName = "月份";  
  31.         // Y周轴单位名称    
  32.         string strYUnitName = "单位(万)";  
  33.         // 第1条折线图例名称  
  34.         string strY1Name = "第1条折线";  
  35.         // 第2条折线图例名称  
  36.         string strY2Name = "第2条折线";  
  37.         // 返回绘制的折线图  
  38.         Graphics gph = null;  
  39.  
  40.         ClassDrawing classDrawing = new ClassDrawing();  
  41.         classDrawing.drawLineGraphY2(ref bmap, ref  iScaleX, ref  iScaleY, ref  arrX, ref  arrY1, ref  arrY2, ref strTitle, ref strXUnitName, ref strYUnitName, ref strY1Name, ref strY2Name, out gph);  
  42.  
  43.         //输出到浏览器  
  44.         System.IO.MemoryStream ms = new System.IO.MemoryStream();  
  45.         bmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);  
  46.         Response.ClearContent();  
  47.         Response.ContentType = "p_w_picpath/Gif";  
  48.         Response.BinaryWrite(ms.ToArray());  
  49.         gph.Dispose();  
  50.         bmap.Dispose();  
  51.  
  52.     }