Home > Silverlight > LineChart with Markers

LineChart with Markers

February 25, 2009 Leave a comment Go to comments

I came across a forum post  in silverlight forums looking for a way to get markers in a linechart. I wanted to try it myself.

This is the end result. As the points are random, you might have to hit refresh, in case you dont see the lines.

charting

 

I changed the template to include a canvas

 <ControlTemplate TargetType=”charting:Chart”>
                        <Border Background=”{TemplateBinding Background}”
                                BorderBrush=”{TemplateBinding BorderBrush}”
                                BorderThickness=”{TemplateBinding BorderThickness}”
                                Padding=”10″>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height=”Auto” />
                                    <RowDefinition Height=”*” />
                                </Grid.RowDefinitions>

                                <datavis:Title Content=”{TemplateBinding Title}”
                                               Style=”{TemplateBinding TitleStyle}” />

                                <!– Use a nested Grid to avoid possible clipping behavior resulting from ColumnSpan+Width=Auto –>
                                <Grid Grid.Row=”1″
                                      Margin=”0,15,0,15″>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width=”*” />
                                        <ColumnDefinition Width=”Auto” />
                                    </Grid.ColumnDefinitions>

                                    <datavis:Legend x:Name=”Legend”
                                                    Title=”{TemplateBinding LegendTitle}”
                                                    Style=”{TemplateBinding LegendStyle}”
                                                    Grid.Column=”1″ />

                                    <Grid x:Name=”ChartArea”
                                          Style=”{TemplateBinding ChartAreaStyle}”>
                                        <Grid x:Name=”PlotArea”
                                              Style=”{TemplateBinding PlotAreaStyle}”>
                                            <Grid x:Name=”GridLinesContainer” />
                                            <Grid x:Name=”SeriesContainer”>
                                              
                                            </Grid>
                                                <Border BorderBrush=”#FF919191″
                                                    BorderThickness=”1″ />
                                             <Canvas  Background=”Transparent”                                                      
                                                         x:Name=”c1″></Canvas>
                                        </Grid>
                                      
                                    </Grid>
                                   
                                </Grid>
                            </Grid>
                        </Border>
                    </ControlTemplate>

and in the code behind once we have the chart rendered . In the Layout updated method of the chart. I call the following function. which adds the markers

  void Highlight(List<Order> orderList)
        {
             LineSeries ls = this.chart1.Series[0] as LineSeries;
             Grid plotArea = chart1.GetChildrenByType<Grid>().Where(g => g.Name == “PlotArea”).SingleOrDefault<Grid>();
             Canvas c1 = chart1.GetChildrenByType<Canvas>().Where(c => c.Name == “c1″).SingleOrDefault<Canvas>();
            foreach (Order o in orderList)
            {
                Point p = ls.Points[orders.IndexOf(o)];
                Line ln = new Line();
                ln.Stroke = new SolidColorBrush(Colors.Black);
                ln.StrokeThickness = 1.0;
                DoubleCollection dashCollection = new DoubleCollection();
                dashCollection.Add(2);
                dashCollection.Add(4);
                ln.StrokeDashArray = dashCollection;
                ln.X1 = p.X;
                ln.X2 = p.X;
                ln.Y1 = -10.0;
                ln.Y2 = plotArea.ActualHeight;
                TextBlock txt = new TextBlock();
                txt.Text = o.OrderDate.ToShortDateString();
                txt.Foreground = new SolidColorBrush(Colors.Blue);
                Grid chartArea = plotArea.Parent as Grid;
                txt.SetValue(Canvas.LeftProperty, ln.X1 + 5.0);
                txt.SetValue(Canvas.TopProperty, ln.Y1 – 10);               
                c1.Children.Add(txt);
                c1.Children.Add(ln);
            }
        }

you can download the sample here

