signalk-livedepth-plugin 0.1.0 → 0.2.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/README.md +3 -1
- package/dist/collector.d.ts +4 -1
- package/dist/collector.d.ts.map +1 -1
- package/dist/collector.js +2 -2
- package/dist/collector.js.map +1 -1
- package/dist/config.d.ts +15 -74
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +17 -104
- package/dist/config.js.map +1 -1
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +59 -2
- package/dist/plugin.js.map +1 -1
- package/dist/streams/live.d.ts +4 -2
- package/dist/streams/live.d.ts.map +1 -1
- package/dist/streams/live.js +15 -14
- package/dist/streams/live.js.map +1 -1
- package/dist/tiles/api.d.ts +1 -1
- package/dist/tiles/api.d.ts.map +1 -1
- package/dist/tiles/api.js +7 -2
- package/dist/tiles/api.js.map +1 -1
- package/dist/tiles/index.d.ts +1 -2
- package/dist/tiles/index.d.ts.map +1 -1
- package/dist/tiles/index.js +1 -2
- package/dist/tiles/index.js.map +1 -1
- package/dist/tiles/seed.d.ts +4 -2
- package/dist/tiles/seed.d.ts.map +1 -1
- package/dist/tiles/seed.js +23 -7
- package/dist/tiles/seed.js.map +1 -1
- package/dist/tiles/store.d.ts +1 -23
- package/dist/tiles/store.d.ts.map +1 -1
- package/dist/tiles/store.js +4 -1
- package/dist/tiles/store.js.map +1 -1
- package/dist/tiles/writer.d.ts +1 -1
- package/dist/tiles/writer.d.ts.map +1 -1
- package/dist/tiles/writer.js +6 -3
- package/dist/tiles/writer.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@ layer. It is the server side of Freeboard-SK's LiveDepth layer.
|
|
|
11
11
|
base level `z20` (≈0.15 m per cell), min-pooled down to `z4` (≈2.4 km per
|
|
12
12
|
cell). A tile is stored sparsely — only the cells a sounding fell in — as a
|
|
13
13
|
5-byte record (`cx, cy, depthCm, count`) keeping the shallowest depth, so
|
|
14
|
-
zooming out never deepens a shoal.
|
|
14
|
+
zooming out never deepens a shoal. The tile algorithm itself lives in
|
|
15
|
+
[`signalk-livedepth-tiles`](https://www.npmjs.com/package/signalk-livedepth-tiles),
|
|
16
|
+
shared with the chart client so both build identical tiles.
|
|
15
17
|
- Serves the tiles over HTTP so a chart client can draw a depth surface for the
|
|
16
18
|
area without replaying the raw track or interpolating at query time.
|
|
17
19
|
- Can seed the store from the server's History API at the finest granularity it
|
package/dist/collector.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Writable } from "stream";
|
|
2
2
|
import { ServerAPI } from "@signalk/server-api";
|
|
3
|
+
import { TransducerOffset } from "signalk-livedepth-tiles";
|
|
3
4
|
import { Config } from "./config.js";
|
|
4
5
|
export interface CollectorOptions {
|
|
5
6
|
app: ServerAPI;
|
|
6
7
|
config: Config;
|
|
7
8
|
/** The tile writer fed the live soundings. */
|
|
8
9
|
writer: Writable;
|
|
10
|
+
/** Shift each sounding from the reported position to the transducer. */
|
|
11
|
+
offset?: TransducerOffset;
|
|
9
12
|
signal: AbortSignal;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* Pair depth with position once and feed the soundings to the tile writer.
|
|
13
16
|
*/
|
|
14
|
-
export declare function createCollector({ app, config, writer, signal, }: CollectorOptions): import("stream-transform").Transformer;
|
|
17
|
+
export declare function createCollector({ app, config, writer, offset, signal, }: CollectorOptions): import("stream-transform").Transformer;
|
|
15
18
|
//# sourceMappingURL=collector.d.ts.map
|
package/dist/collector.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,0CAkBlB"}
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,CAAC;IACjB,wEAAwE;IACxE,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,0CAkBlB"}
|
package/dist/collector.js
CHANGED
|
@@ -3,8 +3,8 @@ import { createLiveStream, toPrecision } from "./streams/index.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Pair depth with position once and feed the soundings to the tile writer.
|
|
5
5
|
*/
|
|
6
|
-
export function createCollector({ app, config, writer, signal, }) {
|
|
7
|
-
const live = createLiveStream(app, config);
|
|
6
|
+
export function createCollector({ app, config, writer, offset, signal, }) {
|
|
7
|
+
const live = createLiveStream(app, config, offset);
|
|
8
8
|
const precise = live.pipe(transform(toPrecision()));
|
|
9
9
|
precise.pipe(writer);
|
|
10
10
|
const destroy = () => {
|
package/dist/collector.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAK7C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAYnE;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,EACN,MAAM,GACW;IACjB,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAErB,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC,CAAC;IAEF,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,42 +1,23 @@
|
|
|
1
1
|
import { ServerAPI } from "@signalk/server-api";
|
|
2
2
|
export type Config = {
|
|
3
|
+
/** Which depth datum to record. Signal K already publishes each relative to
|
|
4
|
+
* its own reference, so the value is stored as-is. */
|
|
3
5
|
path: (typeof DepthPaths)[number];
|
|
6
|
+
/** The depth transducer's position on the hull: `y` from the bow, `x` from
|
|
7
|
+
* the centreline (+starboard). Used only to place a sounding at the
|
|
8
|
+
* transducer rather than at the position the server reports. */
|
|
4
9
|
sounder: {
|
|
5
10
|
x: number;
|
|
6
11
|
y: number;
|
|
7
|
-
z: number;
|
|
8
|
-
draft?: number;
|
|
9
|
-
make?: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
frequency?: number;
|
|
12
|
-
transducer?: string;
|
|
13
|
-
source?: string;
|
|
14
|
-
};
|
|
15
|
-
gnss: {
|
|
16
|
-
x: number;
|
|
17
|
-
y: number;
|
|
18
|
-
z: number;
|
|
19
|
-
make?: string;
|
|
20
|
-
model?: string;
|
|
21
|
-
source?: string;
|
|
22
12
|
};
|
|
13
|
+
/** Shift soundings from the vessel reference point the server reports to the
|
|
14
|
+
* transducer. `off` leaves them where the server put them. */
|
|
15
|
+
transducerCorrection: "off" | "replace";
|
|
23
16
|
seed?: {
|
|
24
17
|
run?: boolean;
|
|
25
18
|
resolution?: number;
|
|
26
19
|
};
|
|
27
20
|
};
|
|
28
|
-
/**
|
|
29
|
-
* The source Signal K currently prioritizes for a path (its `$source`) plus the
|
|
30
|
-
* full list of sources that have reported it. Used to default and populate the
|
|
31
|
-
* source selectors so soundings stay pinned to one sensor rather than mixing
|
|
32
|
-
* antenna offsets from multiple GPS sources.
|
|
33
|
-
*/
|
|
34
|
-
export declare function sourcesFor(app: ServerAPI, path: string): {
|
|
35
|
-
selected: string | undefined;
|
|
36
|
-
available: string[];
|
|
37
|
-
};
|
|
38
|
-
/** Configured source if set, else the server's prioritized source, else undefined. */
|
|
39
|
-
export declare function resolveSource(app: ServerAPI, configured: string | undefined, path: string): string | undefined;
|
|
40
21
|
export declare const DepthPaths: readonly ["belowSurface", "belowTransducer", "belowKeel"];
|
|
41
22
|
export declare function schema(app: ServerAPI): {
|
|
42
23
|
type: string;
|
|
@@ -47,21 +28,15 @@ export declare function schema(app: ServerAPI): {
|
|
|
47
28
|
title: string;
|
|
48
29
|
description: string;
|
|
49
30
|
enum: readonly ["belowSurface", "belowTransducer", "belowKeel"];
|
|
31
|
+
enumNames: string[];
|
|
50
32
|
default: "belowKeel" | "belowSurface" | "belowTransducer" | undefined;
|
|
51
33
|
};
|
|
52
34
|
sounder: {
|
|
53
35
|
type: string;
|
|
54
36
|
title: string;
|
|
37
|
+
description: string;
|
|
55
38
|
required: string[];
|
|
56
39
|
properties: {
|
|
57
|
-
source: {
|
|
58
|
-
type: string;
|
|
59
|
-
title: string;
|
|
60
|
-
enum: string[];
|
|
61
|
-
enumNames: string[];
|
|
62
|
-
default: string | undefined;
|
|
63
|
-
description: string;
|
|
64
|
-
};
|
|
65
40
|
y: {
|
|
66
41
|
type: string;
|
|
67
42
|
title: string;
|
|
@@ -74,49 +49,15 @@ export declare function schema(app: ServerAPI): {
|
|
|
74
49
|
description: string;
|
|
75
50
|
default: unknown;
|
|
76
51
|
};
|
|
77
|
-
z: {
|
|
78
|
-
type: string;
|
|
79
|
-
title: string;
|
|
80
|
-
default: unknown;
|
|
81
|
-
};
|
|
82
|
-
draft: {
|
|
83
|
-
type: string;
|
|
84
|
-
title: string;
|
|
85
|
-
description: string;
|
|
86
|
-
default: unknown;
|
|
87
|
-
};
|
|
88
52
|
};
|
|
89
53
|
};
|
|
90
|
-
|
|
54
|
+
transducerCorrection: {
|
|
91
55
|
type: string;
|
|
92
56
|
title: string;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
title: string;
|
|
98
|
-
enum: string[];
|
|
99
|
-
enumNames: string[];
|
|
100
|
-
default: string | undefined;
|
|
101
|
-
description: string;
|
|
102
|
-
};
|
|
103
|
-
y: {
|
|
104
|
-
type: string;
|
|
105
|
-
title: string;
|
|
106
|
-
minimum: number;
|
|
107
|
-
default: unknown;
|
|
108
|
-
};
|
|
109
|
-
x: {
|
|
110
|
-
type: string;
|
|
111
|
-
title: string;
|
|
112
|
-
description: string;
|
|
113
|
-
default: unknown;
|
|
114
|
-
};
|
|
115
|
-
z: {
|
|
116
|
-
type: string;
|
|
117
|
-
title: string;
|
|
118
|
-
};
|
|
119
|
-
};
|
|
57
|
+
description: string;
|
|
58
|
+
enum: string[];
|
|
59
|
+
enumNames: string[];
|
|
60
|
+
default: string;
|
|
120
61
|
};
|
|
121
62
|
seed: {
|
|
122
63
|
type: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE;QACP,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,MAAM,GAAG;IACnB;0DACsD;IACtD,IAAI,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IAClC;;oEAEgE;IAChE,OAAO,EAAE;QACP,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;KACX,CAAC;IACF;kEAC8D;IAC9D,oBAAoB,EAAE,KAAK,GAAG,SAAS,CAAC;IACxC,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,UAAU,YACrB,cAAc,EACd,iBAAiB,EACjB,WAAW,CACH,CAAC;AAEX,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS;IAKjC,IAAI;IACJ,WAAW;IAEX,UAAU;QACR,IAAI;YACF,IAAI;YACJ,KAAK;YACL,WAAW;YAEX,IAAI;YACJ,SAAS;YAKT,OAAO;;QAET,OAAO;YACL,IAAI;YACJ,KAAK;YACL,WAAW;YAEX,QAAQ;YACR,UAAU;gBACR,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,OAAO;oBACP,OAAO;;gBAET,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,WAAW;oBACX,OAAO;;;;QAIb,oBAAoB;YAClB,IAAI;YACJ,KAAK;YACL,WAAW;YAEX,IAAI;YACJ,SAAS;YACT,OAAO;;QAET,IAAI;YACF,IAAI;YACJ,KAAK;YACL,WAAW;YAEX,UAAU;gBACR,GAAG;oBACD,IAAI;oBACJ,OAAO;oBACP,KAAK;oBACL,WAAW;;gBAGb,UAAU;oBACR,IAAI;oBACJ,OAAO;oBACP,KAAK;oBACL,WAAW;;;;;EAOtB"}
|
package/dist/config.js
CHANGED
|
@@ -1,64 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The source Signal K currently prioritizes for a path (its `$source`) plus the
|
|
3
|
-
* full list of sources that have reported it. Used to default and populate the
|
|
4
|
-
* source selectors so soundings stay pinned to one sensor rather than mixing
|
|
5
|
-
* antenna offsets from multiple GPS sources.
|
|
6
|
-
*/
|
|
7
|
-
export function sourcesFor(app, path) {
|
|
8
|
-
const node = app.getSelfPath(path);
|
|
9
|
-
const selected = node?.$source;
|
|
10
|
-
// Multi-source paths carry a `values` map keyed by sourceRef; single-source
|
|
11
|
-
// paths have none, so fall back to the active `$source`. Either way, make sure
|
|
12
|
-
// the active source is in the list.
|
|
13
|
-
const available = node?.values ? Object.keys(node.values) : [];
|
|
14
|
-
if (selected && !available.includes(selected))
|
|
15
|
-
available.unshift(selected);
|
|
16
|
-
return { selected, available };
|
|
17
|
-
}
|
|
18
|
-
/** Configured source if set, else the server's prioritized source, else undefined. */
|
|
19
|
-
export function resolveSource(app, configured, path) {
|
|
20
|
-
return configured || sourcesFor(app, path).selected;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* A friendly label for a sourceRef, e.g. "Airmar DST200 (PICAN-M.35)", built
|
|
24
|
-
* from the NMEA 2000 device info Signal K keeps under `sources`. Falls back to
|
|
25
|
-
* the raw sourceRef when no device details are known.
|
|
26
|
-
*/
|
|
27
|
-
function sourceLabel(app, sourceRef) {
|
|
28
|
-
const dot = sourceRef.indexOf(".");
|
|
29
|
-
const label = dot === -1 ? sourceRef : sourceRef.slice(0, dot);
|
|
30
|
-
const instance = dot === -1 ? "" : sourceRef.slice(dot + 1);
|
|
31
|
-
const sources = app.getPath("sources");
|
|
32
|
-
const connection = sources?.[label];
|
|
33
|
-
// The sources tree keys devices by numeric bus address, but with
|
|
34
|
-
// useCanName the sourceRef carries the hex CAN name instead, so fall
|
|
35
|
-
// back to matching each device's n2k.canName (mirrors the admin UI's
|
|
36
|
-
// getDeviceInfo in signalk-server's sourceLabels.ts).
|
|
37
|
-
const n2k = connection?.[instance]?.n2k ??
|
|
38
|
-
Object.values(connection ?? {}).find((device) => device?.n2k?.canName === instance)?.n2k;
|
|
39
|
-
const name = [n2k?.manufacturerCode, n2k?.modelId]
|
|
40
|
-
.filter((p) => typeof p === "string" && p.length > 0)
|
|
41
|
-
.join(" ");
|
|
42
|
-
return name ? `${name} (${sourceRef})` : sourceRef;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Schema for a source selector. Always an enum, with friendly device names via
|
|
46
|
-
* enumNames. When nothing has reported the path yet the enum is empty and the
|
|
47
|
-
* description warns that no data is available so the empty dropdown isn't a
|
|
48
|
-
* mystery.
|
|
49
|
-
*/
|
|
50
|
-
function sourceSchema(app, title, noun, sources) {
|
|
51
|
-
return {
|
|
52
|
-
type: "string",
|
|
53
|
-
title,
|
|
54
|
-
enum: sources.available,
|
|
55
|
-
enumNames: sources.available.map((source) => sourceLabel(app, source)),
|
|
56
|
-
default: sources.selected,
|
|
57
|
-
description: sources.available.length
|
|
58
|
-
? `The ${noun} source to record. Defaults to the source Signal K prioritizes; choose one when the vessel has more than one.`
|
|
59
|
-
: `No ${noun} data available — reload this page once it is being received.`,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
1
|
export const DepthPaths = [
|
|
63
2
|
"belowSurface",
|
|
64
3
|
"belowTransducer",
|
|
@@ -66,27 +5,28 @@ export const DepthPaths = [
|
|
|
66
5
|
];
|
|
67
6
|
export function schema(app) {
|
|
68
7
|
const defaultPath = DepthPaths.find((path) => app.getSelfPath(`environment.depth.${path}.value`));
|
|
69
|
-
const positionSources = sourcesFor(app, "navigation.position");
|
|
70
|
-
const depthSources = defaultPath
|
|
71
|
-
? sourcesFor(app, `environment.depth.${defaultPath}`)
|
|
72
|
-
: { selected: undefined, available: [] };
|
|
73
8
|
return {
|
|
74
9
|
type: "object",
|
|
75
10
|
description: "Build a gridded bathymetry tile store from the vessel's own position and depth, and serve it to a chart client's LiveDepth layer.",
|
|
76
11
|
properties: {
|
|
77
12
|
path: {
|
|
78
13
|
type: "string",
|
|
79
|
-
title: "
|
|
80
|
-
description: "
|
|
14
|
+
title: "Depth",
|
|
15
|
+
description: "Which depth datum to record. Signal K publishes each relative to its own reference, so no draft or transducer offset is needed here.",
|
|
81
16
|
enum: DepthPaths,
|
|
17
|
+
enumNames: [
|
|
18
|
+
"Depth below surface",
|
|
19
|
+
"Depth below transducer",
|
|
20
|
+
"Depth below keel",
|
|
21
|
+
],
|
|
82
22
|
default: defaultPath,
|
|
83
23
|
},
|
|
84
24
|
sounder: {
|
|
85
25
|
type: "object",
|
|
86
|
-
title: "Depth
|
|
87
|
-
|
|
26
|
+
title: "Depth Transducer",
|
|
27
|
+
description: "Where the transducer sits on the hull, so a sounding is placed at it rather than at the position the server reports.",
|
|
28
|
+
required: ["x", "y"],
|
|
88
29
|
properties: {
|
|
89
|
-
source: sourceSchema(app, "Depth source", "depth", depthSources),
|
|
90
30
|
y: {
|
|
91
31
|
type: "number",
|
|
92
32
|
title: "Distance of the transducer from the bow (meters)",
|
|
@@ -99,42 +39,15 @@ export function schema(app) {
|
|
|
99
39
|
description: "+ve to starboard, -ve to port",
|
|
100
40
|
default: app.getSelfPath("sensors.depth.fromCenter.value"),
|
|
101
41
|
},
|
|
102
|
-
z: {
|
|
103
|
-
type: "number",
|
|
104
|
-
title: "Distance of the transducer below the waterline (meters)",
|
|
105
|
-
default: app.getSelfPath("environment.depth.surfaceToTransducer.value"),
|
|
106
|
-
},
|
|
107
|
-
draft: {
|
|
108
|
-
type: "number",
|
|
109
|
-
title: "Draft",
|
|
110
|
-
description: "The draft of the vessel in meters.",
|
|
111
|
-
default: app.getSelfPath("design.draft.value"),
|
|
112
|
-
},
|
|
113
42
|
},
|
|
114
43
|
},
|
|
115
|
-
|
|
116
|
-
type: "
|
|
117
|
-
title: "
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
type: "number",
|
|
123
|
-
title: "Distance of the antenna from the bow (meters)",
|
|
124
|
-
minimum: 0,
|
|
125
|
-
default: app.getSelfPath("sensors.gps.fromBow.value"),
|
|
126
|
-
},
|
|
127
|
-
x: {
|
|
128
|
-
type: "number",
|
|
129
|
-
title: "Distance of the antenna from the center (meters)",
|
|
130
|
-
description: "+ve to starboard, -ve to port",
|
|
131
|
-
default: app.getSelfPath("sensors.gps.fromCenter.value"),
|
|
132
|
-
},
|
|
133
|
-
z: {
|
|
134
|
-
type: "number",
|
|
135
|
-
title: "Distance of the antenna above the waterline (meters)",
|
|
136
|
-
},
|
|
137
|
-
},
|
|
44
|
+
transducerCorrection: {
|
|
45
|
+
type: "string",
|
|
46
|
+
title: "Transducer position correction",
|
|
47
|
+
description: "Shift each sounding from the vessel reference point the server reports to the transducer. This is only meaningful when the server's own GNSS correction is on (Server → Settings → Vessel → GNSS correction): otherwise the position is the GNSS antenna, not the vessel reference point, and the offset is applied from the wrong place.",
|
|
48
|
+
enum: ["off", "replace"],
|
|
49
|
+
enumNames: ["Off", "Replace with the transducer's position"],
|
|
50
|
+
default: "off",
|
|
138
51
|
},
|
|
139
52
|
seed: {
|
|
140
53
|
type: "object",
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAsBA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,cAAc;IACd,iBAAiB;IACjB,WAAW;CACH,CAAC;AAEX,MAAM,UAAU,MAAM,CAAC,GAAc;IACnC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC3C,GAAG,CAAC,WAAW,CAAC,qBAAqB,IAAI,QAAQ,CAAC,CACnD,CAAC;IACF,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,WAAW,EACT,mIAAmI;QACrI,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,OAAO;gBACd,WAAW,EACT,sIAAsI;gBACxI,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE;oBACT,qBAAqB;oBACrB,wBAAwB;oBACxB,kBAAkB;iBACnB;gBACD,OAAO,EAAE,WAAW;aACrB;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,kBAAkB;gBACzB,WAAW,EACT,sHAAsH;gBACxH,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;gBACpB,UAAU,EAAE;oBACV,CAAC,EAAE;wBACD,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,kDAAkD;wBACzD,OAAO,EAAE,CAAC;wBACV,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,6BAA6B,CAAC;qBACxD;oBACD,CAAC,EAAE;wBACD,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,qDAAqD;wBAC5D,WAAW,EAAE,+BAA+B;wBAC5C,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,gCAAgC,CAAC;qBAC3D;iBACF;aACF;YACD,oBAAoB,EAAE;gBACpB,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,gCAAgC;gBACvC,WAAW,EACT,2UAA2U;gBAC7U,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC;gBACxB,SAAS,EAAE,CAAC,KAAK,EAAE,wCAAwC,CAAC;gBAC5D,OAAO,EAAE,KAAK;aACf;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,sBAAsB;gBAC7B,WAAW,EACT,iQAAiQ;gBACnQ,UAAU,EAAE;oBACV,GAAG,EAAE;wBACH,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,+CAA+C;wBACtD,WAAW,EACT,wGAAwG;qBAC3G;oBACD,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,OAAO,EAAE,GAAG;wBACZ,KAAK,EAAE,8BAA8B;wBACrC,WAAW,EACT,kGAAkG;qBACrG;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import { ServerAPI, Plugin } from "@signalk/server-api";
|
|
2
|
+
/** The vessel's length overall, for locating the reference point the server
|
|
3
|
+
* reports (the CCRP is midships).
|
|
4
|
+
*
|
|
5
|
+
* `design.length` is a compound-value node — `{ value: { overall, hull,
|
|
6
|
+
* waterline } }` — not a leaf, and `getSelfPath` is a `lodash.get` over the raw
|
|
7
|
+
* self model, so `design.length.overall` resolves to nothing. Read the node and
|
|
8
|
+
* take `.value.overall` (matching how the server's own GNSS corrector reads it).
|
|
9
|
+
* Handles `getSelfPath` returning either the value or its node. */
|
|
10
|
+
export declare function readLengthOverall(app: ServerAPI): number | undefined;
|
|
2
11
|
export default function createPlugin(app: ServerAPI): Plugin;
|
|
3
12
|
//# sourceMappingURL=plugin.d.ts.map
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAgB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAgB,MAAM,qBAAqB,CAAC;AActE;;;;;;;mEAOmE;AACnE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAWpE;AA+CD,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAwG3D"}
|
package/dist/plugin.js
CHANGED
|
@@ -5,12 +5,67 @@ import { createTileWriter } from "./tiles/writer.js";
|
|
|
5
5
|
import { seedFromHistory } from "./tiles/seed.js";
|
|
6
6
|
import { registerBathymetryRoutes, } from "./tiles/api.js";
|
|
7
7
|
import { createCollector } from "./collector.js";
|
|
8
|
+
/** The vessel's length overall, for locating the reference point the server
|
|
9
|
+
* reports (the CCRP is midships).
|
|
10
|
+
*
|
|
11
|
+
* `design.length` is a compound-value node — `{ value: { overall, hull,
|
|
12
|
+
* waterline } }` — not a leaf, and `getSelfPath` is a `lodash.get` over the raw
|
|
13
|
+
* self model, so `design.length.overall` resolves to nothing. Read the node and
|
|
14
|
+
* take `.value.overall` (matching how the server's own GNSS corrector reads it).
|
|
15
|
+
* Handles `getSelfPath` returning either the value or its node. */
|
|
16
|
+
export function readLengthOverall(app) {
|
|
17
|
+
const node = app.getSelfPath("design.length");
|
|
18
|
+
const value = typeof node === "number" ? node : node?.value;
|
|
19
|
+
const overall = typeof value === "number"
|
|
20
|
+
? value
|
|
21
|
+
: value?.overall;
|
|
22
|
+
return typeof overall === "number" && Number.isFinite(overall) && overall > 0
|
|
23
|
+
? overall
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
/** The server's GNSS antenna correction mode; `off` unless configured. */
|
|
27
|
+
function readGnssCorrection(app) {
|
|
28
|
+
// @ts-expect-error: app.config is not a public API
|
|
29
|
+
return app.config?.settings?.gnssCorrection ?? "off";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The body-frame offset from the reference point the server reports to the
|
|
33
|
+
* transducer, or undefined when correction is off (or can't be located).
|
|
34
|
+
*
|
|
35
|
+
* The server corrects `navigation.position` to the CCRP (midships on the
|
|
36
|
+
* centreline) only when its own `gnssCorrection` is on. When it is off the
|
|
37
|
+
* position is the GNSS antenna, whose body position we do not know — so the
|
|
38
|
+
* offset is meaningless. We still apply what the user configured, but flag it.
|
|
39
|
+
*/
|
|
40
|
+
function resolveTransducerOffset(app, config) {
|
|
41
|
+
if (config.transducerCorrection !== "replace") {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
if (readGnssCorrection(app) === "off") {
|
|
45
|
+
app.setPluginError("Transducer correction is on but the server's GNSS correction is off, so " +
|
|
46
|
+
"the position is the GNSS antenna, not the vessel reference point the " +
|
|
47
|
+
"offset is measured from. Enable GNSS correction (Server → Settings → " +
|
|
48
|
+
"Vessel) or turn this off.");
|
|
49
|
+
}
|
|
50
|
+
const length = readLengthOverall(app);
|
|
51
|
+
if (length === undefined) {
|
|
52
|
+
app.setPluginError("Transducer correction needs the vessel's length overall " +
|
|
53
|
+
"(design.length.overall) to locate the reference point; soundings are " +
|
|
54
|
+
"left where the server reports them.");
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
forward: (config.sounder?.y ?? 0) - length / 2,
|
|
59
|
+
starboard: config.sounder?.x ?? 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
8
62
|
export default function createPlugin(app) {
|
|
9
63
|
let abortController = undefined;
|
|
10
64
|
// The gridded store served to chart clients. Built in start(), read by the
|
|
11
65
|
// routes registered in registerWithRouter().
|
|
12
66
|
let tileStore;
|
|
13
67
|
let config;
|
|
68
|
+
let transducer;
|
|
14
69
|
let seedStatus = { running: false };
|
|
15
70
|
const runSeed = async (resolution) => {
|
|
16
71
|
if (seedStatus.running)
|
|
@@ -27,6 +82,7 @@ export default function createPlugin(app) {
|
|
|
27
82
|
store,
|
|
28
83
|
config: cfg,
|
|
29
84
|
resolution,
|
|
85
|
+
offset: transducer,
|
|
30
86
|
signal: abortController?.signal,
|
|
31
87
|
onProgress: (p) => {
|
|
32
88
|
seedStatus = { running: !p.done, progress: p };
|
|
@@ -51,10 +107,12 @@ export default function createPlugin(app) {
|
|
|
51
107
|
app.debug("Starting signalk-livedepth-plugin");
|
|
52
108
|
abortController = new AbortController();
|
|
53
109
|
tileStore = createTileStore(createTileDB(join(app.getDataDirPath(), `bathymetry-tiles.sqlite`)));
|
|
110
|
+
transducer = resolveTransducerOffset(app, config);
|
|
54
111
|
createCollector({
|
|
55
112
|
app,
|
|
56
113
|
config,
|
|
57
114
|
writer: createTileWriter(tileStore),
|
|
115
|
+
offset: transducer,
|
|
58
116
|
signal: abortController.signal,
|
|
59
117
|
});
|
|
60
118
|
app.setPluginStatus("Collecting depth into the bathymetry tile store");
|
|
@@ -79,8 +137,7 @@ export default function createPlugin(app) {
|
|
|
79
137
|
registerWithRouter(router) {
|
|
80
138
|
registerBathymetryRoutes(router, () => tileStore, () => ({
|
|
81
139
|
depthPath: config ? `environment.depth.${config.path}` : undefined,
|
|
82
|
-
|
|
83
|
-
gnss: config?.gnss,
|
|
140
|
+
transducer,
|
|
84
141
|
}), seed);
|
|
85
142
|
},
|
|
86
143
|
};
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/streams/live.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ServerAPI } from "@signalk/server-api";
|
|
2
2
|
import { PassThrough } from "stream";
|
|
3
|
+
import { TransducerOffset } from "signalk-livedepth-tiles";
|
|
3
4
|
import { Config } from "../config.js";
|
|
4
5
|
/**
|
|
5
6
|
* Subscribe to the vessel's own depth and pair each sounding with the last
|
|
6
|
-
* position fix, emitting `BathymetryData` objects.
|
|
7
|
+
* position fix, emitting `BathymetryData` objects. When `offset` is given, the
|
|
8
|
+
* position is shifted from the vessel reference point to the transducer.
|
|
7
9
|
*/
|
|
8
|
-
export declare function createLiveStream(app: ServerAPI, config: Config): PassThrough;
|
|
10
|
+
export declare function createLiveStream(app: ServerAPI, config: Config, offset?: TransducerOffset): PassThrough;
|
|
9
11
|
//# sourceMappingURL=live.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/streams/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/streams/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAuB,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,gBAAgB,eAyE1B"}
|
package/dist/streams/live.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import { PassThrough } from "stream";
|
|
2
|
+
import { correctToTransducer } from "signalk-livedepth-tiles";
|
|
2
3
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
4
|
/** Maximum age of last position fix for a depth to be saved */
|
|
4
5
|
const ttl = 2000;
|
|
5
6
|
/**
|
|
6
7
|
* Subscribe to the vessel's own depth and pair each sounding with the last
|
|
7
|
-
* position fix, emitting `BathymetryData` objects.
|
|
8
|
+
* position fix, emitting `BathymetryData` objects. When `offset` is given, the
|
|
9
|
+
* position is shifted from the vessel reference point to the transducer.
|
|
8
10
|
*/
|
|
9
|
-
export function createLiveStream(app, config) {
|
|
11
|
+
export function createLiveStream(app, config, offset) {
|
|
10
12
|
const path = `environment.depth.${config.path}`;
|
|
11
|
-
let offset = 0;
|
|
12
|
-
if (config.path === "belowTransducer")
|
|
13
|
-
offset += config.sounder?.z ?? 0;
|
|
14
|
-
if (config.path === "belowKeel")
|
|
15
|
-
offset += config.sounder?.draft ?? 0;
|
|
16
13
|
app.debug(`Collecting depth data from environment.depth.${path}`);
|
|
17
14
|
const unsubscribes = [];
|
|
18
15
|
const stream = new PassThrough({ objectMode: true });
|
|
@@ -31,7 +28,6 @@ export function createLiveStream(app, config) {
|
|
|
31
28
|
update.values.forEach(({ value }) => {
|
|
32
29
|
if (!value)
|
|
33
30
|
return;
|
|
34
|
-
const depth = value + offset;
|
|
35
31
|
if (!position)
|
|
36
32
|
return app.debug("No position data, ignoring depth data");
|
|
37
33
|
if (isStale(position, timestamp, ttl))
|
|
@@ -40,14 +36,19 @@ export function createLiveStream(app, config) {
|
|
|
40
36
|
app.debug("Stale heading data, discarding");
|
|
41
37
|
heading = undefined;
|
|
42
38
|
}
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
const { lon, lat } = offset
|
|
40
|
+
? correctToTransducer({
|
|
41
|
+
lon: position.value.longitude,
|
|
42
|
+
lat: position.value.latitude,
|
|
43
|
+
}, heading?.value, offset)
|
|
44
|
+
: { lon: position.value.longitude, lat: position.value.latitude };
|
|
45
|
+
stream.push({
|
|
46
|
+
longitude: lon,
|
|
47
|
+
latitude: lat,
|
|
48
|
+
depth: value,
|
|
47
49
|
timestamp,
|
|
48
50
|
heading: heading?.value,
|
|
49
|
-
};
|
|
50
|
-
stream.push(data);
|
|
51
|
+
});
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
});
|
package/dist/streams/live.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/streams/live.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/streams/live.ts"],"names":[],"mappings":"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"}
|
package/dist/tiles/api.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PluginRouter } from "@signalk/server-api";
|
|
2
|
+
import { TileStore } from "signalk-livedepth-tiles";
|
|
2
3
|
import { SeedProgress } from "./seed.js";
|
|
3
|
-
import { TileStore } from "./store.js";
|
|
4
4
|
/** Wire format of a `/bathymetry/tiles` response. */
|
|
5
5
|
export declare const BATHYMETRY_FORMAT = "sparse-v1";
|
|
6
6
|
/** Extra fields a client needs to mirror the store (depth path, offsets, …). */
|
package/dist/tiles/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/tiles/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/tiles/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAKL,SAAS,EAEV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAErD,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,IAAI,UAAU,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,SAAS,GAAG,SAAS,EACrC,OAAO,GAAE,MAAM,cAA2B,EAC1C,IAAI,CAAC,EAAE,UAAU,GAChB,IAAI,CAoEN"}
|
package/dist/tiles/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BASE_ZOOM, MIN_ZOOM, RECORD_BYTES, TILE_SIZE, encodeTile, } from "
|
|
1
|
+
import { BASE_ZOOM, MIN_ZOOM, RECORD_BYTES, TILE_SIZE, encodeTile, } from "signalk-livedepth-tiles";
|
|
2
2
|
/** Wire format of a `/bathymetry/tiles` response. */
|
|
3
3
|
export const BATHYMETRY_FORMAT = "sparse-v1";
|
|
4
4
|
/**
|
|
@@ -55,10 +55,15 @@ export function registerBathymetryRoutes(router, getStore, getMeta = () => ({}),
|
|
|
55
55
|
res.status(404).end();
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
+
// Send a Buffer, not the Uint8Array `encodeTile` returns: express's
|
|
59
|
+
// `res.send` JSON-encodes anything that isn't a Buffer or string (it
|
|
60
|
+
// becomes `{"0":…,"1":…}`), so the client would decode the JSON text as
|
|
61
|
+
// sparse records. `Buffer` is a Uint8Array subclass, so it sends the
|
|
62
|
+
// bytes verbatim.
|
|
58
63
|
res
|
|
59
64
|
.set("Content-Type", "application/octet-stream")
|
|
60
65
|
.set("Cache-Control", "no-cache")
|
|
61
|
-
.send(encodeTile(cells));
|
|
66
|
+
.send(Buffer.from(encodeTile(cells)));
|
|
62
67
|
});
|
|
63
68
|
if (seed) {
|
|
64
69
|
// Registered without access() so the trigger requires admin.
|