Select to view content in your preferred language

Callout text overlapping

2405
15
07-08-2011 07:17 AM
JonathanMeyer
Deactivated User
Anyone I have any suggestions on how to add some conflict detection for text callouts? I have a custom tool that labels certain features a user has selected. The problem is when these features are close together the labels overlap and must be moved by the user. I am arbitrarily setting an offset for the callouts from the features when creating them so they will display away from the feature. However, I can???t find an easy way to determine if the callout will overlap another callout before placing it on the map.
0 Kudos
15 Replies
JonathanMeyer
Deactivated User
Ok, so no help. 

How bout can someone help me figure out the extent of the callout balloon text so I can at least try and figure out where these things are or should go on the map.  Using QueryBounds on the element it�??s not giving me the extent of the callout text.  It appears to be returning something that�??s close to the location of anchor point associated with the callout but not exactly.
0 Kudos
JeffreyHamblin
Occasional Contributor
Can you post some code that shows how you are constructing and placing the callout element?
0 Kudos
JonathanMeyer
Deactivated User
I have simiplified this a little bit to post here but you should be able to get the idea:
        

            double fromX = centerline.FromPoint.X;
            double fromY = centerline.FromPoint.Y;

            ITextElement leftFromTextElement = new TextElementClass();
            IElement leftFromElement = leftFromTextElement as IElement;
            IElementProperties leftFromProperties = leftFromElement as IElementProperties;
            leftFromProperties.Name = "LF:" + OID.ToString();
            leftFromTextElement.Text = "LF " + LeftAddressFrom.ToString();


            ESRI.ArcGIS.Geometry.Point point = new ESRI.ArcGIS.Geometry.Point();

            point.PutCoords(fromX, fromY + mOffset);
            leftFromElement.Geometry = point;


            // Create text symbology
            IFormattedTextSymbol textSymLeftAlign = new TextSymbol() as IFormattedTextSymbol;
            stdole.IFontDisp fontFrom = textSymLeftAlign.Font;
            fontFrom.Size = 8;
            textSymLeftAlign.Font = fontFrom;
            textSymLeftAlign.HorizontalAlignment = esriTextHorizontalAlignment.esriTHALeft;

            ICallout callOut = new BalloonCalloutClass();
            textSymLeftAlign.Background = (ITextBackground)callOut;

            // Set anchor point
            ESRI.ArcGIS.Geometry.Point anchorPTFrom = new ESRI.ArcGIS.Geometry.Point();
            anchorPTFrom.PutCoords(fromX, fromY);
            callOut.AnchorPoint = anchorPTFrom;


            leftFromTextElement.Symbol = textSymLeftAlign;

            IGraphicsContainer graphicsContainer = mMxDoc.ActivatedView as IGraphicsContainer;
            graphicsContainer.AddElement(leftFromElement, 0);
            leftFromElement.Activate(mMxDoc.ActivatedView.ScreenDisplay);
  
   //Testing to see if I can figure out extent of callout graphic
   IEnvelope elementEnvelope = new EnvelopeClass();
   leftFromElement.QueryBounds(mMxDoc.ActiveView.ScreenDisplay,elementEnvelope);
0 Kudos
JeffreyHamblin
Occasional Contributor
I put your code into a test Add-In and made as few modifications as needed to get it to run (just some constant values and document references):


public void PerformTest()
{
    double fromX = 0;
    double fromY = 0;

    ITextElement leftFromTextElement = new TextElementClass();
    IElement leftFromElement = leftFromTextElement as IElement;
    IElementProperties leftFromProperties = leftFromElement as IElementProperties;
    leftFromProperties.Name = "LF:" + "TEST";
    leftFromTextElement.Text = "Sample text to go in a callout to test gettting the size. " +
            "\r\nThis adds some text on a second line." +
            "\r\nThis adds some text on a third line.";


    ESRI.ArcGIS.Geometry.Point point = new ESRI.ArcGIS.Geometry.Point();

    point.PutCoords(fromX, fromY + 0);
    leftFromElement.Geometry = point;


    // Create text symbology
    IFormattedTextSymbol textSymLeftAlign = new TextSymbol() as IFormattedTextSymbol;
    stdole.IFontDisp fontFrom = textSymLeftAlign.Font;
    fontFrom.Size = 8;
    textSymLeftAlign.Font = fontFrom;
    textSymLeftAlign.HorizontalAlignment = esriTextHorizontalAlignment.esriTHALeft;

    ICallout callOut = new BalloonCalloutClass();
    textSymLeftAlign.Background = (ITextBackground)callOut;

    // Set anchor point
    ESRI.ArcGIS.Geometry.Point anchorPTFrom = new ESRI.ArcGIS.Geometry.Point();
    anchorPTFrom.PutCoords(fromX, fromY);
    callOut.AnchorPoint = anchorPTFrom;


    leftFromTextElement.Symbol = textSymLeftAlign;

    IGraphicsContainer graphicsContainer = ArcMap.Document.ActivatedView as IGraphicsContainer;
    graphicsContainer.AddElement(leftFromElement, 0);
    leftFromElement.Activate(ArcMap.Document.ActivatedView.ScreenDisplay);

    //Testing to see if I can figure out extent of callout graphic
    IEnvelope elementEnvelope = new EnvelopeClass();
    leftFromElement.QueryBounds(ArcMap.Document.ActiveView.ScreenDisplay, elementEnvelope);

    System.Diagnostics.Debug.WriteLine("Element: " + elementEnvelope.Width + ", " + elementEnvelope.Height);
}


