今回のアプリのダウンロード先
矢印線の描画
直線部分になるPolyLineと矢印になるPolygon、2つを組み合わせて表現
クリックしたところを中継点にする直線の矢印線を描画
線を描画するコン
トロールのPolyLineやLineには線の開始や終了の形の
StrokeStartLineCap、StrokeEndLineCapがあるけど
指定できる形のPenLineCapってのがFlat、Round、Triangle、Squareの4つしかない
しかもFlatとSquareはほとんど一緒なので実質3つ
StrokeStartLineCap="Round"
StrokeEndLineCap="Triangle"
Windows Formのときには矢印(ArrowHead)があった、上の図の水色の矢印がまさにそれで、
WPFにもあるんだろうと思ってたら、ない!
ググったけどわからんので作ることに
目的は矢印に見えればいいんだから単純に線と三角の図形を組み合わせればいいんじゃないかと
矢印の三角部分はPolygonで作って、線はそのままLineとかPolyLineで作って
あとはくっついて見えるようにするんだから、三角の後ろの座標と線の始点や終点の座標を合わせれば
線の傾きに合わせて矢印を回転
これは合っていないけど、だいたいこんな感じで合わせていく
矢印の回転の中心は矢印の先端、横は真ん中、縦は上端にしたいのでRenderTransformOriginは0.5,0
デザイン画面
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace _20180615_直線に矢印2
{
public partial class MainWindow : Window
{
Point OffsetFine矢印先端Point;
double ArrowheadHeight矢印の高さ;
public MainWindow()
{
InitializeComponent();
MyCanvas.MouseMove += MyCanvas_MouseMove;
MyCanvas.MouseLeftButtonDown += MyCanvas_MouseLeftButtonDown;
MyCanvas.MouseRightButtonDown += MyCanvas_MouseRightButtonDown;
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
OffsetFine矢印先端Point = new Point(ArrowHead.ActualWidth / 2, 0);
ArrowheadHeight矢印の高さ = ArrowHead.ActualHeight;
ArrowHead.RenderTransformOrigin = new Point(0.5, 0.0);
}
private void MyCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
MyPolyline.Points.Clear();
}
private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
PointCollection points = MyPolyline.Points;
Point ima = e.GetPosition(MyCanvas);
if (points.Count == 0)
{
points.Add(ima);
}
points[points.Count - 1] = ima;
points.Add(ima);
}
private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
{
PointCollection points = MyPolyline.Points;
Point ima = e.GetPosition(MyCanvas);
if (points.Count != 0)
{
Point pre = points[points.Count - 2];
double angle = Math.Atan2(ima.Y - pre.Y, ima.X - pre.X);
angle = angle / Math.PI * 180;
angle += 90;
ArrowHead.RenderTransform = new RotateTransform(angle);
MyLabel.Content = "Angle = " + angle.ToString();
points[points.Count - 1] = GetContactPoint接点(pre, ima);
}
ima.Offset(-OffsetFine矢印先端Point.X, -OffsetFine矢印先端Point.Y);
Canvas.SetLeft(ArrowHead, ima.X);
Canvas.SetTop(ArrowHead, ima.Y);
}
<summary>
</summary>
<param name="pre"></param>
<param name="ima"></param>
<returns></returns>
private Point GetContactPoint接点(Point pre, Point ima)
{
double lastLineLength = Distance(ima, pre);
double diffLength = lastLineLength - ArrowheadHeight矢印の高さ + 1;
double ratio = diffLength / lastLineLength;
double x = (ima.X - pre.X) * ratio;
double y = (ima.Y - pre.Y) * ratio;
Point nPoint = new Point(pre.X + x, pre.Y + y);
return nPoint;
}
private double Distance(Point p1, Point p2) =>
Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
}
}
矢印の回転
マウスカーソル位置と一個前の中継点の、
yとxそれぞれの差(縦横の長さ)をMath.Atan2に渡すとラジアンが得られて、そこから角度に変換して、74行目で90度足しているのはMath.Atan2の角度0は右向きで、用意した三角は上向きに作ったからその差だと思う、これでちょうどよくなった
矢印と線の接点を求める
長さ調節しないと矢印と重なるので線の終端は青●の位置にするから
矢印の高さを引く感じで青●の座標を計算
この辺はよく解っていないので冗長、三角関数を利用できるのかもしれないけど、線の長さとそれから矢印の高さを引いた長さの比率から計算した
103行目で+1しているのは調整で、しないと
線の長さが足りなくて線と三角形の間に隙間ができてしまう
矢印の形を変えてみる
Polygonの座標を少し変更して長細い三角の矢印
■
こういうのがWindowsFormにはあった
●
これもWindowsFormにはあった
アンカーって名前だったかな
∧
これも高さ自体は40だけど凹んでいるところは20だから
調節したら
これは線が太すぎってことで少し細くして
★
ソワソワする
コード
関連記事
5年後、デザイナー画面でも表示できるようになった
次、2018/06/21は翌日
2018/6/8は12日前