mirror of https://github.com/espruino/BangleApps
openstmap
Added ability to upload multiple sets of map tiles Support for zooming in on map Satellite count moved to widget bar to leave more room for the mappull/2297/head
parent
f4a48e62e6
commit
459a643c87
|
@ -12,3 +12,5 @@
|
|||
Fix alignment of satellite info text
|
||||
0.12: switch to using normal OpenStreetMap tiles (opentopomap was too slow)
|
||||
0.13: Use a single image file with 'frames' of data (drastically reduces file count, possibility of >1 map on device)
|
||||
0.14: Added ability to upload multiple sets of map tiles
|
||||
Support for zooming in on map
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# OpenStreetMap
|
||||
|
||||
This app allows you to upload and use OpenSteetMap map tiles onto your
|
||||
Bangle. There's an uploader, the app, and also a library that
|
||||
allows you to use the maps in your Bangle.js applications.
|
||||
|
||||
## Uploader
|
||||
|
||||
Once you've installed OpenStreepMap on your Bangle, find it
|
||||
in the App Loader and click the Disk icon next to it.
|
||||
|
||||
A window will pop up showing what maps you have loaded.
|
||||
|
||||
To add a map:
|
||||
|
||||
* Click `Add Map`
|
||||
* Scroll and zoom to the area of interest or use the Search button in the top left
|
||||
* Now choose the size you want to upload (Small/Medium/etc)
|
||||
* On Bangle.js 1 you can choose if you want a 3 bits per pixel map (this is lower
|
||||
quality but uploads faster and takes less space). On Bangle.js 2 you only have a 3bpp
|
||||
display so can only use 3bpp.
|
||||
* Click `Get Map`, and a preview will be displayed. If you need to adjust the area you
|
||||
can change settings, move the map around, and click `Get Map` again.
|
||||
* When you're ready, click `Upload`
|
||||
|
||||
## Bangle.js App
|
||||
|
||||
The Bangle.js app allows you to view a map - it also turns the GPS on and marks
|
||||
the path that you've been travelling.
|
||||
|
||||
* Drag on the screen to move the map
|
||||
* Press the button to bring up a menu, where you can zoom, go to GPS location
|
||||
or put the map back in its default location
|
||||
|
||||
## Library
|
||||
|
||||
See the documentation in the library itself for full usage info:
|
||||
https://github.com/espruino/BangleApps/blob/master/apps/openstmap/openstmap.js
|
||||
|
||||
Or check the app itself: https://github.com/espruino/BangleApps/blob/master/apps/openstmap/app.js
|
||||
|
||||
But in the most simple form:
|
||||
|
||||
```
|
||||
var m = require("openstmap");
|
||||
// m.lat/lon are now the center of the loaded map
|
||||
m.draw(); // draw centered on the middle of the loaded map
|
||||
```
|
|
@ -1,20 +1,27 @@
|
|||
var m = require("openstmap");
|
||||
var HASWIDGETS = true;
|
||||
var y1,y2;
|
||||
var R;
|
||||
var fix = {};
|
||||
var mapVisible = false;
|
||||
var hasScrolled = false;
|
||||
|
||||
// Redraw the whole page
|
||||
function redraw() {
|
||||
g.setClipRect(0,y1,g.getWidth()-1,y2);
|
||||
g.setClipRect(R.x,R.y,R.x2,R.y2);
|
||||
m.draw();
|
||||
drawMarker();
|
||||
if (WIDGETS["gpsrec"] && WIDGETS["gpsrec"].plotTrack) {
|
||||
g.flip(); // force immediate draw on double-buffered screens - track will update later
|
||||
g.setColor(0.75,0.2,0);
|
||||
if (HASWIDGETS && WIDGETS["gpsrec"] && WIDGETS["gpsrec"].plotTrack) {
|
||||
g.flip().setColor("#f00"); // force immediate draw on double-buffered screens - track will update later
|
||||
WIDGETS["gpsrec"].plotTrack(m);
|
||||
}
|
||||
if (HASWIDGETS && WIDGETS["recorder"] && WIDGETS["recorder"].plotTrack) {
|
||||
g.flip().setColor("#f00"); // force immediate draw on double-buffered screens - track will update later
|
||||
WIDGETS["recorder"].plotTrack(m);
|
||||
}
|
||||
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
||||
}
|
||||
|
||||
// Draw the marker for where we are
|
||||
function drawMarker() {
|
||||
if (!fix.fix) return;
|
||||
var p = m.latLonToXY(fix.lat, fix.lon);
|
||||
|
@ -22,50 +29,66 @@ function drawMarker() {
|
|||
g.fillRect(p.x-2, p.y-2, p.x+2, p.y+2);
|
||||
}
|
||||
|
||||
var fix;
|
||||
Bangle.on('GPS',function(f) {
|
||||
fix=f;
|
||||
g.reset().clearRect(0,y1,g.getWidth()-1,y1+8).setFont("6x8").setFontAlign(0,0);
|
||||
var txt = fix.satellites+" satellites";
|
||||
if (!fix.fix)
|
||||
txt += " - NO FIX";
|
||||
g.drawString(txt,g.getWidth()/2,y1 + 4);
|
||||
drawMarker();
|
||||
if (HASWIDGETS) WIDGETS["sats"].draw(WIDGETS["sats"]);
|
||||
if (mapVisible) drawMarker();
|
||||
});
|
||||
Bangle.setGPSPower(1, "app");
|
||||
|
||||
if (HASWIDGETS) {
|
||||
Bangle.loadWidgets();
|
||||
WIDGETS["sats"] = { area:"tl", width:48, draw:w=>{
|
||||
var txt = (0|fix.satellites)+" Sats";
|
||||
if (!fix.fix) txt += "\nNO FIX";
|
||||
g.reset().setFont("6x8").setFontAlign(0,0)
|
||||
.drawString(txt,w.x+24,w.y+12);
|
||||
}
|
||||
};
|
||||
Bangle.drawWidgets();
|
||||
y1 = 24;
|
||||
var hasBottomRow = Object.keys(WIDGETS).some(w=>WIDGETS[w].area[0]=="b");
|
||||
y2 = g.getHeight() - (hasBottomRow ? 24 : 1);
|
||||
} else {
|
||||
y1=0;
|
||||
y2=g.getHeight()-1;
|
||||
}
|
||||
R = Bangle.appRect;
|
||||
|
||||
redraw();
|
||||
|
||||
function recenter() {
|
||||
if (!fix.fix) return;
|
||||
m.lat = fix.lat;
|
||||
m.lon = fix.lon;
|
||||
function showMap() {
|
||||
mapVisible = true;
|
||||
g.reset().clearRect(R);
|
||||
redraw();
|
||||
Bangle.setUI({mode:"custom",drag:e=>{
|
||||
if (e.b) {
|
||||
g.setClipRect(R.x,R.y,R.x2,R.y2);
|
||||
g.scroll(e.dx,e.dy);
|
||||
m.scroll(e.dx,e.dy);
|
||||
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
||||
hasScrolled = true;
|
||||
} else if (hasScrolled) {
|
||||
hasScrolled = false;
|
||||
redraw();
|
||||
}
|
||||
}, btn: btn=>{
|
||||
mapVisible = false;
|
||||
var menu = {"":{title:"Map"},
|
||||
"< Back": ()=> showMap(),
|
||||
/*LANG*/"Zoom In": () =>{
|
||||
m.scale /= 2;
|
||||
showMap();
|
||||
},
|
||||
/*LANG*/"Zoom Out": () =>{
|
||||
m.scale *= 2;
|
||||
showMap();
|
||||
},
|
||||
/*LANG*/"Center Map": () =>{
|
||||
m.lat = m.map.lat;
|
||||
m.lon = m.map.lon;
|
||||
m.scale = m.map.scale;
|
||||
showMap();
|
||||
}};
|
||||
if (fix.fix) menu[/*LANG*/"Center GPS"]=() =>{
|
||||
m.lat = fix.lat;
|
||||
m.lon = fix.lon;
|
||||
showMap();
|
||||
};
|
||||
E.showMenu(menu);
|
||||
}});
|
||||
}
|
||||
|
||||
setWatch(recenter, global.BTN2?BTN2:BTN1, {repeat:true});
|
||||
|
||||
var hasScrolled = false;
|
||||
Bangle.on('drag',e=>{
|
||||
if (e.b) {
|
||||
g.setClipRect(0,y1,g.getWidth()-1,y2);
|
||||
g.scroll(e.dx,e.dy);
|
||||
m.scroll(e.dx,e.dy);
|
||||
g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1);
|
||||
hasScrolled = true;
|
||||
} else if (hasScrolled) {
|
||||
hasScrolled = false;
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
showMap();
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
html, body, #map {
|
||||
html, body, #map, #mapsLoaded, #mapContainer {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -27,20 +28,40 @@
|
|||
width: 256px;
|
||||
height: 256px;
|
||||
}
|
||||
.tile-title {
|
||||
font-weight:bold;
|
||||
font-size: 125%;
|
||||
}
|
||||
.tile-map {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map">
|
||||
<div id="mapsLoadedContainer">
|
||||
</div>
|
||||
<div id="controls">
|
||||
<div style="display:inline-block;text-align:center;vertical-align: top;" id="3bitdiv"> <input type="checkbox" id="3bit"></input><br/><span>3 bit</span></div>
|
||||
<button id="getmap" class="btn btn-primary">Get Map</button><br/>
|
||||
<canvas id="maptiles" style="display:none"></canvas>
|
||||
<div id="uploadbuttons" style="display:none"><button id="upload" class="btn btn-primary">Upload</button>
|
||||
<button id="cancel" class="btn">Cancel</button></div>
|
||||
<div id="mapContainer">
|
||||
<div id="map">
|
||||
</div>
|
||||
<div id="controls">
|
||||
<div style="display:inline-block;text-align:center;vertical-align: top;" id="3bitdiv"> <input type="checkbox" id="3bit"></input><br/><span>3 bit</span></div>
|
||||
<div class="form-group" style="display:inline-block;">
|
||||
<select class="form-select" id="mapSize">
|
||||
<option value="4">Small</option>
|
||||
<option value="5" selected>Medium</option>
|
||||
<option value="6">Large</option>
|
||||
<option value="7">XL</option>
|
||||
</select>
|
||||
</div>
|
||||
<button id="getmap" class="btn btn-primary">Get Map</button><button class="btn" onclick="showLoadedMaps()">Map List</button><br/>
|
||||
<canvas id="maptiles" style="display:none"></canvas>
|
||||
<div id="uploadbuttons" style="display:none"><button id="upload" class="btn btn-primary">Upload</button>
|
||||
<button id="cancel" class="btn">Cancel</button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../../core/lib/customize.js"></script>
|
||||
<script src="../../core/lib/interface.js"></script>
|
||||
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
||||
<script src="../../webtools/heatshrink.js"></script>
|
||||
|
@ -60,8 +81,6 @@ TODO:
|
|||
*/
|
||||
var TILESIZE = 96; // Size of our tiles
|
||||
var OSMTILESIZE = 256; // Size of openstreetmap tiles
|
||||
var MAPSIZE = TILESIZE*5; ///< 480 - Size of map we download
|
||||
var OSMTILECOUNT = 3; // how many tiles do we download in each direction (Math.floor(MAPSIZE / OSMTILESIZE)+1)
|
||||
/* Can see possible tiles on http://leaflet-extras.github.io/leaflet-providers/preview/
|
||||
However some don't allow cross-origin use */
|
||||
//var TILELAYER = 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png'; // simple, high contrast, TOO SLOW
|
||||
|
@ -69,8 +88,8 @@ TODO:
|
|||
var TILELAYER = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||
var PREVIEWTILELAYER = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||
|
||||
// Create map and try and set the location to where the browser thinks we are
|
||||
var map = L.map('map').locate({setView: true, maxZoom: 16, enableHighAccuracy:true});
|
||||
var loadedMaps = [];
|
||||
|
||||
// Tiles used for Bangle.js itself
|
||||
var bangleTileLayer = L.tileLayer(TILELAYER, {
|
||||
maxZoom: 18,
|
||||
|
@ -83,6 +102,10 @@ TODO:
|
|||
});
|
||||
// Could optionally overlay trails: https://wiki.openstreetmap.org/wiki/Tiles
|
||||
|
||||
// Create map and try and set the location to where the browser thinks we are
|
||||
var map = L.map('map').locate({setView: true, maxZoom: 16, enableHighAccuracy:true});
|
||||
previewTileLayer.addTo(map);
|
||||
|
||||
// Search box:
|
||||
const searchProvider = new window.GeoSearch.OpenStreetMapProvider();
|
||||
const searchControl = new GeoSearch.GeoSearchControl({
|
||||
|
@ -96,6 +119,7 @@ TODO:
|
|||
});
|
||||
map.addControl(searchControl);
|
||||
|
||||
// ---------------------------------------- Run at startup
|
||||
function onInit(device) {
|
||||
if (device && device.info && device.info.g) {
|
||||
// On 3 bit devices, don't even offer the option. 3 bit is the only way
|
||||
|
@ -104,12 +128,120 @@ TODO:
|
|||
document.getElementById("3bitdiv").style = "display:none";
|
||||
}
|
||||
}
|
||||
|
||||
showLoadedMaps();
|
||||
}
|
||||
|
||||
var mapFiles = [];
|
||||
previewTileLayer.addTo(map);
|
||||
function showLoadedMaps() {
|
||||
document.getElementById("mapsLoadedContainer").style.display = "";
|
||||
document.getElementById("mapContainer").style.display = "none";
|
||||
|
||||
function tilesLoaded(ctx, width, height) {
|
||||
Util.showModal("Loading maps...");
|
||||
let mapsLoadedContainer = document.getElementById("mapsLoadedContainer");
|
||||
mapsLoadedContainer.innerHTML = "";
|
||||
loadedMaps = [];
|
||||
|
||||
Puck.write(`\x10Bluetooth.println(require("Storage").list(/openstmap\\.\\d+\\.json/))\n`,function(files) {
|
||||
console.log("MAPS:",files);
|
||||
let promise = Promise.resolve();
|
||||
files.trim().split(",").forEach(filename => {
|
||||
if (filename=="") return;
|
||||
promise = promise.then(() => new Promise(resolve => {
|
||||
Util.readStorage(filename, fileContents => {
|
||||
console.log(filename + " => " + fileContents);
|
||||
let mapNumber = filename.match(/\d+/)[0]; // figure out what map number we are
|
||||
let mapInfo;
|
||||
try {
|
||||
mapInfo = JSON.parse(fileContents);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
loadedMaps[mapNumber] = mapInfo;
|
||||
if (mapInfo!==undefined) {
|
||||
let latlon = L.latLng(mapInfo.lat, mapInfo.lon);
|
||||
mapsLoadedContainer.innerHTML += `
|
||||
<div class="tile">
|
||||
<div class="tile-icon">
|
||||
<div class="tile-map" id="tile-map-${mapNumber}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<p class="tile-title">Map ${mapNumber}</p>
|
||||
<p class="tile-subtitle">${mapInfo.w*mapInfo.h} Tiles (${((mapInfo.imgx*mapInfo.imgy)>>11).toFixed(0)}k)</p>
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
<button class="btn btn-primary" onclick="onMapDelete(${mapNumber})">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
let map = L.map(`tile-map-${mapNumber}`);
|
||||
L.tileLayer(PREVIEWTILELAYER, {
|
||||
maxZoom: 18
|
||||
}).addTo(map);
|
||||
let marker = new L.marker(latlon).addTo(map);
|
||||
map.fitBounds(latlon.toBounds(2000/*meters*/), {animation: false});
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
});
|
||||
promise = promise.then(() => new Promise(resolve => {
|
||||
if (!loadedMaps.length) {
|
||||
mapsLoadedContainer.innerHTML += `
|
||||
<div class="tile">
|
||||
<div class="tile-icon">
|
||||
<div class="tile-map">
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<p class="tile-title">No Maps Loaded</p>
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
mapsLoadedContainer.innerHTML += `
|
||||
<div class="tile">
|
||||
<div class="tile-icon">
|
||||
<div class="tile-map">
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
</div>
|
||||
<div class="tile-action">
|
||||
<button class="btn btn-primary" onclick="showMap()">Add Map</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
Util.hideModal();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function onMapDelete(mapNumber) {
|
||||
console.log("delete", mapNumber);
|
||||
Util.showModal(`Erasing map ${mapNumber}...`);
|
||||
Util.eraseStorage(`openstmap.${mapNumber}.json`, function() {
|
||||
Util.eraseStorage(`openstmap.${mapNumber}.img`, function() {
|
||||
Util.hideModal();
|
||||
showLoadedMaps();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showMap() {
|
||||
document.getElementById("mapsLoadedContainer").style.display = "none";
|
||||
document.getElementById("mapContainer").style.display = "";
|
||||
document.getElementById("maptiles").style.display="none";
|
||||
document.getElementById("uploadbuttons").style.display="none";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
var mapFiles = [];
|
||||
|
||||
// convert canvas into an actual tiled image file
|
||||
function tilesLoaded(ctx, width, height, mapImageFile) {
|
||||
var options = {
|
||||
compression:false, output:"raw",
|
||||
mode:"web"
|
||||
|
@ -166,12 +298,17 @@ TODO:
|
|||
}
|
||||
}
|
||||
return [{
|
||||
name:"openstmap.0.img",
|
||||
name:mapImageFile,
|
||||
content:tiledImage
|
||||
}];
|
||||
}
|
||||
|
||||
document.getElementById("getmap").addEventListener("click", function() {
|
||||
|
||||
var MAPTILES = parseInt(document.getElementById("mapSize").value);
|
||||
var MAPSIZE = TILESIZE*MAPTILES; /// Size of map we download to Bangle in pixels
|
||||
var OSMTILECOUNT = (Math.ceil((MAPSIZE+TILESIZE) / OSMTILESIZE)+1); // how many tiles do we download from OSM in each direction
|
||||
|
||||
var zoom = map.getZoom();
|
||||
var centerlatlon = map.getBounds().getCenter();
|
||||
var center = map.project(centerlatlon, zoom).divideBy(OSMTILESIZE);
|
||||
|
@ -242,8 +379,11 @@ TODO:
|
|||
|
||||
Promise.all(tileGetters).then(() => {
|
||||
document.getElementById("uploadbuttons").style.display="";
|
||||
mapFiles = tilesLoaded(ctx, canvas.width, canvas.height);
|
||||
mapFiles.unshift({name:"openstmap.0.json",content:JSON.stringify({
|
||||
var mapNumber = 0;
|
||||
while (loadedMaps[mapNumber]) mapNumber++;
|
||||
let mapImageFile = `openstmap.${mapNumber}.img`;
|
||||
mapFiles = tilesLoaded(ctx, canvas.width, canvas.height, mapImageFile);
|
||||
mapFiles.unshift({name:`openstmap.${mapNumber}.json`,content:JSON.stringify({
|
||||
imgx : canvas.width,
|
||||
imgy : canvas.height,
|
||||
tilesize : TILESIZE,
|
||||
|
@ -252,21 +392,31 @@ TODO:
|
|||
lon : centerlatlon.lng,
|
||||
w : Math.round(canvas.width / TILESIZE), // width in tiles
|
||||
h : Math.round(canvas.height / TILESIZE), // height in tiles
|
||||
fn : "openstmap.0.img"
|
||||
fn : mapImageFile
|
||||
})});
|
||||
console.log(mapFiles);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("upload").addEventListener("click", function() {
|
||||
sendCustomizedApp({
|
||||
storage:mapFiles
|
||||
Util.showModal("Uploading...");
|
||||
let promise = Promise.resolve();
|
||||
mapFiles.forEach(file => {
|
||||
promise = promise.then(function() {
|
||||
return new Promise(resolve => {
|
||||
Util.writeStorage(file.name, file.content, resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
promise.then(function() {
|
||||
Util.hideModal();
|
||||
console.log("Upload Complete");
|
||||
showLoadedMaps();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("cancel").addEventListener("click", function() {
|
||||
document.getElementById("maptiles").style.display="none";
|
||||
document.getElementById("uploadbuttons").style.display="none";
|
||||
showMap();
|
||||
});
|
||||
|
||||
</script>
|
|
@ -2,17 +2,20 @@
|
|||
"id": "openstmap",
|
||||
"name": "OpenStreetMap",
|
||||
"shortName": "OpenStMap",
|
||||
"version": "0.13",
|
||||
"version": "0.14",
|
||||
"description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps",
|
||||
"readme": "README.md",
|
||||
"icon": "app.png",
|
||||
"tags": "outdoors,gps,osm",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"custom": "custom.html",
|
||||
"customConnect": true,
|
||||
"interface": "interface.html",
|
||||
"storage": [
|
||||
{"name":"openstmap","url":"openstmap.js"},
|
||||
{"name":"openstmap.app.js","url":"app.js"},
|
||||
{"name":"openstmap.img","url":"app-icon.js","evaluate":true}
|
||||
], "data": [
|
||||
{"wildcard":"openstmap.*.json"},
|
||||
{"wildcard":"openstmap.*.img"}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -20,32 +20,59 @@ function center() {
|
|||
m.draw();
|
||||
}
|
||||
|
||||
// you can even change the scale - eg 'm/scale *= 2'
|
||||
|
||||
*/
|
||||
|
||||
var map = require("Storage").readJSON("openstmap.0.json");
|
||||
map.center = Bangle.project({lat:map.lat,lon:map.lon});
|
||||
exports.map = map;
|
||||
exports.lat = map.lat; // actual position of middle of screen
|
||||
exports.lon = map.lon; // actual position of middle of screen
|
||||
var m = exports;
|
||||
m.maps = require("Storage").list(/openstmap\.\d+\.json/).map(f=>{
|
||||
let map = require("Storage").readJSON(f);
|
||||
map.center = Bangle.project({lat:map.lat,lon:map.lon});
|
||||
return map;
|
||||
});
|
||||
// we base our start position on the middle of the first map
|
||||
m.map = m.maps[0];
|
||||
m.scale = m.map.scale; // current scale (based on first map)
|
||||
m.lat = m.map.lat; // position of middle of screen
|
||||
m.lon = m.map.lon; // position of middle of screen
|
||||
|
||||
exports.draw = function() {
|
||||
var img = require("Storage").read(map.fn);
|
||||
var cx = g.getWidth()/2;
|
||||
var cy = g.getHeight()/2;
|
||||
var p = Bangle.project({lat:m.lat,lon:m.lon});
|
||||
var ix = (p.x-map.center.x)/map.scale + (map.imgx/2) - cx;
|
||||
var iy = (map.center.y-p.y)/map.scale + (map.imgy/2) - cy;
|
||||
//console.log(ix,iy);
|
||||
var tx = 0|(ix/map.tilesize);
|
||||
var ty = 0|(iy/map.tilesize);
|
||||
var ox = (tx*map.tilesize)-ix;
|
||||
var oy = (ty*map.tilesize)-iy;
|
||||
for (var x=ox,ttx=tx;x<g.getWidth();x+=map.tilesize,ttx++)
|
||||
for (var y=oy,tty=ty;y<g.getHeight();y+=map.tilesize,tty++) {
|
||||
if (ttx>=0 && ttx<map.w && tty>=0 && tty<map.h) g.drawImage(img,x,y,{frame:ttx+(tty*map.w)});
|
||||
else g.clearRect(x,y,x+map.tilesize-1,y+map.tilesize-1).drawLine(x,y,x+map.tilesize-1,y+map.tilesize-1).drawLine(x,y+map.tilesize-1,x+map.tilesize-1,y);
|
||||
m.maps.forEach((map,idx) => {
|
||||
var d = map.scale/m.scale;
|
||||
var ix = (p.x-map.center.x)/m.scale + (map.imgx*d/2) - cx;
|
||||
var iy = (map.center.y-p.y)/m.scale + (map.imgy*d/2) - cy;
|
||||
var o = {};
|
||||
var s = map.tilesize;
|
||||
if (d!=1) { // if the two are different, add scaling
|
||||
s *= d;
|
||||
o.scale = d;
|
||||
}
|
||||
//console.log(ix,iy);
|
||||
var tx = 0|(ix/s);
|
||||
var ty = 0|(iy/s);
|
||||
var ox = (tx*s)-ix;
|
||||
var oy = (ty*s)-iy;
|
||||
var img = require("Storage").read(map.fn);
|
||||
// fix out of range so we don't have to iterate over them
|
||||
if (tx<0) {
|
||||
ox+=s*-tx;
|
||||
tx=0;
|
||||
}
|
||||
if (ty<0) {
|
||||
oy+=s*-ty;
|
||||
ty=0;
|
||||
}
|
||||
var mx = g.getWidth();
|
||||
var my = g.getHeight();
|
||||
for (var x=ox,ttx=tx; x<mx && ttx<map.w; x+=s,ttx++)
|
||||
for (var y=oy,tty=ty;y<my && tty<map.h;y+=s,tty++) {
|
||||
o.frame = ttx+(tty*map.w);
|
||||
g.drawImage(img,x,y,o);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/// Convert lat/lon to pixels on the screen
|
||||
|
@ -55,15 +82,15 @@ exports.latLonToXY = function(lat, lon) {
|
|||
var cx = g.getWidth()/2;
|
||||
var cy = g.getHeight()/2;
|
||||
return {
|
||||
x : (q.x-p.x)/map.scale + cx,
|
||||
y : cy - (q.y-p.y)/map.scale
|
||||
x : (q.x-p.x)/m.scale + cx,
|
||||
y : cy - (q.y-p.y)/m.scale
|
||||
};
|
||||
};
|
||||
|
||||
/// Given an amount to scroll in pixels on the screen, adjust the lat/lon of the map to match
|
||||
exports.scroll = function(x,y) {
|
||||
var a = Bangle.project({lat:this.lat,lon:this.lon});
|
||||
var b = Bangle.project({lat:this.lat+1,lon:this.lon+1});
|
||||
this.lon += x * this.map.scale / (a.x-b.x);
|
||||
this.lat -= y * this.map.scale / (a.y-b.y);
|
||||
var a = Bangle.project({lat:m.lat,lon:m.lon});
|
||||
var b = Bangle.project({lat:m.lat+1,lon:m.lon+1});
|
||||
this.lon += x * m.scale / (a.x-b.x);
|
||||
this.lat -= y * m.scale / (a.y-b.y);
|
||||
};
|
||||
|
|
|
@ -266,6 +266,7 @@
|
|||
WIDGETS["recorder"].reload();
|
||||
return Promise.resolve(settings.recording);
|
||||
}/*,plotTrack:function(m) { // m=instance of openstmap module
|
||||
// FIXME - add track plotting
|
||||
// if we're here, settings was already loaded
|
||||
var f = require("Storage").open(settings.file,"r");
|
||||
var l = f.readLine(f);
|
||||
|
|
Loading…
Reference in New Issue