signalk-livedepth-plugin 0.3.0 → 0.3.2
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 +46 -0
- package/dist/config.d.ts +49 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +33 -1
- package/dist/config.js.map +1 -1
- package/dist/plotterext/manifest.d.ts.map +1 -1
- package/dist/plotterext/manifest.js +4 -3
- package/dist/plotterext/manifest.js.map +1 -1
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +21 -3
- package/dist/plugin.js.map +1 -1
- package/dist/streams/live.d.ts +15 -3
- package/dist/streams/live.d.ts.map +1 -1
- package/dist/streams/live.js +163 -42
- package/dist/streams/live.js.map +1 -1
- package/dist/tiles/core/tile-source.d.ts +9 -0
- package/dist/tiles/core/tile-source.d.ts.map +1 -1
- package/dist/tiles/core/tile-source.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/public/js/config.js +40 -2
- package/public/js/config.js.map +2 -2
- package/public/js/render-worker.js +225 -65
- package/public/js/render-worker.js.map +3 -3
- package/public/js/renderer.js +76 -190
- package/public/js/renderer.js.map +4 -4
package/public/js/renderer.js
CHANGED
|
@@ -739,6 +739,7 @@ function parseDepthSeries(result, depthPath2) {
|
|
|
739
739
|
var DEFAULT_SETTINGS = {
|
|
740
740
|
enabled: true,
|
|
741
741
|
source: "history",
|
|
742
|
+
quality: "auto",
|
|
742
743
|
historyWindowHours: 1,
|
|
743
744
|
historyResolutionS: 0.1,
|
|
744
745
|
shadeLimitMetres: 10,
|
|
@@ -748,6 +749,10 @@ var DEFAULT_SETTINGS = {
|
|
|
748
749
|
maxDepthMetres: 100,
|
|
749
750
|
safetyDepthMetres: 3
|
|
750
751
|
};
|
|
752
|
+
var ENUM_VALUES = {
|
|
753
|
+
source: ["history", "tiles"],
|
|
754
|
+
quality: ["auto", "high", "balanced", "low"]
|
|
755
|
+
};
|
|
751
756
|
function mergeSettings(stored) {
|
|
752
757
|
const out = { ...DEFAULT_SETTINGS };
|
|
753
758
|
if (!stored) {
|
|
@@ -757,9 +762,14 @@ function mergeSettings(stored) {
|
|
|
757
762
|
DEFAULT_SETTINGS
|
|
758
763
|
)) {
|
|
759
764
|
const value = stored[key];
|
|
760
|
-
if (typeof value
|
|
761
|
-
|
|
765
|
+
if (typeof value !== typeof DEFAULT_SETTINGS[key]) {
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
const allowed = ENUM_VALUES[key];
|
|
769
|
+
if (allowed && !allowed.includes(value)) {
|
|
770
|
+
continue;
|
|
762
771
|
}
|
|
772
|
+
out[key] = value;
|
|
763
773
|
}
|
|
764
774
|
return out;
|
|
765
775
|
}
|
|
@@ -773,38 +783,9 @@ var RECORD_BYTES = 5;
|
|
|
773
783
|
var EARTH_RADIUS = 6378137;
|
|
774
784
|
var ORIGIN_SHIFT = Math.PI * EARTH_RADIUS;
|
|
775
785
|
var WORLD_WIDTH = 2 * ORIGIN_SHIFT;
|
|
776
|
-
var clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
777
|
-
function tileFraction(lon, lat, z) {
|
|
778
|
-
const n = Math.pow(2, z);
|
|
779
|
-
const latRad = clamp(lat, -85.05112878, 85.05112878) * Math.PI / 180;
|
|
780
|
-
const x = (lon + 180) / 360 * n;
|
|
781
|
-
const y = (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n;
|
|
782
|
-
return { x, y, n };
|
|
783
|
-
}
|
|
784
|
-
function lngLatToCell(lon, lat, z) {
|
|
785
|
-
const { x: fx, y: fy, n } = tileFraction(lon, lat, z);
|
|
786
|
-
const x = clamp(Math.floor(fx), 0, n - 1);
|
|
787
|
-
const y = clamp(Math.floor(fy), 0, n - 1);
|
|
788
|
-
const cx = clamp(Math.floor((fx - x) * TILE_SIZE), 0, TILE_SIZE - 1);
|
|
789
|
-
const cy = clamp(Math.floor((fy - y) * TILE_SIZE), 0, TILE_SIZE - 1);
|
|
790
|
-
return { x, y, cx, cy };
|
|
791
|
-
}
|
|
792
|
-
function encodeDepth(metres) {
|
|
793
|
-
if (!Number.isFinite(metres)) return NODATA;
|
|
794
|
-
return clamp(Math.round(metres * 100), 0, NODATA - 1);
|
|
795
|
-
}
|
|
796
786
|
function decodeDepth(cm) {
|
|
797
787
|
return cm === NODATA ? NaN : cm / 100;
|
|
798
788
|
}
|
|
799
|
-
function mergeCell(cells, key, depthCm, count = 1) {
|
|
800
|
-
const existing = cells.get(key);
|
|
801
|
-
if (!existing) {
|
|
802
|
-
cells.set(key, { depth: depthCm, count: Math.min(255, count) });
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
if (depthCm < existing.depth) existing.depth = depthCm;
|
|
806
|
-
existing.count = Math.min(255, existing.count + count);
|
|
807
|
-
}
|
|
808
789
|
function decodeTile(bytes) {
|
|
809
790
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
810
791
|
const cells = /* @__PURE__ */ new Map();
|
|
@@ -817,133 +798,6 @@ function decodeTile(bytes) {
|
|
|
817
798
|
}
|
|
818
799
|
return cells;
|
|
819
800
|
}
|
|
820
|
-
function minPoolTile(children) {
|
|
821
|
-
const parent = /* @__PURE__ */ new Map();
|
|
822
|
-
children.forEach((child, index) => {
|
|
823
|
-
if (!child) return;
|
|
824
|
-
const dx = index & 1;
|
|
825
|
-
const dy = index >> 1;
|
|
826
|
-
for (const [key, { depth, count }] of child) {
|
|
827
|
-
const cx = key % TILE_SIZE;
|
|
828
|
-
const cy = Math.floor(key / TILE_SIZE);
|
|
829
|
-
const pcx = dx * TILE_SIZE + cx >> 1;
|
|
830
|
-
const pcy = dy * TILE_SIZE + cy >> 1;
|
|
831
|
-
mergeCell(parent, pcy * TILE_SIZE + pcx, depth, count);
|
|
832
|
-
}
|
|
833
|
-
});
|
|
834
|
-
return parent;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// src/tiles/core/store.ts
|
|
838
|
-
function createMemoryTileStore() {
|
|
839
|
-
const tiles = /* @__PURE__ */ new Map();
|
|
840
|
-
const meta = /* @__PURE__ */ new Map();
|
|
841
|
-
const key = (z, x, y) => `${z}/${x}/${y}`;
|
|
842
|
-
const read = (z, x, y) => tiles.get(key(z, x, y));
|
|
843
|
-
const write = (z, x, y, cells) => {
|
|
844
|
-
if (cells.size === 0) {
|
|
845
|
-
tiles.delete(key(z, x, y));
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
tiles.set(key(z, x, y), cells);
|
|
849
|
-
};
|
|
850
|
-
const merge = (z, x, y, incoming) => {
|
|
851
|
-
const cells = read(z, x, y) ?? /* @__PURE__ */ new Map();
|
|
852
|
-
for (const [k, cell] of incoming) {
|
|
853
|
-
const existing = cells.get(k);
|
|
854
|
-
if (!existing) {
|
|
855
|
-
cells.set(k, { depth: cell.depth, count: cell.count });
|
|
856
|
-
} else {
|
|
857
|
-
if (cell.depth < existing.depth) existing.depth = cell.depth;
|
|
858
|
-
existing.count = Math.min(255, existing.count + cell.count);
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
write(z, x, y, cells);
|
|
862
|
-
};
|
|
863
|
-
const updateAncestors = (z, x, y) => {
|
|
864
|
-
let lz = z;
|
|
865
|
-
let lx = x;
|
|
866
|
-
let ly = y;
|
|
867
|
-
while (lz > MIN_ZOOM) {
|
|
868
|
-
const pz = lz - 1;
|
|
869
|
-
const px = lx >> 1;
|
|
870
|
-
const py = ly >> 1;
|
|
871
|
-
const children = [
|
|
872
|
-
read(lz, px * 2, py * 2),
|
|
873
|
-
read(lz, px * 2 + 1, py * 2),
|
|
874
|
-
read(lz, px * 2, py * 2 + 1),
|
|
875
|
-
read(lz, px * 2 + 1, py * 2 + 1)
|
|
876
|
-
];
|
|
877
|
-
write(pz, px, py, minPoolTile(children));
|
|
878
|
-
lz = pz;
|
|
879
|
-
lx = px;
|
|
880
|
-
ly = py;
|
|
881
|
-
}
|
|
882
|
-
};
|
|
883
|
-
return {
|
|
884
|
-
read,
|
|
885
|
-
write,
|
|
886
|
-
merge,
|
|
887
|
-
updateAncestors,
|
|
888
|
-
listTiles: (z) => {
|
|
889
|
-
const out = [];
|
|
890
|
-
for (const key2 of tiles.keys()) {
|
|
891
|
-
const [tz, tx, ty] = key2.split("/");
|
|
892
|
-
if (Number(tz) === z) {
|
|
893
|
-
out.push({ x: Number(tx), y: Number(ty) });
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
return out;
|
|
897
|
-
},
|
|
898
|
-
getMeta: (k) => meta.get(k),
|
|
899
|
-
setMeta: (k, v) => {
|
|
900
|
-
meta.set(k, v);
|
|
901
|
-
},
|
|
902
|
-
transaction: (fn) => fn(),
|
|
903
|
-
clear: () => {
|
|
904
|
-
tiles.clear();
|
|
905
|
-
},
|
|
906
|
-
close: () => {
|
|
907
|
-
tiles.clear();
|
|
908
|
-
}
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
// src/tiles/core/accumulator.ts
|
|
913
|
-
function createTileAccumulator(store, { baseZoom = BASE_ZOOM, ancestors = true } = {}) {
|
|
914
|
-
const dirty2 = /* @__PURE__ */ new Map();
|
|
915
|
-
return {
|
|
916
|
-
add(sample) {
|
|
917
|
-
if (!Number.isFinite(sample.lon) || !Number.isFinite(sample.lat) || !Number.isFinite(sample.depth) || sample.depth < 0) {
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
const { x, y, cx, cy } = lngLatToCell(sample.lon, sample.lat, baseZoom);
|
|
921
|
-
const key = `${x},${y}`;
|
|
922
|
-
let tile = dirty2.get(key);
|
|
923
|
-
if (!tile) {
|
|
924
|
-
tile = { z: baseZoom, x, y, cells: /* @__PURE__ */ new Map() };
|
|
925
|
-
dirty2.set(key, tile);
|
|
926
|
-
}
|
|
927
|
-
mergeCell(tile.cells, cy * TILE_SIZE + cx, encodeDepth(sample.depth));
|
|
928
|
-
},
|
|
929
|
-
flush() {
|
|
930
|
-
if (dirty2.size === 0) return;
|
|
931
|
-
const tiles = [...dirty2.values()];
|
|
932
|
-
dirty2.clear();
|
|
933
|
-
store.transaction(() => {
|
|
934
|
-
for (const tile of tiles) {
|
|
935
|
-
store.merge(tile.z, tile.x, tile.y, tile.cells);
|
|
936
|
-
if (ancestors) {
|
|
937
|
-
store.updateAncestors(tile.z, tile.x, tile.y);
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
});
|
|
941
|
-
},
|
|
942
|
-
get pending() {
|
|
943
|
-
return dirty2.size;
|
|
944
|
-
}
|
|
945
|
-
};
|
|
946
|
-
}
|
|
947
801
|
|
|
948
802
|
// src/tiles/core/tile-source.ts
|
|
949
803
|
var RAD2 = Math.PI / 180;
|
|
@@ -997,14 +851,14 @@ function tileCellCentre(z, x, y, key) {
|
|
|
997
851
|
return [lon, lat];
|
|
998
852
|
}
|
|
999
853
|
function cellsToSamples(z, x, y, cells) {
|
|
1000
|
-
const
|
|
854
|
+
const samples = [];
|
|
1001
855
|
for (const [key, cell] of cells) {
|
|
1002
856
|
const depth = decodeDepth(cell.depth);
|
|
1003
857
|
if (!Number.isFinite(depth)) continue;
|
|
1004
858
|
const [lon, lat] = tileCellCentre(z, x, y, key);
|
|
1005
|
-
|
|
859
|
+
samples.push({ lon, lat, depth });
|
|
1006
860
|
}
|
|
1007
|
-
return
|
|
861
|
+
return samples;
|
|
1008
862
|
}
|
|
1009
863
|
function decodeTileSamples(z, x, y, bytes) {
|
|
1010
864
|
return cellsToSamples(z, x, y, decodeTile(bytes));
|
|
@@ -1035,7 +889,7 @@ var BATHY_BASE = `${ASSET_BASE}/bathymetry`;
|
|
|
1035
889
|
var DEBOUNCE_MS = 400;
|
|
1036
890
|
var POLL_MS = 15e3;
|
|
1037
891
|
var MAX_TILE_FETCHES = 24;
|
|
1038
|
-
var LIVE_FLUSH_MS =
|
|
892
|
+
var LIVE_FLUSH_MS = 300;
|
|
1039
893
|
var DEFAULT_DEPTH_PATH = "environment.depth.belowTransducer";
|
|
1040
894
|
var client = await connectExtension();
|
|
1041
895
|
var worker = new Worker(new URL("./render-worker.js", import.meta.url), {
|
|
@@ -1044,7 +898,9 @@ var worker = new Worker(new URL("./render-worker.js", import.meta.url), {
|
|
|
1044
898
|
var settings = { ...DEFAULT_SETTINGS };
|
|
1045
899
|
var transducer = null;
|
|
1046
900
|
var depthPath = DEFAULT_DEPTH_PATH;
|
|
1047
|
-
var
|
|
901
|
+
var vessel = {};
|
|
902
|
+
var showFootprint = false;
|
|
903
|
+
var baseSamples = [];
|
|
1048
904
|
var lastReq = null;
|
|
1049
905
|
var busy = false;
|
|
1050
906
|
var dirty = false;
|
|
@@ -1052,11 +908,12 @@ var rendering = null;
|
|
|
1052
908
|
var renderingLive = false;
|
|
1053
909
|
var liveInterval = 200;
|
|
1054
910
|
var lastLiveAt = 0;
|
|
911
|
+
var perfScale = 0;
|
|
912
|
+
var perfFrameMs = 0;
|
|
913
|
+
var framesSeen = 0;
|
|
914
|
+
var framesSince = Date.now();
|
|
1055
915
|
var timer;
|
|
1056
|
-
var
|
|
1057
|
-
var clientStore = createMemoryTileStore();
|
|
1058
|
-
var clientAccumulator = createTileAccumulator(clientStore);
|
|
1059
|
-
var liveDirty = false;
|
|
916
|
+
var pendingLive = [];
|
|
1060
917
|
var liveFlushTimer;
|
|
1061
918
|
async function loadSettings() {
|
|
1062
919
|
try {
|
|
@@ -1082,6 +939,9 @@ async function loadMeta() {
|
|
|
1082
939
|
const meta = await res.json();
|
|
1083
940
|
transducer = meta.transducer ?? null;
|
|
1084
941
|
if (meta.depthPath) depthPath = meta.depthPath;
|
|
942
|
+
vessel = meta.vessel ?? {};
|
|
943
|
+
showFootprint = meta.debug?.vesselFootprint === true;
|
|
944
|
+
publishVessel();
|
|
1085
945
|
} catch {
|
|
1086
946
|
}
|
|
1087
947
|
}
|
|
@@ -1117,8 +977,8 @@ async function fetchHistory() {
|
|
|
1117
977
|
const { lon, lat } = correct(row.position[0], row.position[1], row.heading);
|
|
1118
978
|
out.push({ lon, lat, depth: row.depth });
|
|
1119
979
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
980
|
+
baseSamples = out;
|
|
981
|
+
publishBase();
|
|
1122
982
|
}
|
|
1123
983
|
async function fetchTiles(req) {
|
|
1124
984
|
const cellMetres = Math.max(req.resolution, 0.01);
|
|
@@ -1128,7 +988,6 @@ async function fetchTiles(req) {
|
|
|
1128
988
|
if (xs2.length * ys2.length <= MAX_TILE_FETCHES) break;
|
|
1129
989
|
zoom--;
|
|
1130
990
|
}
|
|
1131
|
-
lastZoom = zoom;
|
|
1132
991
|
const { xs, ys } = tileRangeForBbox(req.bounds, zoom);
|
|
1133
992
|
const out = [];
|
|
1134
993
|
await Promise.all(
|
|
@@ -1146,16 +1005,8 @@ async function fetchTiles(req) {
|
|
|
1146
1005
|
})
|
|
1147
1006
|
)
|
|
1148
1007
|
);
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
const cells = clientStore.read(lastZoom, x, y);
|
|
1152
|
-
if (cells && cells.size) {
|
|
1153
|
-
out.push(...cellsToSamples(lastZoom, x, y, cells));
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
samples = out;
|
|
1158
|
-
publish();
|
|
1008
|
+
baseSamples = out;
|
|
1009
|
+
publishBase();
|
|
1159
1010
|
}
|
|
1160
1011
|
function schedule() {
|
|
1161
1012
|
clearTimeout(timer);
|
|
@@ -1169,8 +1020,8 @@ async function refresh() {
|
|
|
1169
1020
|
await fetchTiles(lastReq);
|
|
1170
1021
|
}
|
|
1171
1022
|
}
|
|
1172
|
-
function
|
|
1173
|
-
worker.postMessage({ type: "
|
|
1023
|
+
function publishBase() {
|
|
1024
|
+
worker.postMessage({ type: "base", samples: baseSamples });
|
|
1174
1025
|
dirty = true;
|
|
1175
1026
|
if (lastReq) draw(true);
|
|
1176
1027
|
}
|
|
@@ -1180,13 +1031,19 @@ function startLive() {
|
|
|
1180
1031
|
void client.signalk.subscribe(
|
|
1181
1032
|
["navigation.position", depthPath, "navigation.headingTrue"],
|
|
1182
1033
|
(ev) => {
|
|
1183
|
-
if (ev.path === "navigation.position"
|
|
1184
|
-
|
|
1034
|
+
if (ev.path === "navigation.position") {
|
|
1035
|
+
const p = ev.value;
|
|
1036
|
+
if (Array.isArray(p)) {
|
|
1037
|
+
livePosition = [p[0], p[1]];
|
|
1038
|
+
} else if (typeof p?.longitude === "number" && typeof p?.latitude === "number") {
|
|
1039
|
+
livePosition = [p.longitude, p.latitude];
|
|
1040
|
+
}
|
|
1185
1041
|
} else if (ev.path === depthPath && typeof ev.value === "number") {
|
|
1186
1042
|
liveDepth = ev.value;
|
|
1187
1043
|
} else if (ev.path === "navigation.headingTrue" && typeof ev.value === "number") {
|
|
1188
1044
|
liveHeading = ev.value;
|
|
1189
1045
|
}
|
|
1046
|
+
publishVessel();
|
|
1190
1047
|
sampleLive();
|
|
1191
1048
|
}
|
|
1192
1049
|
).then((un) => {
|
|
@@ -1205,17 +1062,30 @@ function stopLive() {
|
|
|
1205
1062
|
var livePosition = null;
|
|
1206
1063
|
var liveDepth = null;
|
|
1207
1064
|
var liveHeading;
|
|
1065
|
+
function publishVessel() {
|
|
1066
|
+
if (!showFootprint) return;
|
|
1067
|
+
worker.postMessage({
|
|
1068
|
+
type: "vessel",
|
|
1069
|
+
position: livePosition,
|
|
1070
|
+
heading: liveHeading,
|
|
1071
|
+
loa: vessel.loa,
|
|
1072
|
+
beam: vessel.beam
|
|
1073
|
+
});
|
|
1074
|
+
dirty = true;
|
|
1075
|
+
if (lastReq) draw(true);
|
|
1076
|
+
}
|
|
1208
1077
|
function sampleLive() {
|
|
1209
1078
|
if (!livePosition || liveDepth === null) return;
|
|
1210
1079
|
const { lon, lat } = correct(livePosition[0], livePosition[1], liveHeading);
|
|
1211
|
-
|
|
1212
|
-
liveDirty = true;
|
|
1080
|
+
pendingLive.push({ lon, lat, depth: liveDepth });
|
|
1213
1081
|
}
|
|
1214
1082
|
function flushLive() {
|
|
1215
|
-
if (
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1083
|
+
if (pendingLive.length === 0) return;
|
|
1084
|
+
const live = pendingLive;
|
|
1085
|
+
pendingLive = [];
|
|
1086
|
+
worker.postMessage({ type: "live", samples: live });
|
|
1087
|
+
dirty = true;
|
|
1088
|
+
if (lastReq) draw(true);
|
|
1219
1089
|
}
|
|
1220
1090
|
function draw(live = false) {
|
|
1221
1091
|
if (busy || !lastReq || !settings.enabled) return;
|
|
@@ -1228,6 +1098,11 @@ function draw(live = false) {
|
|
|
1228
1098
|
}
|
|
1229
1099
|
worker.onmessage = (e) => {
|
|
1230
1100
|
const msg = e.data;
|
|
1101
|
+
if (msg.type === "perf") {
|
|
1102
|
+
perfScale = msg.scale;
|
|
1103
|
+
perfFrameMs = msg.frameMs;
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1231
1106
|
const req = rendering;
|
|
1232
1107
|
const live = renderingLive;
|
|
1233
1108
|
busy = false;
|
|
@@ -1243,6 +1118,16 @@ worker.onmessage = (e) => {
|
|
|
1243
1118
|
image: msg.image
|
|
1244
1119
|
}).catch(() => {
|
|
1245
1120
|
});
|
|
1121
|
+
framesSeen++;
|
|
1122
|
+
const now = Date.now();
|
|
1123
|
+
if (now - framesSince >= 5e3) {
|
|
1124
|
+
const fps = framesSeen * 1e3 / (now - framesSince);
|
|
1125
|
+
console.info(
|
|
1126
|
+
`[LiveDepth] ${fps.toFixed(1)} frames/s \xB7 render scale ${perfScale.toFixed(2)} \xB7 worker ${perfFrameMs.toFixed(1)} ms/frame`
|
|
1127
|
+
);
|
|
1128
|
+
framesSeen = 0;
|
|
1129
|
+
framesSince = now;
|
|
1130
|
+
}
|
|
1246
1131
|
if (dirty || lastReq !== req) draw(live);
|
|
1247
1132
|
};
|
|
1248
1133
|
await client.subscribe(["overlay.request"], (_name, payload) => {
|
|
@@ -1251,6 +1136,7 @@ await client.subscribe(["overlay.request"], (_name, payload) => {
|
|
|
1251
1136
|
if (typeof req.liveInterval === "number" && req.liveInterval > 0) {
|
|
1252
1137
|
liveInterval = req.liveInterval;
|
|
1253
1138
|
}
|
|
1139
|
+
if (settings.source === "tiles") schedule();
|
|
1254
1140
|
draw();
|
|
1255
1141
|
});
|
|
1256
1142
|
await client.subscribe(["overlay.state"], (_name, payload) => {
|