All,
Has anyone successfully created a balloon callout on graphics layer by codes ? I asked this question before with previous version of arcgis Pro. I was under the impression with version 2.8 I should be able to do it but no luck so far. Below is my codes. I got all other properties correct but NO callout arrow. Thanks in advance for your help.
_subjectTextSymbol = await CreateBalloonCalloutAsync(ColorFactory.Instance.RedRGB);
.
.
.
subjectLabelGraphic.Text = "Subject";
subjectLabelGraphic.Symbol = _subjectTextSymbol.MakeSymbolReference();
//Add the graphic label
graphicsLayer.AddElement(subjectLabelGraphic);
.
.
.
private static Task<CIMTextSymbol> CreateBalloonCalloutAsync(CIMColor textColor)
{
return QueuedTask.Run<CIMTextSymbol>(() =>
{
//create a text symbol
var textSymbol = SymbolFactory.Instance.ConstructTextSymbol(textColor, 11, "Corbel", "Regular");
//A balloon callout
var balloonCallout = new CIMBalloonCallout();
//set the callout's style
balloonCallout.BalloonStyle = BalloonCalloutStyle.RoundedRectangle;
//Create a solid fill polygon symbol for the callout.
var polySymbol = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.GreyRGB, SimpleFillStyle.Solid);
//Set the callout's background to be the black polygon symbol
balloonCallout.BackgroundSymbol = polySymbol;
//margin inside the callout to place the text
balloonCallout.Margin = new CIMTextMargin
{
Left = 5,
Right = 5,
Bottom = 5,
Top = 5
};
//assign the callout to the text symbol's callout property
textSymbol.Callout = balloonCallout;
return textSymbol;
});
}
Solved! Go to Solution.
Looks like the leader is part of the graphic not the symbol. I made a text graphic in the UI and added a leader to it then deconstructed the CIM xml.
Note that, w/ a map via graphics layer, the leader position is specified in map units (not page units/points). In my case, the base map is the World Topo in Web Mercator, meters. The leader offset (in the symbol) seems to be the minimum distance beyond which a leader is shown.
var graphicsLayer = MapView.Active.Map.TargetGraphicsLayer;
//This is your method
var textSymbol = await CreateBalloonCalloutAsync(ColorFactory.Instance.WhiteRGB);
var textGraphic = new CIMTextGraphic()
{
Text = "Callout Text",
Placement = Anchor.CenterPoint,
Symbol = textSymbol.MakeSymbolReference(),
Shape = MapView.Active.Extent.Center,
//Leaders is an array of CIMLeader - add a Leader point to show
//the leader, remove Leaders to hide the leader.
Leaders = new CIMLeader[] { new CIMLeaderPoint()
{
//for a graphics layer, the leader location is in map coords
Point = MapPointBuilderEx.CreateMapPoint(MapView.Active.Extent.Center.X - 5000,
MapView.Active.Extent.Center.Y - 1500)
}
}
};
QueuedTask.Run(() =>
{
graphicsLayer.AddElement(textGraphic);
});
Do you have an offset? It will not make the callout arrow unless there is an offset.
I tried
balloonCallout.LeaderOffset = 20;
but didn't see any changes. Is that the correct offset property you talked about ? Thanks @JeremyWiles .
In Pro, if you want it to show the leader line , you can do right-click -> show/hide leader line but I'm unable to find that property in proSDK.
I believe it is LeaderOffset, and your LeaderTolerance should be a lower number than the leader offset. Have you changed the LeaderTolerance proeprty?
Here is an example
balloonCallout.Margin = New CIMTextMargin With {.Left = 2.5, .Right = 2.5, .Bottom = 2, .Top = 2}
balloonCallout.LeaderOffset = 10
balloonCallout.LeaderTolerance = 0
Thanks @JeremyWiles . I tried what you suggested. No luck! 😞
Have you tried it ? Did you get the balloon ?
Looks like the leader is part of the graphic not the symbol. I made a text graphic in the UI and added a leader to it then deconstructed the CIM xml.
Note that, w/ a map via graphics layer, the leader position is specified in map units (not page units/points). In my case, the base map is the World Topo in Web Mercator, meters. The leader offset (in the symbol) seems to be the minimum distance beyond which a leader is shown.
var graphicsLayer = MapView.Active.Map.TargetGraphicsLayer;
//This is your method
var textSymbol = await CreateBalloonCalloutAsync(ColorFactory.Instance.WhiteRGB);
var textGraphic = new CIMTextGraphic()
{
Text = "Callout Text",
Placement = Anchor.CenterPoint,
Symbol = textSymbol.MakeSymbolReference(),
Shape = MapView.Active.Extent.Center,
//Leaders is an array of CIMLeader - add a Leader point to show
//the leader, remove Leaders to hide the leader.
Leaders = new CIMLeader[] { new CIMLeaderPoint()
{
//for a graphics layer, the leader location is in map coords
Point = MapPointBuilderEx.CreateMapPoint(MapView.Active.Extent.Center.X - 5000,
MapView.Active.Extent.Center.Y - 1500)
}
}
};
QueuedTask.Run(() =>
{
graphicsLayer.AddElement(textGraphic);
});
I had never considered that there was a CIMLeader / CIMLeaderPoint in the graphic.
In my case, I did not want a leader. I wanted to be sure there was no leader.
So, I am curious, what does it look like if you added more than one CIMLeaderPoint to the array? I don't think I have seen any label that looked like that in ArcGIS Pro or ArcMap before.
Just creating it on a layout, I can only see one place for a leader point.
Then there is also the option to "Remove Leader." There is never any option to add another vertex to an array of leader points. I am very curious what that would look like.
If you find something, I would love to see it.
@JeremyWiles In my case, it'll loop through many polygons in query and create a label for each of them.
using (var foundCursor = parcelLayer.Search(accountQf))
{
while (foundCursor.MoveNext())
{
using (var row = foundCursor.Current)
{
//The parcel is found. Get the center point to label at.
var shape = row as Feature;
var poly = shape.GetShape() as Polygon;
var maxY = poly.Extent.YMax + 10;
var maxX = poly.Extent.XMax + 10;
MapPoint maxPoint = MapPointBuilder.CreateMapPoint(maxX, maxY);
var textSymbol = await CreateBalloonCalloutAsync(ColorFactory.Instance.BlueRGB);
var textGraphic = new CIMTextGraphic()
{
Text = $"Comp {counter}",
Placement = Anchor.CenterPoint,
Symbol = textSymbol.MakeSymbolReference(),
Shape = maxPoint,
Leaders = new CIMLeader[] { new CIMLeaderPoint()
{
//for a graphics layer, the leader location is in map coords
Point = MapPointBuilderEx.CreateMapPoint(poly.Extent.Center.X,
poly.Extent.Center.Y)
}
}
};
graphicsLayer.AddElement(textGraphic);