var loader = new PIXI.Loader();
var colors = ['66FF00','FF5555','FFE419','2A7FFF','BC5FD3','C8AB37','ECECEC','FF6600'];
for (var i in colors){
loader.add('marker'+colors[i]+'', 'src/img/plane-'+colors[i]+'.png');
}
//global variable
var nbPlane = 0
loader.add('shadow', 'src/img/shadow.png');
loader.load(function(loader, resources) {
var pixiContainer = new PIXI.Container();
var map = L.map('map',{
zoomControl: false,
minZoom:2,
maxZoom: 16,
maxBounds: [
[-Infinity, -360],
[Infinity, 360]
],
//worldCopyJump: true,
attributionControl: false
})
//zoom controls
L.control.zoom({position: 'bottomright'}).addTo(map);
//Locate user
L.control.locate({position: 'bottomright'}).addTo(map);
//fullscreen
map.addControl(new L.Control.Fullscreen({position: 'bottomright'}));
// Licence Icon
L.Control.Watermark = L.Control.extend({
onAdd: function(map) {
var img = L.DomUtil.create('img');
img.src = 'src/img/licence.svg';
img.style.width = '100px';
return img;
}
});
L.control.watermark = function(opts) {
return new L.Control.Watermark(opts);
}
L.control.watermark({ position: 'bottomleft' }).addTo(map);
//scale
L.control.scale().addTo(map);
//disabling send plane button if alreada 100 planes sent the current day
$.post("avionJournalier.php", function(result) {
result = result.replace(/'/g, '"');
result = $.parseJSON(result)
nbPlane = Number(result.nAvion)
$("#buttonNewPlane").val("Lancer un avion-poème "+Number(result.nAvion)+"/100")
if (nbPlane > 99){
$("#buttonNewPlane").prop("disabled",true);
}
else{
}
translateUI(lang)
})
//background
L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: '',
//minZoom:8,
maxZoom: 16,
}).addTo(map);
//adding terminator
var terminator = L.terminator()
.addTo(map);
setInterval(function() {
terminator.setTime();
}, 1000);
//center map on sun by default
function centerOnSun(){
var equator = turf.lineString([[-1000, 0], [1000, 0]])
var intersects = turf.lineIntersect(equator, terminator.toGeoJSON());
//console.log(intersects)
var lonCenter = ((intersects.features[1].geometry.coordinates[0])+(intersects.features[2].geometry.coordinates[0]))/2
//console.log(lonCenter)
return lonCenter
}
map.setView([30,0], 2);
//could layer from GBIS NASA - always 1 day of delay
var twoDaysAgo = moment(new Date()).subtract(2, "days").format('YYYY-MM-DD')
L.tileLayer('https://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/'+twoDaysAgo+'/GoogleMapsCompatible_Level9/{z}/{y}/{x}.jpg', {
attribution: '',
maxZoom: 8,
opacity:0.4
})
.addTo(map);
//Bluring the terminator | Source: https://stackoverflow.com/questions/28235792/leaflet-polygon-with-fuzzy-outline
var svg = map.getPanes().overlayPane.firstChild,
svgFilter = document.createElementNS('http://www.w3.org/2000/svg', 'filter'),
svgBlur = document.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
svgFilter.setAttribute('id', 'blur');
svgFilter.setAttribute('x', '-100%');
svgFilter.setAttribute('y', '-100%');
svgFilter.setAttribute('width', '500%');
svgFilter.setAttribute('height', '500%');
svgBlur.setAttribute('stdDeviation', 15);
svgFilter.appendChild(svgBlur);
svg.appendChild(svgFilter);
terminator._path.setAttribute('filter', 'url(#blur)');
//geojson for arclines
//travel
var arcTravelStyle = {
"color": "#00ff00",
"weight": 2.5,
"dashArray": "10 5",
"opacity": 0.65
};
var arcTravel = L.geoJSON([],{style: arcTravelStyle}).addTo(map);
//travelled
var arcTravelledStyle = {
"color": "#00ff00",
"weight": 2.5,
"opacity": 0.65
};
var arcTravelled = L.geoJSON([],{style: arcTravelledStyle}).addTo(map);
var pulsatingMarker = L.layerGroup([]).addTo(map)
var originMarker = L.layerGroup([]).addTo(map)
var firstDraw = true;
var prevZoom;
var pixiOverlay = L.pixiOverlay(function(utils, event) {
var zoom = utils.getMap().getZoom();
var container = utils.getContainer();
var renderer = utils.getRenderer();
var project = utils.latLngToLayerPoint;
var scale = utils.getScale();
if (firstDraw) {
//get planes
$.post( "getCurrentPlanes.php", function(result) {
// console.log(result)
var planes = $.parseJSON(result)
console.log(planes)
function formatResults(data){
data.deliveryTime = Number(data.deliveryTime)*1000
data.startTime = Number(data.startTime)*1000
return data
}
function displayPlane(data){
var line = turf.greatCircle(turf.point([Number(data.startLon),Number(data.startLat)]), turf.point([Number(data.destLon),Number(data.destLat)]),{offset:20})
var lineDistance = turf.length(line);
var dateStart = moment(data.startTime)
var dateEnd = moment(data.deliveryTime)
var dateNow = moment(new Date())
var totalSeconds = dateEnd.diff(dateStart,'seconds');
var travelledSeconds = dateNow.diff(dateStart,'seconds')
var travelRatio = travelledSeconds/totalSeconds
var travelledDistance = lineDistance*travelRatio // getting the travelled distance
var segment;
if(line.geometry.type == "MultiLineString"){ // if the arc is cutting the dateline, well it's a mess.
var l1 = turf.lineString(line.geometry.coordinates[0]) // creating a line from first segment
var l2 = turf.lineString(line.geometry.coordinates[1]) // creating a line from second segment
var l1Length = turf.length(l1) // calculating length of first segment
if (travelledDistance < l1Length){ // if the travelled distance is inferior to segment 1 line, the point is somewhere in it
segment = l1
data.position = 1
}
else{
segment = l2 // otherwise on segment 2
data.position = 2
travelledDistance = Number(travelledDistance)-Number(l1Length) // we remove the travel distance done in s1
}
}
else{
segment = line
data.position = 0
}
var currentPosition = turf.along(segment, travelledDistance,{units: 'kilometers'})
if(currentPosition.geometry.coordinates[0] < -180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]+360}
if(currentPosition.geometry.coordinates[0] > 180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]-Number(360)}
//calculating bearing based on two points, one just before and one just after
var positionBefore = turf.along(segment, (travelledDistance)-0.00001,{units: 'kilometers'})
var positionAfter = turf.along(segment, (travelledDistance)+0.00001,{units: 'kilometers'})
var rotation = turf.bearing(
positionBefore,
positionAfter
);
//plane
var iconColor = 'marker'+data.color
var markerTexture = resources[iconColor].texture;
var marker = new PIXI.Sprite(markerTexture);
marker.anchor.set(0.5, 0.5);
var markerCoords = project([currentPosition.geometry.coordinates[1],currentPosition.geometry.coordinates[0]]);
marker.x = markerCoords.x;
marker.y = markerCoords.y;
marker.angle = rotation;
marker.scale.set(5);
marker.interactive = true;
marker.cursor = 'pointer'
marker.data = data
marker.data.line = line
marker.data.currentPosition = currentPosition
//shadow
var shadowTexture = resources.shadow.texture;
var shadow = new PIXI.Sprite(shadowTexture);
shadow.anchor.set(0.5, 0.5);
shadow.x = markerCoords.x;
shadow.y = markerCoords.y + 0.5;
shadow.angle = rotation;
shadow.scale.set(0.00025);
shadow.alpha = 0.3
shadow.visible = false
//popup
marker.popup = L.popup({className: 'pixi-popup'})
pixiContainer.addChild(shadow);
pixiContainer.addChild(marker);
renderer.render(container)
//adapting scale based on zoom level. Max zoom = writting visible
map.on('zoomend', function() {
marker.scale.set((1/(utils.getScale(map.getZoom())*20))+(Math.pow(map.getZoom(),2)/100*2*(1/(utils.getScale(map.getZoom())*20))))
if(map.getZoom() == 16){
shadow.visible = true
}
else{
shadow.visible = false
}
});
//animating moving plane
setInterval(function() {
animate();
}, 1000)
function animate() {
if (map.getZoom() > 12){ // we animate only starting zoom 12
var bounds = map.getBounds()
var bbox = [bounds._southWest.lng, bounds._southWest.lat, bounds._northEast.lng, bounds._northEast.lat];
var extentPoly = turf.bboxPolygon(bbox);
var planeInExtent = turf.booleanWithin(marker.data.currentPosition, extentPoly);
if(planeInExtent == true){ // we animate only the planes in map extent
var dateNow = moment(new Date())
var totalSeconds = dateEnd.diff(dateStart,'seconds');
var travelledSeconds = dateNow.diff(dateStart,'seconds')
var travelRatio = travelledSeconds/totalSeconds
var lineDistance = turf.length(line);
var segment;
var travelledDistance = lineDistance*travelRatio // getting the travelled distance
if(line.geometry.type == "MultiLineString"){ // if the arc is cutting the dateline
var l1 = turf.lineString(line.geometry.coordinates[0]) // creating a line from first segment
var l2 = turf.lineString(line.geometry.coordinates[1]) // creating a line from second segment
var l1Length = turf.length(l1) // calculating length of first segment
if (travelledDistance < l1Length){ // if the travelled distance is inferior to segment 1 line, the point is somewhere in it
segment = l1
marker.data.position = 1 // we store it, usefull for popup event
}
else{
segment = l2 // otherwise on segment 2
marker.data.position = 2
travelledDistance = Number(travelledDistance)-Number(l1Length) // we remove the travel distance done in s1
}
}
else{
segment = line
}
var currentPosition = turf.along(segment, travelledDistance,{units: 'kilometers'})
//troubleshooting extreme lons
if(currentPosition.geometry.coordinates[0] < -180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]+360}
if(currentPosition.geometry.coordinates[0] > 180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]-Number(360)}
marker.data.currentPosition = currentPosition
var markerCoords = project([currentPosition.geometry.coordinates[1],currentPosition.geometry.coordinates[0]]);
marker.x = markerCoords.x;
marker.y = markerCoords.y;
shadow.x = markerCoords.x;
shadow.y = markerCoords.y + 0.5;
renderer.render(container);
}
}
}
//if parameter in URL, zoom on it
var queryString = window.location.search;
queryString = queryString.split('=')[1]
if(Number(queryString)==data.uid){
setTimeout(
function()
{
map.setView([data.currentPosition.geometry.coordinates[1],data.currentPosition.geometry.coordinates[0]], 15);
openPopup(marker)
}, 100);
}
}
for (var i in planes){
displayPlane(formatResults(planes[i]),0)
}
});
function openPopup(target){
//drawing arcs
arcTravel.clearLayers()
arcTravelled.clearLayers()
arcTravelStyle.color = '#'+target.data.color
arcTravelledStyle.color = '#'+target.data.color
var travel = target.data.line
var start = turf.point([Number(target.data.startLon),Number(target.data.startLat)])
var current = target.data.currentPosition
var end = turf.point([Number(target.data.destLon),Number(target.data.destLat)])
// for linestrings
if(travel.geometry.type == "LineString"){
var sliced1 = turf.lineSlice(start, current, travel);
var sliced2 = turf.lineSlice(current, end, travel);
arcTravelled.addData(sliced1);
arcTravel.addData(sliced2);
}
// we create a copy of lines crossing the datetime
function createCopy(c){
for (var i in c.geometry.coordinates){
if (c.geometry.coordinates[i][0] > 0){
c.geometry.coordinates[i][0] = c.geometry.coordinates[i][0] - Number(360)
}
else{
c.geometry.coordinates[i][0] = c.geometry.coordinates[i][0] + Number(360)
}
}
return c
}
//for multilinetrings
if(travel.geometry.type == "MultiLineString"){
var l1 = turf.lineString(travel.geometry.coordinates[0]) // creating a line from first segment
var l2 = turf.lineString(travel.geometry.coordinates[1]) // creating a line from second segment
if(target.data.position == 1){
var sliced1 = turf.lineSlice(start, current, l1);
var sliced2 = turf.lineSlice(current, turf.point(l1.geometry.coordinates[l1.geometry.coordinates.length-1]), l1);
arcTravelled.addData(sliced1);
arcTravel.addData(sliced2);
arcTravel.addData(l2);
}
else if(target.data.position == 2){
var sliced1 = turf.lineSlice(turf.point(l2.geometry.coordinates[0]), current, l2);
var sliced2 = turf.lineSlice(current, end, l2);
arcTravelled.addData(l1);
arcTravelled.addData(sliced1);
arcTravel.addData(sliced2);
}
var travelledGeoJSON = arcTravelled.toGeoJSON()
for (var i in travelledGeoJSON.features){
arcTravelled.addData(createCopy(travelledGeoJSON.features[i]))
}
var travelGeoJSON = arcTravel.toGeoJSON()
for (var i in travelGeoJSON.features){
arcTravel.addData(createCopy(travelGeoJSON.features[i]))
}
}
//add pulsating marker on destination;
pulsatingMarker.clearLayers()
var pulseIcon = L.divIcon({
className: 'pulse-icon', //empty class to overwrite leaflet defaults
html: '
',
iconSize: [22,22]
});
var endCoordo = [Number(target.data.destLat),Number(target.data.destLon)]
pulsatingMarker.addLayer(new L.marker(endCoordo, {icon: pulseIcon}));
if(travel.geometry.type == "MultiLineString"){ //if arc cross dateline, we multiply the marker
pulsatingMarker.addLayer(new L.marker([endCoordo[0],endCoordo[1]-Number(360)], {icon: pulseIcon}));
pulsatingMarker.addLayer(new L.marker([endCoordo[0],endCoordo[1]+Number(360)], {icon: pulseIcon}));
}
//adding static marker on origin
originMarker.clearLayers()
var startCoordo = [Number(target.data.startLat),Number(target.data.startLon)]
originMarker.addLayer(new L.circleMarker(startCoordo, {radius: 6,opacity:0.7, weight:2,color:'#'+target.data.color}));
if(travel.geometry.type == "MultiLineString"){ //if arc cross dateline, we multiply the marker
originMarker.addLayer(new L.circleMarker([startCoordo[0],startCoordo[1]-Number(360)], {radius: 6,opacity:0.7,weight:2,color:'#'+target.data.color}));
originMarker.addLayer(new L.circleMarker([startCoordo[0],startCoordo[1]+Number(360)], {radius: 6,opacity:0.7,color:'#'+target.data.color}));
}
//popup
var momentLocale = lang;
if (momentLocale == 'zh'){momentLocale = 'zh-cn'} //troubleshot for chinese
moment.locale(momentLocale)
target.popup.setLatLng([target.data.currentPosition.geometry.coordinates[1],target.data.currentPosition.geometry.coordinates[0]])
//arabic popup
if(lang=="ar"){
target.popup.setContent(''+target.data.startName+' | | '+target.data.destName+' |
---|
'+moment(target.data.startTime).fromNow()+' | | '+moment(target.data.deliveryTime).fromNow()+' |
---|
')
}
//other languages
else{
target.popup.setContent(''+target.data.startName+' | | '+target.data.destName+' |
---|
'+moment(target.data.startTime).fromNow()+' | | '+moment(target.data.deliveryTime).fromNow()+' |
---|
')
}
target.popup.openOn(map);
target.popup.on('remove', function() {
arcTravel.clearLayers()
arcTravelled.clearLayers()
pulsatingMarker.clearLayers()
originMarker.clearLayers()
});
target.popup.on('popupclose', function() {
arcTravel.clearLayers()
arcTravelled.clearLayers()
pulsatingMarker.clearLayers()
originMarker.clearLayers()
});
}
//utils for popup
utils.getMap().on('click', function(e) {
var interaction = utils.getRenderer().plugins.interaction;
var pointerEvent = e.originalEvent;
var pixiPoint = new PIXI.Point();
interaction.mapPositionToPoint(pixiPoint, pointerEvent.clientX, pointerEvent.clientY);
var target = interaction.hitTest(pixiPoint, container);
if (target && target.popup) {
openPopup(target)
}
});
utils.getMap().on('touchend', function(e) {
var interaction = utils.getRenderer().plugins.interaction;
var pointerEvent = e.originalEvent;
var pixiPoint = new PIXI.Point();
interaction.mapPositionToPoint(pixiPoint, pointerEvent.clientX, pointerEvent.clientY);
var target = interaction.hitTest(pixiPoint, container);
if (target && target.popup) {
openPopup(target)
}
});
}
firstDraw = false;
prevZoom = zoom;
renderer.render(container);
}, pixiContainer);
pixiOverlay.addTo(map);
});
//hack to make white lines between lines disapear on non-retina screens (from: https://github.com/Leaflet/Leaflet/issues/3575 )
(function(){
var originalInitTile = L.GridLayer.prototype._initTile
L.GridLayer.include({
_initTile: function (tile) {
originalInitTile.call(this, tile);
var tileSize = this.getTileSize();
tile.style.width = tileSize.x + 1 + 'px';
tile.style.height = tileSize.y + 1 + 'px';
}
});
})()