@marineyachtradar/signalk-playback-plugin 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -13
- package/package.json +3 -3
- package/public/api.js +402 -0
- package/public/assets/MaYaRa_RED.png +0 -0
- package/public/base.css +91 -0
- package/public/control.html +23 -0
- package/public/control.js +1155 -0
- package/public/controls.css +538 -0
- package/public/discovery.css +478 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +10 -0
- package/public/layout.css +87 -0
- package/public/mayara.js +510 -0
- package/public/playback.html +572 -0
- package/public/proto/RadarMessage.proto +41 -0
- package/public/protobuf/protobuf.js +9112 -0
- package/public/protobuf/protobuf.js.map +1 -0
- package/public/protobuf/protobuf.min.js +8 -0
- package/public/protobuf/protobuf.min.js.map +1 -0
- package/public/radar.svg +29 -0
- package/public/render_webgpu.js +886 -0
- package/public/responsive.css +29 -0
- package/public/van-1.5.2.debug.js +126 -0
- package/public/van-1.5.2.js +140 -0
- package/public/van-1.5.2.min.js +1 -0
- package/public/viewer.html +30 -0
- package/public/viewer.js +797 -0
- package/build.js +0 -282
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
Responsive Styles - Media Queries
|
|
3
|
+
============================================ */
|
|
4
|
+
|
|
5
|
+
/* Touch-friendly: larger touch targets */
|
|
6
|
+
@media (pointer: coarse) {
|
|
7
|
+
.myr_power_button,
|
|
8
|
+
.myr_range_button,
|
|
9
|
+
.myr_toggle_button,
|
|
10
|
+
.myr_enum_button,
|
|
11
|
+
.myr_mode_button {
|
|
12
|
+
min-height: 44px;
|
|
13
|
+
font-size: 14px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.myr_slider {
|
|
17
|
+
height: 32px;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.myr_slider::-webkit-slider-thumb {
|
|
21
|
+
width: 32px;
|
|
22
|
+
height: 32px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.myr_slider::-moz-range-thumb {
|
|
26
|
+
width: 32px;
|
|
27
|
+
height: 32px;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import van from "./van-1.5.2.js"
|
|
2
|
+
|
|
3
|
+
// If this variable is set to an Array, we will push the error message into the array instead of
|
|
4
|
+
// throwing an error. This is useful in testing, to capture the error occurred asynchronous to the initiating
|
|
5
|
+
// callstack. e.g.: a state change can trigger a dom update processing when idle (i.e.: dom update
|
|
6
|
+
// processing is set via setTimeout function, which is asynchronous to the initiating callstack).
|
|
7
|
+
let capturedErrors
|
|
8
|
+
|
|
9
|
+
const startCapturingErrors = () => capturedErrors = []
|
|
10
|
+
|
|
11
|
+
const stopCapturingErrors = () => capturedErrors = null
|
|
12
|
+
|
|
13
|
+
const expect = (cond, msg) => {
|
|
14
|
+
if (!cond) {
|
|
15
|
+
if (capturedErrors) capturedErrors.push(msg); else throw new Error(msg)
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const protoOf = Object.getPrototypeOf
|
|
22
|
+
const stateProto = protoOf(van.state())
|
|
23
|
+
const isState = s => protoOf(s ?? 0) === stateProto
|
|
24
|
+
|
|
25
|
+
const checkStateValValid = v => {
|
|
26
|
+
expect(!isState(v), "State couldn't have value to other state")
|
|
27
|
+
expect(!(v instanceof Node), "DOM Node is not valid value for state")
|
|
28
|
+
return v
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const state = initVal => {
|
|
32
|
+
const proxy = new Proxy(van.state(checkStateValValid(initVal)), {
|
|
33
|
+
set: (s, prop, val) => {
|
|
34
|
+
prop === "val" && checkStateValValid(val)
|
|
35
|
+
return Reflect.set(s, prop, val, proxy)
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
return proxy
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const derive = f => {
|
|
42
|
+
expect(typeof(f) === "function", "Must pass-in a function to `van.derive`")
|
|
43
|
+
return van.derive(f)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const isValidPrimitive = v =>
|
|
47
|
+
typeof(v) === "string" ||
|
|
48
|
+
typeof(v) === "number" ||
|
|
49
|
+
typeof(v) === "boolean" ||
|
|
50
|
+
typeof(v) === "bigint"
|
|
51
|
+
|
|
52
|
+
const isDomOrPrimitive = v => v instanceof Node || isValidPrimitive(v)
|
|
53
|
+
|
|
54
|
+
const validateChild = child => {
|
|
55
|
+
expect(
|
|
56
|
+
isDomOrPrimitive(child) || child === null || child === undefined,
|
|
57
|
+
"Only DOM Node, string, number, boolean, bigint, null, undefined are valid child of a DOM Element",
|
|
58
|
+
)
|
|
59
|
+
return child
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const withResultValidation = f => dom => {
|
|
63
|
+
const r = validateChild(f(dom))
|
|
64
|
+
if (r !== dom && r instanceof Node)
|
|
65
|
+
expect(!r.isConnected,
|
|
66
|
+
"If the result of complex binding function is not the same as previous one, it shouldn't be already connected to document")
|
|
67
|
+
return r
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const checkChildren = children => children.flat(Infinity).map(c => {
|
|
71
|
+
if (isState(c)) return withResultValidation(() => c.val)
|
|
72
|
+
if (typeof c === "function") return withResultValidation(c)
|
|
73
|
+
expect(!c?.isConnected, "You can't add a DOM Node that is already connected to document")
|
|
74
|
+
return validateChild(c)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const add = (dom, ...children) => {
|
|
78
|
+
expect(dom instanceof Element, "1st argument of `van.add` function must be a DOM Element object")
|
|
79
|
+
return van.add(dom, ...checkChildren(children))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const debugHandler = {
|
|
83
|
+
get: (vanTags, name) => {
|
|
84
|
+
const vanTag = vanTags[name]
|
|
85
|
+
return (...args) => {
|
|
86
|
+
const [props, ...children] = protoOf(args[0] ?? 0) === Object.prototype ? args : [{}, ...args]
|
|
87
|
+
const debugProps = {}
|
|
88
|
+
for (const [k, v] of Object.entries(props)) {
|
|
89
|
+
const validatePropValue = k.startsWith("on") ?
|
|
90
|
+
(k.toLowerCase() === k ?
|
|
91
|
+
v => (expect(typeof v === "function" || v === null,
|
|
92
|
+
`Invalid property value for ${k}: Only functions and null are allowed for ${k} property`), v) :
|
|
93
|
+
v => (expect(typeof v === "string",
|
|
94
|
+
`Invalid property value for ${k}: Only strings are allowed for ${k} attribute`), v)
|
|
95
|
+
) :
|
|
96
|
+
v => (expect(isValidPrimitive(v) || v === null,
|
|
97
|
+
`Invalid property value for ${k}: Only string, number, boolean, bigint and null are valid prop value types`), v)
|
|
98
|
+
|
|
99
|
+
if (isState(v))
|
|
100
|
+
debugProps[k] = van.derive(() => validatePropValue(v.val))
|
|
101
|
+
else if (typeof v === "function" && (!k.startsWith("on") || v._isBindingFunc))
|
|
102
|
+
debugProps[k] = van.derive(() => validatePropValue(v()))
|
|
103
|
+
else
|
|
104
|
+
debugProps[k] = validatePropValue(v)
|
|
105
|
+
}
|
|
106
|
+
return vanTag(debugProps, ...checkChildren(children))
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const _tagsNS = ns => new Proxy(van.tags(ns), debugHandler)
|
|
112
|
+
const tagsNS = ns => {
|
|
113
|
+
expect(typeof ns === "string", "Must provide a string for parameter `ns` in `van.tags`")
|
|
114
|
+
return _tagsNS(ns)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const _tags = _tagsNS("")
|
|
118
|
+
const tags = new Proxy(tagsNS, {get: (_, name) => _tags[name]})
|
|
119
|
+
|
|
120
|
+
const hydrate = (dom, f) => {
|
|
121
|
+
expect(dom instanceof Node, "1st argument of `van.hydrate` function must be a DOM Node object")
|
|
122
|
+
expect(typeof(f) === "function", "2nd argument of `van.hydrate` function must be a function")
|
|
123
|
+
return van.hydrate(dom, withResultValidation(f))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default {add, tags, state, derive, hydrate, startCapturingErrors, stopCapturingErrors, get capturedErrors() { return capturedErrors }}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// This file consistently uses `let` keyword instead of `const` for reducing the bundle size.
|
|
2
|
+
|
|
3
|
+
// Global variables - aliasing some builtin symbols to reduce the bundle size.
|
|
4
|
+
let protoOf = Object.getPrototypeOf
|
|
5
|
+
let changedStates, derivedStates, curDeps, curNewDerives, alwaysConnectedDom = {isConnected: 1}
|
|
6
|
+
let gcCycleInMs = 1000, statesToGc, propSetterCache = {}
|
|
7
|
+
let objProto = protoOf(alwaysConnectedDom), funcProto = protoOf(protoOf), _undefined
|
|
8
|
+
|
|
9
|
+
let addAndScheduleOnFirst = (set, s, f, waitMs) =>
|
|
10
|
+
(set ?? (setTimeout(f, waitMs), new Set)).add(s)
|
|
11
|
+
|
|
12
|
+
let runAndCaptureDeps = (f, deps, arg) => {
|
|
13
|
+
let prevDeps = curDeps
|
|
14
|
+
curDeps = deps
|
|
15
|
+
try {
|
|
16
|
+
return f(arg)
|
|
17
|
+
} catch (e) {
|
|
18
|
+
console.error(e)
|
|
19
|
+
return arg
|
|
20
|
+
} finally {
|
|
21
|
+
curDeps = prevDeps
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let keepConnected = l => l.filter(b => b._dom?.isConnected)
|
|
26
|
+
|
|
27
|
+
let addStatesToGc = d => statesToGc = addAndScheduleOnFirst(statesToGc, d, () => {
|
|
28
|
+
for (let s of statesToGc)
|
|
29
|
+
s._bindings = keepConnected(s._bindings),
|
|
30
|
+
s._listeners = keepConnected(s._listeners)
|
|
31
|
+
statesToGc = _undefined
|
|
32
|
+
}, gcCycleInMs)
|
|
33
|
+
|
|
34
|
+
let stateProto = {
|
|
35
|
+
get val() {
|
|
36
|
+
curDeps?._getters?.add(this)
|
|
37
|
+
return this.rawVal
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
get oldVal() {
|
|
41
|
+
curDeps?._getters?.add(this)
|
|
42
|
+
return this._oldVal
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
set val(v) {
|
|
46
|
+
curDeps?._setters?.add(this)
|
|
47
|
+
if (v !== this.rawVal) {
|
|
48
|
+
this.rawVal = v
|
|
49
|
+
this._bindings.length + this._listeners.length ?
|
|
50
|
+
(derivedStates?.add(this), changedStates = addAndScheduleOnFirst(changedStates, this, updateDoms)) :
|
|
51
|
+
this._oldVal = v
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let state = initVal => ({
|
|
57
|
+
__proto__: stateProto,
|
|
58
|
+
rawVal: initVal,
|
|
59
|
+
_oldVal: initVal,
|
|
60
|
+
_bindings: [],
|
|
61
|
+
_listeners: [],
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
let bind = (f, dom) => {
|
|
65
|
+
let deps = {_getters: new Set, _setters: new Set}, binding = {f}, prevNewDerives = curNewDerives
|
|
66
|
+
curNewDerives = []
|
|
67
|
+
let newDom = runAndCaptureDeps(f, deps, dom)
|
|
68
|
+
newDom = (newDom ?? document).nodeType ? newDom : new Text(newDom)
|
|
69
|
+
for (let d of deps._getters)
|
|
70
|
+
deps._setters.has(d) || (addStatesToGc(d), d._bindings.push(binding))
|
|
71
|
+
for (let l of curNewDerives) l._dom = newDom
|
|
72
|
+
curNewDerives = prevNewDerives
|
|
73
|
+
return binding._dom = newDom
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let derive = (f, s = state(), dom) => {
|
|
77
|
+
let deps = {_getters: new Set, _setters: new Set}, listener = {f, s}
|
|
78
|
+
listener._dom = dom ?? curNewDerives?.push(listener) ?? alwaysConnectedDom
|
|
79
|
+
s.val = runAndCaptureDeps(f, deps, s.rawVal)
|
|
80
|
+
for (let d of deps._getters)
|
|
81
|
+
deps._setters.has(d) || (addStatesToGc(d), d._listeners.push(listener))
|
|
82
|
+
return s
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let add = (dom, ...children) => {
|
|
86
|
+
for (let c of children.flat(Infinity)) {
|
|
87
|
+
let protoOfC = protoOf(c ?? 0)
|
|
88
|
+
let child = protoOfC === stateProto ? bind(() => c.val) :
|
|
89
|
+
protoOfC === funcProto ? bind(c) : c
|
|
90
|
+
child != _undefined && dom.append(child)
|
|
91
|
+
}
|
|
92
|
+
return dom
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let tag = (ns, name, ...args) => {
|
|
96
|
+
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]
|
|
97
|
+
let dom = ns ? document.createElementNS(ns, name) : document.createElement(name)
|
|
98
|
+
for (let [k, v] of Object.entries(props)) {
|
|
99
|
+
let getPropDescriptor = proto => proto ?
|
|
100
|
+
Object.getOwnPropertyDescriptor(proto, k) ?? getPropDescriptor(protoOf(proto)) :
|
|
101
|
+
_undefined
|
|
102
|
+
let cacheKey = name + "," + k
|
|
103
|
+
let propSetter = propSetterCache[cacheKey] ??= getPropDescriptor(protoOf(dom))?.set ?? 0
|
|
104
|
+
let setter = k.startsWith("on") ?
|
|
105
|
+
(v, oldV) => {
|
|
106
|
+
let event = k.slice(2)
|
|
107
|
+
dom.removeEventListener(event, oldV)
|
|
108
|
+
dom.addEventListener(event, v)
|
|
109
|
+
} :
|
|
110
|
+
propSetter ? propSetter.bind(dom) : dom.setAttribute.bind(dom, k)
|
|
111
|
+
let protoOfV = protoOf(v ?? 0)
|
|
112
|
+
k.startsWith("on") || protoOfV === funcProto && (v = derive(v), protoOfV = stateProto)
|
|
113
|
+
protoOfV === stateProto ? bind(() => (setter(v.val, v._oldVal), dom)) : setter(v)
|
|
114
|
+
}
|
|
115
|
+
return add(dom, children)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let handler = ns => ({get: (_, name) => tag.bind(_undefined, ns, name)})
|
|
119
|
+
|
|
120
|
+
let update = (dom, newDom) => newDom ? newDom !== dom && dom.replaceWith(newDom) : dom.remove()
|
|
121
|
+
|
|
122
|
+
let updateDoms = () => {
|
|
123
|
+
let iter = 0, derivedStatesArray = [...changedStates].filter(s => s.rawVal !== s._oldVal)
|
|
124
|
+
do {
|
|
125
|
+
derivedStates = new Set
|
|
126
|
+
for (let l of new Set(derivedStatesArray.flatMap(s => s._listeners = keepConnected(s._listeners))))
|
|
127
|
+
derive(l.f, l.s, l._dom), l._dom = _undefined
|
|
128
|
+
} while (++iter < 100 && (derivedStatesArray = [...derivedStates]).length)
|
|
129
|
+
let changedStatesArray = [...changedStates].filter(s => s.rawVal !== s._oldVal)
|
|
130
|
+
changedStates = _undefined
|
|
131
|
+
for (let b of new Set(changedStatesArray.flatMap(s => s._bindings = keepConnected(s._bindings))))
|
|
132
|
+
update(b._dom, bind(b.f, b._dom)), b._dom = _undefined
|
|
133
|
+
for (let s of changedStatesArray) s._oldVal = s.rawVal
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default {
|
|
137
|
+
tags: new Proxy(ns => new Proxy(tag, handler(ns)), handler()),
|
|
138
|
+
hydrate: (dom, f) => update(dom, bind(f, dom)),
|
|
139
|
+
add, state, derive,
|
|
140
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e,t,r,o,l,n,s=Object.getPrototypeOf,f={isConnected:1},i={},h=s(f),a=s(s),d=(e,t,r,o)=>(e??(setTimeout(r,o),new Set)).add(t),u=(e,t,o)=>{let l=r;r=t;try{return e(o)}catch(e){return console.error(e),o}finally{r=l}},w=e=>e.filter(e=>e.t?.isConnected),_=e=>l=d(l,e,()=>{for(let e of l)e.o=w(e.o),e.l=w(e.l);l=n},1e3),c={get val(){return r?.i?.add(this),this.rawVal},get oldVal(){return r?.i?.add(this),this.h},set val(o){r?.u?.add(this),o!==this.rawVal&&(this.rawVal=o,this.o.length+this.l.length?(t?.add(this),e=d(e,this,v)):this.h=o)}},S=e=>({__proto__:c,rawVal:e,h:e,o:[],l:[]}),g=(e,t)=>{let r={i:new Set,u:new Set},l={f:e},n=o;o=[];let s=u(e,r,t);s=(s??document).nodeType?s:new Text(s);for(let e of r.i)r.u.has(e)||(_(e),e.o.push(l));for(let e of o)e.t=s;return o=n,l.t=s},y=(e,t=S(),r)=>{let l={i:new Set,u:new Set},n={f:e,s:t};n.t=r??o?.push(n)??f,t.val=u(e,l,t.rawVal);for(let e of l.i)l.u.has(e)||(_(e),e.l.push(n));return t},b=(e,...t)=>{for(let r of t.flat(1/0)){let t=s(r??0),o=t===c?g(()=>r.val):t===a?g(r):r;o!=n&&e.append(o)}return e},m=(e,t,...r)=>{let[o,...l]=s(r[0]??0)===h?r:[{},...r],f=e?document.createElementNS(e,t):document.createElement(t);for(let[e,r]of Object.entries(o)){let o=t=>t?Object.getOwnPropertyDescriptor(t,e)??o(s(t)):n,l=t+","+e,h=i[l]??=o(s(f))?.set??0,d=e.startsWith("on")?(t,r)=>{let o=e.slice(2);f.removeEventListener(o,r),f.addEventListener(o,t)}:h?h.bind(f):f.setAttribute.bind(f,e),u=s(r??0);e.startsWith("on")||u===a&&(r=y(r),u=c),u===c?g(()=>(d(r.val,r.h),f)):d(r)}return b(f,l)},x=e=>({get:(t,r)=>m.bind(n,e,r)}),j=(e,t)=>t?t!==e&&e.replaceWith(t):e.remove(),v=()=>{let r=0,o=[...e].filter(e=>e.rawVal!==e.h);do{t=new Set;for(let e of new Set(o.flatMap(e=>e.l=w(e.l))))y(e.f,e.s,e.t),e.t=n}while(++r<100&&(o=[...t]).length);let l=[...e].filter(e=>e.rawVal!==e.h);e=n;for(let e of new Set(l.flatMap(e=>e.o=w(e.o))))j(e.t,g(e.f,e.t)),e.t=n;for(let e of l)e.h=e.rawVal};export default{tags:new Proxy(e=>new Proxy(m,x(e)),x()),hydrate:(e,t)=>j(e,g(t,e)),add:b,state:S,derive:y};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<title>Mayara - Marine Yacht Radar PPI</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
|
8
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
|
9
|
+
<meta http-equiv="Expires" content="0" />
|
|
10
|
+
<link type="text/css" rel="stylesheet" href="base.css?v=1" />
|
|
11
|
+
<link type="text/css" rel="stylesheet" href="layout.css?v=1" />
|
|
12
|
+
<link type="text/css" rel="stylesheet" href="controls.css?v=1" />
|
|
13
|
+
<link type="text/css" rel="stylesheet" href="responsive.css?v=1" />
|
|
14
|
+
<script type="module" src="viewer.js?v=44"></script>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<div class="myr_container">
|
|
18
|
+
<div id="myr_controller" class="myr_controller myr_controller_left">
|
|
19
|
+
<div id="myr_title">Radar Controls</div>
|
|
20
|
+
<div id="myr_error" class="myr_error" style="visibility: hidden;"></div>
|
|
21
|
+
<div id="myr_controls" class="myr_control"></div>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="myr_ppi">
|
|
24
|
+
<canvas id="myr_canvas_background" width="600" height="600"></canvas>
|
|
25
|
+
<canvas id="myr_canvas_webgl" width="600" height="600"></canvas>
|
|
26
|
+
<canvas id="myr_canvas_overlay" width="600" height="600"></canvas>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|