private void AddTargetLine() { if (DataList.TargetLine.Equals(0)) { return; } else { var TargetLine = new ChartLine() { Name = "XAxis", X1Position = 0, X2Position = LengthForXAxis - 100, Y1Position = 0, //ChartHeight - 150, Y2Position = 0, // ChartHeight - 150, Stroke = Brushes.Black, Thickness = 2, XPosition = 100 }; if (ForceYStartAtZero) { TargetLine.YPosition = (ChartHeight - 150) - DataList.TargetLine * BarHeightModifier - 2; } else { TargetLine.YPosition = (ChartHeight - 150) - (DataList.TargetLine - LowestTickMarkValue) * BarHeightModifier - 2; } ChartNodesCollection.Add(TargetLine); } }
private void AddAxis() { var Xaxis = new ChartLine() { Name = "XAxis", X1Position = 0, X2Position = LengthForXAxis - 100, Y1Position = 0, //ChartHeight - 150, Y2Position = 0, // ChartHeight - 150, Stroke = Brushes.Black, Thickness = 2, XPosition = 100, YPosition = ChartHeight - 150, }; ChartNodesCollection.Add(Xaxis); var YAxis = new ChartLine() { Name = "YAxis", X1Position = 0, X2Position = 0, Y1Position = ChartHeight - 250, Y2Position = 0, Stroke = Brushes.Black, Thickness = 2, XPosition = 100, YPosition = 100, }; ChartNodesCollection.Add(YAxis); }
private void GenerateTickmarks() { ChartHeightDifference = MaxDataValue - MinDataValue; double MostFittingTickMark = ChartHeightDifference / YTickmarkCount; double BestAvailableTickMark = TickMarkIntervals.Where(s => s > MostFittingTickMark).First(); LowestTickMarkValue = Math.Floor(MinDataValue / BestAvailableTickMark) * BestAvailableTickMark - BestAvailableTickMark; if (LowestTickMarkValue < 0) { LowestTickMarkValue = 0; } HigestTickMarkValue = Math.Ceiling(MaxDataValue / BestAvailableTickMark) * BestAvailableTickMark; double TickMarksToGenerate = (HigestTickMarkValue - LowestTickMarkValue) / BestAvailableTickMark; // test if this gives us a good amount of tickmarks or if there are way too many (could occur sometimes!) if (ChartHeightDifference / BestAvailableTickMark > YTickmarkCount * 1.4) { BestAvailableTickMark = TickMarkIntervals.Where(s => s > BestAvailableTickMark).First(); } int TickMarksGenerated = 0; // needed to count them somehow :S for (double TickMarkNumber = LowestTickMarkValue; TickMarkNumber <= HigestTickMarkValue; TickMarkNumber = TickMarkNumber + BestAvailableTickMark) { var TickMarkBox = new ChartText(); TickMarkBox.Name = "YTickmark"; TickMarkBox.Text = string.Format("{0}", TickMarkNumber); TickMarkBox.Width = 95; TickMarkBox.FlowDirection = FlowDirection.RightToLeft; TickMarkBox.XPosition = 0; TickMarkBox.YPosition = ChartHeight - 158 - ((TickMarksGenerated / TickMarksToGenerate) * (ChartHeight - 250)); ChartNodesCollection.Add(TickMarkBox); /* * Canvas.SetLeft(TickMarkBox, 0); //provide enough space on the left size of the axis * TickMarkBox.FlowDirection = FlowDirection.RightToLeft; * Canvas.SetTop(TickMarkBox, ChartHeight - 158 - ((TickMarksGenerated / TickMarksToGenerate) * (ChartHeight-250))); // 158 = 8 so the tickmark is in the middle of what it represents, 150 extra space on the bottom --- 250 is to limit the range used (100 at the top + 150 at the bottom) * ShapeCollection.Add(TickMarkBox); */ TickMarksGenerated++; } }
private void AddAxis() { // need to calculate how "high" the X-axis will be in our chart double YPositionForXaxis; if ((LowestTickMarkValue == 0)) { YPositionForXaxis = ChartHeight - ChartSpaceOffsetBottom; } else { YPositionForXaxis = ChartHeight - ChartSpaceOffsetBottom - (BarHeightModifier * (0 - LowestTickMarkValue)); } var Xaxis = new ChartLine() { Name = "XAxis", X1Position = 0, X2Position = LengthForXAxis - ChartSpaceOffsetLeft, Y1Position = 0, Y2Position = 0, Stroke = Brushes.Black, Thickness = 2, XPosition = ChartSpaceOffsetLeft, YPosition = YPositionForXaxis, //had to calculate this first (bit above :)) }; ChartNodesCollection.Add(Xaxis); var YAxis = new ChartLine() { Name = "YAxis", X1Position = 0, X2Position = 0, Y1Position = ChartAvailableSpaceY, Y2Position = 0, Stroke = Brushes.Black, Thickness = 2, XPosition = ChartSpaceOffsetLeft, YPosition = ChartSpaceOffsetTop, }; ChartNodesCollection.Add(YAxis); }
private void GenerateTickmarks() { ChartHeightDifference = MaxDataValue - MinDataValue; double MostFittingTickMark = ChartHeightDifference / YTickmarkCount; double BestAvailableTickMark = TickMarkIntervals.Where(s => s > MostFittingTickMark).First(); LowestTickMarkValue = Math.Floor(MinDataValue / BestAvailableTickMark) * BestAvailableTickMark - BestAvailableTickMark; //if (LowestTickMarkValue < 0) { LowestTickMarkValue = 0; } HigestTickMarkValue = Math.Ceiling(MaxDataValue / BestAvailableTickMark) * BestAvailableTickMark; double TickMarksToGenerate = (HigestTickMarkValue - LowestTickMarkValue) / BestAvailableTickMark; int TickMarksGenerated = 0; // needed to count them somehow :S for (double TickMarkNumber = LowestTickMarkValue; TickMarkNumber <= HigestTickMarkValue; TickMarkNumber += BestAvailableTickMark) { var TickMarkBox = new ChartText(); TickMarkBox.Name = "YTickmark"; TickMarkBox.Text = string.Format("{0:n0}", TickMarkNumber); TickMarkBox.Width = 95; // should fit enough numbers like this :) TickMarkBox.FlowDirection = FlowDirection.RightToLeft; TickMarkBox.XPosition = ChartSpaceOffsetLeft - 100; // since the textbox itself is 95 long, and we want a bit of space between the Y-axis and the box itself :) TickMarkBox.YPosition = ChartHeight - ChartSpaceOffsetBottom - 8 - ((TickMarksGenerated / TickMarksToGenerate) * (ChartAvailableSpaceY)); //positions the numbers on the y-axis at the appropiate height ChartNodesCollection.Add(TickMarkBox); TickMarksGenerated++; } // set the position of the Yaxis 0-value for use later in the proces //can of course only be set if the 0-value is in range of the chart if (!(HigestTickMarkValue < 0 || LowestTickMarkValue > 0)) { YAxisZeroValueOffset = ChartAvailableSpaceY / (HigestTickMarkValue - LowestTickMarkValue) * (0 - LowestTickMarkValue); } }
/// <summary> /// add the targetline to the graph if it falls within the chartrange, otherwise does nothing /// </summary> private void AddTargetLine() { if (DataList.TargetLine.Equals(0)) { return; } else if (DataList.TargetLine > LowestTickMarkValue && DataList.TargetLine < HigestTickMarkValue) { var TargetLine = new ChartLine() { Name = "TargetLine", X1Position = 0, X2Position = LengthForXAxis - ChartSpaceOffsetLeft, Y1Position = 0, Y2Position = 0, Stroke = Brushes.Black, Thickness = 2, XPosition = ChartSpaceOffsetLeft }; if (ForceYStartAtZero) { TargetLine.YPosition = (ChartHeight - ChartSpaceOffsetBottom) - DataList.TargetLine * BarHeightModifier; } else { TargetLine.YPosition = (ChartHeight - ChartSpaceOffsetBottom) - (DataList.TargetLine - LowestTickMarkValue) * BarHeightModifier; } ChartNodesCollection.Add(TargetLine); } else { return; } }
private void GenerateBarsInChart() { LengthForXAxis = 1; //reset variable to 1 if it is not 1 (which is the standard offset from the Y-Axis to not overlap, if the chart was already calculated before, this will not contain zero so this is necassary) double SpaceAvailablePerBar = ((double)ChartWidth - ChartSpaceOffsetLeft - ChartSpaceOffsetRight) / (double)DataList.DataPoints.Count; // the 2 here should be "assignable" BarHeightModifier = (ChartAvailableSpaceY) / (HigestTickMarkValue - LowestTickMarkValue); // space available per bar gives us the amount of pixels we are allowed to spend, then we add in emtpy spaces with BarGapModifier // if anything other than a number between 0 and 1, don't show any gaps between bars if (AddWhiteSpacePerBar < 0 || AddWhiteSpacePerBar > 1) { AddWhiteSpacePerBar = 0; } double BarWidthWhitespace = SpaceAvailablePerBar * AddWhiteSpacePerBar; //calculate whitespace per bar BarWidth = SpaceAvailablePerBar - BarWidthWhitespace; //leftover amounts go to the bar itself for (int LoopCounter = 0; LoopCounter < DataList.DataPoints.Count; LoopCounter++)//using loopcounter since we need to know on which bar we are for positioning { //from this part its going to be interesting.. we need to accomodate for a waterfall, not individual values... var CurrentBar = new ChartBar(); CurrentBar.Name = "BarInChart"; //Identifier for collection if (!DataList.TargetLine.Equals(null)) { if (DataList.DataPoints[LoopCounter].Value < DataList.TargetLine) { CurrentBar.Fill = DataList.WorseThanTargetColor; } else { CurrentBar.Fill = DataList.BetterThanTargetColor; } } else { CurrentBar.Fill = DataList.Color; } CurrentBar.Width = BarWidth; //set the bar width to represent the data // calculate the 0 y-axis value of the chart in pixels // so now we need to, at least, also have the value where we ended up from the previous bar, otherwise this will not make much sense // Still I want to keep the data input the same, so we need to modify this code "a bit" if (LowestTickMarkValue == 0) // { CurrentBar.Height = BarHeightModifier * DataList.DataPoints[LoopCounter].Value; CurrentBar.YPosition = (ChartHeight - ChartSpaceOffsetBottom) - DataList.DataPoints[LoopCounter].Value * BarHeightModifier; } else if (MinDataValue >= 0) // normal chart starting from above 0 { CurrentBar.Height = BarHeightModifier * (DataList.DataPoints[LoopCounter].Value - LowestTickMarkValue); CurrentBar.YPosition = (ChartHeight - ChartSpaceOffsetBottom) - (DataList.DataPoints[LoopCounter].Value - LowestTickMarkValue) * BarHeightModifier; } else //chart that has y=0 somewhere in the middle { if (DataList.DataPoints[LoopCounter].Value > 0) { CurrentBar.Height = BarHeightModifier * (DataList.DataPoints[LoopCounter].Value); CurrentBar.YPosition = -YAxisZeroValueOffset + (ChartHeight - ChartSpaceOffsetBottom) - (DataList.DataPoints[LoopCounter].Value) * BarHeightModifier; } else { CurrentBar.Height = BarHeightModifier * (-DataList.DataPoints[LoopCounter].Value); CurrentBar.YPosition = -YAxisZeroValueOffset + (ChartHeight - ChartSpaceOffsetBottom); } } //now we need to position the bar correctly on the graph, how many pixels to the right? // 3 is the standard offset to not hit the Y-Axis // BarWidth is the width of the bar itself, barWidthWhitespace is the gaps between the bars // the last bit ensures the first bar also has half a whitespace in front of it // add a bit of whitespace before the first bar, makes it look better in the chart if (LoopCounter == 0) { LengthForXAxis += BarWidthWhitespace / 2 + ChartSpaceOffsetLeft; } CurrentBar.XPosition = LengthForXAxis; //Canvas.SetLeft(CurrentBar, LengthForXAxis); ChartNodesCollection.Add(CurrentBar); //ShapeCollection.Children.Add(CurrentBar); // if the datapoint has a name, it should display below the bar if (!string.IsNullOrWhiteSpace(DataList.DataPoints[LoopCounter].Name)) { var BarName = new ChartText(); BarName.Name = "BarInChartNameBox"; BarName.Text = DataList.DataPoints[LoopCounter].Name; BarName.YPosition = ChartHeight - ChartSpaceOffsetBottom; BarName.XPosition = LengthForXAxis + SpaceAvailablePerBar / 2; BarName.Width = 200; //Canvas.SetTop(BarName, ChartHeight-150); //Canvas.SetLeft(BarName, LengthForXAxis+SpaceAvailablePerBar/2); BarName.RenderTransform = new RotateTransform(30); ChartNodesCollection.Add(BarName); //ShapeCollection.Children.Add(BarName); } LengthForXAxis += (BarWidth) + (BarWidthWhitespace); //prepare for adding the next bar in the chart :) } }
private void GenerateBarsInChart() { LengthForXAxis = 1; //reset variable to zero if it is not 1 (which is the standard offset from the Y-Axis to not overlap) double SpaceAvailablePerBar = ((double)ChartWidth - 200) / (double)DataList.DataPoints.Count; // the 2 here should be "assignable" BarHeightModifier = (ChartHeight - 250) / (HigestTickMarkValue - LowestTickMarkValue); // space available per bar gives us the amount of pixels we are allowed to spend, then we add in emtpy spaces with BarGapModifier // if anything other than a number between 0 and 1, don't show any gaps between bars if (AddWhiteSpacePerBar < 0 || AddWhiteSpacePerBar > 1) { AddWhiteSpacePerBar = 0; } double BarWidthWhitespace = SpaceAvailablePerBar * AddWhiteSpacePerBar; //calculate whitespace per bar BarWidth = SpaceAvailablePerBar - BarWidthWhitespace; //leftover amounts go to the bar itself for (int LoopCounter = 0; LoopCounter < DataList.DataPoints.Count; LoopCounter++)//using loopcounter since we need to know on which bar we are for positioning { var CurrentBar = new ChartBar(); CurrentBar.Name = "BarInChart"; //Identifier for canvas collection if (!DataList.TargetLine.Equals(null)) { if (DataList.DataPoints[LoopCounter].Value < DataList.TargetLine) { CurrentBar.Fill = DataList.WorseThanTargetColor; } else { CurrentBar.Fill = DataList.BetterThanTargetColor; } } else { CurrentBar.Fill = DataList.Color; } CurrentBar.Width = BarWidth; //set the bar width to represent the data if (ForceYStartAtZero) { CurrentBar.Height = BarHeightModifier * DataList.DataPoints[LoopCounter].Value; CurrentBar.YPosition = (ChartHeight - 150) - DataList.DataPoints[LoopCounter].Value * BarHeightModifier - 2; //Canvas.SetTop(CurrentBar, (ChartHeight-150) - DataList.DataPoints[LoopCounter].Value * BarHeightModifier - 2); } else { CurrentBar.Height = BarHeightModifier * (DataList.DataPoints[LoopCounter].Value - LowestTickMarkValue); CurrentBar.YPosition = (ChartHeight - 150) - (DataList.DataPoints[LoopCounter].Value - LowestTickMarkValue) * BarHeightModifier - 2; //Canvas.SetTop(CurrentBar, (ChartHeight-150) - (DataList.DataPoints[LoopCounter].Value - LowestTickMarkValue) * BarHeightModifier - 2); } //now we need to position the bar correctly on the graph, how many pixels to the right? // 3 is the standard offset to not hit the Y-Axis // BarWidth is the width of the bar itself, barWidthWhitespace is the gaps between the bars // the last bit ensures the first bar also has half a whitespace in front of it // add a bit of whitespace before the first bar, makes it look better in the chart if (LoopCounter == 0) { LengthForXAxis += BarWidthWhitespace / 2 + 100; } CurrentBar.XPosition = LengthForXAxis; //Canvas.SetLeft(CurrentBar, LengthForXAxis); ChartNodesCollection.Add(CurrentBar); //ShapeCollection.Children.Add(CurrentBar); // if the datapoint has a name, it should display below the bar if (!string.IsNullOrWhiteSpace(DataList.DataPoints[LoopCounter].Name)) { var BarName = new ChartText(); BarName.Name = "BarInChartNameBox"; BarName.Text = DataList.DataPoints[LoopCounter].Name; BarName.YPosition = ChartHeight - 150; BarName.XPosition = LengthForXAxis + SpaceAvailablePerBar / 2; BarName.Width = 200; //Canvas.SetTop(BarName, ChartHeight-150); //Canvas.SetLeft(BarName, LengthForXAxis+SpaceAvailablePerBar/2); BarName.RenderTransform = new RotateTransform(30); ChartNodesCollection.Add(BarName); //ShapeCollection.Children.Add(BarName); } LengthForXAxis += (BarWidth) + (BarWidthWhitespace); //prepare for adding the next bar in the chart :) } }