Interactive 3D bar chart custom control in WPF with rotation, touch-sense display, and databinding support

Create a WPF 3D Bar chart in your .NET application easily. You can create interactive 3D bar charts in seconds using this WPF 3D bar chart custom control. You can even databind your input to see the '3D chart bar change live as you enter your input' effect.

Introduction

Create an interactive 3D 'spin'able (or 'rotate'able) bar chart in seconds using this WPF3DChart custom control. A few lines of XAML or C# (or any .NET compliant language code) is enough to create an interactive, spinnable 3D bar chart. Also, you can use WPF databinding to have the ‘see the 3D chart change live as you input data’ effect.

What do you want to do today?

If you want to see a quick demo, follow the easy instructions in the section ‘To see a Demo’.

If you want to test this WPF3DChart control in a sample project, follow the instructions in the section ‘How to use the code / Steps to use the assembly’.

If you want to learn how to write such a control, start reading from the section ‘Basics of WPF 3D Geometry’.

To see a demo

Step 1: Copy the binary zip file (download using the link at the top of this article) to a separate folder.

Step 2: It is a compressed file. Choose a temporary folder and copy (decompress) all the files into the folder.

Step 3: Run the Test3DChart.exe file.

Step 4: You should see an application as in the image above.

Fun part:

Left click on the chart and hold your left mouse button. Slowly move the mouse. You can see the chart spinning /rotating.

Hover the mouse on the bars. You will see the selected bar enhanced and the X,Y,Z values for that bar.

How to use the code / Steps to use the assembly

The steps below may be followed to write a sample application using this WPF based 3D bar chart control:

Step 1: Create a Windows WPF application using Visual Studio 2008.

Step 2: Add the assembly as a reference to the project.

Step 3: In the Toolbox, right click, then select 'Choose Items'. Choose the WPF tab. Then, click the Browse button to choose the assembly. Click the OK button after selecting the assembly.

Step 4: Now, you will see an entry in the Toolbox with the name 'WPF3DControl'. Drag and drop it to your main window or code in XAML to use the control.

First option: The first and the simplest is to add the X, Y, and Z values in the XAML file in the Design mode as below. You will notice the XValuesInput, YValuesInput, and ZValuesInput (in bold) in the XAML file below:

Second option: Drag and drop this 3D chart control from the toolbox window. Right click to select Properties. Find the properties XValuesInput, YValuesInput, and ZValuesInput in there. Update them to your desired values.

Third option: A third way is to use any .NET compliant language code. Here is a C# sample:

How to databind a textbox (or any other) control to this WPF 3D chart so that the chart gets updated we enter values in the textbox?

Databinding is very simple as all the properties exposed by the 3D bar chart are dependency properties. As in the below sample code, first declare the Binding class object. Then, attach the source. The last step is to bind using the SetBinding method call on the target class. If you are looking for a detailed sample, download the source code of the Test3DChart project.

Basics of WPF 3D Geometry

The WPF geometry co-ordinate system divides the screen as in the figure below:

As in the above picture, the positive X starts from the origin point (0,0,0) to X, and positive Y starts from the point (0,0,0) to Y, and positive Z starts from the point (0,0,0) to Z. The converse is true, where the opposite directions are negative X, negative Y, and negative Z, respectively. This understanding is useful to draw our 3D geometry model at a desired location.

To make learning WPF a little more fun, consider you are directing a film. Imagine what all basic things you will require: camera, lighting, costumes, and actor(s). The same applies here – you will need camera, lights, brushes, and 3D geometry models (i.e., actors). WPF provides you with different types of lights, allows you to choose your camera position (as you are the director!), gives different kinds of brushes, and provides a library to draw 3D geometry.

Understanding how to draw 3D geometry (the actor) is important. The basic model you can draw is a triangle. This is because triangle is the simplest possible plane. To draw a triangle, you need to plot 3 points in the co-ordinate system. These are called triangle positions. Then, you have to add a normal. A normal is a vector perpendicular to the triangle. It is not difficult to calculate the normal given the 3 vertex positions of a triangle. I have provided the method CalculateNormal in this project that will calculate the normal given the 3 vertex points of a triangle. With this information, you can create a WPF MeshGeometry3D object. Then, all you have to do is create the appropriate brush to paint the MeshGeometry3D. You may refer to the DrawRect method source code below to understand drawing a rectangle (combining two triangles).

