TeeChart for NET with MVC

TeeChart’s MVC & ASP.NET Charting options

For MVC, TeeChart for .NET can either render as a static image format such as PNG or JPEG or as a live javascript HTML5 Canvas object. See this page for some examples:
TeeChart MVC examples page. Some of the techniques used by TeeChart’s native ASP.NET Webform chart have been enabled for MVC. For further examples from ASP.NET see the full demo here: http://www.steema.net/TeeChartForNET/index.aspx.

This article concentrates on TeeChart’s implementation for MVC.

TeeChart for MVC

To create/call a Chart, from the view, we place have several options:

Render formats

Chart as an HTML5 canvas

The TeeChart may be rendered as an HTML5 Canvas coded by javascript. Steema provides a public Javascript Library that may be used at render time from NET projects to the webpage. TeeChart for .NET for the web extends capabilities across two possible programming environments, native .NET and Javascript. You can create a managed chart under the Visual Studio framework, within the controller and TeeChart will create the required Javascript to render the Chart (for MVC or ASP.NET) – plus – you can enhance the Javascript chart in virtually any way you desire by using javascript at the view or by generating it in the controller to render at the view. It’s your choice; we hope you like the flexibility it offers.

Chart as a static Image

Charts may be rendered as a static image, typical formats are PNG and JPEG.

Chart as a static Ajax enabled Image

Although this is a mode originally implemented for TeeChart’s Webform (ASP.NET) chart only, some of the techniques used may be extended for use in MVC. MVC can use the tools created for ASP.NET to generate clientside javascript for hotspot maps.

Call formats

Chart as an iframed live Javascript/HTML5 Chart

Example 1.
The first example uses an ActionResult to return a Chart. For these examples we’ve put several Chart routines in a Controller, here called “TeeChartMVCController”

The ActionResult does this:

public ActionResult GetHTML5Chart(int? number)
{
    Steema.TeeChart.TChart wChart3 = new Steema.TeeChart.TChart();
 
    if (number==0) //react to input variables
      wChart3.Series.Add(new Steema.TeeChart.Styles.Pie());
    else
      wChart3.Series.Add(new Steema.TeeChart.Styles.Line());
 
    wChart3.Series[0].FillSampleValues(); //data fill routines
 
//continued...

We create the Chart according to the parameters received; in this case simply to choose between the type of Chart required. This is all native .NET code. You can build the Chart and render it to the page without the need to add any Javascript. The Chart export generates the required Javascript view code and links to TeeChart’s Javascript source. For this example we can and will add some Javascript though, to enhance features of the Chart on the page.

//... continued
 
    //optional - add in some custom javascript
    //setting a clientside visualisation theme
    string[] customCode = new string[] {" chart1.applyTheme(\"minimal\");" };
    wChart3.Export.Image.JScript.CustomCode = customCode;
 
        //setup the Chart export stream
    tempStream2 = new System.IO.MemoryStream(); //create stream for transport
    wChart3.Export.Image.JScript.Width = 800; //size the Chart
    wChart3.Export.Image.JScript.Height = 300;
        //build the Chart
    wChart3.Export.Image.JScript.Save(tempStream2); //write to stream
 
    tempStream2.Position = 0;
    System.IO.StreamReader sr = new System.IO.StreamReader(tempStream2);
 
    return Content(sr.ReadToEnd()); //return the Chart to the caller
}

This results in the following chart, well, nearly; the chart also includes a Tooltip, the description of which is covered in the next section:

Note. Examples on this page have been generated on a non-SSL server and cannot be viewed as frames here under SSL. If you can’t see the charts re-load page for non SSL (to view non-SSL demo charts)

ie. http://www.steema.net/TeeChartMVC/TeeChartMVC/GetHTML5Chart?number=2.

As an iframe this would be called in the following way from the page:
<iframe src=”http://www.steema.net/TeeChartMVC/TeeChartMVC/GetHTML5Chart?number=2″ width=”100%” height=”350″>

Example 2.
The second example shows how view code may be extended to use TeeChart’s Javascript Tools. This example, interpolation, brings together several elements to show how you can use cursor mobility with the chart to feedback information about its contents.

