GithubHelp home page GithubHelp logo

fis-sst / blazormaps Goto Github PK

View Code? Open in Web Editor NEW
68.0 68.0 25.0 418 KB

BlazorMaps is a Blazor library that provides a C# interface for maps provided by Leaflet.js library. It includes several Leaflet.js features which are easily accessible from C# level within a project and it does not require any use of JavaScript.

Home Page: https://fis-sst.pl/en

License: MIT License

HTML 17.06% C# 78.28% CSS 4.00% JavaScript 0.66%
blazor leaflet-map leafletjs library map netcore wrapper

blazormaps's People

Contributors

dariuszbrysz avatar irumba avatar mchilicki avatar stisss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blazormaps's Issues

Really slow performance when lot of markers

Is your feature request related to a problem? Please describe.
When I try to add 10000 markers on the Tests page, it takes 30 seconds

Describe the solution you'd like
That it takes a few seconds

Describe alternatives you've considered
Perhaps use a canvas to draw the markers

Additional context

Add Drag, dragstart and dragend events

Is your feature request related to a problem? Please describe.
Would like to request adding Drag, Dragstart and Dragend events to the markers.

Describe the solution you'd like
I am replacing an angular application that used those events to draw lines and capture the latlng when dragging.

NullReferenceException while assign events in OnAfterRenderAsync()

Describe the bug
If I assign an event in OnAfterRenderAsync() a NullReferenceException is given.

To Reproduce
my .razor file:

@page "/"

<Map @ref="mapRef" MapOptions="@mapOptions"></Map>

<style>
  #mapId {
    height: 400px;
  }
</style>

my .cs file:

using System.Diagnostics;
using FisSst.BlazorMaps;

namespace TestMap.Pages
{
  public sealed partial class Index
  {
    private Map? mapRef;

    private readonly MapOptions mapOptions = new()
    {
      DivId = "mapId",
      Center = new LatLng(50.0, 18.0),
      Zoom = 13,
      UrlTileLayer = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
      SubOptions = new MapSubOptions()
      {
        Attribution = "&copy; <a lhref='http://www.openstreetmap.org/copyright'>OpenStreetMap</a>",
        TileSize = 512,
        ZoomOffset = -1,
        MaxZoom = 19,
      }
    };

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
      if (firstRender)
      {
        // this is a workaround to ensure other OnAfterRenderAsync are called first so
        // the following call can be called without errors: await mapRef.OnMouseDown(MapMouseDown);
        for (int i = 0; i < 20; i++)
        {
          //await Task.Delay(1);
        }

        if (mapRef != null)
        {
            await mapRef.OnClick(MapMouseDown);
        }
      }
    }
    
    private async Task MapMouseDown(MouseEvent e)
    {
      Debug.WriteLine("MapMouseDown");
    }
  }
}

Expected behavior
I want to be able to assign events in OnAfterRenderAsync() without workarounds like the await Task.Delay(1);

Screenshots
image

Add preventDefault to map and marker events

Is your feature request related to a problem? Please describe.
I am looking for a way to add or use preventDefault on Map and Marker events such as click, double click, contextmenu.

Describe the solution you'd like

I have a contextmenut in an angular app that uses preventDefault as shown in the last line. I am not sure how this can be done
in for markers and Maps in Blazor

this.map.on('contextmenu', function (e: any) {
const originalEvent = e.originalEvent as MouseEvent;
originalEvent.preventDefault();
}

this.marker.addEventListener('dblclick', function (e: any) {
const evt = e.originalEvent as MouseEvent;
evt.preventDefault();
}

Zoom event

Is your feature request related to a problem? Please describe.
I am looking for a way to use zoom event.

Describe the solution you'd like
If I zoom in or out, then I want to handle my own additional funtionality.

Describe alternatives you've considered
Currently I check the zoom level each second in a timer event. If the zoom level is changed, then I perform the additional functionality I want. However besides it can be seen as pretty ugly, it rarely appears that mapRef.GetZoom() takes relativaly long to execute.

Additional context
I want the same for zoom event like the mouse events which are currenly implemented.

Mapbox layer support

Describe the bug
A clear and concise description of what the bug is.

I was trying to use mapbox with an accesstoken instead of openstreetmaps and receive black tiles.

I am not sure if Mapbox is supported.

Here is an example:

private MapOptions mapOptions = new MapOptions()
{
DivId = "mapId",
Center = new LatLng(33.4272861, -111.8975),
Zoom = 13,
UrlTileLayer = "https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}",
SubOptions = new MapSubOptions()
{
TileSize = 256,
Id = "satellite-streets-v11",
AccessToken = "insert the real key here"
ZoomOffset = -1,
MaxZoom = 19,
}
};

Update I was able to get the maps to work by removing the zoomoffset

No external JS/CSS references

Your readme/example has the JS/CSS linked from an external CDN. I'd rather keep everything in the package and have it referenced locally. Is that possible at present?

.NET 8 support

Works well with .NET 6, but not with .NET 8.
Please implement support, this is a very good map component.

Parameter in Marker.SetOpacity

Refers to nuget version: 1.0.1
The parameter for Marker.SetOpacity is an int, but should be IMHO a double accepting values from 0 to 1.

Click event on map marker

I have the following code for resolving a map marker back to a location (where I got the lat longs from originally.)

    private async Task HandleMapMouseEvent(MouseEvent mouseEvent)
    {
        var lat = Math.Round(mouseEvent.LatLng.Lat, 1);
        var lng = Math.Round(mouseEvent.LatLng.Lng, 1);
        var newLocation = Locations.Single(x => Math.Round(x.Coordinates.Latitude, 1) == lat && Math.Round(x.Coordinates.Longitude, 1) == lng);
        await SelectedLocationChanged(newLocation.Id);
    }

This works but it seems like a strange way to do it. Why not pass an ID to the map marker when I'm creating it, and then find via the ID, rather than deal with rounding issues with lat long?

There doesn't appear to be a way to do that. Am I missing something?

Add IsInitialized method to Map Component

Is your feature request related to a problem? Please describe.
I get problems initializing the map component with objects on start up, because it is not yet initialized and I get null reference exceptions.

Describe the solution you'd like
I cloned the repo and added a IsInitialized() method to the Map Component:

MapComponent

public async Task<bool> IsInitialized()
{
    while(this.MapReference == null || this.MapEvented == null)
    {
        await Task.Delay(100);
    }
    return this.MapReference != null && this.MapEvented != null;
}

with this one I can wait for the map component to be initialized before adding my own objects:

ParentComponent

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    await Task.Run(async () =>
    {
        while (this.mapRef == null)
        {
            await Task.Delay(100);
        }
    });
    if (await this.mapRef.IsInitialized())
    {
        var marker1 =
            await this.MarkerFactory.CreateAndAddToMap(
                new LatLng(0, 0),
                this.mapRef
            );
    }
}

Would be really nice to see something like this in the next release. Keep up the good work!

Parent component don't know about Map rendering

In my page I can't subscribe Map events, because

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
      if (!firstRender)
        return;
      this.MapReference = await this.MapJsInterop.Initialize(this.MapOptions);
      this.MapEvented = new MapEvented(this.MapReference, this.EventedJsInterop);
    }

So, property MapEvented declared in OnAfterRenderAsync, but in parent component I don't know when it happened.
Parent's OnAfterRenderAsync not promise that children had rendered. dotnet/aspnetcore#13781

When I subscribe on click event I get exception NRE, because method OnClick uses property MapEvented, that is null on time when my page rendered.

I think, that Map component must rise event "load" to know when it rendered.

.NET 6.0 support

The example project can run well in .NET 5. But once i set the framework to .NET 6.0 the page stuck at "loading" and doesn't show any map

Exception adding Marker

Describe the bug
I've created a map panel based on your readme, and am adding a marker, but I get this exception:

