using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace wispro.sp.share.Utility
{
public class shapeNode
{
public int InCount { get; set; }
public int OutCount { get; set; }
public double x { get; set; }
public double y { get; set; }
public double width { get; set; }
public double height { get; set; }
///
/// 形状类型
/// 0:圆
/// 1:矩形
/// 3: 虚拟
///
public int Type { get; set; }
public int Level { get; set; } = 1;
public dynamic NodeObject { get; set; }
public List Childrens { get; set; }
public List Parents { get; set; }
public string FillColor { get; set; } = "white";
}
public class FlowChartUtility
{
public double TitleHeight { get; set; } = 100;
public double ChartWidth { get; set; } = 1200;
public double ChartHeight { get; set; } = 900;
public double rectWidth { get; set; } = 150;
public double rectHeight { get; set; } = 60;
public double initRadius { get; set; } = 20;
public double EndRadius { get; set; } = 20;
public double hSeparation { get; set; } = 40;
public string StepShapeColor { get; set; } = "green";
public string EndShapColor { get; set; } = "gray";
int rectFontSize { get; set; } = 18;
public List Steps { get; set; }
public List Transfers { get; set; }
public List Actions { get; set; }
public entity.workflowDefine.Workflow workflow { get; set; }
private List shapeTrees = null;
private shapeNode FindNode(int stepId, out int Level, List lstNodes)
{
Level = 1;
foreach (var sNode in lstNodes)
{
if (sNode.NodeObject is entity.workflowDefine.Step && sNode.NodeObject.Id == stepId)
{
return sNode;
}
else
{
if (sNode.Childrens != null)
{
Level += 1;
var retObj = FindNode(stepId, out Level, sNode.Childrens);
if (retObj != null)
{
return retObj;
}
}
}
}
return null;
}
private void GetShapeLevelNodes(Dictionary> levelNodes, List TreeNodes)
{
if (TreeNodes != null)
{
foreach (var sNode in TreeNodes)
{
List nodes = new List();
if (levelNodes.ContainsKey(sNode.Level))
{
nodes = levelNodes[sNode.Level];
nodes.Add(sNode);
}
else
{
nodes.Add(sNode);
levelNodes.Add(sNode.Level, nodes);
}
GetShapeLevelNodes(levelNodes, sNode.Childrens);
}
}
}
public shapeNode startNode;
public shapeNode InitShape;
public shapeNode endNode;
public Dictionary> LevelNodes = new Dictionary>();
private void initShapeTree()
{
shapeTrees = new List();
LevelNodes = new Dictionary>();
#region 添加开始节点
startNode = new shapeNode()
{
//NodeObject = workflow.InitAction,
InCount = 0,
OutCount = 0,
width = 2 * initRadius,
height = 2 * initRadius,
Level = 0
};
#endregion
#region 添加初始化Action节点
InitShape = new shapeNode()
{
NodeObject = workflow.InitAction,
InCount = 0,
OutCount = 0,
Type = 1,
Level = 1,
FillColor = StepShapeColor
};
startNode.Childrens = new List();
startNode.Childrens.Add(InitShape);
InitShape.Parents = new List();
InitShape.Parents.Add(startNode);
shapeTrees.Add(startNode);
#endregion
#region 将步骤对象生成形状Node并添加到列表中
if (Steps != null)
{
foreach (var step in Steps)
{
var temNode = new shapeNode() { NodeObject = step, InCount = 0, OutCount = 0, Type = 1, FillColor = StepShapeColor };
if (workflow.EndStepId == step.Id)
{
endNode = new shapeNode()
{
NodeObject = step,
InCount = 0,
OutCount = 0,
height = 2 * EndRadius,
width = 2 * EndRadius,
FillColor = EndShapColor
};
temNode = endNode;
}
shapeTrees.Add(temNode);
}
}
#endregion
#region 遍历转移条件,生成流程树
if (Transfers != null && Transfers.Count > 0)
{
foreach (var transfer in Transfers)
{
var FromNode = InitShape;
int FromLevel = 0;
if (transfer.StepId != null)
{
FromNode = FindNode(transfer.StepId.Value, out FromLevel, shapeTrees);
}
int ToLevel = 0;
var ToNode = FindNode(transfer.nextStepId, out ToLevel, shapeTrees);
if (FromNode.Childrens == null)
{
FromNode.Childrens = new List();
}
FromNode.Childrens.Add(ToNode);
if (ToNode.Parents == null)
{
ToNode.Parents = new List();
}
ToNode.Parents.Add(FromNode);
FromNode.OutCount += 1;
ToNode.InCount += 1;
if (FromNode.Level >= ToLevel)
{
ToNode.Level = FromNode.Level + 1;
}
if (shapeTrees.Contains(ToNode))
{
shapeTrees.Remove(ToNode);
}
}
if (endNode.Parents != null && endNode.Parents[0].NodeObject is entity.workflowDefine.Step)
{
endNode.Level = endNode.Parents[0].Level + 1;
}
}
else
{
InitShape.Childrens = new List();
InitShape.Childrens.Add(endNode);
InitShape.OutCount += 1;
endNode.Parents = new List();
endNode.Parents.Add(InitShape);
endNode.InCount += 1;
endNode.Level = InitShape.Level + 1;
shapeTrees.Remove(endNode);
//Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(endNode));
}
#endregion
GetShapeLevelNodes(LevelNodes, shapeTrees);
#region 添加跨层连接的中间层的虚拟节点
List AddNodes = new List();
foreach (int level in LevelNodes.Keys)
{
foreach (var temNode in LevelNodes[level])
{
if (temNode.Childrens != null)
{
foreach (var temChildrenNode in temNode.Childrens)
{
if ((temChildrenNode.Level - temNode.Level) > 1)
{
dynamic temAddInfo = new ExpandoObject();
temAddInfo.Parent = temNode;
temAddInfo.Children = temChildrenNode;
temAddInfo.Start = temNode.Level;
temAddInfo.End = temChildrenNode.Level;
AddNodes.Add(temAddInfo);
}
}
}
}
}
foreach (dynamic dynObj in AddNodes)
{
shapeNode parentNode = dynObj.Parent;
shapeNode endNode = dynObj.Children;
for (int i = dynObj.Start + 1; i < dynObj.End; i++)
{
var xnNode = new shapeNode() { Type = 3, Parents = new List(), Childrens = new List(), Level = i };
parentNode.Childrens.Add(xnNode);
xnNode.Parents.Add(parentNode);
parentNode.Childrens.Remove(endNode);
parentNode.Childrens.Add(xnNode);
endNode.Parents.Remove(parentNode);
endNode.Parents.Add(xnNode);
parentNode = xnNode;
LevelNodes[xnNode.Level].Add(xnNode);
}
}
#endregion
int MaxNodeLevel = 0;
int NodeCount = 0;
foreach (int level in LevelNodes.Keys)
{
if (level > 1)
{
int temLevelCount = 0;
foreach (var temNode in LevelNodes[level])
{
int graterInOrOut = (temNode.OutCount > temNode.InCount) ? temNode.OutCount : temNode.InCount;
if (graterInOrOut <= 1)
{
temLevelCount += 1;
}
else
{
temLevelCount += graterInOrOut;
}
}
if (temLevelCount > MaxNodeLevel)
{
MaxNodeLevel = level;
NodeCount = temLevelCount;
}
}
}
#region 每层节点排序
for (var i = 1; i < LevelNodes.Count; ++i)
{
var top_layer = LevelNodes[i - 1];
LevelNodes[i] = LevelNodes[i].OrderBy(node =>
{
if (node.Parents == null)
{
return 0;
}
var connected_nodes = node.Parents
.Where(l => l.Level == (i - 1)).ToList();
if (!connected_nodes.Any())
{
return 0;
}
var average_index = connected_nodes.Select(cn => { var i = top_layer.IndexOf(cn); return i; }).Average();
return average_index;
}).ToList();
}
if (LevelNodes.Count > 1)
{
LevelNodes[0] = LevelNodes[0].OrderBy(node =>
{
var connected_nodes = node.Childrens
.Where(l => l.Level == 1)
.ToList();
if (!connected_nodes.Any())
{
return 0;
}
var average_index = connected_nodes.Select(cn => { var i = LevelNodes[1].IndexOf(cn); return i; }).Average();
return average_index;
}).ToList();
}
#endregion
ArrangeNodesInRows(LevelNodes);
}
private void ArrangeNodesInRows(Dictionary> LevelNodes)
{
double preBotton = TitleHeight;
for (int iLevel = 0; iLevel < LevelNodes.Count; iLevel++)
{
int iCount = 0;
foreach (var node in LevelNodes[iLevel])
{
int max = (node.InCount > node.OutCount) ? node.InCount : node.OutCount;
if (max == 0)
{
max = 1;
}
iCount += max;
}
double onNodeWidth = ChartWidth / (iCount + 1);
iCount = 0;
double maxHeight = 0;
foreach (var node in LevelNodes[iLevel])
{
int max = (node.InCount > node.OutCount) ? node.InCount : node.OutCount;
if (max == 0)
{
max = 1;
}
node.x = onNodeWidth * (iCount + 1) + (max - 1) * onNodeWidth / 2;
if (node.Type == 0)
{
node.width = 2 * initRadius;
node.height = 2 * initRadius;
}
else
{
node.width = rectWidth;
node.height = rectHeight;
}
iCount += max;
if (node.height > maxHeight)
{
maxHeight = node.height;
}
}
foreach (var node in LevelNodes[iLevel])
{
node.y = preBotton + hSeparation + maxHeight / 2;
}
preBotton = preBotton + hSeparation + maxHeight;
}
}
public dynamic GetLineParater(entity.workflowDefine.TrasferCondition trasferCondition)
{
int level = 0;
var startNode = InitShape;
if (trasferCondition.StepId != null)
{
startNode = FindNode(trasferCondition.StepId.Value, out level, shapeTrees);
}
var endNode = FindNode(trasferCondition.nextStepId, out level, shapeTrees);
dynamic ret = new ExpandoObject();
ret.x1 = startNode.x;
ret.y1 = startNode.y + startNode.height / 2;
ret.x2 = endNode.x;
ret.y2 = endNode.y - endNode.height / 2;
double x3 = 0.0;
double y3 = 0.0;
GetArrorEndPoint(ret, out x3, out y3);
ret.x2 = x3;
ret.y2 = y3;
return ret;
}
public void GetArrorEndPoint(dynamic ret, out double x3, out double y3)
{
if (ret.x1 == ret.x2)
{
x3 = ret.x1;
if (ret.y2 > ret.y1)
{
y3 = ret.y2 - 8;
}
else
{
y3 = ret.y2 + 8;
}
}
else
{
if (ret.y1 == ret.y2)
{
y3 = ret.y1;
if (ret.x1 < ret.x2)
{
x3 = ret.x2 - 8;
}
else
{
x3 = ret.x2 + 8;
}
}
else
{
double k = (ret.y1 - ret.y2) / (ret.x1 - ret.x2);
double b = ret.y2 - k * ret.x2;
double a = k * k + 1;
double B = 2 * k * (b - ret.y2) - 2 * ret.x2;
double c = (b - ret.y2) * (b - ret.y2) + ret.x2 * ret.x2 - 100;
double x3_1 = (Math.Sqrt(B * B - 4 * a * c) - B) / (2 * a);
double x3_2 = ((Math.Sqrt(B * B - 4 * a * c) + B) / (2 * a)) * -1;
if (ret.x1 < ret.x2)
{
x3 = (x3_1 < x3_2) ? x3_1 : x3_2;
}
else
{
x3 = (x3_1 < x3_2) ? x3_2 : x3_1;
}
y3 = k * x3 + b;
}
}
}
public dynamic GetEndStepLine()
{
var startNode = InitShape;
if (endNode.Parents != null)
{
startNode = endNode.Parents[0];
}
dynamic ret = new ExpandoObject();
ret.x1 = startNode.x;
ret.y1 = startNode.y + startNode.height / 2;
ret.x2 = endNode.x;
ret.y2 = endNode.y - endNode.height / 2;
double x3 = 0.0;
double y3 = 0.0;
GetArrorEndPoint(ret, out x3, out y3);
ret.x2 = x3;
ret.y2 = y3;
return ret;
}
public dynamic GetStartInitLine()
{
dynamic ret = new ExpandoObject();
ret.x1 = this.startNode.x;
ret.y1 = this.startNode.y + startNode.height / 2;
ret.x2 = InitShape.x;
ret.y2 = InitShape.y - InitShape.height / 2;
double x3 = 0.0;
double y3 = 0.0;
GetArrorEndPoint(ret, out x3, out y3);
ret.x2 = x3;
ret.y2 = y3;
return ret;
}
public void Refresh()
{
//System.Text.Json.JsonSerializer.Serialize(Actions);
initShapeTree();
}
void InitAction()
{
}
#region 单击/双击事件
public EventCallback OnClickStep { get; set; }
public EventCallback OnClickAction { get; set; }
public EventCallback OnClickTransfer { get; set; }
public EventCallback OnDoubleClickStep { get; set; }
[Parameter]
public EventCallback OnDoubleClickAction { get; set; }
[Parameter]
public EventCallback OnDoubleClickTransfer { get; set; }
public shapeNode SelectedShape { get; set; }
void ClickNode(shapeNode node)
{
SelectedShape = node;
if (node.NodeObject is entity.workflowDefine.Step)
{
if (OnClickStep.HasDelegate)
{
OnClickStep.InvokeAsync((entity.workflowDefine.Step)node.NodeObject);
}
}
if (node.NodeObject is entity.workflowDefine.Action)
{
if (OnClickAction.HasDelegate)
{
OnClickAction.InvokeAsync((entity.workflowDefine.Action)node.NodeObject);
}
}
}
void DoubleClickNode(shapeNode node)
{
SelectedShape = node;
if (node.NodeObject is entity.workflowDefine.Step)
{
if (OnDoubleClickStep.HasDelegate)
{
OnDoubleClickStep.InvokeAsync((entity.workflowDefine.Step)node.NodeObject);
}
}
if (node.NodeObject is entity.workflowDefine.Action)
{
if (OnDoubleClickAction.HasDelegate)
{
OnDoubleClickAction.InvokeAsync((entity.workflowDefine.Action)node.NodeObject);
}
}
}
void ClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
{
SelectedShape = null;
if (OnClickTransfer.HasDelegate)
{
OnClickTransfer.InvokeAsync(trasferCondition);
}
}
void DoubleClickTrasfer(entity.workflowDefine.TrasferCondition trasferCondition)
{
SelectedShape = null;
if (OnDoubleClickTransfer.HasDelegate)
{
OnDoubleClickTransfer.InvokeAsync(trasferCondition);
}
}
#endregion
public string GetSvgString()
{
initShapeTree();
string strReturn = $"";
}
}
}