О рисовании простейших диаграмм в приложениях Windows

logo.gif

На главную страницу

К началу книги

О рисовании простейших диаграмм в приложениях Windows

Аннотация: Данная статья написана после очередного вопроса или даже просьбы - прислать исходный код, для того, чтобы рисовать простейшие диаграммы, как это сделано в популярной программе "LitFrequencyMeter - программа определения частоты повторения слов и знаков в текстах, литературных произведениях, статьях и документах". Устав отвечать на вопросы и посылать куски кода (первое правило программиста - "Вы можете поделиться частью кода программы, но никогда не кодом всей программы - иначе все будут знать какой вы плохой программист"), а без шуток, когда минимум 3-5 писем в месяц с подобными пожеланиями, то невольно приходишь к мысли, чем писать лишних пять писем в месяц, лучше поместить кусок кода на сайте - умный разберется что к чему, а кому не дано, хоть спрашивать не будет из-за того, что не смог разобраться. Поэтому на сайте приведен класс из программы "LitFrequencyMeter", позволяющий рисовать простейшие диаграммы: линейную, гистограмму и круговую. Тот минимум комментариев, который присутствует в тексте кода, по мнению автора достаточен для самостоятельной работы по включению класса в свой код программы.

В начало

Параграф 1. Класс рисования простейших диаграмм

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace SearcherPhrases
{
 class PaitCl
 {
  //Специально подобранные заливки и цвета
  private Brush[] br ={Brushes.LightGreen,Brushes.Chartreuse,Brushes.LimeGreen,Brushes.Green,Brushes.DarkGreen,
                        Brushes.DarkOliveGreen,Brushes.LightPink,Brushes.LightSeaGreen,Brushes.LightCoral,Brushes.DarkCyan ,
                        Brushes.Crimson,Brushes.CornflowerBlue ,Brushes.Chocolate,Brushes.CadetBlue,Brushes.BlueViolet, 
                        Brushes.Maroon, Brushes.Blue,Brushes.Brown,Brushes.DarkBlue, Brushes.Red,
                        Brushes.Coral,Brushes.DarkRed, Brushes.DarkMagenta, Brushes.DarkOrange,Brushes.DarkOrchid};


  private Color[] color ={Color.LightGreen,Color.Chartreuse,Color.LimeGreen,Color.Green,Color.DarkGreen,
                           Color.DarkOliveGreen,Color.LightPink ,Color.LightSeaGreen,Color.LightCoral ,Color.DarkCyan ,
                           Color.Crimson , Color.CornflowerBlue ,Color.Chocolate,Color.CadetBlue,Color.BlueViolet,
                           Color.Maroon,Color.Blue,Color.Brown,Color.DarkBlue, Color.Red,
                           Color.Coral,Color.DarkRed, Color.DarkMagenta, Color.DarkOrange,Color.DarkOrchid};
  //Будущий рисунок
  private Bitmap bmp = null;
  private Graphics graph = null;
  //Размер рисунка
  private int viX = 0;
  private int viY = 0;
  private float vfXcirc = 0;
  private float vfYcirc = 0;
  private float viDiamX = 0;
  private float viDiamY = 0;  
  //Разиер массива отображаемых значений
  private int viMaxRg = 0;
  //Массив значений для отображения
  private string[,] rgsZn = null;
  //Шрифт по умолчанию
  private Font objFont =  new Font("Arial", 8, FontStyle.Bold);
  private Brush objBrush = null;
  //Карандаш
  private Pen objPenLine = null;
  //Отступы осей от краев холста
  private int viDeltaaxisL = 0;
  private int viDeltaaxisR = 0;
  private int viDeltaaxisH = 0;
  private Color colorFont = Color.Black; 

  #region Конструкторы 
  //Первый
  public PaitCl(int a, int b)
  {
      bmp = new Bitmap(a, b);
      graph = Graphics.FromImage(bmp);
      viX = a;
      viY = b;
      //Карандаш по умолчанию         
      objPenLine = new Pen(Color.Black, 1);
      //Кисть по умолчанию
      objBrush = Brushes.Black;
  }
  //Второй
  public PaitCl()
  {
      //Карандаш по умолчанию
      objPenLine = new Pen(Color.Black, 1);
      //Кисть по умолчанию
      objBrush = Brushes.Black;
  }
  #endregion

  #region Создание картинки при использовании второго конструктора 
  public void NewBitmap(int a, int b)
  {
      bmp = new Bitmap(a, b);
      graph = Graphics.FromImage(bmp);
      viX = a;
      viY = b;
  }
  #endregion

  #region Установка цвет фона диаграммы 
  public void vSetBackground(Color bcl)
  {
      graph.Clear(bcl);
  }
  #endregion

  #region Карандаш, шрифт, кисть 
  //Цвет карандаша
  public void vSetPenColorLine(Color pcl)
  {
      if (objPenLine == null)
      {
          objPenLine = new Pen(Color.Black, 1);
      }
      objPenLine.Color = pcl;

  }
  //Установка толщина карандаша        
  public void vSetPenWidthLine(int penwidth)
  {
      if (objPenLine == null)
      {
          objPenLine = new Pen(Color.Black, 1);
      }
      objPenLine.Width = penwidth;

  }       
  //Установка шрифта
  public void vSetFont(string name, float size, bool bold)
  {
      if (objFont != null) objFont = null;
      if (bold)
      {
          objFont = new Font(name, size, FontStyle.Bold);
      }
      else
      {
          objFont = new Font(name, size);
      }
  }
  public void vSetObjFont(Font fnt)
  {
      objFont=fnt;
  }
  //Цвет шрифта
  public void vSetFontColor(Color color)
  {
      colorFont = color;
  }
  //Принудительная кисть	
  public void vSetBrush(Brush brush)
  {
      objBrush = brush;
  }
  #endregion        

  #region Создание массива 
  public void vCreateRg(int a)
  {
      viMaxRg = a;
      rgsZn = new string[a, 2];
  }
  #endregion

  #region Перенос массива строк в класс 
  public void vWriteRg(int a, string s1, string s2)
  {
      rgsZn[a, 0] = s1;
      rgsZn[a, 1] = s2;
  }
  #endregion

  #region Доступ к переменным класса
  public Bitmap bmpGet()
  {
      return bmp;
  }
  public int iGetX()
  {
      return viX;
  }
  public int iGetY()
  {
      return viY;
  }
  #endregion

  #region Использование картинки для рисования на ней 
  public void vSet(Bitmap bmpSet)
  {
      if (bmp == null)
      {
          bmp = new Bitmap(bmpSet.Width, bmpSet.Height);
      }
      bmp = bmpSet;
      graph = Graphics.FromImage(bmp);
  }
  #endregion

  #region Рисование линии 
  public void vDravLine(int a, int b, int c, int d)
  {
    graph.DrawLine(objPenLine, a, b, c, d);
  }
  #endregion

  #region Рисование Осей 
  public void vDravAxis(int deltaaxisL, int deltaaxisR, int deltaaxisH, Color colorpenaxis, int widthpen)
  {
      //Запоминаем отступы                        
      viDeltaaxisL = deltaaxisL;
      viDeltaaxisR = deltaaxisR;
      viDeltaaxisH = deltaaxisH;

      //Запоминаем цвет осей и толщину
      vSetPenColorLine(colorpenaxis);
      if (widthpen > 0) vSetPenWidthLine(widthpen);
      //Точка начала рисования по х и y           
      int x = deltaaxisL;
      int y = viY - deltaaxisH;
      int x1 = viX - deltaaxisR;
      int y1 = deltaaxisH;
      int d = widthpen * 10;
      //Оси на d пикселей длинней для стрелок
      graph.DrawLine(objPenLine, x, y, x1 + d, y);
      graph.DrawLine(objPenLine, x, y, x, y1 - d);
      int a = 10 * (int)objPenLine.Width;
      int b = 2 * (int)objPenLine.Width;
      int x2 = x1 - a;
      int y2 = y + b;
      //Стрелки
      graph.DrawLine(objPenLine, x1 + 20, y, x2 + d, y2);
      y2 = y - b;
      graph.DrawLine(objPenLine, x1 + 20, y, x2 + d, y2);
      x2 = x - b;
      y2 = y1 + a;
      graph.DrawLine(objPenLine, x, y1 - d, x2, y2 - d);
      x2 = x + b;
      graph.DrawLine(objPenLine, x, y1 - d, x2, y2 - d);
  }        
  #endregion
  
  #region Рисование сетки
  public void vDravGrid()
  {
      float x = viDeltaaxisL;// -objPenLine.Width;
      float y = viY - viDeltaaxisH;// +objPenLine.Width;
      float x1 = viX - viDeltaaxisR;// +objPenLine.Width;
      float y1 = viDeltaaxisH;// -objPenLine.Width;
      float f = (y - y1) / (float)viMaxRg;
      for (int i = 1; i < viMaxRg + 1; i++)
      {
          graph.DrawLine(objPenLine, x, y - f * i, x1, y - f * i);
      }
      f = (x - x1) / (float)(viMaxRg-1);
      for (int i = 1; i < viMaxRg; i++)
      {
          graph.DrawLine(objPenLine, x - f * i, y, x-f*i, y1);
      }
  }
  #endregion

  #region Рисование линий графика для линейного графика 
  public void vDrawGraphLines()
  {
      string s = string.Empty;
      string s1 = string.Empty;
      string s2 = string.Empty;
      float f = 0;
      float f1 = 0;
      float x1 = 0;
      float x = viDeltaaxisL;//-objPenLine.Width;
      float y = viY - viDeltaaxisH;// +objPenLine.Width;
      float x2 = 0;
      float fMax = float.MinValue;
      //float fMin = int.MaxValue;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          if (string.IsNullOrEmpty(s)) break;
          if (fMax < float.Parse(s)) fMax = float.Parse(s);
      }
      //Пикселей для рисования по оси х
      float fdeltax = viX - viDeltaaxisL - viDeltaaxisR;
      //Пикселей на один отсчет
      fdeltax = fdeltax / (float)(viMaxRg - 1);
      //Пикселей для рисования по оси y
      float fdeltay = viY - 2 * viDeltaaxisH;
      //Пикселей на одну единицу массива значений
      fdeltay = fdeltay / fMax;
      for (int i = 0; i < viMaxRg; i++)
      {
          //Первый раз запоминаем точку старта
          if (i == 0)
          {
              s = rgsZn[i, 0];
              s2 = rgsZn[i, 1];
              f = y - (float.Parse(s) * fdeltay);
              x1 = x;
          }
          else
          {
              s1 = rgsZn[i, 0];
              if (string.IsNullOrEmpty(s1)) break;
              f1 = y - (float.Parse(s1) * fdeltay);
              x2 = x + (int)(fdeltax * i);
              graph.DrawLine(objPenLine, x1, f, x2, f1);
              s = rgsZn[i, 0];
              s2 = rgsZn[i, 1];
              f = f1;
              x1 = x + (int)(i * fdeltax);
          }
      }
  }
  #endregion

  
  #region Рисование графика для гистограммы
  public void vDrawGraphRectangular(int a,int c)
  {            
      string s = string.Empty;
      string s1 = string.Empty;
      string s2 = string.Empty;
      float f = 0;           
      float x1 = 0;
      float x = viDeltaaxisL;
      float y = viY - viDeltaaxisH;            
      float fMax = float.MinValue;            
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          if (fMax < float.Parse(s)) fMax = float.Parse(s);
      }
      //Пикселей для рисования по оси х
      float fdeltax = viX - viDeltaaxisL - viDeltaaxisR;
      //Пикселей на один отсчет
      fdeltax = fdeltax / (float)(viMaxRg - 1);            
      //Пикселей для рисования по оси y
      float fdeltay = viY - 2 * viDeltaaxisH;
      //Пикселей на одну единицу массива значений
      fdeltay = fdeltay / fMax;
      float fdx=0;
      if (c != 0) fdx = (fdeltax * c / 100)/2;
      Random rand = new Random(DateTime.Now.Millisecond);
      int arn = rand.Next((int)br.Length);
      objBrush = br[arn];
      for (int i = 0; i < viMaxRg - 1; i++)
      {
          s = rgsZn[i, 0];
          f = float.Parse(s);
          x1 = x + ((float)i * fdeltax);
          if (a == 0)
          {
              graph.FillRectangle(objBrush, x1 + fdx, y - fdeltay * f, fdeltax - 2 * fdx, fdeltay * f);
          }
          else
          {
              int b = i % br.Length;
              graph.FillRectangle(br[b], x1 + fdx, y - fdeltay * f, fdeltax - 2 * fdx, fdeltay * f);
          }
          if (i == viMaxRg - 2)
          {
              int b=(i+1) % br.Length;
              s = rgsZn[i+1, 0];
              f = float.Parse(s);
              x1 = x + ((float)(i+1) * fdeltax);
              if (a == 0)
              {
                  graph.FillRectangle(objBrush, x1-2, y - fdeltay * f, 4/*fdeltax*/, fdeltay * f);
                  
              }
              else
              {
                  graph.FillRectangle(br[b], x1-2, y - fdeltay * f, 4/*fdeltax*/, fdeltay * f);
              }
          }
      }
  }
  #endregion
  
  #region Текст по оси X - цифры 1-размер массива 
  public void vDrawTextAxXNumber(bool f)
  {
      //Пикселей для надписей по оси х
      float fdeltax = viX - viDeltaaxisL - viDeltaaxisR;
      //Пикселей на один отсчет
      fdeltax = fdeltax / (float)(viMaxRg - 1);
      float x = viDeltaaxisL;
      float y = viY - viDeltaaxisH + objPenLine.Width;
      for (int i = 1; i < viMaxRg + 1; i++)
      {
          if (!f || i % 2 == 0)
          {
              graph.DrawString(Convert.ToString(i), objFont, objBrush, x + (i - 1) * fdeltax, y);
          }
          else
          {
              
              graph.DrawString(Convert.ToString(i), objFont, objBrush, x + (i - 1) * fdeltax, y + objFont.Size);
          }
      }
  }
  #endregion

  #region Текст по оси X - Значения
  public void vDrawTextAxXValues(bool f)
  {
      string s = string.Empty;
      //Пикселей для надписей по оси х
      float fdeltax = viX - viDeltaaxisL - viDeltaaxisR;
      //Пикселей на один отсчет
      fdeltax = fdeltax / (float)(viMaxRg - 1);
      float x = viDeltaaxisL;
      float y = viY - viDeltaaxisH;// +objPenLine.Width;
      for (int i = 0; i < viMaxRg; i++)
      {
          if (!f || i % 2 == 0)
          {
              graph.DrawString(rgsZn[i, 1], objFont, objBrush, x + i * fdeltax, y);
          }
          else
          {
              graph.DrawString(rgsZn[i, 1], objFont, objBrush, x + i * fdeltax, y+ objFont.Size);
          }
      }
  }
  #endregion

  #region Текст по оси Y - Значения по сетке
  public void vDrawTextAxYValues()
  {
     
      string s = string.Empty;
      float f = 0;           
      float fMax = float.MinValue;            
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          if (string.IsNullOrEmpty(s)) break;
          if (fMax < float.Parse(s)) fMax = float.Parse(s);
      }
      f = fMax / (float)(viMaxRg-1);
      //Пикселей для надписей по оси х
      float fdeltay = viY - 2 * viDeltaaxisH;
      //Пикселей на один отсчет
      fdeltay = fdeltay / (float)(viMaxRg-1);
      float y = viY - viDeltaaxisH - objFont.Size;
      for (int i = 0; i < viMaxRg; i++)
      {
          graph.DrawString(((float)(i * f)).ToString("0.00"), objFont, o
                     bjBrush, viDeltaaxisL - (objFont.Size)*5-5, y - i * fdeltay);
      }
  }
  #endregion

  #region Надписи по оси Y - Значения  над точкой
  public void vDrawTextAxYValuesPoint(int a, int b)
  {
      string s = string.Empty;
      float fMax = float.MinValue;
      float fSum = 0;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          if (string.IsNullOrEmpty(s)) break;
          fSum += float.Parse(s);
          if (fMax < float.Parse(s)) fMax = float.Parse(s);
      }            
      //Пикселей для надписей по оси х
      float fdeltax = viX - viDeltaaxisL - viDeltaaxisR;
      //Пикселей на один отсчет по х
      fdeltax = fdeltax / (float)(viMaxRg - 1);
      float x = viDeltaaxisL;
      float fdeltay = viY - 2 * viDeltaaxisH;
      float y = viY - viDeltaaxisH - objFont.Size;
      //Пикселей на одну единицу
      fdeltay = fdeltay / fMax;
      float fdelta = 0;            
      for (int i = 0; i < viMaxRg; i++)
      {
          if (a == 1)
          {
              if (i % 2 == 0) fdelta = objFont.Size;
              else fdelta = 2 * objFont.Size;
          }
          else
          {
              fdelta = objFont.Size;
          }
          if (b == 0)
          {
              graph.DrawString(rgsZn[i, 0], objFont, objBrush, x + i * fdeltax,
                  y - (float.Parse(rgsZn[i, 0]) * fdeltay) - fdelta);
          }
          else
          {
              s = rgsZn[i, 0];
              if (string.IsNullOrEmpty(s)) break;
              float fp = float.Parse(s);
              fp = (fp * 100) / fSum;

              graph.DrawString(rgsZn[i, 0] + "-" + fp.ToString("0.0")+"%", objFont, objBrush, x + i * fdeltax,
                                     y - (float.Parse(rgsZn[i, 0]) * fdeltay) - fdelta);

          }
      }

  }
  #endregion

  #region Нарисовать круг отступ от краев цвет толщина круга обводки 
  public void vDravCircle(int deltaaxisL,int deltaaxisR,int deltaaxisH, Color colorpenaxis, int widthpen)
  {
      //Запоминаем отступы            
      viDeltaaxisL = deltaaxisL;
      viDeltaaxisR = deltaaxisR;
      viDeltaaxisH = deltaaxisH;
      //Запоминаем цвет осей и толщину
      vSetPenColorLine(colorpenaxis);
      if (widthpen > 0) vSetPenWidthLine(widthpen);
      float a = viY;
      float b = 0;
      if (viX - (viDeltaaxisL + viDeltaaxisR) < viY - 2*deltaaxisH) 
      { 
          a = viX; 
          b = 1; 
      }
      //Диаметр окружности
      if (b == 0)
      {
          a -= 2*deltaaxisH;
      }
      else
      {
          a -= (deltaaxisL + deltaaxisR);
      }
      //Запоминаем диаметр
      viDiamX = a;           
      //Запоминаем центр окружности
      if (b == 0)
      {
          vfXcirc = deltaaxisL + a / 2;
          vfYcirc = viY / 2;
      }
      else
      {
          vfXcirc = deltaaxisL+ a/2;
          vfYcirc = viY / 2;// +deltaaxisH;
      }
      //Просто круг ободка 
      graph.DrawEllipse(objPenLine, vfXcirc - a / 2, vfYcirc - a / 2, a - 1, a - 1);          
      float fSum = 0;
      string s = string.Empty;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          fSum += float.Parse(s);
      }
      float f = 0;
      float fBSum = 0;
      //Рисуем секторы
      float fDeltaGrad = fSum / 360;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          f = float.Parse(s);
          //f в градусах
          f = f / fDeltaGrad;              
          int j = i % br.Length;
          float k = f;
          if (f < 1) k = 1;
          graph.FillPie(br[j], vfXcirc - a / 2 + widthpen / 2, vfYcirc - a / 2 + widthpen / 2,
              a - widthpen, a - widthpen, fBSum, k);
          fBSum += f;               
      } 
  }
  #endregion

  #region vDravTextCircle
  public void vDravTextCircle(int viGde, int viDelta)
  {
      float fSum = 0;
      string s = string.Empty;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          fSum += float.Parse(s);
      }
      float f = 0;
      float fBSum = 0;
      float f1Radian = (float)Math.PI / 180;

      //Рисуем секторы
      float fDeltaGrad = fSum / 360;

      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          f = float.Parse(s);
          //f в градусах
          f = f / fDeltaGrad;
          int j = i % br.Length;               
          //Угол в радианах
          float fRad = (f + fBSum) * f1Radian;
          float fty = 0;
          float ftx = 0;
          float ftxd = 0;
          //if ((i % 2) != 0) ftxd = viDeltaaxisL / 2;
          if ((f / 2 + fBSum) < 90 || (f / 2 + fBSum) > 270)
          {
              if ((f / 2 + fBSum) < 90) ftxd = viDelta/5; else ftxd = viDelta;
              ftx = vfXcirc + (viDiamX / 2) * (float)Math.Cos((360 - (f / 2 + fBSum)) * f1Radian) + ftxd;
          }
          else
          {
              ftxd = -3 * viDelta;
              ftx = vfXcirc + (viDiamX / 2) * (float)Math.Cos((360 - (f / 2 + fBSum)) * f1Radian) + ftxd;
          }
          if ((f / 2 + fBSum) < 180)
          {
              fty = vfYcirc - (viDiamY / 2) * (float)Math.Sin((360 - (f / 2 + fBSum)) * f1Radian);
          }
          else
          {
              ftxd = -15;
              fty = vfYcirc - (viDiamY / 2) * (float)Math.Sin((360 - (f / 2 + fBSum)) * f1Radian) + ftxd;
          }
          vSetBrush(br[j]);
          if (viGde == 1)
          {
              graph.DrawString(rgsZn[i, 0], objFont, objBrush, ftx, fty);
          }
          else
          {
              graph.DrawString(Convert.ToString(i + 1), objFont, objBrush, ftx, fty);
          }
          fBSum += f;               
      }
  }



  #endregion




  #region Текст истории

  public void vDravTextKeyCircle(bool vfGde)
  {
      float fSum = 0;
      float f = 0;
      string s = string.Empty;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          fSum += float.Parse(s);
      }
      //Сдвиг от круговой диаграммы
      float vfSdvig = vfXcirc + viDiamX / 2;
      vfSdvig+=(viX - vfSdvig) / 5;             
      //Высота места для легенды
      //На одну строку по высоте отводится - +1 на заголовок
      float vfHg = viY / (viMaxRg + 2);
      vSetFont("Arial", 12, true);
      if (viMaxRg > 100)
      {
          graph.DrawString("Легенда не может быть размещена", objFont, 
                Brushes.DarkBlue, vfSdvig + (viX - vfSdvig) / 10, objFont.Size);

      }
      else
      {
          //Шрифт в 2 раза меньше места на строку надписи
          if (viMaxRg > 15)
          {
              vSetFont("Arial", (vfHg / 2), true);
          }
          else
          {
              if (viMaxRg > 10)
              {
                  vSetFont("Arial", (vfHg / 3), true);
              }
              else
              {
                  vSetFont("Arial", (vfHg / 6), true);
              }
          }
          if (vfGde)
          {
              graph.DrawString("Пояснения к графику", objFont, Brushes.DarkBlue, 
                                               vfSdvig /*+ (viX - vfSdvig) / 10*/, objFont.Size);
          }
          else
          {
              graph.DrawString("Пояснения к графику", objFont, 
                                     objBrush, vfSdvig/* + (viX - vfSdvig) / 10*/, objFont.Size);
          }
          if (viMaxRg > 15)
          {
              vSetFont("Arial", (vfHg / 2) + 1, true);
          }
          else
          {
              if (viMaxRg > 10)
              {
                  vSetFont("Arial", (vfHg / 4)+1, true);
              }
              else
              {
                  vSetFont("Arial", (vfHg / 7)+1, true);
              }
          }

          for (int i = 0; i < rgsZn.Length / 2; i++)
          {
              Brush brTxt = null;
              int j = i % br.Length;
              if (vfGde) brTxt = br[j];
              else brTxt = objBrush;
              graph.DrawString(Convert.ToString(i + 1), objFont, brTxt, vfSdvig, vfHg * (i + 2));
              f = float.Parse(rgsZn[i, 0]);
              f = (f * 100) / fSum;
              graph.DrawString(rgsZn[i, 0], objFont, brTxt, vfSdvig + 1 * (viX - vfSdvig) / 5, vfHg * (i + 2));
              graph.DrawString(f.ToString("0.0") + "%", objFont, brTxt, vfSdvig + 2 * (viX - vfSdvig) / 5, vfHg * (i + 2));
              graph.DrawString(rgsZn[i, 1], objFont, brTxt, vfSdvig + 3 * (viX - vfSdvig) / 5, vfHg * (i + 2));
          }
      }
  }
  #endregion
  #region  vDravCircle3D
  //Параметры - Отступ от краев по X слева deltaaxisL, от краев по Y справа,
  //deltaaxisH - отступа сверху и снизу, толщина диаграммы viH, сдвиг сектора viDx, viDy
  public void vDravCircle3D(int deltaaxisL, int deltaaxisR, int deltaaxisH, int viH, int viDx, int viDy)
  {
      //Запоминаем отступы            
      viDeltaaxisL = deltaaxisL;
      viDeltaaxisR = deltaaxisR;
      viDeltaaxisH = deltaaxisH;                        
      float a = viX - (deltaaxisL + deltaaxisR);
      //Нужен ли выброс сектора
      int viMov = 1;
      if (viDx == 0 && viDy == 0)
      {
          viMov = 0;
      }
      //Запоминаем диаметр
      viDiamX = a;
      viDiamY = viY - 2 * viDeltaaxisH;
      //Запоминаем центр элипса
      vfXcirc = deltaaxisL + a / 2;
      vfYcirc = viY / 2;
      graph.SmoothingMode = SmoothingMode.AntiAlias;           
      float fSum = 0;
      string s = string.Empty;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          fSum += float.Parse(s);
      }
      float f = 0;
      float fBSum = 0;                    
      float fDeltaGrad = (fSum / (float)360);
      SolidBrush objBrush = new SolidBrush(Color.Aqua);           
      Random rand = new Random(DateTime.Now.Millisecond);
      float[] frgZn = new float[viMaxRg];
      float[] frgSumGr = new float[viMaxRg];
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          frgZn[i] = float.Parse(s);
          if (i == 0) frgSumGr[i] = 0;
          else frgSumGr[i] = frgZn[i] + frgSumGr[i - 1];
      }
      //Рисуем диаграмму против часовой стрелки со штриховкой до 90градусав по часовой
      //Штриховка убирается каждым следующим сектором от сектора предыдущего
      //В первом нарисованном секторе она сохраняетсяна случай сдвига первого по часовой стрелке
      for (int i = viMaxRg - 1; i >= 0; i--)
      {
          if (i != viMaxRg - 1 && fBSum < 90) break;
          //f в градусах  fBSum в градусах
          f = frgZn[i] / fDeltaGrad;
          //fBSum = frgSumGr[i] / fDeltaGrad;
          if (i == viMaxRg - 1)
          {
              fBSum = 360 - f;
          }
          else
          {
              fBSum -= f;
          }                
          //Для цвета
          int j = i % br.Length;
          float k = f;
          if (f < 1) k = 1;
          //objBrush.Color = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255));
          if (i != 0)
          {
              if ((fBSum > 90 && fBSum < 180) || i == viMaxRg - 1)
              {
                  for (int d = 0; d < viH; d++)
                  {
                      graph.FillPie(new HatchBrush(HatchStyle.Percent25, 
                            color[j]/*objBrush.Color*/), vfXcirc - a / 2, vfYcirc - viDiamY / 2 + d,
                          viDiamX, viDiamY, fBSum, k);                           
                  }                       
              }
              objBrush.Color = color[j];
              graph.FillPie(objBrush, vfXcirc - a / 2, vfYcirc - viDiamY / 2,
                   viDiamX, viDiamY, fBSum, k);
          }
      }

      //Рисуем до 90градусов без первого сегмента в случае необходимости сдвига первого по часовой стрелке
      fBSum=0;
      for (int i = viMov; i < viMaxRg; i++)
      {
          //f в градусах  fBSum в градусах
          f = frgZn[i] / fDeltaGrad;
          if (i == 1)
          {
              fBSum = frgZn[0] / fDeltaGrad;
          }
          //Для цвета
          int j = i % br.Length;
          float k = f;
          if (f < 1) k = 1;

          if (fBSum < 90)
          {
              for (int d = 0; d < viH; d++)
              {
                  graph.FillPie(new HatchBrush(HatchStyle.Percent25, 
                      color[j]), vfXcirc - a / 2, vfYcirc - viDiamY / 2 + d,
                      viDiamX, viDiamY, fBSum, k);
              }
              objBrush.Color = color[j];
              graph.FillPie(objBrush, vfXcirc - a / 2, vfYcirc - viDiamY / 2,
               viDiamX, viDiamY, fBSum, k);
          }
          else
          {
              break;
          }
          fBSum += f;
      }
      //Рисуем сдвинутый сектор при необходимости
      if (viMov == 1)
      {
          f = frgZn[0] / fDeltaGrad;
          fBSum = 0;
          float k1 = f;
          if (f < 1) k1 = 1;
          for (int d = 0; d < viH; d++)
          {
              graph.FillPie(new HatchBrush(HatchStyle.Percent25, color[0]), 
                            vfXcirc - a / 2 + viDx, vfYcirc - viDiamY / 2 + d - viDy,
                  viDiamX, viDiamY, fBSum, k1);
          }
          objBrush.Color = color[0];
          graph.FillPie(objBrush, vfXcirc - a / 2 + viDx, vfYcirc - viDiamY / 2 - viDy,
          viDiamX, viDiamY, fBSum, k1);
      }

  }
  #endregion


  #region vDravTextCircle
  public void vDravTextCircle1(bool vfGde)
  {
      float fSum = 0;
      string s = string.Empty;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          fSum += float.Parse(s);
      }
      float f = 0;
      float fBSum = 0;
      float f1Radian = (float)Math.PI / 180;
      float fDeltaGrad = fSum / 360;
      for (int i = 0; i < viMaxRg; i++)
      {
          s = rgsZn[i, 0];
          f = float.Parse(s);
          //f в градусах
          f = f / fDeltaGrad;
          int j = i % br.Length;
          //Угол в радианах
          float fRad = (f + fBSum) * f1Radian;
          float fty = 0;
          float ftx = 0;
          float fSin=(float)Math.Sin((360 - (f / 2 + fBSum)) * f1Radian);
          float fCos=(float)Math.Cos((360 - (f / 2 + fBSum)) * f1Radian);
          float c = (float)Math.Sqrt((viDiamX / 2 * viDiamX / 2 * viDiamY / 2 * viDiamY / 2) /
              (viDiamY / 2 * viDiamY / 2 * fCos * fCos + viDiamX / 2 * viDiamX / 2 * fSin * fSin));
          c -= 3 * objFont.Size;
          if (c < 0) c = 0;
          ftx = c * fCos;
          fty = c * fSin;
          ftx = vfXcirc + ftx;
          fty = vfYcirc - fty;               
          if (vfGde)
          {                           
              graph.DrawString(Convert.ToString(i + 1), objFont, objBrush, ftx, fty);
              
          }
          else
          {
              graph.DrawString(rgsZn[i, 1], objFont, objBrush, ftx, fty);
          }
          fBSum += f;
      }
  }
  #endregion
 }
        
}

В начало

Параграф 2. Чуточку пояснений

Шаг первый при рисовании диаграммы - Создаем класс:

PaitCl clPaint = new PaitCl();

При этом в конструкторе можно передать некоторые параметры.

Шаг второй - передаем массив значений для отображения в класс.

Шаг третий - передаем размеры холста.

Шаг четвертый - передаем фон холста

Шаг пятый -передаем цвет шрифта надписей имя, размер, стиль.

Шаг шестой - рисуем график (в функцию для рисования могут быть переданы доп. параметры: отступ осей x слева, x справа ,y от краев холста, толщина диаграммы, вынос сектора...

Шаг седьмой - забираем Bitmap из класса (clPaint.bmpGet()) и отображаем, например в PictureBox.

Молчанов Владислав 1.12.2008г.

logo.gif

В начало страницы

На главную страницу

К началу книги


Сайт управляется системой uCoz