1
0

fix: synchro repository with production

This commit is contained in:
mberard
2021-10-21 00:07:26 +02:00
parent febc76934b
commit 4ea4011a18
74 changed files with 17935 additions and 735 deletions

33
src/about.js Normal file
View File

@@ -0,0 +1,33 @@
//open / close
var aboutOpen = 0
$('#buttonAbout').on('click',function(){
//hiding navbar
$('.navbar-collapse').collapse('hide');
if (aboutOpen > 0){
$('#about').css('visibility','hidden');
$('#about').css('opacity','0')
$('#backToMap').css('visibility','hidden');
$('#backToMap').css('opacity','0')
aboutOpen = 0
}
else{
$('#about').css('visibility','visible')
$('#about').css('opacity','1')
$('#backToMap').css('visibility','visible');
$('#backToMap').css('opacity','1')
aboutOpen = 1
}
//closing anthology
$('#anthology').css('opacity','0')
$('#anthology').css('visibility','hidden')
anthologyOpen = 0
})
$('#closeAnthologyAbout').on('click',function(){
$('#about').css('opacity','0')
$('#about').css('visibility','hidden')
$('#backToMap').css('opacity','0')
$('#backToMap').css('visibility','hidden')
aboutOpen = 0
})

130
src/anthology.js Normal file
View File

@@ -0,0 +1,130 @@
//open / close
var anthologyOpen = 0
$('#buttonAnthology').on('click',function(){
//hiding navbar
$('.navbar-collapse').collapse('hide');
if (anthologyOpen > 0){
$('#anthology').css('visibility','hidden');
$('#anthology').css('opacity','0')
$('#backToMap').css('visibility','hidden');
$('#backToMap').css('opacity','0')
anthologyOpen = 0
}
else{
$('#anthology').css('visibility','visible')
$('#anthology').css('opacity','1')
$('#backToMap').css('visibility','visible');
$('#backToMap').css('opacity','1')
anthologyOpen = 1
displayAnthology()
}
//closing about
$('#about').css('visibility','hidden');
$('#about').css('opacity','0')
aboutOpen = 0
})
$('#closeAnthologyAbout').on('click',function(){
$('#anthology').css('opacity','0')
$('#anthology').css('visibility','hidden')
$('#backToMap').css('opacity','0')
$('#backToMap').css('visibility','hidden')
anthologyOpen = 0
})
$('#navTitle').on('click',function(){
$('#anthology').css('opacity','0')
$('#anthology').css('visibility','hidden')
$('#backToMap').css('opacity','0')
$('#backToMap').css('visibility','hidden')
$('#about').css('opacity','0')
$('#about').css('visibility','hidden')
aboutOpen = 0
anthologyOpen = 0
})
function flightTime(a,b){
var days = Math.round((b-a)/86400 * 100) / 100
var months = Math.round(days/30)
var years = Math.round(months/12)
if (days < 30){
return ""+days+" "+dictionnary.jours
}
else if (days >= 30 && days < 365){
if(months>1){
return ""+months+" "+dictionnary.mois_pluriel
}
else{
return ""+months+" "+dictionnary.mois
}
}
else if (days >= 365){
if(years>1){
return ""+years+" "+dictionnary.ans
}
else{
return ""+years+" "+dictionnary.an
}
}
}
//load
var nPages;
var nPagesLoaded = 1
$.post( "getAnthology.php", function(pages) {
pages = $.parseJSON(pages)
nPages = Number(pages.nPages)
})
function displayAnthology(){ // clean and display first page
$("#anthologyItems").html('')
nPagesLoaded = 1
$.post( "getAnthology.php?page=1", function(result) {
results = $.parseJSON(result)
var momentLocale = lang;
if (momentLocale == 'zh'){momentLocale = 'zh-cn'} //troubleshot for chinese
moment.locale(momentLocale)
for (var i in results){
addAnthologyLine(results[i])
}
})
}
$( "#anthology" ).scroll(function() {
if($("#anthology").scrollTop() + 700 > $("#anthologyItems").height()){
if (nPagesLoaded < nPages){
nPagesLoaded++
console.log('Loading anthology page '+nPagesLoaded+'/'+nPages)
$.post( "getAnthology.php?page="+nPagesLoaded+"", function(result) {
results = $.parseJSON(result)
var momentLocale = lang;
if (momentLocale == 'zh'){momentLocale = 'zh-cn'} //troubleshot for chinese
moment.locale(momentLocale)
for (var i in results){
addAnthologyLine(results[i])
}
})
}
}
});
function addAnthologyLine(results){
if (lang == 'ar'){ // arabic : rtl + add <br>
$("#anthologyItems").append(
'<small style="float:right">'+dictionnary.origine+': <b>'+results.startName+'</b> &bull; '+dictionnary.destination+': <b>'+results.destName+'</b> &bull; '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> &bull; '+dictionnary.temps_de_vol+': <b>'+flightTime(Number(results.startTime),Number(results.deliveryTime))+'</b></small><br><br>'+results.message+'<br><hr><br>'
)
}
else{
$("#anthologyItems").append(
'<small>'+dictionnary.origine+': <b>'+results.startName+'</b> &bull; '+dictionnary.destination+': <b>'+results.destName+'</b> &bull; '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> &bull; '+dictionnary.temps_de_vol+': <b>'+flightTime(Number(results.startTime),Number(results.deliveryTime))+'</b></small><br><br>'+results.message+'<br><hr><br>'
)
}
}

