@rhizomatics/signalk-einklabel-plugin 0.5.0 → 0.5.1

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 CHANGED
@@ -1,3 +1,5 @@
1
+ # 0.5.1
2
+ - Work around `resvg-wasm` font limitations by overriding generic font family with matching font name prior to rendering
1
3
  # 0.5.0
2
4
  ## Font Handling
3
5
  - Update set of built-in fonts for consistent Roboto monospace and serif
package/README.md CHANGED
@@ -81,7 +81,7 @@ These can all be combined as in `source=resources,resource=tides,path=extremes[2
81
81
 
82
82
  ### Fonts
83
83
 
84
- Three font types are loaded by default, use the exact font name 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). If a font can't be matched it will default to (sans-serif) Roboto.
84
+ Three font types are loaded by default, use the generic font family, or exact font name, 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). If a font can't be matched it will default to (sans-serif) Roboto.
85
85
 
86
86
  * `serif` - `Roboto Serif`
87
87
  * `sans-serif` - `Roboto`
@@ -151,7 +151,7 @@ Placeholder text isn't necessary, and is ignored by the plugin, but makes it muc
151
151
 
152
152
  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.
153
153
 
154
- Due to a limitation in the `resvg-wasm` library used to turn SVGs into images, the font family must match exactly one of the installed fonts - `Roboto` (sans serif), `Roboto Serif` or `Roboto Mono` rather than a generic `serif`,`sans-serif`,`monospace` font family. Inkscape has its own fonts, which won't match what's available in the SignalK plugin, so for more precise design, install [Roboto from Google](https://fonts.google.com/specimen/Roboto) via the web page, `brew` on MacOS or similar.
154
+ Due to a limitation in the `resvg-wasm` library used to turn SVGs into images, the `font-family` is limited to `serif`,`sans-serif`,`monospace` or the exact name of one of the installed fonts - `Roboto` (sans serif), `Roboto Serif` or `Roboto Mono`. Inkscape has its own fonts, which won't match what's available in the SignalK plugin, so for more precise design, install [Roboto from Google](https://fonts.google.com/specimen/Roboto) via the web page, `brew` on MacOS or similar.
155
155
 
156
156
  ### Debugging Templates
157
157
 
@@ -6,11 +6,11 @@
6
6
  * resvg-wasm does NOT route generic keywords (font-family:serif/sans-serif/monospace) to the
7
7
  * "right" loaded font by metadata - a generic keyword, or any font-family value that doesn't
8
8
  * exactly string-match a loaded font's own name, silently falls back to whichever loaded font
9
- * happens to work for the requested glyphs (in practice: array order). Templates MUST reference
10
- * each font by its exact embedded family name (e.g. `font-family:'Roboto Mono'` in the SVG's
11
- * style=, not the bare `serif`/`monospace` keyword) for resvg to actually pick it - see
12
- * templates/tide.svg and project memory. Keep this to one font per bucket rather than adding
13
- * e.g. bold variants - there's no reliable way to pick between two fonts sharing a literal name.
9
+ * happens to work for the requested glyphs (in practice: array order). Templates may still use
10
+ * the generic keywords (Inkscape's default) - svgRenderer.ts rewrites them to the matching
11
+ * literal embedded name from GENERIC_FONT_FAMILY_MAP below before resvg ever sees the SVG - see
12
+ * project memory. Keep this to one font per bucket rather than adding e.g. bold variants - there's
13
+ * no reliable way to pick between two fonts sharing a literal name.
14
14
  *
15
15
  * Must be the static (non-variable) @fontsource builds, not @fontsource-variable - every
16
16
  * @fontsource-variable/roboto-{mono,serif} subset renders zero visible glyphs under resvg-wasm
@@ -20,3 +20,11 @@
20
20
  * Mono/Serif builds used here render correctly and keep the whole set in the Roboto super-family.
21
21
  */
22
22
  export declare const DEFAULT_FONT_PATHS: string[];
23
+ /**
24
+ * Maps each CSS generic font-family keyword to the literal embedded name (nameID1) of the
25
+ * bundled font that backs it in DEFAULT_FONT_PATHS above. svgRenderer.ts rewrites every
26
+ * `font-family:sans-serif`/`serif`/`monospace` in a template to its literal name before handing
27
+ * the SVG to resvg-wasm, since resvg-wasm does not route generic keywords to a loaded font itself
28
+ * - see project memory. Keep these in sync with DEFAULT_FONT_PATHS if a bucket's font ever changes.
29
+ */
30
+ export declare const GENERIC_FONT_FAMILY_MAP: Record<string, string>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_FONT_PATHS = void 0;
3
+ exports.GENERIC_FONT_FAMILY_MAP = exports.DEFAULT_FONT_PATHS = void 0;
4
4
  /**
5
5
  * One font per CSS generic family bucket (monospace/sans-serif/serif), bundled so rendering
6
6
  * doesn't depend on the host having any fonts installed - resvg-wasm cannot see host fonts at
@@ -9,11 +9,11 @@ exports.DEFAULT_FONT_PATHS = void 0;
9
9
  * resvg-wasm does NOT route generic keywords (font-family:serif/sans-serif/monospace) to the
10
10
  * "right" loaded font by metadata - a generic keyword, or any font-family value that doesn't
11
11
  * exactly string-match a loaded font's own name, silently falls back to whichever loaded font
12
- * happens to work for the requested glyphs (in practice: array order). Templates MUST reference
13
- * each font by its exact embedded family name (e.g. `font-family:'Roboto Mono'` in the SVG's
14
- * style=, not the bare `serif`/`monospace` keyword) for resvg to actually pick it - see
15
- * templates/tide.svg and project memory. Keep this to one font per bucket rather than adding
16
- * e.g. bold variants - there's no reliable way to pick between two fonts sharing a literal name.
12
+ * happens to work for the requested glyphs (in practice: array order). Templates may still use
13
+ * the generic keywords (Inkscape's default) - svgRenderer.ts rewrites them to the matching
14
+ * literal embedded name from GENERIC_FONT_FAMILY_MAP below before resvg ever sees the SVG - see
15
+ * project memory. Keep this to one font per bucket rather than adding e.g. bold variants - there's
16
+ * no reliable way to pick between two fonts sharing a literal name.
17
17
  *
18
18
  * Must be the static (non-variable) @fontsource builds, not @fontsource-variable - every
19
19
  * @fontsource-variable/roboto-{mono,serif} subset renders zero visible glyphs under resvg-wasm
@@ -28,3 +28,15 @@ exports.DEFAULT_FONT_PATHS = [
28
28
  require.resolve('@fontsource/roboto-mono/files/roboto-mono-latin-400-normal.woff2'),
29
29
  require.resolve('@fontsource/roboto-serif/files/roboto-serif-latin-400-normal.woff2'),
30
30
  ];
31
+ /**
32
+ * Maps each CSS generic font-family keyword to the literal embedded name (nameID1) of the
33
+ * bundled font that backs it in DEFAULT_FONT_PATHS above. svgRenderer.ts rewrites every
34
+ * `font-family:sans-serif`/`serif`/`monospace` in a template to its literal name before handing
35
+ * the SVG to resvg-wasm, since resvg-wasm does not route generic keywords to a loaded font itself
36
+ * - see project memory. Keep these in sync with DEFAULT_FONT_PATHS if a bucket's font ever changes.
37
+ */
38
+ exports.GENERIC_FONT_FAMILY_MAP = {
39
+ 'sans-serif': 'Roboto',
40
+ monospace: 'Roboto Mono',
41
+ serif: 'Roboto Serif 20pt',
42
+ };
@@ -13,6 +13,27 @@ function ensureWasmInitialized() {
13
13
  }
14
14
  return wasmReady;
15
15
  }
16
+ // Only matches the CSS `font-family:` declaration inside a style="..." attribute, not the bare
17
+ // XML `font-family="..."` presentation attribute - rewriting the latter in place would require
18
+ // quote-aware handling of the surrounding XML attribute delimiter to avoid corrupting the
19
+ // document, and it's unnecessary: resvg-wasm (and any browser) prefers the style declaration
20
+ // whenever both are present, and every <text>/<tspan> in our templates sets one.
21
+ const GENERIC_FONT_FAMILY_PATTERN = /font-family\s*:\s*(['"]?)(sans-serif|serif|monospace)\1(?=\s*[;"])/g;
22
+ /**
23
+ * Rewrites CSS generic font-family keywords to the literal embedded name of the bundled font
24
+ * that backs each bucket (see GENERIC_FONT_FAMILY_MAP, ./fonts.ts), e.g. `font-family:sans-serif`
25
+ * becomes `font-family:'Roboto',sans-serif`. resvg-wasm only selects a font by exact name match -
26
+ * it does not route generic keywords to "the right" loaded font itself (see project memory) - so
27
+ * this lets templates use plain `serif`/`sans-serif`/`monospace` (as Inkscape writes by default)
28
+ * instead of every template author having to hardcode each bundled font's exact embedded name.
29
+ * The original generic keyword is kept as a trailing fallback so the rewritten value stays valid
30
+ * CSS for preview in e.g. Inkscape or a browser; it's inert as far as resvg-wasm is concerned.
31
+ */
32
+ function expandGenericFontFamilies(svgSource) {
33
+ return svgSource.replace(GENERIC_FONT_FAMILY_PATTERN, (_match, _quote, generic) => {
34
+ return `font-family:'${fonts_1.GENERIC_FONT_FAMILY_MAP[generic]}',${generic}`;
35
+ });
36
+ }
16
37
  /**
17
38
  * Renders an SVG+binding template to a common RGBA bitmap.
18
39
  *
@@ -52,7 +73,7 @@ class SvgRenderer {
52
73
  }
53
74
  async render(svgTemplatePath, context, width, height) {
54
75
  const [, fontBuffers] = await Promise.all([ensureWasmInitialized(), this.loadFontBuffers()]);
55
- const svgSource = await (0, promises_1.readFile)(svgTemplatePath, 'utf-8');
76
+ const svgSource = expandGenericFontFamilies(await (0, promises_1.readFile)(svgTemplatePath, 'utf-8'));
56
77
  const doc = new xmldom_1.DOMParser().parseFromString(svgSource, 'image/svg+xml');
57
78
  const elements = doc.getElementsByTagName('text');
58
79
  for (let i = 0; i < elements.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhizomatics/signalk-einklabel-plugin",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
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",
@@ -71,7 +71,7 @@
71
71
  font-size="18"
72
72
  font-family="serif"
73
73
  fill="yellow"
74
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Roboto Serif 20pt';-inkscape-font-specification:'Roboto Serif 20pt';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"
74
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:serif;-inkscape-font-specification:'Roboto Serif 20pt';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"
75
75
  transform="scale(0.89274878,1.1201359)">Tidal Station Name<desc
76
76
  id="desc1">source=resources,resource=tides,path=station.name</desc></text>
77
77
  <text
@@ -81,14 +81,14 @@
81
81
  font-size="18"
82
82
  font-family="serif"
83
83
  fill="black"
84
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:'Roboto';-inkscape-font-specification:'Roboto',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000;stroke-width:3.80045"
84
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:sans-serif;-inkscape-font-specification:'Roboto',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000;stroke-width:3.80045"
85
85
  transform="scale(0.95907863,1.0426674)"><desc
86
86
  id="desc21">source=resources,resource=tides,path=station.source.name</desc><tspan
87
87
  sodipodi:role="line"
88
88
  id="tspan20"
89
89
  x="347.95166"
90
90
  y="226.1548"
91
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3332995px;font-family:'Roboto';-inkscape-font-specification:'Roboto',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:3.80045">SOURCE</tspan></text>
91
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3332995px;font-family:sans-serif;-inkscape-font-specification:'Roboto',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:3.80045">SOURCE</tspan></text>
92
92
  <text
93
93
  id="last_repaint"
94
94
  x="4.3477793"
@@ -96,7 +96,7 @@
96
96
  font-size="18"
97
97
  font-family="serif"
98
98
  fill="black"
99
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:'Roboto';-inkscape-font-specification:'Roboto',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.19309"
99
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:sans-serif;-inkscape-font-specification:'Roboto',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.19309"
100
100
  transform="scale(0.85412558,1.170788)"><desc
101
101
  id="desc12">source=einklabel,path=repainted,format=local_datetime_short</desc><tspan
102
102
  sodipodi:role="line"
@@ -108,7 +108,7 @@
108
108
  font-size="14"
109
109
  font-family="monospace"
110
110
  fill="black"
111
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000"><desc
111
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000"><desc
112
112
  id="desc13">source=resources,resource=tides,path=extremes[0].label</desc>High or Low</text>
113
113
  <text
114
114
  id="extremes.1"
@@ -117,7 +117,7 @@
117
117
  font-size="14"
118
118
  font-family="monospace"
119
119
  fill="black"
120
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000"><desc
120
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000"><desc
121
121
  id="desc14">source=resources,resource=tides,path=extremes[1].label</desc>High or Low</text>
122
122
  <text
123
123
  id="extremes.2"
@@ -126,7 +126,7 @@
126
126
  font-size="14"
127
127
  font-family="monospace"
128
128
  fill="red"
129
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000"><desc
129
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ff0000"><desc
130
130
  id="desc15">source=resources,resource=tides,path=extremes[2].label</desc>High or Low</text>
131
131
  <text
132
132
  id="environment.time.timezoneRegion"
@@ -135,7 +135,7 @@
135
135
  font-size="10.373px"
136
136
  font-family="sans-serif"
137
137
  fill="#ffff00"
138
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;direction:rtl;fill:#000000;stroke-width:0.864419"
138
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;direction:rtl;fill:#000000;stroke-width:0.864419"
139
139
  transform="scale(0.86441854,1.156847)">UTC+01:00<desc
140
140
  id="desc11">source=einklabel,path=local_zone</desc></text>
141
141
  <text
@@ -145,7 +145,7 @@
145
145
  font-size="12px"
146
146
  font-family="sans-serif"
147
147
  fill="#ffff00"
148
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.3333px;font-family:Roboto;-inkscape-font-specification:'\'Roboto, Normal\', sans-serif';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#1a1a1a;stroke:#fefe54;stroke-opacity:1"><desc
148
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.3333px;font-family:sans-serif;-inkscape-font-specification:'\'Roboto, Normal\', sans-serif';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#1a1a1a;stroke:#fefe54;stroke-opacity:1"><desc
149
149
  id="desc18">source=resources,resource=tides,path=station.datums.LAT,category=depth,round=1</desc><tspan
150
150
  sodipodi:role="line"
151
151
  id="tspan17"
@@ -158,7 +158,7 @@
158
158
  font-size="12px"
159
159
  font-family="sans-serif"
160
160
  fill="#ffff00"
161
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.3333px;font-family:Roboto;-inkscape-font-specification:'\'Roboto, Normal\', sans-serif';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#1a1a1a;stroke:#fefe54;stroke-opacity:1"><desc
161
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.3333px;font-family:sans-serif;-inkscape-font-specification:'\'Roboto, Normal\', sans-serif';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#1a1a1a;stroke:#fefe54;stroke-opacity:1"><desc
162
162
  id="desc19">source=resources,resource=tides,path=station.datums.HAT,category=depth,round=1</desc><tspan
163
163
  sodipodi:role="line"
164
164
  id="tspan18"
@@ -171,7 +171,7 @@
171
171
  font-size="14"
172
172
  font-family="monospace"
173
173
  fill="red"
174
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.78893"
174
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.78893"
175
175
  transform="scale(0.7732368,1.2932649)"
176
176
  inkscape:transform-center-x="11.578953"
177
177
  inkscape:transform-center-y="-96.464172"><tspan
@@ -179,7 +179,7 @@
179
179
  id="tspan2-0"
180
180
  x="334.61356"
181
181
  y="159.19211"
182
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;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
182
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;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
183
183
  id="desc6">source=resources,resource=tides,path=extremes[2].level,category=depth</desc></text>
184
184
  <text
185
185
  id="extremes.2.time"
@@ -188,7 +188,7 @@
188
188
  font-size="14"
189
189
  font-family="monospace"
190
190
  fill="red"
191
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.51352"
191
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.51352"
192
192
  transform="scale(0.70226239,1.4239692)">15:53<desc
193
193
  id="desc10">source=resources,resource=tides,path=extremes[2].time,format=local_time</desc></text>
194
194
  <text
@@ -198,7 +198,7 @@
198
198
  font-size="14"
199
199
  font-family="monospace"
200
200
  fill="red"
201
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.701"
201
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.701"
202
202
  transform="scale(0.75163533,1.3304324)"
203
203
  inkscape:transform-center-y="-140.38618"
204
204
  inkscape:transform-center-x="-0.00038058817"><tspan
@@ -206,7 +206,7 @@
206
206
  id="tspan2-1"
207
207
  x="341.23608"
208
208
  y="110.25762"
209
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;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
209
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;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
210
210
  id="desc5">source=resources,resource=tides,path=extremes[1].level,category=depth</desc></text>
211
211
  <text
212
212
  id="extremes.1.time"
@@ -215,7 +215,7 @@
215
215
  font-size="14"
216
216
  font-family="monospace"
217
217
  fill="red"
218
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.48364"
218
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.48364"
219
219
  transform="scale(0.7345432,1.3613903)">09:36<desc
220
220
  id="desc8">source=resources,resource=tides,path=extremes[1].time,format=local_time</desc></text>
221
221
  <text
@@ -225,7 +225,7 @@
225
225
  font-size="14"
226
226
  font-family="monospace"
227
227
  fill="red"
228
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.55397"
228
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.55397"
229
229
  transform="scale(0.74654856,1.3394976)">03:27<desc
230
230
  id="desc3">source=resources,resource=tides,path=extremes[0].time,format=local_time</desc></text>
231
231
  <text
@@ -235,7 +235,7 @@
235
235
  font-size="14"
236
236
  font-family="monospace"
237
237
  fill="red"
238
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
238
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
239
239
  transform="scale(0.82428216,1.2131768)"><desc
240
240
  id="desc2">source=resources,resource=tides,path=extremes[0].time,format=day_mon</desc>27 Jun</text>
241
241
  <text
@@ -245,7 +245,7 @@
245
245
  font-size="14"
246
246
  font-family="monospace"
247
247
  fill="red"
248
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
248
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.32646"
249
249
  transform="scale(0.82428216,1.2131768)"><desc
250
250
  id="desc7">source=resources,resource=tides,path=extremes[1].time,format=day_mon</desc>27 Jun</text>
251
251
  <text
@@ -255,7 +255,7 @@
255
255
  font-size="14"
256
256
  font-family="monospace"
257
257
  fill="red"
258
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:Roboto;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.4652"
258
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:22.6667px;font-family:sans-serif;-inkscape-font-specification:'Roboto, Normal',sans-serif;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.4652"
259
259
  transform="scale(0.74623156,1.3400666)"><desc
260
260
  id="desc9">source=resources,resource=tides,path=extremes[2].time,format=day_mon</desc>27 Jun</text>
261
261
  <text
@@ -265,17 +265,17 @@
265
265
  font-size="14"
266
266
  font-family="monospace"
267
267
  fill="red"
268
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.71992"
268
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;stroke-width:1.71992"
269
269
  transform="scale(0.7703174,1.2981662)"><tspan
270
270
  sodipodi:role="line"
271
271
  id="tspan2"
272
272
  x="334.47769"
273
273
  y="65.931427"
274
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:'Roboto Mono';-inkscape-font-specification:'Roboto Mono, Bold',monospaced;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
274
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:37.3333px;font-family:monospace;-inkscape-font-specification:'Roboto Mono, Bold',monospace;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
275
275
  id="desc4">source=resources,resource=tides,path=extremes[0].level,category=depth</desc></text>
276
276
  <text
277
277
  xml:space="preserve"
278
- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.3333px;font-family:Roboto;-inkscape-font-specification:'\'Roboto, Normal\', sans-serif';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#1a1a1a;stroke:#fefe54;stroke-width:0.612283;stroke-opacity:1"
278
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:21.3333px;font-family:sans-serif;-inkscape-font-specification:'\'Roboto, Normal\', sans-serif';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#1a1a1a;stroke:#fefe54;stroke-width:0.612283;stroke-opacity:1"
279
279
  x="340.84946"
280
280
  y="25.168207"
281
281
  id="text19"><tspan