Giter VIP home page Giter VIP logo

leaflet.movingmarker's Introduction

Leaflet.MovingMarker


A Leaflet plug-in to create moving marker. Very useful to represent transportations or other movable things !

Demos

Follow this link: here

Compatibility with Leaflet Versions

Compatible with the latest stable Leaflet version leaflet-0.7.2.

Browser Compatibility

This plugin internally uses window.requestAnimationFrame through the Leaflet function L.Util.requestAnimFrame

Features

  • Let move your markers along a polyline.
  • You can zoom in/out, your moving marker will be at the right place !
  • You can pause or end the animation whenever you want.
  • You can deal with events.
  • You can make loop.
  • You can add the the point one by one.
  • You can add station at some points of the polyline.

Usage

Add this line to your HTML file:

<script type="text/javascript" src="MovingMarker.js"></script>

Then add your first MovingMarker:

var myMovingMarker = L.Marker.movingMarker([[48.8567, 2.3508],[50.45, 30.523333]],
						[20000]).addTo(map);
//...
myMovingMarker.start();

API

Factory

L.movingMarker(<LatLng[]> latlngs, <Number[]> durations [,<Object> options]);

durations:

  • if array of number : duration in ms per line segment.
  • if number : total duration (autocalculate duration in ms per line segment proportionnaly to distance between points).

Note: As Leaftlet's other functions, it also accept them in a simple Array form and simple object form (see Leaflet docs).

Options All the marker's options are available.

  • autostart: if true the marker will start automatically after it is added to map. Default: false
  • loop: if true the marker will start automatically at the beginning of the polyline when the it arrives at the end. Default: false

Methods

Getter

  • isRunning(): return true if the marker is currently moving.

  • isPaused(): return true if the marker is paused

  • isEnded(): return true if the marker is arrived to the last position or it has been stopped manually

  • isStarted(): return true if the marker has started

Note: Marker.getLatLng() still works and give the current position

Setter

  • start(): the marker begins its path or resumes if it is paused.
  • stop(): manually stops the marker, if you call ```start`` after, the marker starts again the polyline at the beginning.
  • pause(): just pauses the marker
  • resume(): the marker resumes its animation
  • addLatLng(latlng, duration): adds a point to the polyline. Useful, if we have to set the path one by one.
  • moveTo(latlng, duration): stops current animation and make the marker move to latlng in duration ms.
  • addStation(pointIndex, duration): the marker will stop at the pointIndexth points of the polyline during duration ms. You can't add a station at the first or last point of the polyline.

Events

  • start: fired when the marker starts
  • end: fired when the marker stops
  • loop: fired when the marker begin a new loop

Note: Event are not synchrone because of the use of requestAnimationFrame. If you quit the tab where the animation is working, events will be fired when the tab will get back the focus. Events end and loop have the attribute elapsedTime to get the time elapsed since the real end/loop.

How it works

This plugin internally uses window.requestAnimationFrame through the Leaflet function L.Util.requestAnimFrame. When the browser need to repaint, the marker interpolate linearly its position thanks to the elapsed time.

Why do you just not use transitions ?

If your marker moves very slowly (1-2 min or more for one transition) and you zoom in, your marker will be at the wrong place and take a lot of time to be where it has to be. Moreover, you have to do some hacks to get the current position of the marker during the animation.

Future Features

  • Optimizations: clipping

TODO

Tests ;-)

License

MIT License

leaflet.movingmarker's People

Contributors

emmanuelroecker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

leaflet.movingmarker's Issues

problem with array when passing array

I am using Leaflet and the MovingMarker plugin. When I pass an array of hard-coded points, it works normally and the marker moves and loops. But when I pass the variable with an array it is not working. It cannot loop after moving the marker.
var array=[]
for (var i = 0; i < 3; i++) {
array.push([49.8567 + i, 5.3508+i]);
}
var marker1 = L.Marker.movingMarker(array, [10000], { autostart: true, loop: true } ).addTo(map);
with this code the loop is not working and the event end not firing?? can you help me please .

Bower integration

Hi all,

I am trying to integrate this project within the angular-leaflet-directive project. In order to do that, I will require to register it within bower and I would like to merge that through a pull request with your current code. Is there any problem if I do that or do the developers prefer to keep the code out of bower?

Best, Ricardo.

Using negative durations

Is there a way to catch a negative duration? I want to use negative durations so the marker would jump to a location but I need to differentiate what the marker does.
For example, if it catches a -1, the marker would jump to the location but gets hidden for an amount of time. If the value is -2, the marker jumps to a location but changes the marker's border.
I've tried listening for the durations array at the _loadLine and _updateLine functions but whenever there is a small number, negative or not, it just jumps to the next index of the durations array.
Can someone help me?
Thanks in advance!

Question: performance

I wanted to ask about the performance of this library.
Specifically, how many markers does this library support.
Currently, to move markers, I delete and recreate markers consecutively (every 0.5s) to appear them moving. There is a limit of markers I can display of a few hundred.
This limit - as far as I know - is generally about displaying markers.

In this library - is there an overhead that would reduce the amount of displayable markers or would I be able to display the same amount?

movingMarker undefined in Angular7 Project

L.marker.movingMarker([latlng],
{
icon: this.generateIcon(vehicle, transportCategoryId),
draggable: false
}).addTo(this.map)

getting movingMarker as undefined please give me some solution

GeoJson Support

I am working on vehicle history. For this purpose I have to draw a rout and show moving marker on it , Its just fine and working like a charm. But when i need to show a open popup window to show speed and time of vehicle at specific time while moving marker
there is a bad approach I have tried with out using Geojson with moving marker. this below code is working but very sad solution for this purpose when i have a big array of points

image
movingMarkersTrip=L.Marker.movingMarker(singlePolydata[selectedID], 150000,{
autostart: false,
icon: L.ExtraMarkers.icon({
icon:'fa-tachometer',
markerColor: 'blue',
shape: 'circle',
prefix: 'fa',
mapObj:map
})
}).addTo(map);

            movingMarkersTrip.bindPopup('infoWindow',{maxWidth:300 ,minWidth:250}); 
            
            movingMarkersTrip.on('move', function (e) { 
                        updatePopUp(popupDataArray , e);   
                    });

function updatePopUp(data , e ){

    var ll = e.target.getLatLng();

    $.each(data , function(key , val) {
            // console.log(val.geometry.coordinates[0]);
            var lat1 = val.lat;
            var long1 = val.lng; 

            var lat2 = parseFloat(ll.lat).toFixed(6);
            var long2 = parseFloat(ll.lng).toFixed(6);
             
            var infoWindow = '';
            if(long1 == long2 || lat1 == lat2){
                // console.log('equal');
                
                var infoWindow = `<table class="htmlPopupDetail">    
                <tbody>         
                <tr><td><strong><?php echo lang('object');?>:</strong>
                </td><td>`+trackerName+`</td>
                </tr> 
                <tr><td><strong><?php echo lang('reportedTime');?>:</strong>
                </td><td>`+val.reportedTime+`</td>
                </tr>   
                <tr>
                <td><strong><?php echo lang('speed');?>:</strong></td>
                <td>`+val.speed+`</td>
                </tr> 
                <tr>
                <td><strong><?php echo lang('mileage');?>:</strong></td>
                <td>`+val.mileage+`</td>
                </tr>                 
                <tr><td><strong><?php echo lang('position');?>:</strong>
                </td><td><a href="https://maps.google.com/maps?q=`+lat2+`,`+long2+`&amp;t=m" target="_blank">`+lat2+` °, `+long2+` °</a>
                </td>
                </tr>   
                </tbody>
                </table>`;  
                
            }
            e.target._popup.setContent(infoWindow);
            e.target.openPopup();
            
    });
}

Now I want to know is there any way i can use geojson object with it and then oneachlayer function to bind popup with layer and show that popup when moving marker

Change position programmatically

I have a slider that change on each duration, but need to change the position of the marker on change my slider, when the state is pause or stop.

Destionation Reached Event

I'd like to suggest "destionation" event, when the marker reach a point from the list, so we can update other info based on the point (the vehicle speed at the moment of tracker transmission for example, in my application).

I managed to do so by putting my code in the "_loadLine" function in MovingMarker.js wich tell the current point index, so I guess it's a useful and easy to make feature.

Leaflet 0.8-dev incompatibility

This plugin does not seem to work with Leaflet 0.8. Are there any plans to update it?

I'd imagine it'd be very easy to port to 0.8 but my javascript skills are not that good.

Thanks

Edit: Problem was using L.Marker.MovingMarker over L.Marker.movingMarker with no "new" statement. I think, anyway. Javascript is dumb.

Draw polyline

Hello,

Is there a easy way to draw a polyline while the marker is moving? To let behind the polyline, not to move over an existing polyline.

Thank you!

The demo page is broken

I got this on the console when opening the demo page

Uncaught ReferenceError: L is not defined
    <anonymous> https://ewoken.github.io/Leaflet.MovingMarker/MovingMarker.js:1

Implement TypeScript file

Hello,
I'm trying to implement the TypeScript of this plugin but I don't succeed.
Someone already did it or have any good implementation idea ?

This is my implementation :
The main problem is coming from the implementation of movingMarker.

import * as L from 'leaflet';

declare module 'leaflet' {
    interface MarkerOptions {
        autostart?: boolean;
        loop?: boolean;
    }

    interface Marker {
        movingMarker(latlngs: L.LatLng[], durations: Number[], options?: Object): Marker;
        addStation(pointIndex: number, duration: number): this;
        start(): this;
        isRunning(): this;
        isEnded(): this;
        isStarted(): this;
        isPaused(): this;
        resume(): this;
    }
}

The moving marker is not always moving

Hi, I want to use this plugin to do some realtime play work.
And I'm useing addLatLng to add a new point, it's about every 1 second I'll add a new point.
But whatever I did, the markers mostly didn't move to the last new added point, however, by some unkown reasons it do move sometimes.
Is there any way to fix this?
here is my code, thanks very much. Btw, I'm using it in react.

const {user, map} = nextProps;
if (!user || !map) return;
const {coordinates, properties} = user;
if(!this.marker) {
  this.marker = L.Marker.movingMarker(new Array(coordinates,coordinates),1000,{autostart: true,icon: OnlineUser}).addTo(map.leafletElement);
} else {
  this.marker.addLatLng(coordinates,2000);

}

addStation not working correctly

When addingstation with PointIndex from a polyline.... the number is not correct used in addStation(pointIndex,duration)

let's say i have this polyline:
[[40.64397,22.908537],[40.643888,22.908784],[40.643672,22.90953],[40.64353,22.909975],[40.643404,22.910372],[40.643294,22.910758],[40.643041,22.911461],[40.642752,22.912373],[40.642447,22.913349],[40.642077,22.91446],[40.641413,22.916622],[40.641002,22.917925],[40.640884,22.918279],[40.640807,22.918569],[40.640611,22.919433],[40.640599,22.919486]]

i want to addStation on points: 1,4,7,10,11,13,14

but for some reason i had to use 1,5,9,13,15,18,20 to make it work.

after the first addStation i had to add +1, +2, +3, +4 , +5, +6

Removing individual markers from map at the end of animation

I'm having a hard time removing each individual marker from the map as soon as they stop. Tried using methods isEnded() and end without much sucess. With (end), the following code removes only but one marker (I am guessing that it is removing the first to stop). Full code here:

marker.on('end', function() {
  map.removeLayer(this);
  });

With a click event instead of an end event, each marker is made easily removable, but then this is not what I am looking for:

marker.on('click', function() {
  map.removeLayer(this);
  });

What am I missing here?

How to use the events (start, end, loop)?

Hi @ewoken

I am using your plugin in ionic v1 project. How can I use the events (start, end, loop)?
I am using this code:

leafletData.getMap('app-map').then(
    function(map) {
        // more code here ...
        var trolleyIcon = L.icon({iconUrl: 'http://www.freeiconspng.com/uploads/bus-icon-10.png',iconSize:[64,64]});
        trolley = L.Marker.movingMarker(routeTest,[2000],{type:'trolley',icon:trolleyIcon}).bindPopup(
            'This is the Trolley!'
        ).addTo(map);
        trolley.start();
        trolley.on('start',function(e) {
            console.log('start event',e);
        });
        trolley.on('end',function(e) {
            console.log('end event',e);
        });
    }
);

I tried:

trolley.on('end',function(e) {
        console.log(e);
});

But nothing happen.

Marker drifting off line when coords are across equator.

We have spotted an issue whereby if you place a moving marker to follow between 2 points on a polyline if one is in say "Paris", and the other end is in "Rio De Janeiro" the marker drifts off from the line to the right, then returns back to the line at the end.

Is there a way to fix this?

Move marker to a new position

If I already have a mark on the map and that every 30 seconds it chooses its new position, how can I reuse the previous mark? to move the icon to its new position and not have to create a new brand and delete the previous one.

Variable speed?

Is it possible to change the speed of the marker mid-flight? How do I control the speed with a slider?

[Enhancement] Adding a remove option

I am attempting to add a custom option to the plugin so that, if truthy, each marker is removed at the end of the respective animation. I think this could be a really useful feature. Also, it is not trivial to remove them individually outside the plugin (please see issue #11).

With this in mind, I've added a destroyedState: 4 line in the statics properties and a remove: false line in the options properties. I've also added the following code blocks:

isDestroyed: function() {
    return this._state === L.Marker.MovingMarker.destroyedState;
}

destroy: function() {
    if (this.isDestroyed()) {
        return;
    }
    this._state = L.Marker.MovingMarker.destroyedState;
    this._removeMarker();
},

onEnd: function(map) {
    L.Marker.prototype.onEnd.call(this, map);

    if (this.options.remove && (this.isDestroyed())) {
        this.destroy();
        return;
    }
    this._removeMarker();
},

 _removeMarker: function() {
    this._state = L.Marker.MovingMarker.destroyedState;
    if (this._animRequested) {
        L.Util.cancelAnimFrame(this._animId);
        this._animRequested = false;
    }
    this.L.Marker.MovingMarker.clearLayers(this, map);
    this.L.Marker.MovingMarker = null;
},

Unfortunately, for some reason the method clearLayers isn't doing its job here.

I've a working example here

Leaflet API. Move a Marker Along a Polyline

Hi there. Trying to migrate from Googlemaps to Leaflet enviroment, returns some errors in following script.
Need an help, thanks.

Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
//
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
// polyline length calc
L.Polyline.prototype.m_len = function (options) {
var distance = 0, coords = null, coordsArray = this._latlngs;
for (i = 0; i < coordsArray.length - 1; i++) {
coords = coordsArray[i];
distance += coords.distanceTo(coordsArray[i + 1]);
}
return distance;
}
//
L.LatLng.prototype.moveTowards = function(point, distance) {
var lat1 = this.lat().toRad();
var lon1 = this.lng().toRad();
var lat2 = point.lat().toRad();
var lon2 = point.lng().toRad();
var dLon = (point.lng() - this.lng()).toRad();
// Find the bearing from this point to the next.
var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) *
Math.cos(dLon));

  var angDist = distance / 6371000 ;  // 66371000 Earth's radius.
  // Calculate the destination point, given the source and bearing.
  lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) + 
                   Math.cos(lat1) * Math.sin(angDist) * 
                   Math.cos(brng));
  lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                           Math.cos(lat1), 
                           Math.cos(angDist) - Math.sin(lat1) *
                           Math.sin(lat2));

  if (isNaN(lat2) || isNaN(lon2))  {return null; }
  return new L.LatLng(lat2.toDeg(), lon2.toDeg());

} // end moveTowards
//
function moveAlongPath(points, distance, index) {
index = index || 0; // Set index to 0 by default.
if (index < points.length) {
var poly = new L.Polyline([points[index], points[index + 1]]);
var distanceToNextPoint = poly.m_len();
if (distance <= distanceToNextPoint) {
return points[index].moveTowards(points[index + 1], distance);
} else {
return moveAlongPath(points, (distance - distanceToNextPoint), index + 1);
}
} else {
return null;
}
} // end moveAlongPath
//////////
var points = ;
var polycolor = "";
var stroke_w = 5;
if (mobile_dev == 1 ) {
stroke_w = 10;
}
var polyline = L.polyline(points, {color: polycolor, weight: stroke_w, fillOpacity: 0.2});
map.addLayer(polyline);

Leaflet Moving Marker weird loops

Let me first explain what i am trying to do: Every 30 seconds i get array of gps points(lat, lng). These points represent a route along which i must move a maker, i'm trying to do it simply by moving a marker from point1 to point2 , then from point2 to point3 and so on. And then when i receive a new array of points i start doing this again. It is guaranteed that the last point of previous array and the first point of current array are the same. This means that routes are connected and each route is a part of one Big Route, which is divided into smaller routes and these smaller routes are sent to me in an order. (If last sentence was too difficult to understand please ignore it, it's not necessary to understand it).
How i implement it
Here as a code: (it's not full, i wrote it as close to my code and as brief as it is possible)

var api = // setting api here..
var marker = L.Marker.movingMarker(
                    [[0,0],[0,0]],
                    [0],
                    { icon: icons.chosen });

var myPlugin = function(api, marker) {
    this._api = api;
    this._marker = api;

    var that = this.
    this._api.on('receive', function(points) { // receiving points here
        that.moveMarker(points, 2000);
    });
}

myPlugin.prototype.moveMarker = function(points, interval) {
    this._marker.initialize(points, interval);
    this._marker.start();
}

MyPlugin = new myPlugin(api,marker);

And finally my problem
What happens each time we receive points:

  1. Marker moves as it is supposed to move(from point1 to point2, from point2 to point3 and so on to the last point. Then we wait to receive new points)
  2. We recieved new points.(Cool!). Marker moves correctly, in a correct order, but when it reaches the last point it for some (unclear to me) reasons moves to the first point again and starts moving from point1 to point2, from point2 to point3 and so on. It does a laps. But only twice!
  3. Okay, we received points again and our marker again does laps, 3 laps this time.
  4. We received points again, and our marker does 4 laps...

...And when we receive points for twentieth time our marker does 20 laps. ## Why?
Even though loop option of marker if set to false by default, i tried setting loop option of marker to false manually, this didn't help.

Thanks for spending your valuable time on reading this and helping me!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.