kopia lustrzana https://github.com/dl9rdz/rdzwx-go
a bit more
rodzic
9bc26db65b
commit
53f120c232
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 2.4 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 1.4 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 618 B |
|
@ -69,6 +69,71 @@ html, body {
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'Courier New', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.infodiv {
|
||||||
|
background-color: #ecfedf;
|
||||||
|
padding: 5px 19px;
|
||||||
|
margin: 0px 0px !important;
|
||||||
|
}
|
||||||
|
.infodiv td {
|
||||||
|
padding: 0px;
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
.infodiv table {
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infotdr {
|
||||||
|
padding: 0px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infocontent p {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.infocontent {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.infocontentl3 {
|
||||||
|
color: #008cba;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (orientation: portrait) {
|
||||||
|
.infotable {
|
||||||
|
width: 75vw;
|
||||||
|
}
|
||||||
|
.infocontentl1 {
|
||||||
|
font-size: 7vw;
|
||||||
|
}
|
||||||
|
.infocontentl2 {
|
||||||
|
font-size: 5vw;
|
||||||
|
}
|
||||||
|
.infocontentl3 {
|
||||||
|
font-size: 6vw;
|
||||||
|
}
|
||||||
|
.infocontentl4 {
|
||||||
|
font-size: 5vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (orientation: landscape) {
|
||||||
|
.infotable {
|
||||||
|
width: 60vw;
|
||||||
|
}
|
||||||
|
.infocontentl1 {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
.infocontentl2 {
|
||||||
|
font-size: 3vw;
|
||||||
|
}
|
||||||
|
.infocontentl3 {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
.infocontentl4 {
|
||||||
|
font-size: 3vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.leaflet-center {
|
.leaflet-center {
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
117
www/js/index.js
117
www/js/index.js
|
@ -26,8 +26,9 @@ var markers = {};
|
||||||
var ready = 0;
|
var ready = 0;
|
||||||
var map = null;
|
var map = null;
|
||||||
var lastObj = { obj: null, pred: null, land: null };
|
var lastObj = { obj: null, pred: null, land: null };
|
||||||
//var mypos = {lat: 48.56, lon: 13.43};
|
var mypos = {lat: 48.56, lon: 13.43};
|
||||||
var mypos = {lat: 48.1, lon: 13.1};
|
//var mypos = {lat: 48.1, lon: 13.1};
|
||||||
|
var myposMarker = null;
|
||||||
|
|
||||||
var ballonIcon, landIcon;
|
var ballonIcon, landIcon;
|
||||||
var infobox = null;
|
var infobox = null;
|
||||||
|
@ -59,6 +60,7 @@ function onDeviceReady() {
|
||||||
tftrans = L.tileLayer('https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
tftrans = L.tileLayer('https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
||||||
tfout = L.tileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
tfout = L.tileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
||||||
tfcycle = L.tileLayer('https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
tfcycle = L.tileLayer('https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
||||||
|
tfatlas = L.tileLayer('https://{s}.tile.thunderforest.com/mobile-atlas/{z}/{x}/{y}.png?apikey=' + tfapikey, {attribution: '© <a href="http://www.thunderforest.com/">Thunderforest</a>, © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'}),
|
||||||
opentopo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {attribution: 'Kartendaten: © <a href="https://openstreetmap.org/copyright">OpenStreetMap</a>-Mitwirkende, <a href="http://viewfinderpanoramas.org">SRTM</a> | Kartendarstellung: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'}),
|
opentopo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {attribution: 'Kartendaten: © <a href="https://openstreetmap.org/copyright">OpenStreetMap</a>-Mitwirkende, <a href="http://viewfinderpanoramas.org">SRTM</a> | Kartendarstellung: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'}),
|
||||||
sat = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'}),
|
sat = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'}),
|
||||||
Stamen_TonerHybrid = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner-hybrid/{z}/{x}/{y}{r}.{ext}', {
|
Stamen_TonerHybrid = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner-hybrid/{z}/{x}/{y}{r}.{ext}', {
|
||||||
|
@ -81,6 +83,7 @@ function onDeviceReady() {
|
||||||
"Landscape": tfland,
|
"Landscape": tfland,
|
||||||
"Transport": tftrans,
|
"Transport": tftrans,
|
||||||
"Outdoors": tfout,
|
"Outdoors": tfout,
|
||||||
|
"Atlas": tfatlas,
|
||||||
"OpenCycleMap": tfcycle,
|
"OpenCycleMap": tfcycle,
|
||||||
"OpenTopoMap" : opentopo,
|
"OpenTopoMap" : opentopo,
|
||||||
"Sat": sat,
|
"Sat": sat,
|
||||||
|
@ -107,8 +110,8 @@ function onDeviceReady() {
|
||||||
var infoContainer = L.DomUtil.create('div', 'leaflet-control-layers leaflet-control');
|
var infoContainer = L.DomUtil.create('div', 'leaflet-control-layers leaflet-control');
|
||||||
var infoBody = L.DomUtil.create('div', 'leaflet-popup-content-wrapper');
|
var infoBody = L.DomUtil.create('div', 'leaflet-popup-content-wrapper');
|
||||||
infoContainer.appendChild(infoBody);
|
infoContainer.appendChild(infoBody);
|
||||||
infoBody.setAttribute('style', 'max-width: 100vw');
|
//infoBody.setAttribute('style', 'max-width: 100vw');
|
||||||
var infoContent = L.DomUtil.create('div', 'leaflet-popup-content');
|
var infoContent = L.DomUtil.create('div', 'leaflet-popup-content infodiv');
|
||||||
infoBody.appendChild(infoContent);
|
infoBody.appendChild(infoContent);
|
||||||
var infoCloseButton = L.DomUtil.create('a', 'leaflet-popup-close-button');
|
var infoCloseButton = L.DomUtil.create('a', 'leaflet-popup-close-button');
|
||||||
infoContainer.appendChild(infoCloseButton);
|
infoContainer.appendChild(infoCloseButton);
|
||||||
|
@ -118,22 +121,46 @@ function onDeviceReady() {
|
||||||
this._infoBody = infoBody;
|
this._infoBody = infoBody;
|
||||||
this._infoContentContainer = infoContent;
|
this._infoContentContainer = infoContent;
|
||||||
this._infoCloseButton = infoCloseButton;
|
this._infoCloseButton = infoCloseButton;
|
||||||
|
// Info content layout created here...
|
||||||
infoContent.innerHTML = 'This is the inner content';
|
this._infoContentL1 = L.DomUtil.create('div', 'infocontent infocontentl1');
|
||||||
|
this._infoContentL2 = L.DomUtil.create('div', 'infocontent infocontentl2');
|
||||||
|
this._infoContentL3 = L.DomUtil.create('div', 'infocontent infocontentl3');
|
||||||
|
this._infoContentL4 = L.DomUtil.create('div', 'infocontent infocontentl4');
|
||||||
|
infoContent.appendChild(this._infoContentL1);
|
||||||
|
infoContent.appendChild(this._infoContentL2);
|
||||||
|
infoContent.appendChild(this._infoContentL3);
|
||||||
|
infoContent.appendChild(this._infoContentL4);
|
||||||
|
//infoContent.innerHTML = 'This is the inner content';
|
||||||
this._hideContent();
|
this._hideContent();
|
||||||
|
|
||||||
L.DomEvent.disableClickPropagation(infoContainer);
|
L.DomEvent.disableClickPropagation(infoContainer);
|
||||||
L.DomEvent.on(infoCloseButton, 'click', L.DomEvent.stop);
|
L.DomEvent.on(infoCloseButton, 'click', L.DomEvent.stop);
|
||||||
L.DomEvent.on(infoCloseButton, 'click', this._hideContent, this);
|
L.DomEvent.on(infoCloseButton, 'click', this._hideContent, this);
|
||||||
|
/*
|
||||||
|
this.setContent("<table style=\"width:100%;\"><tr><td>RS41</td><td style=\"float:right;\">R1234567</td></tr></table>",
|
||||||
|
"<table style=\"width:100%;\"><tr><td>403.012 MHz</td><td style=\"float:right; font-size:0.9em;\">+ 1.2 kHz</td></tr></table>",
|
||||||
|
"12345m 102.4km/h -12.2m/s", "RSSI -90.5 ||||...EEE||||");
|
||||||
|
*/
|
||||||
return infoContainer;
|
return infoContainer;
|
||||||
},
|
},
|
||||||
toggle: function() {
|
toggle: function() {
|
||||||
if(this._contentShown == false) { this._showContent(); } else { this._hideContent(); }
|
if(this._contentShown == false) { this._showContent(); } else { this._hideContent(); }
|
||||||
},
|
},
|
||||||
setContent: function(content) {
|
setContent: function(obj) {
|
||||||
this._infoContent = content;
|
if(!this._infoContentContainer) return;
|
||||||
if(this._infoContentContainer) { this._infoContentContainer.innerHTML = content; }
|
if(obj.type == null) obj.type = "RS41"; // TODO fix in plugin
|
||||||
|
distance = L.latLng(obj).distanceTo(L.latLng(mypos))
|
||||||
|
if(distance>9999) { distance = distance.toFixed(0); }
|
||||||
|
else { distance = distance.toFixed(1); }
|
||||||
|
distance = "d=" + distance + "m";
|
||||||
|
l1 = "<table class=\"infotable\"><tr><td class=\"infotd\">" + obj.type + "</td><td class=\"infotdr\">" + obj.ser + "</td></tr></table>";
|
||||||
|
l2 = "<table class=\"infotable\"><tr><td class=\"infotd\">" + obj.freq.toFixed(3) + " MHz </td><td class=\"infotdr\" style=\”font-size:0.9em;\">" + (0.001*obj.afc).toFixed(2) + " kHz</td></tr></table>";
|
||||||
|
l3 = "<table class=\"infotable\"><tr><td class=\"infotd\">" + obj.alt.toFixed(0) + "m</td><td class=\"infotd\">" + obj.vs + "m/s </td><td class=\"infotdr\">" + (obj.hs*3.6).toFixed(1) + "km/h </td></tr></table>";
|
||||||
|
l4 = "<table class=\"infotable\"><tr><td class=\"infotd\">RSSI: " + -0.5*obj.rssi + " </td><td class=\"infotdr\">" + distance + " </td></tr></table>";
|
||||||
|
this._infoContentL1.innerHTML = l1;
|
||||||
|
this._infoContentL2.innerHTML = l2;
|
||||||
|
this._infoContentL3.innerHTML = l3;
|
||||||
|
this._infoContentL4.innerHTML = l4;
|
||||||
},
|
},
|
||||||
_hideContent: function(ev) {
|
_hideContent: function(ev) {
|
||||||
this._infoBody.style.display = 'none';
|
this._infoBody.style.display = 'none';
|
||||||
|
@ -150,7 +177,7 @@ function onDeviceReady() {
|
||||||
infobox.addTo(map);
|
infobox.addTo(map);
|
||||||
|
|
||||||
// button to show/hide info box on bottom
|
// button to show/hide info box on bottom
|
||||||
L.easyButton('<span class="infobutton">I</span>', function(btn, map) {
|
L.easyButton('<span class="infobutton">i</span>', function(btn, map) {
|
||||||
infobox.toggle();
|
infobox.toggle();
|
||||||
}).addTo(map);
|
}).addTo(map);
|
||||||
|
|
||||||
|
@ -169,8 +196,8 @@ function onDeviceReady() {
|
||||||
ttgoStatus = L.easyButton( {
|
ttgoStatus = L.easyButton( {
|
||||||
ttgourl: "http://192.168.42.1",
|
ttgourl: "http://192.168.42.1",
|
||||||
states: [{ stateName: 'offline',
|
states: [{ stateName: 'offline',
|
||||||
icon: '<span class="ttgostatus">' + crossMark + '</span>',
|
icon: '<span class="ttgostatus">' + crossMark + '</span>'
|
||||||
onClick: function(btn, map) { btn.state('online'); }
|
//, onClick: function(btn, map) { btn.state('online'); }
|
||||||
},
|
},
|
||||||
{ stateName: 'online',
|
{ stateName: 'online',
|
||||||
icon: '<span class="ttgostatus">' + checkMark + '</span>',
|
icon: '<span class="ttgostatus">' + checkMark + '</span>',
|
||||||
|
@ -200,7 +227,8 @@ function onDeviceReady() {
|
||||||
RdzWx.start("testarg", callBack);
|
RdzWx.start("testarg", callBack);
|
||||||
|
|
||||||
// just for testing
|
// just for testing
|
||||||
update( {id: "A1234567", lat: 48, lon: 13, alt: 10000, vs: 10, hs: 30} );
|
update( {id: "A1234567", lat: 48, lon: 13, alt: 10000, vs: 10, hs: 30, rssi: -90, rxStat: "||||||||||||....", type: "RS41", freq: "400.000", afc: "+1.2", ser: "A1234567"} );
|
||||||
|
updateMypos(mypos);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatParams(params) {
|
function formatParams(params) {
|
||||||
|
@ -209,6 +237,34 @@ function formatParams(params) {
|
||||||
}).join('&');
|
}).join('&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// borrowed from wetterson.de/karte .....
|
||||||
|
function calc_drag(drag,alt){
|
||||||
|
if (alt < 1000 ){
|
||||||
|
drag = drag * 1;
|
||||||
|
} else if (alt < 2000){
|
||||||
|
dragfak = (( alt - 1000 ) * ( 0.98 - 1) / ( 2000 - 1000)) + 1;
|
||||||
|
drag = drag * dragfak;
|
||||||
|
} else if (alt < 3000){
|
||||||
|
dragfak = (( alt - 2000 ) * ( 0.95 - 0.98) / ( 3000 - 2000)) + 0.98;
|
||||||
|
drag = drag * dragfak;
|
||||||
|
} else if (alt < 6000){
|
||||||
|
dragfak = (( alt - 3000 ) * ( 0.75 - 0.95) / ( 6000 - 3000)) + 0.95;
|
||||||
|
drag = drag * dragfak;
|
||||||
|
} else if (alt < 8000){
|
||||||
|
dragfak = (( alt - 6000 ) * ( 0.62- 0.75) / ( 8000 - 6000)) + 0.75;
|
||||||
|
drag = drag * dragfak;
|
||||||
|
} else if (alt < 10000){
|
||||||
|
dragfak = (( alt - 8000 )* ( 0.55 - 0.62) / ( 10000 - 8000)) + 0.62;
|
||||||
|
drag = drag * dragfak;
|
||||||
|
} else if (alt < 20000){
|
||||||
|
dragfak = (( alt - 10000 )* ( 0.3 - 0.55) / ( 20000 - 10000)) + 0.55;
|
||||||
|
drag = drag * dragfak;
|
||||||
|
} else {
|
||||||
|
drag = 5;
|
||||||
|
}
|
||||||
|
return drag;
|
||||||
|
}
|
||||||
|
|
||||||
function getPrediction() {
|
function getPrediction() {
|
||||||
TAWHIRI = 'http://predict.cusf.co.uk/api/v1';
|
TAWHIRI = 'http://predict.cusf.co.uk/api/v1';
|
||||||
if(lastObj.obj == null) {
|
if(lastObj.obj == null) {
|
||||||
|
@ -221,20 +277,27 @@ function getPrediction() {
|
||||||
"launch_altitude": lastObj.obj.alt,
|
"launch_altitude": lastObj.obj.alt,
|
||||||
"launch_datetime": new Date().toISOString().split('.')[0] + 'Z',
|
"launch_datetime": new Date().toISOString().split('.')[0] + 'Z',
|
||||||
"ascent_rate": 5,
|
"ascent_rate": 5,
|
||||||
"descent_rate": 3,
|
"descent_rate": 5,
|
||||||
"burst_altitude": lastObj.obj.alt+2,
|
"burst_altitude": lastObj.obj.alt+2,
|
||||||
"profile": "standard_profile",
|
"profile": "standard_profile",
|
||||||
}
|
}
|
||||||
|
if(lastObj.obj.vs > 0) {
|
||||||
|
// still climbing up
|
||||||
|
tParams["burst_altitude"] = 35000;
|
||||||
|
} else {
|
||||||
|
tParams["descent_rate"] = calc_drag( -lastObj.obj.vs, lastObj.obj.alt );
|
||||||
|
}
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
const url = TAWHIRI + formatParams(tParams);
|
const url = TAWHIRI + formatParams(tParams);
|
||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if(xhr.readyState === 4) {
|
if(xhr.readyState === 4) {
|
||||||
console.log(xhr.response);
|
console.log(xhr.response);
|
||||||
var pred = JSON.parse(xhr.response);
|
var pred = JSON.parse(xhr.response);
|
||||||
var traj = pred.prediction[1]; // 0 is ascent, 1 is descent...
|
var traj0 = pred.prediction[0].trajectory; // 0 is ascent, 1 is descent...
|
||||||
traj = traj.trajectory;
|
var traj1 = pred.prediction[1].trajectory; // 0 is ascent, 1 is descent...
|
||||||
var latlons = [];
|
var latlons = [];
|
||||||
traj.forEach( p => latlons.push( [p.latitude, p.longitude] ) );
|
traj0.forEach( p => latlons.push( [p.latitude, p.longitude] ) );
|
||||||
|
traj1.forEach( p => latlons.push( [p.latitude, p.longitude] ) );
|
||||||
//alert("path: "+JSON.stringify(traj));
|
//alert("path: "+JSON.stringify(traj));
|
||||||
poly = L.polyline(latlons, { opacity: 0.5, color: '#EE0000', dashArray: '8, 6'} );
|
poly = L.polyline(latlons, { opacity: 0.5, color: '#EE0000', dashArray: '8, 6'} );
|
||||||
poly.addTo(map);
|
poly.addTo(map);
|
||||||
|
@ -263,6 +326,19 @@ function callBack(arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateMypos(obj) {
|
||||||
|
mypos = obj;
|
||||||
|
var pos = [obj.lat, obj.lon]
|
||||||
|
if(myposMarker == null) {
|
||||||
|
// create marker
|
||||||
|
myposMarker = new L.marker(pos);
|
||||||
|
myposMarker.addTo(map);
|
||||||
|
} else {
|
||||||
|
myposMarker.setLatLng(pos);
|
||||||
|
myposMarker.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update(obj) {
|
function update(obj) {
|
||||||
console.log("update called");
|
console.log("update called");
|
||||||
if(!ready || !map) {
|
if(!ready || !map) {
|
||||||
|
@ -274,7 +350,9 @@ function update(obj) {
|
||||||
ttgoStatus.ttgourl = 'http://' + obj.ip;
|
ttgoStatus.ttgourl = 'http://' + obj.ip;
|
||||||
ttgoStatus.state(obj.state)
|
ttgoStatus.state(obj.state)
|
||||||
}
|
}
|
||||||
// TODO: add GPS messages
|
if(obj.msgtype == "gps") {
|
||||||
|
updateMypos(obj);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +380,7 @@ function update(obj) {
|
||||||
}
|
}
|
||||||
var tt = '<div class="tooltip-container">' + obj.id + '<div class="text-speed tooltip-container">' + obj.alt + 'm '+ obj.vs +'m/s ' + (obj.hs*3.6).toFixed(1) + 'km/h </div></div>';
|
var tt = '<div class="tooltip-container">' + obj.id + '<div class="text-speed tooltip-container">' + obj.alt + 'm '+ obj.vs +'m/s ' + (obj.hs*3.6).toFixed(1) + 'km/h </div></div>';
|
||||||
tooltip.setContent(tt);
|
tooltip.setContent(tt);
|
||||||
|
infobox.setContent(obj);
|
||||||
|
|
||||||
marker.setLatLng(pos);
|
marker.setLatLng(pos);
|
||||||
marker.update(); // necessary?
|
marker.update(); // necessary?
|
||||||
|
|
Ładowanie…
Reference in New Issue