Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
@page "/geojson-layers"

<PageTitle>GeoJSON Layers</PageTitle>
<h1>GeoJSON Layers</h1>

<div class="links-div">
<a class="btn btn-secondary" target="_blank" href="https://developers.arcgis.com/javascript/latest/sample-code/layers-geojson/">ArcGIS Sample</a>
<a class="btn btn-primary" target="_blank" href="https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-GeoJSONLayer.html">GeoJSONLayer API Reference</a>
Comment on lines +7 to +8
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These links open in a new tab (target="_blank") but don’t include rel="noopener noreferrer", which leaves the app open to reverse-tabnabbing. Add rel="noopener noreferrer" to external links that use target="_blank".

Suggested change
<a class="btn btn-secondary" target="_blank" href="https://developers.arcgis.com/javascript/latest/sample-code/layers-geojson/">ArcGIS Sample</a>
<a class="btn btn-primary" target="_blank" href="https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-GeoJSONLayer.html">GeoJSONLayer API Reference</a>
<a class="btn btn-secondary" target="_blank" rel="noopener noreferrer" href="https://developers.arcgis.com/javascript/latest/sample-code/layers-geojson/">ArcGIS Sample</a>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-GeoJSONLayer.html">GeoJSONLayer API Reference</a>

Copilot uses AI. Check for mistakes.
</div>
<p class="instructions">
Load GeoJSON data directly from a URL. Toggle the checkbox to display recent earthquake data from the USGS,
styled by magnitude with an interactive popup. Click any earthquake to see its details.
</p>

<div class="geojson-layout">
<div class="geojson-controls">
<div class="form-group">
<label>Show Earthquakes: <input type="checkbox" class="form-check-input" @onchange="@(() => _showEarthquakes = !_showEarthquakes)"></label>
</div>
<div class="form-group">
<label>Data Source:
<select class="form-select" style="display:inline-block; width: auto;"
@onchange="OnSourceChanged">
<option value="month">Past Month</option>
<option value="week">Past Week</option>
<option value="day">Past Day</option>
</select>
</label>
</div>
<div class="form-group geojson-info">
<small>Data: USGS Earthquake Hazards Program</small>
</div>
</div>

<MapView Longitude="-150" Latitude="30" Zoom="2" Class="map-view geojson-map">
<Map>
<Basemap>
<BasemapStyle Name="BasemapStyleName.ArcgisDarkGray" />
</Basemap>

@if (_showEarthquakes)
{
<GeoJSONLayer @key="_dataUrl"
Url="@_dataUrl"
Title="USGS Earthquakes"
Copyright="USGS Earthquakes"
OrderBy="@(new[] { new OrderByInfo("mag", SortOrder.Descending) })">
<PopupTemplate Title="Earthquake Info"
StringContent="<b>Magnitude:</b> {mag}<br><b>Type:</b> {type}<br><b>Location:</b> {place}<br><b>Time:</b> {time}" />
<SimpleRenderer>
<SimpleMarkerSymbol Color="@(new MapColor(226, 119, 40))"
Size="6"
Style="SimpleMarkerSymbolStyle.Circle">
<Outline Color="@(new MapColor(255, 255, 255))" Width="0.5" />
</SimpleMarkerSymbol>
<SizeVariable Field="mag"
MinDataValue="2.5"
MaxDataValue="8"
MinSize="4"
MaxSize="40" />
</SimpleRenderer>
</GeoJSONLayer>
}
</Map>
<LegendWidget Position="OverlayPosition.BottomRight" />
</MapView>
</div>

<style>
.geojson-layout {
display: flex;
flex-direction: column;
gap: 1rem;
}

.geojson-controls {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.5rem;
align-items: center;
}

.geojson-info {
opacity: 0.6;
}

@@media (min-width: 900px) {
.geojson-layout {
flex-direction: row-reverse;
align-items: center;
}

.geojson-controls {
flex-direction: column;
flex-wrap: nowrap;
}

.geojson-controls .form-group {
width: 100%;
box-sizing: border-box;
}

.geojson-map {
flex: 1;
min-height: 500px;
height: 70vh;
max-height: none;
}
}
</style>

Comment on lines +69 to +111
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page embeds a large <style> block directly in the Razor file, while most other pages use scoped *.razor.css files for page-specific styling. Consider moving these styles into GeoJSONLayers.razor.css for consistency and to avoid mixing layout/CSS into the component markup.

Suggested change
<style>
.geojson-layout {
display: flex;
flex-direction: column;
gap: 1rem;
}
.geojson-controls {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.5rem;
align-items: center;
}
.geojson-info {
opacity: 0.6;
}
@@media (min-width: 900px) {
.geojson-layout {
flex-direction: row-reverse;
align-items: center;
}
.geojson-controls {
flex-direction: column;
flex-wrap: nowrap;
}
.geojson-controls .form-group {
width: 100%;
box-sizing: border-box;
}
.geojson-map {
flex: 1;
min-height: 500px;
height: 70vh;
max-height: none;
}
}
</style>

Copilot uses AI. Check for mistakes.
@code {
private bool _showEarthquakes;
private string _dataUrl = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson";

private void OnSourceChanged(ChangeEventArgs e)
{
string period = e.Value?.ToString() ?? "month";
_dataUrl = period switch
{
"week" => "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson",
"day" => "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson",
_ => "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson"
};
}
}
132 changes: 132 additions & 0 deletions samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/Legends.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
@page "/legends"

<PageTitle>Legend</PageTitle>
<h1>Legend</h1>

<div class="links-div">
<a class="btn btn-secondary" target="_blank" href="https://developers.arcgis.com/javascript/latest/sample-code/legend/">ArcGIS Sample</a>
<a class="btn btn-primary" target="_blank" href="https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend.html">Legend API Reference</a>
Comment on lines +7 to +8
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These links open in a new tab (target="_blank") but don’t include rel="noopener noreferrer", which leaves the app open to reverse-tabnabbing. Add rel="noopener noreferrer" to external links that use target="_blank".

Suggested change
<a class="btn btn-secondary" target="_blank" href="https://developers.arcgis.com/javascript/latest/sample-code/legend/">ArcGIS Sample</a>
<a class="btn btn-primary" target="_blank" href="https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend.html">Legend API Reference</a>
<a class="btn btn-secondary" target="_blank" rel="noopener noreferrer" href="https://developers.arcgis.com/javascript/latest/sample-code/legend/">ArcGIS Sample</a>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend.html">Legend API Reference</a>

Copilot uses AI. Check for mistakes.
</div>
<p class="instructions">
The Legend widget describes the symbols used to represent layers in the map. Enable the layers
to see the legend populate automatically. The legend reflects each layer's renderer and symbology.
</p>

<div class="legend-layout">
<div class="legend-controls">
<div class="form-group">
<label>Show Census Layer: <input type="checkbox" class="form-check-input" @onchange="@(() => _showCensusLayer = !_showCensusLayer)"></label>
</div>
<div class="form-group">
<label>Show Trails Layer: <input type="checkbox" class="form-check-input" @onchange="@(() => _showTrailsLayer = !_showTrailsLayer)"></label>
</div>
<div class="form-group">
<label>Show Parks Layer: <input type="checkbox" class="form-check-input" @onchange="@(() => _showParksLayer = !_showParksLayer)"></label>
</div>
</div>

<MapView Longitude="-118.805" Latitude="34.027" Zoom="12" Class="map-view legend-map">
<Map>
<Basemap>
<BasemapStyle Name="BasemapStyleName.ArcgisTopographic" />
</Basemap>

@if (_showCensusLayer)
{
<FeatureLayer @ref="_censusLayer"
Title="Census Block Points"
Url="https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/ACS_Population_by_Race_and_Hispanic_Origin_Boundaries/FeatureServer/2"
Opacity="0.6">
<SimpleRenderer>
<SimpleMarkerSymbol Color="@(new MapColor(0, 112, 255, 0.6))"
Size="4"
Style="SimpleMarkerSymbolStyle.Circle">
<Outline Color="@(new MapColor(0, 0, 0, 0.4))" Width="0.5" />
</SimpleMarkerSymbol>
<SizeVariable Field="B03002_001E"
MinDataValue="0"
MaxDataValue="5000"
MinSize="2"
MaxSize="12" />
</SimpleRenderer>
</FeatureLayer>
}

@if (_showTrailsLayer)
{
<FeatureLayer Title="Trails"
Url="https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0">
<UniqueValueRenderer Field="USE_BIKE">
<UniqueValueInfo Value="YES" Label="Bike Allowed">
<SimpleLineSymbol Color="@(new MapColor("#27ae60"))"
Style="SimpleLineSymbolStyle.Solid"
Width="2.5" />
</UniqueValueInfo>
<UniqueValueInfo Value="NO" Label="No Bikes">
<SimpleLineSymbol Color="@(new MapColor("#e74c3c"))"
Style="SimpleLineSymbolStyle.Dash"
Width="1.5" />
</UniqueValueInfo>
</UniqueValueRenderer>
</FeatureLayer>
}

@if (_showParksLayer)
{
<FeatureLayer Title="Parks and Open Space"
Url="https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0">
<SimpleRenderer>
<SimpleFillSymbol Color="@(new MapColor(56, 168, 0, 0.5))"
Style="SimpleFillSymbolStyle.Solid">
<Outline Color="@(new MapColor(56, 168, 0, 0.8))" Width="1" />
</SimpleFillSymbol>
</SimpleRenderer>
</FeatureLayer>
}
</Map>

<LegendWidget Position="OverlayPosition.BottomRight" />
</MapView>
</div>

<style>
.legend-layout {
display: flex;
flex-direction: column;
gap: 1rem;
}

.legend-controls {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.5rem;
}

@@media (min-width: 900px) {
.legend-layout {
flex-direction: row-reverse;
align-items: center;
}

.legend-controls {
flex-direction: column;
flex-wrap: nowrap;
min-width: 220px;
justify-content: center;
}

.legend-map {
flex: 1;
min-height: 500px;
height: 70vh;
max-height: none;
}
}
</style>

Comment on lines +92 to +126
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page embeds a large <style> block directly in the Razor file, but the rest of the sample app typically uses scoped *.razor.css files for per-page styling (e.g., Basemaps.razor.css, FeatureLayers.razor.css). Consider moving these styles into Legends.razor.css to keep styling consistent and easier to maintain.

Suggested change
<style>
.legend-layout {
display: flex;
flex-direction: column;
gap: 1rem;
}
.legend-controls {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.5rem;
}
@@media (min-width: 900px) {
.legend-layout {
flex-direction: row-reverse;
align-items: center;
}
.legend-controls {
flex-direction: column;
flex-wrap: nowrap;
min-width: 220px;
justify-content: center;
}
.legend-map {
flex: 1;
min-height: 500px;
height: 70vh;
max-height: none;
}
}
</style>

Copilot uses AI. Check for mistakes.
@code {
private bool _showCensusLayer;
private bool _showTrailsLayer;
private bool _showParksLayer;
private FeatureLayer? _censusLayer;
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public partial class UniqueValueRenderers
["proposed"] = new SimpleLineSymbol(new MapColor(192, 192, 192), 1.5, SimpleLineSymbolStyle.Dot)
};
private readonly UniqueValueRenderer _uniqueValueRenderer = new(uniqueValueInfos: roadTypes
.Select(r => new UniqueValueInfo(r.Key.ToUpperFirstChar().Replace("_", " "), r.Value, r.Key))
.Select(r => new UniqueValueInfo(string.Concat(r.Key[0].ToString().ToUpper(), r.Key.AsSpan(1)).Replace("_", " "), r.Value, r.Key))
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This capitalization uses ToUpper() which is culture-sensitive and can produce unexpected results under some cultures (e.g., Turkish). Use an invariant casing operation (e.g., ToUpperInvariant() / char.ToUpperInvariant) to keep labels stable regardless of the current culture.

Suggested change
.Select(r => new UniqueValueInfo(string.Concat(r.Key[0].ToString().ToUpper(), r.Key.AsSpan(1)).Replace("_", " "), r.Value, r.Key))
.Select(r => new UniqueValueInfo(string.Concat(r.Key[0].ToString().ToUpperInvariant(), r.Key.AsSpan(1)).Replace("_", " "), r.Value, r.Key))

Copilot uses AI. Check for mistakes.
.ToArray(),
field: "highway", defaultLabel: "Service",
legendOptions: new UniqueValueRendererLegendOptions("Route Type"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ await InvokeAsync(async () =>
new("basemap-layer-lists", "Basemap Layer Lists", "oi-spreadsheet"),
new("csv-layer", "CSV Layers", "oi-grid-four-up"),
new("kmllayers", "KML Layers", "oi-excerpt"),
new("geojson-layers", "GeoJSON Layers", null, "geojson.svg"),
new("georss-layer", "GeoRSS Layer", "oi-rss"),
new("osm-layer", "OpenStreetMaps Layer", null, "osm.webp"),
new("wcslayers", "WCS Layers", "oi-project"),
Expand All @@ -127,6 +128,7 @@ await InvokeAsync(async () =>
new("projection", "Display Projection", "oi-sun"),
new("projection-tool", "Projection Tool", "oi-cog"),
new("basemap-projections", "Basemap Projections", "oi-bullhorn"),
new("legends", "Legend", null, "legend.svg"),
new("unique-value", "Unique Renderers", "oi-eyedropper"),
new("marker-rotation", "Marker Rotation", "oi-loop-circular"),
new("graphic-tracking", "Graphic Tracking", "oi-move"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ summary a {
}

.esri-widget:not(.esri-feature-table) {
color: unset;
color: var(--text-emphasis);
background-color: var(--background-grey-2);
}

Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new .esri-widget:not(.esri-feature-table) rule has higher specificity than the .esri-feature-templates / .esri-feature-form rules above it, so it will override those backgrounds and effectively negate those earlier overrides. Consider either lowering the .esri-widget selector specificity (e.g., avoid :not(...) in the main rule) or adding later, equally/more-specific overrides for .esri-widget.esri-feature-templates and .esri-widget.esri-feature-form so the intended backgrounds still win.

Suggested change
.esri-widget.esri-feature-templates {
background: unset;
}
.esri-widget.esri-feature-form {
background-color: var(--background-grey-1);
}

Copilot uses AI. Check for mistakes.
.esri-button {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading