Software version: 6.0.4
Diagram.DynamicLinks = true;
Diagram.MeasureUnit = Pixel;
I have created a custom node class (IconNode) based on the sample provided and the label property of the custom node does not render correctly. When the chart is small, the text does not appear but the link text does appear so it would appear there is a problem with how I am drawing the label for the IconNode. When I zoom in, the text property starts to appear but part of the top and bottom is cut off. As the diagram gets closer to 100%, the text is rendered correctly. I tried using labelBound.Inflate(5, 5) and then increased it to labelBound.inflate(100, 100) and that seem to work but the links aren’t rendered correctly at 100, 100. How can I resolve this issue?
My second issue involves laying out the custom nodes. If I use SpringLayout, it lays the nodes in one continuance line. When I change the layout to FractalLayout or TreeLayout (Radial), it displays the nodes correctly but the dynamic links do not work. I have also tried using FractalLayout with SpringLayout but that does not fix the dynamic links problem. Any ideas?
Custom Node class:
[Serializable]
public class IconNode : DiagramNode
{
private Image m_Icon;
private string m_Label;
private StringFormat m_StringFormat;
private static Image m_DefaultIcon;
static IconNode()
{
m_DefaultIcon = new Bitmap(48, 48);
Graphics g = Graphics.FromImage(m_DefaultIcon);
Font f = new Font("Segoe UI", 48, FontStyle.Bold, GraphicsUnit.Pixel);
g.FillRectangle(Brushes.Transparent, 0, 0, 48, 48);
g.DrawString("?", f, Brushes.Black, 0, 0);
f.Dispose();
g.Dispose();
}
public IconNode(Diagram diagram)
: base(diagram)
{
m_Icon = m_DefaultIcon;
m_Label = "Label";
m_StringFormat = new StringFormat();
m_StringFormat.Alignment = StringAlignment.Center;
m_StringFormat.LineAlignment = StringAlignment.Center;
Bounds = new RectangleF(Bounds.Location, CalculateSize());
}
/// <summary>
/// Gets or sets the image for the node.
/// </summary>
public Image Icon
{
get { return m_Icon; }
set
{
m_Icon = value;
Bounds = new RectangleF(Bounds.Location, CalculateSize());
}
}
/// <summary>
/// Gets or sets the label for a node.
/// </summary>
public string Label
{
get { return m_Label; }
set
{
m_Label = value;
Bounds = new RectangleF(Bounds.Location, CalculateSize());
}
}
public override void DrawLocal(IGraphics graphics, RenderOptions options)
{
Rectangle iconSizePixels = new Rectangle(0, 0, m_Icon.Width, m_Icon.Height);
RectangleF imageSize = MindFusion.Utilities.DeviceToDoc(graphics, iconSizePixels);
RectangleF localBounds = GetLocalBounds();
// Draw the icon at the top-middle
graphics.DrawImage(m_Icon, localBounds.X + localBounds.Width / 2 - imageSize.Width / 2, localBounds.Y);
// Draw the label at the bottom
RectangleF labelBounds = RectangleF.FromLTRB(localBounds.X, localBounds.Y + imageSize.Height, localBounds.Right, localBounds.Bottom);
labelBounds.Inflate(10, 10);
graphics.DrawString(m_Label, EffectiveFont, Brushes.Black, labelBounds, m_StringFormat);
}
public override void DrawShadowLocal(IGraphics graphics, RenderOptions options) { }
private SizeF CalculateSize()
{
Bitmap tempImage = new Bitmap(1, 1);
Graphics graphics = Graphics.FromImage(tempImage);
IGraphics measureGraphics = new GdiGraphics(graphics);
measureGraphics.PageUnit = Parent.MeasureUnit;
Rectangle iconSizePixels = new Rectangle(0, 0, m_Icon.Width, m_Icon.Height);
RectangleF imageSize = MindFusion.Utilities.DeviceToDoc(measureGraphics, iconSizePixels);
measureGraphics.Dispose();
tempImage.Dispose();
SizeF textSize = Parent.MeasureString(m_Label, EffectiveFont, int.MaxValue, m_StringFormat);
return new SizeF(Math.Max(imageSize.Width, textSize.Width), imageSize.Height + textSize.Height);
}
protected override void UpdateCreate(PointF current)
{
base.UpdateCreate(current);
Bounds = new RectangleF(current, CalculateSize());
}
protected override void SaveTo(BinaryWriter writer, PersistContext ctx)
{
base.SaveTo(writer, ctx);
// Save the label using the standard .NET BinaryWriter
writer.Write(m_Label);
// Save the image using the MindFusion.Diagramming built-in image saving code,
// which stores the contents of shared images only once.
ctx.SaveImage(m_Icon);
}
protected override void LoadFrom(BinaryReader reader, PersistContext ctx)
{
base.LoadFrom(reader, ctx);
m_Label = reader.ReadString();
m_Icon = ctx.LoadImage();
}
}
Chart layout:
private void InitializeCustomNode()
{
// Enable serialization of IconNode instances
if ((diagram as IItemFactory).TypeTable[typeof(IconNode)] == null)
Diagram.RegisterItemClass(typeof(IconNode), "IconNode", 1);
// Let users draw IconNode objects
diagramView.CustomNodeType = typeof(IconNode);
//diagramView.Behavior = Behavior.Custom;
}
private void InitializeLinkChart()
{
LinkChartService service = new LinkChartService();
m_Entities = service.GetAllEdges();
diagramView.AutoScroll = true;
diagram.ShowGrid = false;
diagramView.ShowScrollbars = true;
// Changes the active item's handlestyle by showing a border when a node is selected.
diagram.ActiveItemHandlesStyle.DashPen = new MindFusion.Drawing.Pen(Color.Blue);
diagramView.SmoothingMode = SmoothingMode.AntiAlias;
PopulateNodes();
/*using (TreeLayout layout = new TreeLayout(TreeLayoutType.Radial))
{
layout.NodeDistance = 150;
layout.Arrange(diagram);
}*/
using (FractalLayout layout = new FractalLayout())
{
layout.Anchoring = Anchoring.Reassign;
layout.Arrange(diagram);
}
using (SpringLayout slayout = new SpringLayout(500, 200, true))
{
//slayout.BeginArrange(diagram, diagram.Items);
slayout.EnableClusters = true;
slayout.Arrange(diagram);
//slayout.EndArrange();
}
diagram.AutoResize = AutoResize.AllDirections;
diagram.ResizeToFitItems(diagram.Nodes.Count);
diagramView.ZoomFactor = 50;
}
private void PopulateNodes()
{
foreach (DataRow row in m_Entities.Rows)
{
//CreateNode((int)row["FromNodeId"], row["FromNode"].ToString());
//CreateNode((int)row["ToNodeId"], row["ToNode"].ToString());
//ConnectNodes((ShapeNode)diagram.FindNodeById((int)row["FromNodeId"]), (ShapeNode)diagram.FindNodeById((int)row["ToNodeId"]), row["RelationshipType"].ToString());
CreateIconNode((int)row["FromNodeId"], row["FromNode"].ToString());
CreateIconNode((int)row["ToNodeId"], row["ToNode"].ToString());
ConnectIconNodes((IconNode)diagram.FindNodeById((int)row["FromNodeId"]), (IconNode)diagram.FindNodeById((int)row["ToNodeId"]), row["RelationshipType"].ToString());
}
}
private void CreateIconNode(int key, string value)
{
if (diagram.FindNodeById(key) != null)
return;
IconNode iconNode = new IconNode(diagram);
iconNode.Id = key;
iconNode.Label = value;
iconNode.Icon = Properties.Resources.UserBlue48;
iconNode.HandlesStyle = HandlesStyle.MoveOnly;
diagram.Nodes.Add(iconNode);
}
private void ConnectIconNodes(IconNode parent, IconNode child, string label)
{
if (child == null)
return;
DiagramLink link = diagram.Factory.CreateDiagramLink(parent, child);
link.Text = label;
link.TextStyle = LinkTextStyle.OverLongestSegment;
link.Font = new System.Drawing.Font("Segoe UI", 9.0f);
}