Esri Silverlight control Pan/Zoom from code - silverlight

I have trouble getting Map behave properly when calling ZoomToResolution and PanTo
I need to be able to Zoom into specific coordinate and center map.
The only way I got it working is by removing animations:
this.MapControl.ZoomDuration = new TimeSpan(0);
this.MapControl.PanDuration = new TimeSpan(0);
Otherwise if I make call like this:
control.MapControl.ZoomToResolution(ZoomLevel);
control.MapControl.PanTo(MapPoint());
It does one or another (i.e. pan or zoom, but not both). If (after animation) I call this code second time (map already zoomed or panned to needed position/level) - it does second part.
Tried this:
control.MapControl.ZoomToResolution(ZoomLevel, MapPoint());
Same issue, internally it calls above commands
So, my only workaround right now is to set Zoom/Pan duration to 0. And it makes for bad UX when using mouse.
I also tried something like this:
this.MapControl.ZoomDuration = new TimeSpan(0);
this.MapControl.PanDuration = new TimeSpan(0);
control.MapControl.ZoomToResolution(ZoomLevel);
control.MapControl.PanTo(MapPoint());
this.MapControl.ZoomDuration = new TimeSpan(750);
this.MapControl.PanDuration = new TimeSpan(750);
Which seems to be working, but then mouse interaction becomes "crazy". Mouse scroll will make map jump and zoom to random places.
Is there known solution?

The problem is the second operation replaces the previous one. You would have to wait for one to complete before starting the next one. But that probably doesn't give the effect you want.
Instead zoom to an extent, and you'll get the desired behavior. If you don't have the extent but only center and resolution, you can create one using the following:
var zoomToExtent = new Envelope(point.X - resolution * MapControl.ActualWidth/2, point.Y, point.X + resolution * MapControl.ActualWidth/2, point.Y);
Btw it's a little confusing in your code that you call your resolution "ZoomLevel". I assume this is a map resolution, and not a level number right? The esri map control doesn't deal with service-specific levels, but is agnostic to the data's levels and uses a more generic "units per pixels" resolution value.

Related

OxyPlot performance issue on larg data in WPF on InvalidatePlot

I'm using OxyPlot in my wpf application as line recorder. It's like the LiveDemo example.
On a larg visible data set, I get some UI performance issues and may the whole application could freez. It seems to be PlotModel.InvalidatePlot which is called with to many points to often, but I didn't found a better way.
In deep:
Using OxyPlot 2.0.0
I code all in the PlotModel. The Xaml PlotView is only binding to the PlotModel.
I cyclical collect data in a thread an put them in a DataSource (List of List which are ItemSoure for the LineSeries)
I have a class which calculates cyclical in a thread the presentation for x and y axis and a bit more. After all this stuff, it calls PlotModel.InvalidatePlot.
If I
have more than 100 k points on the display (no matter if in multiple LineSeries or not)
and add 1 DataPoint per LineSeries every 500 ms
and call PlotModel.InvalidatePlot every 200 ms
not only the PlotView has performance issues, also the window is very slow in reaction, even if I call PlotModel.InvalidatePlot (false).
My goal
My goal would be that the Windo / Application is working normally. It should not hang up because of a line recorder. The best would be if it has no performance issues, but I'm skeptical.
What I have found or tested
OxyPlot has Performance guidelines. I'm using ItemsSource with DataPoints. I have also tried adding them directly to the LineSeris.Points, but then the Plot doesn’t refresh anyway (even with an ObservableCollection), so I have to call PlotModel.InvalidatePlot, what results in the same effect. I cannot bind to a defined LineSeries in Xaml because I don’t know how much Lines will be there. Maybe I missed something on adding the points directly?
I have also found a Github issue 1286 which is describing a related problem, but this workaround is slower in my tests.
I have also checked the time which is elapsed on the call of PlotModel.InvalidatePlot, but the count of points does not affect it.
I have checked the UI thread and it seems it have trouble to handle this large set of points
If I zoom in to the plot and display under 20 k Points it looks so
Question:
Is there a way to handle this better, except to call PlotModel.InvalidatePlot much less?
Restrictions:
I also must Update Axis and Annotations. So, I think I will not come around to call PlotModel.InvalidatePlot.
I have found that using the OxyPlot Windows Forms implementation and then displaying it using Windows Form integration in WPF gives much better performance.
e.g.
var plotView = new OxyPlot.WindowsForms.PlotView();
plotView.Model = Plot;
var host = new System.Windows.Forms.Integration.WindowsFormsHost();
host.Child = plotView;
PlotContainer = host;
Where 'Plot' is the PlotModel you call InvalidatePlot() on.
And then in your XAML:
<ContentControl Content="{Binding PlotContainer}"/>
Or however else you want to use your WindowsFormsHost.
I have a similar problem and found that you can use a Decimator in LineSeries. It is documented in the examples: LineSeriesExamples.cs
The usage is like this:
public static PlotModel WithXDecimator()
{
var model = new PlotModel { Title = "LineSeries with X Decimator" };
var s1 = CreateSeriesSuitableForDecimation();
s1.Decimator = Decimator.Decimate;
model.Series.Add(s1);
return model;
}
This may solve the problem on my side, and I hope it helps others too. Unfortunately it is not documented in the documentation
For the moment I ended up with calculating the time for calling InvalidatePlot for the next time. I calculate it with the method given in this answer, wich returns the number of visible points. This rededuce the performance issue, but dosent fix the block on the UI Thread on calling InvalidatePlot.

