From 4828624aa514833e79fb47e1ca905ec0c86917bb Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 3 Jun 2025 16:21:26 +0100 Subject: [PATCH] openstmap: Added 'Autoscroll' option to automatically scroll the map when GPS location moves off it, also add better docs --- apps/openstmap/ChangeLog | 3 +- apps/openstmap/README.md | 16 ++++++++++ apps/openstmap/app.js | 63 ++++++++++++++++++++++++++++------------ 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/apps/openstmap/ChangeLog b/apps/openstmap/ChangeLog index 8ac33f909..d3278a583 100644 --- a/apps/openstmap/ChangeLog +++ b/apps/openstmap/ChangeLog @@ -40,4 +40,5 @@ 0.32: Move to non-deprecated track drawing using the recorder library Add option to hide widgets 0.33: Map zoom by tapping is now only when tapping at each corner (helps with accidental zooming) - When GPS location is offscreen, draw a blue circle showing the direction to scroll \ No newline at end of file + When GPS location is offscreen, draw a blue circle showing the direction to scroll + Added 'Autoscroll' option to automatically scroll the map when GPS location moves off it \ No newline at end of file diff --git a/apps/openstmap/README.md b/apps/openstmap/README.md index bf243c391..8c17cecf3 100644 --- a/apps/openstmap/README.md +++ b/apps/openstmap/README.md @@ -45,6 +45,22 @@ The map displays: * Your currently recorded/recording track in red (if the `Recorder` app is installed) * Any waypoints as red markers (if the `Waypoint` app is installed) +## Bangle.js App Settings + +Pressing the button while in the app and unlocked brings up the settings menu: + +* `Center GPS` - (if GPS lock available) centre the map on the GPS location +* `Zoom in` - zooms in on the map (tapping bottom left in the map also does this) +* `Zoom out` - zooms out on the map (tapping bottom right in the map also does this) +* `Draw Track` - if `Recorder` is installed this will draw the current GPS track in red +* `Draw cont. position` - will leaves a series of red dots on screen marking your previous GPS position (these disappear when you scroll) +* `Hide Widgets` - hide the widget bar to leave more space for the map +* `Autoscroll` - then the GPS marker starts going offscreen, scroll to show it again +* `Direction Source` - (Bangle.js 2 only) `None/GPS/Compass` When showing the direction with the GPS marker where to get the direction from. If `None` a GPS marker isn't shown +* `Reset Compass` - reset the compass (if calibration has gone wrong - turn in a circle immediately after to recalibrate) +* `Center Map` - Center the view on the current map (not GPS) +* `Record` - If `Recorder` app is installed, start/stop recording +* `Exit` - Exit to the Clock ## Library diff --git a/apps/openstmap/app.js b/apps/openstmap/app.js index 00babc9fa..ae7906d1a 100644 --- a/apps/openstmap/app.js +++ b/apps/openstmap/app.js @@ -6,11 +6,12 @@ var settings = require("Storage").readJSON("openstmap.json",1)||{}; var HASWIDGETS = !settings.noWidgets; var plotTrack; let checkMapPos = false; // Do we need to check the if the coordinates we have are valid -var startDrag = 0; //< to detect a short tap when zooming +var startDrag = undefined; //< to detect a short tap when zooming var hasRecorder = require("Storage").read("recorder")!=undefined; // do we have the recorder library? var hasWaypoints = require("Storage").read("waypoints")!=undefined; // do we have the recorder library? var labelFont = g.getFonts().includes("17")?"17":"6x8:2"; var imgLoc, ovLoc, ovSize = 34; /*Math.ceil(Math.sqrt(imgLoc[0]*imgLoc[0]+imgLoc[1]*imgLoc[1]))*/ +var locOnscreen = undefined; // is the GPS location currently onscreen? if (Bangle.setLCDOverlay) { // Icon for current location+direction: https://icons8.com/icon/11932/gps 24x24, 1 Bit + transparency + inverted @@ -117,28 +118,29 @@ function drawLocation() { } var p = m.latLonToXY(fix.lat, fix.lon); - // TODO: if this is getting off the screen, we could adjust the map over? Also show marker to show what direction we're offscreen - ovLoc.clear(); - - if (isInside(R, p, ovLoc.getWidth(), ovLoc.getHeight())) { // avoid drawing over widget area + locOnscreen = isInside(R, p, ovLoc.getWidth(), ovLoc.getHeight()); + if (locOnscreen) { // if we're onscreen, draw the course const angle = settings.dirSrc === 1 ? fix.course : Bangle.getCompass().heading; - if (!isNaN(angle)) { + if (isNaN(angle)) { + ovLoc.fillCircle(ovSize/2,ovSize/2,8); + } else { ovLoc.drawImage(imgLoc, ovLoc.getWidth()/2, ovLoc.getHeight()/2, {rotate: angle*Math.PI/180}); } - } else { // if off-screen, draw a blue dot on the edge - var mx = (R.x+R.x2)/2, my = (R.y+R.y2)/2; - var dy = p.y - mx, dx = p.x - my; + } else { // if off-screen, draw a blue circle on the edge + var mx = R.w/2, my = R.h/2; + var dy = p.y - (R.y+my), dx = p.x - mx; + ovLoc.fillCircle(ovSize/2,ovSize/2,16); if (Math.abs(dx)>Math.abs(dy)) { dy = mx * dy / Math.abs(dx); dx = mx * Math.sign(dx); } else { + if (dy<0) ovLoc.clearRect(0,0,ovSize, (ovSize/2)-1); // so we don't overlap widgets! dx = my * dx / Math.abs(dy); dy = my * Math.sign(dy); } p.x = mx+dx; - p.y = my+dy; - ovLoc.fillCircle(ovSize/2,ovSize/2,16); + p.y = R.y+my+dy; } Bangle.setLCDOverlay({width:ovSize, height:ovSize, bpp:ovLoc.getBPP(), transparent:0, @@ -152,7 +154,22 @@ function drawLocation() { Bangle.on('GPS',function(f) { fix=f; if (HASWIDGETS && WIDGETS["sats"]) WIDGETS["sats"].draw(WIDGETS["sats"]); - if (mapVisible) { + if (mapVisible) { // could be in settings + // Automatically scroll if GPS is going offscreen and not dragging + if (settings.autoscroll && fix.fix && startDrag===undefined) { + if (locOnscreen) { // if we were onscreen last time we drew the location + var p = m.latLonToXY(fix.lat, fix.lon); // where are we onscreen? + var sx=0,sy=0; + if (p.xR.x2-32) sx = -1; + if (p.y>R.y2-32) sy = -1; + if (sx||sy) { + scroll(sx*80,sy*80); + redraw(); + } + } + } drawMarker(); drawLocation(); } @@ -217,6 +234,10 @@ function showMenu() { value : !!settings.noWidgets, onchange : v => { settings.noWidgets=v; writeSettings(); load("openstmap.app.js"); } }, + /*LANG*/"Autoscroll": { + value : !!settings.autoscroll, + onchange : v => { settings.autoscroll=v; writeSettings(); } + }, }); @@ -258,6 +279,13 @@ function showMenu() { E.showMenu(menu); } +function scroll(sx,sy) { + g.setClipRect(R.x,R.y,R.x2,R.y2); + g.scroll(sx,sy); + m.scroll(sx,sy); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); // restore cliprect +} + function showMap() { mapVisible = true; g.reset().clearRect(R); @@ -265,18 +293,15 @@ function showMap() { Bangle.setUI({mode:"custom",drag:e=>{ if (plotTrack && plotTrack.stop) plotTrack.stop(); if (e.b) { - if (!startDrag) + if (startDrag===undefined) startDrag = getTime(); if (e.dx || e.dy) { - 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); + scroll(e.dx,e.dy); } drawLocation(); - } else if (startDrag) { + } else if (startDrag!==undefined) { const delta = getTime() - startDrag; - startDrag = 0; + startDrag = undefined; if (delta < 0.2) { // short tap? if (e.y > g.getHeight() - 32) { // at bottom egde? if (e.x < 32) { // zoom in/out