View File

@@ -1,73 +1,264 @@
body {
margin: 0;
padding: 0;
font-family: 'PT Mono', monospace;
/* font-family: 'Special Elite', cursive !important */
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 30px;
line-height: 30px; /* Vertically center the text there */
background-color: #f5f5f5;
font-size: 12px
}
/* removing footer on mobile */
@media screen and (max-width: 400px) {
.footer {
display:none
}
}
/* big modal */
.modal-lg {
max-width:1140px !important;
}
.mapboxgl-map{
font-family: 'PT Mono', monospace;
/* font-family: 'Special Elite', cursive !important */
}
.mapboxgl-ctrl-logo{
display: none !important;
}
/* paper plane animation */
#canvas3d{
display:none;
transition: all .3s;
position:fixed;
height:100vh;
width:100vw;
background-color: rgba(0,0,0,0);
z-index:9999;
margin-top: 50vh; /* poussé de la moitié de hauteur de viewport */
transform: translateY(-50%) translateX(-50%); /* tiré de la moitié de sa propre hauteur */
margin-left: 50vw; /* poussé de la moitié de hauteur de viewport */
}
/* qill text editor */
#messageTextArea {
min-height: 200px;
border-radius: 0px 0px .25em .25em !important;
border-color: #ced4da !important
}
.ql-toolbar{
border-radius: .25em .25em 0px 0px !important;
border-color: #ced4da !important
}
html,
body {
overflow-x: hidden;
height: 100%;
}
body {
position: relative;
margin: 0;
padding: 0;
font-family: 'PT Mono', monospace;
}
#map {
position: fixed;
top: 0;
bottom: 0;
height:100%;
width: 100%;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 30px;
line-height: 30px; /* Vertically center the text there */
background-color: #f5f5f5;
font-size: 12px
}
/* big modal */
.modal-lg {
max-width:1140px !important;
}
/* paper plane animation */
#canvas3d{
display:none;
transition: all .3s;
position:fixed;
height:100vh;
width:100vw;
background-color: rgba(0,0,0,0);
z-index:9999;
margin-top: 50vh; /* poussé de la moitié de hauteur de viewport */
transform: translateY(-50%) translateX(-50%); /* tiré de la moitié de sa propre hauteur */
margin-left: 50vw; /* poussé de la moitié de hauteur de viewport */
}
/* qill text editor */
#messageTextArea {
min-height: 200px;
border-radius: 0px 0px .25em .25em !important;
border-color: #ced4da !important
}
.ql-toolbar{
border-radius: .25em .25em 0px 0px !important;
border-color: #ced4da !important
}
/* make the pixi overlay on top of the arc lines */
.leaflet-pixi-overlay {
position: absolute !important;
z-index: 201 !important;
}
.bold{
font-weight:bold !important
}
/* Anthology */
#anthology{
visibility:hidden;
opacity:0;
transition:visibility 0.2s linear,opacity 0.2s linear;
position:absolute;
z-index:1029;
padding-top:66px;
padding-bottom:35px;
padding-left:30%;
padding-right:30%;
overflow-x:hidden;
height:100vh;
width:100vw;
background-color:rgba(255,255,255,0.9)
}
/* About */
#about{
visibility:hidden;
opacity:0;
transition:visibility 0.2s linear,opacity 0.2s linear;
position:absolute;
z-index:1029;
padding-top:66px;
padding-bottom:35px;
padding-left:30%;
padding-right:30%;
overflow-x:hidden;
height:100vh;
width:100vw;
background-color:rgba(255,255,255,0.9)
}
#backToMap{
visibility:hidden;
opacity:0;
transition:visibility 0.2s linear,opacity 0.2s linear;
position:fixed;
z-index:1035;
padding-left:10%;
padding-right:10%;
overflow-x:hidden;
width:100vw;
bottom:0px;
background-color:rgba(255,255,255,1);
border-top: 1px solid #ddd;
}
#backToMap a{
color:#070707
}
#backToMap p{
margin-bottom:5px;
padding-top:3px;
}
#backToMap a:hover{
color:black
}
.leaflet-popup-content-wrapper{
font-family: 'PT Mono', monospace;
border-radius: 1px;
/* font-family: 'Special Elite', cursive !important */
}
.leaflet-popup-content{
/* min-width:280px; */
margin-left: 10px;
margin-right: 21px;
margin-top: 10px;
margin-bottom: 10px;
}
.leaflet-popup-content hr{
width: 267px;
margin-top: 10px;
margin-bottom: 10px;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: none;
border-bottom: 1px solid;
margin-top: 0px;
}
.leaflet-control-scale-line {
FONT-WEIGHT: 100;
font-family: 'PT Mono', monospace;
border: 1px solid #fff;
border-right: none;
border-top: none;
border-left: none;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
color: white;
-moz-box-sizing: border-box;
box-sizing: border-box;
/* background: #fff; */
background: rgba(255, 255, 255, 0);
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 1px !important;
border-bottom-right-radius: 1px !important;
}
.leaflet-bar a:first-child {
border-top-left-radius: 1px !important;
border-top-right-radius: 1px !important;
}
/* pulsating marker */
.pulse-icon-anim {
margin-top:2px;
margin-left:2px;
border: 3px solid;
-webkit-border-radius: 30px;
height: 18px;
width: 18px;
-webkit-animation: pulsate 1s ease-out;
-webkit-animation-iteration-count: infinite;
/*opacity: 0.0*/
}
@-webkit-keyframes pulsate {
0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
50% {opacity: 1.0;}
100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
}
a#navbarDropdownLang.nav-link.dropdown-toggle::after{
margin-left:0px !important
}
.nav-item{
margin-right:10px
}
.dropdown-menu{
font-size:0.9em !important;
padding: 0px !important
}
.ql-editor {
min-height:170px !important;
width: 100% !important
}
.ql-editor p {
font-size:1.25em !important;
}
.ql-editor .ql-size-small {
font-size: 0.9em !important;
}
@media screen and (max-width: 600px) {
.modal-body {
font-size:0.9rem
}
.modal-body .form-control{
font-size:0.8rem
}
.leaflet-popup-content {
margin: 10px 10px;
line-height: 1.4;
}
#anthologyItems{
font-size:0.8rem
}
#about{
padding-left:5% !important;
padding-right:5% !important;
}
#anthology{
padding-left:5% !important;
padding-right:5% !important;
}
}

View File

@@ -1,4 +1,4 @@
var config = {
mapboxKey: 'pk.eyJ1IjoibGVvLWlnYSIsImEiOiJjazY2bGV3MTYxMjV3M25sMmdtNWluM2wzIn0.2THSqD6nz9OhE0Xsjnbw1g',
owmKey: "39d5c3be709ba4f5b6230cdffdedd2ac",
var config = {
mapboxKey: 'pk.eyJ1IjoiYXZpb25wb2VtZSIsImEiOiJja20yY28xaWQyNnRiMnBvNm1kdjF4M3A5In0.gbs_ozL4rwh7KNsLmph-yQ',
owmKey: "39d5c3be709ba4f5b6230cdffdedd2ac",
}

25
src/formValidation.js Normal file
View File

@@ -0,0 +1,25 @@
var validExpeMail = false
var validExpeLoc = false //turned to true in geocoder.js
var validDestMail = false
var validDestLoc = false //turned to true in geocoder.js
function validateEmail(email) { //from https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
$("#expeMail").change(function() {
validExpeMail = validateEmail($("#expeMail").val())
checkFormValid()
})
$("#destMail").change(function() {
validDestMail = validateEmail($("#destMail").val())
checkFormValid()
})
function checkFormValid(){
if(validExpeMail && validExpeLoc && validDestMail && validDestLoc){
$('#sendNewPlane').prop("disabled", false)
}
}

View File

@@ -1,67 +1,129 @@
let langGeocoder = "fr"
// Expediteur
var expeLocList = []
var expeLoc;
$('#expeGeocoderPhoton').typeahead({
source: function (query, process) {
expeLocList = []
var url = "https://photon.komoot.io/api?q="+query+"&lang="+langGeocoder+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality";
var res = []
return $.getJSON(url,function(data){
for (var i in data.features){
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
expeLocList.push({
name: data.features[i].properties.name,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
})
}
return process(res)
})
},
matcher: function(item){ //needed when spelling not exact
return true
},
afterSelect: function (obj) {
for (var i in expeLocList){
if (expeLocList[i].fullname == obj){
expeLoc = expeLocList[i]
}
}
}
})
//Destinataire
var destLocList = []
var destLoc;
$('#destGeocoderPhoton').typeahead({
source: function (query, process) {
destLocList = []
var url = "https://photon.komoot.io/api?q="+query+"&lang="+langGeocoder+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality";
var res = []
return $.getJSON(url,function(data){
for (var i in data.features){
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
destLocList.push({
name: data.features[i].properties.name,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
})
}
return process(res)
})
},
matcher: function(item){ //needed when spelling not exact
return true
},
afterSelect: function (obj) {
for (var i in destLocList){
if (destLocList[i].fullname == obj){
destLoc = destLocList[i]
}
}
}
function langGeocoder(lang){
if (lang == 'fr' || lang == 'en' || lang == 'de' || lang == 'it'){ //photon only supports fr en de it, the rest will be en by default
return lang
}
else return "en"
}
// Expediteur
var expeLocList = []
var expeLoc;
$('#expeGeocoderPhoton').typeahead({
source: function (query, process) {
var timer;
clearTimeout(timer);
timer = setTimeout(function() { // using a timer of 400 ms to troubleshot people typing super fast
expeLocList = []
var l = langGeocoder(lang)
var url = "https://photon.komoot.io/api?q="+query+"&lang="+l+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality&osm_tag=place:suburb&osm_tag=place:neighbourhood&osm_tag=place:hamlet&osm_tag=highway";
//var url = "https://photon.komoot.io/api?q="+query+"&lang="+l+"&limit=4";
var res = []
return $.getJSON(url,function(data){
for (var i in data.features){
if(data.features[i].properties.type == "street"){
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
expeLocList.push({
name: data.features[i].properties.city,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
})
}
else if(data.features[i].properties.osm_value == "suburb" || data.features[i].properties.osm_value == "neighbourhood"){
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
expeLocList.push({
name: data.features[i].properties.city,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
})
}
else{
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
expeLocList.push({
name: data.features[i].properties.name,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
})
}
}
return process(res)
})
},
400
)
},
matcher: function(item){ //needed when spelling not exact
return true
},
afterSelect: function (obj) {
for (var i in expeLocList){
if (expeLocList[i].fullname == obj){
expeLoc = expeLocList[i]
validExpeLoc = true
checkFormValid()
}
}
}
})
//Destinataire
var destLocList = []
var destLoc;
$('#destGeocoderPhoton').typeahead({
source: function (query, process) {
var timer;
clearTimeout(timer);
timer = setTimeout(function() { // using a timer of 400 ms to troubleshot people typing super fast
destLocList = []
var l = langGeocoder(lang)
var url = "https://photon.komoot.io/api?q="+query+"&lang="+l+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality&osm_tag=place:suburb&osm_tag=place:neighbourhood&osm_tag=place:hamlet&osm_tag=highway";
var res = []
return $.getJSON(url,function(data){
for (var i in data.features){
if(data.features[i].properties.type == "street"){
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
destLocList.push({
name: data.features[i].properties.city,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
})
}
else if(data.features[i].properties.osm_value == "suburb" || data.features[i].properties.osm_value == "neighbourhood"){
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
destLocList.push({
name: data.features[i].properties.city,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
})
}
else{
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
destLocList.push({
name: data.features[i].properties.name,
center: data.features[i].geometry.coordinates,
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
})
}
}
return process(res)
})
},
400
)
},
matcher: function(item){ //needed when spelling not exact
return true
},
afterSelect: function (obj) {
for (var i in destLocList){
if (destLocList[i].fullname == obj){
destLoc = destLocList[i]
validDestLoc = true
checkFormValid()
}
}
}
})

BIN
src/img/back-2A7FFF.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-66FF00.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-BC5FD3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-C8AB37.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-ECECEC.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-FF5555.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-FF6600.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-FFE419.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
src/img/front.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src/img/lang-hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/img/lang.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

71
src/img/licence.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 52 KiB

BIN
src/img/plane-2A7FFF.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
src/img/plane-66FF00.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
src/img/plane-BC5FD3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
src/img/plane-C8AB37.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
src/img/plane-ECECEC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
src/img/plane-FF5555.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
src/img/plane-FF6600.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/img/plane-FFE419.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
src/img/shadow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -1,266 +1,484 @@
mapboxgl.accessToken = config.mapboxKey;
const owmKey = config.owmKey
var map = new mapboxgl.Map({
container: 'map',
style: {
"glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
"light": {
"anchor": "viewport",
"color": "white",
"intensity": 0.1
},
'version': 8,
'sources': {
'default-background': {
'type': 'raster',
'tiles': [
//'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_CityLights_2012/default//GoogleMapsCompatible_Level8/{z}/{y}/{x}.jpg'
//'https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}'
//'https://stamen-tiles-b.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
],
'tileSize': 256
}
},
'layers': [{
id: 'background',
type: 'background',
paint: {
'background-color': '#ffffff'
}
},
{
'id': 'default-background',
'type': 'raster',
'source': 'default-background',
'minzoom': 0,
'maxzoom': 18
}
]
},
center: [0, 20],
zoom: 2,
attributionControl: false
});
//prevent world duplication
map.setRenderWorldCopies(status === 'false')
map.on('load', function () {
//displaying clouds from OpenWeatherMap free API not enough
// map.addSource('clouds', {
// 'type': 'raster',
// 'tiles': [
// 'https://tile.openweathermap.org/map/clouds_new/{z}/{x}/{y}.png?appid='+owmKey+''
// ],
// 'tileSize': 256
// });
// map.addLayer({
// 'id': 'clouds',
// 'type': 'raster',
// 'source': 'clouds',
// 'minzoom': 0,
// 'maxzoom': 10,
// 'paint':{
// 'raster-opacity':0.5
// }
// });
//loading icons and colors, too lazy to make a loop, to change.
map.loadImage('src/img/plane-FFE419.png',
function (error, image) {
if (error) throw error;
map.addImage('plane-FFE419', image);
})
map.loadImage('src/img/plane-66FF00.png',
function (error, image) {
if (error) throw error;
map.addImage('plane-66FF00', image);
})
map.loadImage('src/img/plane-FF5555.png',
function (error, image) {
if (error) throw error;
map.addImage('plane-FF5555', image);
})
var colors = ["FFE419","66FF00","FF5555"]
//get now in GMT+0
var nowGMTSeconds = moment.tz(new Date(), "Europe/London").unix()
//get the planes from firestore
db.collection("planes").where("deliverySecondsServer", ">", nowGMTSeconds).get().then((querySnapshot) => { //change query to get only the ones who are still flying
querySnapshot.forEach((doc) => {
var id = doc.id
var data = doc.data()
//creating arcs
var line = turf.lineString([data.startCoordo,data.destCoordo])
var lineDistance = turf.length(line);
var arc = [];
var steps = 500;
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
var segment = turf.along(line, i);
arc.push(segment.geometry.coordinates);
}
line.geometry.coordinates = arc;
//random color
var randomColor = colors[Math.floor(Math.random() * colors.length)];
map.addSource('route-'+id+'', {
'type': 'geojson',
'data': line
});
map.addLayer({
'id': 'route-'+id+'',
'source': 'route-'+id+'',
'type': 'line',
'paint': {
'line-width': 2,
'line-color': '#'+randomColor
}
});
map.setLayoutProperty('route-'+id+'', 'visibility', 'none');
//creating and animating planes
// calculating area already travelled
var dateStart = moment(data.sentDate[0])
var dateEnd = moment(data.deliveryDate[0])
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 currentPosition = turf.along(line, lineDistance*travelRatio,{units: 'kilometers'})
var plane = turf.point(currentPosition.geometry.coordinates,data)
//calculating bearing based on two points, one just before and one just after
var positionBefore = turf.along(line, (lineDistance*travelRatio)-0.00001,{units: 'kilometers'})
var positionAfter = turf.along(line, (lineDistance*travelRatio)+0.00001,{units: 'kilometers'})
plane.properties.bearing = turf.bearing(
positionBefore,
positionAfter
);
map.addSource('plane-'+id+'', {
'type': 'geojson',
'data': plane
});
map.addLayer({
'id': 'plane-'+id+'',
'source': 'plane-'+id+'',
'type': 'symbol',
'layout': {
'icon-image': 'plane-'+randomColor+'',
'icon-rotate': ['get', 'bearing'],
'icon-size':0.05,
'icon-rotation-alignment': 'map',
'icon-allow-overlap': true,
'icon-ignore-placement': true
}
});
//animating
function animate(){
var dateStart = moment(data.sentDate[0])
var dateEnd = moment(data.deliveryDate[0])
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 currentPosition = turf.along(line, lineDistance*travelRatio,{units: 'kilometers'})
var plane = turf.point(currentPosition.geometry.coordinates,data)
//calculating bearing based on two points, one just before and one just after
var positionBefore = turf.along(line, (lineDistance*travelRatio)-0.00001,{units: 'kilometers'})
var positionAfter = turf.along(line, (lineDistance*travelRatio)+0.00001,{units: 'kilometers'})
plane.properties.bearing = turf.bearing(
positionBefore,
positionAfter
);
map.getSource('plane-'+id+'').setData(plane);
var nowGMTSeconds = moment.tz(new Date(), "Europe/London").unix()
//removing the plane from map if arrived
if (data.deliverySecondsServer < nowGMTSeconds){
map.setLayoutProperty('plane-'+id+'', 'visibility', 'none');
}
requestAnimationFrame(animate)
}
// uncomment to animate below, still some clipping issues
//animate()
//on click on a plane: get popup + display route
map.on('click', 'plane-'+id+'', function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var prop = e.features[0].properties;
var sentDate = JSON.parse(prop.sentDate)[0]
var deliveryDate = JSON.parse(prop.deliveryDate)[0]
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
//displying route
map.setLayoutProperty('route-'+id+'', 'visibility', 'visible');
var popup = new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML("<b>Origine:</b> "+prop.startName+"<br><em>"+sentDate+"</em><br><b>Destination:</b> "+prop.destName+"<br><em>"+deliveryDate+"</em>")
.addTo(map);
//removing route
popup.on('close', function(){
map.setLayoutProperty('route-'+id+'', 'visibility', 'none');
});
});
// Change the cursor to a pointer when the mouse is over the places layer.
map.on('mouseenter', 'plane-'+id+'', function () {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', 'plane-'+id+'', function () {
map.getCanvas().style.cursor = '';
});
//adapt icon size to zoom level
map.on('zoom', function() {
map.setLayoutProperty('plane-'+id+'', 'icon-size', (map.getZoom())*0.025);
});
//URL Parameter : zooming to ID and opening popup when url in format avion-poe.me?plane=id
var queryString = window.location.search;
queryString = queryString.substring(7)
if(id == queryString){
map.setLayoutProperty('route-'+id+'', 'visibility', 'visible');
var bboxTravel = turf.bbox(line);
var bounds = [[bboxTravel[0],bboxTravel[1]],[bboxTravel[2],bboxTravel[3]]]
map.fitBounds(bounds, {
padding: 65,
speed: 0.5, // make the flying slow
curve: 0.8, // change the speed at which it zooms out
// This can be any easing function: it takes a number between
// 0 and 1 and returns another number between 0 and 1.
easing: function(
t) {
return t;
},
});
var sentDate = plane.properties.sentDate[0]
var deliveryDate = plane.properties.deliveryDate[0]
var popup = new mapboxgl.Popup()
.setLngLat(currentPosition.geometry.coordinates)
.setHTML("<b>Origine:</b> "+plane.properties.startName+"<br><em>"+sentDate+"</em><br><b>Destination:</b> "+plane.properties.destName+"<br><em>"+deliveryDate+"</em>")
.addTo(map);
//removing route
popup.on('close', function(){
map.setLayoutProperty('route-'+id+'', 'visibility', 'none');
});
}
});
});
})
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: '<div class="pulse-icon-anim" style="border-color:#'+target.data.color+'"></div>',
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('<table><tbody><tr><th style="text-align:center">'+target.data.startName+'</th><th>&nbsp;<i class="fas fa-plane"></i>&nbsp;</th><th style="text-align:center">'+target.data.destName+'</th></tr><tr><th style="text-align:center"><small>'+moment(target.data.startTime).fromNow()+'</small></th><th></th><th style="text-align:center"><small>'+moment(target.data.deliveryTime).fromNow()+'</small></th></tr></tbody></table>')
}
//other languages
else{
target.popup.setContent('<table><tbody><tr><th style="text-align:center">'+target.data.startName+'</th><th>&nbsp;<i class="fas fa-plane"></i>&nbsp;</th><th style="text-align:center">'+target.data.destName+'</th></tr><tr><th style="text-align:center"><small>'+moment(target.data.startTime).fromNow()+'</small></th><th></th><th style="text-align:center"><small>'+moment(target.data.deliveryTime).fromNow()+'</small></th></tr></tbody></table>')
}
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';
}
});
})()

View File

@@ -1,111 +1,207 @@
// init text editor in modal
var quill = new Quill('#messageTextArea', {
modules: {
toolbar: [
[{ 'size': ['small', false, 'large'] }],
[{ 'font': [] }],
['bold', 'italic', 'underline','strike'],
[{ 'color': [] }],
]
},
placeholder: '',
theme: 'snow' // or 'bubble',
});
$("#sendNewPlane").on('click',function(){
//hiding navbar
$('.navbar-collapse').collapse('hide');
//hiding modal
$("#newPlaneModal").modal('hide')
var line = turf.lineString([expeLoc.center,destLoc.center]) //create line between start and end
var length = turf.length(line) //get length in Km
var speed = 30 //speed in km/h
var time = length/speed //time to delivery in hours
//get the local time with TZ for starting point
$.getJSON('https://api.mapbox.com/v4/examples.4ze9z6tv/tilequery/'+expeLoc.center[0]+','+expeLoc.center[1]+'.json?access_token='+mapboxgl.accessToken+'',function(startTime){
var expeTimezone = startTime.features[0].properties.TZID;
var sentDate = moment.tz(new Date(), expeTimezone);
sentDate = [sentDate.format(),expeTimezone]
//get the local time with TZ for end point
$.getJSON('https://api.mapbox.com/v4/examples.4ze9z6tv/tilequery/'+destLoc.center[0]+','+destLoc.center[1]+'.json?access_token='+mapboxgl.accessToken+'',function(endTime){
var destTimezone = endTime.features[0].properties.TZID;
var endDate = moment.tz(new Date(), destTimezone);
var deliveryDate = endDate.add(time, 'hours') // adding hours
deliveryDate = [endDate.format(),destTimezone]
//storing the endDate in GMT+0 in seconds for the query
var deliverySecondsServer = moment.tz(new Date(), "Europe/London").add(time, 'hours').unix()
var publicMessage = $("#publicMessage").prop("checked")
var message = $("#messageTextArea").val()
var data = {
'message':message,
'public':publicMessage,
'expeMail':$("#expeMail").val(),
'destMail':$("#destMail").val(),
'expeName':expeLoc.name,
'destName':destLoc.name,
'expeCoordo':expeLoc.center,
'destCoordo':destLoc.center,
'sentDate': sentDate,
'deliveryDate':deliveryDate,
'deliverySecondsServer':deliverySecondsServer,
}
//sending confirm mail
//sending notif mail
//scheduling mail
//adding the plane
var planes = db.collection('planes')
if (!publicMessage){ //removing message from DB if not public
data.message = ''
}
planes.add({
public: data.public,
message:data.message,
destName: data.destName,
destCoordo: data.destCoordo,
startName: data.expeName,
startCoordo: data.expeCoordo,
sentDate: data.sentDate,
deliveryDate: data.deliveryDate,
deliverySecondsServer: data.deliverySecondsServer
});
// creating image for plane, need to link it to the inputs tog et entered values.
var canvas = document.getElementById("blankCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect(0,0,400,400);
ctx.fillStyle = "rgb(0,0,0)";
ctx.font = "9px Courier";
ctx.fillText("Message: .- / -- --- -. / ... . -. ... --..-- /",10,60);
ctx.fillText("Expediteur: leo.martine@yahoo.fr - Annemasse",10,300);
ctx.fillText("Destinataire: leo.martine@yahoo.fr - Lyon",10,320);
$("#front").attr('src',document.getElementById("blankCanvas").toDataURL())
//display and animate plane
$("#canvas3d").css('display','block')
animePlane()
//moving plane at the end
setInterval(function(){
$("#canvas3d").css('transition','transform 2500ms ease-in-out')
$("#canvas3d").css('transform','translate(50vw, -150vh)')
},4400);
//reloading page (to change)
setInterval(function(){
window.location.href = "http://127.0.0.1:8887/?plane=1FTMbm9V9eindbwoJ9uW";
},5500);
})
});
// init text editor in modal
var quill = new Quill('#messageTextArea', {
modules: {
toolbar: [
[{ 'size': ['small', false, 'large'] }],
[{ 'font': [] }],
['bold', 'italic', 'underline','strike'],
[{ 'color': [] }],
]
},
placeholder: '',
theme: 'snow' // or 'bubble',
});
// get random number between interval
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
// get random color
function getRandomColor() {
var colors = ['66FF00','FF5555','FFE419','2A7FFF','BC5FD3','FF6600','ECECEC']
var color = colors[Math.floor(Math.random() * colors.length)];
return color
}
//init tooltips in form
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
//closing navbar antholoy about on open
$('#newPlaneModal').on('shown.bs.modal', function (e) {
$('.navbar-collapse').collapse('hide');
$('#anthology').css('opacity','0')
$('#anthology').css('visibility','hidden')
$('#backToMap').css('opacity','0')
$('#backToMap').css('visibility','hidden')
$('#about').css('visibility','hidden');
$('#about').css('opacity','0')
anthologyOpen = 0
aboutOpen = 0
})
$("#sendNewPlane").on('click',function(){
//hiding modal
$("#newPlaneModal").modal('hide')
var deliveryMethod = $("#selectTime").val()
var time; //time to delivery in hours
if(deliveryMethod == '3days'){
time = 24*3.14
}
else if(deliveryMethod == '7days'){
time = 24*7
}
else if(deliveryMethod == '30days'){
time = 24*30
}
else if(deliveryMethod == '365days'){
time = 24*365
}
else if(deliveryMethod == 'random'){
var speed = randomIntFromInterval(5.05, 25.82)
var line = turf.lineString([expeLoc.center,destLoc.center]) //create line between start and end
var length = turf.length(line) //get length in Km
var additionalTime = length/speed;
time = 37.68 + additionalTime //minimum 37.68 hours + additional time based on random speed
}
//get the local time with TZ for starting point
$.getJSON('https://secure.geonames.org/timezoneJSON?lat='+expeLoc.center[1]+'&lng='+expeLoc.center[0]+'&username=avionpoeme',function(startTime){
var expeTimezone = startTime.timezoneId;
var sentDate = moment.tz(new Date(), expeTimezone).unix();
//get the local time with TZ for end point
$.getJSON('https://secure.geonames.org/timezoneJSON?lat='+destLoc.center[1]+'&lng='+destLoc.center[0]+'&username=avionpoeme',function(endTime){
var destTimezone = endTime.timezoneId;
var endDate = moment.tz(new Date(), destTimezone)
var deliveryDate = endDate.add(time, 'hours').unix(); // adding hours
//storing the endDate in GMT+0 in seconds for the query
var deliverySecondsServer = moment.tz(new Date(), "Europe/Berlin").add(time, 'hours').unix()
var publicMessage = $("#public").prop("checked")
var expeKnown = $("#expeKnown").prop("checked")
if(expeKnown == true){
expeKnown = false
}
else{
expeKnown = true
}
var message = quill.root.innerHTML
var randomColor = getRandomColor()
console.log(message)
var data = {
'message':encodeURIComponent(message),
'expeMail':$("#expeMail").val(),
'expeKnown':expeKnown,
'expeLang':lang,
'destLang':$("#selectDestLang").val(),
'startLat':expeLoc.center[1],
'startLon':expeLoc.center[0],
'startName':expeLoc.name,
'startTime':sentDate,
'startTZ':expeTimezone,
'destMail':$("#destMail").val(),
'destLat':destLoc.center[1],
'destLon':destLoc.center[0],
'destName':destLoc.name,
'public':publicMessage,
'color':randomColor,
'deliveryTime':deliveryDate,
'deliveryTZ':destTimezone,
'deliveryTimeServer':deliverySecondsServer,
'deliveryMethod':$("#selectTime").val()
}
var query = 'avionpoeme.php?'+
'message='+data.message+'&'+
'expeMail='+data.expeMail+'&'+
'expeKnown='+data.expeKnown+'&'+
'expeLang='+data.expeLang+'&'+
'destLang='+data.destLang+'&'+
'startLat='+data.startLat+'&'+
'startLon='+data.startLon+'&'+
'startName='+data.startName+'&'+
'startTime='+data.startTime+'&'+
'startTZ='+data.startTZ+'&'+
'destMail='+data.destMail+'&'+
'destLat='+data.destLat+'&'+
'destLon='+data.destLon+'&'+
'destName='+data.destName+'&'+
'public='+data.public+'&'+
'color='+data.color+'&'+
'deliveryTime='+data.deliveryTime+'&'+
'deliveryTZ='+data.deliveryTZ+'&'+
'deliveryTimeServer='+data.deliveryTimeServer+'&'+
'deliveryMethod='+data.deliveryMethod+'';
$.post(query, function(result) {
result = result.replace(/'/g, '"');
console.log(result)
result = $.parseJSON(result)
var planeId = Number(result.uid);
//selecting proper color for back
$("#back").attr("src","src/img/back-"+data.color+".jpg");
// creating image for plane, need to link it to the inputs tog et entered values.
var message = quill.root.innerHTML
var canvas1 = document.getElementById("blankCanvas1"),
html = quill.root.innerHTML;
rasterizeHTML.drawHTML(html, canvas1,{zoom:0.7}).then(function success(renderResult) {
var canvas2 = document.getElementById("blankCanvas2");
var ctx = canvas2.getContext("2d");
ctx.fillStyle = "#"+data.color;
ctx.fillRect(0,0,400,400);
ctx.drawImage(canvas1, 0, 0,400,400)
ctx.fillStyle = "rgb(0,0,0)";
ctx.font = "9px Courier";
$("#front").attr('src',document.getElementById("blankCanvas2").toDataURL())
//display and animate plane
$("#canvas3d").css('display','block')
animePlane()
//moving plane at the end
setInterval(function(){
$("#canvas3d").css('transition','transform 2500ms ease-in-out')
$("#canvas3d").css('transform','translate(50vw, -150vh)')
},4400);
//reloading page (to change)
setInterval(function(){
window.location.href ='https://avion-poe.me?avion='+planeId+'';
},5500);
})
})
})
});
})

164
src/translation.js Normal file
View File

@@ -0,0 +1,164 @@
var lang = 'en'
var userLang = navigator.userLanguage || navigator.language;
if (userLang){
lang = userLang.substring(0,2)
}
//loading the lang.json file
$(document).ready(function(){
translateUI(lang)
$.getJSON("lang/lang.json", function(data){
//creating dropdown list of languages in navbar
for (var key in data){
$("#langChoices").append( '<a class="dropdown-item langSelect" value="'+key+'" href="#">'+data[key]+'</a>' )
$("#selectDestLang").append( '<option value="'+key+'" href="#">'+data[key]+'</option>' )
}
//setting the user lang
if(data[lang]){
//$("#navbarDropdownLang").html(data[lang])
translateUI(lang)
}
//or english if not in list
else{
//$("#navbarDropdownLang").html("English")
translateUI('en')
}
$(".langSelect").on('click',function(e){
lang = e.currentTarget.attributes[1].value
translateUI(lang)
//$("#navbarDropdownLang").html($(this).html())
})
}).fail(function(error){
console.log(error);
});
});
var dictionnary = []
function translateUI(l){
$.getJSON("lang/"+l+"", function(s){
//console.log(s)
dictionnary = s
//if arabic : display left to right (ltr) + troubleshooting a lot of individual elements
if (lang == "ar"){
//navbar
$("nav").css('direction','rtl')
$(".nav-menus").removeClass('mr-auto')
$(".nav-button").addClass('mr-auto')
//form
// $(".ql-container").css('direction','rtl')
// $(".ql-container").css('float','right')
// $(".ql-editor").css('float','right')
// $(".ql-editor p").css('float','right')
$(".modal-content").css('direction','rtl')
$(".bold").css('float','right')
$("#public").css('margin-left','5px')
$("#prive").css('margin-left','5px')
$("#newPlaneModalAnonyme").css('margin-right','25px')
$("#newPlaneModalCancel").css('margin-left','8px')
$("#closeModal").css('margin-left','0px')
$("#closeModal").css('padding-left','0px')
//anthology
$("#anthology").css('direction','rtl')
$("#anthologyDisclaimer").css('float','right')
}
else{
//navbar
$("nav").css('direction','ltr')
$(".nav-menus").addClass('mr-auto')
$(".nav-button").removeClass('mr-auto')
//form
// $(".ql-container").css('direction','ltr')
// $(".ql-container").css('float','left')
// $(".ql-editor").css('float','left')
// $(".ql-editor p").css('float','none')
$(".modal-content").css('direction','ltr')
$(".bold").css('float','left')
$("#public").css('margin-left','0px')
$("#prive").css('margin-left','0px')
$("#newPlaneModalAnonyme").css('margin-right','0px')
$("#newPlaneModalCancel").css('margin-left','0px')
//anthology
$("#anthology").css('direction','ltr')
$("#anthologyDisclaimer").css('float','left')
}
//changing all strings
//main page
$('head title', window.parent.document).text(s.avionpoeme);
$("#navTitle").html(s.avionpoeme)
$("#buttonAnthology").html(s.anthologie)
$("#buttonAbout").html(s.apropos)
$("#buttonNewPlane").val(s.lancer_avion+" "+nbPlane+"/100")
//new plane form
$("#newPlaneModalTitle").html(s.lancer_avion)
$("#newPlaneModalMessage").html(s.message)
$("#newPlaneModalPrive").html(s.prive)
$("#newPlaneModalPublic").html(s.public)
$("#flightTime").html(s.temps_de_vol)
$("#newPlaneModalRandom").html(s.aléatoire)
$("#newPlaneModal3j").html(s.trois_jours)
$("#newPlaneModal7j").html(s.sept_jours)
$("#newPlaneModal30j").html(s.trente_jours)
$("#newPlaneModal365j").html(s.unan_jours)
$("#newPlaneModalExpediteur").html(s.expediteur)
$("#newPlaneModalDestinataire").html(s.destinataire)
$("#newPlaneModalAnonyme").html(s.anonyme)
$("#newPlaneModalCancel").html(s.annuler)
$("#sendNewPlane").html(s.lancer)
$("#destLang").html(s.langue_destinataire)
$("#expeMail").attr("placeholder", s.expeMail_placeholder)
$("#expeGeocoderPhoton").attr("placeholder", s.expeLoc_placeholder)
$("#destMail").attr("placeholder", s.destMail_placeholder)
$("#destGeocoderPhoton").attr("placeholder", s.destLoc_placeholder)
$('#anonymeTooltip').attr("title", s.anonyme_tooltip).tooltip("_fixTitle");
$('#publicTooltip').attr("title", s.public_tooltip).tooltip("_fixTitle");
$('#selectDestLang option[value="'+lang+'"]').prop('selected', true); //selecting by default recipient language same as interface
//Anthology
displayAnthology()
$("#anthologyTitle").html(s.anthologie)
$("#anthologyDisclaimer").html(s.suppr_message_public)
$("#closeAnthologyAbout").html(s.retour_carte)
//About
$("#aboutTitle").html(s.apropos)
$("#librairies").html(s.librairies)
$("#mapSources").html(s.source_carte)
$("#mapBackground").html(s.map_background)
$("#clouds").html(s.clouds)
$.getJSON("lang/about.json", function(e){
if(lang !== 'en' && lang !== 'fr' && lang !== 'de'){
$("#aboutText").html(e[0].en)
}
else{
$("#aboutText").html(e[0][lang])
}
})
//plane limit tooltip
if (nbPlane > 99){
$("#planeLimitTooltip").attr("title", s.AvionPoeme_epuise).tooltip("_fixTitle");
}
else{
var remainingPlanes = 100 - nbPlane;
s.NB_AvionPoeme_restant = s.NB_AvionPoeme_restant.replace('$NB_avion_poeme',remainingPlanes)
$("#planeLimitTooltip").attr("title", s.NB_AvionPoeme_restant).tooltip("_fixTitle");
}
})
.always(function(callback) {
//console.log( callback );
});
}
//hovering lang icon
$( "#navbarDropdownLang" ).mouseenter(function() {
$("#langIcon").attr("src","src/img/lang-hover.png");
});
$( "#navbarDropdownLang" ).mouseleave(function() {
$("#langIcon").attr("src","src/img/lang.png");
});