Fermer

janvier 12, 2023

Création d’une application basée sur la carte dans Blazor

Création d’une application basée sur la carte dans Blazor


Toute interface utilisateur contenant une carte est automatiquement plus cool que toute autre interface utilisateur. Avec le composant Telerik UI for Blazor’s Map, vous pouvez avoir une carte interactive basée sur les données à afficher en quelques minutes.

Il ne fait aucun doute qu’une interface utilisateur avec une carte est axiomatiquement plus cool qu’une interface utilisateur sans carte. Avec Progrès de l’interface utilisateur Telerik pour Blazorc’est
Composant de cartevous pouvez créer rapidement une application cartographique interactive, basée sur les données et personnalisable qui transmet des informations clés (enfin, à condition que vous disposiez des informations de latitude et de longitude pour tout ce que vous souhaitez cartographier).

Permettez-moi de démontrer cette affirmation en créant une application qui affiche une carte avec les entrepôts d’une entreprise, chacun avec une bulle cool indiquant la quantité en stock dans chaque entrepôt. De plus, dans cette application, lorsqu’un utilisateur clique sur un entrepôt dans la carte, l’application affiche des informations clés sur l’entrepôt sélectionné. Et, juste pour ajouter la cerise sur le gâteau, je laisse l’utilisateur personnaliser l’affichage.

Mise en place

J’ai créé l’application initiale à l’aide du modèle d’application Blazor Server de Visual Studio. Une fois le projet initialisé, j’ai ouvert le fichier Index.cshtml et ajouté le composant TelerikMap à l’UI de la page :

<TelerikMap Center="@Center">
    <MapLayers>

    </MapLayers>
</TelerikMap>

L’attribut Centre de l’élément TelerikMap établit l’emplacement géographique sur lequel la carte est centrée. J’ai lié cela à un champ de mon application (que j’ai intelligemment nommé Centre) et, grâce à une recherche rapide sur Google, j’ai défini ce champ sur la latitude et la longitude de ma ville natale de London, en Ontario (ce qui n’est pas tout à fait choix arbitraire : l’affichage qui en résulte montre les trois entrepôts nord-américains de mon client fictif).

Avec le composant TelerikMap, les informations de localisation doivent être conservées dans un tableau de type double. Ce tableau doit contenir deux valeurs, la première valeur étant la latitude et la seconde la longitude.

Par conséquent, mon champ Centre avec les informations de localisation pour London, Ontario, ressemble à ceci :

