Xamarin.forms: [Enhancement] Map with shapes from pin

Created on 26 Jan 2018  Â·  20Comments  Â·  Source: xamarin/Xamarin.Forms

Rationale

UX could reasonably want to overly shapes onto maps. For example, a semi-transparent circle centered on a pin.

Implementation

Could make it complicated and general or could just make it this:

public class Pin {
    public static readonly BindableProperty CircleColor; // color
    public static readonly BindableProperty CircleSize; // double
}

Expected Result

A circular map overlay centered at the pin.

Implications for CSS

None.

Backward Compatibility

None.

Difficulty : Easy

F100 community-sprint help wanted inactive enhancement âž• up-for-grabs

All 20 comments

I'm willing to take a look at this issue. Would like some others input on what units to use to define the size of the circle. Do we want to just do a simple circle or allow more complex items like polygons or lines based on OpenGIS Well Know Binary/Text, etc?

@bmacombe once the spec is "Ready for Implementation" I can make the assignment.

I agree, a circle is too limited. Could this take any view instead?

I'm looking at examples of other maps and we should be able to handle any manner of view that handles its own color, border, opacity, shape, and even animation.

I think we need some example use cases to guide this. @dotMorten perhaps you have some insight?

Using a view would be interesting, haven't thought of that angle. I come from a more GIS centric background, so point, lines, polygons described via spatial coordinates is my normal thinking but I could see just sticking a view on a pin as more useful for many apps.

I'm happy to take a look once the spec is ready or glad to let someone else work on it also.

I'd be happy to give some insights but I feel like some of the requirements here are missing. Is the circle supposed to show how far something is from the pin? Ie a 1mile radius?
If so I don't really get how a polygon relates to a pin? Where should the pin be (centered doesn't mean the pin is inside).

My suggestion is to add a bindable property to the Map class to be able to customize the pin appearance:

public class Map
{
       public DataTemplate PinTemplate { get; set; }
       public DataTemplateSelector PinTemplateSelector { get; set; }
}

By default it's null, and the Map uses the current pin today.
Furthermore, the PinTemplateSelector property will allow appearance customization by each Pin object.

I find that terrible limited. I want pins to look different.
TBH I'd rather I could add a set of polygons, polylines and points. Each can have their own styling. It'll give the most flexibility for a bunch of scenarios, and if I want to add a pin with a circle around it, I'll just add one point and one circular polyline. I get the convenience of just having it in one simple pin-class but it's also very limiting and not considering other scenarios.

It's also not clear how the PinTemplate would create a circle of a certain metric radius?

@dotMorten That is similar to what I was thinking. I've used ArcEngine and ThinkGeo's mapsuite package for many years. I was thinking something like a layer, with geometry features defined in WKB with attributes and styles.

What I wonder is many if the apps implemented in Forms are not doing the complicated GIS, but just need to quickly show locations on a map. Business locations, delivery radius, etc.

It might be that both would best, I would like the fuller GIS features myself...enough that I've already implemented it on UWP, iOS and Android. But I did it early in my time with XF and I don't think the API or code quality is good enough to contribute it directly.

If having the more complicated GIS features is something that will be of interest, I would be glad to propose an API based on my current work for further iteration.

@bmacombe I guess you could also argue that this would be taking it too far for a simple map control, and might be hard to make work well cross-platform with the native map controls under them. The better approach might be to just support pins, as this is the most common scenario.
If you then need to do more advanced GIS scenarios, perhaps this isn't the control for you, and you could use something like the <ShamelessPlug>ArcGIS Runtime for Xamarin Forms</ShamelessPlug>.

@dotMorten Thanks for the Shameless Plug! I didn't know that existed!

While not reaching the level of complexity and features available from ESRI, it actually is fairly easy to draw simple geometry (points, lines and polygons) on the native map controls. It could still be a useful feature for simple mapping needs.

Just some examples below on the basic conversion from an NTS Polygon to a platform polygon for thought. I left Android out for now...because it's a mess!

iOS
`public static CLLocationCoordinate2D ToClLocationCoordinate2D(this Coordinate coord) =>
new CLLocationCoordinate2D(coord.Y, coord.X);

    public static MKCoordinateRegion ToMkCoordinateRegion(this Envelope envelope)
    {
        var span = new MKCoordinateSpan(envelope.Height, envelope.Width);
        var center = envelope.Centre.ToClLocationCoordinate2D();
        return new MKCoordinateRegion(center, span);
    }

    public static MKPolygon ToMKPolygon(this IPolygon ntsPoly)
    {
        //Create the hole polygons
        var holes = ntsPoly.Holes.Select(h => MKPolygon.FromCoordinates(ToClLocationCoordinate2Ds(h))).ToArray();

        //Create the ring polygon
        return MKPolygon.FromCoordinates(ntsPoly.Shell.ToClLocationCoordinate2Ds(), holes);
    }

    public static CLLocationCoordinate2D[] ToClLocationCoordinate2Ds(this ILineString linestring)
    {
        return linestring.Coordinates.Select(c => c.ToClLocationCoordinate2D()).ToArray();
    }

`

