public void SetGlyphDrawer(GlyphDrawer glyphDrawer, double fontSize) { if (this.glyphDrawer == glyphDrawer && this.fontSize == fontSize) { return; } this.glyphDrawer = glyphDrawer; this.fontSize = fontSize; if (timeSpanUnitConfigs == null) { timeSpanUnitConfigs = new TimeSpanUnitConfig[(int)TimeSpanUnitEnum.max + 1]; } maxFollowLabelWidth = double.MinValue; for (TimeSpanUnitEnum timeSpanUnitIndex = TimeSpanUnitEnum.none + 1; timeSpanUnitIndex <= TimeSpanUnitEnum.max; timeSpanUnitIndex++) { TimeSpanUnitMask mask = timeSpanUnitIndex.GetMask(); double firstLabelWidth = glyphDrawer.GetLength(mask.FirstLabelMask !, fontSize); double followLabelWidth = glyphDrawer.GetLength(mask.FollowLabelMask !, fontSize); maxFollowLabelWidth = Math.Max(followLabelWidth, maxFollowLabelWidth); timeSpanUnitConfigs[(int)timeSpanUnitIndex] = new TimeSpanUnitConfig(timeSpanUnitIndex, firstLabelWidth, followLabelWidth); } }
/// <summary> /// Renders the notes to the drawingContext. The notes gets scaled to the available height and width displaying only /// values between minDisplayValueX and maxDisplayValueX, if the x-values are sorted. /// </summary> protected override void OnCreateVisual(DrawingContext drawingContext, double width, double height, DrawingVisual drawingVisual) { if (glyphDrawers == null || fontFamilytracked != chart.FontFamily || fontSizeTracked != chart.FontSize) { fontFamilytracked = chart.FontFamily; fontSizeTracked = chart.FontSize; if (glyphDrawers == null) { glyphDrawers = new GlyphDrawer[fontDefinitions.Length]; } for (int fontDefinitionIndex = 0; fontDefinitionIndex < fontDefinitions.Length; fontDefinitionIndex++) { FontDefinition fontDefinition = fontDefinitions[fontDefinitionIndex]; glyphDrawers[fontDefinitionIndex] = new GlyphDrawer( fontDefinition.FontFamily ?? chart.FontFamily, fontDefinition.FontStyle ?? chart.FontStyle, fontDefinition.FontWeight ?? chart.FontWeight, fontDefinition.FontStretch ?? chart.FontStretch, VisualTreeHelper.GetDpi(drawingVisual).PixelsPerDip); } } double minDisplayValueX = MinDisplayValues[DimensionX]; double maxDisplayValueX = MaxDisplayValues[DimensionX]; double minDisplayValueY = MinDisplayValues[DimensionY]; double maxDisplayValueY = MaxDisplayValues[DimensionY]; int chartNotesLength = chartNotes.Length; for (int chartNotesIndex = 0; chartNotesIndex < chartNotesLength; chartNotesIndex++) { ChartNote chartNote = chartNotes[chartNotesIndex]; double chartNotesX = chartNote.Values[0]; if (chartNotesX < minDisplayValueX) { continue; } double chartNotesY = chartNote.Values[1]; FontDefinition fontDefinition = fontDefinitions[chartNote.FontDefinitionId]; if ((minDisplayValueY <= chartNotesY && chartNotesY <= maxDisplayValueY) || double.IsInfinity(chartNotesY)) { Point chartNotePoint = TranslateValueXYToPoint(chartNotesX, chartNotesY, width, height); if (double.IsPositiveInfinity(chartNotesY)) { //draw at top const double fontOffset = 1.3; //need to move the letters a bit down chartNotePoint.Y = fontOffset * (fontDefinition.FontSize ?? chart.FontSize); } else if (double.IsPositiveInfinity(chartNotesY)) { //draw at bottom chartNotePoint.Y = height; } glyphDrawers[chartNote.FontDefinitionId].Write(drawingContext, chartNotePoint, chartNote.Note, fontDefinition.FontSize ?? chart.FontSize, fontDefinition.FontBrush ?? chart.Foreground); } if (chartNotesX > maxDisplayValueX) { break; } } }
sealed protected override Size MeasureContentOverride(Size availableSize) { if (double.IsNaN(DisplayValue) || double.IsNaN(DisplayValueRange)) { //Replace default data with some data which can be displayed. OnProvideDefaultValues(out var displayValue, out var displayValueRange); DisplayValue = displayValue; DisplayValueRange = displayValueRange; } //ensure that DisplayValue, DisplayValueRange, MinValue and MaxValue all have legal values if (double.IsInfinity(DisplayValue)) { throw new Exception("DisplayValue " + DisplayValue + " cannot be infinite."); } if (double.IsInfinity(DisplayValueRange)) { throw new Exception("DisplayValueRange " + DisplayValueRange + " cannot be infinite."); } if (DisplayValueRange < double.Epsilon * 1e+9) { throw new ApplicationException("DisplayValueRange " + DisplayValueRange + " must be positive."); } if (double.IsNaN(MinValue) != double.IsNaN(MaxValue)) { throw new ApplicationException("MinValue " + MinValue + " and MaxValue " + MaxValue + " must be both NaN or not."); } if (!double.IsNaN(MinValue)) { //min and max values are defined. Ensure that Max>Min and they are bigger or equal DisplayValue and DisplayValueRange if (MaxValue < MinValue) { throw new ApplicationException("MaxValue " + MaxValue + " must be greater than MinValue " + MinValue + " ."); } if (MinValue > DisplayValue) { MinValue = DisplayValue; } if (MaxValue < DisplayValue + DisplayValueRange) { MaxValue = DisplayValue + DisplayValueRange; } } Size requiredSize = availableSize; if (double.IsInfinity(requiredSize.Width)) { //evaluate a minimum value if host gives unlimited space. The size requested as indicated in the return value of //MeasureContentOverride() can be changed in OnLegendMeasurement(() by an inheritor // //Normally, the legend should be in a container telling the legend the available space. If it is unlimited (Scroll Region or host //wants Legend to take all available space), arrange will later provide the space available, even requiredSize was 0. Another //reason for unlimited space is that Grid sometimes makes 2 measurement calls, in which the first one has infinite space to get //the requested size, followed by second measurement call with the available size, after processing the measurement information //from other GridCells if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { //in Visual Studio require some width to display something requiredSize.Width = 200; } else { //normally, the legend should be in a container telling the legend the available width. If it is unlimited (Scroll Container), //arrange will return all width available, even requiredSize.Width is 0. requiredSize.Width = 0; } } //do the same for required Height if (double.IsInfinity(requiredSize.Height)) { requiredSize.Height = System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) ? 200 : 0; } if (double.IsNaN(FontSize)) { throw new Exception("FontSize cannot be NaN."); } if (FontFamily == null) { throw new Exception("FontFamily cannot be null."); } if (fontFamilyTracked != FontFamily || fontSizeTracked != FontSize) { bool hasOnlyFontSizeChanged = fontFamilyTracked == FontFamily && fontSizeTracked != FontSize; fontFamilyTracked = FontFamily; fontSizeTracked = FontSize; if (FontSize < 1 || FontSize > 200) { throw new Exception("FontSize: " + FontSize + " should be between 1 and 200."); } //font might have different dimension than before. Recalculate space needed isNewGlyphDrawer = true; LegendGlyphDrawer = new GlyphDrawer(FontFamily, FontStyle, FontWeight, FontStretch, VisualTreeHelper.GetDpi(this).PixelsPerDip); OnFontChanged(hasOnlyFontSizeChanged); } return(OnLegendMeasurement(requiredSize)); }