@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.
@@ -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>