setup
|
@ -53,14 +53,14 @@ MYPLAYERKEY=$(grep ${QRCODE} ~/.zen/game/players/*/secret.dunikey | cut -d ':' -
|
|||
[[ ! $MYPLAYERKEY ]] && MYPLAYERKEY="$HOME/.zen/game/players/.current/secret.dunikey"
|
||||
|
||||
## CCHANGE +
|
||||
$MY_PATH/../tools/jaklis/jaklis.py -k $MYPLAYERKEY send -d "${QRCODE}" -t "CONTACT" -m "Rendez vous
|
||||
$MY_PATH/../tools/jaklis/jaklis.py-n $myGCHANGE -k $MYPLAYERKEY send -d "${QRCODE}" -t "CONTACT" -m "Rendez vous
|
||||
sur https://astroport.copylaradio.com/
|
||||
Saisissez votre URL Youtube Favorite et un email
|
||||
Activez votre Capsule IPFS
|
||||
|
||||
/ipns/$ASTRONAUTENS"
|
||||
## CESIUM +
|
||||
$MY_PATH/../tools/jaklis/jaklis.py -n https://g1.data.e-is.pro -k $MYPLAYERKEY send -d "${QRCODE}" -t "CONTACT" -m "Rendez vous
|
||||
$MY_PATH/../tools/jaklis/jaklis.py -n $myCESIUM -k $MYPLAYERKEY send -d "${QRCODE}" -t "CONTACT" -m "Rendez vous
|
||||
sur https://astroport.copylaradio.com/
|
||||
Saisissez votre URL Youtube Favorite et un email
|
||||
Activez votre Capsule IPFS
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
# astroport.cancer.copylaradio.com
|
||||
/ip4/185.202.238.69/tcp/4001/p2p/12D3KooWDYpPdfCFf3CbKpcLNmyA2vmJs4JY55k8yje9R1MxSgdB
|
||||
|
||||
# astroport.aries.copylaradio.com
|
||||
/ip4/37.187.127.175/tcp/4001/p2p/12D3KooWSQYTxeoZZ39SNosEKxi7RUdGTtAQAqpKeZJxjzqqrZTx
|
||||
# cloud.copylaradio.com
|
||||
/dnsaddr/cloud.copylaradio.com/p2p/12D3KooWSQYTxeoZZ39SNosEKxi7RUdGTtAQAqpKeZJxjzqqrZTx
|
||||
|
||||
# astroport.sonic.copylaradio.com
|
||||
/ip4/161.97.174.60/tcp/4001/p2p/12D3KooWJki74EkJ8YUhrAfr2UwtQiJKBY94PYLmVnEQe9jo3aqC
|
||||
|
|
After Width: | Height: | Size: 11 KiB |
91
install.sh
|
@ -164,102 +164,15 @@ if [[ "$USER" == "pi" ]]; then ## PROPOSE QR_CODE PRINTER SUR RPI
|
|||
fi
|
||||
|
||||
echo "#############################################"
|
||||
echo "######### PATIENCE #########################"
|
||||
echo "######### SETUP #########################"
|
||||
echo "#############################################"
|
||||
|
||||
## Scripts pour systemd ou InitV (xbian)
|
||||
echo "=== SETUP IPFS SYSTEM"
|
||||
~/.zen/Astroport.ONE/tools/ipfs_setup.sh
|
||||
|
||||
echo "/ip4/127.0.0.1/tcp/5001" > ~/.ipfs/api
|
||||
|
||||
#### SETUP JAKLIS ###############################################################
|
||||
echo "=== SETUP jaklis"
|
||||
cd ~/.zen/Astroport.ONE/tools/jaklis
|
||||
sudo ./setup.sh
|
||||
|
||||
## XBIAN fail2ban ERROR correction ##
|
||||
#[....] Starting authentication failure monitor: fail2ban No file(s) found for glob /var/log/auth.log
|
||||
[[ "$USER" == "xbian" ]] && sudo sed -i "s/auth.log/faillog/g" /etc/fail2ban/paths-common.conf
|
||||
|
||||
### MODIFIYING /etc/sudoers ###
|
||||
[[ "$USER" == "xbian" ]] && echo "xbian ALL=(ALL) NOPASSWD:ALL" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/astroport')
|
||||
|
||||
# PERSONNAL DEFCON LEVEL
|
||||
# cp ~/.zen/Astroport.ONE/DEFCON ~/.zen/
|
||||
|
||||
if [[ "$USER" == "xbian" ]]
|
||||
then
|
||||
echo "enabling ipfs initV service autostart"
|
||||
cd /etc/rc2.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
cd /etc/rc3.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
cd /etc/rc4.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
cd /etc/rc5.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
|
||||
cd /etc/rc0.d && sudo ln -s ../init.d/ipfs K01ipfs
|
||||
cd /etc/rc1.d && sudo ln -s ../init.d/ipfs K01ipfs
|
||||
cd /etc/rc6.d && sudo ln -s ../init.d/ipfs K01ipfs
|
||||
|
||||
# Disable xbian-config auto launch
|
||||
echo 0 > ~/.xbian-config-start
|
||||
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# CREATE ~/astroport FILESYSTEM GATE
|
||||
mkdir -p ~/Astroport/film
|
||||
mkdir -p ~/Astroport/serie
|
||||
mkdir -p ~/Astroport/anime
|
||||
mkdir -p ~/Astroport/page
|
||||
mkdir -p ~/Astroport/web
|
||||
mkdir -p ~/Astroport/video
|
||||
echo '${TYPE};${MEDIAID};${YEAR};${TITLE};${SAISON};${GENRES};_IPNSKEY_;${RES};/ipfs/_IPFSREPFILEID_/$URLENCODE_FILE_NAME' > ~/Astroport/ajouter_video.modele.txt
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
echo "#############################################"
|
||||
## https://darktrojan.github.io/openwith/webextension.html"
|
||||
~/.zen/Astroport.ONE/open_with_linux.py install
|
||||
|
||||
echo "#############################################
|
||||
# NOURRISSEZ VOTRE BLOB depuis Firefox !!
|
||||
# https://addons.mozilla.org/firefox/addon/open-with
|
||||
#############################################
|
||||
## $HOME/.zen/Astroport.ONE/ajouter_media.sh ##
|
||||
#############################################"
|
||||
|
||||
### ADD 20h12.sh CRON ###############
|
||||
~/.zen/Astroport.ONE/tools/cron_VRFY.sh ON
|
||||
|
||||
########################################################################
|
||||
# SUDO permissions
|
||||
########################################################################
|
||||
## USED FOR fail2ban-client (DEFCON)
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/fail2ban-client" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/fail2ban-client')
|
||||
## USED FOR RAMDISK (video live streaming)
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/bin/mount" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/mount')
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/bin/umount" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/umount')
|
||||
## USED FOR SYSTEM UPGRADE
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/apt-get" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/apt-get')
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/apt" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/apt')
|
||||
## USED FOR "systemctl restart ipfs"
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/bin/systemctl" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/systemctl')
|
||||
## USED FOR "sudo youtube-dl -U"
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/local/bin/youtube-dl" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/youtube-dl')
|
||||
|
||||
|
||||
echo "#############################################"
|
||||
echo "# ADDING <<<Astroport>>> DESKTOP SHORTCUT"
|
||||
[[ -d ~/Bureau ]] && sed "s/_USER_/$USER/g" ~/.zen/Astroport.ONE/astroport.desktop > ~/Bureau/astroport.desktop && chmod +x ~/Bureau/astroport.desktop
|
||||
[[ -d ~/Desktop ]] && sed "s/_USER_/$USER/g" ~/.zen/Astroport.ONE/astroport.desktop > ~/Desktop/astroport.desktop && chmod +x ~/Desktop/astroport.desktop
|
||||
|
||||
mkdir -p ~/.zen/tmp
|
||||
|
||||
|
||||
echo "#############################################"
|
||||
## INSTALL yt-dlp & SYMLINK youtube-dl
|
||||
~/.zen/Astroport.ONE/youtube-dl.sh
|
||||
~/.zen/Astroport.ONE/setup.sh
|
||||
|
||||
|
||||
echo "#############################################"
|
||||
|
|
16
search2
|
@ -1,16 +0,0 @@
|
|||
#!/bin/bash
|
||||
clear
|
||||
echo "------------------------------------------------------------------------------"
|
||||
if [ "$1" == "" ]; then
|
||||
echo " Nothing to search for!"
|
||||
else
|
||||
echo " Searching for "$1" recursively. Please Wait..."
|
||||
echo "------------------------------------------------------------------------------"
|
||||
grep -h -r --exclude=B00 -H --colour=always "$1" ./
|
||||
fi
|
||||
echo "------------------------------------------------------------------------------"
|
||||
if [ "$2" != "" ]; then
|
||||
echo " To replace \"$1\" whith \"$2\", please run"
|
||||
echo " grep -rl '$1' ./ | while read file; do sed -i 's~$1~$2~g' \$file; done"
|
||||
fi
|
||||
## THIS IS A GREAT RETRO ENGINEERING AND CODING TOOLS
|
|
@ -0,0 +1,101 @@
|
|||
#!/bin/bash
|
||||
################################################################################
|
||||
# Author: Fred (support@qo-op.com)
|
||||
# Version: 0.1
|
||||
# License: AGPL-3.0 (https://choosealicense.com/licenses/agpl-3.0/)
|
||||
################################################################################
|
||||
MY_PATH="`dirname \"$0\"`" # relative
|
||||
MY_PATH="`( cd \"$MY_PATH\" && pwd )`" # absolutized and normalized
|
||||
ME="${0##*/}"
|
||||
|
||||
echo "#############################################"
|
||||
echo ">>>>>>>>>>> SYSTEM SETUP "
|
||||
echo "#############################################"
|
||||
#### SETUP JAKLIS ###############################################################
|
||||
echo "=== SETUP jaklis"
|
||||
cd ~/.zen/Astroport.ONE/tools/jaklis
|
||||
sudo ./setup.sh
|
||||
|
||||
## XBIAN fail2ban ERROR correction ##
|
||||
#[....] Starting authentication failure monitor: fail2ban No file(s) found for glob /var/log/auth.log
|
||||
[[ "$USER" == "xbian" ]] && sudo sed -i "s/auth.log/faillog/g" /etc/fail2ban/paths-common.conf
|
||||
|
||||
### MODIFIYING /etc/sudoers ###
|
||||
[[ "$USER" == "xbian" ]] && echo "xbian ALL=(ALL) NOPASSWD:ALL" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/astroport')
|
||||
|
||||
# PERSONNAL DEFCON LEVEL
|
||||
# cp ~/.zen/Astroport.ONE/DEFCON ~/.zen/
|
||||
|
||||
if [[ "$USER" == "xbian" ]]
|
||||
then
|
||||
echo "enabling ipfs initV service autostart"
|
||||
cd /etc/rc2.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
cd /etc/rc3.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
cd /etc/rc4.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
cd /etc/rc5.d && sudo ln -s ../init.d/ipfs S02ipfs
|
||||
|
||||
cd /etc/rc0.d && sudo ln -s ../init.d/ipfs K01ipfs
|
||||
cd /etc/rc1.d && sudo ln -s ../init.d/ipfs K01ipfs
|
||||
cd /etc/rc6.d && sudo ln -s ../init.d/ipfs K01ipfs
|
||||
|
||||
# Disable xbian-config auto launch
|
||||
echo 0 > ~/.xbian-config-start
|
||||
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# CREATE ~/astroport FILESYSTEM GATE
|
||||
mkdir -p ~/Astroport/film
|
||||
mkdir -p ~/Astroport/serie
|
||||
mkdir -p ~/Astroport/anime
|
||||
mkdir -p ~/Astroport/page
|
||||
mkdir -p ~/Astroport/web
|
||||
mkdir -p ~/Astroport/video
|
||||
echo '${TYPE};${MEDIAID};${YEAR};${TITLE};${SAISON};${GENRES};_IPNSKEY_;${RES};/ipfs/_IPFSREPFILEID_/$URLENCODE_FILE_NAME' > ~/Astroport/ajouter_video.modele.txt
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
echo "#############################################"
|
||||
## https://darktrojan.github.io/openwith/webextension.html"
|
||||
~/.zen/Astroport.ONE/open_with_linux.py install
|
||||
|
||||
echo "#############################################
|
||||
# NOURRISSEZ VOTRE BLOB depuis Firefox !!
|
||||
# https://addons.mozilla.org/firefox/addon/open-with
|
||||
#############################################
|
||||
## $HOME/.zen/Astroport.ONE/ajouter_media.sh ##
|
||||
#############################################"
|
||||
|
||||
### ADD 20h12.sh CRON ###############
|
||||
~/.zen/Astroport.ONE/tools/cron_VRFY.sh ON
|
||||
|
||||
########################################################################
|
||||
# SUDO permissions
|
||||
########################################################################
|
||||
## USED FOR fail2ban-client (DEFCON)
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/fail2ban-client" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/fail2ban-client')
|
||||
## USED FOR RAMDISK (video live streaming)
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/bin/mount" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/mount')
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/bin/umount" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/umount')
|
||||
## USED FOR SYSTEM UPGRADE
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/apt-get" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/apt-get')
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/bin/apt" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/apt')
|
||||
## USED FOR "systemctl restart ipfs"
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/bin/systemctl" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/systemctl')
|
||||
## USED FOR "sudo youtube-dl -U"
|
||||
echo "$USER ALL=(ALL) NOPASSWD:/usr/local/bin/youtube-dl" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/youtube-dl')
|
||||
|
||||
|
||||
echo "#############################################"
|
||||
echo "# ADDING <<<Astroport>>> DESKTOP SHORTCUT"
|
||||
[[ -d ~/Bureau ]] && sed "s/_USER_/$USER/g" ~/.zen/Astroport.ONE/astroport.desktop > ~/Bureau/astroport.desktop && chmod +x ~/Bureau/astroport.desktop
|
||||
[[ -d ~/Desktop ]] && sed "s/_USER_/$USER/g" ~/.zen/Astroport.ONE/astroport.desktop > ~/Desktop/astroport.desktop && chmod +x ~/Desktop/astroport.desktop
|
||||
|
||||
mkdir -p ~/.zen/tmp
|
||||
|
||||
|
||||
echo "#############################################"
|
||||
## INSTALL yt-dlp & SYMLINK youtube-dl
|
||||
~/.zen/Astroport.ONE/youtube-dl.sh
|
||||
|
|
@ -388,7 +388,7 @@ myGCHANGE="https://www.gchange.fr"
|
|||
myCESIUM="https://g1.data.e-is.pro"
|
||||
myHOST="$(myHostName)"
|
||||
myIP="$(myIp)"
|
||||
myIPFS="http://$(myHName):8080"
|
||||
myIPFS="http://$(myHName).local:8080"
|
||||
myIPFSGW="$(myIpfsGw)"
|
||||
myTUBE="$(myTube)"
|
||||
myASTROTUBE="https://$(myAstroTube)"
|
||||
|
|
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 305 KiB |
After Width: | Height: | Size: 765 B |
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>ASTROPORT PORTAL : http://astroport.localhost:1234</title>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="index_fichiers/demo.css">
|
||||
<link rel="stylesheet" href="index_fichiers/jquery-ui.min.css">
|
||||
|
||||
<script type="text/javascript" src="index_fichiers/requestanimationframe.polyfill.js"></script>
|
||||
|
||||
<script type="text/javascript" src="index_fichiers/jquery-1.7.2.min.js"></script>
|
||||
<script type="text/javascript" src="index_fichiers/instascan.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="index_fichiers/jquery-ui.0.min.js"></script>
|
||||
<script type="text/javascript" src="index_fichiers/sphere-hacked.js"></script>
|
||||
<script type="text/javascript" src="index_fichiers/jquery.earth-3d.js"></script>
|
||||
<script type="text/javascript" src="index_fichiers/demo.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<a target=_blank href="https://astroport.copylaradio.com"><img style="position: absolute; top: 0; right: 0; border: 0;" src="l0g0.png" alt="Entrez par le Le Claude"></a>
|
||||
|
||||
<h1><a target=_blank href="http://astroport.localhost:1234">Astroport Ŋ1</a></h1>
|
||||
|
||||
<div class="subtitle">Une Planète à Vous<br>Un Internet à Nous</div>
|
||||
<div id="demo">
|
||||
<div id="description">
|
||||
<h2>Utilisez <a href="https://cesium.app">Cesium</a> !</h2>
|
||||
|
||||
<p><img src="/ipfs/QmWUpjGFuF7NhpXgkrCmx8Tbu4xjcFpKhE7Bsvt6HeKYxu/g1ticket_qrcode.png"></p>
|
||||
<h3>Ajoutez en commentaire l'email de vos amis...</h3>
|
||||
<p>NB: "fred@g1sms.fr" a ouvert son compte à <a href="https://opencollective.com/monnaie-libre/projects/stiits">LaSTI</a> il bénéficie du service "G1PalPé"</p>
|
||||
<br>
|
||||
<p><a href="https://opencollective.com/monnaie-libre/projects/coeurbox">La♥BOX</a>, téléporte vos DATA 👍 à l'abris dans "Le Claude"</p>
|
||||
<p>Powered by <a href="https://astroport.com">Astroport</a></p>
|
||||
|
||||
<h2>Scannez votre QRCode</h2>
|
||||
|
||||
<video id="preview" style="transform: scaleX(-1);width: 220px;height: 220px;"></video>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
let scanner = new Instascan.Scanner({ video: document.getElementById('preview') });
|
||||
scanner.addListener('scan', function (content) {
|
||||
alert("qrcode="+content);
|
||||
$.ajax({
|
||||
url: "http://astroport.localhost:1234",
|
||||
data: "qrcode="+content,
|
||||
type: 'GET'
|
||||
});
|
||||
//
|
||||
// $(location).attr('href', content);
|
||||
// Receiver : echo -e 'HTTP/1.1 200 OK\r\n' | nc -l -p 1234 -q 1 | grep '^GET' | cut -d' ' -f2 | cut -d'=' -f 2
|
||||
});
|
||||
|
||||
Instascan.Camera.getCameras().then(function (cameras) {
|
||||
if (cameras.length > 0) {
|
||||
scanner.start(cameras[0]);
|
||||
} else {
|
||||
console.error('No cameras found.');
|
||||
}
|
||||
}).catch(function (e) {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="showoff">
|
||||
<div id="container">
|
||||
<h2>Envoyez la Ḡ1 au Monde</h2>
|
||||
<canvas id="sphere" width="400" height="400"></canvas>
|
||||
<div id="glow-shadows" class="earth"></div>
|
||||
<canvas id="flights" width="400" height="400"></canvas>
|
||||
<div id="locations"></div>
|
||||
</div>
|
||||
<div class="choose_example">
|
||||
Choose example: <select id="example">
|
||||
<option value="simple">Simple earth</option>
|
||||
<option value="simple_tilted">Simple tilted earth</option>
|
||||
<option value="simple_mars">Simple mars</option>
|
||||
<option value="locations">Earth with locations</option>
|
||||
<option value="flights" selected>Earth with locations and flights</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="code">
|
||||
<a href="#" onclick="$('#example_code').show(); $(this).hide().siblings('a').show(); return false;">Show code</a>
|
||||
<a href="#" style="display: none;" onclick="$('#example_code').hide(); $(this).hide().siblings('a').show(); return false;">Hide code</a>
|
||||
<textarea id="example_code" onclick="this.focus();this.select();"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,149 @@
|
|||
body {
|
||||
background: black;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #DDD;
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 10px;
|
||||
font-size: 40px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 20px;
|
||||
margin-bottom: 20px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#demo {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#description {
|
||||
text-align: left;
|
||||
float: left;
|
||||
width: 49%;
|
||||
max-width: 500px;
|
||||
padding-top: 50px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#showoff {
|
||||
float: left;
|
||||
width: 49%;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#sphere, #flights, #glow-shadows, #locations, #drag {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#glow-shadows {
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
#glow-shadows.earth {
|
||||
background: url(../images/earth-glow-shadows.png);
|
||||
}
|
||||
|
||||
#glow-shadows.mars {
|
||||
background: url(../images/mars-glow-shadows.png);
|
||||
}
|
||||
|
||||
.location {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
border: 2px solid white;
|
||||
margin-left: -5px;
|
||||
margin-top: -5px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.location:hover {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-left: -7.5px;
|
||||
margin-top: -7.5px;
|
||||
}
|
||||
|
||||
.flight {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 25px;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
background: url(../images/plain.png);
|
||||
background-size: 100% 100%;
|
||||
margin-left: -12px;
|
||||
margin-top: -12.5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.flight:hover {
|
||||
width: 36px;
|
||||
height: 37.5px;
|
||||
margin-left: -18px;
|
||||
margin-top: -18.75px;
|
||||
}
|
||||
|
||||
|
||||
.choose_example {
|
||||
width: 35%;
|
||||
margin-left: 32.5%;
|
||||
}
|
||||
|
||||
#example_code {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border: 0px;
|
||||
resize: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.code {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.social {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.social.twitter {
|
||||
vertical-align: -3px;
|
||||
}
|
||||
|
||||
.social.google {
|
||||
vertical-align: -7px;
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
var examples = {};
|
||||
|
||||
examples['simple'] = function() {
|
||||
$('#sphere').earth3d({
|
||||
dragElement: $('#locations') // where do we catch the mouse drag
|
||||
});
|
||||
};
|
||||
|
||||
examples['simple_tilted'] = function() {
|
||||
$('#sphere').earth3d({
|
||||
dragElement: $('#locations'), // where do we catch the mouse drag
|
||||
sphere: { // rotation and size of the planet
|
||||
tilt: 40,
|
||||
turn: 20,
|
||||
r: 10
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
examples['simple_mars'] = function() {
|
||||
$('#sphere').earth3d({
|
||||
texture: 'images/mars1024x1024.jpg', // texture used by planet
|
||||
dragElement: $('#locations') // where do we catch the mouse drag
|
||||
});
|
||||
};
|
||||
|
||||
examples['locations'] = function() {
|
||||
/* defining locations to display.
|
||||
Each position must have a key, an alpha and delta position (or x and y if you want to display a static location).
|
||||
Any additional key can be reached via callbacks functions.
|
||||
*/
|
||||
var locations = {
|
||||
obj1: {
|
||||
alpha: Math.PI / 4,
|
||||
delta: 0,
|
||||
name: 'location 1'
|
||||
},
|
||||
obj2: {
|
||||
alpha: 1 * Math.PI / 4,
|
||||
delta: -2 * Math.PI / 4,
|
||||
name: 'location 2'
|
||||
},
|
||||
obj3: {
|
||||
alpha: 2 * Math.PI / 4,
|
||||
delta: 0,
|
||||
name: 'location 3'
|
||||
},
|
||||
obj4: {
|
||||
alpha: 3 * Math.PI / 4,
|
||||
delta: 3 * Math.PI / 4,
|
||||
name: 'location 4'
|
||||
},
|
||||
obj5: {
|
||||
alpha: 2.2 * Math.PI / 4,
|
||||
delta: -1.1 * Math.PI / 4,
|
||||
name: 'location 5'
|
||||
}
|
||||
};
|
||||
$('#sphere').earth3d({
|
||||
locationsElement: $('#locations'),
|
||||
dragElement: $('#locations'), // where do we catch the mouse drag
|
||||
locations: locations
|
||||
});
|
||||
};
|
||||
|
||||
examples['flights'] = function() {
|
||||
/* defining locations to display.
|
||||
Each position must have a key, an alpha and delta position (or x and y if you want to display a static location).
|
||||
Any additional key can be reached via callbacks functions.
|
||||
*/
|
||||
var locations = {
|
||||
obj1: {
|
||||
alpha: Math.PI / 4,
|
||||
delta: 0,
|
||||
name: 'location 1'
|
||||
},
|
||||
obj2: {
|
||||
alpha: 1 * Math.PI / 4,
|
||||
delta: -2 * Math.PI / 4,
|
||||
name: 'location 2'
|
||||
},
|
||||
obj3: {
|
||||
alpha: 2 * Math.PI / 4,
|
||||
delta: 0,
|
||||
name: 'location 3'
|
||||
},
|
||||
obj4: {
|
||||
alpha: 3 * Math.PI / 4,
|
||||
delta: 3 * Math.PI / 4,
|
||||
name: 'location 4'
|
||||
},
|
||||
obj5: {
|
||||
alpha: 2.2 * Math.PI / 4,
|
||||
delta: -1.1 * Math.PI / 4,
|
||||
name: 'location 5'
|
||||
}
|
||||
};
|
||||
/* defining paths to display.
|
||||
Each path must have a key, an origin and a destination. The values are the location's key.
|
||||
You can, if you want to, define flights on these paths.
|
||||
Each flight has a key, a destination (the location's key) and a position.
|
||||
The position is the progress a fleet has made on its path.
|
||||
Any additional key can be reach via callbacks functions.
|
||||
*/
|
||||
var paths = {
|
||||
path: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj2',
|
||||
flights: {
|
||||
flight: {
|
||||
position: 0.25,
|
||||
destination: 'obj2',
|
||||
name: 'Flight 1'
|
||||
},
|
||||
flight2: {
|
||||
position: 0.25,
|
||||
destination: 'obj1',
|
||||
name: 'Flight 2'
|
||||
}
|
||||
}
|
||||
},
|
||||
path2: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj3',
|
||||
flights: {
|
||||
flight3: {
|
||||
position: 0.5,
|
||||
destination: 'obj3',
|
||||
name: 'Flight 3'
|
||||
}
|
||||
}
|
||||
},
|
||||
path3: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj4',
|
||||
flights: {
|
||||
flight4: {
|
||||
position: 0.5,
|
||||
destination: 'obj4',
|
||||
name: 'Flight 4'
|
||||
}
|
||||
}
|
||||
},
|
||||
path4: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj5'
|
||||
},
|
||||
path7: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj5',
|
||||
flights: {
|
||||
flight5: {
|
||||
position: 0.25,
|
||||
destination: 'obj7',
|
||||
name: 'Flight 5'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#sphere').earth3d({
|
||||
flightsCanvas: $('#flights'),
|
||||
locationsElement: $('#locations'),
|
||||
dragElement: $('#locations'), // where do we catch the mouse drag
|
||||
paths: paths,
|
||||
locations: locations
|
||||
});
|
||||
};
|
||||
|
||||
function selectExample(example) {
|
||||
$('#sphere').earth3d('destroy');
|
||||
$('#sphere').replaceWith($('<canvas id="sphere" width="400" height="400"></canvas>'));
|
||||
$('.location').remove();
|
||||
$('.flight').remove();
|
||||
$('#flights')[0].getContext('2d').clearRect(0, 0, 400, 400);
|
||||
if (example == 'simple_mars') {
|
||||
$('#glow-shadows').removeClass('earth').addClass('mars');
|
||||
} else {
|
||||
$('#glow-shadows').removeClass('mars').addClass('earth');
|
||||
}
|
||||
var code = examples[example].toString();
|
||||
code = code.substring(14);
|
||||
code = code.substring(0, code.length - 2);
|
||||
var lines = code.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
lines[i] = lines[i].substring(2);
|
||||
}
|
||||
code = lines.join("\n");
|
||||
$('#example_code').val(code);
|
||||
|
||||
examples[example]();
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
selectExample('flights');
|
||||
|
||||
$('#example').change(function() {
|
||||
selectExample($(this).val());
|
||||
});
|
||||
});
|
||||
|
||||
function addPath() {
|
||||
$('#sphere').earth3d('changePaths', {path2: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj3'
|
||||
}});
|
||||
}
|
|
@ -0,0 +1,849 @@
|
|||
|
||||
/*
|
||||
jquery.earth3d.js
|
||||
|
||||
jQuery ui plugin that allow you to draw a beautiful 3d spinning earth on canvas
|
||||
|
||||
Author: Sebastien Drouyer
|
||||
|
||||
Based on the amazing sphere.js plug of Sam Hasler
|
||||
|
||||
Licensed under the MIT license (MIT-LICENSE.txt)
|
||||
|
||||
http://sdrdis.github.com/jquery.earth-3d/
|
||||
|
||||
|
||||
|
||||
Depends:
|
||||
ui.core.js
|
||||
|
||||
|
||||
|
||||
|
||||
Options:
|
||||
* texture: texture map used by the planet
|
||||
|
||||
* sphere: rotation and size of the planet
|
||||
|
||||
* defaultSpeed: default spinning speed of the planet
|
||||
|
||||
* backToDefaultTime: time (in ms) to return by to default speed when planet is dragged
|
||||
|
||||
* locations: locations to display on the planet:
|
||||
* Each position must have a key, an alpha and delta position (or x and y if you want to display a static location).
|
||||
Any additional key can be reached via callbacks functions
|
||||
Example:
|
||||
{
|
||||
obj1: {
|
||||
alpha: Math.PI / 4,
|
||||
delta: 0,
|
||||
name: 'location 1'
|
||||
}
|
||||
}
|
||||
|
||||
* paths: paths and flights to display over the planet:
|
||||
Each path must have a key, an origin and a destination. The values are the location's key.
|
||||
You can, if you want to, define flights on these paths.
|
||||
Each flight has a key, a destination (the location's key) and a position.
|
||||
The position is the progress a fleet has made on its path.
|
||||
Any additional key can be reach via callbacks functions.
|
||||
Example:
|
||||
{
|
||||
path: {
|
||||
origin: 'obj1',
|
||||
destination: 'obj2',
|
||||
flights: {
|
||||
flight: {
|
||||
position: 0.25,
|
||||
destination: 'obj2',
|
||||
name: 'Flight 1'
|
||||
},
|
||||
flight2: {
|
||||
position: 0.25,
|
||||
destination: 'obj1',
|
||||
name: 'Flight 2'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* flightsCanvas: Dom element which is a canvas and where the flights and paths are drawn
|
||||
|
||||
* dragElement: Dom element where we catch the mouse drag
|
||||
|
||||
* locationsElement: Dom elements where the locations are drawn
|
||||
|
||||
* flightsCanvasPosition: position of the flight canvas (can be use if you have some gap between your planet and your flights
|
||||
|
||||
* pixelRadiusMultiplier: (TEMPORARY) used by the getSphereRadiusInPixel (see the functions)
|
||||
|
||||
* onInitLocation: callback function which allows you to define what to do when the locations are initialized
|
||||
* Parameters:
|
||||
* location: location (coming from locations option)
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onShowLocation: callback function which allows you to define what to do when a location becomes visible (was behind the planet and is now in front of it)
|
||||
* Parameters:
|
||||
* location: location (coming from locations option)
|
||||
* x: 2d left position
|
||||
* y: 2d top position
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onRefreshLocation: callback function which allows you to define what to do when a location is refreshed (it moves)
|
||||
* Parameters:
|
||||
* location: location (coming from locations option)
|
||||
* x: 2d left position
|
||||
* y: 2d top position
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onHideLocation: callback function which allows you to define what to do when a location becomes invisible (was in front of the planet and is now behind it)
|
||||
* Parameters:
|
||||
* location: location (coming from locations option)
|
||||
* x: 2d left position
|
||||
* y: 2d top position
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onInitFlight: callback function which allows you to define what to do when the flights are initialized
|
||||
* Parameters:
|
||||
* flight: flight (coming from flights option)
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onShowFlight: callback function which allows you to define what to do when a flight becomes visible (was behind the planet and is now in front of it)
|
||||
* Parameters:
|
||||
* flight: flight (coming from flights option)
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onRefreshFlight: callback function which allows you to define what to do when a flight is refreshed (it moves)
|
||||
* Parameters:
|
||||
* flight: flight (coming from flights option)
|
||||
* x: 2d left position
|
||||
* y: 2d top position
|
||||
* widget: earth3d widget object
|
||||
|
||||
* onHideFlight: callback function which allows you to define what to do when a flight becomes invisible (was in front of the planet and is now behind it)
|
||||
* Parameters:
|
||||
* flight: flight (coming from flights option)
|
||||
* widget: earth3d widget object
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Functions
|
||||
|
||||
* getSphereRadiusInPixel: function which allows you to get the sphere radius in pixel
|
||||
/!| WARNING: this function needs to be refactored, since I didn't find out (my maths courses are far away) how to
|
||||
get the exact value. I did a basic linear regression, but it is not exact, and you will have to change the pixelRadiusMultiplier
|
||||
option to get the correct value
|
||||
|
||||
* destroy: use this function when you want to destroy the object. It will throw a cancel animation frame, so the
|
||||
CPU won't be used anymore.
|
||||
|
||||
* changePaths: use this function when you want to update paths and flights (options on widget)
|
||||
it will add the callback functions support
|
||||
|
||||
*/
|
||||
var earth3d;
|
||||
(function($) {
|
||||
$.widget('ui.earth3d', {
|
||||
options: {
|
||||
texture: 'images/earth1024x1024.jpg',
|
||||
sphere: {
|
||||
tilt: 0,
|
||||
turn: 0,
|
||||
r: 10
|
||||
},
|
||||
defaultSpeed: 20,
|
||||
backToDefaultTime: 4000,
|
||||
locations: {
|
||||
},
|
||||
paths: {
|
||||
},
|
||||
flightsCanvas: null,
|
||||
dragElement: null,
|
||||
locationsElement: null,
|
||||
flightsCanvasPosition: {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
tiling: {horizontal: 1, vertical: 1},
|
||||
pixelRadiusMultiplier: 0.97,
|
||||
onInitLocation: function(location, widget) {
|
||||
var $elem = $('<div class="location"></div>');
|
||||
$elem.appendTo(widget.options.locationsElement);
|
||||
$elem.click(function() {
|
||||
alert('Clicked on ' + location.name);
|
||||
});
|
||||
location.$element = $elem;
|
||||
},
|
||||
onShowLocation: function(location, x, y) {
|
||||
location.$element.show();
|
||||
},
|
||||
onRefreshLocation: function(location, x, y) {
|
||||
//console.log(x, y);
|
||||
location.$element.css({
|
||||
left: x,
|
||||
top: y
|
||||
});
|
||||
},
|
||||
onHideLocation: function(location, x, y) {
|
||||
location.$element.hide();
|
||||
},
|
||||
onDeleteLocation: function(location) {
|
||||
location.$element.remove();
|
||||
},
|
||||
onInitFlight: function(flight, widget) {
|
||||
var $elem = $('<div class="flight"></div>');
|
||||
$elem.appendTo(widget.options.locationsElement);
|
||||
$elem.click(function() {
|
||||
alert('Clicked on ' + flight.name);
|
||||
});
|
||||
flight.$element = $elem;
|
||||
},
|
||||
onShowFlight: function(flight) {
|
||||
flight.$element.show();
|
||||
},
|
||||
onRefreshFlight: function(flight, x, y, angle, widget) {
|
||||
flight.$element.css({
|
||||
left: x,
|
||||
top: y,
|
||||
'-webkit-transform':'rotate(' + ((angle + Math.PI / 2) * 360 / (2 * Math.PI)) + 'deg)',
|
||||
'-moz-transform':'rotate(' + ((angle + Math.PI / 2) * 360 / (2 * Math.PI)) + 'deg)',
|
||||
'-o-transform':'rotate(' + ((angle + Math.PI / 2) * 360 / (2 * Math.PI)) + 'deg)'
|
||||
});
|
||||
},
|
||||
onHideFlight: function(flight) {
|
||||
flight.$element.hide();
|
||||
},
|
||||
onDeleteFlight: function(flight) {
|
||||
flight.$element.remove();
|
||||
}
|
||||
},
|
||||
earth: null,
|
||||
posVar: 24 * 3600 * 1000,
|
||||
lastMousePos: null,
|
||||
lastSpeed: null,
|
||||
lastTime: null,
|
||||
lastTurnByTime: null,
|
||||
textureWidth: null,
|
||||
textureHeight: null,
|
||||
obj: null,
|
||||
flightsCtx: null,
|
||||
renderAnimationFrameId: null,
|
||||
mousePressed: null,
|
||||
|
||||
_create: function() {
|
||||
earth3d = this;
|
||||
var self = this;
|
||||
this.obj = $('div');
|
||||
if (this.options.flightsCanvas !== null) {
|
||||
this.flightsCtx = this.options.flightsCanvas[0].getContext('2d');
|
||||
}
|
||||
createSphere(this.element[0], this.options.texture, function(earth, textureWidth, textureHeight) { self._onSphereCreated(earth, textureWidth, textureHeight); }, this.options.tiling);
|
||||
if (this.options.dragElement !== null) {
|
||||
this.options.dragElement
|
||||
.bind('mousedown vmousedown', function(e) {
|
||||
self._mouseDragStart(e);
|
||||
self.mousePressed = true;
|
||||
})
|
||||
.bind('mouseup vmouseup', function(e) {
|
||||
self._mouseDragStop(e);
|
||||
self.mousePressed = false;
|
||||
})
|
||||
.bind('mousemove vmousemove', function(e){
|
||||
if (self.mousePressed) {
|
||||
self._mouseDrag(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
this._initLocations();
|
||||
this._initFlights();
|
||||
},
|
||||
|
||||
_initLocations: function() {
|
||||
for (var key in this.options.locations) {
|
||||
var location = this.options.locations[key];
|
||||
location.visible = true;
|
||||
this.options.onInitLocation(location, this);
|
||||
}
|
||||
},
|
||||
|
||||
_initFlights: function() {
|
||||
for (var key in this.options.paths) {
|
||||
var path = this.options.paths[key];
|
||||
for (var key in path.flights) {
|
||||
path.flights[key].visible = true;
|
||||
this.options.onInitFlight(path.flights[key], this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getSphereRadiusInPixel: function() {
|
||||
return this.earth.getRadius() / 2;
|
||||
},
|
||||
|
||||
_onSphereCreated: function(earth, textureWidth, textureHeight) {
|
||||
var self = this;
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
this.earth = earth;
|
||||
this.earth.init(this.options.sphere);
|
||||
this.earth.turnBy = function(time) { return self._turnBy(time); };
|
||||
|
||||
var renderAnimationFrame = function(/* time */ time) {
|
||||
/* time ~= +new Date // the unix time */
|
||||
earth.renderFrame(time);
|
||||
self._renderAnimationFrame(time);
|
||||
self.renderAnimationFrameId = window.requestAnimationFrame(renderAnimationFrame);
|
||||
};
|
||||
this.renderAnimationFrameId = window.requestAnimationFrame(renderAnimationFrame);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
window.cancelAnimationFrame(this.renderAnimationFrameId);
|
||||
},
|
||||
|
||||
_renderAnimationFrame: function(time) {
|
||||
|
||||
|
||||
var ry=90+this.options.sphere.tilt;
|
||||
var rz=180+this.options.sphere.turn;
|
||||
|
||||
var RY = (90-ry);
|
||||
var RZ = (180-rz);
|
||||
var RX = 0,RY,RZ;
|
||||
|
||||
var rx=RX*Math.PI/180;
|
||||
var ry=RY*Math.PI/180;
|
||||
var rz=RZ*Math.PI/180;
|
||||
//console.log(rx, ry, rz);
|
||||
var r = this.getSphereRadiusInPixel();
|
||||
|
||||
var center = {
|
||||
x: this.element.width() / 2,
|
||||
y: this.element.height() / 2
|
||||
}
|
||||
|
||||
for (var key in this.options.locations) {
|
||||
var location = this.options.locations[key];
|
||||
|
||||
if (typeof location.delta === 'undefined') {
|
||||
location.flatPosition = {x: location.x, y: location.y};
|
||||
this.options.onRefreshLocation(location, location.x, location.y, this);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
WARNING: calculation of alphaAngle and deltaAngle is not exact
|
||||
I had to create the _calibrated functions to modify the deltaAngle to make the result look good on
|
||||
a spinning planet without rotation. It will totally bug with rotation!
|
||||
* */
|
||||
var progression = (((this.posVar + this.textureWidth * location.delta / (2 * Math.PI)) % this.textureWidth) / this.textureWidth);
|
||||
var alphaAngle = progression * 2 * Math.PI;
|
||||
var deltaAngle = this._calibrated(progression, location.alpha) * 2 * Math.PI;
|
||||
|
||||
|
||||
var objAlpha = ry + location.alpha - Math.sin(alphaAngle / 2) * 0.15 * (location.alpha - Math.PI / 2) / (Math.PI / 4);
|
||||
var objDelta = rz + deltaAngle;
|
||||
|
||||
var a = this._orbitalTo3d(objAlpha, objDelta, r);
|
||||
|
||||
var flatPosition = this._orthographicProjection(a);
|
||||
|
||||
if (a.x < 0 && !location.visible) {
|
||||
this.options.onShowLocation(location, flatPosition.x, flatPosition.y, this);
|
||||
}
|
||||
if (a.x > 0 && location.visible) {
|
||||
this.options.onHideLocation(location, flatPosition.x, flatPosition.y, this);
|
||||
}
|
||||
this.options.onRefreshLocation(location, flatPosition.x, flatPosition.y, this);
|
||||
|
||||
location.visible = a.x < 0;
|
||||
location.position = a;
|
||||
location.flatPosition = flatPosition;
|
||||
location.rAlpha = objAlpha;
|
||||
location.rDelta = objDelta;
|
||||
|
||||
}
|
||||
|
||||
if (this.flightsCtx !== null) {
|
||||
this.flightsCtx.clearRect(0, 0, this.options.flightsCanvas.width(), this.options.flightsCanvas.height());
|
||||
for (var key in this.options.paths) {
|
||||
this._drawPath(this.options.paths[key], center, r);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
_line_circle_intersection: function(A, B, C, r) {
|
||||
var d = {
|
||||
x: B.x - A.x,
|
||||
y: B.y - A.y
|
||||
};
|
||||
|
||||
var f = {
|
||||
x: A.x - C.x,
|
||||
y: A.y - C.y
|
||||
};
|
||||
|
||||
var a = this._dot(d, d);
|
||||
var b = 2 * this._dot(f, d);
|
||||
var c = this._dot(f, f) - r * r;
|
||||
|
||||
var discriminant = b * b - 4 * a * c;
|
||||
if (discriminant < 0) {
|
||||
return false;
|
||||
} else {
|
||||
discriminant = Math.sqrt(discriminant);
|
||||
var t1 = (-b + discriminant) / (2 * a);
|
||||
var t2 = (-b - discriminant) / (2 * a);
|
||||
|
||||
|
||||
var sols = [];
|
||||
|
||||
if (t1 >= 0 && t1 <= 1) {
|
||||
sols.push({
|
||||
x:A.x + t1 * d.x,
|
||||
y:A.y + t1 * d.y
|
||||
});
|
||||
}
|
||||
|
||||
if (t2 >= 0 && t2 <= 1) {
|
||||
sols.push({
|
||||
x:A.x + t2 * d.x,
|
||||
y:A.y + t2 * d.y
|
||||
});
|
||||
}
|
||||
|
||||
return sols;
|
||||
}
|
||||
},
|
||||
|
||||
_dot: function(A, B) {
|
||||
return A.x * B.x + A.y * B.y;
|
||||
},
|
||||
|
||||
_drawPath: function(path, center, r) {
|
||||
|
||||
|
||||
var originLocation = this.options.locations[path.origin];
|
||||
var destinationLocation = this.options.locations[path.destination];
|
||||
|
||||
var dotSize = 50;
|
||||
var spacing = 0.15;
|
||||
|
||||
if (typeof originLocation.delta === 'undefined' || typeof destinationLocation.delta === 'undefined') {
|
||||
var pathVisible = originLocation.visible && destinationLocation.visible;
|
||||
if (pathVisible) {
|
||||
|
||||
|
||||
var flatDistance = this._distance(originLocation.flatPosition, destinationLocation.flatPosition);
|
||||
|
||||
var nb = flatDistance * 0.9 / 20;
|
||||
// WARNING: we are drawing the paths on canvas, intensively using CPU. Could we gain by instead using SVG or the DOM ?
|
||||
for (var i = 0; i < nb; i++) {
|
||||
|
||||
|
||||
var fromFlatPosition = {
|
||||
x: ((nb - i) / nb) * originLocation.flatPosition.x + (i / nb) * destinationLocation.flatPosition.x,
|
||||
y: ((nb - i) / nb) * originLocation.flatPosition.y + (i / nb) * destinationLocation.flatPosition.y
|
||||
};
|
||||
|
||||
var toFlatPosition = {
|
||||
x: Math.max(((nb - (i + 1)) / nb), 0) * originLocation.flatPosition.x + Math.min(((i + 1) / nb), 1) * destinationLocation.flatPosition.x,
|
||||
y: Math.max(((nb - (i + 1)) / nb), 0) * originLocation.flatPosition.y + Math.min(((i + 1) / nb), 1) * destinationLocation.flatPosition.y
|
||||
};
|
||||
|
||||
var diff = {
|
||||
x: fromFlatPosition.x - toFlatPosition.x,
|
||||
y: fromFlatPosition.y - toFlatPosition.y,
|
||||
z: fromFlatPosition.z - toFlatPosition.z
|
||||
};
|
||||
|
||||
fromFlatPosition.x -= diff.x * spacing;
|
||||
fromFlatPosition.y -= diff.y * spacing;
|
||||
fromFlatPosition.z -= diff.z * spacing;
|
||||
toFlatPosition.x += diff.x * spacing;
|
||||
toFlatPosition.y += diff.y * spacing;
|
||||
toFlatPosition.z += diff.z * spacing;
|
||||
|
||||
|
||||
this.flightsCtx.lineWidth = 3;
|
||||
this.flightsCtx.beginPath();
|
||||
this.flightsCtx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
this.flightsCtx.moveTo(fromFlatPosition.x + this.options.flightsCanvasPosition.x, fromFlatPosition.y + this.options.flightsCanvasPosition.y);
|
||||
this.flightsCtx.lineTo(toFlatPosition.x + this.options.flightsCanvasPosition.x, toFlatPosition.y + this.options.flightsCanvasPosition.y);
|
||||
this.flightsCtx.stroke();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (var key in path.flights) {
|
||||
var flight = path.flights[key];
|
||||
|
||||
var position = flight.destination == path.destination ? flight.position : (1 - flight.position);
|
||||
|
||||
|
||||
var flightFlatPosition = {
|
||||
x: (1 - position) * originLocation.flatPosition.x + position * destinationLocation.flatPosition.x,
|
||||
y: (1 - position) * originLocation.flatPosition.y + position * destinationLocation.flatPosition.y
|
||||
};
|
||||
|
||||
if (!flight.visible && pathVisible) {
|
||||
this.options.onShowFlight(flight, this);
|
||||
flight.visible = true;
|
||||
}
|
||||
|
||||
if (flight.visible && !pathVisible) {
|
||||
this.options.onHideFlight(flight, this);
|
||||
flight.visible = false;
|
||||
}
|
||||
|
||||
var angle = Math.atan2(destinationLocation.flatPosition.y - originLocation.flatPosition.y, destinationLocation.flatPosition.x - originLocation.flatPosition.x) + (flight.destination == path.destination ? 0 : Math.PI);
|
||||
//console.log(flightAheadFlatPosition.y - flightFlatPosition.y);
|
||||
|
||||
this.options.onRefreshFlight(flight, flightFlatPosition.x, flightFlatPosition.y, angle, this);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var locationsDistance = this._distance(originLocation.position, destinationLocation.position);
|
||||
|
||||
|
||||
var middlePosition = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
|
||||
|
||||
var radius = this._distance(originLocation.position, middlePosition);
|
||||
|
||||
var originP = {
|
||||
delta: Math.atan2((originLocation.position.y - middlePosition.y), (originLocation.position.x - middlePosition.x)),
|
||||
alpha: Math.acos((originLocation.position.z - middlePosition.z) / radius)
|
||||
};
|
||||
|
||||
var destinationP = {
|
||||
delta: Math.atan2((destinationLocation.position.y - middlePosition.y), (destinationLocation.position.x - middlePosition.x)),
|
||||
alpha: Math.acos((destinationLocation.position.z - middlePosition.z) / radius)
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (Math.abs(originP.delta - destinationP.delta) > Math.PI) {
|
||||
if ((originP.delta - destinationP.delta) > Math.PI) {
|
||||
originP.delta -= 2 * Math.PI;
|
||||
} else {
|
||||
originP.delta += 2 * Math.PI;
|
||||
}
|
||||
}
|
||||
|
||||
if (path.sens) {
|
||||
if (((originP.delta - destinationP.delta) > 0 ? 1 : -1) != path.sens) {
|
||||
if (Math.abs(originP.delta - destinationP.delta) > Math.PI / 2) {
|
||||
originP.delta += path.sens * 2 * Math.PI;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
path.sens = (originP.delta - destinationP.delta) > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
if (!path.nb) {
|
||||
path.nb = Math.round(((locationsDistance / (2 * r)) * Math.PI * 2 * r + (1 - (locationsDistance / (2 * r))) * locationsDistance) / dotSize);
|
||||
}
|
||||
var nb = path.nb;
|
||||
var maxDistance = 1.2;
|
||||
for (var i = 0; i < nb; i++) {
|
||||
var fromP = {
|
||||
alpha: ((nb - i) / nb) * originP.alpha + (i / nb) * destinationP.alpha,
|
||||
delta: ((nb - i) / nb) * originP.delta + (i / nb) * destinationP.delta
|
||||
};
|
||||
|
||||
var toP = {
|
||||
alpha: ((nb - 1 - i) / nb) * originP.alpha + ((i + 1) / nb) * destinationP.alpha,
|
||||
delta: ((nb - 1 - i) / nb) * originP.delta + ((i + 1) / nb) * destinationP.delta
|
||||
};
|
||||
//console.log(i, fromP.alpha, fromP.delta, toP.alpha, toP.delta);
|
||||
|
||||
var fromPosition = this._orbitalTo3d(fromP.alpha, fromP.delta, -(Math.sin(Math.PI * i / nb) * (maxDistance - 1) + 1) * radius);
|
||||
var toPosition = this._orbitalTo3d(toP.alpha, toP.delta, -(Math.sin(Math.PI * (i + 1) / nb) * (maxDistance - 1) + 1) * radius);
|
||||
var diff = {
|
||||
x: fromPosition.x - toPosition.x,
|
||||
y: fromPosition.y - toPosition.y,
|
||||
z: fromPosition.z - toPosition.z
|
||||
};
|
||||
|
||||
|
||||
|
||||
fromPosition.x -= diff.x * spacing;
|
||||
fromPosition.y -= diff.y * spacing;
|
||||
fromPosition.z -= diff.z * spacing;
|
||||
toPosition.x += diff.x * spacing;
|
||||
toPosition.y += diff.y * spacing;
|
||||
toPosition.z += diff.z * spacing;
|
||||
|
||||
|
||||
fromPosition.x += middlePosition.x;
|
||||
fromPosition.y += middlePosition.y;
|
||||
fromPosition.z += middlePosition.z;
|
||||
toPosition.x += middlePosition.x;
|
||||
toPosition.y += middlePosition.y;
|
||||
toPosition.z += middlePosition.z;
|
||||
|
||||
|
||||
|
||||
var fromFlatPosition = this._orthographicProjection(fromPosition);
|
||||
var toFlatPosition = this._orthographicProjection(toPosition);
|
||||
|
||||
var fromDistanceCenter = this._distance(fromFlatPosition, center);
|
||||
var toDistanceCenter = this._distance(toFlatPosition, center);
|
||||
|
||||
var fromVisible = true;
|
||||
var toVisible = true;
|
||||
if (fromPosition.x > 0) {
|
||||
if (fromDistanceCenter <= r) {
|
||||
fromVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (toPosition.x > 0) {
|
||||
if (toDistanceCenter <= r) {
|
||||
toVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
//console.log(i, fromVisible, toVisible);
|
||||
|
||||
if (!fromVisible && !toVisible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fromVisible) {
|
||||
var intersection = this._line_circle_intersection(fromFlatPosition, toFlatPosition, center, r);
|
||||
if (intersection.length == 0) {
|
||||
continue;
|
||||
}
|
||||
fromFlatPosition = intersection[0];
|
||||
}
|
||||
|
||||
if (!toVisible) {
|
||||
var intersection = this._line_circle_intersection(fromFlatPosition, toFlatPosition, center, r);
|
||||
if (intersection.length == 0) {
|
||||
continue;
|
||||
}
|
||||
toFlatPosition = intersection[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.flightsCtx.lineWidth = 3;
|
||||
this.flightsCtx.beginPath();
|
||||
this.flightsCtx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
this.flightsCtx.moveTo(fromFlatPosition.x + this.options.flightsCanvasPosition.x, fromFlatPosition.y + this.options.flightsCanvasPosition.y);
|
||||
this.flightsCtx.lineTo(toFlatPosition.x + this.options.flightsCanvasPosition.x, toFlatPosition.y + this.options.flightsCanvasPosition.y);
|
||||
this.flightsCtx.stroke();
|
||||
|
||||
}
|
||||
|
||||
for (var key in path.flights) {
|
||||
var flight = path.flights[key];
|
||||
|
||||
|