About these ads
Categories: Silverlight Tags: ,
  1. Faisal Ali
    October 1, 2009 at 8:35 pm

    Lee,

    This is absolutely great work. Well Done! I am new to WPF and I require a chart control with markers; however, the markers should be moveable by the user so that s/he can place them anywhere on the line chart and just read off the x, y values. A single marker would do it; however, it will be a plus to have 2 such markers which user can place/fix at any chosen point(s) on the curve. Would you please give me some ideas as how to go about extending your line charts to include moveable markers/cursors instead of static/random markers?

    Thanks,
    Faisal

    • lee
      October 1, 2009 at 8:59 pm

      Hi,
      one idea, might be to create event handlers for the line and respond to those events to move the line, or you could place a thumb and change the template so that it looks like a line or something and handle DragDelta or DragCompleted events

  2. Faisal
    October 2, 2009 at 2:46 pm

    Thanks Lee. It is a good idea. I will try it out. It will be a good WPF learning exercise for me :).
    Thanks again,
    Faisal

  3. Lina
    January 13, 2010 at 3:40 am

    Hi Lee, great work. Thanks a lot for this blog.
    I am trying to do the same but with Column Series. But when I come to this line: Point p = ls.Points[orders.IndexOf(o)]; I get an error message, saying I am trying to convert data of different type.
    Can you help me with it?

    Thanks a lot!!

    • lee
      January 13, 2010 at 9:49 am

      Lina,
      if you can send a quick sample, I can take a look

  4. Lina
    January 13, 2010 at 3:37 pm

    Thanks Lee for your time and knowledge.
    This is my Code:

    __________________________________________________________________

    __________________________________________________________________

    bool add = true;
    void Highlight(List orderList)
    {
    LineSeries ls = this.lsChart.Series[0] as LineSeries;
    Grid plotArea = lsChart.GetChildrenByType().Where(g => g.Name == “PlotArea”).SingleOrDefault();
    Canvas c1 = lsChart.GetChildrenByType().Where(c => c.Name == “c1″).SingleOrDefault();
    foreach (Order o in orderList)
    {
    Point p = ls.Points[orders.IndexOf(o)];
    Line ln = new Line();
    ln.Stroke = new SolidColorBrush(Colors.Black);
    ln.StrokeThickness = 1.0;
    DoubleCollection dashCollection = new DoubleCollection();
    dashCollection.Add(2);
    dashCollection.Add(4);
    ln.StrokeDashArray = dashCollection;
    ln.X1 = o.VALOR; //p.X;
    ln.X2 = o.VALOR; //p.X;
    ln.Y1 =10.0;
    ln.Y2 = plotArea.ActualHeight;
    TextBlock txt = new TextBlock();
    txt.Text = o.VALOR.ToString();
    txt.Foreground = new SolidColorBrush(Colors.Blue);
    Grid chartArea = plotArea.Parent as Grid;
    txt.SetValue(Canvas.LeftProperty, ln.X1);
    txt.SetValue(Canvas.TopProperty, ln.Y1);
    c1.Children.Add(txt);
    c1.Children.Add(ln);
    }
    }

    private void lsChart_LayoutUpdated(object sender, EventArgs e)
    {
    if (this.add)
    {
    Highlight(orders.Where(o => o.VALOR >= Convert.ToDouble(txtMaximo.Text)).ToList());
    Highlight(orders.Where(o => o.VALOR <= Convert.ToDouble(txtMinimo.Text)).ToList());
    this.add = false;
    }
    }

  5. lee
    January 13, 2010 at 3:44 pm

    if you are using ColumnSeries, then
    LineSeries ls = this.lsChart.Series[0] as LineSeries;
    is not right, you have to cast it to ColumnSeries

  6. Lina
    January 13, 2010 at 3:49 pm

    If I do so, then how should I managed this one: Point p = ls.Points[orders.IndexOf(o)];
    Now I can’t use Points…

  7. lee
    January 13, 2010 at 3:54 pm

    What I was doing is to get the location(x,y) of the particular point. looks like ColumnSeries doesn’t expose the location of the column(atleast in the version of toolkit used in the sample. may be there is another way to get the location when it is columnseries, have to investigate

    • Lina
      January 13, 2010 at 6:04 pm

      Hi Lee,
      What I did, was a chart with ColumnSeries and LineSeries.
      The LineSeries is hidden.
      So I can use its data, but the user only sees the ColumnSeries.
      Thanks a lot for your help.
      If you happend to know something easier, please let me know.

  8. Lina
    January 13, 2010 at 3:56 pm

    ok, thanks a lot!!

  9. lee
    January 13, 2010 at 6:25 pm

    Lina,
    That is a nice workaround

  10. Lina
    January 23, 2010 at 9:22 pm

    Hi Lee,
    I have another question that you may know.
    How can I clear values from the point chart and from the c1 canvas?
    Thanks a lot for your help!!

    • lee
      January 23, 2010 at 10:26 pm

      you should be able to clear the chidren, by setting itemsource to null and from canvas using Children.clear

  11. January 23, 2010 at 11:35 pm

    Thanks a lot, It works!!

  12. frank
    June 23, 2010 at 8:42 am

    Hi Lee,

    Thanks for your article. I use it in a WPF environment and have some approvements.

    1. Add a size changed event.
    void mcChart_SizeChanged(object sender, SizeChangedEventArgs e)
    {
    if (!add)
    {
    Highlight(orders);
    }
    }
    And make sure to add to following command before the foreach in Highlight:
    c1.Children.Clear();

    2. To get the X coordinate, you use Point p = ls.Points[orders.IndexOf(o)];
    Why don’t you do something like:
    DateTimeAxis xaxis = mcChart.Axes[0] as DateTimeAxis;
    System.Windows.Controls.DataVisualization.UnitValue value = xaxis.GetPlotAreaCoordinate(o.Date);

    ln.X1 = value.Value;
    In that case you can have an indepent list of markers

    Anyway thanks for putting me in the Canvas-direction.

  13. July 19, 2012 at 2:49 pm

    I’ll right away snatch your rss as I can’t in finding your email subscription hyperlink or e-newsletter service. Do you have any? Kindly let me understand in order that I could subscribe. Thanks.

  14. sea
    January 4, 2013 at 9:28 am

    anyone got it works on visual studio 2010 with WPF Framework .Net 4.0? Mine doesn’t work i think due WPF version i believe. Kindly help.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: