@rhizomatics/signalk-einklabel-plugin 0.4.2 → 0.4.4
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 +7 -0
- package/README.md +5 -2
- package/dist/cli/liveContext.js +2 -1
- package/dist/render/binding.d.ts +1 -1
- package/dist/render/binding.js +1 -1
- package/dist/render/formatters.d.ts +10 -0
- package/dist/render/formatters.js +36 -12
- package/dist/render/svgRenderer.d.ts +1 -1
- package/dist/render/svgRenderer.js +1 -1
- package/dist/repaintScheduler.js +5 -1
- package/docs/assets/screenshots/example_tidal_clock.png +0 -0
- package/package.json +5 -4
- package/templates/tide.svg +126 -75
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# 0.4.4
|
|
2
|
+
- Update `node-ble` to new packaging
|
|
3
|
+
# 0.4.3
|
|
4
|
+
- Fixed datetime values when running from plugin were blank while CLI was fine
|
|
5
|
+
- Added an example Resources API output from signalk-tides plugin
|
|
6
|
+
- Relaid out the example tide clock, adding the tidal range (LAT to HAT) and the source of tide data
|
|
7
|
+
- Alternative source of time zone info, `source=einklabel,path=local_zone`
|
|
1
8
|
# 0.4.2
|
|
2
9
|
- Fix High/Low display for tide clock template
|
|
3
10
|
- Fix last repaint time for display being hour out
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
** BETA - basic functionality, limited vendor/product support **
|
|
4
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.
|
|
5
|
+
A SignalK plugin to display data from SignalK paths, APIs and plugins on Electronic Shelf Labels over a Bluetooth Low Energy (BLE) connection using simple SVG templates.
|
|
6
6
|
|
|
7
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
8
|
|
|
@@ -36,7 +36,10 @@ The source can be overridden to use the SignalK server's Resources API instead.
|
|
|
36
36
|
|
|
37
37
|
#### Plugin Data
|
|
38
38
|
|
|
39
|
-
`source=einklabel` reads data injected by the plugin itself, rather than from SignalK.
|
|
39
|
+
`source=einklabel` reads data injected by the plugin itself, rather than from SignalK. Available paths:
|
|
40
|
+
|
|
41
|
+
* `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.
|
|
42
|
+
* `path=local_zone` - a short zone name (e.g. `BST`) for the same timezone used for `local_time`/`day_mon`/`local_datetime_short` (see above) - a fallback for `environment.time.timezoneRegion,format=utc_offset` on installs that never publish that path, since it needs no SignalK metadata of its own. Falls back to a plain UTC offset like `GMT+1` where the host's locale has no real abbreviation for the zone.
|
|
40
43
|
|
|
41
44
|
#### Customizing Output
|
|
42
45
|
|
package/dist/cli/liveContext.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.assembleLiveContext = assembleLiveContext;
|
|
4
|
+
const formatters_1 = require("../render/formatters");
|
|
4
5
|
const httpJson_1 = require("../httpJson");
|
|
5
6
|
const unitCategories_1 = require("../unitCategories");
|
|
6
7
|
const pathMeta_1 = require("../pathMeta");
|
|
@@ -71,6 +72,6 @@ async function assembleLiveContext(signalkUrl, bindings) {
|
|
|
71
72
|
const categories = await (0, unitCategories_1.fetchCategoryDisplayUnits)(signalkUrl, categoryNames);
|
|
72
73
|
// Matches `considerRepaint` in repaintScheduler.ts - the CLI has no real device repaint to time, so
|
|
73
74
|
// a `source=einklabel,path=repainted` binding just resolves to "now", same as a live render would.
|
|
74
|
-
const meta = { repainted: new Date().toISOString() };
|
|
75
|
+
const meta = { repainted: new Date().toISOString(), local_zone: (0, formatters_1.resolveLocalZoneAbbreviation)({ signalk }) };
|
|
75
76
|
return { signalk, resources, pathMeta, categories, meta };
|
|
76
77
|
}
|
package/dist/render/binding.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface Binding {
|
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Parses a `<desc>` element's text content into a `Binding`, e.g.
|
|
23
|
-
* `source=resources,resource=tides,path=extremes
|
|
23
|
+
* `source=resources,resource=tides,path=extremes[0].level,category=depth,round=2` or, using the
|
|
24
24
|
* defaults (`source=signalk,context=self`), plain `path=navigation.speedOverGround` (auto-converts via
|
|
25
25
|
* that path's own metadata - see `renderBinding`). A bare path with no `key=value` pairs at all, e.g.
|
|
26
26
|
* `environment.forecast.description`, is shorthand for `path=environment.forecast.description`
|
package/dist/render/binding.js
CHANGED
|
@@ -10,7 +10,7 @@ const SOURCES = ['signalk', 'resources', 'einklabel'];
|
|
|
10
10
|
const KNOWN_KEYS = new Set(['source', 'context', 'resource', 'path', 'format', 'category', 'round']);
|
|
11
11
|
/**
|
|
12
12
|
* Parses a `<desc>` element's text content into a `Binding`, e.g.
|
|
13
|
-
* `source=resources,resource=tides,path=extremes
|
|
13
|
+
* `source=resources,resource=tides,path=extremes[0].level,category=depth,round=2` or, using the
|
|
14
14
|
* defaults (`source=signalk,context=self`), plain `path=navigation.speedOverGround` (auto-converts via
|
|
15
15
|
* that path's own metadata - see `renderBinding`). A bare path with no `key=value` pairs at all, e.g.
|
|
16
16
|
* `environment.forecast.description`, is shorthand for `path=environment.forecast.description`
|
|
@@ -14,5 +14,15 @@ export interface DisplayUnits {
|
|
|
14
14
|
}
|
|
15
15
|
/** Converts a base-SI value (always what SignalK paths deliver) to its metadata's preferred display unit and formats it with the unit's symbol, e.g. 3.42 -> "11.2ft". */
|
|
16
16
|
export declare function formatDisplayUnits(value: number, displayUnits: DisplayUnits, round: number | undefined): string;
|
|
17
|
+
/**
|
|
18
|
+
* Short zone name (e.g. "BST", or "GMT+1" where the host's own `Intl` locale has no real abbreviation
|
|
19
|
+
* for the zone) for the same zone `selfTimezone` resolves - an alternative for
|
|
20
|
+
* `environment.time.timezoneRegion,format=utc_offset` on installs that never publish that path (see
|
|
21
|
+
* `selfTimezone`'s own comment). Uses the host's default locale rather than pinning one, so it shows
|
|
22
|
+
* whatever `Intl` would show the host's own user - "GMT+1" is an acceptable fallback where that locale
|
|
23
|
+
* doesn't have a 3-letter abbreviation to offer. Resolved as a `source=einklabel,path=local_zone`
|
|
24
|
+
* binding (see `considerRepaint`).
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveLocalZoneAbbreviation(context: TemplateContext): string;
|
|
17
27
|
/** Applies a named `format=` formatter to a resolved binding value. */
|
|
18
28
|
export declare function applyFormat(name: string, value: unknown, context: TemplateContext, round: number | undefined): string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatDisplayUnits = formatDisplayUnits;
|
|
4
|
+
exports.resolveLocalZoneAbbreviation = resolveLocalZoneAbbreviation;
|
|
4
5
|
exports.applyFormat = applyFormat;
|
|
5
6
|
const luxon_1 = require("luxon");
|
|
6
7
|
const mathjs_1 = require("mathjs");
|
|
@@ -26,30 +27,53 @@ function selfTimezone(context) {
|
|
|
26
27
|
const environment = self?.environment;
|
|
27
28
|
return environment?.time?.timezoneRegion || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
28
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Short zone name (e.g. "BST", or "GMT+1" where the host's own `Intl` locale has no real abbreviation
|
|
32
|
+
* for the zone) for the same zone `selfTimezone` resolves - an alternative for
|
|
33
|
+
* `environment.time.timezoneRegion,format=utc_offset` on installs that never publish that path (see
|
|
34
|
+
* `selfTimezone`'s own comment). Uses the host's default locale rather than pinning one, so it shows
|
|
35
|
+
* whatever `Intl` would show the host's own user - "GMT+1" is an acceptable fallback where that locale
|
|
36
|
+
* doesn't have a 3-letter abbreviation to offer. Resolved as a `source=einklabel,path=local_zone`
|
|
37
|
+
* binding (see `considerRepaint`).
|
|
38
|
+
*/
|
|
39
|
+
function resolveLocalZoneAbbreviation(context) {
|
|
40
|
+
const part = new Intl.DateTimeFormat(undefined, { timeZone: selfTimezone(context), timeZoneName: 'short' })
|
|
41
|
+
.formatToParts(new Date())
|
|
42
|
+
.find((p) => p.type === 'timeZoneName');
|
|
43
|
+
return part?.value ?? '';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A `resources`-sourced timestamp can arrive as either an ISO string (always true over HTTP, since
|
|
47
|
+
* `JSON.stringify` converts a `Date` to its ISO string automatically) or a live `Date` instance (an
|
|
48
|
+
* in-process `app.resourcesApi` call skips that serialisation step entirely, so a provider that hasn't
|
|
49
|
+
* itself called `.toISOString()` yet hands back the raw object) - accept both so the live plugin and
|
|
50
|
+
* the CLI render identically regardless of which path a binding's data took.
|
|
51
|
+
*/
|
|
52
|
+
function parseTimestamp(value) {
|
|
53
|
+
if (value instanceof Date)
|
|
54
|
+
return luxon_1.DateTime.fromJSDate(value, { zone: 'utc' });
|
|
55
|
+
if (typeof value === 'string')
|
|
56
|
+
return luxon_1.DateTime.fromISO(value, { zone: 'utc' });
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
29
59
|
/**
|
|
30
60
|
* Shows the explicit IANA zone name rather than an abbreviation (e.g. "BST") - UK tide tables are
|
|
31
61
|
* officially published in GMT, so the basis for the displayed time must be unambiguous rather than
|
|
32
62
|
* just locally styled.
|
|
33
63
|
*/
|
|
34
64
|
function formatLocalTime(value, context) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const dt = luxon_1.DateTime.fromISO(value, { zone: 'utc' }).setZone(selfTimezone(context));
|
|
38
|
-
return dt.isValid ? dt.toFormat('HH:mm') : '';
|
|
65
|
+
const dt = parseTimestamp(value)?.setZone(selfTimezone(context));
|
|
66
|
+
return dt?.isValid ? dt.toFormat('HH:mm') : '';
|
|
39
67
|
}
|
|
40
68
|
/** e.g. "27 Jun" - day of month (no leading zero) and abbreviated month name, in the local vessel's timezone. */
|
|
41
69
|
function formatDayMonth(value, context) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const dt = luxon_1.DateTime.fromISO(value, { zone: 'utc' }).setZone(selfTimezone(context));
|
|
45
|
-
return dt.isValid ? dt.toFormat('d MMM') : '';
|
|
70
|
+
const dt = parseTimestamp(value)?.setZone(selfTimezone(context));
|
|
71
|
+
return dt?.isValid ? dt.toFormat('d MMM') : '';
|
|
46
72
|
}
|
|
47
73
|
/** e.g. "21 Jun 26 18:05" - day of month (no leading zero), abbreviated month, 2-digit year, and 24h time, in the local vessel's timezone. */
|
|
48
74
|
function formatLocalDatetimeShort(value, context) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const dt = luxon_1.DateTime.fromISO(value, { zone: 'utc' }).setZone(selfTimezone(context));
|
|
52
|
-
return dt.isValid ? dt.toFormat('d MMM yy HH:mm') : '';
|
|
75
|
+
const dt = parseTimestamp(value)?.setZone(selfTimezone(context));
|
|
76
|
+
return dt?.isValid ? dt.toFormat('d MMM yy HH:mm') : '';
|
|
53
77
|
}
|
|
54
78
|
/**
|
|
55
79
|
* IANA region names are ambiguous about DST (e.g. "Europe/London" is UTC+00:00 in winter, UTC+01:00
|
|
@@ -5,7 +5,7 @@ import { Bitmap, Renderer, TemplateContext } from './types';
|
|
|
5
5
|
* Binding model: a `<text>` element with a `<desc>` child has that child's
|
|
6
6
|
* content parsed as a flat `key=value,key=value` binding against the render
|
|
7
7
|
* context and substituted in as the element's text, e.g.
|
|
8
|
-
* `<desc>source=resources,resource=tides,path=extremes
|
|
8
|
+
* `<desc>source=resources,resource=tides,path=extremes[0].time,format=local_time</desc>`
|
|
9
9
|
* (see `./binding.ts` for the grammar and `./formatters.ts` for the `format=` registry).
|
|
10
10
|
* The `<text>` element's own visible content is left untouched in the source
|
|
11
11
|
* file - it's just a placeholder so the template looks sane while laying it
|
|
@@ -19,7 +19,7 @@ function ensureWasmInitialized() {
|
|
|
19
19
|
* Binding model: a `<text>` element with a `<desc>` child has that child's
|
|
20
20
|
* content parsed as a flat `key=value,key=value` binding against the render
|
|
21
21
|
* context and substituted in as the element's text, e.g.
|
|
22
|
-
* `<desc>source=resources,resource=tides,path=extremes
|
|
22
|
+
* `<desc>source=resources,resource=tides,path=extremes[0].time,format=local_time</desc>`
|
|
23
23
|
* (see `./binding.ts` for the grammar and `./formatters.ts` for the `format=` registry).
|
|
24
24
|
* The `<text>` element's own visible content is left untouched in the source
|
|
25
25
|
* file - it's just a placeholder so the template looks sane while laying it
|
package/dist/repaintScheduler.js
CHANGED
|
@@ -9,6 +9,7 @@ const bleDiscovery_1 = require("./devices/bleDiscovery");
|
|
|
9
9
|
const registry_1 = require("./devices/registry");
|
|
10
10
|
const svgRenderer_1 = require("./render/svgRenderer");
|
|
11
11
|
const binding_1 = require("./render/binding");
|
|
12
|
+
const formatters_1 = require("./render/formatters");
|
|
12
13
|
const unitCategories_1 = require("./unitCategories");
|
|
13
14
|
const pathMeta_1 = require("./pathMeta");
|
|
14
15
|
const resolveApiUrl_1 = require("./resolveApiUrl");
|
|
@@ -136,7 +137,10 @@ async function considerRepaint(app, config, device, state, getApiUrl) {
|
|
|
136
137
|
app.debug(`"${device.friendlyName}": data unchanged, skipping repaint`);
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
|
-
const renderContext = {
|
|
140
|
+
const renderContext = {
|
|
141
|
+
...rawContext,
|
|
142
|
+
meta: { repainted: new Date().toISOString(), local_zone: (0, formatters_1.resolveLocalZoneAbbreviation)(rawContext) },
|
|
143
|
+
};
|
|
140
144
|
const renderer = new svgRenderer_1.SvgRenderer();
|
|
141
145
|
const bitmap = await renderer.render(templatePath, renderContext, metadata.width, metadata.height - metadata.voffset);
|
|
142
146
|
const connectTimeoutMs = config.paintConnectTimeoutSeconds * 1000;
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rhizomatics/signalk-einklabel-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "SignalK plugin that renders selected SignalK data to eInk Electronic Shelf Labels",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"test": "node --require ts-node/register --test \"src/**/*.test.ts\"",
|
|
22
22
|
"prepublishOnly": "npm run build"
|
|
23
23
|
},
|
|
24
|
-
"signalk":{
|
|
25
|
-
"displayName":"eInk Label Instruments",
|
|
24
|
+
"signalk": {
|
|
25
|
+
"displayName": "eInk Label Instruments",
|
|
26
26
|
"appIcon": "docs/assets/icons/icon_tmp.png",
|
|
27
27
|
"screenshots": [
|
|
28
28
|
"docs/assets/screenshots/example_tidal_clock.png"
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"luxon": "^3.7.2",
|
|
53
53
|
"mathjs": "^15.2.0",
|
|
54
54
|
"node-ble": "^1.13.0",
|
|
55
|
-
"pngjs": "^7.0.0"
|
|
55
|
+
"pngjs": "^7.0.0",
|
|
56
|
+
"form-data":"^4.0.6"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@signalk/server-api": "^2.28.0",
|
package/templates/tide.svg
CHANGED
|
@@ -22,15 +22,33 @@
|
|
|
22
22
|
inkscape:pageopacity="0.0"
|
|
23
23
|
inkscape:pagecheckerboard="0"
|
|
24
24
|
inkscape:deskcolor="#d1d1d1"
|
|
25
|
-
inkscape:zoom="
|
|
26
|
-
inkscape:cx="
|
|
27
|
-
inkscape:cy="
|
|
25
|
+
inkscape:zoom="1.3906433"
|
|
26
|
+
inkscape:cx="202.4243"
|
|
27
|
+
inkscape:cy="151.36879"
|
|
28
28
|
inkscape:window-width="1488"
|
|
29
29
|
inkscape:window-height="674"
|
|
30
30
|
inkscape:window-x="0"
|
|
31
31
|
inkscape:window-y="33"
|
|
32
32
|
inkscape:window-maximized="0"
|
|
33
|
-
inkscape:current-layer="svg1"
|
|
33
|
+
inkscape:current-layer="svg1"
|
|
34
|
+
showgrid="true">
|
|
35
|
+
<inkscape:grid
|
|
36
|
+
id="grid1"
|
|
37
|
+
units="px"
|
|
38
|
+
originx="0"
|
|
39
|
+
originy="0"
|
|
40
|
+
spacingx="1"
|
|
41
|
+
spacingy="1"
|
|
42
|
+
empcolor="#0099e5"
|
|
43
|
+
empopacity="0.30196078"
|
|
44
|
+
color="#0099e5"
|
|
45
|
+
opacity="0.14901961"
|
|
46
|
+
empspacing="5"
|
|
47
|
+
dotted="false"
|
|
48
|
+
gridanglex="30"
|
|
49
|
+
gridanglez="30"
|
|
50
|
+
visible="true" />
|
|
51
|
+
</sodipodi:namedview>
|
|
34
52
|
<rect
|
|
35
53
|
x="1.0169492"
|
|
36
54
|
y="2.0798673e-08"
|
|
@@ -58,18 +76,16 @@
|
|
|
58
76
|
id="desc1">source=resources,resource=tides,path=station.name</desc></text>
|
|
59
77
|
<text
|
|
60
78
|
id="station.name-8"
|
|
61
|
-
x="
|
|
62
|
-
y="
|
|
79
|
+
x="440.67529"
|
|
80
|
+
y="196.47466"
|
|
63
81
|
font-size="18"
|
|
64
82
|
font-family="serif"
|
|
65
83
|
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:#
|
|
67
|
-
transform="scale(0.83037506,1.2042751)"><
|
|
84
|
+
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:#ff0000;stroke-width:2.39571"
|
|
85
|
+
transform="scale(0.83037506,1.2042751)"><desc
|
|
86
|
+
id="desc21">source=resources,resource=tides,path=station.source.name</desc><tspan
|
|
68
87
|
sodipodi:role="line"
|
|
69
|
-
id="
|
|
70
|
-
x="325.49939"
|
|
71
|
-
y="195.87753"
|
|
72
|
-
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.99999995px;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:#ffffff">signalk-einklabel-plugin</tspan></text>
|
|
88
|
+
id="tspan20">SOURCE</tspan></text>
|
|
73
89
|
<text
|
|
74
90
|
id="last_repaint"
|
|
75
91
|
x="4.3477793"
|
|
@@ -90,7 +106,7 @@
|
|
|
90
106
|
font-family="monospace"
|
|
91
107
|
fill="black"
|
|
92
108
|
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"><desc
|
|
93
|
-
id="desc13">source=resources,resource=tides,path=extremes
|
|
109
|
+
id="desc13">source=resources,resource=tides,path=extremes[0].label</desc>High</text>
|
|
94
110
|
<text
|
|
95
111
|
id="extremes.1"
|
|
96
112
|
x="13.35283"
|
|
@@ -99,7 +115,7 @@
|
|
|
99
115
|
font-family="monospace"
|
|
100
116
|
fill="black"
|
|
101
117
|
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"><desc
|
|
102
|
-
id="desc14">source=resources,resource=tides,path=extremes
|
|
118
|
+
id="desc14">source=resources,resource=tides,path=extremes[1].label</desc>Low</text>
|
|
103
119
|
<text
|
|
104
120
|
id="extremes.2"
|
|
105
121
|
x="7.9661016"
|
|
@@ -108,123 +124,158 @@
|
|
|
108
124
|
font-family="monospace"
|
|
109
125
|
fill="red"
|
|
110
126
|
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"><desc
|
|
111
|
-
id="desc15">source=resources,resource=tides,path=extremes
|
|
127
|
+
id="desc15">source=resources,resource=tides,path=extremes[2].label</desc>High</text>
|
|
112
128
|
<text
|
|
113
129
|
id="environment.time.timezoneRegion"
|
|
114
|
-
x="
|
|
115
|
-
y="
|
|
130
|
+
x="440.41293"
|
|
131
|
+
y="11.361118"
|
|
132
|
+
font-size="10.373px"
|
|
133
|
+
font-family="sans-serif"
|
|
134
|
+
fill="#ffff00"
|
|
135
|
+
style="direction:rtl;fill:#000000;stroke-width:0.864419"
|
|
136
|
+
transform="scale(0.86441854,1.156847)">UTC+01:00<desc
|
|
137
|
+
id="desc11">source=einklabel,path=local_zone</desc></text>
|
|
138
|
+
<text
|
|
139
|
+
id="lat"
|
|
140
|
+
x="175.5096"
|
|
141
|
+
y="30.720407"
|
|
142
|
+
font-size="12px"
|
|
143
|
+
font-family="sans-serif"
|
|
144
|
+
fill="#ffff00"
|
|
145
|
+
style="fill:#ffff00;-inkscape-font-specification:'Sans, Normal';font-family:Sans;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:18.6667px;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke:#a6a6a6;stroke-opacity:1"><desc
|
|
146
|
+
id="desc18">source=resources,resource=tides,path=station.datums.LAT,category=depth</desc><tspan
|
|
147
|
+
sodipodi:role="line"
|
|
148
|
+
id="tspan17">0.1m</tspan></text>
|
|
149
|
+
<text
|
|
150
|
+
id="hat"
|
|
151
|
+
x="264.41321"
|
|
152
|
+
y="30.800503"
|
|
116
153
|
font-size="12px"
|
|
117
154
|
font-family="sans-serif"
|
|
118
155
|
fill="#ffff00"
|
|
119
|
-
style="fill:#
|
|
120
|
-
|
|
156
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.6667px;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:#ffff00;stroke:#acacaa;stroke-opacity:1"><desc
|
|
157
|
+
id="desc19">source=resources,resource=tides,path=station.datums.HAT,category=depth</desc><tspan
|
|
158
|
+
sodipodi:role="line"
|
|
159
|
+
id="tspan18"
|
|
160
|
+
x="264.41321"
|
|
161
|
+
y="30.800503">6.0m</tspan></text>
|
|
121
162
|
<text
|
|
122
163
|
id="extremes.2.level"
|
|
123
|
-
x="
|
|
124
|
-
y="
|
|
164
|
+
x="335.54352"
|
|
165
|
+
y="168.08856"
|
|
125
166
|
font-size="14"
|
|
126
167
|
font-family="monospace"
|
|
127
168
|
fill="red"
|
|
128
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
129
|
-
transform="scale(0.
|
|
130
|
-
inkscape:transform-center-x="11.
|
|
131
|
-
inkscape:transform-center-y="-
|
|
169
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.78893"
|
|
170
|
+
transform="scale(0.7732368,1.2932649)"
|
|
171
|
+
inkscape:transform-center-x="11.578953"
|
|
172
|
+
inkscape:transform-center-y="-96.464172"><tspan
|
|
132
173
|
sodipodi:role="line"
|
|
133
174
|
id="tspan2-0"
|
|
134
|
-
x="
|
|
135
|
-
y="
|
|
136
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
137
|
-
id="desc6">source=resources,resource=tides,path=extremes
|
|
175
|
+
x="335.54352"
|
|
176
|
+
y="168.08856"
|
|
177
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.78893">3.3m</tspan><desc
|
|
178
|
+
id="desc6">source=resources,resource=tides,path=extremes[2].level,category=depth</desc></text>
|
|
138
179
|
<text
|
|
139
180
|
id="extremes.2.time"
|
|
140
|
-
x="
|
|
141
|
-
y="
|
|
181
|
+
x="164.78383"
|
|
182
|
+
y="154.23825"
|
|
142
183
|
font-size="14"
|
|
143
184
|
font-family="monospace"
|
|
144
185
|
fill="red"
|
|
145
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
146
|
-
transform="scale(0.
|
|
147
|
-
id="desc10">source=resources,resource=tides,path=extremes
|
|
186
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333281px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.51352"
|
|
187
|
+
transform="scale(0.7022624,1.4239692)">15:53<desc
|
|
188
|
+
id="desc10">source=resources,resource=tides,path=extremes[2].time,format=local_time</desc></text>
|
|
148
189
|
<text
|
|
149
190
|
id="extremes.1.level"
|
|
150
|
-
x="
|
|
151
|
-
y="
|
|
191
|
+
x="345.0629"
|
|
192
|
+
y="118.90553"
|
|
152
193
|
font-size="14"
|
|
153
194
|
font-family="monospace"
|
|
154
195
|
fill="red"
|
|
155
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
156
|
-
transform="scale(0.
|
|
157
|
-
inkscape:transform-center-y="-
|
|
158
|
-
inkscape:transform-center-x="-0.
|
|
196
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.701"
|
|
197
|
+
transform="scale(0.75163533,1.3304324)"
|
|
198
|
+
inkscape:transform-center-y="-140.38618"
|
|
199
|
+
inkscape:transform-center-x="-0.00038058817"><tspan
|
|
159
200
|
sodipodi:role="line"
|
|
160
201
|
id="tspan2-1"
|
|
161
|
-
x="
|
|
162
|
-
y="
|
|
163
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
164
|
-
id="desc5">source=resources,resource=tides,path=extremes
|
|
202
|
+
x="345.0629"
|
|
203
|
+
y="118.90553"
|
|
204
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.701">1.6m</tspan><desc
|
|
205
|
+
id="desc5">source=resources,resource=tides,path=extremes[1].level,category=depth</desc></text>
|
|
165
206
|
<text
|
|
166
207
|
id="extremes.1.time"
|
|
167
|
-
x="
|
|
168
|
-
y="
|
|
208
|
+
x="161.1239"
|
|
209
|
+
y="115.52532"
|
|
169
210
|
font-size="14"
|
|
170
211
|
font-family="monospace"
|
|
171
212
|
fill="red"
|
|
172
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
173
|
-
transform="scale(0.
|
|
174
|
-
id="desc8">source=resources,resource=tides,path=extremes
|
|
213
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333356px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.48364"
|
|
214
|
+
transform="scale(0.7345432,1.3613903)">09:36<desc
|
|
215
|
+
id="desc8">source=resources,resource=tides,path=extremes[1].time,format=local_time</desc></text>
|
|
175
216
|
<text
|
|
176
217
|
id="extremes.0.time"
|
|
177
|
-
x="
|
|
178
|
-
y="
|
|
218
|
+
x="156.47511"
|
|
219
|
+
y="73.368919"
|
|
179
220
|
font-size="14"
|
|
180
221
|
font-family="monospace"
|
|
181
222
|
fill="red"
|
|
182
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
183
|
-
transform="scale(0.
|
|
184
|
-
id="desc3">source=resources,resource=tides,path=extremes
|
|
223
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333325px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.55397"
|
|
224
|
+
transform="scale(0.74654856,1.3394976)">03:27<desc
|
|
225
|
+
id="desc3">source=resources,resource=tides,path=extremes[0].time,format=local_time</desc></text>
|
|
185
226
|
<text
|
|
186
227
|
id="extremes.0.time-8"
|
|
187
|
-
x="
|
|
188
|
-
y="
|
|
228
|
+
x="10.326324"
|
|
229
|
+
y="77.594147"
|
|
189
230
|
font-size="14"
|
|
190
231
|
font-family="monospace"
|
|
191
232
|
fill="red"
|
|
192
|
-
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:
|
|
233
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.6667px;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
234
|
transform="scale(0.82428216,1.2131768)"><desc
|
|
194
|
-
id="desc2">source=resources,resource=tides,path=extremes
|
|
235
|
+
id="desc2">source=resources,resource=tides,path=extremes[0].time,format=day_mon</desc>27 Jun</text>
|
|
195
236
|
<text
|
|
196
237
|
id="extremes.0.time-8-5"
|
|
197
|
-
x="
|
|
198
|
-
y="
|
|
238
|
+
x="10.83737"
|
|
239
|
+
y="126.90092"
|
|
199
240
|
font-size="14"
|
|
200
241
|
font-family="monospace"
|
|
201
242
|
fill="red"
|
|
202
|
-
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:
|
|
243
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.6667px;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
244
|
transform="scale(0.82428216,1.2131768)"><desc
|
|
204
|
-
id="desc7">source=resources,resource=tides,path=extremes
|
|
245
|
+
id="desc7">source=resources,resource=tides,path=extremes[1].time,format=day_mon</desc>27 Jun</text>
|
|
205
246
|
<text
|
|
206
247
|
id="extremes.0.time-8-9"
|
|
207
|
-
x="
|
|
208
|
-
y="
|
|
248
|
+
x="12.934491"
|
|
249
|
+
y="161.07082"
|
|
209
250
|
font-size="14"
|
|
210
251
|
font-family="monospace"
|
|
211
252
|
fill="red"
|
|
212
|
-
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:
|
|
213
|
-
transform="scale(0.
|
|
214
|
-
id="desc9">source=resources,resource=tides,path=extremes
|
|
253
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.6667px;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.4652"
|
|
254
|
+
transform="scale(0.74623156,1.3400666)"><desc
|
|
255
|
+
id="desc9">source=resources,resource=tides,path=extremes[2].time,format=day_mon</desc>27 Jun</text>
|
|
215
256
|
<text
|
|
216
257
|
id="extremes.0.level"
|
|
217
|
-
x="
|
|
218
|
-
y="
|
|
258
|
+
x="336.3447"
|
|
259
|
+
y="76.456078"
|
|
219
260
|
font-size="14"
|
|
220
261
|
font-family="monospace"
|
|
221
262
|
fill="red"
|
|
222
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
223
|
-
transform="scale(0.
|
|
263
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.71992"
|
|
264
|
+
transform="scale(0.7703174,1.2981662)"><tspan
|
|
224
265
|
sodipodi:role="line"
|
|
225
266
|
id="tspan2"
|
|
226
|
-
x="
|
|
227
|
-
y="
|
|
228
|
-
style="font-style:normal;font-variant:normal;font-weight:
|
|
229
|
-
id="desc4">source=resources,resource=tides,path=extremes
|
|
267
|
+
x="336.3447"
|
|
268
|
+
y="76.456078"
|
|
269
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.33333333px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.71992">3.4m</tspan><desc
|
|
270
|
+
id="desc4">source=resources,resource=tides,path=extremes[0].level,category=depth</desc></text>
|
|
271
|
+
<text
|
|
272
|
+
xml:space="preserve"
|
|
273
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.6667px;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:#ffff00;stroke:#acacaa;stroke-width:0.612283;stroke-opacity:1"
|
|
274
|
+
x="232.26662"
|
|
275
|
+
y="30.201849"
|
|
276
|
+
id="text19"><tspan
|
|
277
|
+
sodipodi:role="line"
|
|
278
|
+
id="tspan19"
|
|
279
|
+
x="232.26662"
|
|
280
|
+
y="30.201849">-></tspan></text>
|
|
230
281
|
</svg>
|