MORE INFORMATION
Custom drawing works thru the Office Web Component event model. The event architecture allows the O.W.C. component to respond to events - interactivity. Interactivity is strictly regulated thru the licensing terms and conditions. Licensing is covered in Community Solutions Article - 555075
http://support.microsoft.com/default.aspx?scid=kb;en-us;555075
and Microsoft Knowledge Base Article - 243006
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q243006.
Preparing for events in a windows form
Applications using the O.W.C. thru Visual Studio.NET cannot respond to events by default. The problem lies outside the O.W.C. The current work-around to attach events to the O.W.C. is provided in the following article: 328275 HOW TO: Handle Events for the Office Web Components in Visual Studio .NET http://support.microsoft.com/?id=328275
Assuming you have followed the article and your application is now setup to respond to events correctly, open visual studio to a new windows forms project. Either the OWC10 or OWC11 component may be used. This article will focus on OWC11 which ships with Microsoft Office 2003. The code and explanations do not apply to OWC9. This code will not work in a web-form architecture. The reasons are explained later in this article.
Find and drop the OWC11 chart component onto the designer surface. You may have to add the O.W.C. chart component to the toolbox if it is not already present using the tools menu of Visual Studio.
The following will suffice:
private AxMicrosoft.Office.Interop.OWC.AxChartSpace objChart;
This object declaration will only compile after you have followed the steps outlined above in Preparing for events in a windows form. The code which loads the chart is placed in the applications Form1_load event handler routine. This event fires off when the form loads. In this case, the data to load the chart is contrived, literal data for illustrative purposes. Let's have a look.
Form1's code:
objChart.HasChartSpaceTitle = true;
objChart.ChartSpaceTitle.Caption = "Advanced custom drawing with .Net ";
//Add a chart and a series to the chart
objChart.Charts.Add(0);
objChart.Charts[0].HasLegend = true;
objChart.Charts[0].Type = OWC11.ChartChartTypeEnum.chChartTypePie;
OWC11.ChSeries series = objChart.Charts[0].SeriesCollection.Add(0);
//Set the data for the chart to literal comma-delimited string
series.SetData(OWC11.ChartDimensionsEnum.chDimCategories, (int)OWC11.ChartSpecialDataSourcesEnum.chDataLiteral,
"Week 1,Week 2,Week 3,Week 4,Week 5,Week 6");
series.SetData(OWC11.ChartDimensionsEnum.chDimValues, (int)
OWC11.ChartSpecialDataSourcesEnum.chDataLiteral, "11,25,16,14,8,20");
Without hooking into the event model, the previous code produces a plain chart with six slices and a corresponding legend with entries equal to the number of categories. Notice the use of constants for the SetData method. The use of constants are recommended because constants ensure type safety and reduce invalid input. Now, we customize the chart to respond to events to provide a rich, interactive experience to the user. This will set our application apart from the usual run-of-the-mill charts.
Our first modification is to enhance the chart with an information panel. The code which makes this possible will be placed inside the AfterFinalRender event. This event fires once just before the chart is rendered to the canvas. Typically, you will place code in this routine to tweak the look and feel of the chart just before it is rendered to the drawing surface.
Form1_AfterFinalRender's code
//let's customize the background to show a two color gradient
owc11.ChInterior font = e.drawObject.Interior as owc11.ChInterior;
font.SetSolid((object)"gainsboro");
font.SetPatterned(owc11.ChartPatternTypeEnum.chPattern80Percent,(object)"black","gainsboro");
font.SetTwoColorGradient(owc11.ChartGradientStyleEnum.chGradientDiagonalUp, owc11.ChartGradientVariantEnum.chGradientVariantEdges,(object)"gainsboro",(object)"gray");
//adjust the position so it sits on the bottom right hand corner of the drawing surface
e.drawObject.DrawRectangle(20, 50, 260, 260);
e.drawObject.DrawText("Profit Analysis",25,60);
owc11.ChFont infopane = e.drawObject.Font;
infopane.Color = "green";
infopane.Bold = true;
infopane.Underline = owc11.UnderlineStyleEnum.owcUnderlineStyleDouble;
infopane.Italic = true;
e.drawObject.DrawText("1st Qtr",25,80);
Reviewing the code snippet, a font object is extracted from the intrinsic interior object of the chart component. This font object exposes all the goodies which allow us to customize the text used on the drawing surface. The rectangular information panel is statically placed on the drawing surface for illustrative purposes. In a real world application, you may need to calculate the position at run-time. The PlotArea object represents the canvas on which the chart is being rendered. You can determine the width and height of the PlotArea and adjust your calculations accordingly. Consider:
OWC11.ChPlotArea plotDimension = objChart.Charts[0].PlotArea;
where plotDimension would contain a Left, Right, Top and Bottom property for this purpose. It may also help to know the dimension of the chart area. Recall that the chart area lies inside the plotarea surface.
Finally, we need to customize each slice. The AfterRender event is the appropriate place for our code. This event fires for each slice as it is being rendered. We intend to keep this simple by drawing an ellipse with our company's logo as the background in the center of each slice. The background is limited to gif and jpg types only.
Form1_AfterRender's code:
//use the font object again for customization
owc11.ChInterior font = e.drawObject.Interior as owc11.ChInterior;
if(font == null)
return;
font.SetTextured((object)@"C:\Documents and Settings\User\My Documents\My Pictures\logo.gif",
owc11.ChartTextureFormatEnum.chTile, 1, owc11.ChartTexturePlacementEnum.chFront);
//calculate the center of the current slice
owc11.ChPoint slice = (owc11.ChPoint)e.chartObject;
int x = slice.Left + (slice.Right-slice.Left)/2;
int y = slice.Top +(slice.Bottom - slice.Top)/2;
e.drawObject.DrawEllipse(x-10, y-10, x+10, y+10);
The ChPoint is a structure which encapsulates information about the Chart Object. The ChPoint structure internally represents the co-ordinates of the Chart Object as vector quantities. The O.W.C. makes extensive use of vector quantities because of the need to render in 3 dimensions. Vectors provide for greater freedom and flexibility as well. For instance, you may be able to place your text on the outside edge of the pie chart for each slice as it is being rendered by doing some simple vector arithmetic.
Typically, the chart plots the data labels as a percentage of the slice at the center of each slice. If you intend to custom draw, you should disable the default behavior by turning it off so that the chart remains clean and uncluttered.
Find and remove a line of code similar to the following:
SeriesObject.DataLabelsCollection.Add();
If labels have been added at design time, you may disable them with the following snippet of code:
dl = objChart.Charts[0].SeriesCollection[0].DataLabelsCollection[0];
for(int i=0;i<dl.Count;i++)
dl[i].Visible=false;
One final note on customization. Typically, a chart doesn't display labels on its surface proper since the likelihood of multiple series in one chart is a real possibility, resulting in a cluttered chart. The default is to place the labels in the legend. To change the way the legend displays entries consider:
objChart.SeriesCollection[index].Caption = "hello, world";
If you absolutely must have labels on the chart surface proper, you will have to use custom drawing to write text on the chart surface.
Preparing for events in a web-form
As previously mentioned, the code approach listed above is not expected to work in a web-form environment. The answer lies in the fundamental difference in the web architecture. A chart created in a web-form using the code-behind approach on the server is streamed out to the client as an image file, either a gif or jpg. Other formats are not supported. Once this image is sent to the client, no relationship or connection to the server is maintained. This behavior is imposed by the stateless nature of the web; a client connects to the server, makes a request and disconnects. No state information is preserved.
One approach is to abandon server-side chart generation and load the data into the chart from the client instead. This approach would involve dropping the O.W.C. chart control onto the web-form. You would need to load the data into the chart using client-side script. Then you can use scripting to respond to the various events the chart object exposes using this convention:
Private Sub ChartSpace_AfterRender(ByVal drawObject As ChChartDraw, ByVal chartObject As Object)
Client-side charting automation is very well documented in the help files accompanying the Office Web Components and will not be covered here. For online documentation, visit this link: http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q290/3/48.asp&NoWebContent=1
Be aware though that automating the O.W.C. component constitutes interactivity and, as such, is subject to the terms and conditions of the licensing agreement.
Summary
This article provides a good starting point for customization of the O.W.C. chart. The O.W.C. chart component can plot a large number of different types of charts. Custom drawing allows you to customize each one of these charts. In addition, you can handle multiple events such as mouse down and mouse over events. The windows forms architecture offers a richer event model than the web-forms architecture and is easier to program against. As the web-forms architecture matures, you should expect this gap to shrink.
Credits
This article was prepared with the help of Microsoft Product support.