The default behavior of Leaflet's map.flyTo() method is that if the user clicks on the map during the flyTo animation, the animation stops.
I would like to keep the map animating until the desired view is reached, regardless of user interaction.
Is there a way to disable the map mouse/touch interactions for the duration of the animation?
Use the methods described by #IvanSanchez within the function that fires theflyTo() method (let's call this function "triggersFlyTo()")and the 'moveend' event. I hope that the following code solves your problem:
//stop user interaction when flyTo() is fired
function triggersFlyTo() {
...
map.dragging.disable();
map.doubleClickZoom.disable();
map.scrollWheelZoom.disable();
map.flyTo(...)
...
}
//restart user interaction when the "flying" stops.
map.on('moveend', function() {
map.dragging.enable();
map.doubleClickZoom.enable();
map.scrollWheelZoom.enable();
}
Is there a way to disable the map mouse/touch interactions for the duration of the animation?
You probably want to temporarily disable the interaction handlers, like so:
map.dragging.disable();
map.doubleClickZoom.disable();
map.scrollWheelZoom.disable();
...
map.dragging.enable();
map.doubleClickZoom.enable();
map.scrollWheelZoom.enable();
Check the full list at http://leafletjs.com/reference-1.0.3.html#map-handlers , along with the rest of the documentation.
Related
I'm using react-leaflet with the Geoman plugin, and I notice that pm:create doesn't fire when I add new layers programmatically. This code runs on startup and again anytime the activeFeatureGroup is changed:
map.pm.setGlobalOptions({
...map.pm.getGlobalOptions(),
layerGroup: activeFeatureGroup,
hintlineStyle: { color },
templineStyle: { color },
})
This is my function to programmatically add new layers from GeoJSON:
const opts = { style: { color } }
geoJSON(newGeoJsonObject, opts).addTo(activeFeatureGroup)
How can I get pm:create to fire after this code runs? The main concern is that I'm adding event listeners to every layer that pm:create sees, so an alternative solution would be a way to set one listener on the map instance that fires anytime a layer is added in Geoman, but I don't see support for this in the Geoman docs.
How can I get pm:create to fire after this code runs?
You can achive this in 3 different ways:
Create a function and call it after running the geoJson part and in the pm:create listener
add a listener on the map layeradd (leaflet event) and run the same code as in pm:create
you can fire pm:create manually with map.fire('pm:create',{layer: XYZ}); (I don't recommand this!)
alternative solution would be a way to set one listener on the map instance that fires anytime a layer is added in Geoman
This is pm:create ... if you mean to fire an event for each layer that is intialized and is added to Geoman, you can achive this by listening on layeradd and then check if the Geoman property layer.pm exists.
When creating a polygon using Mapbox GL Draw I do not want the polygon to then be editable, clickable etc. After ending the draw event, I'd like to to just appear as finished like below when it's deselected.
Maybe this is embedded in the simple_select config option?
The Mapbox Draw plugin provides an interface for writing and hooking in custom modes, where a mode is defined as way to group sets of user interactions into one behavior. Mapbox Draw Static Mode is a custom mode that displays data stored in Draw but does not let users interact with it, which sounds like what you are looking for.
modes.simple_select.onDrag function disable the onDrag event.
I give you a small example to can contextualize it.
Inside your #map-init method you should have:
const modes = MapboxDraw.modes;
let draw = new MapboxDraw({
// your mapBoxDraw options
});
map.on("draw.create", updateArea);
modes.draw_polygon.clickAnywhere = function (state, e) {
//your polygon click restrictions
}
modes.simple_select.onDrag = function (state, e) {
//when polygon is deselected onDrag will be false and user not be able to drag it
};
function updateArea(e) {
// your stuff when you're drawing
}
I have four buttons to select range of numbers. (clicked button should animate and stay scaled just to indicate which button is selected) I am trying to play animation on button click in unity. so when button is clicked, animation is played and returns to idle. But I do not want it to return to idle state instead I want it to remain at the last frame of on click animation clip(at last frame scale is 1.2). Loop time is unchecked.
I have assigned onclick animator play(string) in the inspector. Please help
also tried following code
public GameObject rangeBtn;
public Animator rangeBtnAnim;
private void Start()
{
if ((rangeBtn != null) && (rangeBtn.GetComponent<Animator>() != null))
{
rangeBtnAnim = rangeBtn.GetComponent<Animator>();
}
}
public void PlayAnimation()
{
rangeBtnAnim.Play("RangeSelectionButton_Pressed");
}
I would simply use this setup with Parameters
Make the PressedAnimation clip not Loop Time and use a bool parameter e.g. IsPressed. (One could also use triggers instead but in this case a bool is easier and saver - triggers stack ...)
Than the setup for the transitions:
Idle -> PressedAnimation
and PressedAnimation -> Idle
Than in your code instead you would set
rangeBtnAnim.SetBool("IsPressed", true);
or
rangeBtnAnim.SetBool("IsPressed", false);
to go back to idle.
Note the simplest way in fact of having animations (if they are not complex) would be to simply only have 1 single keyframe in Idle and also in PRessedAnimation. Unity would than simply make a transition animation interpolating between the values according to the transition duration settings.
Alternatively if your animations get more complex you would probably rather do something like
And for the two transitions
PressedAnimation -> StayPRessed
UnPressAnimation -> Idle
use the ExitTime
for the other two use the parameter
and
Something I used in my games. Let's say you have two animations: Idle and Animated.
You want your button, after Animated finishes, to stays on the last frame right ? Then you create a third animation, Animated_Remains, which contains only one frame, the last from Animated.
Then, in your Animation Controller, you put a transition between Animated (no loop) and Animated_Remains (looped). If you want the same behaviour when transiting from Animated to Idle, then you create a 4th anim, Idle_Remains.
So, after clicking on your button, it will play the Animated animation, and automatically transit to the Animated_Remains.
I did that when I had to move my Camera with an animation and make it stay at the last frame position.
I can't understand how to make css animations to an element no sooner than it appears on page, like css3 transform rotate. when I set in attached(){performRotation()} when the element appears on page it's already rotated. I couldn't find in all documentation which event I need to subscribe to in order to start animation.
You can do that with the help of NeonAnimatableBehavior and NeonAnimationRunnerBehavior, you may configure your animations in animationConfig property and then play them with playAnimation('name') function which is implemented by NeonAnimationRunnerBehavior .
Please check lifecycle callbacks and neon-animation demos.
behaviors: [
Polymer.NeonAnimatableBehavior,
Polymer.NeonAnimationRunnerBehavior
],
properties: {
animationConfig: { ... },
}
...
ready: function() {
this.playAnimation('entry');
}
I've made you a simple example using the above elements to give you a quick start.
Update
You can modify each configured animation based on given properties in one of the lifecycle callbacks, e.g. ready callback:
var entryAnimation = this.animationConfig.entry[0];
entryAnimation.transformFrom = this.doSomethingTo(this.someProperty);
Please check the updated demo.
My code does a .pantolatlong then a .showinfobox
The info box does not appear, unless I remove the pantolatlong. I guess it is stopping it. I tried adding it to the endpan event but that did not work.
What is the simplest way to pan to a pushpin and display the infobox for it?
I was using setcenter, but I discovered that sometimes setcenter pans, and this breaks it.
After some insane googling, I came up with the solution, and I'll share it here so that others can hopefully not have the grief I went through.
I created and power my bing map using pure javascript, no sdk or iframe solutions. In my code, I generate the javascript to add all of the pins I want to the map, and inject it using an asp.net label.
If you call the setCenter() method on your Bing Map, it is supposed to instantly set the map, surprise surprise, to the coordinates you specify. And it does... most of the time. Occasionally though, it decides to pan between points. If you do a SetCenter, followed by a ShowInfoBox, it will work great, unless it decides to pan.
The solution? Being great programmers we are, we dive into the sdk, and it reveals there are events we can hook into to deal with these. There is an onendpan event, which is triggered after a pan is completed. There is also an onchangeview event, which triggers when the map jumps.
So we hook into these events, and try to display the infobox for our pushpin shape... but nothing happens. Why not?
You have to give it a few milliseconds to catch its breath, for unknown reasons, when the event is called. Using a setTimeout with 10 milliseconds seems to be fine. Your box will appear great after this.
The next problem is, you only want it to appear when it pans via whatever you used to make it flick between your pushpins (in my case, a table with onclick methods). I create/destroy the event handlers on the fly, although there are other options such as using a global variable to track if the user is panning, or if the system is panning in response to a click.
Finally, you have the one bug that comes from this. If you click a place in your list, and it jumps/pans to that location, the infobox will display fine. If the user dismisses it though, then clicks again on the list item, the map does not move, and therefore no events are triggered.
My solution to this is to detect if the map moved or not, by recording its long/lat, and using another setTimeout method, detecting if they changed 100ms later. If they did not, display the infobox.
There are other things you need to keep track of, as there is no way I can see to pass parameters to the eventhandlers so I use global javascript variables for this - you have to know which pushpin shape you are displaying, and also keep track of the previous mapcoordinates before checking to see if they changed.
It took me a while to piece all this together, but it seems to work. Here is my code, some sections are removed:
// An array of our pins to allow panning to them
var myPushPins = [];
// Used by the eventhandler
var eventPinIndex;
var oldMapCenter;
// Zoom in and center on a pin, then show its information box
function ShowPushPin(pinIndex) {
eventPinIndex = pinIndex;
oldMapCenter = map.GetCenter();
map.AttachEvent("onendpan", EndPanHandler);
map.AttachEvent("onchangeview", ChangeViewHandler);
setTimeout("DetectNoMapChange();", 200);
map.SetZoomLevel(9);
map.SetCenter(myPushPins[pinIndex].GetPoints()[0]);
}
function EndPanHandler(e) {
map.DetachEvent("onendpan", EndPanHandler);
setTimeout("map.ShowInfoBox(myPushPins[eventPinIndex]);", 10);
}
function ChangeViewHandler(e) {
map.DetachEvent("onchangeview", ChangeViewHandler);
setTimeout("map.ShowInfoBox(myPushPins[eventPinIndex]);", 10);
}
function DetectNoMapChange(centerofmap) {
if (map.GetCenter().Latitude == oldMapCenter.Latitude && map.GetCenter().Longitude == oldMapCenter.Longitude) {
map.ShowInfoBox(myPushPins[eventPinIndex]);
}
}
Here is another way:
function addPushpin(lat,lon,pinNumber) {
var pinLocation = new Microsoft.Maps.Location(lat, lon);
var pin = new Microsoft.Maps.Pushpin(map.getCenter(), { text: pinNumber.toString() });
pinInfobox = new Microsoft.Maps.Infobox(pinLocation,
{ title: 'Details',
description: 'Latitude: ' + lat.toString() + ' Longitude: ' + lon.toString(),
offset: new Microsoft.Maps.Point(0, 15)
});
map.entities.push(pinInfobox);
map.entities.push(pin);
pin.setLocation(pinLocation);
map.setView({ center: pinLocation});
}