I am trying to display pushpins on a map but as i have lots of pushpins i only want to display the ones within the viewable area of the map which should hopefully make the map more responsive.
I get my list of x y points from a query to a database.
This is the code I have so far..
List<Pushpin> ListofPoints = new List<Pushpin>();
foreach (var element in query)
{
//Add a pin to the map
Pushpin pushpin = new Pushpin();
Location location = new Location();
location.Latitude = Convert.ToDouble(element.X);
location.Longitude = Convert.ToDouble(element.Y);
pushpin.Location = location;
ListofPoints.Add(pushpin);
map1.Children.Add(pushpin);
}
// Position map based on a collection of Pushpins points
var x = from l in ListofPoints
select l.Location;
map1.SetView(LocationRect.CreateLocationRect(x));
ListofPoints.Clear();
Can anyone give my any advice/code on how to only display the points on the viewable area of map?
Thanks
Use the ViewChangeStart and ViewChangeEnd events to get the current view after the change and then requery your dataset and update the displayed pins as necessary.
Related
I have an gameobject1(added Scroll Rect component)and inside of it another gameobject2(The Scroll rect component's content).In gameobject2 has images.The number of images can be 10 or 20..(Any numbers).The Movement Type is Elastic.As you know it will stop scrolling only until gameobject2 height's length. How to stop on dynamic number's of length.In gameobject2 the number of images can be different. It depends on search results. The results can be 5,8, or 200. So I need to scroll until last of search result.So how to stop scrolling on exactly length in Scroll rect component?
You can use ContentSizeFitter component. GameObject with name "Content", is a content for scrollRect component of "ScrollView"-gameObject.
RectTransform#SetSizeWithCurrentAnchors
I use this a lot when building dynamic scrolling lists. After adding all the items I want (and each having a known size, and all positioned using that size) I update the content's RectTransform with the new size (total number of objects added * size of the object).
For example, I have this code:
int i = 0;
//for each item in a list of skills...
IEnumerator<Skill> list = SkillList.getSkillList();
Transform skillListParent = GuiManager.instance.skillPanel.transform;
while(list.MoveNext()) {
Skill sk = list.Current;
//create a prefab clone...
GameObject go = Main.Instantiate(PrefabManager.instance.SKILL_LISTITEM, skillListParent) as GameObject;
//set its position...
go.transform.localPosition = new Vector3(5, i * -110 -5, 5);
//add a button event or other data (some lines omitted)...
Transform t1 = go.transform.FindChild("BuyOne");
t1.GetComponent<Button>().onClick.AddListener(delegate {
doBuySkill(sk);
});
t1.GetChild(0).GetComponent<Text>().text = Main.AsCurrency(sk.getCost(1)) + " pts";
//track how many...
i++;
}
//update rect transform
((RectTransform)skillListParent).SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, (i * 110 + 10));
I have an MKMapView in a window, and pitchEnabled is true (and I've confirmed this in the debugger). The "3D" thingy in the middle of the compass is grayed out, and clicking or dragging it does nothing. Option-dragging the map (like I do in Maps.app) doesn't do anything, either.
From my interpretation of the docs, setting pitchEnabled should let me use the 3D view, like Maps.app does. Am I mistaken? Is there something else I need to do to allow my users to get a 3D map view?
You can get close to the experience of 3D mode by adjusting the camera angle from which you view the map and making buildings visible. The example below allows you view the Eiffel Tower in 3D:
viewDidLoad() {
super.viewDidLoad()
mapView.mapType = MKMapType.Standard
mapView.showsBuildings = true // displays buildings
let eiffelTowerCoordinates = CLLocationCoordinate2DMake(48.85815, 2.29452)
mapView.region = MKCoordinateRegionMakeWithDistance(eiffelTowerCoordinates, 1000, 100) // sets the visible region of the map
// create a 3D Camera
let mapCamera = MKMapCamera()
mapCamera.centerCoordinate = eiffelTowerCoordinates
mapCamera.pitch = 45
mapCamera.altitude = 500 // example altitude
mapCamera.heading = 45
// set the camera property
mapView.camera = mapCamera
}
example from: this question
Since OS X El Capitan v10.11 they added a new map type: "3D flyover mode"
For some reason this option doesn't show up in XCode attributes inspector of the mapview. You have to set it programmatically. This makes the map look and behave as the one seen in the maps app.
self.mapView.mapType = MKMapTypeSatelliteFlyover;
I was able to do this in swift on iOS 11:
mapView.mapType = .hybridFlyover
That is giving me the 3D view.
Use this setup method to configure you MapView in viewDidLoad.
func setup() {
objMapView.showsUserLocation = true
objMapView.delegate = self
objMapView.showsBuildings = true
objMapView.mapType = .hybridFlyover
objLocationManager.startUpdatingLocation()
if let center = self.objLocationManager.location?.coordinate {
let currentLocationCoordinates = CLLocationCoordinate2DMake(center.latitude, center.longitude)
objMapView.region = MKCoordinateRegion.init(center: currentLocationCoordinates, latitudinalMeters: 1000, longitudinalMeters: 100)
// create a 3D Camera
let mapCamera = MKMapCamera()
mapCamera.centerCoordinate = currentLocationCoordinates
mapCamera.pitch = 45
mapCamera.altitude = 100
mapCamera.heading = 45
// set the camera property
objMapView.camera = mapCamera
}
}
In above code snippet:
mapType property hybridFlyover displays satellite map along with location names if available.
MkMapCamera instance helps in creating 3D view of map. altitude property determine altitude from where location is to be projected.
Check below screenshot for output:
I'm using amMap country map and want to show all country names in balloons without rollover or hover on that country. Means all balloons are visible on map load.
Showing more than one rollover balloon, or making it appear without hovering on a country is not possible, I'm afraid.
What you can do is to display a "label" on each of those countries. A label is an instance of MapImage with a text label and no actual image.
Placing an image/label for each country using longitude/latitude coordinate can be quite tedious work. Therefore you can use the following example which places area title in the geometrical center of each area automatically.
http://codepen.io/amcharts/pen/5687a78507081e1c8779cf067b762de7
The above map is for the United States, but you can use the code in it to process labels on just about any map.
The following code is responsible for that:
map.addListener("init", function () {
// set up a longitude exceptions for certain areas
var longitude = {
"US-CA": -130,
"US-FL": 120,
"US-TX": 1,
"US-LA": 40
};
var latitude = {
"US-AK": -85
};
setTimeout(function () {
// iterate through areas and put a label over center of each
map.dataProvider.images = [];
for( x in map.dataProvider.areas ) {
var area = map.dataProvider.areas[ x ];
area.groupId = area.id;
var image = new AmCharts.MapImage();
image.latitude = latitude[ area.id ] || map.getAreaCenterLatitude( area );
image.longitude = longitude[ area.id ] || map.getAreaCenterLongitude( area );
image.label = area.id.split('-').pop();
image.title = area.title;
image.linkToObject = area;
image.groupId = area.id;
map.dataProvider.images.push( image );
}
map.validateData();
console.log(map.dataProvider);
}, 100)
});
Please note, that sometimes country/state shapes will not make the dead center a perfect logical place to place a label. For those situations use the longitude and latitude overrides to adjust position of the label for the particular country.
I want to display a certain map region in MKMapView but when I put a rectangular overlay on the map with the very same parameters it is displayed misaligned vertically. It looks good enough close to the equator but the misalignment is increasing with the latitude and the span.
This is for a mac app, but it should be the same for iOS.
This is my relevant code:
MKCoordinateRegion mapRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(latCenter, lonCenter), MKCoordinateSpanMake(mapWidthY, mapWidthX));
self.radarMap.region = mapRegion;
CLLocationCoordinate2D coordinates[4];
coordinates[0] = CLLocationCoordinate2DMake(latCenter+mapWidthY/2, lonCenter+mapWidthX/2);
coordinates[1] = CLLocationCoordinate2DMake(latCenter+mapWidthY/2, lonCenter-mapWidthX/2);
coordinates[2] = CLLocationCoordinate2DMake(latCenter-mapWidthY/2, lonCenter-mapWidthX/2);
coordinates[3] = CLLocationCoordinate2DMake(latCenter-mapWidthY/2, lonCenter+mapWidthX/2);
self.boundaryOverlay = [MKPolygon polygonWithCoordinates:coordinates count:4];
[self.radarMap addOverlay:self.boundaryOverlay];
It shows this: (Notice the blue rect overlay is moved up so the upper region is not displayed):
Instead of something like this: (I'm aware of that it is displayed in aspect fill):
When you set the region property of an MKMapView object, MapKit adjusts the value of the region property so that it matches the actual region that's visible. That means that the actual value of region isn't going to be exactly what you assigned to it. So instead of creating the polygon using the region that you assigned to the map, you should get the updated value of region from the MKMapView object and use that to create the polygon.
MKCoordinateRegion mapRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(latCenter, lonCenter), MKCoordinateSpanMake(mapWidthY, mapWidthX));
self.radarMap.region = mapRegion;
CLLocationCoordinate2D coordinates[4];
// Get the actual region that MapKit is using
MKCoordinateRegion actualMapRegion = self.radarMap.region;
CLLocationDegrees actualLatCenter = actualMapRegion.center.latitude;
CLLocationDegrees actualLonCenter = actualMapRegion.center.longitude;
CLLocationDegrees actualLatSpan = actualMapRegion.span.latitudeDelta;
CLLocationDegrees actualLonSpan = actualMapRegion.span.longitudeDelta;
// And use that to create the polygon
coordinates[0] = CLLocationCoordinate2DMake(actualLatCenter+ actualLatSpan/2, actualLonCenter+ actualLonSpan/2);
coordinates[1] = CLLocationCoordinate2DMake(actualLatCenter+ actualLatSpan/2, actualLonCenter-actualLonSpan/2);
coordinates[2] = CLLocationCoordinate2DMake(actualLatCenter-actualLatSpan/2, actualLonCenter-actualLonSpan/2);
coordinates[3] = CLLocationCoordinate2DMake(actualLatCenter-actualLatSpan/2, actualLonCenter+ actualLonSpan/2);
self.boundaryOverlay = [MKPolygon polygonWithCoordinates:coordinates count:4];
[self.radarMap addOverlay:self.boundaryOverlay];
I was curious about the increasing misalignment that you were seeing as you moved north. It occurred to me that you were probably using a fixed ratio for the mapWidthX and mapWidthY. MapKit uses a projection that is non-conformal. One consequence of that is that the map gets stretched in the North-South direction, with more stretching the farther you get from the equator.
If you create your region using a ratio that's correct for the equator, it will be incorrect as you move toward the poles. MKMapView will take the region you give it and display something close to it. But the farther you get from the equator, the more of an adjustment it needs to make. And the bigger the difference between the region you give it and the actual region it uses.
I have a simple application which polls database for data every minute. When new data is fetched, I am updating the graph using ajax. However, whenever I update the graph (re-plot it with new values added to plot data) the current state of zoom is lost. Before updating the graph, I want to preserve the latest zoom position. After updating the graph, I want to zoom the graph to its saved position. This is important because re-zooming every minute is irritating. Is this possible?
I tried this answer from Ozan and I couldn't get the block for copying the zoom to work so I just used plot.getOptions() and used that to draw the graph.
Like this:
var oldOptions = plot.getOptions();
plot = $.plot($("#graph"), data, oldOptions);
This way you can dynamically change your view and the auto-update will update without changing your view.
Here is the answer by Joshua Varner 1
When you get your new data before you re plot get the current zoom and
add it to the options on update.
// Get the current zoom
var zoom = plot.getAxes();
// Add the zoom to standard options
var zoomed = {};
$.extend(zoomed,options);
zoomed.xaxis.min = zoom.xaxis.min;
zoomed.xaxis.max = zoom.xaxis.max;
zoomed.yaxis.min = zoom.yaxis.min;
zoomed.yaxis.max = zoom.yaxis.max;
// draw/save the plot
plot = $.plot($("#graph"), d, zoomed);
You should get the information about the state of the current axes, merge it with your initial options and than provide them to the new plot.
// Deep copy of the options object so that we can keep it unchanged
// for when we don't want to preserve the zoom.
var copyOptions = $.extend(true, {}, options);
if (plot != null && preserveZoom) {
// There might be more than one Y axis
var zoomY = plot.getYAxes();
for (var i = 0; i < zoomY.length; i++) {
copyOptions.yaxes[i].min = zoomY[i].min;
copyOptions.yaxes[i].max = zoomY[i].max;
}
// Considering only one X axis, in case of more than one
// you should use the same method as for the Y axis.
copyOptions.xaxis.min = plot.getXAxes()[0].min;
copyOptions.xaxis.max = plot.getXAxes()[0].max;
}
plot = $.plot("#placeholder", data, copyOptions);