Next, all you have to do is add a camera and lights to the scene.

After drawing all your geometry, you need to add the geometry (or geometry group) into the ModelVisual3D object. ViewPort3D is the class object that will contain all the drawings. Hence, the ModelVisual3D object needs to be added to the ViewPort3D object. Then, this can be added to a Grid or a Window based on your needs. You may consider looking at the Initialize method source code given below as a sample.

Description of the control code

There are two classes in this solution. They are WPF3DChart and HitDetails.

HitDetails is a small class that has a Dictionary. The Dictionary stores the geometry and (x,y,z) co-ordinates to provide the Hit Text when the user hovers the mouse over the bar.

WPF3DChart is the class that renders the control. I will walk through the important methods in the WPF3DChar class.

Property XValuesInput: This is a WPF Dependency Property that receives the X values of the 3D bar chart. To implement a Dependency Property, the class needs to derive from DependencyObject. Since this is a custom control, this class already does. The property needs to be registered as a Dependency Property as in the first line. We need to define the setters and getters as usual for this property, with one difference. Instead of setting the values to a class private variable, here we need to call the base class methods GetValue/SetValue. That's all. Everything else is taken care of by the framework.

Method DrawRect: As the name suggests, this method draws a rectangle in a 3D space. To draw a rectangle, we need to draw two adjacent triangles. We need to use the MeshGeometry3D class provided by WPF for this purpose. To draw a rectangle, we need to add Positions, TriangleIndices, Normals, and a Brush. Opacity is a parameter whose value can range from 0.0 to 1.0. This opacity parameter determines how transparent your drawing will be. Once we add all of the above to a GeometryModel3D, we are ready with a drawing. You may wonder why we need four triangles instead of two to draw a rectangle. WPF needs you to specify both the sides of the rectangle. Otherwise, the other side will not be visible while rotating/spinning the drawing.

Method Draw3DBar: This is the method that draws the bars. This method uses a DrawRect to accomplish this. This method calculates the 3D bar co-ordinates. Then, it calls DrawRect to draw its drawings. One more important thing this method does is it populates the Dictionary with the bar geometry and the (x,y,z) values. I will explain its usage in the OnRightMouseClick event handler.

Method DrawXYZWithMarkings: This method draws the X plane, Y plane, and the Z plane. This method calculates the length and width planes. It draws the X, Y, and Z planes based on these calculations. The three for loops are used to draw the markings on the planes. These markings are used to specify values in the X, Y, and Z planes.

Method Draw3DChart: This method is the main method called by Initialize. This method gets input the X, Y, and Z values. Then, this method draws the bars calling the Draw3DBar method. Finally, this method calls DrawXYZWithMarkings to draw the X, Y, and Z planes.

Mouse move and left button down handlers: This is an important handler that is responsible for the rotation of the 3D geometry. This method calculates the move, i.e., how far the mouse moved with respect to the Y or X axis, while pressing the left button. Then, it calls ComputeCameraPosition to calculate the position in the Sphere. Well, to explain in a little detail: initially, our work is to just draw the geometry, light up the scene, and then place the camera. These three basic steps are required by WPF to show us a 3D picture on the screen. After doing this, if we want to spin/rotate the geometry, all we have to do is move the camera. Imagine placing all these geometry on a dining table in your home. Then, imagine viewing it in a camcorder display moving on a spherical plane.

I simply used the standard 8th grade math geometry formula ‘Any point on sphere’ to calculate the camera position:

19 Sep. 2008 -- Modified all the properties in the custom control to be WPF Dependency Properties. Also updated the test app to bind to the Dependency Properties. Now, as the user enters values, the chart changes dynamically.

21 Sep. 2008 -- Modified the 3D bar interactivity based on the mouse move, bar resized to fit the screen, fixed a few bugs, and added source code comments.

About the Author

Comments and Discussions

I think you are referencing the old dll in your project. Clean up your drive to remove all the dlls. Then build your new assembly with the modified title. Make sure you reference the new assembly that you built

Excellent work!!!
but this issues here:The Yaxis value didn't match the 3Dbar.
for example,the input value of Y is 8,the chart's 3D bar which should catch 8 level of Y axis didn't catch that place,a little lower,not 8,looks like 7.X
how can I fix it in the source code?
3Q!!!