fix: synchro repository with production
33
src/about.js
Normal 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
@@ -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> • '+dictionnary.destination+': <b>'+results.destName+'</b> • '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> • '+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> • '+dictionnary.destination+': <b>'+results.destName+'</b> • '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> • '+dictionnary.temps_de_vol+': <b>'+flightTime(Number(results.startTime),Number(results.deliveryTime))+'</b></small><br><br>'+results.message+'<br><hr><br>'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
337
src/app.css
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
194
src/geocoder.js
@@ -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
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-66FF00.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-BC5FD3.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-C8AB37.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-ECECEC.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-FF5555.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-FF6600.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-FFE419.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
src/img/front.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/icon.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/img/lang-hover.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
src/img/lang.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
71
src/img/licence.svg
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
src/img/plane-2A7FFF.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
src/img/plane-66FF00.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
src/img/plane-BC5FD3.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
src/img/plane-C8AB37.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
src/img/plane-ECECEC.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
src/img/plane-FF5555.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
src/img/plane-FF6600.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
src/img/plane-FFE419.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
src/img/shadow.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
750
src/map.js
@@ -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> <i class="fas fa-plane"></i> </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> <i class="fas fa-plane"></i> </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';
|
||||
}
|
||||
});
|
||||
})()
|
||||
|
||||
316
src/newPlane.js
@@ -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
@@ -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");
|
||||
});
|
||||
|
||||
|
||||