Leaflet map breaks after flyTo if zoom in is called

As the title states, I have a Leaflet (version 1.02) map that breaks if I try to zoom in after calling a flyTo() action. Oddly, if I zoom out first, I can then zoom freely, in or out without the map breaking. Panning also works after the flyTo(), but zooming in will still break the map unless I first call a zoomOut action.
I am not at max zoom, and this happens in multiple maps with different sets of markers. If, at zoomend of the flyTo(), I setZoom at the current level, I can then zoom freely, in or out, but this causes the map to flicker after the flyTo() and is very unappealing.
Any thoughts about this?
Thanks in advance!
I know this post is somewhat old at this point, but if anyone runs into a situation where they're using leaflet with the flyTo() function and getting subsequent weird behaviour with zooming then the issue may be what format you're passing your arguments to flyTo().
Make sure the lat, lon are cast to float and zoom is cast to int. I ran into this issue and it turned out to be due to my parameters being passed in a strings. flyTo() seems to operate fine with strings as parameters but subsequent zoom operations act erratically.
I also ran into that bug and I manage to find out a workaround, assuming that the 'zoom' function in 'flyTo' was somehow corrupting the following zoom in action made by clicking on the "+" icon.
I decided to make the flyTo immediately followed by a setZoom action. Here's the code :
map.flyTo(latlong, zoom, {animate: true, duration: 3});
setTimeout(function(){ map.setZoom(zoom);}, 3000);
Options make the flyTo sequence last for 3 seconds
Next line waits 3 second, i.e. exact time for the flyTo to end end and then performs a setZoom, thus canceling any mysterious action of the flyTo that breaks the zoomIn action of the user.
Then it works.
I ran into the same problem. After a .flyTo() call pressing the Zoom + button caused the map to go to maximum zoom, but pressing the Zoom - first meant everything worked OK.
After reading dageshi above, that proved to be the issue.
Make sure the lat, lon are cast to float and zoom is cast to int.
Adding a parseInt() to the value passed to .flyTo() fixed it straight away.
Thanks dageshi

ios 6 MapKit annotation rotation

Our app has a rotating map view which aligns with the compass heading. We counter-rotate the annotations so that their callouts remain horizontal for reading. This works fine on iOS5 devices but is broken on iOS6 (problem seen with same binary as used on iOS5 device and with binary built with iOS6 SDK). The annotations initially rotate to the correct horizontal position and then a short time later revert to the un-corrected rotation. We cannot see any events that are causing this. This is the code snippet we are using in - (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id )annotation
CATransform3D transformZ = CATransform3DIdentity;
transformZ = CATransform3DRotate(transformZ, _rotationZ, 0, 0, 1);
annotation.myView.layer.transform = transformZ;
Anyone else seen this and anyone got any suggestions on how to fix it on iOS6?
I had an identical problem so my workaround may work for you. I've also submitted a bug to Apple on it. For me, every time the map got panned by the user the Annotations would get "unrotated".
In my code I set the rotations using CGAffineTransformMakeRotation and I don't set it in viewForAnnotation but whenever the users location get's updated. So that is a bit different than you.
My workaround was to add an additional minor rotation at the bottom of my viewForAnnotation method.
if(is6orMore) {
[annView setTransform:CGAffineTransformMakeRotation(.001)]; //iOS6 BUG WORKAROUND !!!!!!!
}
So for you, I'm not sure if that works, since you are rotating differently and doing it in viewForAnnotation. But give it a try.
Took me forever to find and I just happened across this fix.

TransformToVisual returns incorrect result only for the first time

I am trying to use the TransformToVisual method to get an Image element's absolute coordinates like this:
var transform = img.TransformToVisual( this ); // this is the current page
Point absolutePosition = transform.Transform( new Point(0, 0) );
For the first time I use it, this code returns an incorrect value (it is always 155,255). However, it always returns the correct coordinates afterwards.
This code runs in a Tap event handler, so the UI is already completely rendered when it is being executed. I tried calling InvalidateMeasure and InvalidateArrange (both on the Image element and on the page), but it did not help (I don't know if those calls have any connection whatsoever with TransformToVisual).
What could be the problem?
UPDATE: If I pin lock my phone and then unlock it, then the above issue does not happen.
UPDATE2: The position seems to be where the upper left hand corner of the image would be if it was at the center of the page. (The image's size is fixed 170x260. I get the coordinates 155,255. 2*155 + 170 = 480, 2*255 + 260 = 770 (okay the second one is not exactly 800, but it is suspicious anyway. The Application bar and the System tray are both hidden.))
UPDATE3: The problem occurs on the main page of my app. However, if I navigate to another page, then come back to the main page, it also works correctly.

silverlight animation with constant speed

I would like to create animations where Duration is not set, but instead it is calculated based on an absolute speed setting. E.g. I want the animation to happen at 100 pixels/second and the duration is calculated automatically based on To and From values. If the path is 350 pixels, the animation will take 3.5 seconds to finish.
Duration.Automatic is NOT for this. Also Animation.SpeedRatio is a different thing.
I can of course calculate the duration from the path length, but I will have many objects moving on the screen, each created and removed procedural way and personally find it clumsy to bother with this.
What is a nice solution? Is there any built-in behaviour for this in Silverlight 4 or later?
Imaginary code:
DoubleAnimation ani = new DoubleAnimation();
ani.From = 0;
ani.To = 200;
ani.AbsoluteSpeed = "300 pixels / sec";
storyBoard1.Begin(); // now my animation will take 0.66 sec
Use code like:-
ani.Duration = new Duration(TimeSpan.FromSeconds(200 / myPixelsPerSecond))
This is not at all "clumsy".
If the use of such a fairly straight forward expression would merit the addition of new property what would happen if the same approach were applied to the rest of the available API? The set of these "helpful" properties would expand to unmanagable levels. The API would be crushed by the weight of zillions of similar properties all performing fairly simple expressions for setting the true fundemental properties.
Elegance (the opposite of clusmy) is having a small set of carefully chosen properties that can be combined in a zillions ways using simple expressions. Exactly as above.

Resources