@signalk/freeboard-sk 3.0.0-rc.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -3
- package/public/assets/features-corpus.json +1 -1
- package/public/{chunk-FPX76ANK.js → chunk-4ORQORV3.js} +1 -1
- package/public/{chunk-I52SSF5D.js → chunk-BW2ETQQP.js} +1 -1
- package/public/{chunk-GHN3L3U7.js → chunk-GGSNNB7Z.js} +1 -1
- package/public/{chunk-4JHNLGK4.js → chunk-HF67WER7.js} +1 -1
- package/public/{chunk-ISSYYBS2.js → chunk-OTJKIGKW.js} +3 -3
- package/public/{chunk-5YCNPW7M.js → chunk-ZNBGUBXU.js} +1 -1
- package/public/{chunk-3BQ5RDDM.js → chunk-ZTLTHAPK.js} +1 -1
- package/public/{chunk-QJ6KIYPA.js → chunk-ZUWZA665.js} +1 -1
- package/public/index.html +1 -1
- package/public/{main-4WEWE6IY.js → main-GWT4XTZZ.js} +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signalk/freeboard-sk",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Openlayers chart plotter implementation for Signal K",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"signalk-webapp",
|
|
@@ -24,8 +24,10 @@
|
|
|
24
24
|
],
|
|
25
25
|
"recommends": [
|
|
26
26
|
"signalk-charts-provider-simple",
|
|
27
|
-
"signalk-
|
|
28
|
-
"signalk-
|
|
27
|
+
"signalk-instrument-widgets",
|
|
28
|
+
"signalk-symbol-manager",
|
|
29
|
+
"@signalk/open-meteo-provider",
|
|
30
|
+
"signalk-basic-tide-widgets",
|
|
29
31
|
"signalk-restricted-areas"
|
|
30
32
|
]
|
|
31
33
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"docs":[{"id":"buddy-list","raw":"---\nid: buddy-list\ntitle: Buddy List\ncategory: AIS & Vessels\n---\n\nKeep track of boats you know — friends, other boats in your flotilla — by\nmarking them as **buddies**, then filter the vessel list down to just them\nwhen you want to find one quickly.\n\nThis requires the [signalk-buddylist-plugin](https://www.npmjs.com/package/signalk-buddylist-plugin)\ninstalled on your Signal K server. Without it, Freeboard behaves as before —\nthere's no buddy marking or filtering available.\n\n**To mark a vessel as a buddy**, tap it on the chart to open its popover and\ntap the **Is Buddy** button. Tap it again to remove the mark.\n\n**To see just your buddies**, open **Vessels** from the main menu and switch\non the **Buddies Only** toggle in the filter row. The list narrows to the\nvessels you've marked. Buddies Only can be combined with the list's other\nfilters — Ship Type and IMO Only — to narrow things down further.\n"},{"id":"chart-image-adjustment","raw":"---\nid: chart-image-adjustment\ntitle: Chart Image Adjustment\ncategory: Charts\n---\n\n\n\nAerial and satellite chart imagery is usually exposed for the land, which\ncan leave the water — where the hazards are — looking crushed and nearly\nblack. Adjusting the brightness and contrast can pull submerged rocks,\nshallows, and reefs back into view, which is handy when you're scouting an\nanchorage.\n\n**To adjust a chart's image**, open the chart list and tap the **tune**\nicon next to a chart (it appears alongside the existing opacity control,\nfor image-based charts only). A dialog offers **Brightness** and\n**Contrast** sliders with a live preview on the chart as you drag them, a\n**RESET** button to put both back to neutral, and **SAVE** to keep your\nchanges.\n\nYour adjustment is saved with that chart, alongside its opacity, so it's\nstill applied the next time you open Freeboard. Left untouched, a chart\nlooks exactly as it always has — the neutral default makes no visible\nchange.\n\nThis applies to raster, tile, WMS, and WMTS image charts. Vector charts\n(like S-57) don't have an image to adjust, so the control doesn't appear\nfor them.\n"},{"id":"chart-zoom-limits","raw":"---\nid: chart-zoom-limits\ntitle: Chart Zoom Limits\ncategory: Charts\n---\n\nEvery chart holds detail down to a certain resolution and no further. Zoom in past that\npoint and you aren't shown more information — you're shown the last real chart data\nmagnified, which looks sharper than it is. Freeboard gives you two controls over what\nhappens at that boundary.\n\n## Constrain map zoom\n\nThe **Constrain map zoom** button (the `zoom_in_map` icon on the right-hand toolbar) stops\nthe map at the edge of your chart data. Turn it on and you simply cannot zoom in — or out —\nbeyond the range your selected charts actually cover. The button highlights while active,\nand the zoom **+** / **−** buttons grey out once you reach a limit.\n\nThe limits are taken from the **widest** range across all currently selected charts: the\nlowest minimum zoom and the highest maximum zoom of any of them. Selecting or deselecting\ncharts recalculates it, so the constraint always reflects what you have switched on. Charts\nthat don't declare their own zoom range fall back to a 0–24 range. With the setting off,\nthe map is free to move between zoom 2 and 28 regardless of what your charts hold.\n\nThis is off by default. It matters most when you're working from downloaded or offline\nchart sets — a cached raster or MBTiles collection on a boat with no internet — where\nzooming past the data can't be rescued by fetching better tiles, and where a magnified\ntile can read as detail that was never surveyed.\n\n## Keep tiles visible on max zoom\n\nThe companion setting, **Keep tiles visible on max zoom** (Settings → Map), decides what a\nchart layer does once you pass *its* maximum zoom. Leave it on — it is on by default — and\nthe chart keeps drawing, stretched, instead of disappearing. Turn it off and each layer\nstops rendering beyond the resolution it genuinely has, leaving the chart blank there.\n\nIt also matters when charts of different resolutions are stacked. In a selection mixing a\nwide-area chart with a detailed harbour chart, the lower-resolution one keeps rendering\n(stretched) up to the map's maximum rather than dropping out as you zoom in.\n\nThe two settings answer different questions: *Constrain map zoom* decides **whether you can\nget there at all**, while *Keep tiles visible on max zoom* decides **what you see if you\ndo**. With the defaults — constrain off, keep-tiles on — you can zoom freely and charts\nstay visible but progressively blurrier past their real detail.\n"},{"id":"cursor-eta","raw":"---\nid: cursor-eta\ntitle: Live ETA at Cursor\ncategory: Display\n---\n\n\n\nGet a quick bearing, distance, and time estimate to any point on the chart,\njust by pointing at it — without setting a destination first.\n\n**To turn it on**, go to **Settings → Display → Status Bar Options** and\ncheck **Live ETA at cursor**. As you move the mouse over the chart, the\nstatus bar adds the bearing, distance, and ETA from your boat to the cursor,\nalongside the existing latitude/longitude readout. It's off by default and\nonly updates as the mouse moves, so it's a planning aid for anyone at a\ndesktop or laptop rather than something you'll see on a touchscreen at the\nhelm.\n\nThe ETA uses your boat's current speed over ground. If you're stopped — at\nanchor, hove to — there's no speed to estimate from, so Freeboard falls back\nto a **Reference Boat Speed** you set alongside the checkbox, keeping the\nETA useful even when you're not moving.\n"},{"id":"custom-map-symbols","raw":"---\nid: custom-map-symbols\ntitle: Custom Map Symbols\ncategory: Charts\n---\n\n\n\nFreeboard normally marks notes, waypoints, your boat, AIS traffic, aids to\nnavigation, and route points with its own built-in icons. If you'd rather use\nyour own artwork — a personal marker for a favorite dive site, a custom boat\nicon for your own vessel, a branded buoy — you can, once you install a\n**symbol provider** app on your Signal K server. Freeboard picks up whatever\nicons the provider offers and uses them automatically — there's nothing to\nturn on.\n\nThe reference app for this is\n[signalk-symbol-manager](https://www.npmjs.com/package/signalk-symbol-manager),\nwhich gives you a simple web page for uploading and organizing your own icons.\nAny similar app that publishes icons the standard way works too.\n\n## Two ways to use a custom icon\n\n**Replace one of Freeboard's built-in icons.** Give your icon the same name\nas the built-in you want to replace (for example `dive-site`) and mark it as\nbelonging to Freeboard's icon set. Your version then shows up everywhere that\nicon is normally used — on the chart and in the icon pickers — without you\nhaving to touch any existing notes or waypoints. See the reference list below\nfor which built-in names you can replace.\n\n**Add a brand-new icon.** Give your icon a new name of your choosing and it\nshows up as an extra option in the icon pickers, alongside the built-ins.\n\nWhen you've replaced a built-in, the picker shows only your version — not\nboth — so the list doesn't get cluttered. Flip the **\"Show all symbols\"**\ntoggle in a note or waypoint's icon picker to see everything at once,\nbuilt-ins included, in case you ever want to go back to the original. If you\ndeliberately pick the original built-in this way, Freeboard remembers your\nchoice and won't swap your custom icon back in later.\n\n## Where custom icons show up\n\n| Area | Custom icons? |\n|------|:---:|\n| Notes | Yes |\n| Waypoints | Yes |\n| Your own vessel | Yes |\n| AIS vessels | Yes |\n| Aids to navigation | Yes |\n| Route start / turn / end points | Yes |\n| Special waypoint markers (start pin, start boat, sightings, alarms) | No |\n| Shaded chart areas | No |\n| Dots for moored vessels | No |\n\nIcons that normally rotate to a heading or bearing — your vessel, AIS\ntargets, aids to navigation, route turn points — keep rotating correctly even\nwhen you've replaced them with your own artwork.\n\n## Built-in icon names you can replace\n\nTo replace one of these, give your icon the matching name below.\n\n**Note and waypoint markers:**\n\n```\nanchorage boatramp bridge business dam\ndive-site ferry hazard inlet lock\nmarina dock turning-basin radio-call-point\ntranshipment-dock notice-to-mariners diver-down\nnavigation-structure fuel tunnel waterway-guage\n```\n\n**Generic waypoint marker:** `waypoint`\n\n**Your own vessel:** `vessel-self`\n\n**AIS vessels** (by type):\n\n```\nais_active ais_highspeed ais_special ais_passenger ais_cargo\nais_tanker ais_other ais_inactive ais_buddy ais_self\n```\n\n(`ais_self` is whichever AIS target you currently have selected — not your\nown boat, which is `vessel-self`.)\n\n**Aids to navigation** — each comes in a physical (`real-…`) and an AIS-only\n(`virtual-…`) version:\n\n```\nreal-north / virtual-north real-east / virtual-east\nreal-south / virtual-south real-west / virtual-west\nreal-port / virtual-port real-starboard / virtual-starboard\nreal-danger / virtual-danger real-safe / virtual-safe\nreal-special / virtual-special real-basestation / virtual-basestation\nreal-weatherStation / virtual-weatherStation\nreal-aton / virtual-aton\n```\n\n**Route points:** `route-start`, `route-waypoint`, `route-end`\n\nYour own vessel, AIS, aids-to-navigation, and route icons apply everywhere at\nonce — Freeboard picks these automatically rather than letting you choose\nthem per marker, so one custom icon covers every marker of that kind.\n\n## Keeping icons through GPX import and export\n\nIf your icon declares a matching GPX symbol name, Freeboard will recognize it\nwhen you import a GPX file — a waypoint tagged with that symbol picks up your\ncustom icon instead of the default marker. Exporting a waypoint that uses a\ncustom icon writes the same information back into the GPX file, so the icon\nsurvives a round trip: export, re-import elsewhere, and your custom icon is\nstill there.\n\n## Without a symbol provider\n\nIf you haven't installed a symbol provider — or it isn't publishing any\nicons — Freeboard looks and behaves exactly as it always has: built-in icons\neverywhere, and \"Show all symbols\" just shows the built-ins.\n"},{"id":"extension-panels","raw":"---\nid: extension-panels\ntitle: Extension Panels\ncategory: Extensions\n---\n\n\n\nPanel extensions let a Signal K server plugin add a completely new feature to\nFreeboard, without waiting on a Freeboard code change to get it. You can pick\nand choose which of these tools you want installed on your boat. Each one\nadds its own new button to Freeboard's toolbar — for example, a proximity\nsearch for nearby points of interest, or an automatic route planner that\nroutes around land.\n\n\n\n**To use one**, tap the grid icon in the top-right corner of the chart to\nreveal the toolbar, then tap the plugin's button. Its panel slides in from\nthe right-hand side of the screen. Tap the button again, or use the panel's\nown close button, to put it away.\n\nA panel can also narrow down what's shown on the chart — for example,\nfiltering the waypoints list to just the ones matching your search. When a\npanel does this, a small chip appears near the top of the screen describing\nthe filter; tap its **×** to clear it and show everything again.\n\nIf you haven't installed any plugins that add a panel, the extension toolbar\nbutton doesn't appear — Freeboard looks and works exactly as it always has.\n"},{"id":"feature-browser","raw":"---\nid: feature-browser\ntitle: Feature Browser\ncategory: Display\n---\n\nThis very window you're looking at right now is the **Feature Browser** — a\nsearchable \"What's New\" window covering everything Freeboard can do. Curious\nwhat a feature does, how to use it, or when it was added? Open it any time\nfrom the **⋯ (More actions)** menu, no matter what you're doing on the\nchart.\n\nEach entry shows a screenshot, a plain description of what the feature does\nand how to use it, and the release it last changed in — click a screenshot\nto view it larger. Search narrows the list by name, and you can sort the\ntable by category, feature, status, or release.\n\nA small lightbulb button also appears on the left toolbar whenever there's\nsomething new or changed you haven't seen yet — click it to jump straight\ninto the Feature Browser. It only shows up when there's something to tell\nyou about, and disappears once you've opened the browser. Freeboard no\nlonger interrupts you with a welcome screen or a \"what's new\" popup when it\nstarts — this lightbulb is the quiet, opt-in replacement.\n"},{"id":"notes","raw":"---\nid: notes\ntitle: Notes\ncategory: Notes\n---\n\nDrop a note anywhere on the chart to mark something worth remembering — a\ngood anchorage, a hazard, a spot to check next time you're through.\n\n**To add a note**, open the edit menu (pencil icon) and choose **Add Note**,\nthen tap the chart where you want it.\n\n**To work with an existing note**, tap it on the chart. By default this\nopens a quick popover with **Move**, **Edit**, **Delete**, and **Info**\n(the info panel or a details dialog, depending on your **Prefer Info-Panel**\nsetting under **Settings → Display**). If you'd rather skip that popover and\ngo straight to the note's details, turn on **Single Click for Note Details**\nin the same settings section — a single tap then opens the details directly,\nand the details view itself offers **Move**, **Edit**, and **Delete**, so\nyou don't lose anything by skipping the popover.\n\nA note with rich content — an embedded image, or a graph like the one on a\ntide-station note — resizes its details dialog to fit, instead of clipping\nthe content or forcing you to scroll in two directions.\n"},{"id":"route-planning","raw":"---\nid: route-planning\ntitle: Route Planning\ncategory: Routes\n---\n\n\n\nDraw a route on the chart, review and adjust it, then save it for later —\nor skip saving and just use it right away.\n\n**To draw a route**, open the edit menu (pencil icon) and choose **Draw\nRoute**. Tap each point along your intended route, then double-tap (or\npress Enter) to finish. Your new route appears on the chart in amber to\nshow it hasn't been saved yet.\n\n**Unsaved and saved routes now work the same way.** Tap any route on the\nchart — freshly drawn or previously saved — to bring up its actions:\n**Modify** to drag its points into shape, **Delete** to remove it, **Points**\nto see its point list, and more. An unsaved route also offers **Save**\nright there, so turning a quick sketch into a permanent route is one tap.\nSaving keeps the route right where it is on the chart — it won't disappear\non you.\n\nThe route's info panel offers the same actions — **Save**, **Edit**,\n**Delete** — plus the point list, distance, and a description you can write\nfor the route. A route that hasn't been saved yet is labelled **(unsaved)**\nso you always know its status at a glance.\n\nIf you have an extension plugin installed that helps you plan routes — an\nauto-router that fits a route around land, for instance — it can work with\nyour route while it's still a draft, before you decide to save it.\n"},{"id":"screen-widgets","raw":"---\nid: screen-widgets\ntitle: Screen Widgets\ncategory: Extensions\n---\n\n\n\nIf you've installed a Signal K server plugin that provides a screen widget,\nyou can place it directly onto the chart screen — a compact readout like a\nspeed dial, a wind gauge, or anything else the plugin offers. Two examples\nare [signalk-instrument-widgets](https://www.npmjs.com/package/signalk-instrument-widgets),\na set of boat instrument gauges, and\n[signalk-basic-tide-widgets](https://www.npmjs.com/package/signalk-basic-tide-widgets),\nwhich shows upcoming tides.\n\nWidgets sit in the corners of the screen and at the centre of the top and\nbottom edges *(the top-left corner is reserved for Freeboard's own menu)*.\n\n**To add a widget**, press and hold an empty spot in one of these areas for\nabout a second and a half (or right-click there if you're using a mouse and\nkeyboard). A short list of the widgets that fit there appears — choose one\nand it's added to your screen. As you place more, widgets stack neatly from\nthe edge inward.\n\n**To change or remove a widget**, press and hold the widget itself. This\nopens its settings, where you can adjust it (if it has any options) or\nremove it from the screen.\n\nYour layout is remembered, so the widgets you place are still there the next\ntime you open Freeboard-SK.\n\nSome widgets can also narrow down what's shown elsewhere on the chart — for\nexample, showing only certain waypoints. When a widget does this, a small\nchip appears near the top of the screen describing the filter; tap its **×**\nto clear it and show everything again.\n\nIf you haven't installed any plugins that provide screen widgets, none of\nthis is visible — Freeboard looks and works exactly as it always has.\n"},{"id":"vessel-tracks","raw":"---\nid: vessel-tracks\ntitle: Vessel Tracks\ncategory: Tracks\n---\n\n\n\nSee where another AIS vessel has been by showing its recent track (trail) on\nthe chart.\n\n**To show every vessel's track at once**, turn on **Show Track** under\n**Settings → Vessels → Other Vessels**. Every AIS vessel's track then draws\non the chart.\n\n**To follow just one or two vessels** instead of cluttering the chart with\neveryone's track, leave that setting off and pick vessels individually: tap\na vessel on the chart to open its popover, or find it in the AIS vessel\nlist, and use the **track** button (labelled **TRACK** in the list) to turn\nits track on or off. Your picks apply for the current session only — they\naren't saved between visits.\n\nThe per-vessel picker is only available while **Show Track** is off; with it\non, every vessel is already shown, so there's nothing to pick.\n\nTrack data comes from your Signal K server, so no extra setup is needed\nbeyond what tracking already requires on the server side.\n"},{"id":"weather-overlays","raw":"---\nid: weather-overlays\ntitle: Wind, Currents & Tides\ncategory: Weather\n---\n\n\n\nGrid overlays sample live weather and current data across the visible chart\narea, each toggled independently from the **Weather** panel (opened from the\nresources list):\n\n- **Wind** — \"Enable wind layer\" toggle. Requires a Signal K Weather Provider\n plugin installed on the server. Freeboard samples a 5×4 grid of points across\n the current view and refreshes them shortly after you pan or zoom. Each point\n renders as a **wind barb** by default (half feather = 5 kn, full = 10 kn,\n pennant = 50 kn, staff pointing into the wind) or, with the\n **Display → Weather → \"Wind indicator\"** setting set to Arrow, an arrow\n pointing where the wind flows to. Either glyph always shows the sampled wind\n speed as a label. The glyph choice is shared with the wind barbs shown on\n weather-station targets — switching the Wind indicator setting changes both\n at once. The arrow glyph can be replaced with custom artwork through a symbol\n provider plugin by publishing a symbol with the well-known id\n `windIndicator-arrow`.\n\n- **Ocean Currents** — \"Enable ocean currents layer\" toggle. No server plugin\n needed — Freeboard queries the Open-Meteo Marine API directly. It samples a\n denser 10×8 grid; each arrow points in the current's flow direction, is\n colour-graded from blue (slow) to red (fast), sized by speed, and labelled\n with the current's velocity in knots.\n\n\n\n- **Tidal Currents** — appears in the Weather panel as **\"Enable tidal\n currents layer\"**, but only when a `signalk-tidal-currents` plugin is\n installed on the server; otherwise this option doesn't show up at all.\n Arrows are colour-graded and labelled with speed, the same as Ocean\n Currents. What sets it apart is a **24-hour time bar** underneath the\n toggle: drag it, click anywhere on it, or use the step buttons (±1h, ±6h)\n to see how currents shift through the day, with **Play** to animate\n through time and **Now** to jump back to the current moment.\n\nAll three overlays refresh automatically as you pan or zoom, and can be\nshown together or independently.\n"},{"id":"weather-station-wind-barbs","raw":"---\nid: weather-station-wind-barbs\ntitle: Weather Station Wind Barbs\ncategory: Weather\n---\n\n\n\nWeather-station (`meteo`) targets — AIS Met/Hydro buoys and plugin-published shore\nstations such as signalk-viva — show wind as a standard **wind barb**: half\nfeather = 5 kn, full = 10 kn, pennant = 50 kn. The barb is picked from the\nstation's reported wind speed in 5-knot buckets (5–75 kn, clamped) and its staff\nrotates to point into the reported wind direction. Below 5 kn, or when no wind is\nreported, the target falls back to the plain windsock icon, unrotated.\n\nThe wind speed is always shown as a label next to the glyph, in your configured\nwind-speed units.\n\nAll 15 barb glyphs ship with Freeboard, so this works with no setup. Any bucket\ncan be replaced with custom artwork through a symbol provider plugin by\npublishing a symbol whose id matches the well-known bucket id —\n`real-weatherStation-<kts>` for real stations, `virtual-weatherStation-<kts>` for\nvirtual ones, where `<kts>` is one of the buckets 5–75 (e.g.\n`real-weatherStation-25`).\n\nA **Display → Weather → \"Wind indicator\"** setting can switch the glyph to a\nplain arrow instead of a barb for every weather-station target on the chart.\n"}],"ledger":[{"feature":"weather-station-wind-barbs","pr":495,"kind":"new","since":"v3.0.0-beta.3","date":"2026-07-10","title":"feat(map): render meteo targets as wind barbs"},{"feature":"weather-overlays","pr":413,"kind":"new","since":"v3.0.0-beta.1","date":"2026-07-03","title":"feat(weather): add wind and ocean current overlays"},{"feature":"weather-overlays","pr":520,"kind":"enhanced","since":"v3.0.0-rc.1","date":"2026-07-14","title":"feat(weather): unify wind indicator rendering across overlays"},{"feature":"weather-station-wind-barbs","pr":520,"kind":"enhanced","since":"v3.0.0-rc.1","date":"2026-07-14","title":"feat(weather): unify wind indicator rendering across overlays"},{"feature":null,"pr":520,"kind":"skip","reason":"internal UI fix — settings dialog fixed sizing/scrolling, not a distinct feature"},{"feature":"custom-map-symbols","pr":394,"kind":"new","since":"v3.0.0-beta.0","date":"2026-06-25","title":"feat(charts): Custom map symbols via symbol providers"},{"feature":"screen-widgets","pr":395,"kind":"new","since":"v3.0.0-beta.0","date":"2026-06-26","title":"feat: Add plotter extension host: widgets, panels, buttons, resource filters & background runtimes"},{"feature":"extension-panels","pr":395,"kind":"new","since":"v3.0.0-beta.0","date":"2026-06-26","title":"feat: Add plotter extension host: widgets, panels, buttons, resource filters & background runtimes"},{"feature":"route-planning","pr":432,"kind":"enhanced","since":"v3.0.0-beta.0","date":"2026-06-29","title":"feat(routes): live route editing — editable drafts + plotter-extension route API"},{"feature":null,"pr":432,"kind":"skip","reason":"adds the routes capability to the Plotter Extensions API for extension plugins (e.g. auto-routing); no direct end-user surface in Freeboard itself"},{"feature":"vessel-tracks","pr":448,"kind":"enhanced","since":"v3.0.0-beta.0","date":"2026-07-02","title":"feat(map): add per-vessel AIS track display"},{"feature":"cursor-eta","pr":455,"kind":"new","since":"v3.0.0-beta.0","date":"2026-07-03","title":"feat(map): show live bearing, distance and ETA at cursor"},{"feature":"buddy-list","pr":484,"kind":"enhanced","since":"v3.0.0-beta.2","date":"2026-07-07","title":"feat(ais): add \"Buddies only\" option to the vessel filter"},{"feature":"chart-image-adjustment","pr":489,"kind":"new","since":"v3.0.0-beta.2","date":"2026-07-07","title":"feat(charts): add brightness/contrast adjustment for raster image layers"},{"feature":"weather-overlays","pr":491,"kind":"enhanced","since":"v3.0.0-beta.3","date":"2026-07-11","title":"feat(weather): add tidal currents overlay with time-stepping controls"},{"feature":"notes","pr":485,"kind":"enhanced","since":"v3.0.0-beta.2","date":"2026-07-07","title":"feat(notes): size Note Details dialog to fit its content"},{"feature":"notes","pr":512,"kind":"enhanced","since":"v3.0.0-beta.4","date":"2026-07-12","title":"feat(notes): add option to open note details on single click"},{"feature":"feature-browser","pr":528,"kind":"new","since":"v3.0.0-rc.1","date":"2026-07-16","title":"feat(features): add a searchable \"What's New\" feature browser"},{"feature":"feature-browser","pr":530,"kind":"enhanced","since":"v3.0.0-rc.1","date":"2026-07-17","title":"feat(features): replace forced onboarding modals with a passive What's New indicator"},{"feature":"chart-zoom-limits","kind":"new","since":"v2.1.0","date":"2023-07-06","title":"limit zoom to selected maps"}],"categories":[{"name":"Charts","hue":215},{"name":"Waypoints","hue":30},{"name":"Routes","hue":140},{"name":"Tracks","hue":170},{"name":"Notes","hue":50},{"name":"Navigation","hue":265},{"name":"Autopilot","hue":300},{"name":"Weather","hue":200},{"name":"Radar","hue":110},{"name":"AIS & Vessels","hue":240},{"name":"Alarms & Notifications","hue":5},{"name":"Import/Export","hue":80},{"name":"Extensions","hue":325},{"name":"Display","hue":185}]}
|
|
1
|
+
{"docs":[{"id":"buddy-list","raw":"---\nid: buddy-list\ntitle: Buddy List\ncategory: AIS & Vessels\n---\n\nKeep track of boats you know — friends, other boats in your flotilla — by\nmarking them as **buddies**, then filter the vessel list down to just them\nwhen you want to find one quickly.\n\nThis requires the [signalk-buddylist-plugin](https://www.npmjs.com/package/signalk-buddylist-plugin)\ninstalled on your Signal K server. Without it, Freeboard behaves as before —\nthere's no buddy marking or filtering available.\n\n**To mark a vessel as a buddy**, tap it on the chart to open its popover and\ntap the **Is Buddy** button. Tap it again to remove the mark.\n\n**To see just your buddies**, open **Vessels** from the main menu and switch\non the **Buddies Only** toggle in the filter row. The list narrows to the\nvessels you've marked. Buddies Only can be combined with the list's other\nfilters — Ship Type and IMO Only — to narrow things down further.\n"},{"id":"chart-image-adjustment","raw":"---\nid: chart-image-adjustment\ntitle: Chart Image Adjustment\ncategory: Charts\n---\n\n\n\nAerial and satellite chart imagery is usually exposed for the land, which\ncan leave the water — where the hazards are — looking crushed and nearly\nblack. Adjusting the brightness and contrast can pull submerged rocks,\nshallows, and reefs back into view, which is handy when you're scouting an\nanchorage.\n\n**To adjust a chart's image**, open the chart list and tap the **tune**\nicon next to a chart (it appears alongside the existing opacity control,\nfor image-based charts only). A dialog offers **Brightness** and\n**Contrast** sliders with a live preview on the chart as you drag them, a\n**RESET** button to put both back to neutral, and **SAVE** to keep your\nchanges.\n\nYour adjustment is saved with that chart, alongside its opacity, so it's\nstill applied the next time you open Freeboard. Left untouched, a chart\nlooks exactly as it always has — the neutral default makes no visible\nchange.\n\nThis applies to raster, tile, WMS, and WMTS image charts. Vector charts\n(like S-57) don't have an image to adjust, so the control doesn't appear\nfor them.\n"},{"id":"chart-zoom-limits","raw":"---\nid: chart-zoom-limits\ntitle: Chart Zoom Limits\ncategory: Charts\n---\n\nEvery chart holds detail down to a certain resolution and no further. Zoom in past that\npoint and you aren't shown more information — you're shown the last real chart data\nmagnified, which looks sharper than it is. Freeboard gives you two controls over what\nhappens at that boundary.\n\n## Constrain map zoom\n\nThe **Constrain map zoom** button (the `zoom_in_map` icon on the right-hand toolbar) stops\nthe map at the edge of your chart data. Turn it on and you simply cannot zoom in — or out —\nbeyond the range your selected charts actually cover. The button highlights while active,\nand the zoom **+** / **−** buttons grey out once you reach a limit.\n\nThe limits are taken from the **widest** range across all currently selected charts: the\nlowest minimum zoom and the highest maximum zoom of any of them. Selecting or deselecting\ncharts recalculates it, so the constraint always reflects what you have switched on. Charts\nthat don't declare their own zoom range fall back to a 0–24 range. With the setting off,\nthe map is free to move between zoom 2 and 28 regardless of what your charts hold.\n\nThis is off by default. It matters most when you're working from downloaded or offline\nchart sets — a cached raster or MBTiles collection on a boat with no internet — where\nzooming past the data can't be rescued by fetching better tiles, and where a magnified\ntile can read as detail that was never surveyed.\n\n## Keep tiles visible on max zoom\n\nThe companion setting, **Keep tiles visible on max zoom** (Settings → Map), decides what a\nchart layer does once you pass *its* maximum zoom. Leave it on — it is on by default — and\nthe chart keeps drawing, stretched, instead of disappearing. Turn it off and each layer\nstops rendering beyond the resolution it genuinely has, leaving the chart blank there.\n\nIt also matters when charts of different resolutions are stacked. In a selection mixing a\nwide-area chart with a detailed harbour chart, the lower-resolution one keeps rendering\n(stretched) up to the map's maximum rather than dropping out as you zoom in.\n\nThe two settings answer different questions: *Constrain map zoom* decides **whether you can\nget there at all**, while *Keep tiles visible on max zoom* decides **what you see if you\ndo**. With the defaults — constrain off, keep-tiles on — you can zoom freely and charts\nstay visible but progressively blurrier past their real detail.\n"},{"id":"cursor-eta","raw":"---\nid: cursor-eta\ntitle: Live ETA at Cursor\ncategory: Display\n---\n\n\n\nGet a quick bearing, distance, and time estimate to any point on the chart,\njust by pointing at it — without setting a destination first.\n\n**To turn it on**, go to **Settings → Display → Status Bar Options** and\ncheck **Live ETA at cursor**. As you move the mouse over the chart, the\nstatus bar adds the bearing, distance, and ETA from your boat to the cursor,\nalongside the existing latitude/longitude readout. It's off by default and\nonly updates as the mouse moves, so it's a planning aid for anyone at a\ndesktop or laptop rather than something you'll see on a touchscreen at the\nhelm.\n\nThe ETA uses your boat's current speed over ground. If you're stopped — at\nanchor, hove to — there's no speed to estimate from, so Freeboard falls back\nto a **Reference Boat Speed** you set alongside the checkbox, keeping the\nETA useful even when you're not moving.\n"},{"id":"custom-map-symbols","raw":"---\nid: custom-map-symbols\ntitle: Custom Map Symbols\ncategory: Charts\n---\n\n\n\nFreeboard normally marks notes, waypoints, your boat, AIS traffic, aids to\nnavigation, and route points with its own built-in icons. If you'd rather use\nyour own artwork — a personal marker for a favorite dive site, a custom boat\nicon for your own vessel, a branded buoy — you can, once you install a\n**symbol provider** app on your Signal K server. Freeboard picks up whatever\nicons the provider offers and uses them automatically — there's nothing to\nturn on.\n\nThe reference app for this is\n[signalk-symbol-manager](https://www.npmjs.com/package/signalk-symbol-manager),\nwhich gives you a simple web page for uploading and organizing your own icons.\nAny similar app that publishes icons the standard way works too.\n\n## Two ways to use a custom icon\n\n**Replace one of Freeboard's built-in icons.** Give your icon the same name\nas the built-in you want to replace (for example `dive-site`) and mark it as\nbelonging to Freeboard's icon set. Your version then shows up everywhere that\nicon is normally used — on the chart and in the icon pickers — without you\nhaving to touch any existing notes or waypoints. See the reference list below\nfor which built-in names you can replace.\n\n**Add a brand-new icon.** Give your icon a new name of your choosing and it\nshows up as an extra option in the icon pickers, alongside the built-ins.\n\nWhen you've replaced a built-in, the picker shows only your version — not\nboth — so the list doesn't get cluttered. Flip the **\"Show all symbols\"**\ntoggle in a note or waypoint's icon picker to see everything at once,\nbuilt-ins included, in case you ever want to go back to the original. If you\ndeliberately pick the original built-in this way, Freeboard remembers your\nchoice and won't swap your custom icon back in later.\n\n## Where custom icons show up\n\n| Area | Custom icons? |\n|------|:---:|\n| Notes | Yes |\n| Waypoints | Yes |\n| Your own vessel | Yes |\n| AIS vessels | Yes |\n| Aids to navigation | Yes |\n| Route start / turn / end points | Yes |\n| Special waypoint markers (start pin, start boat, sightings, alarms) | No |\n| Shaded chart areas | No |\n| Dots for moored vessels | No |\n\nIcons that normally rotate to a heading or bearing — your vessel, AIS\ntargets, aids to navigation, route turn points — keep rotating correctly even\nwhen you've replaced them with your own artwork.\n\n## Built-in icon names you can replace\n\nTo replace one of these, give your icon the matching name below.\n\n**Note and waypoint markers:**\n\n```\nanchorage boatramp bridge business dam\ndive-site ferry hazard inlet lock\nmarina dock turning-basin radio-call-point\ntranshipment-dock notice-to-mariners diver-down\nnavigation-structure fuel tunnel waterway-guage\n```\n\n**Generic waypoint marker:** `waypoint`\n\n**Your own vessel:** `vessel-self`\n\n**AIS vessels** (by type):\n\n```\nais_active ais_highspeed ais_special ais_passenger ais_cargo\nais_tanker ais_other ais_inactive ais_buddy ais_self\n```\n\n(`ais_self` is whichever AIS target you currently have selected — not your\nown boat, which is `vessel-self`.)\n\n**Aids to navigation** — each comes in a physical (`real-…`) and an AIS-only\n(`virtual-…`) version:\n\n```\nreal-north / virtual-north real-east / virtual-east\nreal-south / virtual-south real-west / virtual-west\nreal-port / virtual-port real-starboard / virtual-starboard\nreal-danger / virtual-danger real-safe / virtual-safe\nreal-special / virtual-special real-basestation / virtual-basestation\nreal-weatherStation / virtual-weatherStation\nreal-aton / virtual-aton\n```\n\n**Route points:** `route-start`, `route-waypoint`, `route-end`\n\nYour own vessel, AIS, aids-to-navigation, and route icons apply everywhere at\nonce — Freeboard picks these automatically rather than letting you choose\nthem per marker, so one custom icon covers every marker of that kind.\n\n## Keeping icons through GPX import and export\n\nIf your icon declares a matching GPX symbol name, Freeboard will recognize it\nwhen you import a GPX file — a waypoint tagged with that symbol picks up your\ncustom icon instead of the default marker. Exporting a waypoint that uses a\ncustom icon writes the same information back into the GPX file, so the icon\nsurvives a round trip: export, re-import elsewhere, and your custom icon is\nstill there.\n\n## Without a symbol provider\n\nIf you haven't installed a symbol provider — or it isn't publishing any\nicons — Freeboard looks and behaves exactly as it always has: built-in icons\neverywhere, and \"Show all symbols\" just shows the built-ins.\n"},{"id":"extension-panels","raw":"---\nid: extension-panels\ntitle: Extension Panels\ncategory: Extensions\n---\n\n\n\nPanel extensions let a Signal K server plugin add a completely new feature to\nFreeboard, without waiting on a Freeboard code change to get it. You can pick\nand choose which of these tools you want installed on your boat. Each one\nadds its own new button to Freeboard's toolbar — for example, a proximity\nsearch for nearby points of interest, or an automatic route planner that\nroutes around land.\n\n\n\n**To use one**, tap the grid icon in the top-right corner of the chart to\nreveal the toolbar, then tap the plugin's button. Its panel slides in from\nthe right-hand side of the screen. Tap the button again, or use the panel's\nown close button, to put it away.\n\nA panel can also narrow down what's shown on the chart — for example,\nfiltering the waypoints list to just the ones matching your search. When a\npanel does this, a small chip appears near the top of the screen describing\nthe filter; tap its **×** to clear it and show everything again.\n\nIf you haven't installed any plugins that add a panel, the extension toolbar\nbutton doesn't appear — Freeboard looks and works exactly as it always has.\n"},{"id":"feature-browser","raw":"---\nid: feature-browser\ntitle: Feature Browser\ncategory: Display\n---\n\nThis very window you're looking at right now is the **Feature Browser** — a\nsearchable \"What's New\" window covering everything Freeboard can do. Curious\nwhat a feature does, how to use it, or when it was added? Open it any time\nfrom the **⋯ (More actions)** menu, no matter what you're doing on the\nchart.\n\nEach entry shows a screenshot, a plain description of what the feature does\nand how to use it, and the release it last changed in — click a screenshot\nto view it larger. Search narrows the list by name, and you can sort the\ntable by category, feature, status, or release.\n\nA small lightbulb button also appears on the left toolbar whenever there's\nsomething new or changed you haven't seen yet — click it to jump straight\ninto the Feature Browser. It only shows up when there's something to tell\nyou about, and disappears once you've opened the browser. Freeboard no\nlonger interrupts you with a welcome screen or a \"what's new\" popup when it\nstarts — this lightbulb is the quiet, opt-in replacement.\n"},{"id":"notes","raw":"---\nid: notes\ntitle: Notes\ncategory: Notes\n---\n\nDrop a note anywhere on the chart to mark something worth remembering — a\ngood anchorage, a hazard, a spot to check next time you're through.\n\n**To add a note**, open the edit menu (pencil icon) and choose **Add Note**,\nthen tap the chart where you want it.\n\n**To work with an existing note**, tap it on the chart. By default this\nopens a quick popover with **Move**, **Edit**, **Delete**, and **Info**\n(the info panel or a details dialog, depending on your **Prefer Info-Panel**\nsetting under **Settings → Display**). If you'd rather skip that popover and\ngo straight to the note's details, turn on **Single Click for Note Details**\nin the same settings section — a single tap then opens the details directly,\nand the details view itself offers **Move**, **Edit**, and **Delete**, so\nyou don't lose anything by skipping the popover.\n\nA note with rich content — an embedded image, or a graph like the one on a\ntide-station note — resizes its details dialog to fit, instead of clipping\nthe content or forcing you to scroll in two directions.\n"},{"id":"route-planning","raw":"---\nid: route-planning\ntitle: Route Planning\ncategory: Routes\n---\n\n\n\nDraw a route on the chart, review and adjust it, then save it for later —\nor skip saving and just use it right away.\n\n**To draw a route**, open the edit menu (pencil icon) and choose **Draw\nRoute**. Tap each point along your intended route, then double-tap (or\npress Enter) to finish. Your new route appears on the chart in amber to\nshow it hasn't been saved yet.\n\n**Unsaved and saved routes now work the same way.** Tap any route on the\nchart — freshly drawn or previously saved — to bring up its actions:\n**Modify** to drag its points into shape, **Delete** to remove it, **Points**\nto see its point list, and more. An unsaved route also offers **Save**\nright there, so turning a quick sketch into a permanent route is one tap.\nSaving keeps the route right where it is on the chart — it won't disappear\non you.\n\nThe route's info panel offers the same actions — **Save**, **Edit**,\n**Delete** — plus the point list, distance, and a description you can write\nfor the route. A route that hasn't been saved yet is labelled **(unsaved)**\nso you always know its status at a glance.\n\nIf you have an extension plugin installed that helps you plan routes — an\nauto-router that fits a route around land, for instance — it can work with\nyour route while it's still a draft, before you decide to save it.\n"},{"id":"screen-widgets","raw":"---\nid: screen-widgets\ntitle: Screen Widgets\ncategory: Extensions\n---\n\n\n\nIf you've installed a Signal K server plugin that provides a screen widget,\nyou can place it directly onto the chart screen — a compact readout like a\nspeed dial, a wind gauge, or anything else the plugin offers. Two examples\nare [signalk-instrument-widgets](https://www.npmjs.com/package/signalk-instrument-widgets),\na set of boat instrument gauges, and\n[signalk-basic-tide-widgets](https://www.npmjs.com/package/signalk-basic-tide-widgets),\nwhich shows upcoming tides.\n\nWidgets sit in the corners of the screen and at the centre of the top and\nbottom edges *(the top-left corner is reserved for Freeboard's own menu)*.\n\n**To add a widget**, press and hold an empty spot in one of these areas for\nabout a second and a half (or right-click there if you're using a mouse and\nkeyboard). A short list of the widgets that fit there appears — choose one\nand it's added to your screen. As you place more, widgets stack neatly from\nthe edge inward.\n\n**To change or remove a widget**, press and hold the widget itself. This\nopens its settings, where you can adjust it (if it has any options) or\nremove it from the screen.\n\nYour layout is remembered, so the widgets you place are still there the next\ntime you open Freeboard-SK.\n\nSome widgets can also narrow down what's shown elsewhere on the chart — for\nexample, showing only certain waypoints. When a widget does this, a small\nchip appears near the top of the screen describing the filter; tap its **×**\nto clear it and show everything again.\n\nIf you haven't installed any plugins that provide screen widgets, none of\nthis is visible — Freeboard looks and works exactly as it always has.\n"},{"id":"vessel-tracks","raw":"---\nid: vessel-tracks\ntitle: Vessel Tracks\ncategory: Tracks\n---\n\n\n\nSee where another AIS vessel has been by showing its recent track (trail) on\nthe chart.\n\n**To show every vessel's track at once**, turn on **Show Track** under\n**Settings → Vessels → Other Vessels**. Every AIS vessel's track then draws\non the chart.\n\n**To follow just one or two vessels** instead of cluttering the chart with\neveryone's track, leave that setting off and pick vessels individually: tap\na vessel on the chart to open its popover, or find it in the AIS vessel\nlist, and use the **track** button (labelled **TRACK** in the list) to turn\nits track on or off. Your picks apply for the current session only — they\naren't saved between visits.\n\nThe per-vessel picker is only available while **Show Track** is off; with it\non, every vessel is already shown, so there's nothing to pick.\n\nTrack data comes from your Signal K server, so no extra setup is needed\nbeyond what tracking already requires on the server side.\n"},{"id":"weather-overlays","raw":"---\nid: weather-overlays\ntitle: Wind, Currents & Tides\ncategory: Weather\n---\n\n\n\nGrid overlays sample live weather and current data across the visible chart\narea, each toggled independently from the **Weather** panel (opened from the\nresources list):\n\n- **Wind** — \"Enable wind layer\" toggle. Requires a Signal K Weather Provider\n plugin installed on the server. Freeboard samples a 5×4 grid of points across\n the current view and refreshes them shortly after you pan or zoom. Each point\n renders as a **wind barb** by default (half feather = 5 kn, full = 10 kn,\n pennant = 50 kn, staff pointing into the wind) or, with the\n **Display → Weather → \"Wind indicator\"** setting set to Arrow, an arrow\n pointing where the wind flows to. Either glyph always shows the sampled wind\n speed as a label. The glyph choice is shared with the wind barbs shown on\n weather-station targets — switching the Wind indicator setting changes both\n at once. The arrow glyph can be replaced with custom artwork through a symbol\n provider plugin by publishing a symbol with the well-known id\n `windIndicator-arrow`.\n\n- **Ocean Currents** — \"Enable ocean currents layer\" toggle. No server plugin\n needed — Freeboard queries the Open-Meteo Marine API directly. It samples a\n denser 10×8 grid; each arrow points in the current's flow direction, is\n colour-graded from blue (slow) to red (fast), sized by speed, and labelled\n with the current's velocity in knots.\n\n\n\n- **Tidal Currents** — appears in the Weather panel as **\"Enable tidal\n currents layer\"**, but only when a `signalk-tidal-currents` plugin is\n installed on the server; otherwise this option doesn't show up at all.\n Arrows are colour-graded and labelled with speed, the same as Ocean\n Currents. What sets it apart is a **24-hour time bar** underneath the\n toggle: drag it, click anywhere on it, or use the step buttons (±1h, ±6h)\n to see how currents shift through the day, with **Play** to animate\n through time and **Now** to jump back to the current moment.\n\nAll three overlays refresh automatically as you pan or zoom, and can be\nshown together or independently.\n"},{"id":"weather-station-wind-barbs","raw":"---\nid: weather-station-wind-barbs\ntitle: Weather Station Wind Barbs\ncategory: Weather\n---\n\n\n\nWeather-station (`meteo`) targets — AIS Met/Hydro buoys and plugin-published shore\nstations such as signalk-viva — show wind as a standard **wind barb**: half\nfeather = 5 kn, full = 10 kn, pennant = 50 kn. The barb is picked from the\nstation's reported wind speed in 5-knot buckets (5–75 kn, clamped) and its staff\nrotates to point into the reported wind direction. Below 5 kn, or when no wind is\nreported, the target falls back to the plain windsock icon, unrotated.\n\nThe wind speed is always shown as a label next to the glyph, in your configured\nwind-speed units.\n\nAll 15 barb glyphs ship with Freeboard, so this works with no setup. Any bucket\ncan be replaced with custom artwork through a symbol provider plugin by\npublishing a symbol whose id matches the well-known bucket id —\n`real-weatherStation-<kts>` for real stations, `virtual-weatherStation-<kts>` for\nvirtual ones, where `<kts>` is one of the buckets 5–75 (e.g.\n`real-weatherStation-25`).\n\nA **Display → Weather → \"Wind indicator\"** setting can switch the glyph to a\nplain arrow instead of a barb for every weather-station target on the chart.\n"}],"ledger":[{"feature":"weather-station-wind-barbs","pr":495,"kind":"new","since":"v3.0.0","date":"2026-07-10","title":"feat(map): render meteo targets as wind barbs"},{"feature":"weather-overlays","pr":413,"kind":"new","since":"v3.0.0","date":"2026-07-03","title":"feat(weather): add wind and ocean current overlays"},{"feature":"weather-overlays","pr":520,"kind":"enhanced","since":"v3.0.0","date":"2026-07-14","title":"feat(weather): unify wind indicator rendering across overlays"},{"feature":"weather-station-wind-barbs","pr":520,"kind":"enhanced","since":"v3.0.0","date":"2026-07-14","title":"feat(weather): unify wind indicator rendering across overlays"},{"feature":null,"pr":520,"kind":"skip","reason":"internal UI fix — settings dialog fixed sizing/scrolling, not a distinct feature"},{"feature":"custom-map-symbols","pr":394,"kind":"new","since":"v3.0.0","date":"2026-06-25","title":"feat(charts): Custom map symbols via symbol providers"},{"feature":"screen-widgets","pr":395,"kind":"new","since":"v3.0.0","date":"2026-06-26","title":"feat: Add plotter extension host: widgets, panels, buttons, resource filters & background runtimes"},{"feature":"extension-panels","pr":395,"kind":"new","since":"v3.0.0","date":"2026-06-26","title":"feat: Add plotter extension host: widgets, panels, buttons, resource filters & background runtimes"},{"feature":"route-planning","pr":432,"kind":"enhanced","since":"v3.0.0","date":"2026-06-29","title":"feat(routes): live route editing — editable drafts + plotter-extension route API"},{"feature":null,"pr":432,"kind":"skip","reason":"adds the routes capability to the Plotter Extensions API for extension plugins (e.g. auto-routing); no direct end-user surface in Freeboard itself"},{"feature":"vessel-tracks","pr":448,"kind":"enhanced","since":"v3.0.0","date":"2026-07-02","title":"feat(map): add per-vessel AIS track display"},{"feature":"cursor-eta","pr":455,"kind":"new","since":"v3.0.0","date":"2026-07-03","title":"feat(map): show live bearing, distance and ETA at cursor"},{"feature":"buddy-list","pr":484,"kind":"enhanced","since":"v3.0.0","date":"2026-07-07","title":"feat(ais): add \"Buddies only\" option to the vessel filter"},{"feature":"chart-image-adjustment","pr":489,"kind":"new","since":"v3.0.0","date":"2026-07-07","title":"feat(charts): add brightness/contrast adjustment for raster image layers"},{"feature":"weather-overlays","pr":491,"kind":"enhanced","since":"v3.0.0","date":"2026-07-11","title":"feat(weather): add tidal currents overlay with time-stepping controls"},{"feature":"notes","pr":485,"kind":"enhanced","since":"v3.0.0","date":"2026-07-07","title":"feat(notes): size Note Details dialog to fit its content"},{"feature":"notes","pr":512,"kind":"enhanced","since":"v3.0.0","date":"2026-07-12","title":"feat(notes): add option to open note details on single click"},{"feature":"feature-browser","pr":528,"kind":"new","since":"v3.0.0","date":"2026-07-16","title":"feat(features): add a searchable \"What's New\" feature browser"},{"feature":"feature-browser","pr":530,"kind":"enhanced","since":"v3.0.0","date":"2026-07-17","title":"feat(features): replace forced onboarding modals with a passive What's New indicator"},{"feature":"chart-zoom-limits","kind":"new","since":"v2.1.0","date":"2023-07-06","title":"limit zoom to selected maps"}],"categories":[{"name":"Charts","hue":215},{"name":"Waypoints","hue":30},{"name":"Routes","hue":140},{"name":"Tracks","hue":170},{"name":"Notes","hue":50},{"name":"Navigation","hue":265},{"name":"Autopilot","hue":300},{"name":"Weather","hue":200},{"name":"Radar","hue":110},{"name":"AIS & Vessels","hue":240},{"name":"Alarms & Notifications","hue":5},{"name":"Import/Export","hue":80},{"name":"Extensions","hue":325},{"name":"Display","hue":185}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ta as z}from"./chunk-
|
|
1
|
+
import{ta as z}from"./chunk-OTJKIGKW.js";import"./chunk-IURS3QQO.js";import"./chunk-4BXCQ655.js";import"./chunk-LXTM3LEN.js";import"./chunk-IYNTZMNB.js";import"./chunk-3CRIFTHA.js";import"./chunk-UF7LOYCE.js";import"./chunk-XHEJEIFO.js";import"./chunk-I3OUN6B4.js";import"./chunk-WX7YZB5N.js";import{Dd as C,Ea as m,Ed as w,Fa as d,Gd as S,Hd as R,Id as E,Jd as O,Ka as _,La as a,Ma as o,Na as v,Q as f,R as u,Rd as T,Td as A,Ua as D,Wa as p,Wd as k,Ya as g,Yd as j,Zd as V,ab as b,bb as x,cb as y,ha as h,ja as s,kc as I,lb as r,mb as M,oa as c,ra as P}from"./chunk-4BSA3TDQ.js";import"./chunk-EQVTEUXC.js";var U=["frame"];function Q(n,e){if(n&1&&(a(0,"mat-dialog-content",3),v(1,"iframe",6,0),o()),n&2){let t=g();s(),_("src",t.url,h)("title",t.data.panel.title)}}function B(n,e){n&1&&(a(0,"mat-dialog-content",4),r(1," This widget has no settings. "),o())}function F(n,e){if(n&1){let t=D();a(0,"mat-dialog-actions",5)(1,"button",7),p("click",function(){f(t);let l=g();return u(l.removeWidget())}),a(2,"mat-icon"),r(3,"delete"),o(),r(4," Remove widget "),o()()}}var W=class n{constructor(e,t,i,l){this.dialogRef=e;this.data=t;this.service=i;this.sanitizer=l}frame;url;detach=null;ngOnInit(){let e=this.data.panel;e&&(this.url=this.sanitizer.bypassSecurityTrustResourceUrl(e.url?this.service.resolveAssetUrl(e.url):"about:blank"))}ngAfterViewInit(){let e=this.data.panel;!e||!this.frame||(this.detach=this.service.attachPanel(this.frame.nativeElement,{extension:this.data.extension,panel:e,targetInstance:this.data.targetInstance,targetWidget:this.data.targetWidget,close:()=>this.dialogRef.close()}))}removeWidget(){this.data.targetInstance&&this.service.removeWidget(this.data.targetInstance),this.dialogRef.close()}ngOnDestroy(){this.detach?.(),this.detach=null}static \u0275fac=function(t){return new(t||n)(c(C),c(w),c(z),c(I))};static \u0275cmp=P({type:n,selectors:[["fb-plotterext-panel-dialog"]],viewQuery:function(t,i){if(t&1&&b(U,5),t&2){let l;x(l=y())&&(i.frame=l.first)}},decls:9,vars:3,consts:[["frame",""],["mat-dialog-title","",1,"pe-panel-header"],["mat-icon-button","","aria-label","Close",3,"click"],[1,"pe-panel-content"],[1,"pe-panel-noconfig"],[1,"pe-panel-actions"],["sandbox","allow-scripts allow-same-origin allow-forms",3,"src","title"],["mat-button","",1,"pe-remove",3,"click"]],template:function(t,i){t&1&&(a(0,"div",1)(1,"span"),r(2),o(),a(3,"button",2),p("click",function(){return i.dialogRef.close()}),a(4,"mat-icon"),r(5,"close"),o()()(),m(6,Q,3,2,"mat-dialog-content",3)(7,B,2,0,"mat-dialog-content",4),m(8,F,5,0,"mat-dialog-actions",5)),t&2&&(s(2),M(i.data.panel?i.data.panel.title:i.data.title),s(4),d(i.data.panel?6:7),s(2),d(i.data.targetInstance?8:-1))},dependencies:[O,S,E,R,k,A,T,V,j],styles:[".pe-panel-header[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:space-between;padding-right:8px}.pe-panel-content[_ngcontent-%COMP%]{padding:0;height:60vh}.pe-panel-noconfig[_ngcontent-%COMP%]{padding:16px 24px;color:#0009}iframe[_ngcontent-%COMP%]{display:block;width:100%;height:100%;border:none}.pe-panel-actions[_ngcontent-%COMP%]{justify-content:flex-start}.pe-remove[_ngcontent-%COMP%]{color:#d32f2f}"]})};export{W as PlotterPanelDialog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Aa as a}from"./chunk-
|
|
1
|
+
import{Aa as a}from"./chunk-OTJKIGKW.js";import"./chunk-IURS3QQO.js";import"./chunk-4BXCQ655.js";import"./chunk-LXTM3LEN.js";import"./chunk-IYNTZMNB.js";import"./chunk-3CRIFTHA.js";import"./chunk-UF7LOYCE.js";import"./chunk-XHEJEIFO.js";import"./chunk-I3OUN6B4.js";import"./chunk-WX7YZB5N.js";import"./chunk-4BSA3TDQ.js";import"./chunk-EQVTEUXC.js";export{a as GeoJSONImportDialog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as ue,b as w,c as me,d as he,e as fe}from"./chunk-FEIJMPL7.js";import{A as ce,B as de,g as z,h as ee,i as te,j as ie,k as ae,l as ne,o as re,s as le,x as pe}from"./chunk-ISSYYBS2.js";import{a as N,b as se,c as oe}from"./chunk-IURS3QQO.js";import{b as H}from"./chunk-4BXCQ655.js";import{i as q,j as J,k as Q}from"./chunk-LXTM3LEN.js";import"./chunk-IYNTZMNB.js";import{a as U}from"./chunk-3CRIFTHA.js";import"./chunk-UF7LOYCE.js";import"./chunk-XHEJEIFO.js";import"./chunk-I3OUN6B4.js";import{j as Y,o as Z}from"./chunk-WX7YZB5N.js";import{Dd as X,Ea as _,Ed as F,Fa as k,Ha as v,Hd as V,Ia as b,Ja as C,Jd as I,Ka as f,L as R,La as s,Ma as r,P as D,Q as m,R as h,Rd as K,Td as B,Ua as x,Wa as g,Wd as $,Ya as d,Yd as A,Zd as j,c as E,gb as T,ja as p,lb as c,mb as W,nb as G,oa as y,pe as L,ra as O}from"./chunk-4BSA3TDQ.js";import{f as M}from"./chunk-EQVTEUXC.js";var P=class{gpx;constructor(){this.init()}init(){this.gpx=new ue,this.gpx.metadata.name="Signal K Resource Export",this.gpx.metadata.desc="Freeboard export of Signal K resources"}toXML(){return this.gpx.toXML()}setRoutes(i,t){if(t)t.forEach(e=>{i[e]&&this.gpx.rte.push(this.packageRoute(e,i[e]))});else for(let e in i)this.gpx.rte.push(this.packageRoute(e,i[e]))}packageRoute(i,t){let e=new me;e.extensions=e.extensions??{},e.extensions.signalk={},e.extensions.signalk.uuid=i,t.distance&&(e.extensions.signalk.distance=t.distance),e.name=t.name||null,e.desc=t.description||null,e.cmt=t.feature.properties.cmt||null,e.src=t.feature.properties.src||null,e.number=t.feature.properties.number||null,e.type=t.feature.properties.type||null;for(let a of t.feature.geometry.coordinates){let n=new w;n.lon=a[0],n.lat=a[1],n.ele=a[2]||null,e.rtept.push(n),this.gpx.updateBounds(n)}return e}setWaypoints(i,t){if(t)t.forEach(e=>{i[e]&&this.gpx.wpt.push(this.packageWaypoint(e,i[e]))});else for(let e in i)this.gpx.wpt.push(this.packageWaypoint(e,i[e]))}packageWaypoint(i,t){let e=new w;if(e.extensions=e.extensions||{},e.extensions.signalk={},e.extensions.signalk.uuid=i,e.name=t.name||"",e.desc=t.description||"",e.cmt=t.feature.properties.cmt||null,e.geoidHeight=t.feature.properties.geoidHeight||null,e.src=t.feature.properties.src||null,e.sym=t.feature.properties.sym||null,e.type=t.feature.properties.type||null,t.type==="waypoint"){let a=le(t.feature.properties.skIcon);a?.gpxType&&(e.type=a.gpxType),a?.gpxSym&&(e.sym=a.gpxSym)}return e.fix=t.feature.properties.fix||null,e.sat=t.feature.properties.sat||null,e.hdop=t.feature.properties.hdop||null,e.vdop=t.feature.properties.vdop||null,e.pdop=t.feature.properties.pdop||null,e.ageOfGpsData=t.feature.properties.ageOfGpsData||null,e.dgpsid=t.feature.properties.dgpsid||null,e.lat=t.feature.geometry.coordinates[1],e.lon=t.feature.geometry.coordinates[0],e.ele=t.feature.geometry.coordinates[2]||null,this.gpx.updateBounds(e),e}setTracks(i,t){if(t)t.forEach(e=>{i[e]&&this.gpx.trk.push(this.packageTrack(e,i[e]))});else for(let e in i)this.gpx.trk.push(this.packageTrack(e,i[e]))}packageTrack(i,t){let e=new he;e.extensions=e.extensions||{},e.extensions.signalk={},e.extensions.signalk.uuid=i,e.name=t.feature.properties.name||null,e.desc=t.feature.properties.description||null,e.cmt=t.feature.properties.cmt||null,e.src=t.feature.properties.src||null,e.number=t.feature.properties.number||null,e.type=t.feature.properties.type||null;for(let a of t.feature.geometry.coordinates){let n=new fe;for(let o of a){let u=new w;u.lon=o[0],u.lat=o[1],u.ele=o[2]||null,n.trkpt.push(u),this.gpx.updateBounds(u)}e.trkseg.push(n)}return e}};var S=class l{resultSource;result$;sk2gpx;hasFSA;signalk=D(re);constructor(){this.resultSource=new E,this.result$=this.resultSource.asObservable(),this.hasFSA="showOpenFilePicker"in window}clear(){this.sk2gpx=null}prepData(i){let t={routes:[],waypoints:[],tracks:[]},e=1;return t.routes=i.routes.map(a=>{let n=a[1];return n.feature.id=a[0],n}),e=1,t.waypoints=i.waypoints.map(a=>{let n=a[1];return n.feature.id=a[0],n.name=n.name??`Wpt: ${e}`,e++,n}),t.tracks=i.tracks,t}saveToFile(i,t){this.sk2gpx=new P;let e={},a={},n={};for(let o=0;o<t.rte.selected.length;o++)t.rte.selected[o]&&(e[i.routes[o].feature.id]=i.routes[o]);this.sk2gpx.setRoutes(e);for(let o=0;o<t.wpt.selected.length;o++)t.wpt.selected[o]&&(a[i.waypoints[o].feature.id]=i.waypoints[o]);this.sk2gpx.setWaypoints(a);for(let o=0;o<t.trk.selected.length;o++)if(t.trk.selected[o]){let u=this.signalk.uuid;n[u]=new ce,n[u].feature.id=u,n[u].feature.properties.name=`Vessel trail: ${Date().toString()}`,n[u].feature.geometry.coordinates.push(i.tracks[o])}this.sk2gpx.setTracks(n),this.hasFSA?this.fsaSaveFile():this.legacySaveToFile()}legacySaveToFile(){let i=new Blob([this.sk2gpx.toXML()],{type:"text/xml"}),t=document.createElement("a");t.href=URL.createObjectURL(i),t.download="fb_export.gpx",t.click(),URL.revokeObjectURL(t.href),t.remove(),this.resultSource.next(-1)}fsaSaveFile(){window.showSaveFilePicker({types:[{description:"GPX file",accept:{"text/xml":[".gpx"]}}]}).then(i=>{i.createWritable().then(t=>{let e=new Blob([this.sk2gpx.toXML()]);t.write(e).then(()=>{t.close(),this.resultSource.next(0)})}).catch(t=>{console.warn(t),this.resultSource.next(1)})}).catch(()=>{this.resultSource.next(-1)})}static \u0275fac=function(t){return new(t||l)};static \u0275prov=R({token:l,factory:l.\u0275fac,providedIn:"root"})};function _e(l,i){if(l&1){let t=x();s(0,"div",18)(1,"div",19),c(2),r(),s(3,"div",20)(4,"mat-checkbox",21,0),g("change",function(){let a=m(t).$index,n=T(5),o=d(2);return h(o.checkWpt(n.checked,a))}),r()()()}if(l&2){let t=i.$implicit,e=i.$index,a=d(2);p(2),W(t.name),p(2),f("checked",a.selWaypoints[e])}}function ke(l,i){if(l&1){let t=x();s(0,"div",11)(1,"mat-expansion-panel",12),g("opened",function(){m(t);let a=d();return h(a.display.expand.waypoints=!0)})("closed",function(){m(t);let a=d();return h(a.display.expand.waypoints=!1)}),s(2,"mat-expansion-panel-header",13)(3,"mat-panel-title")(4,"mat-icon",14),c(5,"place"),r(),c(6," \xA0"),s(7,"b"),c(8,"Waypoints:"),r()(),s(9,"mat-panel-description")(10,"div",15)(11,"mat-checkbox",16),g("change",function(a){m(t);let n=d();return h(n.checkWpt(a.checked,-1))})("click",function(a){return a.cancelBubble=!0}),r()()()(),s(12,"div",17),b(13,_e,6,2,"div",18,v),r()()()}if(l&2){let t=d();p(),f("expanded",t.display.expand.waypoints),p(10),f("indeterminate",t.display.someWptChecked)("checked",t.display.allWaypointsChecked)("disabled",t.resData.waypoints.length===0),p(2),C(t.resData.waypoints)}}function ve(l,i){if(l&1){let t=x();s(0,"div",18)(1,"div",19)(2,"mat-icon",22),c(3,"directions"),r(),c(4),r(),s(5,"div",20)(6,"mat-checkbox",24,1),g("change",function(){let a=m(t).$index,n=T(7),o=d(2);return h(o.checkRte(n.checked,a))}),r()()()}if(l&2){let t=i.$implicit,e=i.$index,a=d(2);p(4),G(" ",t.name," "),p(2),f("checked",a.selRoutes[e])}}function be(l,i){if(l&1){let t=x();s(0,"div",11)(1,"mat-expansion-panel",12),g("opened",function(){m(t);let a=d();return h(a.display.expand.routes=!0)})("closed",function(){m(t);let a=d();return h(a.display.expand.routes=!1)}),s(2,"mat-expansion-panel-header",13)(3,"mat-panel-title")(4,"mat-icon",22),c(5,"directions"),r(),c(6," \xA0"),s(7,"b"),c(8,"Routes:"),r()(),s(9,"mat-panel-description")(10,"div",15)(11,"mat-checkbox",23),g("change",function(a){m(t);let n=d();return h(n.checkRte(a.checked,-1))})("click",function(a){return a.cancelBubble=!0}),r()()()(),s(12,"div",17),b(13,ve,8,2,"div",18,v),r()()()}if(l&2){let t=d();p(),f("expanded",t.display.expand.routes),p(10),f("indeterminate",t.display.someRteChecked)("checked",t.display.allRoutesChecked)("disabled",t.resData.routes.length==0),p(2),C(t.resData.routes)}}function Ce(l,i){if(l&1){let t=x();s(0,"div",18)(1,"div",19)(2,"mat-icon",26),c(3,"directions_boat"),r(),c(4," Vessel Trail "),r(),s(5,"div",20)(6,"mat-checkbox",28,2),g("change",function(){let a=m(t).$index,n=T(7),o=d(2);return h(o.checkTrk(n.checked,a))}),r()()()}if(l&2){let t=i.$index,e=d(2);p(6),f("checked",e.selTracks[t])}}function Te(l,i){if(l&1){let t=x();s(0,"div",11)(1,"mat-expansion-panel",25)(2,"mat-expansion-panel-header",13)(3,"mat-panel-title")(4,"mat-icon",26),c(5,"show_chart"),r(),c(6," \xA0"),s(7,"b"),c(8,"Tracks:"),r()(),s(9,"mat-panel-description")(10,"div",15)(11,"mat-checkbox",27),g("change",function(a){m(t);let n=d();return h(n.checkTrk(a.checked,-1))})("click",function(a){return a.cancelBubble=!0}),r()()()(),s(12,"div",17),b(13,Ce,8,1,"div",18,v),r()()()}if(l&2){let t=d();p(),f("expanded",!1),p(10),f("indeterminate",!1)("checked",t.display.allTracksChecked)("disabled",t.resData.tracks.length==0),p(2),C(t.resData.tracks)}}var ge=class l{constructor(i,t,e,a,n){this.app=i;this.skres=t;this.facade=e;this.dialogRef=a;this.data=n}resData={routes:[],waypoints:[],tracks:[]};selRoutes=[];selectedRoute=null;selWaypoints=[];selTracks=[];display={notValid:!1,allRoutesChecked:!1,allWaypointsChecked:!1,allTracksChecked:!1,someWptChecked:!1,someRteChecked:!1,someTrkChecked:!1,saveRoutesOK:!1,saveWaypointsOK:!1,saveTracksOK:!1,routeViewer:!1,selCount:{routes:0,waypoints:0,tracks:0},expand:{routes:!1,waypoints:!1,tracks:!1}};unsubscribe=[];ngOnInit(){this.loadResources(),this.unsubscribe.push(this.facade.result$.subscribe(i=>{this.dialogRef.close(i)}))}ngOnDestroy(){this.unsubscribe.forEach(i=>i.unsubscribe()),this.facade.clear()}loadResources(){return M(this,null,function*(){this.data.routes.sort((i,t)=>i[1].name.localeCompare(t[1].name));try{this.app.sIsFetching.set(!0);let i=yield this.skres.listFromServer("waypoints");i.sort((t,e)=>t[1].name.localeCompare(e[1].name)),this.data.waypoints=i,this.app.sIsFetching.set(!1)}catch(i){this.app.sIsFetching.set(!1),this.resData.waypoints=[]}this.parseResourceData()})}save(){this.facade.saveToFile(this.resData,{rte:{selected:this.selRoutes},wpt:{selected:this.selWaypoints},trk:{selected:this.selTracks}})}parseResourceData(){this.display.allRoutesChecked=!1,this.display.saveRoutesOK=!1,this.selRoutes=[],this.display.allWaypointsChecked=!1,this.display.saveWaypointsOK=!1,this.selWaypoints=[],this.display.allTracksChecked=!1,this.display.saveTracksOK=!1,this.selTracks=[],this.display.selCount={routes:0,waypoints:0,tracks:0},this.display.expand={routes:!1,waypoints:!1,tracks:!1},this.display.notValid=!1,this.resData=this.facade.prepData(this.data),this.resData.routes.forEach(()=>{this.selRoutes.push(!1)}),this.selRoutes.length===1&&(this.selRoutes[0]=!0,this.display.allRoutesChecked=!0,this.display.expand.routes=!0,this.display.saveRoutesOK=!0),this.resData.waypoints.forEach(()=>{this.selWaypoints.push(!1)}),this.selTracks.push(!1)}checkRte(i,t=-1){let e=0;if(t!==-1){this.selRoutes[t]=i,this.display.saveRoutesOK=i;for(let a of this.selRoutes)a&&e++;this.display.saveRoutesOK=e!==0,this.display.selCount.routes=e,this.display.allRoutesChecked=e===this.selRoutes.length}else{for(let a=0;a<this.selRoutes.length;a++)this.selRoutes[a]=i,this.display.saveRoutesOK=i,this.display.allRoutesChecked=i;this.display.selCount.routes=i?this.selRoutes.length:0}this.display.someRteChecked=!(this.display.allRoutesChecked||e===0)}checkWpt(i,t=-1){let e=0;if(t!==-1){this.selWaypoints[t]=i,this.display.saveWaypointsOK=i;for(let a of this.selWaypoints)a&&e++;this.display.saveWaypointsOK=e!==0,this.display.selCount.waypoints=e,this.display.allWaypointsChecked=e===this.selWaypoints.length}else{for(let a=0;a<this.selWaypoints.length;a++)this.selWaypoints[a]=i,this.display.saveWaypointsOK=i,this.display.allWaypointsChecked=i;this.display.selCount.waypoints=i?this.selWaypoints.length:0}this.display.someWptChecked=!(this.display.allWaypointsChecked||e===0)}checkTrk(i,t=-1){let e=0;if(t!==-1){this.selTracks[t]=i,this.display.saveTracksOK=i;for(let a of this.selTracks)a&&e++;this.display.saveTracksOK=e!==0,this.display.selCount.tracks=e,this.display.allTracksChecked=e===this.selTracks.length}else{for(let a=0;a<this.selTracks.length;a++)this.selTracks[a]=i,this.display.saveTracksOK=i,this.display.allTracksChecked=i;this.display.selCount.tracks=i?this.selTracks.length:0}this.display.someTrkChecked=!(this.display.allTracksChecked||e===0)}static \u0275fac=function(t){return new(t||l)(y(pe),y(de),y(S),y(X),y(F))};static \u0275cmp=O({type:l,selectors:[["gpxsave-dialog"]],decls:18,vars:4,consts:[["wval",""],["rval",""],["tval",""],[1,"gpxsave-dialog"],[2,"background-color","transparent"],[2,"display","flex","width","100%"],["mat-raised-button","","matTooltip","Save selected resources","matTooltipPosition","right",2,"width","85px",3,"click","disabled"],[2,"flex","1 1 auto","text-align","center"],[2,"text-align","right"],["mat-icon-button","",3,"click"],["mat-dialog-content","",2,"padding","2px"],[1,"card-group"],[3,"opened","closed","expanded"],[1,"panel-header"],[1,"icon-waypoint"],[1,"panel-description"],["matTooltip","Select all Waypoints","matTooltipPosition","before",3,"change","click","indeterminate","checked","disabled"],[1,"list-container-scrollable"],[1,"item-row"],[1,"name"],[1,"check"],["matTooltip","Select Waypoint","matTooltipPosition","below",3,"change","checked"],[1,"icon-route"],["matTooltip","Select all Routes","matTooltipPosition","before",3,"change","click","indeterminate","checked","disabled"],["matTooltip","Select this Route","matTooltipPosition","below",3,"change","checked"],[3,"expanded"],[1,"icon-track"],["matTooltip","Vessel Trail to Track","matTooltipPosition","before",3,"change","click","indeterminate","checked","disabled"],["matTooltip","Select this Track","matTooltipPosition","below",3,"change","checked"]],template:function(t,e){t&1&&(s(0,"div",3)(1,"mat-toolbar",4)(2,"div",5)(3,"div")(4,"button",6),g("click",function(){return e.save()}),s(5,"mat-icon"),c(6,"save"),r(),c(7,"\xA0Save\xA0 "),r()(),s(8,"div",7),c(9,"Export to GPX"),r(),s(10,"div",8)(11,"button",9),g("click",function(){return e.dialogRef.close(-1)}),s(12,"mat-icon"),c(13,"close"),r()()()()(),s(14,"div",10),_(15,ke,15,4,"div",11),_(16,be,15,4,"div",11),_(17,Te,15,4,"div",11),r()()),t&2&&(p(4),f("disabled",!e.display.saveRoutesOK&&!e.display.saveWaypointsOK&&!e.display.saveTracksOK),p(11),k(e.resData.waypoints.length!==0?15:-1),p(),k(e.resData.routes.length!==0?16:-1),p(),k(!e.app.data.serverTrail&&e.resData.tracks.length!==0?17:-1))},dependencies:[oe,se,z,I,V,j,A,$,B,K,q,Y,Z,H,ne,ee,te,ae,ie,Q,J,N,U,L],styles:[".gpxsave-dialog[_ngcontent-%COMP%]{font-family:roboto;position:relative}.dialog-content[_ngcontent-%COMP%]{position:relative;min-height:300px;max-height:400px;width:100%;min-width:240px;overflow-y:auto}.dialog-icon[_ngcontent-%COMP%]{display:none}.card-group[_ngcontent-%COMP%]{padding:5px 5%}.card-group[_ngcontent-%COMP%] .panel-header[_ngcontent-%COMP%]{padding:0 5px}.card-group[_ngcontent-%COMP%] .panel-description[_ngcontent-%COMP%]{text-align:right;width:100%;padding-right:10px}.card-group-title[_ngcontent-%COMP%]{font-weight:700;font-size:10pt;font-family:Arial,Helvetica,sans-serif;padding:10px 0}button[_ngcontent-%COMP%]{min-width:unset;padding:unset}.item-row[_ngcontent-%COMP%]{display:flex;width:100%;padding:2px 0}.item-row[_ngcontent-%COMP%] .name[_ngcontent-%COMP%]{flex:1 1 auto;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;text-overflow:ellipsis;line-height:2.5em}.item-row[_ngcontent-%COMP%] .check[_ngcontent-%COMP%]{text-align:right;padding-right:15px}@media only screen and (min-width:475px){button[_ngcontent-%COMP%]{min-width:inherit;padding:inherit}.dialog-content[_ngcontent-%COMP%]{min-width:400px}.dialog-icon[_ngcontent-%COMP%]{display:inline}}@media only screen and (min-width:800px){.card-group[_ngcontent-%COMP%]{padding:5px 5%}}"]})};export{ge as GPXExportDialog};
|
|
1
|
+
import{a as ue,b as w,c as me,d as he,e as fe}from"./chunk-FEIJMPL7.js";import{A as ce,B as de,g as z,h as ee,i as te,j as ie,k as ae,l as ne,o as re,s as le,x as pe}from"./chunk-OTJKIGKW.js";import{a as N,b as se,c as oe}from"./chunk-IURS3QQO.js";import{b as H}from"./chunk-4BXCQ655.js";import{i as q,j as J,k as Q}from"./chunk-LXTM3LEN.js";import"./chunk-IYNTZMNB.js";import{a as U}from"./chunk-3CRIFTHA.js";import"./chunk-UF7LOYCE.js";import"./chunk-XHEJEIFO.js";import"./chunk-I3OUN6B4.js";import{j as Y,o as Z}from"./chunk-WX7YZB5N.js";import{Dd as X,Ea as _,Ed as F,Fa as k,Ha as v,Hd as V,Ia as b,Ja as C,Jd as I,Ka as f,L as R,La as s,Ma as r,P as D,Q as m,R as h,Rd as K,Td as B,Ua as x,Wa as g,Wd as $,Ya as d,Yd as A,Zd as j,c as E,gb as T,ja as p,lb as c,mb as W,nb as G,oa as y,pe as L,ra as O}from"./chunk-4BSA3TDQ.js";import{f as M}from"./chunk-EQVTEUXC.js";var P=class{gpx;constructor(){this.init()}init(){this.gpx=new ue,this.gpx.metadata.name="Signal K Resource Export",this.gpx.metadata.desc="Freeboard export of Signal K resources"}toXML(){return this.gpx.toXML()}setRoutes(i,t){if(t)t.forEach(e=>{i[e]&&this.gpx.rte.push(this.packageRoute(e,i[e]))});else for(let e in i)this.gpx.rte.push(this.packageRoute(e,i[e]))}packageRoute(i,t){let e=new me;e.extensions=e.extensions??{},e.extensions.signalk={},e.extensions.signalk.uuid=i,t.distance&&(e.extensions.signalk.distance=t.distance),e.name=t.name||null,e.desc=t.description||null,e.cmt=t.feature.properties.cmt||null,e.src=t.feature.properties.src||null,e.number=t.feature.properties.number||null,e.type=t.feature.properties.type||null;for(let a of t.feature.geometry.coordinates){let n=new w;n.lon=a[0],n.lat=a[1],n.ele=a[2]||null,e.rtept.push(n),this.gpx.updateBounds(n)}return e}setWaypoints(i,t){if(t)t.forEach(e=>{i[e]&&this.gpx.wpt.push(this.packageWaypoint(e,i[e]))});else for(let e in i)this.gpx.wpt.push(this.packageWaypoint(e,i[e]))}packageWaypoint(i,t){let e=new w;if(e.extensions=e.extensions||{},e.extensions.signalk={},e.extensions.signalk.uuid=i,e.name=t.name||"",e.desc=t.description||"",e.cmt=t.feature.properties.cmt||null,e.geoidHeight=t.feature.properties.geoidHeight||null,e.src=t.feature.properties.src||null,e.sym=t.feature.properties.sym||null,e.type=t.feature.properties.type||null,t.type==="waypoint"){let a=le(t.feature.properties.skIcon);a?.gpxType&&(e.type=a.gpxType),a?.gpxSym&&(e.sym=a.gpxSym)}return e.fix=t.feature.properties.fix||null,e.sat=t.feature.properties.sat||null,e.hdop=t.feature.properties.hdop||null,e.vdop=t.feature.properties.vdop||null,e.pdop=t.feature.properties.pdop||null,e.ageOfGpsData=t.feature.properties.ageOfGpsData||null,e.dgpsid=t.feature.properties.dgpsid||null,e.lat=t.feature.geometry.coordinates[1],e.lon=t.feature.geometry.coordinates[0],e.ele=t.feature.geometry.coordinates[2]||null,this.gpx.updateBounds(e),e}setTracks(i,t){if(t)t.forEach(e=>{i[e]&&this.gpx.trk.push(this.packageTrack(e,i[e]))});else for(let e in i)this.gpx.trk.push(this.packageTrack(e,i[e]))}packageTrack(i,t){let e=new he;e.extensions=e.extensions||{},e.extensions.signalk={},e.extensions.signalk.uuid=i,e.name=t.feature.properties.name||null,e.desc=t.feature.properties.description||null,e.cmt=t.feature.properties.cmt||null,e.src=t.feature.properties.src||null,e.number=t.feature.properties.number||null,e.type=t.feature.properties.type||null;for(let a of t.feature.geometry.coordinates){let n=new fe;for(let o of a){let u=new w;u.lon=o[0],u.lat=o[1],u.ele=o[2]||null,n.trkpt.push(u),this.gpx.updateBounds(u)}e.trkseg.push(n)}return e}};var S=class l{resultSource;result$;sk2gpx;hasFSA;signalk=D(re);constructor(){this.resultSource=new E,this.result$=this.resultSource.asObservable(),this.hasFSA="showOpenFilePicker"in window}clear(){this.sk2gpx=null}prepData(i){let t={routes:[],waypoints:[],tracks:[]},e=1;return t.routes=i.routes.map(a=>{let n=a[1];return n.feature.id=a[0],n}),e=1,t.waypoints=i.waypoints.map(a=>{let n=a[1];return n.feature.id=a[0],n.name=n.name??`Wpt: ${e}`,e++,n}),t.tracks=i.tracks,t}saveToFile(i,t){this.sk2gpx=new P;let e={},a={},n={};for(let o=0;o<t.rte.selected.length;o++)t.rte.selected[o]&&(e[i.routes[o].feature.id]=i.routes[o]);this.sk2gpx.setRoutes(e);for(let o=0;o<t.wpt.selected.length;o++)t.wpt.selected[o]&&(a[i.waypoints[o].feature.id]=i.waypoints[o]);this.sk2gpx.setWaypoints(a);for(let o=0;o<t.trk.selected.length;o++)if(t.trk.selected[o]){let u=this.signalk.uuid;n[u]=new ce,n[u].feature.id=u,n[u].feature.properties.name=`Vessel trail: ${Date().toString()}`,n[u].feature.geometry.coordinates.push(i.tracks[o])}this.sk2gpx.setTracks(n),this.hasFSA?this.fsaSaveFile():this.legacySaveToFile()}legacySaveToFile(){let i=new Blob([this.sk2gpx.toXML()],{type:"text/xml"}),t=document.createElement("a");t.href=URL.createObjectURL(i),t.download="fb_export.gpx",t.click(),URL.revokeObjectURL(t.href),t.remove(),this.resultSource.next(-1)}fsaSaveFile(){window.showSaveFilePicker({types:[{description:"GPX file",accept:{"text/xml":[".gpx"]}}]}).then(i=>{i.createWritable().then(t=>{let e=new Blob([this.sk2gpx.toXML()]);t.write(e).then(()=>{t.close(),this.resultSource.next(0)})}).catch(t=>{console.warn(t),this.resultSource.next(1)})}).catch(()=>{this.resultSource.next(-1)})}static \u0275fac=function(t){return new(t||l)};static \u0275prov=R({token:l,factory:l.\u0275fac,providedIn:"root"})};function _e(l,i){if(l&1){let t=x();s(0,"div",18)(1,"div",19),c(2),r(),s(3,"div",20)(4,"mat-checkbox",21,0),g("change",function(){let a=m(t).$index,n=T(5),o=d(2);return h(o.checkWpt(n.checked,a))}),r()()()}if(l&2){let t=i.$implicit,e=i.$index,a=d(2);p(2),W(t.name),p(2),f("checked",a.selWaypoints[e])}}function ke(l,i){if(l&1){let t=x();s(0,"div",11)(1,"mat-expansion-panel",12),g("opened",function(){m(t);let a=d();return h(a.display.expand.waypoints=!0)})("closed",function(){m(t);let a=d();return h(a.display.expand.waypoints=!1)}),s(2,"mat-expansion-panel-header",13)(3,"mat-panel-title")(4,"mat-icon",14),c(5,"place"),r(),c(6," \xA0"),s(7,"b"),c(8,"Waypoints:"),r()(),s(9,"mat-panel-description")(10,"div",15)(11,"mat-checkbox",16),g("change",function(a){m(t);let n=d();return h(n.checkWpt(a.checked,-1))})("click",function(a){return a.cancelBubble=!0}),r()()()(),s(12,"div",17),b(13,_e,6,2,"div",18,v),r()()()}if(l&2){let t=d();p(),f("expanded",t.display.expand.waypoints),p(10),f("indeterminate",t.display.someWptChecked)("checked",t.display.allWaypointsChecked)("disabled",t.resData.waypoints.length===0),p(2),C(t.resData.waypoints)}}function ve(l,i){if(l&1){let t=x();s(0,"div",18)(1,"div",19)(2,"mat-icon",22),c(3,"directions"),r(),c(4),r(),s(5,"div",20)(6,"mat-checkbox",24,1),g("change",function(){let a=m(t).$index,n=T(7),o=d(2);return h(o.checkRte(n.checked,a))}),r()()()}if(l&2){let t=i.$implicit,e=i.$index,a=d(2);p(4),G(" ",t.name," "),p(2),f("checked",a.selRoutes[e])}}function be(l,i){if(l&1){let t=x();s(0,"div",11)(1,"mat-expansion-panel",12),g("opened",function(){m(t);let a=d();return h(a.display.expand.routes=!0)})("closed",function(){m(t);let a=d();return h(a.display.expand.routes=!1)}),s(2,"mat-expansion-panel-header",13)(3,"mat-panel-title")(4,"mat-icon",22),c(5,"directions"),r(),c(6," \xA0"),s(7,"b"),c(8,"Routes:"),r()(),s(9,"mat-panel-description")(10,"div",15)(11,"mat-checkbox",23),g("change",function(a){m(t);let n=d();return h(n.checkRte(a.checked,-1))})("click",function(a){return a.cancelBubble=!0}),r()()()(),s(12,"div",17),b(13,ve,8,2,"div",18,v),r()()()}if(l&2){let t=d();p(),f("expanded",t.display.expand.routes),p(10),f("indeterminate",t.display.someRteChecked)("checked",t.display.allRoutesChecked)("disabled",t.resData.routes.length==0),p(2),C(t.resData.routes)}}function Ce(l,i){if(l&1){let t=x();s(0,"div",18)(1,"div",19)(2,"mat-icon",26),c(3,"directions_boat"),r(),c(4," Vessel Trail "),r(),s(5,"div",20)(6,"mat-checkbox",28,2),g("change",function(){let a=m(t).$index,n=T(7),o=d(2);return h(o.checkTrk(n.checked,a))}),r()()()}if(l&2){let t=i.$index,e=d(2);p(6),f("checked",e.selTracks[t])}}function Te(l,i){if(l&1){let t=x();s(0,"div",11)(1,"mat-expansion-panel",25)(2,"mat-expansion-panel-header",13)(3,"mat-panel-title")(4,"mat-icon",26),c(5,"show_chart"),r(),c(6," \xA0"),s(7,"b"),c(8,"Tracks:"),r()(),s(9,"mat-panel-description")(10,"div",15)(11,"mat-checkbox",27),g("change",function(a){m(t);let n=d();return h(n.checkTrk(a.checked,-1))})("click",function(a){return a.cancelBubble=!0}),r()()()(),s(12,"div",17),b(13,Ce,8,1,"div",18,v),r()()()}if(l&2){let t=d();p(),f("expanded",!1),p(10),f("indeterminate",!1)("checked",t.display.allTracksChecked)("disabled",t.resData.tracks.length==0),p(2),C(t.resData.tracks)}}var ge=class l{constructor(i,t,e,a,n){this.app=i;this.skres=t;this.facade=e;this.dialogRef=a;this.data=n}resData={routes:[],waypoints:[],tracks:[]};selRoutes=[];selectedRoute=null;selWaypoints=[];selTracks=[];display={notValid:!1,allRoutesChecked:!1,allWaypointsChecked:!1,allTracksChecked:!1,someWptChecked:!1,someRteChecked:!1,someTrkChecked:!1,saveRoutesOK:!1,saveWaypointsOK:!1,saveTracksOK:!1,routeViewer:!1,selCount:{routes:0,waypoints:0,tracks:0},expand:{routes:!1,waypoints:!1,tracks:!1}};unsubscribe=[];ngOnInit(){this.loadResources(),this.unsubscribe.push(this.facade.result$.subscribe(i=>{this.dialogRef.close(i)}))}ngOnDestroy(){this.unsubscribe.forEach(i=>i.unsubscribe()),this.facade.clear()}loadResources(){return M(this,null,function*(){this.data.routes.sort((i,t)=>i[1].name.localeCompare(t[1].name));try{this.app.sIsFetching.set(!0);let i=yield this.skres.listFromServer("waypoints");i.sort((t,e)=>t[1].name.localeCompare(e[1].name)),this.data.waypoints=i,this.app.sIsFetching.set(!1)}catch(i){this.app.sIsFetching.set(!1),this.resData.waypoints=[]}this.parseResourceData()})}save(){this.facade.saveToFile(this.resData,{rte:{selected:this.selRoutes},wpt:{selected:this.selWaypoints},trk:{selected:this.selTracks}})}parseResourceData(){this.display.allRoutesChecked=!1,this.display.saveRoutesOK=!1,this.selRoutes=[],this.display.allWaypointsChecked=!1,this.display.saveWaypointsOK=!1,this.selWaypoints=[],this.display.allTracksChecked=!1,this.display.saveTracksOK=!1,this.selTracks=[],this.display.selCount={routes:0,waypoints:0,tracks:0},this.display.expand={routes:!1,waypoints:!1,tracks:!1},this.display.notValid=!1,this.resData=this.facade.prepData(this.data),this.resData.routes.forEach(()=>{this.selRoutes.push(!1)}),this.selRoutes.length===1&&(this.selRoutes[0]=!0,this.display.allRoutesChecked=!0,this.display.expand.routes=!0,this.display.saveRoutesOK=!0),this.resData.waypoints.forEach(()=>{this.selWaypoints.push(!1)}),this.selTracks.push(!1)}checkRte(i,t=-1){let e=0;if(t!==-1){this.selRoutes[t]=i,this.display.saveRoutesOK=i;for(let a of this.selRoutes)a&&e++;this.display.saveRoutesOK=e!==0,this.display.selCount.routes=e,this.display.allRoutesChecked=e===this.selRoutes.length}else{for(let a=0;a<this.selRoutes.length;a++)this.selRoutes[a]=i,this.display.saveRoutesOK=i,this.display.allRoutesChecked=i;this.display.selCount.routes=i?this.selRoutes.length:0}this.display.someRteChecked=!(this.display.allRoutesChecked||e===0)}checkWpt(i,t=-1){let e=0;if(t!==-1){this.selWaypoints[t]=i,this.display.saveWaypointsOK=i;for(let a of this.selWaypoints)a&&e++;this.display.saveWaypointsOK=e!==0,this.display.selCount.waypoints=e,this.display.allWaypointsChecked=e===this.selWaypoints.length}else{for(let a=0;a<this.selWaypoints.length;a++)this.selWaypoints[a]=i,this.display.saveWaypointsOK=i,this.display.allWaypointsChecked=i;this.display.selCount.waypoints=i?this.selWaypoints.length:0}this.display.someWptChecked=!(this.display.allWaypointsChecked||e===0)}checkTrk(i,t=-1){let e=0;if(t!==-1){this.selTracks[t]=i,this.display.saveTracksOK=i;for(let a of this.selTracks)a&&e++;this.display.saveTracksOK=e!==0,this.display.selCount.tracks=e,this.display.allTracksChecked=e===this.selTracks.length}else{for(let a=0;a<this.selTracks.length;a++)this.selTracks[a]=i,this.display.saveTracksOK=i,this.display.allTracksChecked=i;this.display.selCount.tracks=i?this.selTracks.length:0}this.display.someTrkChecked=!(this.display.allTracksChecked||e===0)}static \u0275fac=function(t){return new(t||l)(y(pe),y(de),y(S),y(X),y(F))};static \u0275cmp=O({type:l,selectors:[["gpxsave-dialog"]],decls:18,vars:4,consts:[["wval",""],["rval",""],["tval",""],[1,"gpxsave-dialog"],[2,"background-color","transparent"],[2,"display","flex","width","100%"],["mat-raised-button","","matTooltip","Save selected resources","matTooltipPosition","right",2,"width","85px",3,"click","disabled"],[2,"flex","1 1 auto","text-align","center"],[2,"text-align","right"],["mat-icon-button","",3,"click"],["mat-dialog-content","",2,"padding","2px"],[1,"card-group"],[3,"opened","closed","expanded"],[1,"panel-header"],[1,"icon-waypoint"],[1,"panel-description"],["matTooltip","Select all Waypoints","matTooltipPosition","before",3,"change","click","indeterminate","checked","disabled"],[1,"list-container-scrollable"],[1,"item-row"],[1,"name"],[1,"check"],["matTooltip","Select Waypoint","matTooltipPosition","below",3,"change","checked"],[1,"icon-route"],["matTooltip","Select all Routes","matTooltipPosition","before",3,"change","click","indeterminate","checked","disabled"],["matTooltip","Select this Route","matTooltipPosition","below",3,"change","checked"],[3,"expanded"],[1,"icon-track"],["matTooltip","Vessel Trail to Track","matTooltipPosition","before",3,"change","click","indeterminate","checked","disabled"],["matTooltip","Select this Track","matTooltipPosition","below",3,"change","checked"]],template:function(t,e){t&1&&(s(0,"div",3)(1,"mat-toolbar",4)(2,"div",5)(3,"div")(4,"button",6),g("click",function(){return e.save()}),s(5,"mat-icon"),c(6,"save"),r(),c(7,"\xA0Save\xA0 "),r()(),s(8,"div",7),c(9,"Export to GPX"),r(),s(10,"div",8)(11,"button",9),g("click",function(){return e.dialogRef.close(-1)}),s(12,"mat-icon"),c(13,"close"),r()()()()(),s(14,"div",10),_(15,ke,15,4,"div",11),_(16,be,15,4,"div",11),_(17,Te,15,4,"div",11),r()()),t&2&&(p(4),f("disabled",!e.display.saveRoutesOK&&!e.display.saveWaypointsOK&&!e.display.saveTracksOK),p(11),k(e.resData.waypoints.length!==0?15:-1),p(),k(e.resData.routes.length!==0?16:-1),p(),k(!e.app.data.serverTrail&&e.resData.tracks.length!==0?17:-1))},dependencies:[oe,se,z,I,V,j,A,$,B,K,q,Y,Z,H,ne,ee,te,ae,ie,Q,J,N,U,L],styles:[".gpxsave-dialog[_ngcontent-%COMP%]{font-family:roboto;position:relative}.dialog-content[_ngcontent-%COMP%]{position:relative;min-height:300px;max-height:400px;width:100%;min-width:240px;overflow-y:auto}.dialog-icon[_ngcontent-%COMP%]{display:none}.card-group[_ngcontent-%COMP%]{padding:5px 5%}.card-group[_ngcontent-%COMP%] .panel-header[_ngcontent-%COMP%]{padding:0 5px}.card-group[_ngcontent-%COMP%] .panel-description[_ngcontent-%COMP%]{text-align:right;width:100%;padding-right:10px}.card-group-title[_ngcontent-%COMP%]{font-weight:700;font-size:10pt;font-family:Arial,Helvetica,sans-serif;padding:10px 0}button[_ngcontent-%COMP%]{min-width:unset;padding:unset}.item-row[_ngcontent-%COMP%]{display:flex;width:100%;padding:2px 0}.item-row[_ngcontent-%COMP%] .name[_ngcontent-%COMP%]{flex:1 1 auto;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;text-overflow:ellipsis;line-height:2.5em}.item-row[_ngcontent-%COMP%] .check[_ngcontent-%COMP%]{text-align:right;padding-right:15px}@media only screen and (min-width:475px){button[_ngcontent-%COMP%]{min-width:inherit;padding:inherit}.dialog-content[_ngcontent-%COMP%]{min-width:400px}.dialog-icon[_ngcontent-%COMP%]{display:inline}}@media only screen and (min-width:800px){.card-group[_ngcontent-%COMP%]{padding:5px 5%}}"]})};export{ge as GPXExportDialog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Ba as a}from"./chunk-
|
|
1
|
+
import{Ba as a}from"./chunk-OTJKIGKW.js";import"./chunk-IURS3QQO.js";import"./chunk-4BXCQ655.js";import"./chunk-LXTM3LEN.js";import"./chunk-IYNTZMNB.js";import"./chunk-3CRIFTHA.js";import"./chunk-UF7LOYCE.js";import"./chunk-XHEJEIFO.js";import"./chunk-I3OUN6B4.js";import"./chunk-WX7YZB5N.js";import"./chunk-4BSA3TDQ.js";import"./chunk-EQVTEUXC.js";export{a as Trail2RouteDialog};
|