I need to add a bunch of pins on a MapsUI map control that uses OpenStreetMap tiles.
The problem is I cant find anything mentioning pins in their documentation so my question is:
Are there any pins available but have different names or i have to draw pins myself (using Geometry and Points as in some examples i found) and if so how do i keep them the same size when zooming the map ?
Maybe someone can point out where should i look in their documentation in case I'm blind and missed it.
Thanks!
Your Mapsui Map View Mapsui.UI.Forms.MapView has property Pins. You can add pins there.
You can access MapView View from code-behind *xaml.cs of your MapView.
For that, first, name your Map View in XAML Page:
<ContentPage
xmlns:mapsui="clr-namespace:Mapsui.UI.Forms;assembly=Mapsui.UI.Forms"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourProject.Pages.YourMap">
<ContentPage.Content>
<mapsui:MapView
x:Name="selectMapControl"/>
</ContentPage.Content>
</ContentPage>
Then access it from C# code-behind of that Page:
using Mapsui.UI.Forms;
protected override async void OnAppearing()
{
selectMapControl.Pins.Add(new Pin(new MapView())
{
Position = new Position(0, 0),
Type = PinType.Pin,
Label = "Zero point",
Address = "Zero point",
});
}
Hope this simplest example will help.
The idea is that you use your own bitmaps to draw as 'pins'.
Mapsui has features. A feature has a geometry which can be a point, linestring and polygon (and some others). A feature is drawn with some kind of style. What you need to do is create features with point geometry and use a symbolstyle with a bitmap as symbol. You need to register your bitmap and use the bitmapId in the symbol. See the sample here:
https://github.com/Mapsui/Mapsui/blob/master/Samples/Mapsui.Samples.Common/Maps/PointsSample.cs
You can use Xamarin.Forms.GoogleMaps as they give you the feature to add multiple pins of your choice.
Here is the sample code :
var position = new Position(Latitude, Longitude);
var pin = new Pin
{
Type = PinType.Place,
Position = position,
Icon = BitmapDescriptorFactory.FromBundle("pin.png"),
Label = "custom pin",
Address = "custom detail info",
};
MyMap.Pins.Add(pin);
The following works on version 3.02. I've not checked it on any other version of MapSui.
First make sure your pin Bitmap is an embedded resource. You can then get the Bitmap ID like this:
var assembly = typeof(YourClass).GetTypeInfo().Assembly;
var image = assembly.GetManifestResourceStream("YourSolution.YourProject.AFolder.image.png");
If var image returns null, then the image was not found and it's likely not an embedded resource or you got the address/name wrong.
var ID = BitmapRegistry.Instance.Register(image);
The BitmapRegistry method also registers the BitMap for MapSui to use later. I think if it's your first image registered it will be 0.
Then you can create a memory layer as follows:
MemoryLayer PointLayer = new MemoryLayer
{
Name = "Points",
IsMapInfoLayer=true,
DataSource = new MemoryProvider(GetListOfPoints()),
Style = new SymbolStyle { BitmapId = ID, SymbolScale = 0.50, SymbolOffset = new Offset(0, bitmapHeight * 0.5) };
};
The DataSource can be generated as follows (I'm just adding one feature, but you can add as many as you like):
private IEnumerable<IFeature> GetListOfPoints()
{
List<IFeature> list = new List<IFeature>();
var feature = new Feature();
feature.Geometry = new Point(-226787, 7155483);
feature["name"] = "MyPoint";
list.Add(feature);
IEnumerable<IFeature> points = list as IEnumerable<IFeature>;
return points;
}
Then add the new MemoryLayer to your Map as follows:
MapControl.Map?.Layers.Add(PointLayer);
Related
I have the issue with MapsUI 2.0.3 that the marker of my own location is always at 0,0 west of Africa. Clicking the focus on own location button obviously also moves me there.
I did add coarse and fine location permissions to manifest and do get permission to access locations, but "you are here" is always 0,0.
I then downloaded the MapsUI repository, and tried the samples, which show the same behavior, mostly. When the map loads, it shows position at 0,0. If I drag the map slightly, the marker slowly moves to my correct position. If I (in the samples) reload the same sample or another one, the marker remains stuck at 0,0, even when I drag the map. In summary, I can "fix" the 0,0 marker by interacting with the map but only once.
My device does have gps location enabled, and other location using apps work fine. This including other home made Xamarin forms apps, so this is an issue for MapsUI only.
It failing for both samples and own code makes this a bit confusing.
Does this ring a bell for anyone? Seems a bit strange to say the least.
Note that this also fails on the xamagin/android device emulator with a set position. Just mentioning this as a "fun" extra detail, map longpress event will never fire on my device, but does work on the emulator. I saw someone else, a long time back, complaining about that same issue, and a developer commenting on it being fixed in 2.0, while I see it in 2.3. All in all MapsUI seems like an extremely rich system that I would love to use, but which has weird little bugs and poor support.
The xaml for adding the mapview
<StackLayout>
<mapsui:MapView x:Name="mapView" IsMyLocationButtonVisible="True" />
</StackLayout>
And the c# setup
void start()
{
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
if(status==PermissionStatus.Denied) return;
var map = new Mapsui.Map
{
Transformation = new MinimalTransformation(),CRS = "EPSG:3857"};
var tileSource = new HttpTileSource(new GlobalSphericalMercator(),
"https://tile.thunderforest.com/landscape/{z}/{x}/{y}.png?
apikey=xxxxxxxxx",new[] { "a", "b", "c" }, name: "OpenStreetMap");
var tileLayer = new TileLayer(tileSource) { Name = "Carto Light" };
map.Layers.Add(tileLayer);
mapView.Map = map;
}
Although not knowing why MyLocationButton not works, but there is a workaround to make the current location to show in MapsUI.
There is a UpdateMyLocation method inside MyLocationLayer,then we can use this method to show the current location programmatically.
In addition, you could use Geolocation to get the current location.
Code as follows:
protected override async void OnAppearing()
{
base.OnAppearing();
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
mapView.MyLocationLayer.UpdateMyLocation(new Position(location.Latitude, location.Longitude), true);
}
The effect:
I'm developing an application that retrieves an image of "Bing Maps" with [Bing Api] since my webService.
My problem is the rendering of the image.
If I set my zoom greater than 11,or if I set a size too big, the result of recover my image is like "cut" into several loading and gives the impression that the image is not entirely downloaded.
Example picture below...
Have you any idea why the image looks like its back?
Here is my code used in my webService.
//call function
GetImageMap(46,6,800,800,17);
//Get Bing map Image from the web
public string GetImageMap(double latitude,double longitude,int mapSizeHeight, int mapSizeWidth, int zoomLevel)
{
string key = "asoidfz9aos78fa9w3hf9w3fh9hf7ha9wfw37fhblablablablablabla";
MapUriRequest mapUriRequest = new MapUriRequest();
// Set credentials using a valid Bing Maps key
mapUriRequest.Credentials = new ImageryService.Credentials();
mapUriRequest.Credentials.ApplicationId = key;
// Set the location of the requested image
mapUriRequest.Center = new ImageryService.Location();
mapUriRequest.Center.Latitude = latitude;
mapUriRequest.Center.Longitude = longitude;
// Set the map style and zoom level
MapUriOptions mapUriOptions = new MapUriOptions();
mapUriOptions.Style = MapStyle.Aerial;
mapUriOptions.ZoomLevel = zoomLevel;
mapUriOptions.PreventIconCollision = true;
// Set the size of the requested image in pixels
mapUriOptions.ImageSize = new ImageryService.SizeOfint();
mapUriOptions.ImageSize.Height = mapSizeHeight;
mapUriOptions.ImageSize.Width = mapSizeWidth;
mapUriRequest.Options = mapUriOptions;
//Make the request and return the URI
ImageryServiceClient imageryService = new ImageryServiceClient();
MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);
return mapUriResponse.Uri;
}
// ### END Function getImageMap
And the url query:
http://api.tiles.virtualearth.net/api/GetMap.ashx?c=46,6&dcl=1&w=800&h=800&b=a,mkt.en-US&z=17&token={token}
Result image.. :
It seems to be related to the aerial imagery and it's not technically related.
I will report it to the appropriate team.
By the way, you should use the REST Imagery API which is the official way to use the imagery from Bing, see the MSDN:
http://msdn.microsoft.com/en-us/library/ff701724.aspx
Here is a sample URL based on your example:
http://dev.virtualearth.net/REST/v1/Imagery/Map/Aerial/46,6/17?mapSize=800,800&key=YOURKEY
I would have an openlayers vector layer with features scattered all over the map. I want to be able to click on a feature and have a message display.
I'm not sure if there is a way to add a listener/handler to each feature.
Any ideas?
Add SelectFeture control:
var selectFeature = new OpenLayers.Control.SelectFeature(vector_layer);
map.addControl(selectFeature);
selectFeature.activate();
After that you can listen to select/unselect events on vector layer:
vector_layer.events.on({
'featureselected': function(feature) {
//display your message here
},
'featureunselected': function(feature) {
//hide message
}
});
You need to use a combination of the SelectFeature control and one of the OpenLayers.Popup classes such as OpenLayers.Popup.FramedCloud. Here is an example of just that:
http://openlayers.org/dev/examples/select-feature-openpopup.html
In that example, try using the "draw polygon" option to draw a polygon (double-click on the map to complete the polygon). Then use "select polygon on click" and click on the polygon, and you will get a framed cloud popup.
You can view the source for the page to see how it this is done. Here are the relevant parts of the code. You can, of course, change the message to whatever you want to display in the framed cloud:
var map = <your OpenLayers.Map object>;
var polygonLayer = <your vector layer>;
selectControl = new OpenLayers.Control.SelectFeature(polygonLayer,
{onSelect: onFeatureSelect, onUnselect: onFeatureUnselect});
map.addControl(selectControl); // not in the example, but do this
function onPopupClose(evt) {
selectControl.unselect(selectedFeature);
}
function onFeatureSelect(feature) {
var message = "<div style='font-size:.8em'>Feature: " + feature.id +"<br>Area: " + feature.geometry.getArea()+"</div>";
selectedFeature = feature;
popup = new OpenLayers.Popup.FramedCloud("chicken",
feature.geometry.getBounds().getCenterLonLat(),
null,
message,
null, true, onPopupClose);
feature.popup = popup;
map.addPopup(popup);
}
function onFeatureUnselect(feature) {
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
Here are the references for the controls you will be using:
http://dev.openlayers.org/apidocs/files/OpenLayers/Control/SelectFeature-js.html
http://dev.openlayers.org/apidocs/files/OpenLayers/Popup/FramedCloud-js.html
If there are many vector layers is it necessary to write "layer_name.events.on ..." for each layer? Is it possible to make a list of layers and assign ".events.on" to all of them?
Hey folks, i ve got this issue implementing the Factory method.
Following is the snippet of the the main chart class which calls ChartFactory's method to attain the proper object. I Type Cast chartobject so as to be able to call the Show method;i m apprehensive about that as well.
container = new VBox();
container.percentWidth = 100;
container.percentHeight = 100;
super.media.addChild(container);
chartObject = new ChartBase();
chartObject = ChartFactory.CreateChartObject(chartType);
IChart(chartObject).Show(o);
container.addChild(chartObject);
legend = new Legend();
legend.dataProvider = IChart(chartObject);
container.addChild(legend);
Following is the snippet of ChartFactory's method:
public static function CreateChartObject(subType:String):ChartBase
{
switch(subType)
{
case ChartFactory.AREA_CHART:
return new AreaCharts();
break;
case ChartFactory.COLUMN_CHART:
return new ColumnCharts();
break;
case ChartFactory.PIE_CHART:
return new PieCharts();
break;
default:
throw new ArgumentError(subType + ": Chart type is not recognized.");
}
}
And following is Show method of one of the several Charts type classes: AreaCharts, PieCharts etc. All of which implements IChart Interface.
public function Show(o:ObjectProxy):void
{
var grids:GridLines;
var stroke:SolidColorStroke;
var horizontalAxis:CategoryAxis;
var verticalAxis:LinearAxis;
var horizontalAxisRenderer:AxisRenderer;
var verticalAxisRenderer:AxisRenderer;
grids = new GridLines();
if(WidgetStylesheet.instance.LineChart_ShowGrid)
grids.setStyle("gridDirection", "both");
else
grids.setStyle("gridDirection", "");
stroke = new SolidColorStroke(WidgetStylesheet.instance.LineChart_GridLineColor, WidgetStylesheet.instance.LineChart_GridLineThickness);
grids.setStyle("horizontalStroke", stroke);
grids.setStyle("verticalStroke", stroke);
horizontalAxis = new CategoryAxis();
horizontalAxis.categoryField = o.LargeUrl.Chart.xField;
horizontalAxis.title = o.LargeUrl.Chart.xAxisTitle.toString();
verticalAxis = new LinearAxis();
verticalAxis.title = o.LargeUrl.Chart.yAxisTitle.toString();
horizontalAxisRenderer = new AxisRenderer();
horizontalAxisRenderer.axis = horizontalAxis;
horizontalAxisRenderer.setStyle("tickLength", 0);
horizontalAxisRenderer.setStyle("showLine", false);
horizontalAxisRenderer.setStyle("showLabels", true);
horizontalAxisRenderer.setStyle("fontSize", WidgetStylesheet.instance.ComputeChartAxisFontSize(o.HeadlineFontSize));
verticalAxisRenderer = new AxisRenderer();
verticalAxisRenderer.axis = verticalAxis;
verticalAxisRenderer.setStyle("tickLength", 0);
verticalAxisRenderer.setStyle("showLine", false);
verticalAxisRenderer.setStyle("fontSize", WidgetStylesheet.instance.ComputeChartAxisFontSize(o.HeadlineFontSize));
this.series = this.m_createSeries(o);
this.horizontalAxis = horizontalAxis;
this.horizontalAxisRenderers = [horizontalAxisRenderer];
this.verticalAxis = verticalAxis;
this.verticalAxisRenderers = [verticalAxisRenderer];
this.backgroundElements = [grids];
}
I'm afraid that there is more than one issue with this code. Unfortunately it is not obvious why your chart doesn't show up so you may apply some of advices below and use debugger to analyse the issue.
There is no point in creating ChartBase instance if you are going to change value of chartObject reference in the next line
chartObject = new ChartBase();
chartObject = ChartFactory.CreateChartObject(chartType);
If the API of your charts is IChart your factory should return IChart instead of casting.
public static function CreateChartObject(subType:String):IChart
Make sure that you are returning instances of the correct class from the factory. i.e. that you are returning your subclass of standard PieChart. Generally it's not the best idea to extend the class keeping the same name and just changing the package.
Once again, if you are not sure if the program enters some function use the Flash Builder debugger to check this. I can't imagine development without debugger.
Some thoughts:
you call the Show method, pass it some object but nowhere in that method is any child added to a displayObject. What exactly is Show supposed to do?
a lot of member variables in your classes start with UpperCase. The compiler can easily confuse those with class names, in case your classes are named the same. Bad practice to start variable and function names with capitals.
If your casting an instance to another class or interface fails, you will get a runtime error. Those are easy to debug using the Flash Builder debugger.
Hey ppl..
i found out wat wnt wrng..as olwys it wa "I".
I ve a habit of mkin mock ups secluded from the main project n dn integrate it. So in mock up i hd used an xml whch hd a format slightly diff dn d one being used in the main project.
N i hd a conditional chk to return from the prog if certain value doesnt match, n due to faulty xml i did'nt.
So this more a lexical error than a logical one.
Sorry n Thanx evryone for responding.
I wonder how it would be possible to launch a series of popups, containing a form,
from code-behind.
I possess a list of objects 'Products'
and I wish I could change one property (quantity) of each "product".
Here's how I build my list (normally I use a database).
Private List<Product> listProduct;
listProduits = new List<Product>();
Product objProduit_1 = new Produit;
objProduct_1.ref = "001";
objProduct_1.article = "G900";
objProduct_1.quantity = 30;
listProducts.Add(objProduct_1);
ProductobjProduit_2 = new Product;
objProduct_2.ref = "002";
objProduct_2.article = "G900";
objProduct_2.quantity = 35;
listProduits.Add(objProduct_2);
And I would like displayed popup one after one.
Thank you in advance for your help
you'll need to write some client side code that produces what you're looking for. The AJAX Control tool kit may be along the lines of what you're looking for.