/// <summary> /// Call this method when you turn on LiveScrolling. /// </summary> public void SetCurrentValue(DataValue value) { System.Threading.Interlocked.Exchange<DataValue>(ref currentValue, value); }
private void SmoothScroll(DataValue newValue) { if (this.series == null) { this.series = new DataSeries() { Name = "", Values = new List<DataValue>() }; } // we do not use the data value x coordinates right now because they are timestamp values // and they bunch up and are not smooth...due to random network noise, so until we figure // out something better the graph is smoothing out the x values. double x = 0; if (this.series.Values.Count > 0) { x = this.series.Values[this.series.Values.Count - 1].X + 1; } DataValue copy = new Model.DataValue() { X = x, Y = newValue.Y }; this.series.Values.Add(copy); PathGeometry g = Graph.Data as PathGeometry; if (g == null) { UpdateChart(); return; } PathFigure f = g.Figures[0]; if (ComputeScale() || g.Bounds.Width > 2 * this.ActualWidth) { // can't do incremental, have to reset scaled values. if (this.series != null && this.series.Values.Count > 2 * this.ActualWidth) { // purge history since this is an infinite scrolling stream... this.series.Values.RemoveRange(0, this.series.Values.Count - (int)this.ActualWidth); System.Diagnostics.Debug.WriteLine("Trimming data series {0} back to {1} values", this.series.Name, this.series.Values.Count); } UpdateChart(); } else { AddScaledValues(f, updateIndex, series.Values.Count); Graph.UpdateLayout(); if (g.Bounds.Width >= this.ActualWidth) { Canvas.SetLeft(Graph, Canvas.GetLeft(Graph) - 1); } updateIndex = series.Values.Count; } }
internal DataValue GetDataValue(LogItemSchema schema, Message msg) { // we support 3 levels of nesting, so schema could be the row, the column or an array item. LogItemSchema rowSchema = schema; LogItemSchema columnSchema = schema; LogItemSchema arraySchema = schema; if (rowSchema.Parent != this.schema) { rowSchema = rowSchema.Parent; } if (rowSchema.Parent != this.schema) { columnSchema = rowSchema; rowSchema = rowSchema.Parent; } StringBuilder textBuilder = new StringBuilder(); var row = msg.TypedValue; if (row != null && row.GetType().Name == rowSchema.Type) { // get a time value for this message. FieldInfo fi = row.GetType().GetField(columnSchema.Name, BindingFlags.Public | BindingFlags.Instance); if (fi != null) { object value = fi.GetValue(row); DataValue data = new DataValue() { X = msg.Timestamp.Ticks / 10, UserData = row }; // microseconds (Ticks are in 100 nanoseconds). // byte array is special (we treat this like text). if (value is byte[]) { textBuilder.Length = 0; byte[] text = (byte[])value; bool binary = false; // see if this is binary or text. for (int i = 0, n = text.Length; i < n; i++) { byte b = text[i]; if (b != 0 && b < 0x20 || b > 0x80) { binary = true; } } for (int i = 0, n = text.Length; i < n; i++) { byte b = text[i]; if (b != 0) { if (binary) { textBuilder.Append(b.ToString("x2")); textBuilder.Append(" "); } else { char ch = Convert.ToChar(b); textBuilder.Append(ch); } } } data.Label = textBuilder.ToString(); } else if (value is string) { data.Label = (string)value; } else { if (fi.FieldType.IsArray) { // then we are expecting an array selector as well... Array a = (Array)value; int index = 0; int.TryParse(arraySchema.Name, out index); if (a.Length > index) { value = a.GetValue(index); } } data.Y = ConvertToNumeric(value); data.Label = GetLabel(row, columnSchema.Name); }; return(data); } } return(null); }