|
POST
|
First, add the tool to the ribbon. I hate the context switching UI of Pro so I tried to make a ribbon group where I placed all my common tools in it and that's where I put my add-in tool. Using my tool is pretty straightforward. First. set up the labelling properties for all the layers you want to manually label in your map & then point and click like you would have in Arcmap. It attempts to use hierarchy logic in labelling so labelling a point feature that's on top of a line & polygon would take precedence. Basically, highest point in the TOC > highest line in the TOC > highest polygon in the TOC. The labels are placed into a graphic layer. If one is not found, it creates one. It's not perfect but it's close enough for how I work.
... View more
02-11-2025
08:05 AM
|
0
|
0
|
1623
|
|
POST
|
On the page you're on in the screenshot, open the browser Developer tools and use the inspect element tool to target the HTML element where the icon is. You may have to drill into it but you'll find the reference to it. Attached is an example.
... View more
02-10-2025
12:33 PM
|
0
|
2
|
1217
|
|
POST
|
One thing I noticed today that I didn't previously is that your HTML table code is missing the preceding less than symbol ( the < ) before the "table" tag which would break the HTML interpretation for the popup. Your HTML table code should be this: <table style="border-collapse: collapse; width: 100%;">
<tbody>
<tr>
<th style="border: 1px solid #ddd; padding: 8px;">Fire District</th>
<th style="border: 1px solid #ddd; padding: 8px;">Contact Name</th>
<th style="border: 1px solid #ddd; padding: 8px;">Phone</th>
<th style="border: 1px solid #ddd; padding: 8px;">Email</th>
<th style="border: 1px solid #ddd; padding: 8px;">Address</th>
</tr>
<tr>
<td style="border: 1px solid #ddd; padding: 8px;">{FireDist}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{ContactName1}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{Phone1}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{Email1}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{Address1}</td>
</tr>
<tr>
<td style="border: 1px solid #ddd; padding: 8px;"></td>
<td style="border: 1px solid #ddd; padding: 8px;">{ContactName2}</td>
<td style="border: 1px solid #ddd; padding: 8px;"></td>
<td style="border: 1px solid #ddd; padding: 8px;">{Email2}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{Address2}</td>
</tr>
</tbody>
</table> Also, because I'm not seeing it in your latest post, I'll just point out that when using the table HTML element, you also need to include the rows element (the <TR> object) and cell data elements (the <TD> object) inside the <table></table> tags. This is what gives it that nice, structured look. Lastly, your screenshot looks like the Classic Map Viewer rather than the New Map Viewer. They should be basically the same but there's always a chance that there is difference. I have stopped using the classic map viewer in my projects but perhaps you have reasons to continue its use.
... View more
02-10-2025
08:37 AM
|
0
|
1
|
2042
|
|
POST
|
You absolutely can do this. In the Popup options, add a text component and enter the editor. Click the "Source" button and then paste in your HTML clock block. Click the Source button once again to go back to "normal" edit mode & click ok. You don't need the dollar sign stuff in the HTML code block. Just put the field names (or expression names) within the curly brackets {}
... View more
02-07-2025
03:53 PM
|
1
|
1
|
2088
|
|
POST
|
The most proactive thing that you can do is enter URLs of concern into the Internet Archive to have them archive the site. I have been able to retrieve older datasets from as far back as the mid 2000s from some Forest Service sites this way. As for AGOL / Living Atlas, I would not have any concerns about a layer disappearing if the "owner" who has published the service is ESRI or ESRI associated. In these situations, they have likely copied the data from the original source and are publishing from that point of origin. Some federal agencies such as the Forest Service have published their datasets through AGOL under their agency accounts and those could fall victim to whatever happens.
... View more
02-06-2025
02:55 PM
|
5
|
0
|
2435
|
|
POST
|
According to this ESRI document page, the GeoLookup Tool was replaced with the Analysis tool in EB. In typical ESRI fashion, what usually happens is that the replacing tool/widget doesn't offer the same parity as what it's designed to replace. You'll need to review the Analysis Tool help doc to see if your workflow is possible with it and, if not, submit an ESRI Idea to backfill the functionality lost. It absolutely sucks but this is how ESRI has continued to operate.
... View more
02-05-2025
02:37 PM
|
1
|
0
|
811
|
|
POST
|
There are a lot of samples and snippits and it's a challenge tying it all together since no single sample usually accomplishes what you want. I'm by no means a seasoned veteran at this but here's the code I developed to label features in Pro the same way I was accustomed to in Arcmap. I disagree with much of Pro's forced workflow and labels in feature classes is one of them. It's overkill for adding 30 or 50 labels for a map but I digress.. This tool attempts to replicate the Arcmap label tool- label symbology is defined in each layer and the tool will obtain that based on what features were clicked on. I also tried to implement layer hierarchy so that the feature that gets labelled is the one the drew on top of the other features (point on a line, line on a polygon, etc). Anyways, this won't do what you want right out of the box but hopefully this ties together some of the tasks you need to pull off your labelling and you can modify where you need to do things differently. The code is C# and should work using the v3.3 API. using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using ArcGIS.Core.Arcade;
using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Data.DDL;
using ArcGIS.Core.Data.UtilityNetwork.Trace;
using ArcGIS.Core.Geometry;
using ArcGIS.Core.Internal.CIM;
using ArcGIS.Core.Internal.Geometry;
using ArcGIS.Desktop.Catalog;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Extensions;
using ArcGIS.Desktop.Framework;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Internal.Mapping.CommonControls;
using ArcGIS.Desktop.Layouts;
using ArcGIS.Desktop.Mapping;
using Microsoft.VisualBasic;
namespace pwTools
{
internal class arcmapLabeller : MapTool
{
public arcmapLabeller()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Point;
SketchOutputMode = SketchOutputMode.Map;
UseSnapping = true;
}
protected override Task OnToolActivateAsync(bool active)
{
QueuedTask.Run(() =>
{
var graphicsLayer = MapView.Active.Map.TargetGraphicsLayer;
if (graphicsLayer == null)
{
var graphicsLayerCreationParams = new GraphicsLayerCreationParams { Name = "Map Labels Layer", MapMemberPosition = MapMemberPosition.AutoArrange };
var theOutGraphicsLayer = LayerFactory.Instance.CreateLayer<ArcGIS.Desktop.Mapping.GraphicsLayer>(graphicsLayerCreationParams, MapView.Active.Map);
}
});
return base.OnToolActivateAsync(active);
}
protected override Task<bool> OnSketchCompleteAsync(ArcGIS.Core.Geometry.Geometry geometry)
{
var popupContent = QueuedTask.Run(async () =>
{
var popupContents = new List<PopupContent>();
var mapView = MapView.Active;
Dictionary<MapMember, List<long>> features = new Dictionary<MapMember, List<long>>();
await QueuedTask.Run(() =>
{
features = mapView.GetFeatures(geometry).ToDictionary();
});
var featCount = features.Count;
//The click event returns a list of features encountered but that list has an unexpected hierachy so the first value is not
//necessarily the "top" layer. The list of layers must be sorted in order to evaluate which layer is the top layer
Dictionary<int, string> theHitList = new Dictionary<int, string>();
await QueuedTask.Run(() =>
{
var counter = 0;
foreach (var feature in features)
{
theHitList.Add(counter, feature.Key.Name);
counter++;
}
});
//Based on the click hit, get a reference to the layer name, Map, and Object ID
var theLayerName = "";
await QueuedTask.Run(() =>
{
theLayerName = getTopLayer(theHitList, features.First().Key.Map);
});
var theMap = features.First().Key.Map;
//Loop through the layer list to find theLayerName and get it's ObjectID
var theOID = features.First().Value[0];
foreach (var item in features)
{
if (item.Key.ToString() == theLayerName)
{
theOID = item.Value[0];
}
}
//Now get references to the layer and its geometry type
var theLayer = theMap.FindLayers(theLayerName).First();
var theFLayer = theMap.FindLayers(theLayerName).First() as FeatureLayer;
var theFeatureGeometry = "";
var fieldDescriptions = theFLayer.GetFieldDescriptions();
//Determine the geometry type of the layer whose feature was clicked
ShapeDescription alternativeShapeDescription = new ShapeDescription(theFLayer.GetFeatureClass().GetDefinition());
if (alternativeShapeDescription.GeometryType == GeometryType.Polyline)
{
theFeatureGeometry = "Polyline";
} else if (alternativeShapeDescription.GeometryType == GeometryType.Polygon)
{
theFeatureGeometry = "Point";
} else
{
theFeatureGeometry = "Polygon";
}
//Now get symbol information that's been defined for the layer
var lyrDefn = theFLayer.GetDefinition() as CIMFeatureLayer;
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
var theTextSymbol = theLabelClass.TextSymbol;
ArcGIS.Core.Geometry.Geometry theFeatGeometry = null;
var theExpression = theLabelClass.Expression;
var theLabelField = theExpression.Split(".").ElementAt(1);
var theLabelText = "";
//Get the attribute value for the field that provides the label
theLabelText = await QueuedTask.Run(() =>
{
ArcGIS.Core.Data.QueryFilter queryFilter = new ArcGIS.Core.Data.QueryFilter { WhereClause = "OBJECTID = " + theOID };
Feature curFeature = null;
var curLabel = "";
using (RowCursor rowCursor = theFLayer.Search(queryFilter))
{
if (rowCursor != null)
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
curFeature = row as Feature;
//curLabel = curFeature.GetOriginalValue(curFeature.FindField(theLabelField)).ToString();
//--------------------------------------------
// BEGIN 3.2 CODE BLOCK
// Source: https://community.esri.com/t5/arcgis-pro-sdk-questions/evaluate-python-label-expression/m-p/1399197
//--------------------------------------------
var arcade_expr = new CIMExpressionInfo()
{
Expression = theExpression,
ReturnType = ExpressionReturnType.Default
};
var variables = new List<KeyValuePair<string, object>>() { new KeyValuePair<string, object>("$feature", curFeature) };
var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(arcade_expr, ArcadeProfile.Popups);
var result = arcade.Evaluate(variables).GetResult();
curLabel = result.ToString();
//-------------------------------------------
// END 3.2 CODE BLOCK
//-------------------------------------------
if (theFeatureGeometry == "Polyline")
{
theFeatGeometry = curFeature.GetShape(); //Needed if the feature clicked was a line. Otherwise the point geometry where the user clicked is used
//Using a line as the geometry for graphic text is problematic as lines with a general bearing of 180-359 degrees tend to produce a graphic text
//that appears upside down when labelled using this add-in tool. Because of this, we must examine the line's bearing and, if needed, flip the
//line's geometry so that the text that gets produced will appear properly...
var length2D = GeometryEngine.Instance.Length(theFeatGeometry);
var qStartPoint = GeometryEngine.Instance.QueryPoint(theFeatGeometry as Multipart, SegmentExtensionType.NoExtension, 0, AsRatioOrLength.AsLength);
var qEndPoint = GeometryEngine.Instance.QueryPoint(theFeatGeometry as Multipart, SegmentExtensionType.NoExtension, length2D, AsRatioOrLength.AsLength);
double Rad2Degrees = 180 / Math.PI;
var lineBuilder = new LineBuilder(qStartPoint, qEndPoint);
var lineSeg = lineBuilder.ToSegment();
var degrees = lineSeg.Angle * Rad2Degrees;
degrees = 90 - degrees;
if (degrees < 0)
degrees = degrees + 360;
if (180 < degrees && degrees < 360)
{
var theReverseGeometry = GeometryEngine.Instance.ReverseOrientation(theFeatGeometry as Multipart);
theFeatGeometry = theReverseGeometry;
}
else
{
theFeatGeometry = curFeature.GetShape();
}
}
else
{
theFeatGeometry = geometry;
}
}
}
}
}
return curLabel;
});
await QueuedTask.Run(() =>
{
var graphicsLayer = MapView.Active?.Map.TargetGraphicsLayer;
if (theLabelText.Length > 1)
{
var graphic = new CIMTextGraphic()
{
Symbol = theTextSymbol
};
graphic.Shape = theFeatGeometry;
graphic.Text = theLabelText;
graphicsLayer.AddElement(graphic);
}
else
{
MessageBox.Show("No label text exists for the feature clicked", "Arcmap Labeller");
}
});
//MessageBox.Show("Label Parameters:\nLayer Name: " + theLayerName + "\nGeometry Type: " + theFeatureGeometry + "\nLabelling Field Specified: " + theLabelField + "\nLabel Placed would be: " + theLabelText, "Arcmap Labeller Result");
});
var clickPoint = MouseCursorPosition.GetMouseCursorPosition();
return base.OnSketchCompleteAsync(geometry);
}
private static string getTopLayer(Dictionary<int,string> clickList, Map theMap)
{
//This function processes the supplied dictionary list of layers and sorts that list according to each layer's
//position in the Table of Contents. The first value in the list will be the top layer in the TOC
var layers = MapView.Active.Map.GetLayersAsFlattenedList(); // MapView.Active.Map.Layers.Where(layer => layer is FeatureLayer);
SortedDictionary<int, string> sortedLayerList = new SortedDictionary<int, string>();
foreach (var layer in clickList)
{
var curLayerName = layer.Value;
for (int i = 0; i < layers.Count; i++)
{
if (layers[i].Name == curLayerName)
{
sortedLayerList.Add(i, layers[i].Name);
break;
}
}
}
return sortedLayerList.First().Value;
}
}
}
... View more
01-28-2025
08:59 AM
|
2
|
1
|
1713
|
|
BLOG
|
@AzizaParveen1 Ok, so it won't be in the Feb 2025 release but is ESRI implementing this in a subsequent release?
... View more
01-23-2025
07:34 AM
|
0
|
0
|
19746
|
|
BLOG
|
Hoping the ability to sort the information within the Near Me report based on a field (or fields) will be included when it's released but I'm prepared to be disappointed.
... View more
01-21-2025
11:42 AM
|
3
|
0
|
20183
|
|
POST
|
To my knowledge, the answer is no, and it's surprising that ESRI has not addressed this as this is a pretty common need. ESRI does have a sample for WebApp Builder that does precisely this (link here) but elevating it to standard functionality hasn't happened yet (I've mentioned this to the devs at the UC).
... View more
01-14-2025
08:06 AM
|
1
|
0
|
838
|
|
POST
|
ESRI has several "feedback" maps where users can identify issues and request corrections/updates- ESRI Basemap Feedback ESRI Imagery Basemap Feedback Open either map, draw a polygon around your area of interest and add a description of what is needed. There's no guarantee that ESRI will actually do it but it's at least logged and they'll look at it.
... View more
01-08-2025
02:07 PM
|
0
|
1
|
1270
|
|
IDEA
|
You can try specifying the area of interest in the Imagery Feedback application. Whether ESRI follows through on that is an entirely different matter but that is one of the options for requesting updates to the imagery basemap.
... View more
12-12-2024
07:39 AM
|
0
|
0
|
414
|
|
POST
|
Sure, no problem. Not my area but it does seem like at least *some* of the gaps may be covered by the Illinois Lidar holdings? That gap along the eastern state border and the southern tip seems available according to this Lidar Status Map from 2024.
... View more
11-19-2024
11:53 AM
|
1
|
0
|
2179
|
|
POST
|
Normally all USGS stuff would be downloaded through the EarthExplorer website but in this case, there's a different web app for that (link here). Look under the Elevation Producst (3DEP).
... View more
11-19-2024
11:26 AM
|
1
|
1
|
2184
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 03-12-2026 01:43 PM | |
| 1 | 03-12-2026 08:41 AM | |
| 2 | 03-10-2026 10:10 AM | |
| 1 | 02-18-2026 09:20 AM | |
| 3 | 01-22-2026 02:03 PM |