Mysterious extra box by every vertex

Jul 27, 2012 at 6:26 PM

Hi all,

Great work with this project, it's been very easy to get a custom graph up and running with your API.

I'm using your class libraries to create a custom graph in an application of mine and I'm noticing a strange little artifact near all of the vertices I create.

On the displayed graph output there's a translucent white rounded rectangle to the upper left of each of my vertices. I have a hunch that this is each vertex's label background because I explicitly set the label position on each vertex to something other than the default. My vertex creation method looks like:

        private IVertex CreateVertex(string label, Bitmap image, VertexLabelPosition labelPosition)
        {
            var vertex = NodeXlControl.Graph.Vertices.Add();

            vertex.SetValue(ReservedMetadataKeys.PerVertexShape, VertexShape.Image);
            vertex.SetValue(ReservedMetadataKeys.PerVertexLabelPosition, labelPosition);

            vertex.SetValue(ReservedMetadataKeys.PerVertexImage, image.ToBitMapImage());
            vertex.SetValue(ReservedMetadataKeys.PerVertexLabel, label);
            vertex.SetValue(ReservedMetadataKeys.PerVertexLabelFillColor, Colors.Transparent);

            return vertex;
        }

Typically my application will pass either VertexLabelPosition.TopCenter or VertexLabelPosition.MiddleCenter to this method (depending on my needs for each Vertex in this particular graph I'm creating).

Has anyone seen this translucent box floating to the upper left of each vertex before? Is there anyway to remove it, or if my assumption is correct that it is the label background, is there anyway to get the label background to have the same position as the label itself?

My apologies for not having a screenshot to show here.

Thanks in advance!

Coordinator
Jul 27, 2012 at 7:26 PM

Yes, it has come up before.  Please see these posts:

http://nodexl.codeplex.com/discussions/281857
http://nodexl.codeplex.com/workitem/21874

To summarize, I can't reproduce this weird behavior on any of my computers.  The label backgrounds always appear behind the labels for me, as they are supposed to.  My first guess with the other poster, Brian, was that his misplaced label backgrounds were due to bad metrics provided by an old video driver.  Unfortunately,  Brian wasn't able to test his software on a different computer.  So perhaps you can do that.  Do you see this bad label behavior when you try your software on other computers?

-- Tony

Jul 27, 2012 at 8:00 PM
Edited Jul 27, 2012 at 8:00 PM

Hi Tony,

Thanks for the quick reply! Yes, I can reproduce this problem on both a Windows 7 (Professional x64) machine and a Windows XP machine. Both have Matrox video cards, just different models (and different sets of drivers) - on Windows 7 I have a Matrox M9140 with drivers from 11/7/2011 and on the XP machine I have a Matrox QID with drivers from 6/10/2008. If it matters, both are multi-monitor setups (the Windows XP machine with 2 monitors, the Windows 7 machine with 4 monitors).

Also I forgot to mention (in case it matters), my application is a WinForms app (.NET 4) that uses the NodeXlControl inside an ElementHost.

Thanks!

Coordinator
Jul 29, 2012 at 8:49 PM
Edited Jul 29, 2012 at 8:52 PM

Oh, no...

This bad label-drawing behavior occurs only in .NET 4.0 applications.  If I take the simplest application that uses the NodeXLControl to show a couple of vertices with labels and compile it to use the .NET 3.5 assemblies, the label backgrounds appear directly underneath the labels, as expected.  If instead I compile the application to use .NET 4.0 assemblies, the label backgrounds get shifted to the wrong places.  Nothing has changed in NodeXL in these two cases; only the Microsoft-supplied .NET assemblies are different.  (For my own reference, I'm going to attach the sample application after this post.)  I am surprised by this, because Microsoft tries very hard to make .NET releases backward compatible.

The NodeXL Excel Template application uses the .NET 3.5 assemblies, which is why I hadn't seen this bad behavior until now.

The long-term fix is for me to figure out what changed in .NET 4.0 that broke the label positions, and then to adjust the NodeXL code accordingly.  Because we're not using .NET 4.0 yet, and in fact we will probably skip it and wait for .NET 4.5, I cannot do this right now.

Here are some short-term fixes you might consider:

1. Target .NET 3.5 in your application.

2. Wait a few weeks for the next NodeXL release, in which you will be able to turn off label backgrounds by setting NodeXLControl.GraphDrawer.VertexDrawer.BackgroundAlpha to zero.

3. If you can't wait a few weeks, you can recompile the NodeXL source code today and set the background alpha, which is a constant in the current release, to zero.  Ask me for details if you want to go this route.

In any case, thanks for pointing out this bug.

-- Tony

Coordinator
Jul 29, 2012 at 8:50 PM

using System;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using Smrf.NodeXL.Core;
using Smrf.NodeXL.Visualization.Wpf;

/*
This program demonstrates a bug in which vertex labels drawn as annotations
have semi-transparent label backgrounds that are drawn in the wrong places.

The bug occurs when this form is compiled into a .NET 4.0 application.  The bug
does NOT occur when this form is compiled into a .NET 3.5 application.
*/

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private NodeXLControl nodeXLControl;

        public Form1()
        {
            InitializeComponent();

            this.Load += new System.EventHandler(this.Form1_Load);

            ElementHost elementHost = new ElementHost();
            nodeXLControl = new NodeXLControl();
            elementHost.Child = nodeXLControl;
            this.Controls.Add(elementHost);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            IVertex vertex1 = nodeXLControl.Graph.Vertices.Add();

            vertex1.SetValue(ReservedMetadataKeys.PerVertexShape, VertexShape.Square);
            vertex1.SetValue(ReservedMetadataKeys.PerVertexLabelPosition, VertexLabelPosition.BottomCenter);
            vertex1.SetValue(ReservedMetadataKeys.PerVertexLabel, "This is a label.");

            IVertex vertex2 = nodeXLControl.Graph.Vertices.Add();
            vertex2.SetValue(ReservedMetadataKeys.PerVertexRadius, 20F);
            vertex2.SetValue(ReservedMetadataKeys.PerVertexLabelPosition, VertexLabelPosition.BottomCenter);
            vertex2.SetValue(ReservedMetadataKeys.PerVertexLabel, "This is another label.");                          

            nodeXLControl.DrawGraph(true);
        }
    }
}

Jul 30, 2012 at 1:40 PM

Hi Tony,

No worries, it's not a showstopper for me; the benefits I've gotten from using NodeXL far outweigh a few background label ghosts :-) I'll wait to pick up the change in the next release.

Good catch with the issue, and thanks again for the responses! And again, great work on this project

Aug 31, 2012 at 7:26 PM

Hi Tony,

I just wanted to let you know that I just tried the latest NodeXL class libraries release that just came out, 1.0.1.224, and I was able to set NodeXLControl.GraphDrawer.VertexDrawer.BackgroundAlpha to zero as you mentioned before and the misplaced label backgrounds are now gone.

Thanks again for the fix!

Coordinator
Aug 31, 2012 at 7:33 PM

That's good news.  Thanks for letting me know.

I hope to have a real fix later this year when we upgrade to .NET 4.5 and I have a chance to adapt the code to Microsoft's changes.

-- Tony

Apr 9, 2013 at 12:15 AM
There's an additional issue with having the label background offset which may affect the priority of a bugfix.

The label background remains selectable regardless of alpha value. I'd applied the alpha bugfix to avoid the drawing issue, but was getting seemingly random vertices selected outside of my selection fence. Turns out the selection fence was including the invisible offset label backgrounds.

Is there a way to turn off selection by label in the meantime?
Coordinator
Apr 10, 2013 at 1:57 AM
Not through the NodeXL API, no. The only thing I can think of is for you to download the source code, remove the calls that draw the background, and build the solution yourself. The steps to do that are as follows:
  1. Download the source code from the Source Code tab on CodePlex.
  2. Open the solution in Visual Studio. If it's Visual Studio 2010, let Visual Studio convert the solution from the 2007 format.
  3. In Solution Explorer, remove all projects that start with "Excel", and "UnitTests" as well.
  4. In the file VertexDrawer.cs, add a "false" argument to each of the two calls to the VertexLabelDrawer.DrawLabel() method.
  5. Rebuild the solution.
-- Tony
Apr 12, 2013 at 1:02 PM
Thanks, Tony.

I had a cursory look at it and I'll recompile it with the changes over the weekend. I'm keen to nail the original problem as well so I'll grab a look at that while I'm at it.

Cheers, and have a nice weekend :)

Marcus
Coordinator
Apr 12, 2013 at 4:45 PM
Marcus:

If you figure out the root cause of the problem and what needs to be modified in NodeXL to fix it, please let me know!

Thanks,
Tony
Apr 12, 2013 at 9:12 PM
Edited Apr 12, 2013 at 9:13 PM
If I change it to:
        if (drawBackground)
        {
            DrawLabelBackground(drawingContext, graphDrawingContext,
                formattedText, formattedTextColor, m_btBackgroundAlpha,
                new Point(dLabelBoundsLeft, dLabelBoundsTop));
        }
...then it works up until the text butts up against the edge, so I'm inclined to think it's the offset adjustment beforehand that has an issue. Investigating...
Apr 12, 2013 at 10:15 PM
Edited Apr 12, 2013 at 10:16 PM
The following appears to fix the issue ('works on my machine'). I've tried it with various VertexLabelPosition settings and it's adjusted itself to the border correctly when necessary.
// Don't let the text exceed the bounds of the graph rectangle.
Double dLabelBoundsTop = dDrawY;
Double dLabelBoundsBottom = dDrawY + dLabelHeight;

Rect oGraphRectangleMinusMargin = graphDrawingContext.GraphRectangleMinusMargin;

var dXBorderAdjustment = Math.Max(0, oGraphRectangleMinusMargin.Left - dLabelBoundsLeft);
dXBorderAdjustment -= Math.Max(0, dLabelBoundsRight - oGraphRectangleMinusMargin.Right);

var dYBorderAdjustment = Math.Max(0, oGraphRectangleMinusMargin.Top - dLabelBoundsTop);
dYBorderAdjustment -= Math.Max(0, dLabelBoundsBottom - oGraphRectangleMinusMargin.Bottom);

if (drawBackground)
{
        DrawLabelBackground(drawingContext, graphDrawingContext,
                formattedText, formattedTextColor, m_btBackgroundAlpha,
                new Point(dLabelBoundsLeft + dXBorderAdjustment, dLabelBoundsTop + dYBorderAdjustment));
}

drawingContext.DrawText(formattedText, new Point(dDrawX + dXAdjustment + dXBorderAdjustment, dDrawY + dYBorderAdjustment));
Coordinator
Apr 16, 2013 at 8:48 AM
Many thanks, Marcus. I haven't had a chance to try your code yet, but I will.

-- Tony
Coordinator
Nov 14, 2013 at 12:50 AM
Edited Nov 14, 2013 at 12:54 AM
Marcus:

This turns out to be due to a bug in the FormattedText class in .NET 3.5. Specifically, FormattedText.Width, OverhangLeading and OverhangTrailing were being calculated incorrectly when the text was centered or right-aligned. NodeXL has code to compensate for this bug. Microsoft fixed the FormattedText bug in .NET 4.0, but then NodeXL's compensation code breaks the label backgrounds if the code is left in place.

I'm in the process of porting the entire project to Visual Studio 2013 and .NET 4.0, and I've removed NodeXL's compensation code in the process. When we release a ported version of the class libraries, the entire problem will go away in applications that target .NET 4.0.

-- Tony
Coordinator
Nov 14, 2013 at 12:57 AM
Nov 14, 2013 at 9:12 AM
Thanks for the heads-up - glad it got sorted. Looking forward to the new port.

Thanks for your time and effort :)

Marcus