@rhizomatics/signalk-einklabel-plugin 0.4.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/CHANGELOG.md +12 -0
- package/README.md +129 -0
- package/package.json +73 -0
- package/templates/tide.svg +230 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# 0.4.0
|
|
2
|
+
- Added `einklabel` as a `source` for template fields, and `repainted` as path
|
|
3
|
+
- Added `local_datetime_short` as a datetime format option, for `27 Jun 26 18:05` style output
|
|
4
|
+
- Add Last Repainted field to the Tide Clock example
|
|
5
|
+
# 0.3.2
|
|
6
|
+
- Renamed to signalk-einklabel-plugin
|
|
7
|
+
- Added core test suite
|
|
8
|
+
# 0.3.1
|
|
9
|
+
- Correct name, and include changelog
|
|
10
|
+
# 0.3.0
|
|
11
|
+
- First published beta release
|
|
12
|
+
- Tested publishing Tide Clock on interval to a Zhunyco 3.7" display
|
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# ESL for SignalK
|
|
2
|
+
|
|
3
|
+
** BETA - basic functionality, limited vendor/product support **
|
|
4
|
+
|
|
5
|
+
A SignalK plugin to display data from SignalK paths, APIs and plugins on Electronic Shelf Labels over a Bluetooth Low Energy (BLE) connection.
|
|
6
|
+
|
|
7
|
+
Electronic Shelf Labels (ESLs) are [eInk](https://en.wikipedia.org/wiki/E_Ink) devices that consume very little battery energy, presuming they are not constantly updated - the battery is used only when the display changes, and a periodic BLE check for incoming changes. Perfect for info that changes only once or twice a day, like tidal information.
|
|
8
|
+
|
|
9
|
+
Since they are designed to be used in large quantity in small shops, they are cheap and simple devices. Earlier models required dedicated controllers, or updates over Wifi or NFC, whereas many modern ones are standalone BLE devices that can be updated from a phone or server.
|
|
10
|
+
|
|
11
|
+
Unlike some eInk projects, this plugin doesn't require any physical modification to the labels, or loading any new firmware. It can send an image to a supported shelf label fresh out of the box.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Tide Clock
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
The tide clock needs the [signalk-tides](https://github.com/openwatersio/signalk-tides) plugin to be installed and publishing tides to the Resources API. It can however be customized to run with other APIs or take data only from SignalK data paths.
|
|
20
|
+
|
|
21
|
+
## Templating
|
|
22
|
+
|
|
23
|
+
Templates are simply SVG files, to which expressions can be added to use SignalK data, with options to make it easier to read, like rounding or simplifying dates and times. The template can have sample data in the placeholder, so is easy to layout and visualize.
|
|
24
|
+
|
|
25
|
+
### Template Source Specification
|
|
26
|
+
|
|
27
|
+
In the `description` of the SVG text box, use a comma separated set of key value pairs to define the data source and formatting.
|
|
28
|
+
|
|
29
|
+
#### SignalK Paths
|
|
30
|
+
|
|
31
|
+
For example, `path=environment.forecast.description` uses the default data source (the `self` vessel context) and the named SignalK path. A bare path with no key/value pairs at all, e.g. just `environment.forecast.description`, is shorthand for the same thing. Overriding the default context can be done with `path=environment.forecast.description,context=vessels.urn:mrn:imo:mmsi:232345678` - the `context` value must match a real SignalK context exactly as it appears in the Data Browser.
|
|
32
|
+
|
|
33
|
+
#### SignalK REST APIs
|
|
34
|
+
|
|
35
|
+
The source can be overridden to use the SignalK server's Resources API instead. For example, `source=resources,resource=tides,path=station.name` picks the `tides` resource and pulls the `station.name` path out of the JSON response - this works for any resource type (`tides`, `waypoints`, `routes`, ...), and needs nothing configured: the plugin reaches the Resources API directly. Where a resource is specified, it will be fetched once for that render, and subsequent fields sourced from the same resource use that cached response.
|
|
36
|
+
|
|
37
|
+
#### Plugin Data
|
|
38
|
+
|
|
39
|
+
`source=einklabel` reads data injected by the plugin itself, rather than from SignalK. Currently the only such value is `path=repainted`, the timestamp of the current repaint - for example `source=einklabel,path=repainted,format=local_datetime_short` to show when the label was last updated.
|
|
40
|
+
|
|
41
|
+
#### Customizing Output
|
|
42
|
+
|
|
43
|
+
A `format` can be specified to make the value easier to understand. The supported formats are:
|
|
44
|
+
|
|
45
|
+
* `local_time` - reduce a time stamp to just the time (H:M:S), omitting the date, and applying daylight savings if appropriate
|
|
46
|
+
* `day_mon` - reduce a time stamp to day and month, e.g. `27 Jun`, applying daylight savings if appropriate
|
|
47
|
+
* `local_datetime_short` - format a time stamp as day, abbreviated month, 2-digit year and 24h time, e.g. `21 Jun 26 18:05`, applying daylight savings if appropriate
|
|
48
|
+
* `utc_offset` - Show a timezone in `UTC+01:00` style format
|
|
49
|
+
* `position` - Format a `{ latitude, longitude }` value as decimal degrees with hemisphere letters, e.g. `56.6250°N 6.0700°W`
|
|
50
|
+
* `raw` - Don't apply automatic SignalK unit conversion and symbol display (see below)
|
|
51
|
+
|
|
52
|
+
SignalK's unit preferences are used to automatically convert a `signalk`-sourced numeric value to its preferred display unit, and append a unit symbol like `kt` or `m`, unless `format=raw` is specified to switch that off. However, when using plugin or API data there may be no path metadata to convert from (for example `signalk-tides` publishes tide data to the Resources API, and `level` is a raw metre value with no SignalK path of its own) - in these cases an explicit `category` can be given instead, and the unit preferences will be applied the same way, for example `category=depth` for the tides level figure.
|
|
53
|
+
|
|
54
|
+
Common categories:
|
|
55
|
+
|
|
56
|
+
* `depth` - Use the SignalK preferred depth unit, make the conversion if needed, and tack on the unit name as a suffix
|
|
57
|
+
* `speed` - Use the SignalK preferred speed unit, make the conversion if needed, and tack on the unit name as a suffix
|
|
58
|
+
* `temperature` - Use the SignalK preferred temperature unit, make the conversion if needed, and tack on the unit name as a suffix
|
|
59
|
+
|
|
60
|
+
Additionally, `round=n` can be used to round to limited decimal places.
|
|
61
|
+
|
|
62
|
+
These can all be combined as in `source=resources,resource=tides,path=extremes[2].level,category=depth,round=2`
|
|
63
|
+
|
|
64
|
+
### Fonts
|
|
65
|
+
|
|
66
|
+
Three font types are loaded by default, use the font name or simply 'sans-serif' in the SVG editor and choose size and weight (bold, semi-bold etc). Some labels will make a decent attempt to gray scale. Use the simple pure red, yellow, white, black to match the label's limited colour choice (some labels only offer black and white, or black/white/red).
|
|
67
|
+
|
|
68
|
+
* `serif` - Playfair Display
|
|
69
|
+
* `sans-serif` - Roboto
|
|
70
|
+
* `monospace` - JetBrains Mono
|
|
71
|
+
|
|
72
|
+
## Command Line Interface
|
|
73
|
+
|
|
74
|
+
To get fast feedback on templates and shelf devices without updating and configuring SignalK, a CLI is provided that has these commands.
|
|
75
|
+
|
|
76
|
+
- `vendors` - list supported vendors
|
|
77
|
+
- `scan` - report supported devices found from a BLE scan
|
|
78
|
+
|
|
79
|
+
See also the commands useful for debugging under [Developing Templates]
|
|
80
|
+
- `render` - transform an SVG template and data into a PNG
|
|
81
|
+
- `paint` - render an SVG template and data to a selected ESL
|
|
82
|
+
|
|
83
|
+
## Vendors
|
|
84
|
+
|
|
85
|
+
### Zhsunyco
|
|
86
|
+
|
|
87
|
+
Also known as 'Suny'
|
|
88
|
+
|
|
89
|
+
- [BLE ESLs](https://www.zhsunyco.com/digital-display-solution-for-small-retail-business/ble-esl-solution/)
|
|
90
|
+
- The range of labels available on retail sites like AliExpress may be larger than on their corporate site
|
|
91
|
+
- In mid 2026, a 4 colour (BWRY) 3.7" label retailed for about $35, with quantity discounts for bulk sets
|
|
92
|
+
- Cheapest units are 2 colour 1.54", and they go up to 7.5"
|
|
93
|
+
|
|
94
|
+
Python code for a variety of their labels at https://github.com/roxburghm/zhsunyco-esl and https://github.com/NickWaterton/Wolink
|
|
95
|
+
|
|
96
|
+
## Architecture
|
|
97
|
+
|
|
98
|
+
The primary things managed and provided by the plugin are:
|
|
99
|
+
|
|
100
|
+
* ESL Vendor
|
|
101
|
+
* ESL Device
|
|
102
|
+
* SVG Template
|
|
103
|
+
* SignalK API base URL
|
|
104
|
+
- Used for automatic unit conversion on `signalk`-sourced numeric values and for resolving an explicit `category=` binding - neither has an in-process equivalent, both go via this server's own REST API
|
|
105
|
+
- Optional: left blank, the plugin probes the probable values in likelihood order at startup - `http://localhost:3000`, `http://localhost`, `https://localhost`. Set it explicitly to skip probing
|
|
106
|
+
- Either way, errors clearly if nothing responds (wrong port) or the probe is rejected (anonymous read access not enabled) - these endpoints must allow anonymous read access, since the plugin has no login flow
|
|
107
|
+
|
|
108
|
+
### Extending
|
|
109
|
+
|
|
110
|
+
#### Hardware
|
|
111
|
+
|
|
112
|
+
Additional vendors and devices can be added by a separate npm package that implements the `VendorDriver` interface and registers itself - there's no scanning of installed packages, registration is always an explicit call by the extension's own code.
|
|
113
|
+
|
|
114
|
+
- `import esl from '@rhizomatics/signalk-einklabel-plugin'; esl.registerVendorDriver(myDriver)`
|
|
115
|
+
- In the SignalK runtime, call this from the extension's own plugin `start()`. In the CLI, load the extension with `esl-cli --require <module> <command>`.
|
|
116
|
+
- Declare this package as a `peerDependency` (not a regular dependency) in the extension package, so npm resolves a single shared copy of the registry.
|
|
117
|
+
|
|
118
|
+
#### Developing Templates
|
|
119
|
+
|
|
120
|
+
Templates can be added to the configurable directory. [Inkscape](https://inkscape.org) free, open source, and recommended for editing templates, or your own favourite editor, or by hand in a text editor for hard core (or just tidying up the template side).
|
|
121
|
+
|
|
122
|
+
Inkscape adds its own metadata to images, which can be stripped off by exporting a simple SVG, although can be left in place with no harm; main reason to simplify the SVG is manual changes in a text editor.
|
|
123
|
+
|
|
124
|
+
The `esl-cli` can be used to debug and validate templates quickly:
|
|
125
|
+
|
|
126
|
+
* `render` - Render templates with SignalK data and write to a local PNG file
|
|
127
|
+
* `paint` - Render templates with SignalK data and send to selected ESL device
|
|
128
|
+
* `fields` - List the fields in the template, with the source specification and the rendered data value
|
|
129
|
+
* `field` - Accept a source specification (outside of any template context) and return the rendered value if available
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rhizomatics/signalk-einklabel-plugin",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "SignalK plugin that renders selected SignalK data to eInk Electronic Shelf Labels",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"esl-cli": "dist/cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"templates",
|
|
13
|
+
"CHANGELOG.md",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"watch": "tsc --watch",
|
|
19
|
+
"cli": "ts-node src/cli/index.ts",
|
|
20
|
+
"test": "node --require ts-node/register --test \"src/**/*.test.ts\""
|
|
21
|
+
},
|
|
22
|
+
"signalk":{
|
|
23
|
+
"displayName":"eInk ESL Instruments",
|
|
24
|
+
"appIcon": "/docs/assets/icons/icon_tmp.png",
|
|
25
|
+
"screenshots": [
|
|
26
|
+
"docs/assets/screenshots/example_tidal_clock.png"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"signalk-node-server-plugin",
|
|
31
|
+
"signalk-category-instruments",
|
|
32
|
+
"signalk-category-hardware",
|
|
33
|
+
"signalk",
|
|
34
|
+
"eink",
|
|
35
|
+
"esl",
|
|
36
|
+
"display",
|
|
37
|
+
"instrument",
|
|
38
|
+
"ble"
|
|
39
|
+
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@fontsource/jetbrains-mono": "^5.2.8",
|
|
45
|
+
"@fontsource/playfair-display": "^5.2.8",
|
|
46
|
+
"@fontsource/roboto": "^5.2.10",
|
|
47
|
+
"@resvg/resvg-wasm": "^2.6.2",
|
|
48
|
+
"@xmldom/xmldom": "^0.9.10",
|
|
49
|
+
"commander": "^12.1.0",
|
|
50
|
+
"luxon": "^3.7.2",
|
|
51
|
+
"mathjs": "^15.2.0",
|
|
52
|
+
"node-ble": "^1.13.0",
|
|
53
|
+
"pngjs": "^7.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@signalk/server-api": "^2.28.0",
|
|
57
|
+
"@types/luxon": "^3.7.1",
|
|
58
|
+
"@types/node": "^20.14.0",
|
|
59
|
+
"@types/pngjs": "^6.0.5",
|
|
60
|
+
"ts-node": "^10.9.2",
|
|
61
|
+
"typescript": "^5.5.0"
|
|
62
|
+
},
|
|
63
|
+
"license": "APACHE-2.0",
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/rhizomatics/signalk-einklabel-plugin.git"
|
|
67
|
+
},
|
|
68
|
+
"author": "jey burrows",
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/rhizomatics/signalk-einklabel-plugin/issues"
|
|
71
|
+
},
|
|
72
|
+
"homepage": "https://github.com/rhizomatics/signalk-einklabel-plugin#readme"
|
|
73
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg
|
|
3
|
+
width="416"
|
|
4
|
+
height="240"
|
|
5
|
+
viewBox="0 0 416 240"
|
|
6
|
+
version="1.1"
|
|
7
|
+
id="svg1"
|
|
8
|
+
sodipodi:docname="tide.svg"
|
|
9
|
+
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
|
|
10
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
11
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
|
14
|
+
<defs
|
|
15
|
+
id="defs1" />
|
|
16
|
+
<sodipodi:namedview
|
|
17
|
+
id="namedview1"
|
|
18
|
+
pagecolor="#ffffff"
|
|
19
|
+
bordercolor="#000000"
|
|
20
|
+
borderopacity="0.25"
|
|
21
|
+
inkscape:showpageshadow="2"
|
|
22
|
+
inkscape:pageopacity="0.0"
|
|
23
|
+
inkscape:pagecheckerboard="0"
|
|
24
|
+
inkscape:deskcolor="#d1d1d1"
|
|
25
|
+
inkscape:zoom="0.98333333"
|
|
26
|
+
inkscape:cx="250.16949"
|
|
27
|
+
inkscape:cy="246.61017"
|
|
28
|
+
inkscape:window-width="1488"
|
|
29
|
+
inkscape:window-height="674"
|
|
30
|
+
inkscape:window-x="0"
|
|
31
|
+
inkscape:window-y="33"
|
|
32
|
+
inkscape:window-maximized="0"
|
|
33
|
+
inkscape:current-layer="svg1" />
|
|
34
|
+
<rect
|
|
35
|
+
x="1.0169492"
|
|
36
|
+
y="2.0798673e-08"
|
|
37
|
+
width="416"
|
|
38
|
+
height="240"
|
|
39
|
+
fill="#ffffff"
|
|
40
|
+
id="rect1" />
|
|
41
|
+
<rect
|
|
42
|
+
style="fill:#ffff00;stroke:#000000;stroke-width:0.614045"
|
|
43
|
+
id="rect2"
|
|
44
|
+
width="416.94916"
|
|
45
|
+
height="18.410578"
|
|
46
|
+
x="-24.928873"
|
|
47
|
+
y="-242.40596"
|
|
48
|
+
transform="matrix(1,0,-0.1068988,-0.99426991,0,0)" />
|
|
49
|
+
<text
|
|
50
|
+
id="station.name"
|
|
51
|
+
x="11.235578"
|
|
52
|
+
y="26.851856"
|
|
53
|
+
font-size="18"
|
|
54
|
+
font-family="serif"
|
|
55
|
+
fill="yellow"
|
|
56
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:32px;font-family:serif;-inkscape-font-specification:'serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffff00;stroke:#000000;stroke-width:1.2278;stroke-opacity:1"
|
|
57
|
+
transform="scale(0.89274878,1.1201359)">Tobermory<desc
|
|
58
|
+
id="desc1">source=resources,resource=tides,path=station.name</desc></text>
|
|
59
|
+
<text
|
|
60
|
+
id="station.name-8"
|
|
61
|
+
x="325.49939"
|
|
62
|
+
y="195.87753"
|
|
63
|
+
font-size="18"
|
|
64
|
+
font-family="serif"
|
|
65
|
+
fill="black"
|
|
66
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#999999;stroke-width:2.39571"
|
|
67
|
+
transform="scale(0.83037506,1.2042751)"><tspan
|
|
68
|
+
sodipodi:role="line"
|
|
69
|
+
id="tspan1"
|
|
70
|
+
x="325.49939"
|
|
71
|
+
y="195.87753"
|
|
72
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2.39571;fill:#999999">signalk-einklabel-plugin</tspan></text>
|
|
73
|
+
<text
|
|
74
|
+
id="station.name-8-2"
|
|
75
|
+
x="4.3477793"
|
|
76
|
+
y="201.9895"
|
|
77
|
+
font-size="18"
|
|
78
|
+
font-family="serif"
|
|
79
|
+
fill="black"
|
|
80
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:Sans;-inkscape-font-specification:'Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.19309"
|
|
81
|
+
transform="scale(0.85412558,1.170788)"><desc
|
|
82
|
+
id="desc12">source=einklabel,path=repainted,format=local_datetime_short</desc><tspan
|
|
83
|
+
sodipodi:role="line"
|
|
84
|
+
id="tspan3"
|
|
85
|
+
x="4.3477793"
|
|
86
|
+
y="201.9895"
|
|
87
|
+
style="stroke-width:1.19309;-inkscape-font-specification:'Sans, Normal';font-family:Sans;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:13.33333347px;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal">Last updated 27 Jun 26 18:05</tspan></text>
|
|
88
|
+
<text
|
|
89
|
+
id="extremes.0"
|
|
90
|
+
x="7.9661016"
|
|
91
|
+
y="60"
|
|
92
|
+
font-size="14"
|
|
93
|
+
font-family="monospace"
|
|
94
|
+
fill="black"
|
|
95
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.6667px;font-family:monospace;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000">High Water</text>
|
|
96
|
+
<text
|
|
97
|
+
id="extremes.1"
|
|
98
|
+
x="13.35283"
|
|
99
|
+
y="118.57627"
|
|
100
|
+
font-size="14"
|
|
101
|
+
font-family="monospace"
|
|
102
|
+
fill="black"
|
|
103
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.6667px;font-family:monospace;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000">Low Water</text>
|
|
104
|
+
<text
|
|
105
|
+
id="extremes.2"
|
|
106
|
+
x="7.9661016"
|
|
107
|
+
y="177.55931"
|
|
108
|
+
font-size="14"
|
|
109
|
+
font-family="monospace"
|
|
110
|
+
fill="red"
|
|
111
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.6667px;font-family:monospace;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000">High Water</text>
|
|
112
|
+
<text
|
|
113
|
+
id="environment.time.timezoneRegion"
|
|
114
|
+
x="338.47461"
|
|
115
|
+
y="17.457626"
|
|
116
|
+
font-size="12px"
|
|
117
|
+
font-family="sans-serif"
|
|
118
|
+
fill="#ffff00"
|
|
119
|
+
style="fill:#000000">UTC+01:00<desc
|
|
120
|
+
id="desc11">path=environment.time.timezoneRegion,format=utc_offset</desc></text>
|
|
121
|
+
<text
|
|
122
|
+
id="extremes.2.level"
|
|
123
|
+
x="173.64978"
|
|
124
|
+
y="199.27094"
|
|
125
|
+
font-size="14"
|
|
126
|
+
font-family="monospace"
|
|
127
|
+
fill="red"
|
|
128
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.44101"
|
|
129
|
+
transform="scale(0.95993086,1.0417417)"
|
|
130
|
+
inkscape:transform-center-x="11.578901"
|
|
131
|
+
inkscape:transform-center-y="-62.5909"><tspan
|
|
132
|
+
sodipodi:role="line"
|
|
133
|
+
id="tspan2-0"
|
|
134
|
+
x="173.64978"
|
|
135
|
+
y="199.27094"
|
|
136
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.44101">3.3m</tspan><desc
|
|
137
|
+
id="desc6">source=resources,resource=tides,path=extremes.[2].level,category=depth</desc></text>
|
|
138
|
+
<text
|
|
139
|
+
id="extremes.2.time"
|
|
140
|
+
x="31.471279"
|
|
141
|
+
y="166.20743"
|
|
142
|
+
font-size="14"
|
|
143
|
+
font-family="monospace"
|
|
144
|
+
fill="red"
|
|
145
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.31448"
|
|
146
|
+
transform="scale(0.77910527,1.2835236)">15:53<desc
|
|
147
|
+
id="desc10">source=resources,resource=tides,path=extremes.[2].time,format=local_time</desc></text>
|
|
148
|
+
<text
|
|
149
|
+
id="extremes.1.level"
|
|
150
|
+
x="182.71886"
|
|
151
|
+
y="135.3521"
|
|
152
|
+
font-size="14"
|
|
153
|
+
font-family="monospace"
|
|
154
|
+
fill="red"
|
|
155
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.40832"
|
|
156
|
+
transform="scale(0.90784041,1.1015152)"
|
|
157
|
+
inkscape:transform-center-y="-96.23206"
|
|
158
|
+
inkscape:transform-center-x="-0.00043342573"><tspan
|
|
159
|
+
sodipodi:role="line"
|
|
160
|
+
id="tspan2-1"
|
|
161
|
+
x="182.71886"
|
|
162
|
+
y="135.3521"
|
|
163
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.40832">1.6m</tspan><desc
|
|
164
|
+
id="desc5">source=resources,resource=tides,path=extremes.[1].level,category=depth</desc></text>
|
|
165
|
+
<text
|
|
166
|
+
id="extremes.1.time"
|
|
167
|
+
x="33.328102"
|
|
168
|
+
y="118.54723"
|
|
169
|
+
font-size="14"
|
|
170
|
+
font-family="monospace"
|
|
171
|
+
fill="red"
|
|
172
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.31609"
|
|
173
|
+
transform="scale(0.77081545,1.2973274)">09:36<desc
|
|
174
|
+
id="desc8">source=resources,resource=tides,path=extremes.[1].time,format=local_time</desc></text>
|
|
175
|
+
<text
|
|
176
|
+
id="extremes.0.time"
|
|
177
|
+
x="29.798925"
|
|
178
|
+
y="79.890121"
|
|
179
|
+
font-size="14"
|
|
180
|
+
font-family="monospace"
|
|
181
|
+
fill="red"
|
|
182
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.32646"
|
|
183
|
+
transform="scale(0.82428216,1.2131768)">03:27<desc
|
|
184
|
+
id="desc3">source=resources,resource=tides,path=extremes.[0].time,format=local_time</desc></text>
|
|
185
|
+
<text
|
|
186
|
+
id="extremes.0.time-8"
|
|
187
|
+
x="378.11157"
|
|
188
|
+
y="79.890121"
|
|
189
|
+
font-size="14"
|
|
190
|
+
font-family="monospace"
|
|
191
|
+
fill="red"
|
|
192
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
|
|
193
|
+
transform="scale(0.82428216,1.2131768)"><desc
|
|
194
|
+
id="desc2">source=resources,resource=tides,path=extremes.[0].time,format=day_mon</desc>27 Jun</text>
|
|
195
|
+
<text
|
|
196
|
+
id="extremes.0.time-8-5"
|
|
197
|
+
x="378.11157"
|
|
198
|
+
y="125.12273"
|
|
199
|
+
font-size="14"
|
|
200
|
+
font-family="monospace"
|
|
201
|
+
fill="red"
|
|
202
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
|
|
203
|
+
transform="scale(0.82428216,1.2131768)"><desc
|
|
204
|
+
id="desc7">source=resources,resource=tides,path=extremes.[1].time,format=day_mon</desc>27 Jun</text>
|
|
205
|
+
<text
|
|
206
|
+
id="extremes.0.time-8-9"
|
|
207
|
+
x="378.11157"
|
|
208
|
+
y="174.46791"
|
|
209
|
+
font-size="14"
|
|
210
|
+
font-family="monospace"
|
|
211
|
+
fill="red"
|
|
212
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
|
|
213
|
+
transform="scale(0.82428216,1.2131768)"><desc
|
|
214
|
+
id="desc9">source=resources,resource=tides,path=extremes.[2].time,format=day_mon</desc>27 Jun</text>
|
|
215
|
+
<text
|
|
216
|
+
id="extremes.0.level"
|
|
217
|
+
x="173.7571"
|
|
218
|
+
y="88.829666"
|
|
219
|
+
font-size="14"
|
|
220
|
+
font-family="monospace"
|
|
221
|
+
fill="red"
|
|
222
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.38653"
|
|
223
|
+
transform="scale(0.95553786,1.046531)"><tspan
|
|
224
|
+
sodipodi:role="line"
|
|
225
|
+
id="tspan2"
|
|
226
|
+
x="173.7571"
|
|
227
|
+
y="88.829666"
|
|
228
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.38653">3.4m</tspan><desc
|
|
229
|
+
id="desc4">source=resources,resource=tides,path=extremes.[0].level,category=depth</desc></text>
|
|
230
|
+
</svg>
|