JavaScript appears to be disabled. We recommend you enable JavaScript while visiting this site.

(All original content on this site is licensed under the Creative Commons License Attribution-Noncommercial-No Derivative Works 3.0.)

ASP.NET charts example: Odin Sphere: Part 3 - Creating the chart

In part one of this series we covered what we'd be doing, and what data model we'd be using.

In part two of this series we used LINQ to XML to query the XML file with the data we want to display.

This time we'll be doing the heavy lifting of actually creating the chart and displaying it to the user. For ease, I'll be implementing very basic caching.

Preliminary requirement

Before you can use the charting functionality you need to have a reference to System.Web.DataVisualization. We can then use this in our handler as below.

using System.Web.UI.DataVisualization.Charting;

Next we can do the heavy lifting of creating the basics of the chart:

// Create a new chart, and set the basic properties of it.
Chart hpChart = new Chart();
hpChart.Width = 800;
hpChart.Height = 500;
hpChart.Titles.Add("Odin Sphere HP leveling");
hpChart.Palette = ChartColorPalette.Bright;
hpChart.Legends.Add("Main");
hpChart.Legends[0].LegendStyle = LegendStyle.Row;
hpChart.Legends[0].Docking = Docking.Bottom;
// Create a new area for the main chart to display within.
ChartArea mainArea = new ChartArea("Main chart");
// Set the properties for the x-axis.
mainArea.AxisX.Name = "Level";
mainArea.AxisX.Title = "Level";
mainArea.AxisX.MajorGrid.LineColor = System.Drawing.Color.DimGray;
mainArea.AxisX.MinorGrid.Enabled = true;
mainArea.AxisX.MinorGrid.LineColor = System.Drawing.Color.LightGray;
// Set the properties for the y-axis.
mainArea.AxisY.Name = "Hit points";
mainArea.AxisY.Title = "Hit points";
mainArea.AxisY.MajorGrid.LineColor = System.Drawing.Color.DimGray;
mainArea.AxisY.MinorGrid.Enabled = true;
mainArea.AxisY.MinorGrid.LineColor = System.Drawing.Color.LightGray;
mainArea.AxisY.MinorGrid.Interval = 50;
hpChart.ChartAreas.Add(mainArea);

With our chart created we can now add our data.

foreach (Character character in characterData) {
	// Add a new series of points for each character.
	Series characterSeries = new Series();
	characterSeries.Name = character.Name;
	characterSeries.ChartType = SeriesChartType.Line;
	foreach (HpLevel characterLevel in character.HpLevels) {
		// Add a point for each level recorded.
		characterSeries.Points.AddXY(characterLevel.Level, characterLevel.HitPoints);
	}
	hpChart.Series.Add(characterSeries);
}

Since we want to cache the chart, we'll add an informational message.

// Add a new informational title.
Title cacheTitle = new Title("Cached " + DateTime.Now.ToString() + " and based on http://jamesrskemp.com/files/OdinSphere.xml");
cacheTitle.Docking = Docking.Bottom;
hpChart.Titles.Add(cacheTitle);

Next we'll set the rendering type of the chart and add it to the cache.

hpChart.RenderType = RenderType.BinaryStreaming;
// Cache our object for an amount of time
HttpRuntime.Cache.Add("OdinSphereChart", hpChart, null, DateTime.Now.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Low, null);

Everything above, as well as the XDocument load from part two, can be wrapped by a check for whether the chart is in the cache.

// Determine whether the chart is already cached.
if (HttpRuntime.Cache["OdinSphereChart"] == null) {
//...
}

And then we can finally output the chart to the user.

// Output the cached chart to the browser.
using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) {
	((Chart)HttpRuntime.Cache["OdinSphereChart"]).SaveImage(stream);
	context.Response.ContentType = "image/png";
	context.Response.BinaryWrite(stream.GetBuffer());
}

Final code

At the end of our exercise, our handler (OdinSphere.ashx) looks something like the following:

<%@ WebHandler Language="C#" Class="OdinSphere" %>

using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Web.UI.DataVisualization.Charting;

public class OdinSphere : IHttpHandler {

