зеркало из https://github.com/stride3d/GraphX.git
+ Added vertex control labels with following functionality:
+ 2 available positioning modes: by sides or by coordinates + Always attached to vertex and moves with it + Same template logic as in EdgeLabelControl + Added key modifiers to vertex event args + Fixed ViewFinder not deriving ZoomControl background + Implemented some properties as dependencies + Reworked EdgeLabelControl inner logic. Should now be more flexible and performance efficient.
This commit is contained in:
Родитель
8a9f321e15
Коммит
f3966d8042
|
@ -1,6 +1,14 @@
|
|||
RELEASE 2.0.2
|
||||
+ Added vertex control labels with following functionality:
|
||||
+ 2 available positioning modes: by sides or by coordinates
|
||||
+ Always attached to vertex and moves with it
|
||||
+ Same template logic as in EdgeLabelControl
|
||||
+ Added key modifiers to vertex event args
|
||||
+ Fixed labels rendering for parallel edges. Now they are displayed separately for each edge.
|
||||
+ Fixed async calculations being broken due to LogicCore property became dependency
|
||||
+ Fixed ViewFinder not deriving ZoomControl background
|
||||
+ Implemented some properties as dependencies
|
||||
+ Reworked EdgeLabelControl inner logic. Should now be more flexible and performance efficient.
|
||||
+ Some code refactoring. Minor performance improvements.
|
||||
|
||||
RELEASE 2.0.1
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Windows;
|
||||
using GraphX.GraphSharp.Algorithms.EdgeRouting;
|
||||
using GraphX.GraphSharp.Algorithms.Layout.Simple.FDP;
|
||||
using GraphX.GraphSharp.Algorithms.OverlapRemoval;
|
||||
using GraphX.Logic;
|
||||
using GraphX.GraphSharp.Algorithms.Layout.Simple.Tree;
|
||||
using GraphX.GraphSharp.Algorithms.Layout;
|
||||
|
@ -28,52 +29,44 @@ namespace ShowcaseExample
|
|||
tst_Area.SetVerticesDrag(true, true);
|
||||
}
|
||||
|
||||
private GraphExample GenerateTestGraph()
|
||||
{
|
||||
var graph = new GraphExample();
|
||||
var v1 = new DataVertex() { Text = "Test1", ID = 1 };
|
||||
graph.AddVertex(v1);
|
||||
var v2 = new DataVertex() { Text = "Test2", ID = 2 };
|
||||
graph.AddVertex(v2);
|
||||
var v3 = new DataVertex() { Text = "Test3", ID = 3 };
|
||||
graph.AddVertex(v3);
|
||||
var v4 = new DataVertex() { Text = "Test4", ID = 4 };
|
||||
graph.AddVertex(v4);
|
||||
|
||||
graph.AddEdge(new DataEdge(v1, v2, 100));
|
||||
graph.AddEdge(new DataEdge(v2, v3, 100));
|
||||
graph.AddEdge(new DataEdge(v2, v4, 100));
|
||||
return graph;
|
||||
|
||||
}
|
||||
|
||||
void tst_but_gen_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var _graph = new GraphExample();
|
||||
var v1 = new DataVertex() { Text = "Test1", ID = 1 };
|
||||
_graph.AddVertex(v1);
|
||||
var v2 = new DataVertex() { Text = "Test2", ID = 2 };
|
||||
_graph.AddVertex(v2);
|
||||
var v3 = new DataVertex() { Text = "Test3", ID = 3 };
|
||||
_graph.AddVertex(v3);
|
||||
var v4 = new DataVertex() { Text = "Test4", ID = 4 };
|
||||
_graph.AddVertex(v4);
|
||||
|
||||
_graph.AddEdge(new DataEdge(v1, v2, 1) { ID = 1000 });
|
||||
_graph.AddEdge(new DataEdge(v1, v2, 1) { ID = 1 });
|
||||
|
||||
|
||||
_graph.AddEdge(new DataEdge(v1, v4, 1) { ID = 1000 });
|
||||
_graph.AddEdge(new DataEdge(v1, v4, 1) { ID = 1 });
|
||||
_graph.AddEdge(new DataEdge(v1, v4, 1) { ID = 2 });
|
||||
_graph.AddEdge(new DataEdge(v2, v4, 1) { ID = 1001 });
|
||||
_graph.AddEdge(new DataEdge(v3, v4, 1) { ID = 1002 });
|
||||
_graph.AddEdge(new DataEdge(v3, v4, 1) { ID = 1003 });
|
||||
_graph.AddEdge(new DataEdge(v4, v3, 1) { ID = 1004 });
|
||||
_graph.AddEdge(new DataEdge(v4, v3, 1) { ID = 1005 });
|
||||
_graph.AddEdge(new DataEdge(v4, v3, 1) { ID = 1006 });
|
||||
|
||||
tst_Area.ShowAllEdgesArrows(true);
|
||||
|
||||
var ergTreeLayoutParameters = new KKLayoutParameters { };
|
||||
|
||||
var logic = new LogicCoreExample();
|
||||
TSTLC = logic;
|
||||
logic.Graph = _graph;
|
||||
logic.EnableParallelEdges = true;
|
||||
|
||||
var graph = GenerateTestGraph();
|
||||
var logic = new LogicCoreExample {Graph = graph};
|
||||
logic.EnableParallelEdges = false;
|
||||
logic.ParallelEdgeDistance = 15;
|
||||
|
||||
logic.DefaultLayoutAlgorithm = LayoutAlgorithmTypeEnum.KK;
|
||||
logic.DefaultLayoutAlgorithmParams = ergTreeLayoutParameters;
|
||||
tst_Area.ShowAllEdgesArrows(false);
|
||||
|
||||
var layParams = new LinLogLayoutParameters { IterationCount = 100 };
|
||||
logic.DefaultLayoutAlgorithm = LayoutAlgorithmTypeEnum.LinLog;
|
||||
logic.DefaultLayoutAlgorithmParams = layParams;
|
||||
var overlapParams = new OverlapRemovalParameters { HorizontalGap = 100, VerticalGap = 100 };
|
||||
logic.DefaultOverlapRemovalAlgorithm = OverlapRemovalAlgorithmTypeEnum.FSA;
|
||||
logic.DefaultOverlapRemovalAlgorithmParams = logic.AlgorithmFactory.CreateOverlapRemovalParameters(OverlapRemovalAlgorithmTypeEnum.FSA);
|
||||
logic.DefaultOverlapRemovalAlgorithmParams = overlapParams;
|
||||
IExternalEdgeRouting<DataVertex, DataEdge> erParams = null;
|
||||
//logic.ExternalEdgeRoutingAlgorithm =
|
||||
|
||||
((GraphX.GraphSharp.Algorithms.OverlapRemoval.OverlapRemovalParameters)logic.DefaultOverlapRemovalAlgorithmParams).HorizontalGap = 140;
|
||||
((GraphX.GraphSharp.Algorithms.OverlapRemoval.OverlapRemovalParameters)logic.DefaultOverlapRemovalAlgorithmParams).VerticalGap = 140;
|
||||
tst_Area.GenerateGraph(_graph, true);
|
||||
tst_Area.GenerateGraph(graph, true);
|
||||
//tst_Area.VertexList[v1].Visibility = System.Windows.Visibility.Collapsed;
|
||||
//tst_Area.VertexList[v2].Visibility = System.Windows.Visibility.Collapsed;
|
||||
//tst_Area.VertexList[v3].Visibility = System.Windows.Visibility.Collapsed;
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace ShowcaseExample.Models
|
||||
|
|
Двоичные данные
GraphX v2.v11.suo
Двоичные данные
GraphX v2.v11.suo
Двоичный файл не отображается.
|
@ -1,8 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace GraphX
|
||||
{
|
||||
|
@ -13,42 +10,72 @@ namespace GraphX
|
|||
private const int BOT = 4; /* двоичное 0100 */
|
||||
private const int TOP = 8; /* двоичное 1000 */
|
||||
|
||||
const double D30_DEGREES_IN_RADIANS = Math.PI / 6.0;
|
||||
|
||||
public static double Tangent30Degrees { get; private set; }
|
||||
|
||||
static MathHelper()
|
||||
{
|
||||
Double d30DegreesInRadians = Math.PI / 6.0;
|
||||
Tangent30Degrees = Math.Tan(d30DegreesInRadians);
|
||||
Tangent30Degrees = Math.Tan(D30_DEGREES_IN_RADIANS);
|
||||
}
|
||||
|
||||
public static double GetAngleBetweenPoints(Point point1, Point point2)
|
||||
{
|
||||
return Math.Atan2(point1.Y - point2.Y, point2.X - point1.X);
|
||||
}
|
||||
|
||||
public static double GetDistanceBetweenPoints(Point point1, Point point2)
|
||||
{
|
||||
return Math.Sqrt(Math.Pow(point2.X - point1.X, 2) + Math.Pow(point2.Y - point1.Y, 2));
|
||||
}
|
||||
|
||||
|
||||
public static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
|
||||
{
|
||||
var angleInRadians = angleInDegrees * (Math.PI / 180);
|
||||
var cosTheta = Math.Cos(angleInRadians);
|
||||
var sinTheta = Math.Sin(angleInRadians);
|
||||
return new Point
|
||||
{
|
||||
X =
|
||||
(int)
|
||||
(cosTheta * (pointToRotate.X - centerPoint.X) -
|
||||
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
|
||||
Y =
|
||||
(int)
|
||||
(sinTheta * (pointToRotate.X - centerPoint.X) +
|
||||
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsIntersected(Rect r, Point a, Point b)
|
||||
{
|
||||
sides code;
|
||||
Point c; /* одна из точек */
|
||||
Point start = new Point(a.X, a.Y);
|
||||
// var start = new Point(a.X, a.Y);
|
||||
/* код конечных точек отрезка */
|
||||
sides code_a = GetIntersectionData(r, a);
|
||||
sides code_b = GetIntersectionData(r, b);
|
||||
var codeA = GetIntersectionData(r, a);
|
||||
var codeB = GetIntersectionData(r, b);
|
||||
|
||||
if (code_a.IsInside() && code_b.IsInside())
|
||||
if (codeA.IsInside() && codeB.IsInside())
|
||||
return true;
|
||||
|
||||
/* пока одна из точек отрезка вне прямоугольника */
|
||||
while (!code_a.IsInside() || !code_b.IsInside())
|
||||
while (!codeA.IsInside() || !codeB.IsInside())
|
||||
{
|
||||
/* если обе точки с одной стороны прямоугольника, то отрезок не пересекает прямоугольник */
|
||||
if (code_a.SameSide(code_b))
|
||||
if (codeA.SameSide(codeB))
|
||||
return false;
|
||||
|
||||
/* выбираем точку c с ненулевым кодом */
|
||||
if (!code_a.IsInside())
|
||||
sides code;
|
||||
Point c; /* одна из точек */
|
||||
if (!codeA.IsInside())
|
||||
{
|
||||
code = code_a;
|
||||
code = codeA;
|
||||
c = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
code = code_b;
|
||||
code = codeB;
|
||||
c = b;
|
||||
}
|
||||
|
||||
|
@ -77,15 +104,15 @@ namespace GraphX
|
|||
}
|
||||
|
||||
/* обновляем код */
|
||||
if (code == code_a)
|
||||
if (code == codeA)
|
||||
{
|
||||
a = c;
|
||||
code_a = GetIntersectionData(r, a);
|
||||
codeA = GetIntersectionData(r, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = c;
|
||||
code_b = GetIntersectionData(r, b);
|
||||
codeB = GetIntersectionData(r, b);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -95,10 +122,10 @@ namespace GraphX
|
|||
{
|
||||
sides code;
|
||||
Point c; /* одна из точек */
|
||||
Point start = new Point(a.X, a.Y);
|
||||
var start = new Point(a.X, a.Y);
|
||||
/* код конечных точек отрезка */
|
||||
sides code_a = GetIntersectionData(r, a);
|
||||
sides code_b = GetIntersectionData(r, b);
|
||||
var code_a = GetIntersectionData(r, a);
|
||||
var code_b = GetIntersectionData(r, b);
|
||||
|
||||
/* пока одна из точек отрезка вне прямоугольника */
|
||||
while (!code_a.IsInside() || !code_b.IsInside())
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace GraphX
|
|||
bool EnableParallelEdges { get; set; }
|
||||
int ParallelEdgeDistance { get; set; }
|
||||
bool IsEdgeRoutingEnabled { get; }
|
||||
|
||||
bool EnableEdgeLabelsOverlapRemoval { get; set; }
|
||||
|
||||
void CreateNewAlgorithmFactory();
|
||||
void CreateNewAlgorithmStorage(IExternalLayout<TVertex> layout, IExternalOverlapRemoval<TVertex> or, IExternalEdgeRouting<TVertex, TEdge> er);
|
||||
|
@ -40,5 +40,7 @@ namespace GraphX
|
|||
IExternalLayout<TVertex> GenerateLayoutAlgorithm(Dictionary<TVertex, Size> vertexSizes);
|
||||
IExternalOverlapRemoval<TVertex> GenerateOverlapRemovalAlgorithm(Dictionary<TVertex, Rect> rectangles = null);
|
||||
IExternalEdgeRouting<TVertex, TEdge> GenerateEdgeRoutingAlgorithm(Size DesiredSize);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,5 +24,6 @@ namespace GraphX
|
|||
IOverlapRemovalParameters CreateOverlapRemovalParameters(OverlapRemovalAlgorithmTypeEnum algorithmType);
|
||||
IExternalEdgeRouting<TVertex, TEdge> CreateEdgeRoutingAlgorithm(EdgeRoutingAlgorithmTypeEnum newAlgorithmType, Rect graphArea, TGraph Graph, IDictionary<TVertex, Point> Positions, IDictionary<TVertex, Rect> Rectangles, IEdgeRoutingParameters parameters = null);
|
||||
IEdgeRoutingParameters CreateEdgeRoutingParameters(EdgeRoutingAlgorithmTypeEnum algorithmType);
|
||||
IOverlapRemovalAlgorithm<T> CreateFSAA<T>(IDictionary<T, Rect> rectangles, float horgap, float vertGap) where T : class;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace GraphX
|
|||
ec.StrokeDashArray = null;
|
||||
break;
|
||||
}
|
||||
ec.UpdateEdge();
|
||||
ec.UpdateEdge(false);
|
||||
}
|
||||
|
||||
private DoubleCollection StrokeDashArray { get; set; }
|
||||
|
@ -115,6 +115,12 @@ namespace GraphX
|
|||
/// </summary>
|
||||
public bool CanBeParallel { get { return _canbeparallel; } set { _canbeparallel = value; } }
|
||||
|
||||
private bool _updateLabelPosition;
|
||||
/// <summary>
|
||||
/// Gets or sets if label position should be updated on edge update
|
||||
/// </summary>
|
||||
public bool UpdateLabelPosition { get { return _updateLabelPosition; } set { _updateLabelPosition = true; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this edge is self looped (have same Source and Target)
|
||||
/// </summary>
|
||||
|
@ -126,14 +132,26 @@ namespace GraphX
|
|||
/// <summary>
|
||||
/// Show arrows on the edge ends. Default value is true.
|
||||
/// </summary>
|
||||
public bool ShowArrows { get { return _showarrows; } set { _showarrows = value; UpdateEdge(); } }
|
||||
public bool ShowArrows { get { return _showarrows; } set { _showarrows = value; UpdateEdge(false); } }
|
||||
private bool _showarrows;
|
||||
|
||||
|
||||
public static readonly DependencyProperty ShowLabelProperty = DependencyProperty.Register("ShowLabel",
|
||||
typeof(bool),
|
||||
typeof(EdgeControl),
|
||||
new UIPropertyMetadata(showlabel_changed));
|
||||
|
||||
private static void showlabel_changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ec = (d as EdgeControl);
|
||||
if(ec == null) return;
|
||||
|
||||
ec.UpdateEdge(false);
|
||||
}
|
||||
/// <summary>
|
||||
/// Show edge label.Default value is False.
|
||||
/// </summary>
|
||||
public bool ShowLabel { get { return _showlabel; } set { _showlabel = value; UpdateEdge(); } }
|
||||
private bool _showlabel;
|
||||
public bool ShowLabel { get { return (bool)GetValue(ShowLabelProperty); } set { SetValue(ShowLabelProperty, value); } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if lables should be aligned to edges and be displayed under the same angle
|
||||
|
@ -250,6 +268,7 @@ namespace GraphX
|
|||
Edge = edge; DataContext = edge;
|
||||
ShowArrows = showArrows;
|
||||
ShowLabel = showLabels;
|
||||
_updateLabelPosition = true;
|
||||
|
||||
EventOptions = new EdgeEventOptions(this);
|
||||
foreach (var item in Enum.GetValues(typeof(EventType)).Cast<EventType>())
|
||||
|
@ -480,11 +499,11 @@ namespace GraphX
|
|||
|
||||
#region public PrepareEdgePath()
|
||||
|
||||
internal void UpdateEdge()
|
||||
internal void UpdateEdge(bool updateLabel = true)
|
||||
{
|
||||
if (Visibility == Visibility.Visible && _linePathObject != null)
|
||||
{
|
||||
PrepareEdgePath(true);
|
||||
PrepareEdgePath(true, null, updateLabel);
|
||||
_linePathObject.Data = _linegeometry;
|
||||
_linePathObject.StrokeDashArray = StrokeDashArray;
|
||||
|
||||
|
@ -522,7 +541,7 @@ namespace GraphX
|
|||
/// </summary>
|
||||
/// <param name="useCurrentCoords">Use current vertices coordinates or final coorfinates (for.ex if move animation is active final coords will be its destination)</param>
|
||||
/// <param name="externalRoutingPoints">Provided custom routing points will be used instead of stored ones.</param>
|
||||
public void PrepareEdgePath(bool useCurrentCoords = false, Point[] externalRoutingPoints = null)
|
||||
public void PrepareEdgePath(bool useCurrentCoords = false, Point[] externalRoutingPoints = null, bool updateLabel = true)
|
||||
{
|
||||
//do not calculate invisible edges
|
||||
if (Visibility != Visibility.Visible || Source == null || Target == null || ManualDrawing) return;
|
||||
|
@ -661,7 +680,9 @@ namespace GraphX
|
|||
}
|
||||
GeometryHelper.TryFreeze(_linegeometry);
|
||||
GeometryHelper.TryFreeze(_arrowgeometry);
|
||||
|
||||
|
||||
if (ShowLabel && _edgeLabelControl != null && _updateLabelPosition && updateLabel )
|
||||
_edgeLabelControl.UpdatePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -675,5 +696,26 @@ namespace GraphX
|
|||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
public Rect GetLabelSize()
|
||||
{
|
||||
return _edgeLabelControl.LastKnownRectSize;
|
||||
}
|
||||
|
||||
public void SetCustomLabelSize(Rect rect)
|
||||
{
|
||||
_edgeLabelControl.LastKnownRectSize = rect;
|
||||
_edgeLabelControl.Arrange(rect);
|
||||
}
|
||||
|
||||
internal void UpdateLabelLayout()
|
||||
{
|
||||
_edgeLabelControl.Visibility = Visibility.Visible;
|
||||
if (_edgeLabelControl.LastKnownRectSize == Rect.Empty || double.IsNaN(_edgeLabelControl.Width))
|
||||
{
|
||||
_edgeLabelControl.UpdateLayout();
|
||||
_edgeLabelControl.UpdatePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
@ -30,11 +32,26 @@ namespace GraphX
|
|||
|
||||
public EdgeLabelControl()
|
||||
{
|
||||
if (DesignerProperties.GetIsInDesignMode(this)) return;
|
||||
|
||||
LayoutUpdated += EdgeLabelControl_LayoutUpdated;
|
||||
HorizontalAlignment = HorizontalAlignment.Left;
|
||||
VerticalAlignment = VerticalAlignment.Top;
|
||||
}
|
||||
|
||||
void EdgeLabelControl_LayoutUpdated(object sender, EventArgs e)
|
||||
{
|
||||
//TODO optimize parent call by calling it once from constructor
|
||||
var edgeControl = GetEdgeControl(VisualParent);
|
||||
if(edgeControl == null || !edgeControl.ShowLabel) return;
|
||||
if (LastKnownRectSize == Rect.Empty || double.IsNaN(LastKnownRectSize.Width) || LastKnownRectSize.Width == 0)
|
||||
{
|
||||
UpdateLayout();
|
||||
UpdatePosition();
|
||||
}
|
||||
else Arrange(LastKnownRectSize);
|
||||
}
|
||||
|
||||
private static EdgeControl GetEdgeControl(DependencyObject parent)
|
||||
{
|
||||
while (parent != null)
|
||||
|
@ -46,24 +63,17 @@ namespace GraphX
|
|||
return null;
|
||||
}
|
||||
|
||||
private static double GetAngleBetweenPoints(Point point1, Point point2)
|
||||
{
|
||||
return Math.Atan2(point1.Y - point2.Y, point2.X - point1.X);
|
||||
}
|
||||
|
||||
private static double GetDistanceBetweenPoints(Point point1, Point point2)
|
||||
{
|
||||
return Math.Sqrt(Math.Pow(point2.X - point1.X, 2) + Math.Pow(point2.Y - point1.Y, 2));
|
||||
}
|
||||
|
||||
private static double GetLabelDistance(double edgeLength)
|
||||
{
|
||||
return edgeLength / 2; // set the label halfway the length of the edge
|
||||
}
|
||||
|
||||
private void EdgeLabelControl_LayoutUpdated(object sender, EventArgs e)
|
||||
internal void UpdatePosition()
|
||||
{
|
||||
|
||||
if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) return;
|
||||
|
||||
// if (!IsLoaded)
|
||||
// return;
|
||||
var edgeControl = GetEdgeControl(VisualParent);
|
||||
|
@ -91,25 +101,27 @@ namespace GraphX
|
|||
var routingInfo = edgeControl.Edge as IRoutingInfo;
|
||||
if (routingInfo != null)
|
||||
{
|
||||
var routePoints = routingInfo.RoutingPoints;
|
||||
var routePoints = routingInfo.RoutingPoints == null ? null : routingInfo.RoutingPoints.ToArray();
|
||||
|
||||
if (routePoints == null)
|
||||
{
|
||||
// the edge is a single segment (p1,p2)
|
||||
edgeLength = GetLabelDistance(GetDistanceBetweenPoints(p1, p2));
|
||||
edgeLength = GetLabelDistance(MathHelper.GetDistanceBetweenPoints(p1, p2));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// the edge has one or more segments
|
||||
// compute the total length of all the segments
|
||||
edgeLength = 0;
|
||||
var rplen = routePoints.Length;
|
||||
for (var i = 0; i <= rplen; ++i)
|
||||
if (i == 0)
|
||||
edgeLength += GetDistanceBetweenPoints(p1, routePoints[0]);
|
||||
edgeLength += MathHelper.GetDistanceBetweenPoints(p1, routePoints[0]);
|
||||
else if (i == rplen)
|
||||
edgeLength += GetDistanceBetweenPoints(routePoints[rplen - 1], p2);
|
||||
edgeLength += MathHelper.GetDistanceBetweenPoints(routePoints[rplen - 1], p2);
|
||||
else
|
||||
edgeLength += GetDistanceBetweenPoints(routePoints[i - 1], routePoints[i]);
|
||||
edgeLength += MathHelper.GetDistanceBetweenPoints(routePoints[i - 1], routePoints[i]);
|
||||
// find the line segment where the half distance is located
|
||||
edgeLength = GetLabelDistance(edgeLength);
|
||||
var newp1 = p1;
|
||||
|
@ -118,11 +130,11 @@ namespace GraphX
|
|||
{
|
||||
double lengthOfSegment;
|
||||
if (i == 0)
|
||||
lengthOfSegment = GetDistanceBetweenPoints(newp1 = p1, newp2 = routePoints[0]);
|
||||
lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = p1, newp2 = routePoints[0]);
|
||||
else if (i == rplen)
|
||||
lengthOfSegment = GetDistanceBetweenPoints(newp1 = routePoints[rplen - 1], newp2 = p2);
|
||||
lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = routePoints[rplen - 1], newp2 = p2);
|
||||
else
|
||||
lengthOfSegment = GetDistanceBetweenPoints(newp1 = routePoints[i - 1], newp2 = routePoints[i]);
|
||||
lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = routePoints[i - 1], newp2 = routePoints[i]);
|
||||
if (lengthOfSegment >= edgeLength)
|
||||
break;
|
||||
edgeLength -= lengthOfSegment;
|
||||
|
@ -139,43 +151,29 @@ namespace GraphX
|
|||
|
||||
// move it "edgLength" on the segment
|
||||
double tmpAngle;
|
||||
var angleBetweenPoints = tmpAngle = GetAngleBetweenPoints(p1, p2);
|
||||
var angleBetweenPoints = tmpAngle = MathHelper.GetAngleBetweenPoints(p1, p2);
|
||||
//set angle in degrees
|
||||
if (edgeControl.AlignLabelsToEdges)
|
||||
{
|
||||
if (p1.X > p2.X)
|
||||
tmpAngle = GetAngleBetweenPoints(p2, p1);
|
||||
tmpAngle = MathHelper.GetAngleBetweenPoints(p2, p1);
|
||||
Angle = -tmpAngle * 180 / Math.PI;
|
||||
}
|
||||
|
||||
p.Offset(edgeLength * Math.Cos(angleBetweenPoints), -edgeLength * Math.Sin(angleBetweenPoints));
|
||||
if(edgeControl.AlignLabelsToEdges)
|
||||
p = RotatePoint(new Point(p.X, p.Y - edgeControl.LabelVerticalOffset), p, Angle);
|
||||
p = MathHelper.RotatePoint(new Point(p.X, p.Y - edgeControl.LabelVerticalOffset), p, Angle);
|
||||
//optimized offset here
|
||||
/*float x = 12.5f, y = 12.5f;
|
||||
double sin = Math.Sin(angleBetweenPoints);
|
||||
double cos = Math.Cos(angleBetweenPoints);
|
||||
double sign = sin * cos / Math.Abs(sin * cos);
|
||||
p.Offset(x * sin * sign + edgeLength * cos, y * cos * sign - edgeLength * sin);*/
|
||||
Arrange(new Rect(p, desiredSize));
|
||||
LastKnownRectSize = new Rect(p, desiredSize);
|
||||
Arrange(LastKnownRectSize);
|
||||
}
|
||||
|
||||
private static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
|
||||
{
|
||||
var angleInRadians = angleInDegrees * (Math.PI / 180);
|
||||
var cosTheta = Math.Cos(angleInRadians);
|
||||
var sinTheta = Math.Sin(angleInRadians);
|
||||
return new Point
|
||||
{
|
||||
X =
|
||||
(int)
|
||||
(cosTheta * (pointToRotate.X - centerPoint.X) -
|
||||
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
|
||||
Y =
|
||||
(int)
|
||||
(sinTheta * (pointToRotate.X - centerPoint.X) +
|
||||
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
|
||||
};
|
||||
}
|
||||
internal Rect LastKnownRectSize;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -758,11 +758,20 @@ namespace GraphX
|
|||
item.ShowArrows = _svShowEdgeArrows;
|
||||
item.ShowLabel = _svShowEdgeLabels;
|
||||
item.AlignLabelsToEdges = _svAlignEdgeLabels;
|
||||
item.UpdateLabelPosition = _svUpdateLabelPosition;
|
||||
HighlightBehaviour.SetIsHighlightEnabled(item, _svEdgeHlEnabled);
|
||||
HighlightBehaviour.SetHighlightControl(item, _svEdgeHlObjectType);
|
||||
HighlightBehaviour.SetHighlightEdges(item, EdgesType.All);
|
||||
}
|
||||
|
||||
private bool _svUpdateLabelPosition;
|
||||
public void UpdateEdgeLabelPosition(bool value)
|
||||
{
|
||||
_svUpdateLabelPosition = value;
|
||||
foreach (var item in EdgesList)
|
||||
item.Value.UpdateLabelPosition = value;
|
||||
}
|
||||
|
||||
private EdgeDashStyle _svEdgeDashStyle = EdgeDashStyle.Solid;
|
||||
/// <summary>
|
||||
/// Sets all edges dash style
|
||||
|
@ -862,6 +871,7 @@ namespace GraphX
|
|||
_svVertexHlEdgesType = hlEdgesOfType;
|
||||
foreach (var item in VertexList)
|
||||
{
|
||||
HighlightBehaviour.SetHighlighted(item.Value, false);
|
||||
HighlightBehaviour.SetIsHighlightEnabled(item.Value, isEnabled);
|
||||
HighlightBehaviour.SetHighlightControl(item.Value, hlObjectsOfType);
|
||||
HighlightBehaviour.SetHighlightEdges(item.Value, hlEdgesOfType);
|
||||
|
@ -882,6 +892,7 @@ namespace GraphX
|
|||
|
||||
foreach (var item in VertexList)
|
||||
{
|
||||
HighlightBehaviour.SetHighlighted(item.Value, false);
|
||||
HighlightBehaviour.SetIsHighlightEnabled(item.Value, isEnabled);
|
||||
HighlightBehaviour.SetHighlightControl(item.Value, hlObjectsOfType);
|
||||
HighlightBehaviour.SetHighlightEdges(item.Value, EdgesType.All);
|
||||
|
@ -938,6 +949,8 @@ namespace GraphX
|
|||
var edgectrl = new EdgeControl(_vertexlist[item.Source], _vertexlist[item.Target], item) { Visibility = defaultVisibility };
|
||||
InternalInsertEdge(item, edgectrl);
|
||||
//setup path
|
||||
if (_svShowEdgeLabels)
|
||||
edgectrl.ShowLabel = true;
|
||||
edgectrl.PrepareEdgePath();
|
||||
//edgectrl.InvalidateChildren();
|
||||
}
|
||||
|
@ -945,6 +958,64 @@ namespace GraphX
|
|||
|
||||
if (LogicCore.EnableParallelEdges)
|
||||
ParallelizeEdges();
|
||||
if (_svShowEdgeLabels && LogicCore.EnableEdgeLabelsOverlapRemoval)
|
||||
RemoveEdgeLabelsOverlap();
|
||||
|
||||
}
|
||||
|
||||
private void RemoveEdgeLabelsOverlap()
|
||||
{
|
||||
var sizes = new Dictionary<LabelOverlapData, Rect>();
|
||||
var sz = GetVertexSizeRectangles();
|
||||
|
||||
foreach (var item in sz)
|
||||
sizes.Add(new LabelOverlapData() { Id = item.Key.ID, IsVertex = true }, item.Value);
|
||||
foreach (var item in EdgesList)
|
||||
{
|
||||
item.Value.UpdateLabelLayout();
|
||||
sizes.Add(new LabelOverlapData() { Id = item.Key.ID, IsVertex = false }, item.Value.GetLabelSize());
|
||||
}
|
||||
|
||||
var orAlgo = LogicCore.AlgorithmFactory.CreateFSAA(sizes, 15f, 15f);
|
||||
orAlgo.Compute();
|
||||
foreach (var item in orAlgo.Rectangles)
|
||||
{
|
||||
if (item.Key.IsVertex)
|
||||
{
|
||||
var vertex = VertexList.FirstOrDefault(a => a.Key.ID == item.Key.Id).Value;
|
||||
if (vertex == null) throw new GX_InvalidDataException("RemoveEdgeLabelsOverlap() -> Vertex not found!");
|
||||
vertex.SetPosition(new Point(item.Value.X + item.Value.Width * .5,item.Value.Y + item.Value.Height * .5));
|
||||
//vertex.Arrange(item.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var edge = EdgesList.FirstOrDefault(a => a.Key.ID == item.Key.Id).Value;
|
||||
if (edge == null) throw new GX_InvalidDataException("RemoveEdgeLabelsOverlap() -> Edge not found!");
|
||||
edge.SetCustomLabelSize(item.Value);
|
||||
}
|
||||
}
|
||||
//recalculate route path for new vertex positions
|
||||
if (LogicCore.AlgorithmStorage.EdgeRouting != null)
|
||||
{
|
||||
LogicCore.AlgorithmStorage.EdgeRouting.VertexSizes = GetVertexSizeRectangles();
|
||||
LogicCore.AlgorithmStorage.EdgeRouting.VertexPositions = GetVertexPositions();
|
||||
LogicCore.AlgorithmStorage.EdgeRouting.Compute();
|
||||
if (LogicCore.AlgorithmStorage.EdgeRouting.EdgeRoutes != null)
|
||||
foreach (var item in LogicCore.AlgorithmStorage.EdgeRouting.EdgeRoutes)
|
||||
item.Key.RoutingPoints = item.Value;
|
||||
}
|
||||
foreach (var item in EdgesList)
|
||||
{
|
||||
item.Value.PrepareEdgePath(false, null, false);
|
||||
}
|
||||
//update edges
|
||||
// UpdateAllEdges();
|
||||
}
|
||||
|
||||
private class LabelOverlapData
|
||||
{
|
||||
public bool IsVertex;
|
||||
public int Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace GraphX
|
|||
internal virtual void OnVertexDoubleClick(VertexControl vc)
|
||||
{
|
||||
if (VertexDoubleClick != null)
|
||||
VertexDoubleClick(this, new VertexSelectedEventArgs(vc, null));
|
||||
VertexDoubleClick(this, new VertexSelectedEventArgs(vc, null, Keyboard.Modifiers));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -105,10 +105,10 @@ namespace GraphX
|
|||
/// </summary>
|
||||
public virtual event VertexSelectedEventHandler VertexSelected;
|
||||
|
||||
internal virtual void OnVertexSelected(VertexControl vc, MouseButtonEventArgs e)
|
||||
internal virtual void OnVertexSelected(VertexControl vc, MouseButtonEventArgs e, ModifierKeys keys)
|
||||
{
|
||||
if (VertexSelected != null)
|
||||
VertexSelected(this, new VertexSelectedEventArgs(vc, e));
|
||||
VertexSelected(this, new VertexSelectedEventArgs(vc, e, keys));
|
||||
}
|
||||
/// <summary>
|
||||
/// Fires when mouse is over the vertex control
|
||||
|
@ -118,7 +118,7 @@ namespace GraphX
|
|||
internal virtual void OnVertexMouseEnter(VertexControl vc)
|
||||
{
|
||||
if (VertexMouseEnter != null)
|
||||
VertexMouseEnter(this, new VertexSelectedEventArgs(vc, null));
|
||||
VertexMouseEnter(this, new VertexSelectedEventArgs(vc, null, Keyboard.Modifiers));
|
||||
if (MouseOverAnimation != null)
|
||||
MouseOverAnimation.AnimateVertexForward(vc);
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ namespace GraphX
|
|||
internal virtual void OnVertexMouseLeave(VertexControl vc)
|
||||
{
|
||||
if (VertexMouseLeave != null)
|
||||
VertexMouseLeave(this, new VertexSelectedEventArgs(vc, null));
|
||||
VertexMouseLeave(this, new VertexSelectedEventArgs(vc, null, Keyboard.Modifiers));
|
||||
if (MouseOverAnimation != null)
|
||||
MouseOverAnimation.AnimateVertexBackward(vc);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Windows.Controls;
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using GraphX.Models;
|
||||
|
||||
|
@ -12,6 +13,7 @@ namespace GraphX
|
|||
/// Visual vertex control
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[TemplatePart(Name = "PART_vertexLabel", Type = typeof(VertexLabelControl))]
|
||||
public class VertexControl: Control, IGraphControl
|
||||
{
|
||||
#region Properties
|
||||
|
@ -57,6 +59,18 @@ namespace GraphX
|
|||
public static readonly DependencyProperty RootCanvasProperty =
|
||||
DependencyProperty.Register("RootArea", typeof(GraphAreaBase), typeof(VertexControl), new UIPropertyMetadata(null));
|
||||
|
||||
private bool _showLabel;
|
||||
public bool ShowLabel
|
||||
{
|
||||
get { return _showLabel; }
|
||||
set
|
||||
{
|
||||
_showLabel = value;
|
||||
if (_vertexLabelControl != null)
|
||||
_vertexLabelControl.Visibility = _showLabel ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
static VertexControl()
|
||||
{
|
||||
//override the StyleKey Property
|
||||
|
@ -99,6 +113,8 @@ namespace GraphX
|
|||
|
||||
private void source_PositionChanged(object sender, EventArgs e)
|
||||
{
|
||||
if(ShowLabel && _vertexLabelControl != null)
|
||||
_vertexLabelControl.UpdatePosition();
|
||||
OnPositionChanged(new Point(0,0), GetPosition());
|
||||
}
|
||||
#endregion
|
||||
|
@ -144,6 +160,21 @@ namespace GraphX
|
|||
UpdateEventhandling(item);
|
||||
}
|
||||
|
||||
private VertexLabelControl _vertexLabelControl;
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (Template != null)
|
||||
{
|
||||
_vertexLabelControl = Template.FindName("PART_vertexLabel", this) as VertexLabelControl;
|
||||
if(_vertexLabelControl != null)
|
||||
_vertexLabelControl.UpdatePosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region Events handling
|
||||
|
||||
internal void UpdateEventhandling(EventType typ)
|
||||
|
@ -206,7 +237,7 @@ namespace GraphX
|
|||
void VertexControl_Down(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (RootArea != null && Visibility == Visibility.Visible)
|
||||
RootArea.OnVertexSelected(this, e);
|
||||
RootArea.OnVertexSelected(this, e, Keyboard.Modifiers);
|
||||
e.Handled = true;
|
||||
}
|
||||
#endregion
|
||||
|
@ -226,5 +257,7 @@ namespace GraphX
|
|||
EventOptions.Clean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GraphX
|
||||
{
|
||||
public class VertexLabelControl : ContentControl
|
||||
{
|
||||
|
||||
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle",
|
||||
typeof(double),
|
||||
typeof(VertexLabelControl),
|
||||
new UIPropertyMetadata(0.0));
|
||||
/// <summary>
|
||||
/// Gets or sets label drawing angle in degrees
|
||||
/// </summary>
|
||||
public double Angle
|
||||
{
|
||||
get { return (double)GetValue(AngleProperty); }
|
||||
set { SetValue(AngleProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LabelPositionProperty = DependencyProperty.Register("LabelPosition",
|
||||
typeof(Point),
|
||||
typeof(VertexLabelControl),
|
||||
new UIPropertyMetadata(new Point()));
|
||||
/// <summary>
|
||||
/// Gets or sets label position if LabelPositionMode is set to Coordinates
|
||||
/// Position is always measured from top left VERTEX corner.
|
||||
/// </summary>
|
||||
public Point LabelPosition
|
||||
{
|
||||
get { return (Point)GetValue(LabelPositionProperty); }
|
||||
set { SetValue(LabelPositionProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LabelPositionModeProperty = DependencyProperty.Register("LabelPositionMode",
|
||||
typeof(VertexLabelPositionMode),
|
||||
typeof(VertexLabelControl),
|
||||
new UIPropertyMetadata(VertexLabelPositionMode.Sides));
|
||||
/// <summary>
|
||||
/// Gets or set label positioning mode
|
||||
/// </summary>
|
||||
public VertexLabelPositionMode LabelPositionMode
|
||||
{
|
||||
get { return (VertexLabelPositionMode)GetValue(LabelPositionModeProperty); }
|
||||
set { SetValue(LabelPositionModeProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty LabelPositionSideProperty = DependencyProperty.Register("LabelPositionSide",
|
||||
typeof(VertexLabelPositionSide),
|
||||
typeof(VertexLabelControl),
|
||||
new UIPropertyMetadata(VertexLabelPositionSide.BottomRight));
|
||||
/// <summary>
|
||||
/// Gets or sets label position side if LabelPositionMode is set to Sides
|
||||
/// </summary>
|
||||
public VertexLabelPositionSide LabelPositionSide
|
||||
{
|
||||
get { return (VertexLabelPositionSide)GetValue(LabelPositionSideProperty); }
|
||||
set { SetValue(LabelPositionSideProperty, value); }
|
||||
}
|
||||
|
||||
public VertexLabelControl()
|
||||
{
|
||||
if (DesignerProperties.GetIsInDesignMode(this)) return;
|
||||
|
||||
LayoutUpdated += VertexLabelControl_LayoutUpdated;
|
||||
HorizontalAlignment = HorizontalAlignment.Left;
|
||||
VerticalAlignment = VerticalAlignment.Top;
|
||||
}
|
||||
|
||||
void VertexLabelControl_LayoutUpdated(object sender, EventArgs e)
|
||||
{
|
||||
var vc = GetVertexControl(VisualParent);
|
||||
if(vc == null || !vc.ShowLabel) return;
|
||||
UpdatePosition();
|
||||
}
|
||||
|
||||
private static VertexControl GetVertexControl(DependencyObject parent)
|
||||
{
|
||||
while (parent != null)
|
||||
{
|
||||
var control = parent as VertexControl;
|
||||
if (control != null) return control;
|
||||
parent = VisualTreeHelper.GetParent(parent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
internal void UpdatePosition()
|
||||
{
|
||||
if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) return;
|
||||
|
||||
var vc = GetVertexControl(VisualParent);
|
||||
if (vc == null) return;
|
||||
|
||||
if (LabelPositionMode == VertexLabelPositionMode.Sides)
|
||||
{
|
||||
Point pt;
|
||||
switch (LabelPositionSide)
|
||||
{
|
||||
case VertexLabelPositionSide.TopRight:
|
||||
pt = new Point(vc.DesiredSize.Width, -DesiredSize.Height);
|
||||
break;
|
||||
case VertexLabelPositionSide.BottomRight:
|
||||
pt = new Point(vc.DesiredSize.Width, vc.DesiredSize.Height);
|
||||
break;
|
||||
case VertexLabelPositionSide.TopLeft:
|
||||
pt = new Point(-DesiredSize.Width, -DesiredSize.Height);
|
||||
break;
|
||||
case VertexLabelPositionSide.BottomLeft:
|
||||
pt = new Point(-DesiredSize.Width, vc.DesiredSize.Height);
|
||||
break;
|
||||
case VertexLabelPositionSide.Top:
|
||||
pt = new Point(vc.DesiredSize.Width *.5 - DesiredSize.Width *.5, -DesiredSize.Height);
|
||||
break;
|
||||
case VertexLabelPositionSide.Bottom:
|
||||
pt = new Point(vc.DesiredSize.Width * .5 - DesiredSize.Width * .5, vc.DesiredSize.Height);
|
||||
break;
|
||||
case VertexLabelPositionSide.Left:
|
||||
pt = new Point(-DesiredSize.Width, vc.DesiredSize.Height * .5f - DesiredSize.Height * .5);
|
||||
break;
|
||||
case VertexLabelPositionSide.Right:
|
||||
pt = new Point(vc.DesiredSize.Width, vc.DesiredSize.Height * .5f - DesiredSize.Height * .5);
|
||||
break;
|
||||
default:
|
||||
throw new GX_InvalidDataException("UpdatePosition() -> Unknown vertex label side!");
|
||||
}
|
||||
LastKnownRectSize = new Rect(pt, DesiredSize);
|
||||
} else
|
||||
{
|
||||
LastKnownRectSize = new Rect(LabelPosition, DesiredSize);
|
||||
}
|
||||
Arrange(LastKnownRectSize);
|
||||
}
|
||||
|
||||
internal Rect LastKnownRectSize;
|
||||
|
||||
}
|
||||
|
||||
public enum VertexLabelPositionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Vertex label is positioned on one of the sides
|
||||
/// </summary>
|
||||
Sides,
|
||||
/// <summary>
|
||||
/// Vertex label is positioned using custom coordinates
|
||||
/// </summary>
|
||||
Coordinates
|
||||
}
|
||||
|
||||
public enum VertexLabelPositionSide
|
||||
{
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight,
|
||||
Top, Right, Bottom, Left
|
||||
}
|
||||
}
|
|
@ -193,6 +193,7 @@ namespace GraphX.Controls
|
|||
{
|
||||
// create VisualBrush for the view finder display panel
|
||||
CreateVisualBrushForViewFinder(Content as Visual);
|
||||
_viewFinderDisplay.Background = this.Background;
|
||||
|
||||
// hook up event handlers for dragging and resizing the viewport
|
||||
_viewFinderDisplay.MouseMove += ViewFinderDisplayMouseMove;
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
<Compile Include="Animations\MoveSimpleAnimation.cs" />
|
||||
<Compile Include="Behaviours\DragBehaviour.cs" />
|
||||
<Compile Include="Behaviours\HighlightBehaviour.cs" />
|
||||
<Compile Include="Controls\VertexLabelControl.cs" />
|
||||
<Compile Include="Controls\ZoomControl\Converters\RoundedValueConverter.cs" />
|
||||
<Compile Include="Controls\ZoomControl\Converters\VisibilityToBoolConverter.cs" />
|
||||
<Compile Include="Controls\ZoomControl\SupportClasses\AreaSelectedEventArgs.cs" />
|
||||
|
|
|
@ -7,12 +7,14 @@ namespace GraphX.Models
|
|||
{
|
||||
public VertexControl VertexControl { get; private set; }
|
||||
public MouseButtonEventArgs MouseArgs { get; private set; }
|
||||
public ModifierKeys Modifiers { get; private set; }
|
||||
|
||||
public VertexSelectedEventArgs(VertexControl vc, MouseButtonEventArgs e)
|
||||
public VertexSelectedEventArgs(VertexControl vc, MouseButtonEventArgs e, ModifierKeys keys)
|
||||
: base()
|
||||
{
|
||||
VertexControl = vc;
|
||||
MouseArgs = e;
|
||||
Modifiers = keys;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace GraphX.Models
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using GraphX.GraphSharp;
|
||||
using System.Reflection;
|
||||
using GraphX.GraphSharp;
|
||||
using GraphX.GraphSharp.Algorithms.EdgeRouting;
|
||||
using GraphX.GraphSharp.Algorithms.Layout;
|
||||
using GraphX.GraphSharp.Algorithms.Layout.Simple.Circular;
|
||||
|
@ -134,6 +135,11 @@ namespace GraphX.Logic.Models
|
|||
}
|
||||
}
|
||||
|
||||
public IOverlapRemovalAlgorithm<T> CreateFSAA<T>(IDictionary<T, Rect> rectangles, float horGap, float vertGap) where T : class
|
||||
{
|
||||
return new FSAAlgorithm<T>(rectangles, new OverlapRemovalParameters() { HorizontalGap = horGap, VerticalGap = vertGap});
|
||||
}
|
||||
|
||||
public IOverlapRemovalParameters CreateOverlapRemovalParameters(OverlapRemovalAlgorithmTypeEnum algorithmType)
|
||||
{
|
||||
switch (algorithmType)
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace GraphX.Logic
|
|||
public IAlgorithmStorage<TVertex, TEdge> AlgorithmStorage { get; set; }
|
||||
#endregion
|
||||
|
||||
public bool EnableEdgeLabelsOverlapRemoval { get; set; }
|
||||
|
||||
public IExternalLayout<TVertex> ExternalLayoutAlgorithm { get; set; }
|
||||
public IExternalOverlapRemoval<TVertex> ExternalOverlapRemovalAlgorithm { get; set; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче