65.9K
CodeProject 正在变化。 阅读更多。
Home

在网页上创建和显示漏斗图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (16投票s)

2008年10月7日

CPOL

1分钟阅读

viewsIcon

57485

downloadIcon

392

如何使用 C# 和 ASP.NET 在网页上创建和显示漏斗图。

引言

有时,为了提供更好的用户体验,需要以漏斗图的形式显示数据(财务数据),并且开发者可能需要从头开始编写漏斗图的显示代码。以下文章将帮助您编写漏斗图代码并在网页上显示它们。

使用代码

在创建漏斗图时,我们将它分成不同的切片。每个切片代表一个不同的阶段。在下面的示例中,每个切片都以不同的颜色显示。请查看下面的代码。代码中使用了 System.DrawingSystem.Drawing.Imaging 命名空间来绘制漏斗切片并将它们组合在一起形成漏斗。

FunnelChartCode

// This structure holds the details of each of the slices 
public struct Slice
{
    public string stageName;
    public int value;
    public double dollars;
    public Point[] coordinates;
    public Color color;
}

private Color[] colorPalette = new Color[]
                            {Color.LightSkyBlue,Color.LightGreen,
                             Color.PaleVioletRed,Color.SteelBlue};
// Following constants are used to initialize
// the funnel maximum height, width, slice gap 
private const int FUNNEL_HEIGHT = 106;
private const int IMAGE_WIDTH = 291;
private const int IMAGE_HEIGHT = 160;
private const int SLICE_GAP = 1; 
private Slice[] funnelSlices;