The output in Page Layout is:
Element: 2.85220000000118, 0.530399999999645

The output in Data View is:
Element: 6608.73942823708, 1228.99884448946

These look to me to correspond to the width and height of the callout box. Isn't that what you are looking for?
0 Kudos
JonathanMeyer
Deactivated User
I put your code into a test Add-In and made as few modifications as needed to get it to run (just some constant values and document references):


public void PerformTest()
{
    double fromX = 0;
    double fromY = 0;

    ITextElement leftFromTextElement = new TextElementClass();
    IElement leftFromElement = leftFromTextElement as IElement;
    IElementProperties leftFromProperties = leftFromElement as IElementProperties;
    leftFromProperties.Name = "LF:" + "TEST";
    leftFromTextElement.Text = "Sample text to go in a callout to test gettting the size. " +
            "\r\nThis adds some text on a second line." +
            "\r\nThis adds some text on a third line.";


    ESRI.ArcGIS.Geometry.Point point = new ESRI.ArcGIS.Geometry.Point();

    point.PutCoords(fromX, fromY + 0);
    leftFromElement.Geometry = point;


    // Create text symbology
    IFormattedTextSymbol textSymLeftAlign = new TextSymbol() as IFormattedTextSymbol;
    stdole.IFontDisp fontFrom = textSymLeftAlign.Font;
    fontFrom.Size = 8;
    textSymLeftAlign.Font = fontFrom;
    textSymLeftAlign.HorizontalAlignment = esriTextHorizontalAlignment.esriTHALeft;

    ICallout callOut = new BalloonCalloutClass();
    textSymLeftAlign.Background = (ITextBackground)callOut;

    // Set anchor point
    ESRI.ArcGIS.Geometry.Point anchorPTFrom = new ESRI.ArcGIS.Geometry.Point();
    anchorPTFrom.PutCoords(fromX, fromY);
    callOut.AnchorPoint = anchorPTFrom;


    leftFromTextElement.Symbol = textSymLeftAlign;

    IGraphicsContainer graphicsContainer = ArcMap.Document.ActivatedView as IGraphicsContainer;
    graphicsContainer.AddElement(leftFromElement, 0);
    leftFromElement.Activate(ArcMap.Document.ActivatedView.ScreenDisplay);

    //Testing to see if I can figure out extent of callout graphic
    IEnvelope elementEnvelope = new EnvelopeClass();
    leftFromElement.QueryBounds(ArcMap.Document.ActiveView.ScreenDisplay, elementEnvelope);

    System.Diagnostics.Debug.WriteLine("Element: " + elementEnvelope.Width + ", " + elementEnvelope.Height);
}


The output in Page Layout is:
Element: 2.85220000000118, 0.530399999999645

The output in Data View is:
Element: 6608.73942823708, 1228.99884448946

These look to me to correspond to the width and height of the callout box. Isn't that what you are looking for?


If you go to the coordinates returned for upper left/right, lower left/right on the elementEnvelope they aren't the four points of the callout box.  They aren't even close.
0 Kudos
JeffreyHamblin
Occasional Contributor
Running same test code as before. The corner location coordinates are correct in Layout View:

Element Size: 2.85220000000118, 0.530399999999645
  UpperLeft:-0.0694000000003143, 0.436700000000201
  LowerLeft:-0.0694000000003143, -0.0936999999994441
  UpperRight:2.78280000000086, 0.436700000000201
  LowerRight:2.78280000000086, -0.0936999999994441