Note. Examples on this page have been generated on a non-SSL server and cannot be viewed as frames here under SSL. If you can’t see the charts re-load page for non SSL (to view non-SSL demo charts)

This is the controller code:

public ActionResult GetInterpolatedChart(int? type)
{

    lock (renderLock)
    {
        Steema.TeeChart.TChart wChart3 = new Steema.TeeChart.TChart();

        // wChart3.Export.Image.JScript.DoFullPage = false;

        List<string> customCode = new List<string>();
        List<string> externalCode = new List<string>();
        List<string> externalHTML = new List<string>();

        string[] externalHTMLS = new string[] {
          "<font face=\"verdana\" size=1><span id=\"xpos\"></span><br/>",
          "<span id=\"yposBar\"></span></font><br>"
        };

        string[] externalCodeS = new string[] {
          " ",
          " var posXLabel, posYLabel;",
          " ",
          " function interpolateLineSeries(s, xval) {",
          "  var yValues=s.data.values;",
          "  var len=yValues.length;",
          "  var xValues=[];",
          "",
          "  if (s.data.x)",
          "    xValues=s.data.x;",
          "  else {",
          "    for (i=0;i<len;i++)",
          "      xValues[i]=i;",
          "  }",
          "",
          "  var index;",
          "  for (index=0;index<len;index++) {",
          "    if (xValues[index]>xval)",
          "      break;",
          "  }",
          "",
          "  if (index<1)",
          "    index=1;",
          "  else",
          "    if (index>=len)",
          "      index=len-1;",
          "",
          "  var dx=xValues[index] - xValues[index-1];",
          "  var dy=yValues[index] - yValues[index-1];",
          "",
          "  if (dx!=0)",
          "    return dy*(xval - xValues[index-1])/dx + yValues[index-1];",
          "  else",
          "    return 0;",
          "}",

        };

        string[] customCodeS = new string[] {
          " ",
          " ",

          "  var ypos=document.getElementById('yposBar'); ",
          "  for (i=0;i<3;i++) {",
          "    if (i>0) {",
          "      var br = document.createElement('br');",
          "      ypos.appendChild(br);",
          "    }",
          "    posYLabel=document.createElement('span');",
          "    posYLabel.id='ypos'+i;",
          "    ypos.appendChild(posYLabel);",
          "  }",

          "  ",
          "//tooltip",
          "tip=new Tee.ToolTip(chart1);",
          "tip.render=\"dom\";",
          "tip.domStyle = \"padding-left:8px; padding-right:8px; padding-top:2px; padding-bottom:4px; margin-left:5px; margin-top:0px; \";",
          "tip.domStyle = tip.domStyle + \"background-color:#FCFCFC; border-radius:4px 4px; color:#FFF; \";",
          "tip.domStyle = tip.domStyle + \"border-style:solid;border-color:#A3A3AF;border-width:1; z-index:1000;\";",
          "chart1.tools.add(tip);",
          "tip.onhide=function() { scaling=0; poindex=-1; }",

          "tip.ongettext=function( tool, text, series, index) { ",
          "  var s = '<font face=\"verdana\" color=\"black\" size=\"1\"><strong>'+ series.title+'</strong></font>';",
          "  s = s + '<br/><font face=\"verdana\" color=\"darkblue\" size=\"1\">Series point: <strong>'+ index.toFixed(0)+'</strong></font>';",
          "  s = s +'<br/><font face=\"verdana\" color=\"red\" size=\"1\">Value: '+series.data.values[index].toFixed(2)+'</font>';  ",
          "   return s;",
          "}",
          "  ",

          "  var t=new Tee.CursorTool(chart1); ",
          "  t.direction='vertical';",
          "  t.format.stroke.size=1;",
          "  t.format.stroke.fill='gray';",
          "  chart1.tools.add(t);",
          "  var xValue;",
          "  ",
          "  posXLabel=document.getElementById('xpos');  ",
          "  t.onchange=function(p) {",
          "    xValue=chart1.axes.bottom.fromPos(p.x);",
          "    posXLabel.textContent='X Value = '+xValue.toFixed(2);",
          "    for (var i=0; i<chart1.series.items.length; i++) {",
          "      posYLabel=document.getElementById('ypos'+i);",
          "      posYLabel.textContent=chart1.series.items[i].title+' Y Value = '+interpolateLineSeries(chart1.series.items[i],xValue).toFixed(2);",
          "    }",
          "",
          "   // changeTheme(chart1, 'minimal');",
          "   chart1.draw();",
          "  };",
          "",

          "chart1.ondraw=function() {",
          "  var xs=this.axes.bottom.calc(xValue);",
          "",
          "  for (var i=0;i<this.series.items.length;i++) {",
          "    var ys=this.axes.left.calc(interpolateLineSeries(this.series.items[i],xValue));",
          "    var f=new Tee.Format(this);",
          "    f.fill=this.series.items[i].format.fill;",
          "    if ((!isNaN(xs)) && (!isNaN(ys)))",
          "      f.ellipse(xs,ys,8,8);",
          "  }",
          "}",
          "  "

          //"chart1.tools.items[0].setRender('layer'); chart1.draw();"

        };
        //********* end client code *********************

        customCode.AddRange(customCodeS);

        customCode.Add(" chart1.applyTheme(\"minimal\");");
        
        Steema.TeeChart.Styles.Line line1 = new Steema.TeeChart.Styles.Line();
        Steema.TeeChart.Styles.Line line2 = new Steema.TeeChart.Styles.Line();
        Steema.TeeChart.Styles.Points p3 = new Steema.TeeChart.Styles.Points();

        p3.Pointer.Gradient.Visible = false;

        line1.Pointer.Visible = true;
        line2.Pointer.Visible = true;

        p3.Pointer.Style = Steema.TeeChart.Styles.PointerStyles.Circle;

        wChart3.Series.Add(line1);
        wChart3.Series.Add(line2);
        wChart3.Series.Add(p3);

        wChart3.Legend.Visible = false;

        for (int i = 0; i < 3; i++)
        {
          wChart3.Series[i].FillSampleValues(50);
        }

        wChart3.Export.Image.JScript.CustomCode = customCode.ToArray();
        wChart3.Export.Image.JScript.ExternalCode = externalCodeS.ToArray();
        wChart3.Export.Image.JScript.BodyHTML = externalHTMLS.ToArray();

        tempStream2 = new System.IO.MemoryStream();
        wChart3.Export.Image.JScript.Width = 950;
        wChart3.Export.Image.JScript.Height = 300;
        wChart3.Export.Image.JScript.Save(tempStream2);

        tempStream2.Position = 0;

        System.IO.StreamReader sr = new System.IO.StreamReader(tempStream2);

        return Content(sr.ReadToEnd());
      }
    }