[23:18:32.700-.NET ThreadPool Worker-WRN] Unhandled exception rendering component: Cannot read properties of null (reading 'addLayer')
TypeError: Cannot read properties of null (reading 'addLayer')
    at i.addTo (https://unpkg.com/[email protected]/dist/leaflet.js:5:63275)
    at http://localhost:6363/_framework/blazor.server.js:1:3501
    at new Promise (<anonymous>)
    at Tt.beginInvokeJSFromDotNet (http://localhost:6363/_framework/blazor.server.js:1:3475)
    at http://localhost:6363/_framework/blazor.server.js:1:71783
    at Array.forEach (<anonymous>)
    at Tt._invokeClientMethod (http://localhost:6363/_framework/blazor.server.js:1:71769)
    at Tt._processIncomingData (http://localhost:6363/_framework/blazor.server.js:1:69811)
    at bt.Tt.connection.onreceive (http://localhost:6363/_framework/blazor.server.js:1:64211)
    at WebSocket.o.onmessage (http://localhost:6363/_framework/blazor.server.js:1:48527)

My code is:

    private Map mapRef;
    private LatLng firstMarkerLatLng;
    private Marker marker1;
   
   protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if( firstRender )
        {
            await AddMarkers();
        }
    }

    private async Task AddMarkers()
    {
        firstMarkerLatLng = new LatLng(51.506130, -0.090270);
        marker1 = await MarkerFactory.CreateAndAddToMap(firstMarkerLatLng, mapRef);
    }

If I don't call AddMarkers the map renders fine.

Any ideas? Did I miss something?

Marker.SetIcon crashes

Describe the bug
Calling Marker.SetIcon to change the Icon crashes at the Javascript level.

To Reproduce

  1. Create a Marker and add it to the map
  2. Call SetIcon to update its Icon
  3. Exception in Javascript

Error

fail: WasmComponents.Map[0]
      Error occurred executing task work item.
Microsoft.JSInterop.JSException: t.icon.createIcon is not a function
TypeError: t.icon.createIcon is not a function
    at i._initIcon (https://unpkg.com/[email protected]/dist/leaflet.js:5:72551)
    at i.setIcon (https://unpkg.com/[email protected]/dist/leaflet.js:5:72179)
    at https://localhost:5001/_framework/blazor.webassembly.js:1:3332
    at new Promise (<anonymous>)
    at Object.beginInvokeJSFromDotNet (https://localhost:5001/_framework/blazor.webassembly.js:1:3306)
    at Object.St [as invokeJSFromDotNet] (https://localhost:5001/_framework/blazor.webassembly.js:1:59853)
    at _mono_wasm_invoke_js_blazor (https://localhost:5001/_framework/dotnet.6.0.6.z9b9uq0m6e.js:1:195300)
    at wasm://wasm/00971e46:wasm-function[219]:0x1a490
    at wasm://wasm/00971e46:wasm-function[167]:0xce5e
    at wasm://wasm/00971e46:wasm-function[166]:0xbd71
   at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[Microsoft.JSInterop.IJSObjectReference, Microsoft.JSInterop, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
   at FisSst.BlazorMaps.Marker.SetIcon(Icon icon) in A:\Test\BlazorMaps\FisSst.BlazorMaps\FisSst.BlazorMaps\Models\Markers\Marker.cs:line 47
   at WasmComponents.Map.UpdateIcon(Icon icon) in A:\Test\WasmComponents\Map.razor.cs:line 266

Additional context
It seems the Icon isn't properly passed from C# to Javascript: in i._initIcon the t object is just empty, meaning t.icon is null leading to t.icon.createIcon is not a function.

Add getBounds, fitBounds and Rectangle

Is your feature request related to a problem? Please describe.
Not a problem, but an improvement
getBounds, fitbounds and Rectangle are existing features in Leaflet,
getBounds is used to get a rectangular area occupied by Circle, Rectangle, Polygon, Polylines, etc.
fitBounds is used to Zoom an specific area, usually enclosed by getBounds result.
getBounds is a existing feature in Leaflet, it can be used to get rectangular area used by any

Describe the solution you'd like
getBounds: we can get southwest and northeast coordinates of any Circle, Rectangle, Polygon or Polyline.
fitBounds: we can Zoom in to an area collected by getBounds.
Rectangle: we don´t need to use Polyline and can forget about calcular coordinates of each corner, Leaflet already does it

Describe alternatives you've considered
None, I want to draw an object and Zoom In like a Zoom Window or Contents

Additional Info
Leaflet getBounds returns a modified object of type LatLngBound it is like (sorry code did not showing formatted):
{"_southWest":{"lat":-23.601783040147975,"lng":-46.537071217637845}, "_northEast":{"lat":-23.556816959852032,"lng":-46.48800878236214}}"
Leaflet fitBounds expects a LatLngBound(corner1, corner2) or an Array like [ [lat,lng], [lat,lng] ]

Here a new class to hold getBound result with a method to be used with fitBounds:
using System.Collections.Generic; namespace FisSst.BlazorMaps { public class LatLngBounds { public LatLngBounds() {} public LatLngBounds(LatLng southwest, LatLng northeast) { _southWest = southwest; _northEast = northeast; } public LatLng _southWest { get; set; } public LatLng _northEast { get; set; } // Return a IEnumerable of LatLng, to be used with fitBounds or Rectangle public IEnumerable<LatLng> ToLatLng() { return new List<LatLng>() { _southWest, _northEast }; } } }

On Models CircleMaker, Polygon, Polyline and Rectangle I had to add one constant for "getBounds"
private const string GetBoundsJsFunction = "getBounds";
and also a new Task
public async Task<LatLngBounds> GetBounds() { // Leaflet getBounds() function returns // {"_southWest":{"lat":-23.601783040147975,"lng":-46.537071217637845}, "_northEast":{"lat":-23.556816959852032,"lng":-46.48800878236214}}" // Class LatLngBounds represents object retuned by getBounds() return await this.JsReference.InvokeAsync<LatLngBounds>(GetBoundsJsFunction); }

On Components Map, I had to add one constant for "fitBounds"
private const string fitBounds = "fitBounds";
and also a new Task, note IEnumerable came from LatLngBounds.ToLatLng method if using like
myMap.FitBonds(myCircle.getBounds())
public async Task FitBounds(IEnumerable<LatLng> coords) { await this.MapReference.InvokeAsync<IJSObjectReference>(fitBounds, coords); }

Rectangle, just create a Rectangle folder in Models & Factory and duplicate Polyline files with proper name changes from Polyline to Rectangle including constant string "L.polyline" by "L.rectangle"
And finally include rectangle at FisSstMapsDependencyInjection
services.AddTransient<IRectangleFactory, RectangleFactory>(); // Added to allow use L.rectangle

Hope you undertand all above, and sorry in advance, I´m not too familiar with Github way on post like this

How to add options to popups?

Is your feature request related to a problem? Please describe.
I am unable to keep popups open and to have more than one at a time.

Describe the solution you'd like
I would like popups to appear when map loads and also I would like them to dissapear only if I click on the close cross icon at the right top corner of the popup

Describe alternatives you've considered
Leaflet has options for this, I think just adding being able to create the popupOptions object would be enought

Is there any way to do this with what you have already uploaded?
Thank you

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.