先看效果:

可以實現動態縮放比例,隨窗口改變數程,自適應單位,動態調整間隔等功能。

項目文件:

https://pan.baidu.com/s/1dW5udUkwvUATiSYnob1T9A?

pan.baidu.com

界面佈局

<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除整,所以標註間隔之間的小間隔也可以很方便的知道其代表的刻度值。最後算出所有的線位置並繪製刻度及文字。

推薦閱讀:

相關文章