@code{
       public double[] Center { get; set; } = new double[] { 42.983612, -81.249725 };

Une carte Telerik consiste en fait en un ensemble d’objets MapLayer, chacun ajoutant des données à la carte.

Par exemple, pour obtenir l’affichage initial d’une carte, j’ajoute un MapLayer de type Tile, lié au service open-source OpenStreet. Le passe-partout MapLayer suivant me donne une carte de base (et inclut un lien vers la page de licence d’OpenStreet, comme l’exige le contrat de licence d’OpenStreet):

<MapLayers>
    <MapLayer Type="@MapLayersType.Tile"
                         Attribution="&copy; <a href="https://osm.org/copyright">OpenStreetMap contributors</a>"
                         Subdomains="@(new string[] {"a", "b", "c"})"
                         UrlTemplate="https://#= subdomain #.tile.openstreetmap.org/#= zoom #/#= x #/#= y #.png"
>
     </MapLayer> 
</MapLayers>

Avec juste cela en place, appuyez sur F5 pour afficher la carte initiale.

Une carte montrant l'Amérique du Nord, une partie de l'Amérique du Sud, l'Europe occidentale et une partie du nord-ouest de l'Afrique.  Il y a un lien vers le contrat de licence OpenStreet dans le coin inférieur droit de la carte

Obtenir des données

Je suis maintenant prêt à afficher certains emplacements d’entrepôt. D’abord, bien sûr, j’ai besoin de quelques données. Pour cela, dans la méthode OnInitializedAsync de Index.cshtml, je récupère une collection d’objets Warehouse à partir (vraisemblablement) du service Web de mon client et stocke ces objets dans le champ que j’appelle entrepôts :

IList<Warehouse> warehouses;
protected async override Task OnInitializedAsync()
{
   HttpClient httpClient = new HttpClient();
   HttpResponseMessage httpResponse = await httpClient.GetAsync("…");
   warehouses = await httpResponse.Content.ReadFromJsonAsync<IList<Warehouse>>();
}

Mon objet Warehouse a une propriété Address qui, à son tour, contient un objet Address qui a plusieurs propriétés qui lui sont propres : City, Street et (heureusement pour moi) une propriété LatLong peuplée avec les coordonnées de localisation de la ville de l’entrepôt.

D’autres informations incluent si l’entrepôt accepte les expéditions internationales, la quantité disponible (QoH) et la quantité vendue :

public class Warehouse
{
   public int WarehouseId { get; set; }
   public int ProductId { get; set; }
   public string WarehouseName { get; set; }
   public bool International { get; set; }
   public Address Address { get; set; }
   public int Qoh { get; set; }
   public int Sold { get; set; }
}

public class Address
{     
   public string Street { get; set; }     
   public string City { get; set; }     
   public string Country { get; set; }
   public double[] LatLong { get; set; }
}

Affichage des emplacements

Obtenir des marqueurs sur ma carte pour chaque entrepôt signifie simplement ajouter un MapLayer à ma carte Blazor de type Marker et lier ce MapLayer à mon champ d’entrepôts. Je dois également indiquer au MapLayer où trouver les informations de localisation dans chaque objet.

Pour faire tout cela, il suffit de définir trois attributs sur le MapLayer :

  • Taper: Définissez sur MapLayersType.Marker pour ajouter un MapLayer qui génère des marqueurs
  • Données: Lié à la collecte des données à afficher (dans mon cas, mon champ entrepôts)
  • Champ d’emplacement : Défini sur le nom de la propriété contenant les informations de localisation (dans mon cas, la propriété LatLong dans la propriété Address de chaque entrepôt : Address.LatLong)

Donc, pour afficher les marqueurs de tous les entrepôts de la liste des entrepôts, j’ajoute simplement ce MapLayer après mon premier Tile MapLayer :

    <MapLayer Type="@MapLayersType.Marker"
                  Data="@warehouses"
                  LocationField="Address.LatLong"
                  TitleField="Address.City"
    >
    </MapLayer>
</MapLayers>

Avant de continuer, j’ai fait quelques ajustements : lorsque j’ai appuyé sur F5 pour regarder ma carte, la carte a pris trop de place sur la page et a commencé à zoomer trop loin. Pour résoudre ce problème, j’ai défini les attributs Hauteur, Largeur et Zoom dans l’élément TelerikMap pour obtenir l’affichage souhaité. Il y a eu quelques essais et erreurs avant de choisir ces valeurs :

<TelerikMap Center="@Center"
     	         Height="500px"
        Width="750px"
                       Zoom="4"
>

Avec ces modifications apportées, mon balisage (y compris mes couches de tuiles et de marqueurs) ressemblait à ceci :

<TelerikMap Center="@Center"
     	         Height="500px"
                       Width="750px"
                       Zoom="4"
>
  <MapLayers>
          <MapLayer Type="@MapLayersType.Tile"
	….other attributes…
          >
         </MapLayer>

         <MapLayer Type="@MapLayersType.Marker"
                  Data="@warehouses"
                  LocationField="Address.LatLong"
                  TitleField="Address.City"
         >
        </MapLayer>

   </MapLayers>
</TelerikMap>

Et le résultat ressemblait à ceci :

Une carte du sud-est du Canada et du nord-est des États-Unis avec les deux marqueurs de carte dans l'est des États-Unis (apparemment à environ 300 milles l'un de l'autre) et un autre marqueur plus loin dans le centre du Canada.

À ce stade, ma carte commence à être véritablement utile (mon client pourrait, par exemple, se demander pourquoi il a deux entrepôts si proches l’un de l’autre dans l’est des États-Unis). Ce serait bien sûr encore plus utile si un marqueur affichait des informations lorsque l’utilisateur clique dessus, le nom de la ville, par exemple.

Je peux ajouter cette fonctionnalité en tant qu’info-bulle sur le marqueur en ajoutant un élément Template imbriqué dans l’élément MapLayerMarkerSettings de MapLayer. Je peux traiter ce modèle un peu comme une partie d’une vue : je peux inclure des blocs de code, du HTML et du texte, par exemple, qui seront affichés lorsque l’utilisateur cliquera sur le marqueur.

Dans cet exemple, j’utilise un bloc de code pour récupérer la propriété DataItem du marqueur (dans le modèle, le marqueur actuel est représenté par la pseudo-variable de contexte prédéfinie). La propriété DataItem du marqueur contient l’objet lié au marqueur (dans mon cas, c’est l’un de mes objets Warehouse). Une fois que j’ai récupéré le DataItem (et que je l’ai converti en objet Warehouse), j’affiche la ville de l’entrepôt.

Tout ressemble à ça :

<MapLayer Type="@MapLayersType.Marker"
                     Data="@warehouses"
                     LocationField="Address.LatLong">
            <MapLayerMarkerSettings>
                  <MapLayerMarkerSettingsTooltip>
                    <Template>
                         @{
                                var wh = context.DataItem as Warehouse;
                              }
                          <div>@wh.Address.City</div>
                    </Template>
                </MapLayerMarkerSettingsTooltip>
            </MapLayerMarkerSettings>
</MapLayer>

Désormais, l’utilisateur peut confirmer quel entrepôt il regarde en cliquant simplement sur le marqueur.

La section de la carte qui montre les deux entrepôts dans l'est des États-Unis.  L'utilisateur a cliqué sur l'entrepôt le plus à l'est qui affiche une boîte noire au-dessus du marqueur indiquant Pittsburgh.

Enrichir l’affichage graphique

Mais, même s’il est bon d’afficher du texte pour informer les utilisateurs de l’emplacement des entrepôts, il serait encore mieux d’ajouter des informations clés dans le cadre du graphique. Pour ce faire, j’ajoute un autre MapLayer à ma carte Blazor, cette fois de type Bubble, et je lui demande d’afficher la quantité de marchandises en stock dans chaque entrepôt.

Pour un Bubble MapLayer, je dois définir l’attribut Type de MapLayer sur MapLayersType.Bubble et (comme avec mon marqueur MapLayer) définir LocationField sur la propriété avec les informations de localisation. Mais je dois également définir l’attribut ValueField sur une valeur numérique qui contrôlera la taille de la bulle dessinée à cet endroit.

Dans mon cas, j’ai défini l’attribut ValueField sur la propriété Qoh (Quantity on Hand) de l’entrepôt. De plus, pour que la bulle s’affiche, je dois également utiliser les MapLayerBubbleSettings qui contrôlent l’apparence de mes bulles. Je choisis un bleu clair pour le remplissage de la bulle et un blanc pour le contour de la bulle, donc mon troisième MapLayer ressemble à ceci :

    <MapLayer Type="@MapLayersType.Bubble"
                  Data="@warehouses"
                  LocationField="Address.LatLong"
                  ValueField="Qoh">
            <MapLayerBubbleSettings>
                <MapLayerBubbleSettingsStyle>
                    <MapLayerBubbleSettingsStyleFill Color="cornflowerblue"/>
                    <MapLayerBubbleSettingsStyleStroke Color="white"/>
                </MapLayerBubbleSettingsStyle>
            </MapLayerBubbleSettings
     >
    </MapLayer>
</MapLayers>

Le résultat n’est pas seulement, à mon avis du moins, plutôt beau, il est aussi vraiment utile : en un coup d’œil, un utilisateur peut voir quel est l’inventaire à la fois dans n’importe quel entrepôt et dans tous les entrepôts d’une région (c’est-à-dire, pourquoi ont autant d’inventaire dans l’est des États-Unis et si peu dans le centre du Canada?).

La carte précédente mais chaque marqueur pointe maintenant vers le centre d'un cercle bleu.  Les cercles sont de tailles différentes avec deux grandes bulles proches l'une de l'autre dans l'est des États-Unis et une très petite bulle au milieu du Canada

Contrôler la carte

Bien sûr, aucune interface utilisateur n’est intéressante sans une certaine interactivité. Le Blazor TelerikMap a un événement OnClick qui se déclenche chaque fois qu’un utilisateur clique n’importe où sur la carte.

Je peux lier cet événement à une méthode de mon choix qui accepte un objet MapClickEventArgs. L’objet d’événement MapClickEventArgs a des propriétés Latitude et Longtitude que je vais utiliser pour recentrer la carte.

Mon premier changement consiste à connecter l’événement OnClick de TelerikMap à une méthode que j’appelle Recenter :

<TelerikMap Center="@Center"
                        Height="500px"
                        Width="750px"
                        Zoom="4"
                       OnClick="@AddWarehouse"
>

Ensuite, j’écris la méthode pour mettre à jour le champ Center qui contrôle l’endroit où ma carte est centrée :

void Recenter(MapClickEventArgs args)
{
    Center = new double[] { args.Location.Latitude, args.Location.Longitude };
}

Désormais, lorsque l’utilisateur clique sur la carte, la carte se centre sur la région que l’utilisateur a sélectionnée.

Affichage des données

Le TelerikMap prend également en charge un MarkerClickEvent qui se déclenche lorsque l’utilisateur clique sur un marqueur – cet événement transmet un objet MapMarkerClickEventArgs à la méthode à laquelle l’événement est lié.

Cet objet événement possède également une propriété DataItem qui contient l’objet lié au marqueur. Je pourrais utiliser cet événement pour afficher des informations dans un autre calque lorsque l’utilisateur clique sur un marqueur.

Pour implémenter cela, j’ajouterais d’abord lier l’événement OnMarkerClick sur l’élément TelerikMap à une méthode appelée ShowWarehouse :

<TelerikMap Center="@Center"
                        Height="500px"
                        Width="750px"
                        Zoom="4"
                        OnClick="@Recenter"
                       OnMarkerClick="@ShowWarehouse"
>

Ensuite, j’ajouterais quelques champs à ma zone de code pour contenir des informations clés sur un entrepôt :

@code 
{
    string WarehouseName = string.Empty;
    int Qoh = 0;
    string City = string.Empty;

Enfin, je réécrirais ma méthode ShowWarehouse. Dans cette méthode, je pourrais extraire la propriété DataItem de MapMarkerClickEventArgs (en la transformant en objet Warehouse) et définir mes champs à partir des propriétés de l’objet Warehouse :

void ShowWarehouse(MapMarkerClickEventArgs args)
{
    Warehouse wh = args.DataItem as Warehouse;
    WarehouseName = wh.WarehouseName;
    City = wh.Address.City;
    Qoh = wh.Qoh;
}

Une fois ce travail effectué, je pouvais accéder à ces champs et les utiliser dans l’une des couches de carte ou dans le cadre d’une info-bulle définie dans un élément de modèle.

Nettoyer l’écran

Puisque je m’inquiète de la surcharge d’informations, je dois considérer que la combinaison des marqueurs et des bulles peut être plus d’informations qu’un utilisateur ne le souhaite (ou, alternativement, simplement considérer comme un peu moche). Pour gérer cela, je donnerai à l’utilisateur la possibilité d’activer ou de désactiver des MapLayers individuels.

Pour ce faire, j’ajoute deux cases à cocher en haut de ma page et les lie aux champs que je vais configurer dans un instant :

<p>
    Show Bubbles:
    <TelerikCheckBox @bind-Value="@showBubbles" />
    <br />
    Show Markers:
    <TelerikCheckBox @bind-Value="@showMarkers" />
    <br />
</p>

<TelerikMap Center="@Center" …

J’ajouterai ensuite les champs correspondants à ma candidature :

@code 
{
    bool showBubbles = true;
    bool showMarkers = true;

Enfin, j’envelopperai mes MapLayers à l’intérieur si des blocs qui vérifient l’état de ces deux champs :

        @if (showMarkers)
        {
            <MapLayer Type="@MapLayersType.Marker"
               …
            </MapLayer>
        }

        @if (showBubbles)
        {
            <MapLayer Type="@MapLayersType.Bubble"
            …
            </MapLayer>
        }

Désormais, l’utilisateur peut avoir son choix de couches pour créer un affichage qui a du sens pour lui (bien que s’il désactive les marqueurs, il perdra la possibilité de cliquer sur un marqueur et de voir des informations supplémentaires sur l’entrepôt sélectionné).

Trois affichages de la carte.  Il y a deux cases à cocher en haut de la carte intitulées

Et c’est tout! À ce stade, j’ai non seulement quelque chose qui vaut la peine d’être montré à un ami, mais quelque chose de potentiellement utile pour mon client (en plus, c’est même personnalisable). C’est pas mal.

Essayez l’interface utilisateur Telerik pour Blazor

Développez de nouvelles applications Blazor et modernisez les projets Web hérités en deux fois moins de temps grâce à une grille hautes performances et à plus de 100 composants Blazor véritablement natifs et faciles à personnaliser pour répondre à toutes les exigences. Essayez-le gratuitement avec notre essai de 30 jours et profitez de notre assistance de pointe.

Essayez maintenant




Source link

janvier 12, 2023