Replace Leaftlet Elevation with HeightGraph

This commit is contained in:
2020-04-20 11:57:53 +02:00
parent 0c5edb862b
commit ead9cf3a49
15 changed files with 359 additions and 957 deletions

View File

@@ -23,6 +23,7 @@ class Converter extends PhpObject {
$oGeoJson->buildTracks($oGpx->getTracks());
if($oGeoJson->isSimplicationRequired()) $oGeoJson->buildTracks($oGpx->getTracks(), true);
$oGeoJson->sortOffTracks();
$oGeoJson->saveFile();
return $oGpx->getLog().'<br />'.$oGeoJson->getLog();
@@ -205,6 +206,58 @@ class GeoJson extends Geo {
if($bSimplify) $this->addNotice('Total: '.$iGlobalInvalidPointCount.'/'.$iGlobalPointCount.' points removed ('.round($iGlobalInvalidPointCount / $iGlobalPointCount * 100, 1).'%)');
}
public function sortOffTracks() {
$this->addNotice('Sorting off-tracks');
//Find first & last track points
$asTracksEnds = array();
$asTracks = array();
foreach($this->asTracks as $iTrackId=>$asTrack) {
$sTrackId = 't'.$iTrackId;
$asTracksEnds[$sTrackId] = array('first'=>reset($asTrack['geometry']['coordinates']), 'last'=>end($asTrack['geometry']['coordinates']));
$asTracks[$sTrackId] = $asTrack;
}
//Find variants close-by tracks
$asClonedTracks = $asTracks;
foreach($asClonedTracks as $sTrackId=>$asTrack) {
if($asTrack['properties']['type'] != 'off-track') continue;
$iMinDistance = INF;
$sConnectedTrackId = 0;
$iPosition = 0;
//Test all track ending points to find the closest
foreach($asTracksEnds as $sTrackEndId=>$asTrackEnds) {
if($sTrackEndId != $sTrackId) {
//Calculate distance between the last point of the track and every starting point of other tracks
$iDistance = self::getDistance($asTracksEnds[$sTrackId]['last'], $asTrackEnds['first']);
if($iDistance < $iMinDistance) {
$sConnectedTrackId = $sTrackEndId;
$iPosition = 0; //Track before the Connected Track
$iMinDistance = $iDistance;
}
//Calculate distance between the first point of the track and every ending point of other tracks
$iDistance = self::getDistance($asTracksEnds[$sTrackId]['first'], $asTrackEnds['last']);
if($iDistance < $iMinDistance) {
$sConnectedTrackId = $sTrackEndId;
$iPosition = +1; //Track after the Connected Track
$iMinDistance = $iDistance;
}
}
}
//Move track
unset($asTracks[$sTrackId]);
$iOffset = array_search($sConnectedTrackId, array_keys($asTracks)) + $iPosition;
$asTracks = array_slice($asTracks, 0, $iOffset) + array($sTrackId => $asTrack) + array_slice($asTracks, $iOffset);
}
$this->asTracks = array_values($asTracks);
}
private function parseOptions($sComment){
$asOptions = array(self::OPT_SIMPLE=>'');
foreach(explode("\n", $sComment) as $sLine) {
@@ -243,6 +296,21 @@ class GeoJson extends Geo {
}
private function buildGeoJson() {
return json_encode(array('features'=>$this->asTracks));
return json_encode(array('type'=>'FeatureCollection', 'features'=>$this->asTracks));
}
private static function getDistance($asPointA, $asPointB) {
$fLatFrom = $asPointA[1];
$fLonFrom = $asPointA[0];
$fLatTo = $asPointB[1];
$fLonTo = $asPointB[0];
$fRad = M_PI / 180;
//Calculate distance from latitude and longitude
$fTheta = $fLonFrom - $fLonTo;
$fDistance = sin($fLatFrom * $fRad) * sin($fLatTo * $fRad) + cos($fLatFrom * $fRad) * cos($fLatTo * $fRad) * cos($fTheta * $fRad);
return acos($fDistance) / $fRad * 60 * 1.853;
}
}

View File

@@ -6,7 +6,7 @@ save = Save
admin_save_success = Saved
track_main = Main track
track_offtrack = Off-track
track_off-track = Off-track
track_hitchhiking = Hitchhiking
track_download = Download GPX Track
@@ -96,3 +96,9 @@ email_update_subject= Spotted!
update_preheader = New position received
update_title = Message
update_latest_news = Latest news:
distance = Distance
elevation = Elevation
segment_length = Segment length
type = Track Type
legend = Legend

View File

@@ -6,7 +6,7 @@ save = Sauvegarder
admin_save_success = Sauvegardé
track_main = Trajet principal
track_offtrack = Variante
track_off-track = Variante
track_hitchhiking = Hors rando
track_download = Télécharger la trace GPX
@@ -96,3 +96,9 @@ email_update_subject= Nouvelle position reçue
update_preheader = Nouvelle position !
update_title = Message
update_latest_news = Dernières nouvelles :
distance = Distance
elevation = Dénivelé
segment_length = Taille du segment
type = Type de rando
legend = Légende

View File

@@ -30,11 +30,11 @@
</div>
</div>
<div id="elems">
<div id="settings-button"><i class="fa fa-menu fa-fw"></i></div>
<div id="post-button"><i class="fa fa-fw"></i></div>
<div id="settings-button" class="spot-control"><i class="fa fa-menu fa-fw"></i></div>
<div id="post-button" class="spot-control"><i class="fa fa-fw"></i></div>
<div id="legend" class="leaflet-control-layers leaflet-control leaflet-control-layers-expanded">
<div class="track"><span class="line main"></span><span class="desc">[#]lang:track_main[#]</span></div>
<div class="track"><span class="line off-track"></span><span class="desc">[#]lang:track_offtrack[#]</span></div>
<div class="track"><span class="line off-track"></span><span class="desc">[#]lang:track_off-track[#]</span></div>
<div class="track"><span class="line hitchhiking"></span><span class="desc">[#]lang:track_hitchhiking[#]</span></div>
</div>
</div>
@@ -391,21 +391,52 @@ function initSpotMessages(aoMessages, aoTracks, bNoFeed) {
oScale = L.control.scale({imperial: false, 'position':'bottomright'}).addTo(oMap);
//Controls: Elevation
if(!isIE() && !isMobile()) {
var oElev = L.control.elevation({
collapsed: true,
position: "bottomright",
if(!isMobile()) {
var aoElevTracks = {type: 'FeatureCollection', features:[], properties: {summary: 'Elevation'}};
var aoLegend = {Elevation: {}};
for(var i in aoTracks.features) {
if(aoTracks.features[i].properties.type != 'hitchhiking') {
//Feature
var oTrack = jQuery.extend(true, {}, aoTracks.features[i]);
var sType = aoTracks.features[i].properties.type;
oTrack.properties.attributeType = sType;
aoElevTracks.features.push(oTrack);
//Legend
aoLegend.Elevation[sType] = {text: oSpot.lang('track_'+sType), color: self.tmp(['track-type-styles', sType, 'color'])};
}
}
var oElev = L.control.heightgraph({
position: 'bottomright',
expand: false,
width: getElevWidth(),
height: 129,
hoverNumber: {
decimalsX: 0, //distance (km)
decimalsY: 0 //elevation (m)
height: 200,
margins: {
top: 10,
right: 30,
bottom: 55,
left: 50
},
theme: 'spot-theme',
onExpand: function(){$('.leaflet-control-scale').hide();},
onCollapse: function(){$('.leaflet-control-scale').show();}
}).addTo(oMap);
self.tmp('elev', oElev);
translation: {
distance: oSpot.lang('distance'),
elevation: oSpot.lang('elevation'),
segment_length: oSpot.lang('segment_length'),
type: oSpot.lang('type'),
legend: oSpot.lang('legend')
},
xTicks: 3,
yTicks: 2,
mappings: aoLegend,
highlightStyle: {
weight: self.tmp(['track-type-styles', 'main', 'weight']),
opacity: 1,
color: '#326526'
},
expandCallback: function(bExpanded){$('.leaflet-control-scale').toggle(!bExpanded);}
});
oElev.addTo(oMap);
oElev.addData([aoElevTracks]);
//self.tmp('elev', oElev);
}
//Controls: Tiles (layers): Add & Move to Settings Panel
@@ -503,8 +534,6 @@ function initSpotMessages(aoMessages, aoTracks, bNoFeed) {
asTrailMarkers.start.remove();
asTrailMarkers.end.remove();
});
if(!isIE() && !isMobile()) (oElev.addData.bind(oElev))(feature, oLayer);
}
}
}).addTo(oMap));

4
script/d3.min.js vendored

File diff suppressed because one or more lines are too long

826
script/leaflet.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -355,13 +355,3 @@ $.prototype.onSwipe = function(fCallBack){
fCallBack({x:iDeltaX, y:iDeltaY});
});
};
function isIE() {
var sUA = window.navigator.userAgent;
//IE 10: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)
//IE 11: Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
//Edge 12 (Spartan): Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0
//Edge 13: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586
//Edge 18: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363
return (sUA.indexOf('MSIE ') > 0 || sUA.indexOf('Trident/') > 0 || sUA.indexOf('Edge/') > 0);
}

View File

@@ -37,8 +37,8 @@
}
@mixin drop-shadow($opacity) {
filter: drop-shadow( -1px 1px 1px rgba(0, 0, 0, $opacity));
-webkit-filter: drop-shadow( -1px 1px 1px rgba(0, 0, 0, $opacity));
filter: drop-shadow(1px 0px 0px rgba(0, 0, 0, $opacity));
-webkit-filter: drop-shadow(1px 0px 0px rgba(0, 0, 0, $opacity));
}
/* Common objects */

View File

@@ -28,9 +28,13 @@ $fa-css-prefix: fa;
text-align: center;
line-height: 44px;
text-decoration: none;
color: #999;
color: #CCC;
background: none;
@extend .fa;
&:hover {
color: white;
}
}
/* Map */

View File

@@ -10,7 +10,7 @@ $stroke-width-height-focus: 2;
$stroke-width-axis : 2;
@import 'leaflet/leaflet';
@import 'leaflet/leaflet_elevation';
@import 'leaflet/leaflet_heightgraph';
/* Leaflet fixes */
.leaflet-container {
@@ -23,27 +23,72 @@ $stroke-width-axis : 2;
margin: 1rem;
}
/* Leaflet Elevation fixes */
.#{$theme} {
&.height-focus,
&.height-focus.line,
&.height-focus-label,
&.leaflet-control.elevation .area {
@include drop-shadow(0.6);
}
.leaflet-control.spot-control, .leaflet-control .heightgraph-toggle {
cursor: pointer;
text-shadow: 0px 1px 1px rgba(0,0,0,0.8);
width: 44px;
text-align: center;
&.leaflet-control.elevation-collapsed {
.background {
display: none;
}
.elevation-toggle {
@extend .control-icon;
@extend .fa-elev-chart;
}
}
.details text {
text-anchor: middle;
.fa, .heightgraph-toggle-icon {
@extend .control-icon;
}
}
/* Leaflet Heightgraph fixes */
.legend-text, .tick, .tick text, .focusbox, .height-focus.circle, .height-focus.label, .lineSelection, .horizontalLineText {
fill: #333 !important;
}
.axis path, .focusbox rect, .focusLine line, .height-focus.label rect, .height-focus.line, .horizontalLine {
stroke: #333 !important;
}
.focusbox rect, .height-focus.label rect {
stroke-width: 0;
}
.focusLine line, .focusbox rect, .height-focus.label rect {
-webkit-filter: drop-shadow(1px 0px 2px rgba(0, 0, 0, 0.6));
filter: drop-shadow(1px 0px 2px rgba(0, 0, 0, 0.6));
}
.height-focus.label rect, .focusbox rect {
fill: rgba(255,255,255,.6);
}
.heightgraph.leaflet-control {
svg.heightgraph-container {
background: none;
border-radius: 0;
.area {
@include drop-shadow(0.6);
}
}
.horizontalLine {
stroke-width: 2px;
}
.heightgraph-toggle {
height: 44px;
background: none;
.heightgraph-toggle-icon {
@extend .fa-elev-chart;
position: static;
background: none;
}
}
.heightgraph-close-icon {
@extend .control-icon;
@extend .fa-unsubscribe;
color: #333;
background: none;
font-size: 20px;
line-height: 28px;
display: none;
}
}

View File

@@ -192,21 +192,6 @@ $legend-color: $post-color;
}
}
#post-button, #settings-button {
cursor: pointer;
text-shadow: 0px 1px 1px rgba(0,0,0,0.8);
width: 44px;
text-align: center;
&:hover .fa {
color: white;
}
.fa {
color: #CCC;
@extend .control-icon;
}
}
#post-button .fa {
@extend .fa-post;
}

View File

@@ -1,61 +0,0 @@
.#{$theme}.leaflet-control.elevation {
.background {
//background-color: $background;
//@include rounded(3px);
margin: 6px 0 -12px;
}
.axis path,
.axis line {
fill: none;
stroke: $axis-color;
stroke-width: $stroke-width-axis;
}
//.mouse-focus-label-y,
.mouse-focus-label-x {
text-anchor: middle;
}
.mouse-drag{
fill: $drag-color;
}
.elevation-toggle {
cursor: pointer;
width: 44px;
height: 44px;
color: #CCC;
text-shadow: 0px 1px 1px rgba(0,0,0,0.8);
}
.area {
fill: $base-color;
@include drop-shadow(0.6);
}
.mouse-focus-line {
pointer-events: none;
stroke-width: $stroke-width-mouse-focus;
stroke: $stroke-color;
}
}
.#{$theme}.height-focus{
stroke: $base-color;
fill: $base-color;
}
.#{$theme}.height-focus.line{
pointer-events: none;
stroke-width: $stroke-width-height-focus;
}
.#{$theme}.height-focus-label{
text-anchor: middle;
fill: $base-color;
}
.#{$theme}.height-focus.circle-lower {
}

View File

@@ -0,0 +1,148 @@
.heightgraph-container {
background-color: rgba(250,250,250,.8);
border-radius: 10px;
display: none;
cursor: default;
user-select: none;
}
.heightgraph-toggle {
cursor: pointer;
box-shadow: 0 1px 7px rgba(0, 0, 0, .4);
border-radius: 5px;
width: 28px;
height: 28px;
background: #f8f8f9;
display: block;
}
.heightgraph-toggle-icon {
background: url(img/area-chart.svg) no-repeat center center;
background-size: 14px 14px;
width: 26px;
height: 26px;
position: absolute;
}
.heightgraph-close-icon {
background: url(img/remove.svg) no-repeat center center;
background-size: 14px 14px;
width: 26px;
height: 26px;
position: absolute;
right: 0;
display: none;
cursor: pointer;
}
.border-top {
fill: none;
}
.legend-hover {
cursor: pointer;
}
.legend-text {
fill: #000;
font-size: 10px;
cursor: pointer;
}
.tick, .tick text {
fill: #000;
pointer-events: none;
}
.axis .tick line {
visibility: hidden;
pointer-events: none;
}
.axis path {
stroke: black;
fill: none;
stroke-width: 2px;
shape-rendering: crispEdges;
pointer-events: none;
}
.focusbox {
display: none;
font-size: 10px;
fill: #000;
pointer-events: none;
}
.focusbox rect {
fill: rgba(255, 255, 255, 0.8);
stroke-width: 1px;
stroke: #888;
pointer-events: none;
}
.focusbox text {
font-size: 12px;
}
.focusLine line {
stroke-width: 1px;
stroke: rgb(20, 20, 20);
display: none;
cursor: default;
shape-rendering: crispEdges;
}
.height-focus.label rect {
fill: rgba(255, 255, 255, 0.5);
stroke-width: 1px;
stroke: #888;
pointer-events: none;
shape-rendering: crispEdges;
}
.height-focus.line {
stroke: rgb(20, 20, 20);
stroke-width: 1px;
shape-rendering: crispEdges;
}
.height-focus.circle {
stroke: #FFF;
stroke-width: 1px;
}
.mouse-height-box-text{
font-size: 12px;
}
.grid .tick {
pointer-events: none;
}
.grid .tick line {
stroke: #EEE;
stroke-width: 1px;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
pointer-events: none;
}
.tspan {
font-weight: bold;
}
.select-symbol {
cursor: pointer;
}
.select-info {
cursor: default;
}
.lineSelection {
cursor: move;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long