pondělí 3. března 2008

Zedgraph 2

Tento příspěvek je překladem originálního tutoriálu pro zobrazení dynamický dat. Nejedná se o doslovný překlad.

ZedGraphControl může zobrazovat statická nebo dynamická data. Pokud chcete dynamicky zobrazovat data, pokaždé, když chcete přidat grafu nová data, musíte provést následující:

  1. V kolekci GraphPane.CurveList najít křivku (tedy objekt typu CurveItem), do které chcete přidat data.
  2. Přistoupit k PointPairList (nebo jinému objektu, který implementuje rozhraní IPointListEdit) příslůšné křivky a přidat nová data.
  3. Zavolat metodu ZedGraphControl.AxisChange(), aby se přepočítaly rozsahy os.
  4. Zavolat metodu Form.Invalidate() pro update grafu.

Následující příklad obsahuje veškerý kód, kromě kódu vygenerovaného automaticky Visual Studiem. Obsahuje dvě hlavní metody:
  • Form_Load(), která provede inicializaci grafu s jednou křivkou, která zatím neobsahuje žádné body.
  • Timer_Tick(), která obsluhuje událost tiknutí časovače (timer), a přidá nová data

Graf zobrazuje základní sinusovou křivku, na kterou je každých 50 milisekund přidán nový bod. Po spuštění aplikace počkejte 25 vteřin, abyste viděli posunující se dynamická data.
V kódu je použita kolekce RollingPointPairList, která je speciální implementací IPointListEdit rozhraní. Tato kolekce udržuje stále stejný počet bodů tím, že stará data přemazává novými.

Metoda Timer_Tick() nejdříve najde naši křivku. V tomto případě zde je pouze jedna, proto jednoduše vezmeme první křivku s indexem nula (GraphPane.CurveList[0]). Potom vezmeme referenci na CurveItem.Points a přetypujeme na typ IPointListEdit. Pokud je výsledkem přetypování null, víme, že třída s daty neimplementuje rozhraní IPointListEdit, takže ji nemůžeme použít.
Ve chvíli, kdy přidáme nový bod, zařídíme, aby osa X měla vždy rozsah 30 vteřin. Minimum, maximum a velikost kroku nastavujeme ručně, takže se rozsah pohybuje s každým přidaným bodem. Stále voláme metodu AxisChange(), abychom přizpůsobyli osu Y hodnotám (AxisChange() zaručí, že se hodnoty "vlezou" na osu - tedy že budou ve viditelném rozsahu ). Invalidate() voláme, abychom se přesvědčili, že se graf překreslí.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ZedGraph;

namespace DynamicData
{
public partial class Form1 : Form
{
 // počáteční čas v milisekundách
int tickStart = 0;

public Form1()
{
InitializeComponent();
}

 private void Form1_Load( object sender, EventArgs e )
{
GraphPane myPane = zedGraphControl1.GraphPane;
myPane.Title.Text = "Test dynamických dat s komponentou ZedGraph\n" +
"(Graf začne skrolovat po 25 vteřinách)";
myPane.XAxis.Title.Text = "Čas (s)";
myPane.YAxis.Title.Text = "Napětí (V)";

// Uloží 1200 bodů. Každý po 50 ms, což dává jednu minutu.
         // RollingPointPairList je efektivní třída pro ukládání dat grafu,
         // která udržuje sadu rolujících dat, takže není potřeba přesunovat žádné hodnoty
RollingPointPairList list = new RollingPointPairList( 1200 );

  // Při inicializaci je přidána jedna křivka bez žádných dat
         // Barva křivky je modrá a body nemají žádný symbol
LineItem curve = myPane.AddCurve( "Napětí", list, Color.Blue, SymbolType.None );

    // Jeden vzorek po 50 ms
timer1.Interval = 50;
timer1.Enabled = true;
timer1.Start();

  // Ručně nastavíme rozsah osy X, takže může průběžně skrolovat,
  // namísto diskrétních krokových skoků
myPane.XAxis.Scale.Min = 0;
myPane.XAxis.Scale.Max = 30;
myPane.XAxis.Scale.MinorStep = 1;
myPane.XAxis.Scale.MajorStep = 5;

         // Přepočítáme osy
zedGraphControl1.AxisChange();

        // Uložíme si počáteční čas
tickStart = Environment.TickCount;
}

 private void timer1_Tick( object sender, EventArgs e )
{
    // Ujistíme se, že v seznamu křivek máme alespoň jednu
if ( zedGraphControl1.GraphPane.CurveList.Count <= 0 )
return;

     // Vezmeme první křivku v seznamu
LineItem curve = zedGraphControl1.GraphPane.CurveList[0] as LineItem;
if ( curve == null )
return;

     // Vezmeme PointPairList
IPointListEdit list = curve.Points as IPointListEdit;

  // Pokud je list null, znamená to, že reference na curve.Points
  // nepodporuje IPointListEdit, takže jej nebudeme moct modifikovat
if ( list == null )
return;

       // Čas měříme ve vteřinách
double time = (Environment.TickCount - tickStart) / 1000.0;

      // 3 vteřiny na jeden cyklus
list.Add( time, Math.Sin( 2.0 * Math.PI * time / 3.0 ) );

 // Rozsah osy X roluje v intervalu 30 vteřin
  // s jedním hlavním krokem mezi hodnoutou max osy X a koncem osy
Scale xScale = zedGraphControl1.GraphPane.XAxis.Scale;
if ( time > xScale.Max - xScale.MajorStep )
{
xScale.Max = time + xScale.MajorStep;
xScale.Min = xScale.Max - 30.0;
}

 // Zde přepočítáme rozsah osy Y podle zobrazených dat
zedGraphControl1.AxisChange();
    // Žádost o překreslení
zedGraphControl1.Invalidate();
}

 private void Form1_Resize( object sender, EventArgs e )
{
SetSize();
}

 // Nastavíme velikost a umístění ZedGraphControlu
private void SetSize()
{ 
// Control je vždy 10 pixelů od klienteského obdelníku formu
Rectangle formRect = this.ClientRectangle;
formRect.Inflate( -10, -10 );

if ( zedGraphControl1.Size != formRect.Size )
{
zedGraphControl1.Location = formRect.Location;
zedGraphControl1.Size = formRect.Size;
}
}
} 
} 

Žádné komentáře:

Okomentovat