	/// <summary>
	/// One of the five playable characters in Odin Sphere, for the Playstation 2.
	/// </summary>
	public class Character {
		/// <summary>
		/// Name of the character.
		/// </summary>
		public String Name { get; set; }
		/// <summary>
		/// List of hit point leveling information.
		/// </summary>
		public List<HpLevel> HpLevels { get; set; }
	}

	/// <summary>
	/// Hit point information at a particular level.
	/// </summary>
	public class HpLevel {
		/// <summary>
		/// Level of the character.
		/// </summary>
		public int Level { get; set; }
		/// <summary>
		/// Hit points at a level, for a character.
		/// </summary>
		public int HitPoints { get; set; }
	}

	public void ProcessRequest(HttpContext context) {
		// Determine whether the chart is already cached.
		if (HttpRuntime.Cache["OdinSphereChart"] == null) {
			// Grab the current data.
			XDocument dataFile = XDocument.Load("http://jamesrskemp.com/files/OdinSphere.xml");
			IEnumerable<Character> characterData = from characters in dataFile.Descendants("Character")
												   select new Character {
													   Name = characters.Attribute("name").Value,
													   HpLevels = (from levels in characters.Element("HP").Element("Levels").Descendants("Level")
																   select new HpLevel {
																	   Level = int.Parse(levels.Attribute("id").Value),
																	   HitPoints = int.Parse(levels.Attribute("hitPoints").Value)
																   }
													   ).ToList()
												   };

			// Create a new chart, and set the basic properties of it.
			Chart hpChart = new Chart();
			hpChart.Width = 800;
			hpChart.Height = 500;
			hpChart.Titles.Add("Odin Sphere HP leveling");
			hpChart.Palette = ChartColorPalette.Bright;
			hpChart.Legends.Add("Main");
			hpChart.Legends[0].LegendStyle = LegendStyle.Row;
			hpChart.Legends[0].Docking = Docking.Bottom;
			// Create a new area for the main chart to display within.
			ChartArea mainArea = new ChartArea("Main chart");
			// Set the properties for the x-axis.
			mainArea.AxisX.Name = "Level";
			mainArea.AxisX.Title = "Level";
			mainArea.AxisX.MajorGrid.LineColor = System.Drawing.Color.DimGray;
			mainArea.AxisX.MinorGrid.Enabled = true;
			mainArea.AxisX.MinorGrid.LineColor = System.Drawing.Color.LightGray;
			// Set the properties for the y-axis.
			mainArea.AxisY.Name = "Hit points";
			mainArea.AxisY.Title = "Hit points";
			mainArea.AxisY.MajorGrid.LineColor = System.Drawing.Color.DimGray;
			mainArea.AxisY.MinorGrid.Enabled = true;
			mainArea.AxisY.MinorGrid.LineColor = System.Drawing.Color.LightGray;
			mainArea.AxisY.MinorGrid.Interval = 50;
			hpChart.ChartAreas.Add(mainArea);

			foreach (Character character in characterData) {
				// Add a new series of points for each character.
				Series characterSeries = new Series();
				characterSeries.Name = character.Name;
				characterSeries.ChartType = SeriesChartType.Line;
				foreach (HpLevel characterLevel in character.HpLevels) {
					// Add a point for each level recorded.
					characterSeries.Points.AddXY(characterLevel.Level, characterLevel.HitPoints);
				}
				hpChart.Series.Add(characterSeries);
			}

			// Add a new informational title.
			Title cacheTitle = new Title("Cached " + DateTime.Now.ToString() + " and based on http://jamesrskemp.com/files/OdinSphere.xml");
			cacheTitle.Docking = Docking.Bottom;
			hpChart.Titles.Add(cacheTitle);
			
			hpChart.RenderType = RenderType.BinaryStreaming;
			// Cache our object for an amount of time
			HttpRuntime.Cache.Add("OdinSphereChart", hpChart, null, DateTime.Now.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Low, null);
		}

		// Output the cached chart to the browser.
		using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) {
			((Chart)HttpRuntime.Cache["OdinSphereChart"]).SaveImage(stream);
			context.Response.ContentType = "image/png";
			context.Response.BinaryWrite(stream.GetBuffer());
		}
	}
 
    public bool IsReusable {
        get {
            return false;
        }
    }
}

You can see this in action online.

Tags: , , ,

Categories: tutorials/guides

(All original content on this site is licensed under the Creative Commons License Attribution-Noncommercial-No Derivative Works 3.0.)

ASP.NET charts example: Odin Sphere: Part 2 - Parsing the XML

In part one of this series we covered what we'd be doing, and what model we'd be using for the data.

This time we'll parse the XML file that contains the data we need, and populate the objects.

Loading the XML file

The XML file we'll be loading is located at http://jamesrskemp.com/files/OdinSphere.xml, and to keep it simple, we'll load it in assuming we're on a different server/domain.

First we'll need to add the following so we can make use of XDocument.

using System.Xml.Linq;

Next we'll update ProcessRequest by loading the XML file.

XDocument dataFile = XDocument.Load("http://jamesrskemp.com/files/OdinSphere.xml");

And then we'll parse it out into our custom objects.

IEnumerable<Character> characterData = from characters in dataFile.Descendants("Character")
	select new Character {
		Name = characters.Attribute("name").Value,
		HpLevels = (from levels in characters.Element("HP").Element("Levels").Descendants("Level")
			select new HpLevel {
				Level = int.Parse(levels.Attribute("id").Value),
				HitPoints = int.Parse(levels.Attribute("hitPoints").Value)
			}
		).ToList()
	};

With that done, we can now verify the data by displaying some very basic information on the page.

		context.Response.ContentType = "text/plain";
		foreach (Character character in characterData) {
			context.Response.Write(character.Name + Environment.NewLine);
			context.Response.Write("Maximum HP level = " + character.HpLevels.Last().Level.ToString() + Environment.NewLine + Environment.NewLine);

		}

With that aspect verified, we can create and output our graphs, which we'll cover in part three.

Tags: , , ,

Categories: tutorials/guides

(All original content on this site is licensed under the Creative Commons License Attribution-Noncommercial-No Derivative Works 3.0.)

ASP.NET charts example: Odin Sphere: Part 1 - Introduction and model

For a while now I've been meaning to work with ASP.NET 4's built-in charting functionality. While I was going to use it alongside my gas tracking, I think I'm instead going to use my Odin Sphere leveling guide, so I don't have to create an XSLT for the output.

In this part of the series I'll outline the data model I'll be using, and preliminary setups.

Method

So that this can easily be deployed anywhere, I'm going to opt not to use the control itself, but rather programmatically create the charts/graphs. I'll be creating a generic handler (.ashx) to handle the output.

I'll be using LINQ to XML to query the XML file that stores the content and may implement some level of caching at some point.

My environment is Visual Studio 2010 and .NET Framework 4. The controls are available for 3.5 and 2008, however, and 2010 Express should also suffice.

Data model

For this chart I'd like to chart each character's HP progression as they level, with each character displaying on the same graph.

This then gives us a List of Character, with each Character having a Name and a List of HpLevel, with HpLevel containing a Level and a HP total.

In our new Generic Handler (OdinSphere.ashx) we'll add the following within the existing public class:

	/// <summary>
	/// One of the five playable characters in Odin Sphere, for the Playstation 2.
	/// </summary>
	public class Character {
		/// <summary>
		/// Name of the character.
		/// </summary>
		public String Name { get; set; }
		/// <summary>
		/// List of hit point leveling information.
		/// </summary>
		public List<HpLevel> HpLevels { get; set; }
	}

	/// <summary>
	/// Hit point information at a particular level.
	/// </summary>
	public class HpLevel {
		/// <summary>
		/// Level of the character.
		/// </summary>
		public int Level { get; set; }
		/// <summary>
		/// Hit points at a level, for a character.
		/// </summary>
		public int HitPoints { get; set; }
	}

These also require the following:

using System.Collections.Generic;
using System.Linq;

At this point we've got our objects defined and set, so we can grab the data from the XML file and create our necessary objects ... which is exactly what we'll do in the second part of this series.

Tags: , , ,

Categories: tutorials/guides

Month List