先看效果:
可以實現動態縮放比例,隨窗口改變數程,自適應單位,動態調整間隔等功能。
項目文件:
<Grid> <Slider x:Name="sdScale" ValueChanged="sdScale_ValueChanged" Height="20" Width="400"/> <Border BorderThickness="1" Margin="5" VerticalAlignment="Bottom" Height="37" BorderBrush="DimGray"> <Canvas x:Name="cvRuler" Background="WhiteSmoke"/> </Border> </Grid>
private void DrawRule() {
if (cvRuler.Children != null) { cvRuler.Children.Clear(); }
System.Windows.Shapes.Line _line; TextBlock _textBlock;
const double _minPixel = 30; //長黑標線最小像素間距 string _unit = "mm"; //記錄尺度單位 double _interval; //長黑標線實際距離 double _intervalPixel; //長黑標線實際像素距離 double _scientificF; //用來判斷實際有效數字及尺度 int _scientificE; string[] _strTemp = (_minPixel / sdScale.Value).ToString("E").Split(E); double.TryParse(_strTemp[0], out _scientificF); int.TryParse(_strTemp[1], out _scientificE); if (_scientificE >= 2 || (_scientificE >= 1 && _scientificF >= 5)) { _unit = "m"; _scientificE -= 3; }
//文字「0」 _textBlock = new TextBlock(); _textBlock.Text = _unit; _textBlock.FontSize = 8; _textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; _textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top; _textBlock.Margin = new Thickness(10, 25, 0, 0); cvRuler.Children.Add(_textBlock);
//將間隔標準化 if (_scientificF >= 5) { _interval = 10 * Math.Pow(10, _scientificE); } else if (_scientificF >= 2.5) { _interval = 5 * Math.Pow(10, _scientificE); } else { _interval = 2.5 * Math.Pow(10, _scientificE); }
if (_unit == "mm") { _intervalPixel = _interval * sdScale.Value; } else { _intervalPixel = _interval * 1000 * sdScale.Value; } int _lineIndex = 0; double _width = cvRuler.ActualWidth - 10; double _pixelDistence = _intervalPixel / 5; //單個小間隔像素距離 for (double i = 10; i < _width; i += _pixelDistence) { _line = new System.Windows.Shapes.Line(); if (_lineIndex % 5 == 0) { _line.Stroke = Brushes.Black; _line.StrokeThickness = 1; _line.X1 = i; _line.Y1 = 0; _line.X2 = i; _line.Y2 = 20;
_textBlock = new TextBlock(); _textBlock.Text = (_interval * (_lineIndex / 5)).ToString(); _textBlock.FontSize = 8; _textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; _textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top; _textBlock.Margin = new Thickness(i - 5, 25, 0, 0); cvRuler.Children.Add(_textBlock); } else { _line.Stroke = Brushes.DimGray; _line.StrokeThickness = 1; _line.X1 = i; _line.Y1 = 0; _line.X2 = i; _line.Y2 = 15; } cvRuler.Children.Add(_line);
_lineIndex++; } }
主要思路是,先根據最小要顯示的間隔及縮放因子判斷單位,然後對間隔進行標準化,為了能夠實現比較人性化的間隔標註,取(1,2.5,5)作為標註間隔,由於他們可以被5除整,所以標註間隔之間的小間隔也可以很方便的知道其代表的刻度值。最後算出所有的線位置並繪製刻度及文字。
推薦閱讀: