Dernier clic: Rien pour l’instant
Map trace les lignes Dataverse à partir d’une vue ou d’une requête à leur latitude et longitude, à côté de marqueurs, lignes, zones et cercles de votre propre taille. Un composant, identique sur Blazor et React, est dessiné par le fournisseur que vous choisissez : Azure Maps, Esri, Google, OpenStreetMap ou tout autre style MapLibre.
Douze bureaux servant de marqueurs, un itinéraire, une zone de livraison et une région de vente. Les marqueurs très proches les uns des autres se regroupent en groupes, qui zooment lorsqu’on clique dessus. Cliquez sur un bureau pour son popup, ici le contenu de la page ; l’itinéraire et les zones n’en ouvrent aucun, car la page répond elle-même à leurs clics, et la ligne sous la carte montre ce qu’elle a entendu.
Dernier clic: Rien pour l’instant
Les comptes actifs, colorés par leur type de relation, ou avec le commuter les contacts, sont lus par une requête FetchXML avec les permissions du visiteur et placés à leur latitude et longitude. Cliquez sur l’un pour son pop-up : les autres colonnes de la requête sous le nom de la ligne, qui ouvrent sa page. La case au-dessus de la carte trouve une adresse avec le fournisseur du portail et l’épingle.
Dernier clic: Rien pour l’instant
Adresse trouvée: Cherchez-en un dans la case au-dessus de la carte
La configuration du portail nomme son fournisseur et contient les clés de chaque fournisseur, dans la PowerPortalsPro:Maps section, donc une carte doit n’en nommer aucun et aucune page ne contient de clé. Les marqueurs, clusters, fenêtres pop-up et clics fonctionnent de la même manière sur chaque fournisseur :
Esri:ApiKey, et tout style de carte de base ArcGIS à la place des rues.Google:ApiKey, et un identifiant de carte pour une carte stylisée dans Google Cloud.OpenStreetMap:TileUrl production.MapLibre:StyleUrl ou MapLibre:TileUrl, comme MapTiler, OpenFreeMap, Stadia ou votre propre serveur.// appsettings.json; keep the keys with the portal's other secrets
{
"PowerPortalsPro": {
"Maps": {
"Provider": "AzureMaps",
"AzureMaps": { "ClientId": "the Azure Maps account's client id" },
"Esri": { "ApiKey": "an ArcGIS API key" },
"Google": { "ApiKey": "a Maps JavaScript API key", "MapId": "a map id" }
}
}
}
Les clés d’Esri et de Google atteignent le navigateur du spectateur, qui les envoie au fournisseur, comme le font toutes les cartes web. Limitez chacune aux adresses de votre portail dans la console du fournisseur.
Une page ne nomme un fournisseur que pour utiliser un autre que celui du portail, et ne précise que son apparence : un style, un identifiant de carte, une vue des frontières contestées. Ce qu’elle laisse non défini provient de la configuration. Dans un thème sombre, la carte passe au style sombre du fournisseur ; UsePortalTheme ce changement est désactivé.
<Map items={items} />
<Map provider={{ name: 'google', mapId: 'a map id' }} items={items} />
<Map provider={{ name: 'esri', styleName: 'arcgis/navigation' }} items={items} />
<Map provider={{ name: 'mapLibre', styleUrl: 'https://tiles.openfreemap.org/styles/liberty' }} items={items} /><Map Items="items" />
<Map Provider="@(new GoogleMapProvider { MapId = "a map id" })" Items="items" />
<Map Provider="@(new EsriMapProvider { StyleName = "arcgis/navigation" })" Items="items" />
<Map Provider="@(new MapLibreMapProvider { StyleUrl = "https://tiles.openfreemap.org/styles/liberty" })" Items="items" />Une carte Azure Maps se connecte avec des tokens Entra que le portail délivre à sa propre identité, celle qu’il relie à Dataverse, donc aucune clé Azure Maps n’est nécessaire ni n’atteint le navigateur. Attribuez à cette identité le rôle Azure Maps Data Reader sur le compte Azure Maps et rien de plus, puis définissez AzureMaps:ClientId l’identifiant client sur la page d’authentification du compte.
Chaque spectateur détient le jeton pendant son exécution, donc il ne peut faire que ce que ce rôle permet ; limiter les origines autorisées du compte aux adresses de votre portail également. La carte demande un nouveau jeton avant son expiration. Une page demande une fois, et un spectateur peut recevoir 120 jetons par minute sauf PowerPortalsPro:Maps:RateLimit indication contraire ; les visiteurs non connectés sont comptabilisés par leur adresse, que tous les membres d’un bureau partagent.
Affichez une vue ou une requête FetchXML, et chaque ligne avec une latitude et une longitude devient un marqueur nommé par le nom principal de la table. Les lignes sont lues avec les permissions de l’utilisateur, comme celles d’une grille, et cliquer sur une affiche les colonnes de sa vue.
<Map
viewId={activeAccountsViewId}
latitudeColumn="address1_latitude"
longitudeColumn="address1_longitude"
recordColor="var(--colorPaletteRedBackground3)"
/><Map ViewId="activeAccountsViewId"
LatitudeColumn="address1_latitude"
LongitudeColumn="address1_longitude"
RecordColor="var(--colorPaletteRedBackground3)" />Les lignes sans les deux coordonnées sont exclues de la requête. La carte affiche 1 000 lignes sauf MaxRows indication contraire (au maximum 5 000) et note sur la carte lorsqu’il y en a plus.
Les lignes sans coordonnées peuvent les avoir remplies à partir de leurs adresses au fur et à mesure de leur sauvegarde : voir Géocodage.
Avec MultiTable (Réagir : multiTable), la carte montre les lignes de chaque table que le serveur enregistre pour les cartes avec ForMaps, chaque table dans sa propre couleur avec une légende. L’enregistrement nomme les colonnes contenant la latitude et la longitude d’une ligne, qui sont toujours lues. DefaultTables choisit les tables affichées en premier et Tables celles qu’elle peut afficher ; Regarding réduit à les lignes autour d’un enregistrement.
// Program.cs
builder.Services.AddMultiTableSource("account", t => t
.Columns("address1_city")
.ForMaps(latitude: "address1_latitude", longitude: "address1_longitude"));
builder.Services.AddMultiTableSource("contact", t => t
.ForMaps(latitude: "address1_latitude", longitude: "address1_longitude"));
Une table dont les coordonnées sont enregistrées avec AddMapCoordinates, ou remplies par AddGeocoding, est enregistrée pour les cartes avec ForMaps() uniquement : voir Géocodage.
<Map multiTable defaultTables={['account']} allowSavedViews /><Map MultiTable="true" DefaultTables="@(["account"])" AllowSavedViews="true" />Une barre d’outils au-dessus de la carte choisit la vue : chaque table, ou une vue de plusieurs tables enregistrées avec AddMultiTableView et ForMaps(). ViewIds (Réagir : viewIds) ne propose que les vues enregistrées qu’elle nomme, dans son ordre, et DefaultViewId (defaultViewId) celle sur laquelle elle s’ouvre. Son menu Filtre active ou désactive les tables et modifie les filtres de chaque table. Avec AllowSavedViews (Réagir : allowSavedViews), un utilisateur connecté peut enregistrer ce que la carte montre comme une vue propre : voir Vues sauvegarées.
Avec (Réagir : allowNearSearch), une carte de plusieurs tables possède un bouton Proche dans sa barre d’outils. Elle trouve un lieu — une adresse, avec la recherche propre au fournisseur de la carte, ou la localisation du visiteur, que le navigateur lui demande de partager — et la carte affiche alors uniquement les lignes à la distance choisie, la plus proche en première sur chaque table : le cercle est dessiné, la carte y est adaptée, et chaque fenêtre contextuelle indique la distance.NearDistances (nearDistances) définit les distances proposées, 1, 5, 10, 25, 50 et 100 sauf si elle est définie, NearDistance (nearDistance) celle à laquelle elle commence sauf si elle AllowNearSearch est définie, 25 sauf si elle est définie, et NearDistanceUnit (nearDistanceUnit) si elle commence en miles, par défaut ou en kilomètres ; le visiteur peut changer. Voyez-la sur la démo Prochein.
<Map
multiTable
allowNearSearch
nearDistances={[10, 25, 50, 100]}
nearDistance={25}
nearDistanceUnit={DistanceUnits.Kilometers}
/><Map MultiTable="true"
AllowNearSearch="true"
NearDistances="@([10, 25, 50, 100])"
NearDistance="25"
NearDistanceUnit="DistanceUnit.Kilometers" />Chaque table est lue selon ses coordonnées enregistrées, avec les permissions du visiteur : le serveur lit la case autour du cercle, garde les rangées à distance par rapport au sol, et retourne la plus proche. Une recherche près d’un lieu compte au maximum 500 rangées, la plus proche, et la légende de la carte indique quand il y en avait plus ; NearSearchOptions.MaximumMatches augmente ou diminue ce chiffre, jusqu’à 5 000. Un visiteur qui ne peut pas lire les coordonnées d’une table ne trouve aucune de ses rangées.
// Program.cs
builder.Services.Configure<NearSearchOptions>(options => options.MaximumMatches = 1_000);
Cliquer sur un objet, un marqueur ou une ligne, une zone ou un cercle, se relève OnItemClick avec l’objet, ses données et l’endroit où il a été cliqué, puis s’ouvre une fenêtre pop-up au-dessus. La fenêtre pop-up est une carte Fluent avec votre propre contenu : un modèle sur Blazor, une fonction de rendu sur React. Un clic sur la carte elle-même affiche OnMapClick sa position.
<Map
items={items}
onItemClick={({ item, position }) => select(item)}
onMapClick={({ position }) => addStop(position)}
renderPopup={(item) => (
<>
<strong>{item.title}</strong>
<Button onClick={() => open(item)}>Open</Button>
</>
)}
/><Map Items="items" OnItemClick="OnItemClicked" OnMapClick="OnMapClicked">
<PopupTemplate>
<strong>@context.Title</strong>
<FluentButton OnClick="@(() => Open(context))">Open</FluentButton>
</PopupTemplate>
</Map>Pour répondre à un clic à votre façon, ouvrez la page d’un enregistrement, par exemple, ou sélectionnez une région, appelez PreventDefault() au clic (preventDefault() sur React) et la carte n’ouvre aucune fenêtre pop-up pour cela. ShowPopups Réglez sur False Turn Popups désactivés pour chaque élément.
<Map
viewId={accountsViewId}
onItemClick={(event) => {
// A row's marker opens its record's page; anything else its popup.
const row = event.item.data as MapRecord | undefined;
if (row?.record) {
event.preventDefault();
navigate(`/accounts/${row.record.id}`);
}
}}
/><Map ViewId="accountsViewId" OnItemClick="OnItemClicked" />
@code {
// A row's marker opens its record's page; anything else its popup.
private void OnItemClicked(MapItemClickEventArgs args)
{
if (args.Item.Record is { } record)
{
args.PreventDefault();
Navigation.NavigateTo($"accounts/{record.Id}");
}
}
}L’en-tête d’une ligne fait référence à la page de son enregistrement, celle enregistrée pour sa table avec AddRecordPage ( voir Pages d’enregistrement), sur une carte d’une ou plusieurs tables. RecordUrl la lie ailleurs : une URL avec {0} à la place de l’id de la ligne et {1} celle de sa table. ShowRecordLinks (Réagir : showRecordLinks) défini sur faux désactive les liens. Un élément de vos propres liens vers son Urlfichier . Sur React, onNavigate suit le lien avec votre routeur.
Les marqueurs à un endroit, comme les contacts à une adresse, ne se défont jamais en zoomant, donc leur groupe les liste à la place.
ColorColumn colorer le marqueur de chaque ligne selon son option dans une colonne de choix, statut, raison de statut ou oui/non : la couleur que l’option a dans Dataverse, ou l’une des palettes de Fluent lorsqu’elle n’en a pas, avec une légende des options sur la carte. Les lignes sans valeur sont grises. Pour toute autre règle, RecordColorSelector sur Blazor et une fonction pour recordColor sur React donnent à chaque ligne sa propre couleur.
<Map viewId={accountsViewId} colorColumn="customertypecode" recordUrl="/accounts/{0}" />
<Map viewId={accountsViewId} recordColor={(record) => (isKeyAccount(record) ? 'var(--colorPaletteRedBackground3)' : undefined)} /><Map ViewId="accountsViewId" ColorColumn="customertypecode" RecordUrl="accounts/{0}" />
<Map ViewId="accountsViewId" RecordColorSelector="@(record => IsKeyAccount(record) ? "var(--colorPaletteRedBackground3)" : null)" />ShowAddressSearch place une boîte de recherche au-dessus du coin de la carte. Elle trouve les adresses et lieux avec le fournisseur du portail, place en vue en premier, et épingle celui choisi ; OnAddressSelected remet la page à l’endroit et la nul une fois la recherche effacée. AddressSearchCountries La garde dans certains pays, et GoToAddressAsync (goToAddress dans la référence de React) effectue des recherches à partir du code.
<Map
viewId={accountsViewId}
showAddressSearch
addressSearchCountries={['US', 'CA']}
onAddressSelected={(place) => setNear(place?.position ?? null)}
/><Map ViewId="accountsViewId"
ShowAddressSearch="true"
AddressSearchCountries="@(["US", "CA"])"
OnAddressSelected="@(place => _near = place?.Position)" />Azure Maps, Esri et Google suggèrent des lieux comme types de visiteurs. La clé de Google doit activer l’API Places (Nouveau), et la clé d’Esri son privilège de géocodage. OpenStreetMap et MapLibre Maps recherchent dans Nominatim d’OpenStreetMap, dont la politique d’utilisation ne permet qu’un usage léger et jamais en tant que personne tape, donc ils cherchent quand on appuie sur Entrée ; nommer votre propre serveur Nominatim dans OpenStreetMap:GeocoderUrl ou MapLibre:GeocoderUrl pour en savoir plus.
Address (address dans React) affiche une adresse sans boîte de recherche : la carte la trouve avec la même recherche une fois qu’elle est dessinée, et à chaque fois qu’elle change, elle l’épingle et zoome dessus. Un spinner s’affiche pendant qu’elle regarde, et un message quand elle n’est pas trouvée. C’est ce que AddressDisplayValuela broche de la carte s’ouvre pour une adresse sans coordonnées.
<Map address="1 Microsoft Way, Redmond, WA 98052" height="300px" /><Map Address="1 Microsoft Way, Redmond, WA 98052" Height="300px" />ShowPrintButton (showPrintButton dans React) ajoute un bouton Impression — sur la barre d’outils d’une MultiTable carte, sinon dans le coin supérieur droit de la carte — qui affiche la carte telle qu’elle l’affiche, avec ses épingles, sa légende, la fenêtre pop-up ouverte et l’attribution du fournisseur. PrintTitle est le titre au-dessus, et PrintEntries liste les enregistrements en dessous, chacun à côté de l’étiquette de son code PIN. Un Label marqueur est dessiné sur son code à la place du point : donne un nombre aux arrêts et l’impression se lit comme une feuille de route. PrintAsync() (print() sur la référence React) imprime depuis un bouton propre à la page, et OnPrintChanged (onPrintChange) indique quand la carte peut être imprimée et si elle peut être enregistrée en tant qu’image, pour que ce bouton suive.
const stops: MapMarker[] = [{ kind: 'marker', id: '1', label: '1', title: 'Contoso', position: { latitude: 47.61, longitude: -122.33 } }];
<Map
ref={mapRef}
items={stops}
showPrintButton
printTitle="Tuesday's visits"
printEntries={stops.map((stop) => ({ label: stop.label, title: stop.title ?? '' }))}
/>
// The same from a button of the page's own.
mapRef.current?.print();<Map @ref="_map"
Items="stops"
ShowPrintButton="true"
PrintTitle="Tuesday's visits"
PrintEntries="@stops.Select(stop => new MapPrintEntry(stop.Title!, stop.Label)).ToList()" />
@code {
// A marker's Label is drawn on its pin, and beside it in the printed list.
private List<MapMarker> stops = [new() { Id = "1", Label = "1", Title = "Contoso", Position = new(47.61, -122.33) }];
private Map? _map;
// The same from a button of the page's own.
private Task PrintAsync() => _map!.PrintAsync();
}Azure Maps, Esri, OpenStreetMap et MapLibre sont imprimés comme une image de la carte, donc la page autour de la carte est laissée de côté et la carte ne bouge pas ; le même bouton sauvegarde également cette image comme fichier PNG (SaveImageAsync, ou saveImage()). Une fenêtre pop-up ouverte est dessinée sur l’image avec son titre et ses champs, ou les marqueurs qu’elle liste ; une affichant le contenu propre de la page (PopupTemplate, ou renderPopup) est dessinée avec le titre de son article. Une carte Google ne peut pas être copiée dans une image, elle est donc imprimée telle qu’elle est sur la page, popup inclus, le reste de la page est exclu de l’impression, et n’offre aucune image à sauvegarder. Un fournisseur à vous est imprimé comme image lorsque sa surface implémente capture.
NativeOptions sont transmis à la carte du fournisseur au fur et à mesure de sa création, plutôt que sur la carte de la carte. Cela active Street View pour Google, par exemple, ou permet à une carte MapLibre de zoomer uniquement avec la molette de défilement (cooperativeGestures: false) ; par défaut, elle nécessite Ctrl, comme Google sur une page qui défile, donc la page défile au-delà. L’objet carte du fournisseur est également disponible sur votre propre JavaScript : GetNativeMapAsync sur Blazor, native sur la référence React.
<Map provider={{ name: 'google' }} nativeOptions={{ streetViewControl: true }} /><Map Provider="@(new GoogleMapProvider())"
NativeOptions="@(new Dictionary<string, object?> { ["streetViewControl"] = true })" />Un fournisseur dessine la carte de base et les formes, place des éléments et rapporte les clics et les déplacements. Tout le reste appartient à la carte. Inscrivez-en une avec son nom, puis nommez-la dans les paramètres du fournisseur de la carte.
import { registerMapProvider, type MapSurface } from '@powerportalspro/react-maps';
registerMapProvider({
name: 'arcgis-sdk',
async create(context): Promise<MapSurface> {
// Draw into context.container with your library; report clicks and moves through
// context.events; return the surface: camera, projection, overlays and shapes.
},
});
Sur Blazor, utilisez CustomMapProvider avec le nom que vous avez enregistré dans le JavaScript de votre page.
MapLibre, qui dessine tous les fournisseurs sauf Google, charge un script worker à partir de son propre fichier. Installe maplibre-gl à côté @powerportalspro/react-mapsde , et indique-lui où ton bundler a placé le worker une fois, avant qu’une carte ne soit dessinée. Blazor n’a pas besoin de configuration.
// main.tsx, with Vite
import { setMapLibreWorkerUrl } from '@powerportalspro/react-maps';
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
setMapLibreWorkerUrl(workerUrl);
Nom | Type | Par défaut | Description |
|---|---|---|---|
Address | string? | ||
AddressSearchCountries | IReadOnlyList<string>? | ||
AllowFiltering | bool | False | |
AllowNearSearch | bool | False | |
AllowSavedViews | bool | False | |
Center | MapPosition? | ||
Cluster | bool | True | |
ColorColumn | string? | ||
DefaultTables | IEnumerable<string>? | ||
DefaultViewId | Guid? | ||
FetchXml | string? | ||
Filters | IReadOnlyList<QueryFilter>? | ||
FitItemIds | IReadOnlyList<string>? | ||
Height | string | 400px | |
Items | IReadOnlyList<MapItem>? | ||
LatitudeColumn | string | address1_latitude | |
LongitudeColumn | string | address1_longitude | |
MapStyle | MapStyle | Road | |
MaxRows | int | 1000 | |
MultiTable | bool | False | |
NativeOptions | IReadOnlyDictionary<string, Object>? | ||
NearDistance | double? | ||
NearDistances | IReadOnlyList<double>? | ||
NearDistanceUnit | DistanceUnit | Miles | |
PopupTemplate | RenderFragment<MapItem>? | ||
PrintEntries | IReadOnlyList<MapPrintEntry>? | ||
PrintEntriesProvider | Func<IReadOnlyList<MapPrintEntry>>? | ||
PrintTitle | string? | ||
Provider | MapProvider? | ||
RecordColor | string? | ||
RecordColorSelector | Func<TableRecord, string>? | ||
RecordUrl | string? | ||
RecordUrlSelector | Func<TableRecord, string>? | ||
Regarding | TableRecordReference? | ||
SavedViewsKey | string? | ||
ShowAddressSearch | bool | False | |
ShowLegend | bool | True | |
ShowPopups | bool | True | |
ShowPrintButton | bool | False | |
ShowRecordLinks | bool | True | |
SignInUrl | string | Account/Login | |
Tables | IEnumerable<string>? | ||
Title | string? | ||
TitleColumn | string? | ||
UsePortalTheme | bool | True | |
ViewId | Guid? | ||
ViewIds | IEnumerable<Guid>? | ||
Width | string | 100% | |
Zoom | double? |
AddressAddressSearchCountriesAllowFilteringAllowNearSearchAllowSavedViewsCenterClusterColorColumnDefaultTablesDefaultViewIdFetchXmlFiltersFitItemIdsHeightItemsLatitudeColumnLongitudeColumnMapStyleMaxRowsMultiTableNativeOptionsNearDistanceNearDistancesNearDistanceUnitPopupTemplatePrintEntriesPrintEntriesProviderPrintTitleProviderRecordColorRecordColorSelectorRecordUrlRecordUrlSelectorRegardingSavedViewsKeyShowAddressSearchShowLegendShowPopupsShowPrintButtonShowRecordLinksSignInUrlTablesTitleTitleColumnUsePortalThemeViewIdViewIdsWidthZoomNom | Type | Description |
|---|---|---|
OnAddressSelected | EventCallback<MapPlace> | |
OnError | EventCallback<string> | |
OnItemClick | EventCallback<MapItemClickEventArgs> | |
OnMapClick | EventCallback<MapClickEventArgs> | |
OnPrintChanged | EventCallback<MapPrintState> | |
OnViewChanged | EventCallback<MapView> |
OnAddressSelectedOnErrorOnItemClickOnMapClickOnPrintChangedOnViewChangedNom | Paramètres | Type | Description |
|---|---|---|---|
ClearAddressAsync | Task | ||
ClosePopupAsync | Task | ||
FitToItemsAsync | IEnumerable<string> ids | Task | |
GetMapSettingsAsync | string provider | Task<MapSettingsResponse> | |
GetNativeMapAsync | Task<IJSObjectReference> | ||
GetViewAsync | Task<MapView> | ||
GoToAddressAsync | string text | Task<MapPlace> | |
NotifyAddressSelectedAsync | MapPlace place | Task | |
NotifyAddressStatusAsync | string status | Task | |
NotifyClusterClickAsync | string[] ids MapPosition position | Task | |
NotifyErrorAsync | string kind string message | Task | |
NotifyItemClickAsync | string id MapPosition position | Task | |
NotifyMapClickAsync | MapPosition position | Task | |
NotifyViewChangedAsync | MapView view | Task | |
OpenPopupAsync | string id | Task | |
PrintAsync | Task | ||
SaveImageAsync | string fileName | Task<bool> | |
SetCameraAsync | MapCamera camera bool animate | Task |
ClearAddressAsyncClosePopupAsyncFitToItemsAsyncGetMapSettingsAsyncGetNativeMapAsyncGetViewAsyncGoToAddressAsyncNotifyAddressSelectedAsyncNotifyAddressStatusAsyncNotifyClusterClickAsyncNotifyErrorAsyncNotifyItemClickAsyncNotifyMapClickAsyncNotifyViewChangedAsyncOpenPopupAsyncPrintAsyncSaveImageAsyncSetCameraAsync