Spot v2: Project Management
This commit is contained in:
25
files/db/update_v1_to_v2.sql
Normal file
25
files/db/update_v1_to_v2.sql
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
CREATE TABLE `projects` (
|
||||||
|
`id_project` int(10) UNSIGNED auto_increment,
|
||||||
|
`codename` VARCHAR(100),
|
||||||
|
`name` VARCHAR(100),
|
||||||
|
`active_from` DATETIME,
|
||||||
|
`active_to` DATETIME,
|
||||||
|
`geofile` VARCHAR(50),
|
||||||
|
`timezone` VARCHAR(100),
|
||||||
|
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id_project`));
|
||||||
|
|
||||||
|
INSERT INTO projects (name, codename, active_from, active_to, geofile, timezone) VALUES ('Te Araroa', 'te_araroa', '2015-12-29 00:00:00', '2016-03-05 23:59:59', 'te_araroa.geojson', 'Pacific/Auckland');
|
||||||
|
INSERT INTO projects (name, codename, active_from, active_to, geofile, timezone) VALUES ('HRP', 'hrp', '2019-06-01 00:00:00', '2019-09-10 23:59:59', 'hrp.geojson', 'Europe/Paris');
|
||||||
|
|
||||||
|
ALTER TABLE feeds ADD COLUMN id_project int(10) UNSIGNED AFTER id_spot;
|
||||||
|
ALTER TABLE feeds ADD last_update DATETIME AFTER status;
|
||||||
|
ALTER TABLE feeds ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);
|
||||||
|
UPDATE feeds SET last_update = led;
|
||||||
|
UPDATE feeds SET id_project = 1;
|
||||||
|
|
||||||
|
ALTER TABLE posts ADD COLUMN id_project int(10) UNSIGNED AFTER id_post;
|
||||||
|
ALTER TABLE posts ADD timestamp DATETIME AFTER content;
|
||||||
|
ALTER TABLE posts ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);
|
||||||
|
UPDATE posts SET timestamp = led;
|
||||||
|
UPDATE posts SET id_project = 1;
|
||||||
36
geo/hrp.geojson
Normal file
36
geo/hrp.geojson
Normal file
File diff suppressed because one or more lines are too long
153
geo/te_araroa.geojson
Normal file
153
geo/te_araroa.geojson
Normal file
File diff suppressed because one or more lines are too long
BIN
images/layers.png
Normal file
BIN
images/layers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 696 B |
BIN
images/marker-icon-2x.png
Normal file
BIN
images/marker-icon-2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
images/marker-icon.png
Normal file
BIN
images/marker-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
images/marker-shadow.png
Normal file
BIN
images/marker-shadow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 618 B |
@@ -14,6 +14,7 @@ class Cacher extends PhpObject
|
|||||||
private $iZ;
|
private $iZ;
|
||||||
private $sToken;
|
private $sToken;
|
||||||
private $asDomains;
|
private $asDomains;
|
||||||
|
private $sReferer;
|
||||||
|
|
||||||
public function __construct($sPattern, $sId='')
|
public function __construct($sPattern, $sId='')
|
||||||
{
|
{
|
||||||
@@ -25,6 +26,7 @@ class Cacher extends PhpObject
|
|||||||
$this->iZ = 0;
|
$this->iZ = 0;
|
||||||
$this->sToken = '';
|
$this->sToken = '';
|
||||||
$this->asDomains = array();
|
$this->asDomains = array();
|
||||||
|
$this->sReferer = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setId($sId) {
|
public function setId($sId) {
|
||||||
@@ -43,6 +45,10 @@ class Cacher extends PhpObject
|
|||||||
$this->asDomains = $asDomains;
|
$this->asDomains = $asDomains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setReferer($sReferer) {
|
||||||
|
$this->sReferer = $sReferer;
|
||||||
|
}
|
||||||
|
|
||||||
public function setGeoPos($iX, $iY, $iZ) {
|
public function setGeoPos($iX, $iY, $iZ) {
|
||||||
$this->iX = $iX;
|
$this->iX = $iX;
|
||||||
$this->iY = $iY;
|
$this->iY = $iY;
|
||||||
@@ -58,7 +64,7 @@ class Cacher extends PhpObject
|
|||||||
curl_setopt($oCurl, CURLOPT_HEADER, false);
|
curl_setopt($oCurl, CURLOPT_HEADER, false);
|
||||||
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($oCurl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
|
curl_setopt($oCurl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
|
||||||
curl_setopt($oCurl, CURLOPT_REFERER, 'http://spot.lutran.fr');
|
curl_setopt($oCurl, CURLOPT_REFERER, $this->sReferer);
|
||||||
$sContent = curl_exec($oCurl);
|
$sContent = curl_exec($oCurl);
|
||||||
curl_close($oCurl);
|
curl_close($oCurl);
|
||||||
|
|
||||||
|
|||||||
111
inc/project.php
Normal file
111
inc/project.php
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Project extends PhpObject {
|
||||||
|
|
||||||
|
//Spot Mode
|
||||||
|
const MODE_PREVIZ = 'P';
|
||||||
|
const MODE_BLOG = 'B';
|
||||||
|
const MODE_HISTO = 'H';
|
||||||
|
const MODES = array('previz'=>self::MODE_PREVIZ, 'blog'=>self::MODE_BLOG, 'histo'=>self::MODE_HISTO);
|
||||||
|
|
||||||
|
//Folders
|
||||||
|
const GEO_FOLDER = 'geo/';
|
||||||
|
|
||||||
|
//DB Tables
|
||||||
|
const PROJ_TABLE = 'projects';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database Handle
|
||||||
|
* @var Db
|
||||||
|
*/
|
||||||
|
private $oDb;
|
||||||
|
|
||||||
|
private $iProjectId;
|
||||||
|
private $sMode;
|
||||||
|
private $sName;
|
||||||
|
private $sCodeName;
|
||||||
|
private $asActive;
|
||||||
|
private $sGeo;
|
||||||
|
|
||||||
|
public function __construct(Db &$oDb) {
|
||||||
|
parent::__construct(__CLASS__, Settings::DEBUG);
|
||||||
|
$this->oDb = $oDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProjectId($iProjectId=0) {
|
||||||
|
if($iProjectId > 0) {
|
||||||
|
$this->iProjectId = $iProjectId;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/**
|
||||||
|
* Project 1 [-----------------]
|
||||||
|
* Project 2 [---------------------------]
|
||||||
|
* Project 3 [-----------]
|
||||||
|
* Selected Project [-------Project 1-------][------------Project 2-------------][---------------Project 3------------------
|
||||||
|
* Mode --P--][--------B--------][--P--][-----------B---------------][---P---][-----B-----][---------H----------
|
||||||
|
*/
|
||||||
|
$sQuery = "SELECT MAX(id_project) FROM projects WHERE active_to = (SELECT MIN(active_to) FROM projects WHERE active_to > NOW() OR active_to = (SELECT MAX(active_to) FROM projects))";
|
||||||
|
$asResult = $this->oDb->getArrayQuery($sQuery, true);
|
||||||
|
$this->iProjectId = array_shift($asResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setProjectInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMode() {
|
||||||
|
return $this->sMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjectId() {
|
||||||
|
return $this->iProjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjectCodeName() {
|
||||||
|
return $this->sCodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActivePeriod($sFromTo='') {
|
||||||
|
return ($sFromTo=='')?$this->asActive:$this->asActive[$sFromTo];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjects($iProjectId=0) {
|
||||||
|
$asInfo = array(
|
||||||
|
'select'=> array(
|
||||||
|
Db::getId(self::PROJ_TABLE)." AS id",
|
||||||
|
'codename',
|
||||||
|
'name',
|
||||||
|
'active_from',
|
||||||
|
'active_to',
|
||||||
|
"IF(NOW() BETWEEN active_from AND active_to, 1, IF(NOW() < active_from, 0, 2)) AS mode",
|
||||||
|
'geofile',
|
||||||
|
'timezone'
|
||||||
|
),
|
||||||
|
'from' => self::PROJ_TABLE
|
||||||
|
);
|
||||||
|
if($iProjectId > 0) $asInfo['constraint'] = array(Db::getId(self::PROJ_TABLE)=>$iProjectId);
|
||||||
|
|
||||||
|
$asProjects = $this->oDb->selectRows($asInfo, 'codename');
|
||||||
|
foreach($asProjects as &$asProject) {
|
||||||
|
switch($asProject['mode']) {
|
||||||
|
case 0: $asProject['mode'] = self::MODE_PREVIZ; break;
|
||||||
|
case 1: $asProject['mode'] = self::MODE_BLOG; break;
|
||||||
|
case 2: $asProject['mode'] = self::MODE_HISTO; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sGeoFilePath = self::GEO_FOLDER.$asProject['geofile'];
|
||||||
|
$asProject['geofile'] = file_exists($sGeoFilePath)?$asProject['geofile'].'?'.date("YmdHis", filemtime($sGeoFilePath)):$asProject['geofile'];
|
||||||
|
}
|
||||||
|
return $asProjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setProjectInfo() {
|
||||||
|
$asResult = $this->getProjects($this->iProjectId);
|
||||||
|
$asProject = reset($asResult);
|
||||||
|
|
||||||
|
$this->sMode = $asProject['mode'];
|
||||||
|
$this->asActive = array('from'=>$asProject['active_from'], 'to'=>$asProject['active_to']);
|
||||||
|
$this->sCodeName = key($asResult);
|
||||||
|
$this->sName = $asProject['name'];
|
||||||
|
$this->sGeo = array('file'=>$asProject['geofile'], 'timezone'=>$asProject['timezone']);
|
||||||
|
}
|
||||||
|
}
|
||||||
216
inc/spot.php
216
inc/spot.php
@@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
class Spot extends Main
|
class Spot extends Main
|
||||||
{
|
{
|
||||||
//Spot Mode
|
|
||||||
const MODE_HISTO = 'histo';
|
|
||||||
const MODE_BLOG = 'blog';
|
|
||||||
|
|
||||||
//Spot feed
|
//Spot feed
|
||||||
const FEED_HOOK = 'https://api.findmespot.com/spot-main-web/consumer/rest-api/2.0/public/feed/';
|
const FEED_HOOK = 'https://api.findmespot.com/spot-main-web/consumer/rest-api/2.0/public/feed/';
|
||||||
const FEED_TYPE_XML = '/message.xml';
|
const FEED_TYPE_XML = '/message.xml';
|
||||||
@@ -25,19 +21,27 @@ class Spot extends Main
|
|||||||
|
|
||||||
const FEED_CHUNK_SIZE = 15;
|
const FEED_CHUNK_SIZE = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active Project
|
||||||
|
* @var Project
|
||||||
|
*/
|
||||||
|
private $oProject;
|
||||||
|
|
||||||
public function __construct($oClassManagement, $sProcessPage)
|
public function __construct($oClassManagement, $sProcessPage)
|
||||||
{
|
{
|
||||||
parent::__construct($oClassManagement, $sProcessPage);
|
$asClasses = array(
|
||||||
$oClassManagement->incClass('cacher', true);
|
array('name'=>'project', 'project'=>true),
|
||||||
|
array('name'=>'cacher', 'project'=>true)
|
||||||
|
);
|
||||||
|
parent::__construct($oClassManagement, $sProcessPage, $asClasses);
|
||||||
|
|
||||||
|
$this->oProject = new Project($this->oDb);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function install()
|
protected function install()
|
||||||
{
|
{
|
||||||
//Install DB
|
//Install DB
|
||||||
$this->oDb->install();
|
$this->oDb->install();
|
||||||
|
|
||||||
//Add feed
|
|
||||||
//$this->oDb->insertRow(self::FEED_TABLE, array('ref_feed_id'=>Settings::FEED_ID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getSqlOptions()
|
protected function getSqlOptions()
|
||||||
@@ -46,36 +50,44 @@ class Spot extends Main
|
|||||||
(
|
(
|
||||||
'tables' => array
|
'tables' => array
|
||||||
(
|
(
|
||||||
self::MSG_TABLE => array('ref_msg_id', Db::getId(self::FEED_TABLE), 'type', 'latitude', 'longitude', 'timestamp', 'unix_timestamp', 'content', 'battery_state'),
|
self::MSG_TABLE => array('ref_msg_id', Db::getId(self::FEED_TABLE), 'type', 'latitude', 'longitude', 'timestamp', 'unix_timestamp', 'content', 'battery_state'),
|
||||||
self::FEED_TABLE => array('ref_feed_id', Db::getId(self::SPOT_TABLE), 'name', 'description', 'status'),
|
self::FEED_TABLE => array('ref_feed_id', Db::getId(self::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
|
||||||
self::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
self::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
||||||
self::POST_TABLE => array('name', 'content')
|
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to', 'geofile', 'timezone'),
|
||||||
|
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), 'name', 'content', 'timestamp')
|
||||||
),
|
),
|
||||||
'types' => array
|
'types' => array
|
||||||
(
|
(
|
||||||
'ref_msg_id' => "INT",
|
'ref_msg_id' => "INT",
|
||||||
'type' => "VARCHAR(20)",
|
'type' => "VARCHAR(20)",
|
||||||
'latitude' => "DECIMAL(7,5)",
|
'latitude' => "DECIMAL(7,5)",
|
||||||
'longitude' => "DECIMAL(8,5)",
|
'longitude' => "DECIMAL(8,5)",
|
||||||
'timestamp' => "DATETIME",
|
'timestamp' => "DATETIME",
|
||||||
'unix_timestamp'=> "INT",
|
'unix_timestamp'=> "INT",
|
||||||
'content' => "LONGTEXT",
|
'content' => "LONGTEXT",
|
||||||
'battery_state' => "VARCHAR(10)",
|
'battery_state' => "VARCHAR(10)",
|
||||||
'ref_spot_id' => "VARCHAR(10)",
|
'ref_spot_id' => "VARCHAR(10)",
|
||||||
'name' => "VARCHAR(100)",
|
'name' => "VARCHAR(100)",
|
||||||
'model' => "VARCHAR(20)",
|
'codename' => "VARCHAR(100)",
|
||||||
'ref_feed_id' => "VARCHAR(40)",
|
'model' => "VARCHAR(20)",
|
||||||
'description' => "VARCHAR(100)",
|
'ref_feed_id' => "VARCHAR(40)",
|
||||||
'status' => "VARCHAR(10)",
|
'description' => "VARCHAR(100)",
|
||||||
|
'status' => "VARCHAR(10)",
|
||||||
|
'active_from' => "DATETIME",
|
||||||
|
'active_to' => "DATETIME",
|
||||||
|
'geofile' => "VARCHAR(50)",
|
||||||
|
'timezone' => "VARCHAR(100)",
|
||||||
|
'last_update' => "DATETIME"
|
||||||
),
|
),
|
||||||
'constraints' => array
|
'constraints' => array
|
||||||
(
|
(
|
||||||
self::MSG_TABLE => "UNIQUE KEY `uni_ref_msg_id` (`ref_msg_id`)",
|
self::MSG_TABLE => "UNIQUE KEY `uni_ref_msg_id` (`ref_msg_id`)",
|
||||||
self::FEED_TABLE => "UNIQUE KEY `uni_ref_feed_id` (`ref_feed_id`)",
|
self::FEED_TABLE => "UNIQUE KEY `uni_ref_feed_id` (`ref_feed_id`)",
|
||||||
self::SPOT_TABLE => "UNIQUE KEY `uni_ref_spot_id` (`ref_spot_id`)",
|
self::SPOT_TABLE => "UNIQUE KEY `uni_ref_spot_id` (`ref_spot_id`)",
|
||||||
self::MSG_TABLE => "INDEX(`ref_msg_id`)",
|
self::MSG_TABLE => "INDEX(`ref_msg_id`)",
|
||||||
self::FEED_TABLE => "INDEX(`ref_feed_id`)",
|
self::FEED_TABLE => "INDEX(`ref_feed_id`)",
|
||||||
self::SPOT_TABLE => "INDEX(`ref_spot_id`)",
|
self::SPOT_TABLE => "INDEX(`ref_spot_id`)",
|
||||||
|
Project::PROJ_TABLE => "UNIQUE KEY `uni_proj_name` (`codename`)",
|
||||||
),
|
),
|
||||||
'cascading_delete' => array
|
'cascading_delete' => array
|
||||||
(
|
(
|
||||||
@@ -89,10 +101,14 @@ class Spot extends Main
|
|||||||
return parent::getMainPage(
|
return parent::getMainPage(
|
||||||
array(
|
array(
|
||||||
'vars' => array(
|
'vars' => array(
|
||||||
'feed_id' => Settings::FEED_ID,
|
'chunk_size' => self::FEED_CHUNK_SIZE,
|
||||||
'chunk_size'=> self::FEED_CHUNK_SIZE,
|
'mapbox_key' => Settings::MAPBOX_KEY,
|
||||||
'mode' => Settings::MODE,
|
'default_project_codename' => $this->oProject->getProjectCodeName(),
|
||||||
'mapbox_key'=> Settings::MAPBOX_KEY
|
'projects' => $this->oProject->getProjects()
|
||||||
|
),
|
||||||
|
'consts' => array(
|
||||||
|
'modes' => Project::MODES,
|
||||||
|
'geo_folder'=> Project::GEO_FOLDER
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'index',
|
'index',
|
||||||
@@ -100,16 +116,22 @@ class Spot extends Main
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Managing projects */
|
||||||
|
|
||||||
|
public function setProjectId($iProjectId=0) {
|
||||||
|
$this->oProject->setProjectId($iProjectId);
|
||||||
|
}
|
||||||
|
|
||||||
/* Getting & Storing messages */
|
/* Getting & Storing messages */
|
||||||
|
|
||||||
private function getFeed($sRefFeedId=Settings::FEED_ID)
|
private function getFeed($sRefFeedId)
|
||||||
{
|
{
|
||||||
$sUrl = self::FEED_HOOK.$sRefFeedId.self::FEED_TYPE_JSON;
|
$sUrl = self::FEED_HOOK.$sRefFeedId.self::FEED_TYPE_JSON;
|
||||||
$sContent = file_get_contents($sUrl);
|
$sContent = file_get_contents($sUrl);
|
||||||
return json_decode($sContent, true);
|
return json_decode($sContent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updateFeed($sRefFeedId=Settings::FEED_ID)
|
private function updateFeed($sRefFeedId)
|
||||||
{
|
{
|
||||||
$asData = $this->getFeed($sRefFeedId);
|
$asData = $this->getFeed($sRefFeedId);
|
||||||
$asMsgs = $asData['response']['feedMessageResponse']['messages'];
|
$asMsgs = $asData['response']['feedMessageResponse']['messages'];
|
||||||
@@ -122,14 +144,15 @@ class Spot extends Main
|
|||||||
$asSpotInfo = array('ref_spot_id'=>$asFirstMsg['messengerId'], 'name'=>$asFirstMsg['messengerName'], 'model'=>$asFirstMsg['modelId']);
|
$asSpotInfo = array('ref_spot_id'=>$asFirstMsg['messengerId'], 'name'=>$asFirstMsg['messengerName'], 'model'=>$asFirstMsg['modelId']);
|
||||||
$iSpotId = $this->oDb->insertUpdateRow(self::SPOT_TABLE, $asSpotInfo, array('ref_spot_id'));
|
$iSpotId = $this->oDb->insertUpdateRow(self::SPOT_TABLE, $asSpotInfo, array('ref_spot_id'));
|
||||||
|
|
||||||
//Update Feed Info
|
//Update Feed Info and last update date
|
||||||
$asFeedInfo = array(
|
$asFeedInfo = array(
|
||||||
'ref_feed_id' => $sRefFeedId,
|
'ref_feed_id' => $sRefFeedId,
|
||||||
Db::getId(self::SPOT_TABLE) => $iSpotId,
|
Db::getId(self::SPOT_TABLE) => $iSpotId,
|
||||||
'name' => $asFeed['name'],
|
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||||
'description' => $asFeed['description'],
|
'name' => $asFeed['name'],
|
||||||
'status' => $asFeed['status'],
|
'description' => $asFeed['description'],
|
||||||
'led' => date(Db::MYSQL_TIMESTAMP) //update with current time
|
'status' => $asFeed['status'],
|
||||||
|
'last_update' => date(Db::TIMESTAMP_FORMAT)
|
||||||
);
|
);
|
||||||
$iFeedId = $this->oDb->insertUpdateRow(self::FEED_TABLE, $asFeedInfo, array('ref_feed_id'));
|
$iFeedId = $this->oDb->insertUpdateRow(self::FEED_TABLE, $asFeedInfo, array('ref_feed_id'));
|
||||||
|
|
||||||
@@ -142,7 +165,7 @@ class Spot extends Main
|
|||||||
'type' => $asMsg['messageType'],
|
'type' => $asMsg['messageType'],
|
||||||
'latitude' => $asMsg['latitude'],
|
'latitude' => $asMsg['latitude'],
|
||||||
'longitude' => $asMsg['longitude'],
|
'longitude' => $asMsg['longitude'],
|
||||||
'timestamp' => date(Db::MYSQL_TIMESTAMP, strtotime($asMsg['dateTime'])), //Stored in Local Time
|
'timestamp' => date(Db::TIMESTAMP_FORMAT, strtotime($asMsg['dateTime'])), //Stored in Local Time
|
||||||
'unix_timestamp' => $asMsg['unixTime'], //Stored in UNIX time
|
'unix_timestamp' => $asMsg['unixTime'], //Stored in UNIX time
|
||||||
'content' => $asMsg['messageContent'],
|
'content' => $asMsg['messageContent'],
|
||||||
'battery_state' => $asMsg['batteryState']
|
'battery_state' => $asMsg['batteryState']
|
||||||
@@ -152,7 +175,7 @@ class Spot extends Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMessages($sRefFeedId=Settings::FEED_ID)
|
public function getMessages()
|
||||||
{
|
{
|
||||||
/* Adding another point to test
|
/* Adding another point to test
|
||||||
$test = $this->oDb->selectRow(self::MSG_TABLE, 1);
|
$test = $this->oDb->selectRow(self::MSG_TABLE, 1);
|
||||||
@@ -162,12 +185,7 @@ class Spot extends Main
|
|||||||
$test['longitude'] = '172.1936';
|
$test['longitude'] = '172.1936';
|
||||||
$this->oDb->insertUpdateRow(self::MSG_TABLE, $test, array('ref_msg_id')); */
|
$this->oDb->insertUpdateRow(self::MSG_TABLE, $test, array('ref_msg_id')); */
|
||||||
|
|
||||||
//Check last message & update feed if necessary (max once a day)
|
$asMessages = $this->getSpotMessages();
|
||||||
$sLastMsg = $this->oDb->selectValue(self::FEED_TABLE, 'led', array('ref_feed_id'=>$sRefFeedId));
|
|
||||||
if(Settings::MODE!=self::MODE_HISTO && mb_substr($sLastMsg, 0, 10) != date('Y-m-d')) $this->updateFeed($sRefFeedId);
|
|
||||||
|
|
||||||
//Extract messages
|
|
||||||
$asMessages = array_values($this->getSpotMessages());
|
|
||||||
$bSuccess = !empty($asMessages);
|
$bSuccess = !empty($asMessages);
|
||||||
$sDesc = $bSuccess?'':self::NO_DATA;
|
$sDesc = $bSuccess?'':self::NO_DATA;
|
||||||
|
|
||||||
@@ -202,22 +220,46 @@ class Spot extends Main
|
|||||||
|
|
||||||
private function getSpotMessages()
|
private function getSpotMessages()
|
||||||
{
|
{
|
||||||
$asInfo = array('from'=>self::MSG_TABLE, 'orderBy'=>array('timestamp'=>'ASC'));
|
//Get Feed IDs
|
||||||
if(Settings::MODE==self::MODE_HISTO) {
|
$asFeeds = $this->oDb->selectRows(array(
|
||||||
$asInfo['constraint'] = array('timestamp'=>Settings::HISTO_SPAN);
|
'select' => array(Db::getId(self::FEED_TABLE), 'ref_feed_id', 'last_update'),
|
||||||
$asInfo['constOpe'] = array('timestamp'=>"BETWEEN");
|
'from' => self::FEED_TABLE,
|
||||||
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()))
|
||||||
|
);
|
||||||
|
|
||||||
|
//Update on Blog Mode and not updated already today
|
||||||
|
$asAllFeedMessages = array();
|
||||||
|
foreach($asFeeds as $asFeed) {
|
||||||
|
|
||||||
|
//Feed updated once a day in Blog Mode
|
||||||
|
if($this->oProject->getMode() == Project::MODE_BLOG && mb_substr($asFeed['last_update'], 0, 10) != date('Y-m-d')) {
|
||||||
|
$this->updateFeed($asFeed['ref_feed_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$asInfo = array(
|
||||||
|
'select' => array('id_message', 'ref_msg_id', 'type', 'latitude', 'longitude', 'timestamp', 'unix_timestamp'),
|
||||||
|
'from' => self::MSG_TABLE,
|
||||||
|
'constraint'=> array(
|
||||||
|
Db::getId(Spot::FEED_TABLE) => $asFeed[Db::getId(self::FEED_TABLE)],
|
||||||
|
'timestamp' => $this->oProject->getActivePeriod()),
|
||||||
|
'constOpe' => array(
|
||||||
|
Db::getId(Spot::FEED_TABLE) => "=",
|
||||||
|
'timestamp' => "BETWEEN"),
|
||||||
|
'orderBy' => array('timestamp'=>'ASC'));
|
||||||
|
|
||||||
|
$asMessages = $this->oDb->selectRows($asInfo);
|
||||||
|
foreach($asMessages as $asMessage)
|
||||||
|
{
|
||||||
|
$asMessage['unix_timestamp'] = (int) $asMessage['unix_timestamp'];
|
||||||
|
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
||||||
|
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
||||||
|
$asMessage['relative_time'] = Toolbox::getDateTimeDesc($asMessage['unix_timestamp']);
|
||||||
|
$asMessage['formatted_time'] = date(self::FORMAT_TIME, $asMessage['unix_timestamp']);
|
||||||
|
$asAllFeedMessages[] = $asMessage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$asMessages = $this->oDb->selectRows($asInfo);
|
return $asAllFeedMessages;
|
||||||
foreach($asMessages as $iKey=>$asMessage)
|
|
||||||
{
|
|
||||||
$asMessages[$iKey]['unix_timestamp'] = (int) $asMessages[$iKey]['unix_timestamp'];
|
|
||||||
$asMessages[$iKey]['latitude'] = floatval($asMessages[$iKey]['latitude']);
|
|
||||||
$asMessages[$iKey]['longitude'] = floatval($asMessages[$iKey]['longitude']);
|
|
||||||
$asMessages[$iKey]['relative_time'] = Toolbox::getDateTimeDesc($asMessages[$iKey]['unix_timestamp']);
|
|
||||||
$asMessages[$iKey]['formatted_time'] = date(self::FORMAT_TIME, $asMessages[$iKey]['unix_timestamp']);
|
|
||||||
}
|
|
||||||
return $asMessages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPictures()
|
private function getPictures()
|
||||||
@@ -234,9 +276,8 @@ class Spot extends Main
|
|||||||
//Get/Create thumbnail
|
//Get/Create thumbnail
|
||||||
$sThumbnailPath = self::getPicThumbnail($sPicPath);
|
$sThumbnailPath = self::getPicThumbnail($sPicPath);
|
||||||
|
|
||||||
//Filter on valid time interval (Histo mode only)
|
//Filter on valid time interval
|
||||||
if( Settings::MODE != self::MODE_HISTO ||
|
if($iPicTimeStamp >= strtotime($this->oProject->getActivePeriod('from')) && $iPicTimeStamp <= strtotime($this->oProject->getActivePeriod('to'))) {
|
||||||
$iPicTimeStamp >= strtotime(Settings::HISTO_SPAN['from']) && $iPicTimeStamp <= strtotime(Settings::HISTO_SPAN['to'])) {
|
|
||||||
|
|
||||||
$asPics[] = array(
|
$asPics[] = array(
|
||||||
'path' => $sPicPath,
|
'path' => $sPicPath,
|
||||||
@@ -253,15 +294,19 @@ class Spot extends Main
|
|||||||
|
|
||||||
private function getPosts()
|
private function getPosts()
|
||||||
{
|
{
|
||||||
$asInfo = array('from'=>self::POST_TABLE);
|
$asInfo = array(
|
||||||
if(Settings::MODE==self::MODE_HISTO) {
|
'from' => self::POST_TABLE,
|
||||||
$asInfo['constraint'] = array('led'=>Settings::HISTO_SPAN);
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()),
|
||||||
$asInfo['constOpe'] = array('led'=>"BETWEEN");
|
'constOpe' => array(Db::getId(Project::PROJ_TABLE) => "=")
|
||||||
|
);
|
||||||
|
if($this->oProject->getMode()==Project::MODE_HISTO) {
|
||||||
|
$asInfo['constraint']['timestamp'] = $this->oProject->getActivePeriod();
|
||||||
|
$asInfo['constOpe']['timestamp'] = "BETWEEN";
|
||||||
}
|
}
|
||||||
|
|
||||||
$asPosts = $this->oDb->selectRows($asInfo);
|
$asPosts = $this->oDb->selectRows($asInfo);
|
||||||
|
|
||||||
foreach($asPosts as &$asPost) {
|
foreach($asPosts as &$asPost) {
|
||||||
$iUnixTimeStamp = strtotime($asPost['led']);
|
$iUnixTimeStamp = strtotime($asPost['timestamp']);
|
||||||
$asPost['unix_timestamp'] = $iUnixTimeStamp;
|
$asPost['unix_timestamp'] = $iUnixTimeStamp;
|
||||||
$asPost['relative_time'] = Toolbox::getDateTimeDesc($iUnixTimeStamp);
|
$asPost['relative_time'] = Toolbox::getDateTimeDesc($iUnixTimeStamp);
|
||||||
$asPost['formatted_time'] = date(self::FORMAT_TIME, $iUnixTimeStamp);
|
$asPost['formatted_time'] = date(self::FORMAT_TIME, $iUnixTimeStamp);
|
||||||
@@ -320,7 +365,12 @@ class Spot extends Main
|
|||||||
|
|
||||||
public function addPost($sName, $sPost)
|
public function addPost($sName, $sPost)
|
||||||
{
|
{
|
||||||
$asData = array('name'=>mb_strtolower(trim($sName)), 'content'=>trim($sPost));
|
$asData = array(
|
||||||
|
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||||
|
'name' => mb_strtolower(trim($sName)),
|
||||||
|
'content' => trim($sPost),
|
||||||
|
'timestamp' => date(Db::TIMESTAMP_FORMAT)
|
||||||
|
);
|
||||||
$iPostId = $this->oDb->insertRow(self::POST_TABLE, $asData);
|
$iPostId = $this->oDb->insertRow(self::POST_TABLE, $asData);
|
||||||
return self::getJsonResult(($iPostId > 0), '');
|
return self::getJsonResult(($iPostId > 0), '');
|
||||||
}
|
}
|
||||||
@@ -337,6 +387,7 @@ class Spot extends Main
|
|||||||
{
|
{
|
||||||
if(isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] == $this->asContext['serv_name']) {
|
if(isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] == $this->asContext['serv_name']) {
|
||||||
$asDomains = array();
|
$asDomains = array();
|
||||||
|
$sReferer = 'http://spot.lutran.fr';
|
||||||
switch($sMapId) {
|
switch($sMapId) {
|
||||||
case 'mapbox.satellite':
|
case 'mapbox.satellite':
|
||||||
case 'mapbox.streets':
|
case 'mapbox.streets':
|
||||||
@@ -348,10 +399,19 @@ class Spot extends Main
|
|||||||
$sToken = Settings::LINZ_KEY;
|
$sToken = Settings::LINZ_KEY;
|
||||||
$asDomains = array('a', 'b', 'c', 'd');
|
$asDomains = array('a', 'b', 'c', 'd');
|
||||||
break;
|
break;
|
||||||
|
case 'ign.es':
|
||||||
|
$sPattern = 'http://www.ign.es/wmts/mapa-raster?request=getTile&format=image/png&layer=MTN&TileMatrixSet=GoogleMapsCompatible&TileMatrix={z}&TileCol={x}&TileRow={y}';
|
||||||
|
break;
|
||||||
|
case 'ign.fr':
|
||||||
|
$sPattern = 'https://wxs.ign.fr/{token}/geoportail/wmts?LAYER=GEOGRAPHICALGRIDSYSTEMS.MAPS&EXCEPTIONS=text/xml&FORMAT=image/jpeg&SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&STYLE=normal&TILEMATRIXSET=PM&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}';
|
||||||
|
$sToken = Settings::IGN_FR_KEY;
|
||||||
|
$sReferer = 'https://www.visugpx.com/yfJDwfuTlf';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
$oCacher = new Cacher($sPattern, $sMapId);
|
$oCacher = new Cacher($sPattern, $sMapId);
|
||||||
$oCacher->setToken($sToken);
|
$oCacher->setToken($sToken);
|
||||||
$oCacher->setDomains($asDomains);
|
$oCacher->setDomains($asDomains);
|
||||||
|
$oCacher->setReferer($sReferer);
|
||||||
|
|
||||||
return $oCacher->pushTile($iX, $iY, $iZ);
|
return $oCacher->pushTile($iX, $iY, $iZ);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,14 @@ $sName = isset($_GET['name'])?$_GET['name']:'';
|
|||||||
$sContent = isset($_GET['content'])?$_GET['content']:'';
|
$sContent = isset($_GET['content'])?$_GET['content']:'';
|
||||||
$iChunk = isset($_GET['chunk'])?$_GET['chunk']:0;
|
$iChunk = isset($_GET['chunk'])?$_GET['chunk']:0;
|
||||||
$sId = isset($_REQUEST['id'])?$_REQUEST['id']:'';
|
$sId = isset($_REQUEST['id'])?$_REQUEST['id']:'';
|
||||||
|
$iProjectId = isset($_REQUEST['project_id'])?$_REQUEST['project_id']:'';
|
||||||
$iX = isset($_GET['x'])?$_GET['x']:0;
|
$iX = isset($_GET['x'])?$_GET['x']:0;
|
||||||
$iY = isset($_GET['y'])?$_GET['y']:0;
|
$iY = isset($_GET['y'])?$_GET['y']:0;
|
||||||
$iZ = isset($_GET['z'])?$_GET['z']:0;
|
$iZ = isset($_GET['z'])?$_GET['z']:0;
|
||||||
|
|
||||||
//Initiate class
|
//Initiate class
|
||||||
$oSpot = new Spot($oClassManagement, __FILE__);
|
$oSpot = new Spot($oClassManagement, __FILE__);
|
||||||
|
$oSpot->setProjectId($iProjectId);
|
||||||
|
|
||||||
$sResult = '';
|
$sResult = '';
|
||||||
if($sAction!='')
|
if($sAction!='')
|
||||||
@@ -49,6 +51,9 @@ if($sAction!='')
|
|||||||
case 'tile':
|
case 'tile':
|
||||||
$sResult = $oSpot->getTile($sId, $iX, $iY, $iZ);
|
$sResult = $oSpot->getTile($sId, $iX, $iY, $iZ);
|
||||||
break;
|
break;
|
||||||
|
/*case 'sql':
|
||||||
|
$sResult = $oSpot->getDbBuildScript();
|
||||||
|
break;*/
|
||||||
default:
|
default:
|
||||||
$sResult = Spot::getJsonResult(false, Spot::NOT_FOUND);
|
$sResult = Spot::getJsonResult(false, Spot::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,376 +0,0 @@
|
|||||||
<div id="messages">
|
|
||||||
<div id="map">
|
|
||||||
<div class="loader fa fa-map"></div>
|
|
||||||
</div>
|
|
||||||
<div id="legend">
|
|
||||||
<div class="line te_araroa">Te Araroa</div>
|
|
||||||
<div class="line routeburn">Routeburn Track</div>
|
|
||||||
<div class="line hitchhiking">Hors rando</div>
|
|
||||||
</div>
|
|
||||||
<div id="feed">
|
|
||||||
<div id="posts">
|
|
||||||
<div id="poster"></div>
|
|
||||||
<div id="posts_list"></div>
|
|
||||||
<div id="loading"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript" src="script/lightbox.min.js"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
oSpot.pageInit = function(asHash)
|
|
||||||
{
|
|
||||||
self.tmp('$Map', $('#map'));
|
|
||||||
|
|
||||||
//Add Loading
|
|
||||||
var asLoading = {
|
|
||||||
type: 'loading',
|
|
||||||
formatted_time: '',
|
|
||||||
relative_time: '',
|
|
||||||
displayed_id: 'Chargement...'
|
|
||||||
};
|
|
||||||
getPost(asLoading).appendTo($('#loading'));
|
|
||||||
|
|
||||||
self.get('messages', function(oMessages){
|
|
||||||
|
|
||||||
//Build Feed
|
|
||||||
self.tmp('updatable', true);
|
|
||||||
self.tmp('out-of-data', 'boolean');
|
|
||||||
updateFeed(true);
|
|
||||||
self.tmp('simple-bar', new SimpleBar($('#posts')[0]));
|
|
||||||
self.tmp('simple-bar').getScrollElement().addEventListener('scroll', onFeedScroll);
|
|
||||||
self.tmp('infowindow', 'boolean');
|
|
||||||
self.tmp('map_offset', -0.3);
|
|
||||||
self.tmp('tile_api', '?a=tile&id={id}&z={z}&x={x}&y={y}');
|
|
||||||
|
|
||||||
//Centering map
|
|
||||||
var agCenter = {lat:0, lng:0};
|
|
||||||
var iZoom = 0;
|
|
||||||
if(self.vars('mode')=='blog')
|
|
||||||
{
|
|
||||||
//on last message
|
|
||||||
var oLastMsg = oMessages[oMessages.length-1];
|
|
||||||
agCenter.lat = oLastMsg.latitude;
|
|
||||||
agCenter.lng = oLastMsg.longitude;
|
|
||||||
iZoom = 12;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var iMapPadding = 0.05;
|
|
||||||
var iMinLat, iMaxLat, iMinLng, iMaxLng;
|
|
||||||
iMinLat = iMinLng = 180;
|
|
||||||
iMaxLat = iMaxLng = -180;
|
|
||||||
$.each(oMessages, function(iKey, oMsg){
|
|
||||||
iMinLat = Math.min(iMinLat, oMsg.latitude);
|
|
||||||
iMaxLat = Math.max(iMaxLat, oMsg.latitude);
|
|
||||||
iMinLng = Math.min(iMinLng, oMsg.longitude);
|
|
||||||
iMaxLng = Math.max(iMaxLng, oMsg.longitude);
|
|
||||||
});
|
|
||||||
|
|
||||||
//Get Marker bounds
|
|
||||||
var oSouthWest = L.latLng(iMinLat, iMinLng);
|
|
||||||
var oNorthEast = L.latLng(iMaxLat, iMaxLng);
|
|
||||||
oMarkerBounds = new L.LatLngBounds(oSouthWest, oNorthEast);
|
|
||||||
agCenter = oMarkerBounds.getCenter();
|
|
||||||
|
|
||||||
//Calculate adequate zoom (map.fitBounds is dezooming too much)
|
|
||||||
var oMapDim = {
|
|
||||||
height: self.tmp('$Map').height()*(1 - iMapPadding),
|
|
||||||
width: self.tmp('$Map').width()*(1 + self.tmp('map_offset') - iMapPadding)
|
|
||||||
};
|
|
||||||
iZoom = getBoundsZoomLevel(oMarkerBounds, oMapDim);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Tile layers
|
|
||||||
var oMapBoxSat = L.tileLayer(self.tmp('tile_api'), {id: 'mapbox.satellite', minZoom: 0, maxZoom: 19}),
|
|
||||||
//oOpenTopoMap = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {id: 'OpenTopoMap', minZoom: 2, maxZoom: 19});
|
|
||||||
//oMapBoxStreet = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token='+self.vars('mapbox_key'), {id: 'mapbox.streets'}),
|
|
||||||
oLinz = L.tileLayer(self.tmp('tile_api'), {id: 'linz', maxZoom: 17, continuousWorld: true, attribution: 'Sourced from LINZ. CC BY 4.0'});
|
|
||||||
//oGoogleSatellite = L.tileLayer('https://mt.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', {id: 'GoogleSatellite', minZoom: 1, maxZoom: 22});
|
|
||||||
|
|
||||||
//Map
|
|
||||||
var oMap = L.map(self.tmp('$Map')[0], {
|
|
||||||
center: agCenter,
|
|
||||||
zoom: iZoom,
|
|
||||||
layers: [oMapBoxSat],
|
|
||||||
attributionControl: false,
|
|
||||||
zoomControl: false
|
|
||||||
});
|
|
||||||
|
|
||||||
//Controls
|
|
||||||
L.control.layers({'Satellite': oMapBoxSat, 'LINZ': oLinz}, null, {position: 'topleft'}).addTo(oMap);
|
|
||||||
|
|
||||||
//Te Araroa track
|
|
||||||
$.ajax({
|
|
||||||
dataType: 'json',
|
|
||||||
url: 'kml/TeAraroaTrail_simplified.geojson',
|
|
||||||
mimeType: 'application/json',
|
|
||||||
success: function(aoTracks) {
|
|
||||||
//Get track colors
|
|
||||||
var asColors = {};
|
|
||||||
$('#legend').find('.line').each(function(iKey, oLegend){
|
|
||||||
var $Legend = $(oLegend);
|
|
||||||
asColors[$Legend.attr('class').replace('line', '').trim()] = $Legend.css('border-top-color');
|
|
||||||
});
|
|
||||||
|
|
||||||
//Assign track color & popup
|
|
||||||
L.geoJson(aoTracks, {
|
|
||||||
style: function(oTrack) {return {color: asColors[oTrack.properties.type], weight: 4, opacity: 1};}
|
|
||||||
})
|
|
||||||
.bindPopup(function(oLayer) {
|
|
||||||
var asProperties = oLayer.feature.properties;
|
|
||||||
var $Tooltip = $('<div>', {'class':'track_tooltip'});
|
|
||||||
$('<p>', {'class':'name'}).text(asProperties.Name).appendTo($Tooltip);
|
|
||||||
if(asProperties.Name != asProperties.description) $('<p>', {'class':'description'}).text(asProperties.description).appendTo($Tooltip);
|
|
||||||
return $Tooltip[0];
|
|
||||||
})
|
|
||||||
.addTo(oMap);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Building messages
|
|
||||||
$.each(oMessages, function(iKey, oMsg){
|
|
||||||
|
|
||||||
//Marker
|
|
||||||
var oMarker = L.marker(L.latLng(oMsg.latitude, oMsg.longitude), {
|
|
||||||
id: oMsg.id_message,
|
|
||||||
riseOnHover: true,
|
|
||||||
icon: L.icon({
|
|
||||||
iconUrl: (iKey%2==0)?'images/footprint_alt.png':'images/footprint.png',
|
|
||||||
iconSize: [32, 37],
|
|
||||||
iconAnchor: [16, 37]
|
|
||||||
})
|
|
||||||
}).addTo(oMap);
|
|
||||||
|
|
||||||
//Marker events
|
|
||||||
oMarker.on({
|
|
||||||
mouseover: function(){
|
|
||||||
this.openPopup();
|
|
||||||
},
|
|
||||||
/*mouseout: function(){
|
|
||||||
|
|
||||||
},*/
|
|
||||||
click: function(oPoint){
|
|
||||||
self.tmp('map').setOffsetView(self.tmp('map_offset'), oPoint.latlng, 15);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Tooltip
|
|
||||||
$Tooltip = $('<div>', {'class':'info-window'})
|
|
||||||
.append($('<h1>').append('Message '+oMsg.type+' #'+oMsg.id_message))
|
|
||||||
.append($('<p>', {'class':'time'}).addIcon('fa-clock-o').append(oMsg.formatted_time+' ('+oMsg.relative_time+')'))
|
|
||||||
.append($('<p>', {'class':'coordinates'}).addIcon('fa-compass').append('Lat : '+oMsg.latitude+', Lng : '+oMsg.longitude));
|
|
||||||
|
|
||||||
//Tooltip pictures
|
|
||||||
if(oMsg.pics) {
|
|
||||||
var $Pics = $('<div>', {'class':'pics'});
|
|
||||||
$.each(oMsg.pics, function(iKey, asPic){
|
|
||||||
$Pics.append($('<a>', {href: asPic.path, 'data-lightbox': self.consts.title, 'data-title': asPic.formatted_time})
|
|
||||||
.append($('<img>', {'src': asPic.thumb_path})));
|
|
||||||
});
|
|
||||||
$Tooltip
|
|
||||||
.append($('<p>').addIcon('fa-image').append('Photos'))
|
|
||||||
.append($Pics);
|
|
||||||
}
|
|
||||||
|
|
||||||
oMarker.bindPopup($Tooltip[0], {
|
|
||||||
maxWidth: 1000,
|
|
||||||
keepInView: true,
|
|
||||||
closeOnClick: true,
|
|
||||||
offset: new L.Point(0, -30)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
//Recenter map to be at the center of 70% (map_offset) of the page, 30% being used by posts
|
|
||||||
if(self.vars('mode')!='blog') oMap.setOffsetView(self.tmp('map_offset'));
|
|
||||||
|
|
||||||
//Legend
|
|
||||||
var oLegend = L.control({position: 'bottomright'});
|
|
||||||
oLegend.onAdd = function(oMap) {return L.DomUtil.get('legend');};
|
|
||||||
oLegend.addTo(oMap);
|
|
||||||
|
|
||||||
self.tmp('map', oMap);
|
|
||||||
});
|
|
||||||
|
|
||||||
//Post
|
|
||||||
if(self.vars('mode')=='histo') $('#poster').hide();
|
|
||||||
else {
|
|
||||||
var asPoster = {
|
|
||||||
type: 'poster',
|
|
||||||
formatted_time: '',
|
|
||||||
relative_time: 'Nouveau message'
|
|
||||||
};
|
|
||||||
getPost(asPoster).appendTo($('#poster'));
|
|
||||||
|
|
||||||
$('#name').defaultVal('Nom...');
|
|
||||||
$('#post').defaultVal('Ton message...');
|
|
||||||
$('#submit').click(function(){
|
|
||||||
if($('#poster').checkForm())
|
|
||||||
{
|
|
||||||
self.get(
|
|
||||||
'add_post',
|
|
||||||
function()
|
|
||||||
{
|
|
||||||
$('#name').val('');
|
|
||||||
$('#post').val('');
|
|
||||||
updateFeed(true);
|
|
||||||
},
|
|
||||||
{name:$('#name').val(), content:$('#post').val()}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function getBoundsZoomLevel(bounds, mapDim) {
|
|
||||||
var WORLD_DIM = { height: 256, width: 256 };
|
|
||||||
var ZOOM_MAX = 21;
|
|
||||||
|
|
||||||
function latRad(lat) {
|
|
||||||
var sin = Math.sin(lat * Math.PI / 180);
|
|
||||||
var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
|
|
||||||
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function zoom(mapPx, worldPx, fraction) {
|
|
||||||
return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ne = bounds.getNorthEast();
|
|
||||||
var sw = bounds.getSouthWest();
|
|
||||||
|
|
||||||
var latFraction = (latRad(ne.lat) - latRad(sw.lat)) / Math.PI;
|
|
||||||
|
|
||||||
var lngDiff = ne.lng - sw.lng;
|
|
||||||
var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
|
|
||||||
|
|
||||||
var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
|
|
||||||
var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);
|
|
||||||
|
|
||||||
return Math.min(latZoom, lngZoom, ZOOM_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
L.Map.include({
|
|
||||||
setOffsetView: function (iOffsetRatioX, oCenter, iZoomLevel) {
|
|
||||||
var oCenter = (typeof oCenter == 'object')?$.extend({}, oCenter):this.getCenter();
|
|
||||||
iZoomLevel = iZoomLevel || this.getZoom();
|
|
||||||
|
|
||||||
var oBounds = this.getBounds();
|
|
||||||
var iOffsetX = (oBounds.getEast() - oBounds.getWest()) * iOffsetRatioX / ( 2 * Math.pow(2, iZoomLevel - this.getZoom()));
|
|
||||||
oCenter.lng = oCenter.lng - iOffsetX;
|
|
||||||
|
|
||||||
this.setView(oCenter, iZoomLevel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function onFeedScroll(){
|
|
||||||
var $Box = $(this);
|
|
||||||
var $BoxContent = $Box.find('.simplebar-content');
|
|
||||||
if(($Box.scrollTop() + $(window).height()) / $BoxContent.height() >= 0.8) updateFeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFeed(bFirstChunk)
|
|
||||||
{
|
|
||||||
bFirstChunk = bFirstChunk || false;
|
|
||||||
|
|
||||||
if(self.tmp('updatable')) {
|
|
||||||
if(!self.tmp('out-of-data') || bFirstChunk) {
|
|
||||||
var $Posts = $('#posts_list');
|
|
||||||
if(bFirstChunk===true) {
|
|
||||||
$Posts.empty();
|
|
||||||
self.tmp('news_chunk', 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tmp('updatable', false);
|
|
||||||
$('#loading').fadeIn('fast');
|
|
||||||
|
|
||||||
self.get('feed', function(asData) {
|
|
||||||
|
|
||||||
$.each(asData, function(iKey, asPost){
|
|
||||||
getPost(asPost).appendTo($Posts);
|
|
||||||
});
|
|
||||||
|
|
||||||
//oSimpleBar.recalculate();
|
|
||||||
|
|
||||||
self.tmp('news_chunk', self.tmp('news_chunk') + 1);
|
|
||||||
self.tmp('out-of-data', Object.keys(asData).length != self.vars('chunk_size'));
|
|
||||||
self.tmp('updatable', true);
|
|
||||||
$('#loading').fadeOut('fast');
|
|
||||||
}, {
|
|
||||||
'chunk': self.tmp('news_chunk')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(bFirstChunk) { //Delaying important data load
|
|
||||||
if(typeof oUpdateTimer != 'undefined') clearTimeout(oUpdateTimer);
|
|
||||||
oUpdateTimer = setTimeout(function(){updateFeed(true);}, 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPost(asPost) {
|
|
||||||
var $Post = $('<div>', {'class':'post '+asPost.type});
|
|
||||||
var sRelTime = (self.vars('mode')=='histo')?asPost.formatted_time.substr(0, 10):asPost.relative_time;
|
|
||||||
var sAbsTime = asPost.formatted_time;
|
|
||||||
var $Body = {};
|
|
||||||
switch(asPost.type)
|
|
||||||
{
|
|
||||||
case 'message':
|
|
||||||
$Body = $('<div>')
|
|
||||||
.append($('<p>').addIcon('fa-compass', true).append('Latitude '+asPost.latitude+', Longitude '+asPost.longitude))
|
|
||||||
.append($('<p>').addIcon('fa-clock-o', true).append(sAbsTime))
|
|
||||||
.append(
|
|
||||||
$('<img>', {'class':'staticmap', title: 'Click pour zoomer', src: getStaticMapUrl(asPost.latitude, asPost.longitude)})
|
|
||||||
.data('lat', asPost.latitude)
|
|
||||||
.data('lng', asPost.longitude)
|
|
||||||
.click(function(){
|
|
||||||
var $This = $(this);
|
|
||||||
var oCenter = L.latLng(parseFloat($This.data('lat')), parseFloat($This.data('lng')));
|
|
||||||
self.tmp('map').setOffsetView(self.tmp('map_offset'), oCenter, 13);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
sClass = 'compass';
|
|
||||||
break;
|
|
||||||
case 'picture':
|
|
||||||
var $Image = $('<img>', {'src': asPost.thumb_path/*, 'style':'transform:rotate('+asPost.rotate+'deg);'*/});
|
|
||||||
$Body = $('<a>', {href: asPost.path, 'data-lightbox': self.consts.title, 'data-title': sAbsTime}).append($Image);
|
|
||||||
sClass = 'image';
|
|
||||||
break;
|
|
||||||
case 'post':
|
|
||||||
$Body = $('<div>')
|
|
||||||
.append($('<p>', {'class':'message'}).text(asPost.content))
|
|
||||||
.append($('<p>', {'class':'signature'}).text('-- '+asPost.formatted_name));
|
|
||||||
sClass = 'comment';
|
|
||||||
break;
|
|
||||||
case 'poster':
|
|
||||||
$Body = $('<p>', {'class':'message'})
|
|
||||||
.append($('<input>', {type:'text', id:'post', name:'post'}))
|
|
||||||
.append($('<input>', {type:'text', id:'name', name:'name'}))
|
|
||||||
.append($('<button>', {type:'button', id:'submit', name:'submit'}).addIcon('fa-send'));
|
|
||||||
sClass = 'comment';
|
|
||||||
break;
|
|
||||||
case 'loading':
|
|
||||||
$Body = $('<p>', {'class':'spinner'}).addIcon('fa-spin fa-spinner');
|
|
||||||
sClass = 'tasks';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$Post
|
|
||||||
.append($('<div>', {'class':'header'})
|
|
||||||
.append($('<span>', {'class':'index'}).addIcon('fa-'+sClass))
|
|
||||||
.append($('<span>', {'class':'time', 'title':sAbsTime}).text(sRelTime)))
|
|
||||||
.append($('<div>', {'class':'body'}).append($Body));
|
|
||||||
|
|
||||||
if(asPost.displayed_id) $Post.find('.index').append(' '+asPost.displayed_id);
|
|
||||||
|
|
||||||
return $Post;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStaticMapUrl(oCenterLat, oCenterLng) {
|
|
||||||
var asParams = [
|
|
||||||
'https://api.mapbox.com/v4/mapbox.satellite', //Domain
|
|
||||||
'url-http%3A%2F%2Fspot.lutran.fr%2Fimages%2Ffootprint.png('+oCenterLng+','+oCenterLat+')', //Marker
|
|
||||||
oCenterLng+','+oCenterLat+',13', //Center + zoom
|
|
||||||
'400x300.png?access_token='+self.vars('mapbox_key') //Image size + access token
|
|
||||||
];
|
|
||||||
|
|
||||||
return asParams.join('/');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
385
masks/project.html
Executable file
385
masks/project.html
Executable file
@@ -0,0 +1,385 @@
|
|||||||
|
<div id="messages">
|
||||||
|
<div id="map">
|
||||||
|
<div class="loader fa fa-map"></div>
|
||||||
|
</div>
|
||||||
|
<div id="legend">
|
||||||
|
<div class="line main">Trajet principal</div>
|
||||||
|
<div class="line off-track">Variante</div>
|
||||||
|
<div class="line hitchhiking">Hors rando</div>
|
||||||
|
</div>
|
||||||
|
<div id="feed">
|
||||||
|
<div id="posts">
|
||||||
|
<div id="poster"></div>
|
||||||
|
<div id="posts_list"></div>
|
||||||
|
<div id="loading"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="script/lightbox.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
self.onSamePageMove = function(asHash){
|
||||||
|
self.tmp('map').remove();
|
||||||
|
self.tmp('$Map').empty();
|
||||||
|
self.pageInit(asHash);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
oSpot.pageInit = function(asHash)
|
||||||
|
{
|
||||||
|
//Set active project
|
||||||
|
if(asHash.items.length==0) {
|
||||||
|
self.setHash(asHash.page, [self.vars('default_project_codename')]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.vars('project', self.vars(['projects', asHash.items[0]]));
|
||||||
|
self.tmp('$Map', $('#map'));
|
||||||
|
self.tmp('tracktype-colors', 'object');
|
||||||
|
|
||||||
|
//Assign Track Type Colors
|
||||||
|
$('#legend').find('.line').each(function(iKey, oLegend){
|
||||||
|
var $Legend = $(oLegend);
|
||||||
|
var sTrackType = $Legend.attr('class').replace('line', '').trim();
|
||||||
|
self.tmp(['tracktype-colors', sTrackType], $Legend.css('border-top-color'));
|
||||||
|
});
|
||||||
|
|
||||||
|
//Add "Loading" Post
|
||||||
|
var asLoading = {
|
||||||
|
type: 'loading',
|
||||||
|
formatted_time: '',
|
||||||
|
relative_time: '',
|
||||||
|
displayed_id: 'Chargement...'
|
||||||
|
};
|
||||||
|
getPost(asLoading).appendTo($('#loading'));
|
||||||
|
|
||||||
|
//Spot Messages
|
||||||
|
$.when(
|
||||||
|
self.get(
|
||||||
|
'messages',
|
||||||
|
function(){},
|
||||||
|
{project_id: self.vars(['project', 'id'])},
|
||||||
|
function(e){console.log(e);}
|
||||||
|
),
|
||||||
|
$.ajax({
|
||||||
|
dataType: 'json',
|
||||||
|
url: self.consts.geo_folder+self.vars(['project', 'geofile']),
|
||||||
|
mimeType: 'application/json'
|
||||||
|
})
|
||||||
|
).done(function(oMessages, aoTracks) {
|
||||||
|
buildSpotMessages(oMessages[0]['data'], aoTracks[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Posts
|
||||||
|
updateFeed(true);
|
||||||
|
initPosts();
|
||||||
|
};
|
||||||
|
|
||||||
|
function buildSpotMessages(oMessages, aoTracks){
|
||||||
|
|
||||||
|
//Build Feed
|
||||||
|
self.tmp('updatable', true);
|
||||||
|
self.tmp('out-of-data', 'boolean');
|
||||||
|
self.tmp('simple-bar', new SimpleBar($('#posts')[0]));
|
||||||
|
self.tmp('simple-bar').getScrollElement().addEventListener('scroll', onFeedScroll);
|
||||||
|
self.tmp('infowindow', 'boolean');
|
||||||
|
self.tmp('feed_width', $('#feed').outerWidth(true));
|
||||||
|
self.tmp('map_offset', -1 * self.tmp('feed_width') / $('body').outerWidth(true));
|
||||||
|
self.tmp('map_padding', 0.05);
|
||||||
|
self.tmp('tile_api', '?a=tile&id={id}&z={z}&x={x}&y={y}');
|
||||||
|
|
||||||
|
//Tile layers
|
||||||
|
var oMapBoxSat = L.tileLayer(self.tmp('tile_api'), {id: 'mapbox.satellite', minZoom: 0, maxZoom: 19}),
|
||||||
|
//oOpenTopoMap = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {id: 'OpenTopoMap', minZoom: 2, maxZoom: 19});
|
||||||
|
//oMapBoxStreet = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token='+self.vars('mapbox_key'), {id: 'mapbox.streets'}),
|
||||||
|
oIgnSpain = L.tileLayer(self.tmp('tile_api'), {id: 'ign.es', minZoom: 1, maxZoom: 20}),
|
||||||
|
oIgnFrance = L.tileLayer(self.tmp('tile_api'), {id: 'ign.fr', minZoom: 0, maxZoom: 18, tileSize: 256}),
|
||||||
|
oLinz = L.tileLayer(self.tmp('tile_api'), {id: 'linz', maxZoom: 17, continuousWorld: true, attribution: 'Sourced from LINZ. CC BY 4.0'});
|
||||||
|
//oGoogleSatellite = L.tileLayer('https://mt.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', {id: 'GoogleSatellite', minZoom: 1, maxZoom: 22});
|
||||||
|
|
||||||
|
//Map
|
||||||
|
var oMap = L.map(self.tmp('$Map')[0], {
|
||||||
|
//center: agCenter,
|
||||||
|
//zoom: iZoom,
|
||||||
|
layers: [oMapBoxSat],
|
||||||
|
attributionControl: false,
|
||||||
|
zoomControl: false
|
||||||
|
});
|
||||||
|
|
||||||
|
//Tracks, colors & popup
|
||||||
|
var oTracks = L.geoJson(aoTracks, {
|
||||||
|
style: function(oTrack) {return {color: self.tmp(['tracktype-colors', oTrack.properties.type]), weight: 4, opacity: 1};}
|
||||||
|
})
|
||||||
|
.bindPopup(function(oLayer) {
|
||||||
|
var asProperties = oLayer.feature.properties;
|
||||||
|
var $Tooltip = $('<div>', {'class':'track_tooltip'});
|
||||||
|
$('<p>', {'class':'name'}).text(asProperties.name).appendTo($Tooltip);
|
||||||
|
if(asProperties.Name != asProperties.description) $('<p>', {'class':'description'}).text(asProperties.description).appendTo($Tooltip);
|
||||||
|
return $Tooltip[0];
|
||||||
|
})
|
||||||
|
.addTo(oMap);
|
||||||
|
|
||||||
|
//Centering map
|
||||||
|
if(self.vars(['project', 'mode'])==self.consts.modes.blog)
|
||||||
|
{
|
||||||
|
//Zoom on last message
|
||||||
|
var oLastMsg = oMessages[oMessages.length-1];
|
||||||
|
oMap.setView(L.latLng(oLastMsg.latitude, oLastMsg.longitude), 15);
|
||||||
|
|
||||||
|
//Recenter map to be at the center of 70% (map_offset) of the page, 30% being used by posts
|
||||||
|
oMap.setOffsetView(self.tmp('map_offset'));
|
||||||
|
}
|
||||||
|
else oMap.fitBounds(oTracks.getBounds(), {paddingTopLeft: L.point(5, 42), paddingBottomRight: L.point(self.tmp('feed_width')+5, 5)});
|
||||||
|
|
||||||
|
//Controls
|
||||||
|
L.control.layers({
|
||||||
|
'Satellite': oMapBoxSat,
|
||||||
|
'IGN (France)': oIgnFrance,
|
||||||
|
'IGN (Espagne)': oIgnSpain,
|
||||||
|
'LINZ (Nouvelle-Zélande)': oLinz
|
||||||
|
}, null, {position: 'topleft'}).addTo(oMap);
|
||||||
|
|
||||||
|
//Building messages
|
||||||
|
$.each(oMessages, function(iKey, oMsg){
|
||||||
|
|
||||||
|
//Marker
|
||||||
|
var oMarker = L.marker(L.latLng(oMsg.latitude, oMsg.longitude), {
|
||||||
|
id: oMsg.id_message,
|
||||||
|
riseOnHover: true,
|
||||||
|
icon: L.icon({
|
||||||
|
iconUrl: (iKey%2==0)?'images/footprint_alt.png':'images/footprint.png',
|
||||||
|
iconSize: [32, 37],
|
||||||
|
iconAnchor: [16, 37]
|
||||||
|
})
|
||||||
|
}).addTo(oMap);
|
||||||
|
|
||||||
|
//Marker events
|
||||||
|
oMarker.on({
|
||||||
|
mouseover: function(){
|
||||||
|
this.openPopup();
|
||||||
|
},
|
||||||
|
/*mouseout: function(){
|
||||||
|
|
||||||
|
},*/
|
||||||
|
click: function(oPoint){
|
||||||
|
self.tmp('map').setOffsetView(self.tmp('map_offset'), oPoint.latlng, 15);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Tooltip
|
||||||
|
$Tooltip = $('<div>', {'class':'info-window'})
|
||||||
|
.append($('<h1>').append('Message '+oMsg.type+' #'+oMsg.id_message))
|
||||||
|
.append($('<p>', {'class':'time'}).addIcon('fa-clock-o').append(oMsg.formatted_time+' ('+oMsg.relative_time+')'))
|
||||||
|
.append($('<p>', {'class':'coordinates'}).addIcon('fa-compass').append('Lat : '+oMsg.latitude+', Lng : '+oMsg.longitude));
|
||||||
|
|
||||||
|
//Tooltip pictures
|
||||||
|
if(oMsg.pics) {
|
||||||
|
var $Pics = $('<div>', {'class':'pics'});
|
||||||
|
$.each(oMsg.pics, function(iKey, asPic){
|
||||||
|
$Pics.append($('<a>', {href: asPic.path, 'data-lightbox': self.consts.title, 'data-title': asPic.formatted_time})
|
||||||
|
.append($('<img>', {'src': asPic.thumb_path})));
|
||||||
|
});
|
||||||
|
$Tooltip
|
||||||
|
.append($('<p>').addIcon('fa-image').append('Photos'))
|
||||||
|
.append($Pics);
|
||||||
|
}
|
||||||
|
|
||||||
|
oMarker.bindPopup($Tooltip[0], {
|
||||||
|
maxWidth: 1000,
|
||||||
|
keepInView: true,
|
||||||
|
closeOnClick: true,
|
||||||
|
offset: new L.Point(0, -30)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//Legend
|
||||||
|
var oLegend = L.control({position: 'bottomright'});
|
||||||
|
oLegend.onAdd = function(oMap) {return L.DomUtil.get('legend');};
|
||||||
|
oLegend.addTo(oMap);
|
||||||
|
|
||||||
|
self.tmp('map', oMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPosts() {
|
||||||
|
if(self.vars(['project', 'mode'])==self.consts.modes.histo) $('#poster').hide();
|
||||||
|
else {
|
||||||
|
var asPoster = {
|
||||||
|
type: 'poster',
|
||||||
|
formatted_time: '',
|
||||||
|
relative_time: 'Nouveau message'
|
||||||
|
};
|
||||||
|
getPost(asPoster).appendTo($('#poster'));
|
||||||
|
|
||||||
|
//$('#name').defaultVal('Nom...');
|
||||||
|
//$('#post').defaultVal('Ton message...');
|
||||||
|
$('#submit').click(function(){
|
||||||
|
if($('#poster').checkForm())
|
||||||
|
{
|
||||||
|
self.get(
|
||||||
|
'add_post',
|
||||||
|
function()
|
||||||
|
{
|
||||||
|
$('#name').val('');
|
||||||
|
$('#post').val('');
|
||||||
|
updateFeed(true);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
project_id: self.vars(['project', 'id']),
|
||||||
|
name: $('#name').val(),
|
||||||
|
content: $('#post').val()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBoundsZoomLevel(bounds, mapDim) {
|
||||||
|
var WORLD_DIM = { height: 256, width: 256 };
|
||||||
|
var ZOOM_MAX = 21;
|
||||||
|
|
||||||
|
function latRad(lat) {
|
||||||
|
var sin = Math.sin(lat * Math.PI / 180);
|
||||||
|
var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
|
||||||
|
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoom(mapPx, worldPx, fraction) {
|
||||||
|
return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ne = bounds.getNorthEast();
|
||||||
|
var sw = bounds.getSouthWest();
|
||||||
|
|
||||||
|
var latFraction = (latRad(ne.lat) - latRad(sw.lat)) / Math.PI;
|
||||||
|
|
||||||
|
var lngDiff = ne.lng - sw.lng;
|
||||||
|
var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
|
||||||
|
|
||||||
|
var latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
|
||||||
|
var lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);
|
||||||
|
|
||||||
|
return Math.min(latZoom, lngZoom, ZOOM_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
L.Map.include({
|
||||||
|
setOffsetView: function (iOffsetRatioX, oCenter, iZoomLevel) {
|
||||||
|
var oCenter = (typeof oCenter == 'object')?$.extend({}, oCenter):this.getCenter();
|
||||||
|
iZoomLevel = iZoomLevel || this.getZoom();
|
||||||
|
|
||||||
|
var oBounds = this.getBounds();
|
||||||
|
var iOffsetX = (oBounds.getEast() - oBounds.getWest()) * iOffsetRatioX / ( 2 * Math.pow(2, iZoomLevel - this.getZoom()));
|
||||||
|
oCenter.lng = oCenter.lng - iOffsetX;
|
||||||
|
|
||||||
|
this.setView(oCenter, iZoomLevel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onFeedScroll(){
|
||||||
|
var $Box = $(this);
|
||||||
|
var $BoxContent = $Box.find('.simplebar-content');
|
||||||
|
if(($Box.scrollTop() + $(window).height()) / $BoxContent.height() >= 0.8) updateFeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFeed(bFirstChunk)
|
||||||
|
{
|
||||||
|
bFirstChunk = bFirstChunk || false;
|
||||||
|
|
||||||
|
if(self.tmp('updatable')) {
|
||||||
|
if(!self.tmp('out-of-data') || bFirstChunk) {
|
||||||
|
var $Posts = $('#posts_list');
|
||||||
|
if(bFirstChunk===true) {
|
||||||
|
$Posts.empty();
|
||||||
|
self.tmp('news_chunk', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tmp('updatable', false);
|
||||||
|
$('#loading').fadeIn('fast');
|
||||||
|
|
||||||
|
self.get('feed', function(asData) {
|
||||||
|
$('#loading').hide();
|
||||||
|
$.each(asData, function(iKey, asPost){
|
||||||
|
getPost(asPost).appendTo($Posts);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.tmp('news_chunk', self.tmp('news_chunk') + 1);
|
||||||
|
self.tmp('out-of-data', Object.keys(asData).length != self.vars('chunk_size'));
|
||||||
|
self.tmp('updatable', true);
|
||||||
|
}, {
|
||||||
|
'project_id': self.vars(['project', 'id']),
|
||||||
|
'chunk': self.tmp('news_chunk')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(bFirstChunk) { //Delaying important data load
|
||||||
|
if(typeof oUpdateTimer != 'undefined') clearTimeout(oUpdateTimer);
|
||||||
|
oUpdateTimer = setTimeout(function(){updateFeed(true);}, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPost(asPost) {
|
||||||
|
var $Post = $('<div>', {'class':'post '+asPost.type});
|
||||||
|
var sRelTime = (self.vars(['project', 'mode'])==self.consts.modes.histo)?asPost.formatted_time.substr(0, 10):asPost.relative_time;
|
||||||
|
var sAbsTime = asPost.formatted_time;
|
||||||
|
var $Body = {};
|
||||||
|
switch(asPost.type)
|
||||||
|
{
|
||||||
|
case 'message':
|
||||||
|
$Body = $('<div>')
|
||||||
|
.append($('<p>').addIcon('fa-compass', true).append('Latitude '+asPost.latitude+', Longitude '+asPost.longitude))
|
||||||
|
.append($('<p>').addIcon('fa-clock-o', true).append(sAbsTime))
|
||||||
|
.append(
|
||||||
|
$('<img>', {'class':'staticmap', title: 'Click pour zoomer', src: getStaticMapUrl(asPost.latitude, asPost.longitude)})
|
||||||
|
.data('lat', asPost.latitude)
|
||||||
|
.data('lng', asPost.longitude)
|
||||||
|
.click(function(){
|
||||||
|
var $This = $(this);
|
||||||
|
var oCenter = L.latLng(parseFloat($This.data('lat')), parseFloat($This.data('lng')));
|
||||||
|
self.tmp('map').setOffsetView(self.tmp('map_offset'), oCenter, 13);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
sClass = 'compass';
|
||||||
|
break;
|
||||||
|
case 'picture':
|
||||||
|
var $Image = $('<img>', {'src': asPost.thumb_path/*, 'style':'transform:rotate('+asPost.rotate+'deg);'*/});
|
||||||
|
$Body = $('<a>', {href: asPost.path, 'data-lightbox': self.consts.title, 'data-title': sAbsTime}).append($Image);
|
||||||
|
sClass = 'image';
|
||||||
|
break;
|
||||||
|
case 'post':
|
||||||
|
$Body = $('<div>')
|
||||||
|
.append($('<p>', {'class':'message'}).text(asPost.content))
|
||||||
|
.append($('<p>', {'class':'signature'}).text('-- '+asPost.formatted_name));
|
||||||
|
sClass = 'comment';
|
||||||
|
break;
|
||||||
|
case 'poster':
|
||||||
|
$Body = $('<p>', {'class':'message'})
|
||||||
|
.append($('<input>', {type:'text', id:'post', name:'post', placeholder:'Message'}))
|
||||||
|
.append($('<input>', {type:'text', id:'name', name:'name', placeholder:'Nom'}))
|
||||||
|
.append($('<button>', {type:'button', id:'submit', name:'submit'}).addIcon('fa-send'));
|
||||||
|
sClass = 'comment';
|
||||||
|
break;
|
||||||
|
case 'loading':
|
||||||
|
$Body = $('<p>', {'class':'spinner'}).addIcon('fa-spin fa-spinner');
|
||||||
|
sClass = 'tasks';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$Post
|
||||||
|
.append($('<div>', {'class':'header'})
|
||||||
|
.append($('<span>', {'class':'index'}).addIcon('fa-'+sClass))
|
||||||
|
.append($('<span>', {'class':'time', 'title':sAbsTime}).text(sRelTime)))
|
||||||
|
.append($('<div>', {'class':'body'}).append($Body));
|
||||||
|
|
||||||
|
if(asPost.displayed_id) $Post.find('.index').append(' '+asPost.displayed_id);
|
||||||
|
|
||||||
|
return $Post;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStaticMapUrl(oCenterLat, oCenterLng) {
|
||||||
|
var asParams = [
|
||||||
|
'https://api.mapbox.com/v4/mapbox.satellite', //Domain
|
||||||
|
'url-http%3A%2F%2Fspot.lutran.fr%2Fimages%2Ffootprint.png('+oCenterLng+','+oCenterLat+')', //Marker
|
||||||
|
oCenterLng+','+oCenterLat+',13', //Center + zoom
|
||||||
|
'400x300.png?access_token='+self.vars('mapbox_key') //Image size + access token
|
||||||
|
];
|
||||||
|
|
||||||
|
return asParams.join('/');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
4
script/leaflet.min.js
vendored
4
script/leaflet.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@ function Spot(asGlobals)
|
|||||||
this.consts = asGlobals.consts;
|
this.consts = asGlobals.consts;
|
||||||
this.consts.hash_sep = '-';
|
this.consts.hash_sep = '-';
|
||||||
this.consts.title = 'Te Araroa';
|
this.consts.title = 'Te Araroa';
|
||||||
this.consts.default_page = 'messages';
|
this.consts.default_page = 'project';
|
||||||
|
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
@@ -63,11 +63,12 @@ function Spot(asGlobals)
|
|||||||
this.get = function(sAction, fOnSuccess, oVars, fOnError, bProcessIcon)
|
this.get = function(sAction, fOnSuccess, oVars, fOnError, bProcessIcon)
|
||||||
{
|
{
|
||||||
if(!oVars) oVars = {};
|
if(!oVars) oVars = {};
|
||||||
|
fOnError = fOnError || function(textStatus, errorThrown) {console.log(textStatus+' '+errorThrown);};
|
||||||
bProcessIcon = bProcessIcon || false;
|
bProcessIcon = bProcessIcon || false;
|
||||||
//if(bProcessIcon) self.addBufferIcon();
|
//if(bProcessIcon) self.addBufferIcon();
|
||||||
|
|
||||||
oVars['a'] = sAction;
|
oVars['a'] = sAction;
|
||||||
$.ajax(
|
return $.ajax(
|
||||||
{
|
{
|
||||||
url: self.consts.process_page,
|
url: self.consts.process_page,
|
||||||
data: oVars,
|
data: oVars,
|
||||||
@@ -85,8 +86,7 @@ function Spot(asGlobals)
|
|||||||
.fail(function(jqXHR, textStatus, errorThrown)
|
.fail(function(jqXHR, textStatus, errorThrown)
|
||||||
{
|
{
|
||||||
//if(bProcessIcon) self.resetIcon();
|
//if(bProcessIcon) self.resetIcon();
|
||||||
if(!fOnError) console.log(textStatus+' '+errorThrown);
|
fOnError(textStatus, errorThrown);
|
||||||
else fOnError(textStatus);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,7 @@ class Settings
|
|||||||
const TEXT_ENC = 'UTF-8';
|
const TEXT_ENC = 'UTF-8';
|
||||||
const TIMEZONE = 'Europe/Paris';
|
const TIMEZONE = 'Europe/Paris';
|
||||||
const MAPBOX_KEY = '';
|
const MAPBOX_KEY = '';
|
||||||
|
const IGN_FR_KEY = '';
|
||||||
const LINZ_KEY = '';
|
const LINZ_KEY = '';
|
||||||
const MODE = Spot::MODE_BLOG; //Spot::MODE_HISTO/MODE_BLOG
|
|
||||||
const HISTO_SPAN = array('from'=>'2015-12-29 00:00:00', 'to'=>'2016-02-23 23:59:59');
|
|
||||||
const FEED_ID = ''; //Spot Feed ID
|
|
||||||
const DEBUG = true;
|
const DEBUG = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -389,7 +389,7 @@
|
|||||||
|
|
||||||
/* Default icon URLs */
|
/* Default icon URLs */
|
||||||
.leaflet-default-icon-path {
|
.leaflet-default-icon-path {
|
||||||
background-image: url(images/marker-icon.png);
|
background-image: url(../images/marker-icon.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,34 +6,37 @@
|
|||||||
@import 'leaflet';
|
@import 'leaflet';
|
||||||
@import 'common';
|
@import 'common';
|
||||||
|
|
||||||
#map {
|
#messages {
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
background: #EEE;
|
|
||||||
|
|
||||||
.loader {
|
#map {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 3em;
|
left: 0;
|
||||||
width: 1em;
|
top: 0;
|
||||||
height: 1em;
|
bottom: 0;
|
||||||
top: calc(50% - 0.5em);
|
width: 100%;
|
||||||
left: calc(50% - 0.5em);
|
background: #EEE;
|
||||||
color: #666;
|
|
||||||
@extend .flicker;
|
|
||||||
}
|
|
||||||
|
|
||||||
.track_tooltip {
|
.loader {
|
||||||
p {
|
position: absolute;
|
||||||
margin: 0;
|
font-size: 3em;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
top: calc(50% - 0.5em);
|
||||||
|
left: calc(50% - 0.5em);
|
||||||
|
color: #666;
|
||||||
|
@extend .flicker;
|
||||||
|
}
|
||||||
|
|
||||||
&.name {
|
.track_tooltip {
|
||||||
font-weight: bold;
|
p {
|
||||||
}
|
margin: 0;
|
||||||
&.description {
|
|
||||||
font-style: italic;
|
&.name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
&.description {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,11 +60,10 @@
|
|||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
color: #222;
|
color: #222;
|
||||||
|
|
||||||
&.te_araroa {
|
&.main {
|
||||||
border-color: #00ff78;
|
border-color: #00ff78;
|
||||||
}
|
}
|
||||||
|
&.off-track {
|
||||||
&.routeburn {
|
|
||||||
border-color: #0000ff;
|
border-color: #0000ff;
|
||||||
}
|
}
|
||||||
&.hitchhiking {
|
&.hitchhiking {
|
||||||
@@ -73,9 +75,10 @@
|
|||||||
|
|
||||||
#feed {
|
#feed {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 1em;
|
right: 0;
|
||||||
top: 0em;
|
top: 0;
|
||||||
bottom: 0em;
|
bottom: 0;
|
||||||
|
margin-right: 1em;
|
||||||
width: calc(30% - 1em);
|
width: calc(30% - 1em);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user