I added this to get the spatial ref and corners:
System.Diagnostics.Debug.WriteLine("  SpatialReference: " + (leftFromTextElement as IGraphicElement).SpatialReference.Name);
System.Diagnostics.Debug.WriteLine("  UpperLeft:" + elementEnvelope.UpperLeft.X + ", " + elementEnvelope.UpperLeft.Y);
System.Diagnostics.Debug.WriteLine("  LowerLeft:" + elementEnvelope.LowerLeft.X + ", " + elementEnvelope.LowerLeft.Y);
System.Diagnostics.Debug.WriteLine("  UpperRight:" + elementEnvelope.UpperRight.X + ", " + elementEnvelope.UpperRight.Y);
System.Diagnostics.Debug.WriteLine("  LowerRight:" + elementEnvelope.LowerRight.X + ", " + elementEnvelope.LowerRight.Y);


In Data View :
Element Size: 6608.73942823708, 1228.99884448946
  SpatialReference: NAD_1983_StatePlane_California_VI_FIPS_0406_Feet
  UpperLeft:-160.905063271523, 1011.83200590312
  LowerLeft:-160.905063271523, -217.16683858633
  UpperRight:6447.83436496556, 1011.83200590312
  LowerRight:6447.83436496556, -217.16683858633

Using the Go To XY (set to Feet like the SR), and it located the corners correctly.
0 Kudos
JonathanMeyer
Deactivated User
Running same test code as before. The corner location coordinates are correct in Layout View:

Element Size: 2.85220000000118, 0.530399999999645
  UpperLeft:-0.0694000000003143, 0.436700000000201
  LowerLeft:-0.0694000000003143, -0.0936999999994441
  UpperRight:2.78280000000086, 0.436700000000201
  LowerRight:2.78280000000086, -0.0936999999994441


I added this to get the spatial ref and corners:
System.Diagnostics.Debug.WriteLine("  SpatialReference: " + (leftFromTextElement as IGraphicElement).SpatialReference.Name);
System.Diagnostics.Debug.WriteLine("  UpperLeft:" + elementEnvelope.UpperLeft.X + ", " + elementEnvelope.UpperLeft.Y);
System.Diagnostics.Debug.WriteLine("  LowerLeft:" + elementEnvelope.LowerLeft.X + ", " + elementEnvelope.LowerLeft.Y);
System.Diagnostics.Debug.WriteLine("  UpperRight:" + elementEnvelope.UpperRight.X + ", " + elementEnvelope.UpperRight.Y);
System.Diagnostics.Debug.WriteLine("  LowerRight:" + elementEnvelope.LowerRight.X + ", " + elementEnvelope.LowerRight.Y);


In Data View :
Element Size: 6608.73942823708, 1228.99884448946
  SpatialReference: NAD_1983_StatePlane_California_VI_FIPS_0406_Feet
  UpperLeft:-160.905063271523, 1011.83200590312
  LowerLeft:-160.905063271523, -217.16683858633
  UpperRight:6447.83436496556, 1011.83200590312
  LowerRight:6447.83436496556, -217.16683858633

Using the Go To XY (set to Feet like the SR), and it located the corners correctly.


Ok yes I agree the code you have works and is returning the 4 corners.  However, try changing your offset value for Y on the leftFromElement.Geometry to something other then 0.  This way the actual callout appears away from the anchor point and will show the tail of the callout.  Then see if the returned coordinates match the corners of the box.
0 Kudos
JeffreyHamblin
Occasional Contributor
Ok yes I agree the code you have works and is returning the 4 corners.  However, try changing your offset value for Y on the leftFromElement.Geometry to something other then 0.  This way the actual callout appears away from the anchor point and will show the tail of the callout.  Then see if the returned coordinates match the corners of the box.



Yeah, it looks like it returns the envelope surrounding the anchor and the balloon -- which makes sense since the element includes both.

Have you tried ITextBackground.QueryBoundary? Since the background is the ballooncallout, it seems like that should work. I don't have time to test it at the moment...
0 Kudos
JonathanMeyer
Deactivated User
Yeah, it looks like it returns the envelope surrounding the anchor and the balloon -- which makes sense since the element includes both.

Have you tried ITextBackground.QueryBoundary? Since the background is the ballooncallout, it seems like that should work. I don't have time to test it at the moment...


No, I'll give that a shot tomorrow see if it works.
0 Kudos