/// <summary>
/// This method initializes the funnel
/// </summary>
public void InitFunnel(int count)
{
    try
    {
        maxSlice = count;
        funnelSlices = new Slice[count];

        chartBMP = new Bitmap(IMAGE_WIDTH, IMAGE_HEIGHT, 
                              PixelFormat.Format32bppArgb);
        graphicsObj = Graphics.FromImage(chartBMP);
        // Draw the background
        graphicsObj.FillRectangle(new SolidBrush(Color.White), 
                                  0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
   
    }
    catch (Exception ex)
    {
        throw new Exception("Error initialising funnel", ex);
    }
}
//    0--------------3
//     \            /
//      \          /
//      1\_______/2

/// <summary>
/// Calculates the coordinates of the slice
/// </summary>
private void GetCoordinates(int sliceIndex)
{
    int sliceHeight;

    // Calculate the top points ie, 0 & 3
    if (sliceIndex == 0)
    {
        // The top 2 points are same as the funnel
        funnelSlices[sliceIndex].coordinates[0] = FUNNEL_BOUNDS[0];
        funnelSlices[sliceIndex].coordinates[3] = FUNNEL_BOUNDS[3];
    }
    else
    {
        // The top 2 points are same
        // as the bottom 2 points of the previous slice
        funnelSlices[sliceIndex].coordinates[0] = 
          funnelSlices[sliceIndex - 1].coordinates[1];
        funnelSlices[sliceIndex].coordinates[3] = 
          funnelSlices[sliceIndex - 1].coordinates[2];
    }


    // Calculate the bottom 2 points ie, 1 & 2
    if (sliceIndex == funnelSlices.Length - 1)
    {
        // The bottom 2 points are same as the funnel
        funnelSlices[sliceIndex].coordinates[1] = FUNNEL_BOUNDS[1];
        funnelSlices[sliceIndex].coordinates[2] = FUNNEL_BOUNDS[2];
    }
    else
    {

        sliceHeight = GetHeight(sliceIndex);
        // Calculate the other 2 points using the 2 point equation
        // Use Point 0 & 1 of the funnel to calculate point 1 of the slice
        funnelSlices[sliceIndex].coordinates[1].Y = 
          funnelSlices[sliceIndex].coordinates[0].Y + sliceHeight;
        funnelSlices[sliceIndex].coordinates[1].X =
            GetX(
            FUNNEL_BOUNDS[0].X, FUNNEL_BOUNDS[0].Y,
            FUNNEL_BOUNDS[1].X, FUNNEL_BOUNDS[1].Y,
            funnelSlices[sliceIndex].coordinates[1].Y);

        // Use Point 2 & 3 of the funnel to calculate point 2 of the slice
        funnelSlices[sliceIndex].coordinates[2].Y = 
          funnelSlices[sliceIndex].coordinates[0].Y + sliceHeight;
        funnelSlices[sliceIndex].coordinates[2].X =
            GetX(
            FUNNEL_BOUNDS[2].X, FUNNEL_BOUNDS[2].Y,
            FUNNEL_BOUNDS[3].X, FUNNEL_BOUNDS[3].Y,
            funnelSlices[sliceIndex].coordinates[2].Y);

    }
}


/// <summary>
/// This method returns the x coordinate on the line defined by
/// (x1, y1) and (x2, y2) for a given y. 
/// </summary>
private int GetX(int x1, int y1, int x2, int y2, int y)
{
    return (x2 - x1) * (y - y1) / (y2 - y1) + x1;
}


/// <summary>
/// Adds required slice with the name, value, associated revenue and color
/// </summary>
public void AddSlice(string name, int value, double dollars, Color sliceClr)
{
    // Throw exception if it exceeds the max
    // Create a new slice object and set the values
    Slice newSlice = new Slice();
    newSlice.coordinates = new Point[4];
    newSlice.stageName = name;
    newSlice.value = value;
    newSlice.dollars = dollars;
    newSlice.color = sliceClr;

    // Place it in the Slice[] array at appropriate location
    funnelSlices[curSlice++] = newSlice;

    // Update the total value
    totalVal += value;
}
/// <summary>
/// This method adds the gaps between the slices
/// </summary>
public void AddGaps(int i)
{
    funnelSlices[i].coordinates[0].Y = 
      funnelSlices[i].coordinates[0].Y + i * SLICE_GAP;
    funnelSlices[i].coordinates[1].Y = 
      funnelSlices[i].coordinates[1].Y + i * SLICE_GAP;
    funnelSlices[i].coordinates[2].Y = 
      funnelSlices[i].coordinates[2].Y + i * SLICE_GAP;
    funnelSlices[i].coordinates[3].Y = 
      funnelSlices[i].coordinates[3].Y + i * SLICE_GAP;

}


/// <summary>
/// This method plots the graph.
/// To be called after all the values have been initialized
/// </summary>
public void PlotGraph()
{
    int i;
    SizeF strSz;
    string label;

    labelTop = FUNNEL_BOUNDS[0].Y;
    // Throw exception if all slices not initialised
    // Repeat the following steps for each of the slices
    for (i = 0; i < maxSlice; i++)
    {
        // Get the coordinates of the slice
        GetCoordinates(i);
    }

    // Get the height of the font
    int labelHeight = (int)graphicsObj.MeasureString("B",labelFont).Height;
    for (i = 0; i < maxSlice; i++)
    {
        // Add gaps between slices
        AddGaps(i);

        // Calculate label top (and bottom for next loop)
        labelTop = (funnelSlices[i].coordinates[0].Y > labelBottom + 1 ? 
                    funnelSlices[i].coordinates[0].Y : labelBottom + 1);
        labelBottom = labelTop + labelHeight;

        // Plot the graph
        graphicsObj.FillPolygon(new SolidBrush(funnelSlices[i].color), 
                                funnelSlices[i].coordinates);
        
        // Add the stage name label on the left
        strSz = graphicsObj.MeasureString(funnelSlices[i].stageName, labelFont);
        graphicsObj.DrawString(funnelSlices[i].stageName, labelFont, 
                               fontBrush, funnelSlices[i].coordinates[0].X - 
                               strSz.Width, labelTop);
        
        

        // Add the value label on the right
        label = ((funnelSlices[i].dollars)).ToString("C0") + "(" + 
                  funnelSlices[i].value.ToString() + ")";
        graphicsObj.DrawString(label, labelFont, fontBrush, 
                    funnelSlices[i].coordinates[3].X,labelTop);

        SummationValue += float.Parse(funnelSlices[i].dollars.ToString());
        TotalDealsOpps += int.Parse(funnelSlices[i].value.ToString());
        
    }
    label = (SummationValue).ToString("C0") + "(" + 
             TotalDealsOpps.ToString() + ")";



    strSz = graphicsObj.MeasureString(label, labelFont);

    int funnelWidth = (FUNNEL_BOUNDS[3].X - FUNNEL_BOUNDS[0].X);
    int labelX = FUNNEL_BOUNDS[0].X + (int)(funnelWidth / 2 - strSz.Width / 2);
    int labelY = (int)(IMAGE_HEIGHT - strSz.Height );

    
    graphicsObj.DrawString(label, labelFont, fontBrush, labelX, labelY);
    // Saves the created funnel as an image in Response.OutStream 
    Response.ContentType = IMAGE_FORMAT;
    chartBMP.Save(Response.OutputStream, ImageFormat.Jpeg);
}

以上所有代码都应放置在 ASPX 页面的代码隐藏文件中。此页面的页面加载事件将加载要显示的数据。请仔细阅读上面的代码以及附件文件。要在网页上显示漏斗图,可以使用以下代码

<div class="blockBody">
   <table cellpadding="0" cellspacing="0" border="0">
       <tr>
           <td align="center">
               <img src="FunnelChart.aspx" /> 
               <!-- FunnelChart.aspx is the page where the above 
                    code is placed as code behind -->
           </td>
       </tr>
    </table>
</div>

关注点

我研究了许多现有的漏斗图代码,但发现将其编码并在网页上显示更有趣也更容易。当我们的项目上线时,我的客户非常赞赏这项工作。

© . All rights reserved.