/// <summary> /// Draws the X Axis labels, returns the height required to fit all the labels. /// </summary> /// <param name="dc"></param> /// <param name="scaleY"></param> /// <param name="labels"></param> /// <param name="offset"></param> /// <returns></returns> private double DrawXAxisLabels(DrawingContext dc, double scaleX, IEnumerable <GridLabel> labels, double offset) { // A list of areas on the label area on which we've already rendered text. // If we go to render text on a area that's already used, then go to the next // area and move out one width List <List <Range <double> > > usedDrawingAreas = new List <List <Range <double> > >(); usedDrawingAreas.Add(new List <Range <double> >()); List <double> maxHeights = new List <double>(); maxHeights.Add(0); // First of all work out all of the render positions on the y axis List <LabelAndPos> labelAndPos = new List <LabelAndPos>(); foreach (var gridLabel in labels) { double xValue = gridLabel.IsFloating ? (MinPoint.X + MaxPoint.X) * 0.5 : gridLabel.Location; if (!RangeX.Contains(xValue)) { continue; } double xPos = (-xValue + MinPoint.X) * scaleX + this.ActualWidth; int labelIndex = 0; FormattedText formattedText = GetText(gridLabel.Text, gridLabel.Brush); UnrestrictedSize labelArea; if (gridLabel.Orientation == Orientation.Vertical) { labelArea = new UnrestrictedSize(formattedText.Height, formattedText.Width); } else { labelArea = new UnrestrictedSize(formattedText.Width, formattedText.Height); } Point textPoint = new Point(xPos - labelArea.Width * 0.5 - 1, offset); textPoint.X = Math.Min(textPoint.X, this.ActualWidth - Math.Max(0, labelArea.Width * 0.5)); // Uncomment this line to stop any labels going below the bottom chart line //textPoint.X = Math.Max(textPoint.X, 0); Range <double> range = new Range <double>(textPoint.X, textPoint.X + labelArea.Width); bool intersects; do { intersects = false; foreach (var usedRange in usedDrawingAreas[labelIndex]) { if (range.Intersects(usedRange)) { intersects = true; labelIndex++; if (usedDrawingAreas.Count <= labelIndex) { usedDrawingAreas.Add(new List <Range <double> >()); maxHeights.Add(0); } break; } } } while(intersects); usedDrawingAreas[labelIndex].Add(range); maxHeights[labelIndex] = Math.Max(maxHeights[labelIndex], labelArea.Height); labelAndPos.Add(new LabelAndPos(formattedText, textPoint, labelIndex, gridLabel.Orientation)); } List <double> labelOffsets = new List <double>(); labelOffsets.Add(0); double labelOffset = -2; foreach (double height in maxHeights) { labelOffset += 2 + height; labelOffsets.Add(labelOffset); } foreach (var gridLabel in labelAndPos) { FormattedText formattedText = gridLabel.Text; Point textPoint = gridLabel.Location; textPoint.X -= labelOffsets[gridLabel.Layer]; if (gridLabel.Orientation == Orientation.Vertical) { RotateTransform rotateTransform = new RotateTransform(-90); dc.PushTransform(rotateTransform); textPoint = rotateTransform.Inverse.Transform(textPoint); dc.DrawText(formattedText, textPoint); dc.Pop(); } else { dc.DrawText(formattedText, textPoint); } } double totalMaxHeight = -2; foreach (var maxHeight in maxHeights) { totalMaxHeight += maxHeight + 2; } return(totalMaxHeight); }
/// <summary> /// Draws the X Axis labels, returns the height required to fit all the labels. /// </summary> /// <param name="dc"></param> /// <param name="scaleY"></param> /// <param name="labels"></param> /// <param name="offset"></param> /// <returns></returns> private double DrawXAxisLabels(DrawingContext dc, double scaleX, IEnumerable<GridLabel> labels, double offset) { // A list of areas on the label area on which we've already rendered text. // If we go to render text on a area that's already used, then go to the next // area and move out one width List<List<Range<double>>> usedDrawingAreas = new List<List<Range<double>>>(); usedDrawingAreas.Add(new List<Range<double>>()); List<double> maxHeights = new List<double>(); maxHeights.Add(0); // First of all work out all of the render positions on the y axis List<LabelAndPos> labelAndPos = new List<LabelAndPos>(); foreach(var gridLabel in labels) { double xValue = gridLabel.IsFloating ? (MinPoint.X + MaxPoint.X) * 0.5 : gridLabel.Location; if(!RangeX.Contains(xValue)) { continue; } double xPos = (-xValue + MinPoint.X) * scaleX + this.ActualWidth; int labelIndex = 0; FormattedText formattedText = GetText(gridLabel.Text, gridLabel.Brush); UnrestrictedSize labelArea; if(gridLabel.Orientation == Orientation.Vertical) { labelArea = new UnrestrictedSize(formattedText.Height, formattedText.Width); } else { labelArea = new UnrestrictedSize(formattedText.Width, formattedText.Height); } Point textPoint = new Point(xPos - labelArea.Width * 0.5 - 1 , offset); textPoint.X = Math.Min(textPoint.X, this.ActualWidth - Math.Max(0, labelArea.Width * 0.5)); // Uncomment this line to stop any labels going below the bottom chart line //textPoint.X = Math.Max(textPoint.X, 0); Range<double> range = new Range<double>(textPoint.X, textPoint.X + labelArea.Width); bool intersects; do { intersects = false; foreach(var usedRange in usedDrawingAreas[labelIndex]) { if(range.Intersects(usedRange)) { intersects = true; labelIndex++; if(usedDrawingAreas.Count <= labelIndex) { usedDrawingAreas.Add(new List<Range<double>>()); maxHeights.Add(0); } break; } } } while(intersects); usedDrawingAreas[labelIndex].Add(range); maxHeights[labelIndex] = Math.Max(maxHeights[labelIndex], labelArea.Height); labelAndPos.Add(new LabelAndPos(formattedText, textPoint, labelIndex, gridLabel.Orientation)); } List<double> labelOffsets = new List<double>(); labelOffsets.Add(0); double labelOffset = -2; foreach(double height in maxHeights) { labelOffset += 2 + height; labelOffsets.Add(labelOffset); } foreach(var gridLabel in labelAndPos) { FormattedText formattedText = gridLabel.Text; Point textPoint = gridLabel.Location; textPoint.X -= labelOffsets[gridLabel.Layer]; if(gridLabel.Orientation == Orientation.Vertical) { RotateTransform rotateTransform = new RotateTransform(-90); dc.PushTransform(rotateTransform); textPoint = rotateTransform.Inverse.Transform(textPoint); dc.DrawText(formattedText, textPoint); dc.Pop(); } else { dc.DrawText(formattedText, textPoint); } } double totalMaxHeight = -2; foreach(var maxHeight in maxHeights) { totalMaxHeight += maxHeight + 2; } return totalMaxHeight; }