uwp
` public static Geopoint ToGeopoint(this Coordinate c) =>
new Geopoint(c.ToBasicGeoposition());

    public static BasicGeoposition ToBasicGeoposition(this Coordinate c) =>
        new BasicGeoposition() { Latitude = c.Y, Longitude = c.X, Altitude = c.Z };

    public static Geopath ToGeopath(this ILineString lineString) =>
        new Geopath(lineString.Coordinates.Select(c => c.ToBasicGeoposition()));

    public static GeoboundingBox ToGeoboundingBox(this Envelope envelope)
    {
        return new GeoboundingBox(new BasicGeoposition() { Latitude = envelope.MaxY, Longitude = envelope.MinX },
            new BasicGeoposition() { Latitude = envelope.MinY, Longitude = envelope.MaxX });
    }

    public static MapPolygon ToMapPolygon(this IPolygon polygon)
    {
        var newPoly = new MapPolygon();
        newPoly.Paths.Add(polygon.Shell.ToGeopath());
        foreach( var geopath in polygon.Holes.Select(p => p.ToGeopath()) )
            newPoly.Paths.Add(geopath);
        return newPoly;
    }`

Would anyone on this thread care to officially take on this enhancement and submit a pull request for it? Thanks!

I could probably take a look at it, but I'm fairly busy at the moment. Not sure how quickly I would get it done.

Is there any decision on if to just do the simple color and radius around a pin or something else?

@bmacombe I think the better and more flexible option is to allow people to draw a polygon and/or polyline, and not focus so much on a radius circle. You could use the polygon approach to create that circle.

@dotMorten To be clear are you thinking let them draw a polygon in screen coordinates and just draw that or in map coordinates?

Edit: Or I should say in screen units or map units, didn't mean coordinates

Map coordinates. Screen units makes no sense in this context.

The ticket needs a spec clearly defined. Also, the title should be changed to reflect the need to display shapes on the map as described in the Rationale section.

Here's my take:

New members in the Map class:

public class Map
{
   public event EventHandler<MapElement> MapElementClicked;
   public IList<MapElement> MapElements { get; }
}

The MapElements property allows setting the map elements in XAML or by code:

<Map>
   <Map.MapElements>
      <MapCircle />
      <MapPolyline />
      <MapPolygon />
   <Map.MapElements>
<Map>
Map map = ...;
map.MapElements.Add(new MapCircle());
map.MapElements.Add(new MapPolyline());
map.MapElements.Add(new MapPolygon());



md5-de407d8cff4505c6fa0497451649de27



// Base class for map elements, more common properties can go here
public class MapElement : BindableObject
{
   public bool IsVisible { get; set; }
}

public class MapCircle : MapElement
{
   public Color FillColor { get; set; }
   public bool Position Center { get; set; }
   public Distance Radius { get; set; }
   public Color StrokeColor { get; set; }
   public double StrokeThickness { get; set; }
}

public class MapPolyline: MapElement
{
   public Geopath Path { get; set; }
   public Color StrokeColor { get; set; }
   public double StrokeThickness { get; set; }
}

public class MapPolygon : MapElement
{
   public Color FillColor { get; set; }
   public IList<Geopath> Holes { get; set; }
   public Geopath Outline { get; set; }
   public Color StrokeColor { get; set; }
   public double StrokeThickness { get; set; }
}

public class Geopath : BindableObject
{
   public IEnumerable<Position> Positions { get; set; }
}

Once the spec is approved I could try take a stab at it.

@andreinitescu I'm not sure you need both Polyline and Polygon, shapes can be filled or not by FillColor = Color.Transparent and the Geopath can be set to AutoClose or not to differentiate a path and an enclosure.
I also think perhaps there is a use case for including a MapRectangle where you set the Top, Left, Bottom and Right and it generates the appropriate Geopath for you, although maybe that is easy enough to implement using a bound model rather than an actual viewable element.

@CZEMacLeod usually transparent background means it's still clickable. Someone might want some lines drawn but without having the interior clickable.

@andreinitescu I think that argument can be made against the MapCircle - I can think of many instances where you want the circle itself to be clickable, but the interior not, such that you can click places or other locations, pins etc. inside. (e.g. Restaurants within X miles of your current location)

I think it's better to have polyline and polygon separate, all platforms have it like this.

Was this page helpful?
0 / 5 - 0 ratings