Technology

Uncharted Territory

Anthony Marshall
Anthony Marshall
14 Dec 2010
blog post featured image
<p>A recent ASP MVC 3 project has required us to create some simple charts. As it’s a .NET 4 project we hoped to use the lovely new charting controls provided by Microsoft. You can read all about them in Scott Guthrie’s blog <a href="http://weblogs.asp.net/scottgu/archive/2010/02/07/built-in-charting-controls-vs-2010-and-net-4-series.aspx">here</a> and as you can see they look very pretty and appear simple to implement.</p> <p><a href="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2010/12/nastypie.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="NastyPie" border="0" alt="NastyPie" align="right" src="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2010/12/nastypie-thumb.jpg" width="192" height="176" /></a>That was the theory at least. There is a simple tutorial on how to use the controls in an MVC project <a href="http://dotnetslackers.com/articles/aspnet/Experience-ASP-NET-MVC-3-Beta-New-View-Helpers-Part1.aspx">here</a>. The problem is that the output looks nothing like the charts in Scott Gu’s blog - far from it in fact with no fancy 3d effects and as a bonus nasty jpeg compression artefacts appear. While eliminating the compression artefacts is straightforward, (pass the write method a parameter of “.png”) gaining control of the styling is far more convoluted process.</p> <p>The style of the charts is controlled by the <b>chart.theme</b> parameter, with only four themes available. None of them are terribly exciting and there are no obvious methods for customisation. So far so disappointing. Viewing the class definition in Visual Studio reveals that ChartTheme is a static class with each theme being a constant, declared as a string that appears to be XML mark-up. We wondered if it would be possible to extend this class, adding our own new themes along the way. Incredibly, it’s possible to do exactly that by creating a static partial class that mirrors the original with the exception of the tweaks we want to make to the XML.</p> <p>Vanilla theme from ChartTheme </p> <pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">string</span> Vanilla = @&quot;<span style="color: #8b0000">&lt;Chart Palette=&quot;&quot;SemiTransparent&quot;&quot; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">BorderColor=&quot;&quot;#000&quot;&quot; BorderWidth=&quot;&quot;2&quot;&quot; BorderlineDashStyle=&quot;&quot;Solid&quot;&quot;&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;ChartAreas&gt; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;ChartArea _Template_=&quot;&quot;All&quot;&quot; Name=&quot;&quot;Default&quot;&quot;&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;AxisX&gt; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;MinorGrid Enabled=&quot;&quot;False&quot;&quot; /&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;MajorGrid Enabled=&quot;&quot;False&quot;&quot; /&gt; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/AxisX&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;AxisY&gt; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;MajorGrid Enabled=&quot;&quot;False&quot;&quot; /&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;MinorGrid Enabled=&quot;&quot;False&quot;&quot; /&gt; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/AxisY&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/ChartArea&gt; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;/ChartAreas&gt; </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;/Chart&gt;</span>&quot;;</pre></pre> <div class="csharpcode">Of course making those XML tweaks really isn’t easy – there’s a lot there and a trial and error process is always time consuming. Furthermore, guessing missing parameters hasn’t ever really worked well for me in the past and I don’t anticipate psychic coding to bear fruit in the future either.</div> <p>At this point it seemed sensible to have another look at Scott Gu’s blog. <a href="http://code.msdn.microsoft.com/mschart/Release/ProjectReleases.aspx?ReleaseId=1591">It contains a sample project that demonstrates the features of the ASP.net chart controls</a>. This gives us a way of generating the xml we need to theme our charts. It also has a sort of WYSIWYG editor for each chart so we can style the chart to our taste. The Chart class includes a SaveXml method that predictably saves the chart to an xml file. Inserting a call to this method generates the xml we need for our partial class. </p> <p>Strip out all the data, leaving just the formatting information and there you have it – a chart theme you can reuse throughout your MVC project. Here is the code for a tasteful pie chart…</p> <pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">string</span> JMW3D = @&quot;<span style="color: #8b0000"> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;Chart BackColor=&quot;&quot;WhiteSmoke&quot;&quot; BackGradientStyle=&quot;&quot;TopBottom&quot;&quot;

</pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">BackSecondaryColor=""White"" BorderColor=""26, 59, 105"" </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">BorderWidth=""2""> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Series> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Series ChartArea=""Default"" Font=""Trebuchet MS, 4.25pt, </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">style=Bold"" ChartType=""Pie"" Name=""Default"" </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Legend=""Default"" XValueType=""String"" YValueType=""Double"" </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Color=""220, 65, 140, 240"" BorderColor=""180, 26, 59, 105""
</pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">CustomProperties=""DoughnutRadius=60, PieLabelStyle=Disabled, </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">PieDrawingStyle=Concave""> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </Series> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </Series> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <ChartAreas> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <ChartArea Name=""Default"" BackColor=""Transparent"" </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">BackSecondaryColor=""Transparent"" ShadowColor=""Transparent"" </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">BorderColor=""64, 64, 64, 64"" BorderWidth=""0""> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <AxisY LineColor=""64, 64, 64, 64""> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <MajorGrid LineColor=""64, 64, 64, 64"" /> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <LabelStyle Font=""Trebuchet MS, 8.25pt, style=Bold"" /> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </AxisY> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <AxisX LineColor=""64, 64, 64, 64""> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <MajorGrid LineColor=""64, 64, 64, 64"" /> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <LabelStyle Font=""Trebuchet MS, 8.25pt, style=Bold"" /> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </AxisX> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Area3DStyle Rotation=""0"" /> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </ChartArea> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </ChartAreas> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Legends> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Legend LegendStyle=""Table"" Name=""Default"" </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">IsTextAutoFit=""true"" BackColor=""Transparent"" </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Font=""Trebuchet MS, 8.25pt, style=Bold"" Alignment=""Center"" </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Docking=""Bottom""> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </Legend> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </Legends> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Titles> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <Title Font=""Arial, 10.25pt, style=Bold"" ForeColor=""black"" </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">ShadowOffset=""0"" ShadowColor=""32, 0, 0, 0"" Name=""Title1""> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </Title> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> </Titles> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <BorderSkin SkinStyle=""None"" /> </pre><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></Chart></span>";</pre></pre>

<p><a href="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2010/12/nicepie.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="NicePie" border="0" alt="NicePie" align="right" src="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2010/12/nicepie-thumb.jpg" width="244" height="192" /></a>And it’s results:</p> <p>It’s admittedly one of the most round about methods I have used for doing, well <em>anything.</em><strong> </strong>But it works. Feel free to download a sample project file containing a couple of examples in full.</p> <p><a href="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2010/12/ChartDemo.zip"><img src="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2010/03/butdownloadcode1.gif" /></a></p>
Close chatbot
Open chatbot
Open chatbot