This is the view code:

<div class="col-md-5">
  <iframe id="fr0" src="/TeeChartMVC/GetInterpolatedChart?number=2" style="border:none; width:970px; height:450px"></iframe>
</div>

This could be converted to an inline call. See the next section for details.

Chart as an inline live Javascript/HTML5 Chart

TeeChart’s Javascript Export class includes a property called DoFullPage. If set to “false” TeeChart hands you control to decide what elements to output to the page. TeeChart will create all of the code lines to generate the Chart but you’ll need to add the Canvas tag and the call to the Chart Draw method. This can of course be automated with your choice of naming convention. We’ve added an example to the TeeChartMVCController.


Note. Examples on this page have been generated on a non-SSL server and cannot be viewed as frames here under SSL. If you can’t see the charts re-load page for non SSL (to view non-SSL demo charts)

public ActionResult CreateInlineChart(int flag, int width, int height)
{
    System.IO.MemoryStream ms = new System.IO.MemoryStream();

    StringBuilder builder = new StringBuilder();

    Steema.TeeChart.TChart wChart3 = new Steema.TeeChart.TChart();
    Steema.TeeChart.Styles.Bubble bubble = new Steema.TeeChart.Styles.Bubble();
    wChart3.Series.Add(bubble);
    wChart3.Legend.Visible = false;
    wChart3.Header.Visible = false;
    bubble.FillSampleValues(50);

    Steema.TeeChart.Export.JavascriptFormat format = (Steema.TeeChart.Export.JavascriptFormat)(wChart3.Export.Image.JScript);

    format.DoFullPage = false; //embedding code without headers

    //name the related page elements
    string ClientID = "w3"; 
    format.CanvasName = ClientID + "img";
    format.ChartName = ClientID + "_chart";

    format.Width = width;
    format.Height = height;

    string[] customCodeS = new string[] {
        "  ",
        " //tooltip",
        " tip=new Tee.ToolTip("+format.ChartName+");",
        " tip.render=\"dom\";",
        " tip.domStyle = \"padding-left:8px; padding-right:8px; padding-top:2px; padding-bottom:4px; margin-left:5px; margin-top:0px; \";",
        " tip.domStyle = tip.domStyle + \"background-color:#FCFCFC; border-radius:4px 4px; color:#FFF; \";",
        " tip.domStyle = tip.domStyle + \"border-style:solid;border-color:#A3A3AF;border-width:1; z-index:1000;\";",
        " "+format.ChartName+".tools.add(tip);",
        " tip.onhide=function() { scaling=0; poindex=-1; }",

        " tip.ongettext=function( tool, text, series, index) { ",
        "   var s = '<font face="verdana" color="black" size="1"><strong>'+ series.title+'</strong></font>';",
        "   s = s + '<br /><font face="verdana" color="darkblue" size="1">Series point: <strong>'+ index.toFixed(0)+'</strong></font>';",
        "   s = s +'<br /><font face="verdana" color="red" size="1">Value: '+series.data.values[index].toFixed(2)+'</font>';  ",
        "   return s;",
        " }",
        "  ",
        " "+format.ChartName+".applyTheme(\"minimal\");",
        "  ",
    };

    format.CustomCode = customCodeS.ToArray();

    System.IO.MemoryStream chartImg = new System.IO.MemoryStream();

    format.Save(chartImg);

    chartImg.Position = 0;
    var sr = new System.IO.StreamReader(chartImg);
    var javaScr = sr.ReadToEnd();

    //add the source paths
    builder.AppendLine("");
    builder.AppendLine("");

    //add our code block and load caller
    builder.AppendLine("");
    builder.AppendLine(" window.onload = function(){ draww3() };");
    builder.AppendLine("var " + format.ChartName + ";\r\nfunction draw" + ClientID.ToString() + "() {\r\n");

    //add-in chart code
    builder.AppendLine(javaScr);

    builder.AppendLine("}\r\n");
    builder.AppendLine("\r\n");

    string styleStr = ""; //optional

    //add the HTML5 canvas
    builder.AppendLine(" 0 ? (styleStr + "\" ") : " style=\"\"") + " width=\"" + format.Width + "\" height=\"" + format.Height + "\">");

    builder.AppendLine("\r\nThis browser does not seem to support HTML5 Canvas.");
    builder.AppendLine("\r\n\r\n");

    return Content(builder.ToString());
}

The above chart generation routine is called from the MVC View in the following way:

@{ Html.RenderAction(“CreateInlineChart”, “TeeChartMVC”, new { flag = 2, width = 970, height = 400 }); }

Chart as an enhanced image

All TeeChart’s Chart types may be rendered as a static image in MVC. Some Ajax ‘enabling’ techniques may be borrowed from tools developed for TeeChart’s ASP.NET (Webform) version chart. In this example we’ll use the hotspot tool to generate a mouseover hint HTML map for the Chart. The technique may extended to offer inline or click-back drill down.

eg.

Note. Examples on this page have been generated on a non-SSL server and cannot be viewed as frames here under SSL. If you can’t see the charts re-load page for non SSL (to view non-SSL demo charts)

<img usemap="#MAPWebChart1" id="Chartimg3" src="/TeeChartMVC/GetStaticBarChart?w=950&h=350&image=true" style="border:none;  width:970px; height:350px">
@{ Html.RenderAction("GetStaticBarChart", "TeeChartMVC", new { w = 950, h = 350, image = false }); }

The RenderAction calls the chart generation function generating the map only.