Hello,
I'm trying to place a point, have a text "label" and a leader line going from the point, to the label.
I can get the point and the text, but no leader line shows. I have looked everywhere, for a long time, tried every sample I can find, and I cannot get the leader line to show. I have seen the community examples, and have tried everything that is even remotely pertinent. And they definitely have balloons and/or callouts defined in the definitions.
I also don't even know what the "best practice" is for this sort of thing. CIMTextGraphic, CIMTextSymbol, labels?
Does anyone have a really basic, "put a dot here, label it with a callout and leader line and actually make it display" example? One that doesn't have numerous other methods being called that are not in the example?
Thanks
Andy
Solved! Go to Solution.
Below is a sample snippet and the method you're looking for is: CreateCIMCalloutTextGraphic(cityName, geometry) which takes a string followed by a geometry (where the leader line ends). The sample is taken from a 2022 Palm Springs Dev Summit tech session, which you can get here: https://github.com/esri/arcgis-pro-sdk/wiki/tech-sessions and then click on "Using Graphic Elements with Maps and Layouts" under 2022 Palm Springs. Note that this sample in 2.x so you would have to convert this to 3.0.
internal class AddCalloutText : Button
{
private List<IDisposable> _graphics = new List<IDisposable>();
protected override void OnClick()
{
try
{
if (_graphics.Count() > 0)
{
// clear existing graphic
foreach (var graphic in _graphics)
graphic.Dispose();
_graphics.Clear();
return;
}
QueuedTask.Run(() =>
{
Envelope zoomExtent;
var cityName = "Redlands";
var geometry = Module1.GetGeometry("U.S. Cities", $@"city_name = '{cityName}'"); // USHighways, route_num = 'I10' States, state_name = 'California'
var cimGraphic = CreateCIMCalloutTextGraphic(cityName, geometry);
var graphic = MapView.Active.AddOverlay(cimGraphic);
_graphics.Add(graphic);
zoomExtent = geometry.Extent;
cityName = "Palm Springs";
geometry = Module1.GetGeometry("U.S. Cities", $@"city_name = '{cityName}'");
cimGraphic = CreateCIMCalloutTextGraphic(cityName, geometry);
graphic = MapView.Active.AddOverlay(cimGraphic);
_graphics.Add(graphic);
zoomExtent = zoomExtent.Union(geometry.Extent);
MapView.Active.ZoomTo(zoomExtent.Expand(1.5, 1.5, true), new TimeSpan(0, 0, 1));
});
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private static CIMTextGraphic CreateCIMCalloutTextGraphic(string text, Geometry geometry)
{
var textSymbolRef = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlackRGB, 10, "Tahoma", "Bold").MakeSymbolReference();
//now set text and location for the CIMGraphic
var textGraphic = new CIMTextGraphic
{
Symbol = textSymbolRef,
Text = text,
Shape = geometry
};
textGraphic.Placement = Anchor.BottomLeftCorner;
//Create a call out
var backgroundCalloutSymbol = new CIMBackgroundCallout();
// set callout colors and leader line
#region callout colors and leader line
//colors used by bounding callout box
CIMColor accentColor = CIMColor.CreateRGBColor(0, 255, 0);
CIMColor backgroundColor = ColorFactory.Instance.CreateRGBColor(190, 255, 190, 50);
//Leader line
//Get a line symbol
var lineSymbol = SymbolFactory.Instance.ConstructLineSymbol(accentColor, 2, SimpleLineStyle.Solid);
//Create a solid fill polygon symbol for the callout.
var polySymbol = SymbolFactory.Instance.ConstructPolygonSymbol(backgroundColor, SimpleFillStyle.Solid);
//accent symbol
var accentSymbol = SymbolFactory.Instance.ConstructLineSymbol(accentColor, 2, SimpleLineStyle.Solid);
//assign the leader line to the callout
backgroundCalloutSymbol.LeaderLineSymbol = lineSymbol;
backgroundCalloutSymbol.LineStyle = LeaderLineStyle.Base;
backgroundCalloutSymbol.LeaderOffset = 2;
//Assign the polygon to the background callout
backgroundCalloutSymbol.BackgroundSymbol = polySymbol;
//Set margins for the callout to center the text
backgroundCalloutSymbol.Margin = new CIMTextMargin
{
Left = 5,
Right = 5,
Top = 5,
Bottom = 5
};
//define the Accent bar
backgroundCalloutSymbol.AccentBarSymbol = accentSymbol;
#endregion callout colors and leader line
//change the Offset for the textbox ... move 20 right and 20 high
var textSym = textGraphic.Symbol.Symbol as CIMTextSymbol;
textSym.OffsetX = 20;
textSym.OffsetY = -40;
//assign the callout to the textSymbol
textSym.Callout = backgroundCalloutSymbol;
if (geometry.GeometryType == GeometryType.Point)
{
// create a leader point
CIMLeaderPoint leaderPt = new CIMLeaderPoint
{
Point = geometry as MapPoint
};
// assign to the textGraphic
textGraphic.Leaders = new List<CIMLeader>() { leaderPt }.ToArray();
}
return textGraphic;
}
}
Below is a sample snippet and the method you're looking for is: CreateCIMCalloutTextGraphic(cityName, geometry) which takes a string followed by a geometry (where the leader line ends). The sample is taken from a 2022 Palm Springs Dev Summit tech session, which you can get here: https://github.com/esri/arcgis-pro-sdk/wiki/tech-sessions and then click on "Using Graphic Elements with Maps and Layouts" under 2022 Palm Springs. Note that this sample in 2.x so you would have to convert this to 3.0.
internal class AddCalloutText : Button
{
private List<IDisposable> _graphics = new List<IDisposable>();
protected override void OnClick()
{
try
{
if (_graphics.Count() > 0)
{
// clear existing graphic
foreach (var graphic in _graphics)
graphic.Dispose();
_graphics.Clear();
return;
}
QueuedTask.Run(() =>
{
Envelope zoomExtent;
var cityName = "Redlands";
var geometry = Module1.GetGeometry("U.S. Cities", $@"city_name = '{cityName}'"); // USHighways, route_num = 'I10' States, state_name = 'California'
var cimGraphic = CreateCIMCalloutTextGraphic(cityName, geometry);
var graphic = MapView.Active.AddOverlay(cimGraphic);
_graphics.Add(graphic);
zoomExtent = geometry.Extent;
cityName = "Palm Springs";
geometry = Module1.GetGeometry("U.S. Cities", $@"city_name = '{cityName}'");
cimGraphic = CreateCIMCalloutTextGraphic(cityName, geometry);
graphic = MapView.Active.AddOverlay(cimGraphic);
_graphics.Add(graphic);
zoomExtent = zoomExtent.Union(geometry.Extent);
MapView.Active.ZoomTo(zoomExtent.Expand(1.5, 1.5, true), new TimeSpan(0, 0, 1));
});
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private static CIMTextGraphic CreateCIMCalloutTextGraphic(string text, Geometry geometry)
{
var textSymbolRef = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlackRGB, 10, "Tahoma", "Bold").MakeSymbolReference();
//now set text and location for the CIMGraphic
var textGraphic = new CIMTextGraphic
{
Symbol = textSymbolRef,
Text = text,
Shape = geometry
};
textGraphic.Placement = Anchor.BottomLeftCorner;
//Create a call out
var backgroundCalloutSymbol = new CIMBackgroundCallout();
// set callout colors and leader line
#region callout colors and leader line
//colors used by bounding callout box
CIMColor accentColor = CIMColor.CreateRGBColor(0, 255, 0);
CIMColor backgroundColor = ColorFactory.Instance.CreateRGBColor(190, 255, 190, 50);
//Leader line
//Get a line symbol
var lineSymbol = SymbolFactory.Instance.ConstructLineSymbol(accentColor, 2, SimpleLineStyle.Solid);
//Create a solid fill polygon symbol for the callout.
var polySymbol = SymbolFactory.Instance.ConstructPolygonSymbol(backgroundColor, SimpleFillStyle.Solid);
//accent symbol
var accentSymbol = SymbolFactory.Instance.ConstructLineSymbol(accentColor, 2, SimpleLineStyle.Solid);
//assign the leader line to the callout
backgroundCalloutSymbol.LeaderLineSymbol = lineSymbol;
backgroundCalloutSymbol.LineStyle = LeaderLineStyle.Base;
backgroundCalloutSymbol.LeaderOffset = 2;
//Assign the polygon to the background callout
backgroundCalloutSymbol.BackgroundSymbol = polySymbol;
//Set margins for the callout to center the text
backgroundCalloutSymbol.Margin = new CIMTextMargin
{
Left = 5,
Right = 5,
Top = 5,
Bottom = 5
};
//define the Accent bar
backgroundCalloutSymbol.AccentBarSymbol = accentSymbol;
#endregion callout colors and leader line
//change the Offset for the textbox ... move 20 right and 20 high
var textSym = textGraphic.Symbol.Symbol as CIMTextSymbol;
textSym.OffsetX = 20;
textSym.OffsetY = -40;
//assign the callout to the textSymbol
textSym.Callout = backgroundCalloutSymbol;
if (geometry.GeometryType == GeometryType.Point)
{
// create a leader point
CIMLeaderPoint leaderPt = new CIMLeaderPoint
{
Point = geometry as MapPoint
};
// assign to the textGraphic
textGraphic.Leaders = new List<CIMLeader>() { leaderPt }.ToArray();
}
return textGraphic;
}
}
Thank you so much for that. With just a few tweaks for my situation, it worked!
Seems like I had all these elements, but something wasn't quite right, apparently.
Andy
A follow up question for these CIMgraphics. Is it possible to have these (the callout boxes) where we can click and drag them around? And have the leader still attached to the point?
Thanks
Andy
Please also refer to the following snippet in the ArcGIS Pro SDK wiki: