diff --git a/src/app.js b/src/app.js index c74f500..9a3c463 100644 --- a/src/app.js +++ b/src/app.js @@ -13,76 +13,12 @@ ShadowDOM.append(ShadowDiv); TW.Init(ShadowCSS, ShadowDiv); -const Controls =()=> -{ - const [State, Dispatch] = Store.Consumer(); - - return html` -
-
Channel
-
${State.Chan.Value}
- <${UI.Button} light=${State.Chan.Value == 0} inactive=${State.Chan.Value == 0} onClick=${()=>Dispatch({Name:"Chan", Data:-1})}>Left - <${UI.Button} light=${State.Chan.Value == 1} inactive=${State.Chan.Value == 1} onClick=${()=>Dispatch({Name:"Chan", Data:1})}>Right -
-
-
Frequency
-
${Store.ColumnMapping[State.Freq.Value][0]}
- <${UI.Button} disabled=${State.Freq.Value == State.Freq.Min} onClick=${()=>Dispatch({Name:"Freq", Data:-1})}>- - <${UI.Button} disabled=${State.Freq.Value == State.Freq.Max} onClick=${()=>Dispatch({Name:"Freq", Data:1})}>+ -
-
-
Stimulus
-
${State.Stim.Value}
- <${UI.Button} disabled=${State.Stim.Value == State.Stim.Min} onClick=${()=>Dispatch({Name:"Stim", Data:-1})}>- - <${UI.Button} disabled=${State.Stim.Value == State.Stim.Max} onClick=${()=>Dispatch({Name:"Stim", Data:1})}>+ -
-
-
Mark
- <${UI.Button} onClick=${()=>Dispatch({Name:"Mark", Data:true })}>Response - <${UI.Button} onClick=${()=>Dispatch({Name:"Mark", Data:false})}>No Response - <${UI.Button} onClick=${()=>Dispatch({Name:"Mark", Data:null })} disabled=${State.Live.Mark == undefined}>Clear -
- `; -}; - -const Audiogram =()=> -{ - const [State] = Store.Consumer(); - - const testMarksL = State.Draw.TestL.Points.map(p=>html`<${UI.Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false}/>`); - const userMarksL = State.Draw.UserL.Points.map(p=>html`<${UI.Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false} classes=${State.Live.Mark == p.Mark ? "stroke-bold":""}/>`); - const testMarksR = State.Draw.TestR.Points.map(p=>html`<${UI.Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} />`); - const userMarksR = State.Draw.UserR.Points.map(p=>html`<${UI.Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} classes=${State.Live.Mark == p.Mark ? "stroke-bold":""}/>`); - - const testLinesL = State.Draw.TestL.Paths.map( p=>html``); - const userLinesL = State.Draw.UserL.Paths.map( p=>html``); - const testLinesR = State.Draw.TestR.Paths.map( p=>html``); - const userLinesR = State.Draw.UserR.Paths.map( p=>html``); - - return html` - ${testMarksL}${testLinesL} - ${testMarksR}${testLinesR} - ${userMarksL}${userLinesL} - ${userMarksR}${userLinesR} - - - - - - - - - - - - `; -}; - React.render(html` <${Store.Provider}> - <${Controls}/> + <${UI.Select}/> + <${UI.Controls}/> <${UI.Chart}> - <${Audiogram}/> + <${UI.Audiogram}/> `, ShadowDiv); \ No newline at end of file diff --git a/src/store.js b/src/store.js index c6a751e..ac13cfe 100644 --- a/src/store.js +++ b/src/store.js @@ -108,16 +108,20 @@ export function Reducer(inState, inAction) if(Name == "Test") { - const test = clone.Tests[Data]; - clone.Live = Reselect(clone, test); - clone.Draw = + const test = clone.Test[Data]; + if(test) { - Cross: Reposition(clone), - UserL: Redraw(test, 0, clone.Stim, true ), - UserR: Redraw(test, 1, clone.Stim, true ), - TestL: Redraw(test, 0, clone.Stim, false), - TestR: Redraw(test, 1, clone.Stim, false) - }; + clone.TestIndex = Data; + clone.Live = Reselect(clone, test); + clone.Draw = + { + Cross: Reposition(clone), + UserL: Redraw(test, 0, clone.Stim, true ), + UserR: Redraw(test, 1, clone.Stim, true ), + TestL: Redraw(test, 0, clone.Stim, false), + TestR: Redraw(test, 1, clone.Stim, false) + }; + } } else if (Name == "Mark") { @@ -165,7 +169,8 @@ export const Initial = Reducer( TestL:{Points:[], Paths:[]}, TestR:{Points:[], Paths:[]} }, - Tests: [ + TestIndex: 0, + Test: [ { Name: "Patient A Asymmetric Notch", Plot: @@ -178,6 +183,19 @@ export const Initial = Reducer( { Hz: 6000, TestL: { Stim: 50, Resp: true }, TestR: { Stim: 55, Resp: true } }, { Hz: 8000, TestL: { Stim: 50, Resp: true }, TestR: { Stim: 55, Resp: true } } ] + }, + { + Name: "Patient B Asymmetric Notch", + Plot: + [ + { Hz: 500, TestL: { Stim: 50, Resp: true }, TestR: { Stim: 70, Resp: true } }, + { Hz: 1000, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 25, Resp: true } }, + { Hz: 2000, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 25, Resp: true } }, + { Hz: 3000, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 25, Resp: true } }, + { Hz: 4000, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 25, Resp: true } }, + { Hz: 6000, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 25, Resp: true } }, + { Hz: 8000, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 25, Resp: true } } + ] } ] }, {Name:"Test", Data:0}); diff --git a/src/ui.js b/src/ui.js index a9a2a7f..76a47fb 100644 --- a/src/ui.js +++ b/src/ui.js @@ -34,6 +34,89 @@ export function Button({children, icon, light, disabled, inactive, onClick}) `; } +/** @type {BasicElement} */ +export const Select =()=> +{ + const [State, Dispatch] = Store.Consumer(); + /** @type {(e:Event)=>void} */ + const handleChange =(e)=> Dispatch({Name:"Test", Data:parseInt(/** @type {HTMLSelectElement}*/(e.target).value)}); + + return html` +
+ + +
`; +} + +/** @type {BasicElement} */ +export const Controls =()=> +{ + const [State, Dispatch] = Store.Consumer(); + + return html` +
+
Channel
+
${State.Chan.Value}
+ <${Button} light=${State.Chan.Value == 0} inactive=${State.Chan.Value == 0} onClick=${()=>Dispatch({Name:"Chan", Data:-1})}>Left + <${Button} light=${State.Chan.Value == 1} inactive=${State.Chan.Value == 1} onClick=${()=>Dispatch({Name:"Chan", Data:1})}>Right +
+
+
Frequency
+
${Store.ColumnMapping[State.Freq.Value][0]}
+ <${Button} disabled=${State.Freq.Value == State.Freq.Min} onClick=${()=>Dispatch({Name:"Freq", Data:-1})}>- + <${Button} disabled=${State.Freq.Value == State.Freq.Max} onClick=${()=>Dispatch({Name:"Freq", Data:1})}>+ +
+
+
Stimulus
+
${State.Stim.Value}
+ <${Button} disabled=${State.Stim.Value == State.Stim.Min} onClick=${()=>Dispatch({Name:"Stim", Data:-1})}>- + <${Button} disabled=${State.Stim.Value == State.Stim.Max} onClick=${()=>Dispatch({Name:"Stim", Data:1})}>+ +
+
+
Mark
+ <${Button} onClick=${()=>Dispatch({Name:"Mark", Data:true })}>Response + <${Button} onClick=${()=>Dispatch({Name:"Mark", Data:false})}>No Response + <${Button} onClick=${()=>Dispatch({Name:"Mark", Data:null })} disabled=${State.Live.Mark == undefined}>Clear +
+ `; +}; + +/** @type {BasicElement} */ +export const Audiogram =()=> +{ + const [State] = Store.Consumer(); + + const testMarksL = State.Draw.TestL.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false}/>`); + const userMarksL = State.Draw.UserL.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false} classes=${State.Live.Mark == p.Mark ? "stroke-bold":""}/>`); + const testMarksR = State.Draw.TestR.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} />`); + const userMarksR = State.Draw.UserR.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} classes=${State.Live.Mark == p.Mark ? "stroke-bold":""}/>`); + + const testLinesL = State.Draw.TestL.Paths.map( p=>html``); + const userLinesL = State.Draw.UserL.Paths.map( p=>html``); + const testLinesR = State.Draw.TestR.Paths.map( p=>html``); + const userLinesR = State.Draw.UserR.Paths.map( p=>html``); + + return html` + ${testMarksL}${testLinesL} + ${testMarksR}${testLinesR} + ${userMarksL}${userLinesL} + ${userMarksR}${userLinesR} + + + + + + + + + + + + `; +}; + /** @type {BasicElement} */ export function Chart({children}) { @@ -78,7 +161,6 @@ export function Chart({children}) `; } - /** @type {Record} */ const Glyph = { Arrow:()=> html` @@ -105,4 +187,4 @@ export const Mark =({right, response, x, y, classes})=> ${ !response && html`<${Glyph.Arrow}/>` } `; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/store.d.ts b/store.d.ts index 7d5e7f7..30bb157 100644 --- a/store.d.ts +++ b/store.d.ts @@ -26,7 +26,8 @@ declare namespace Store { Stim: Range; Live: Context; Draw: DrawChart; - Tests: Array; + TestIndex: number; + Test: Array; }; type ActionMark = { Name: "Mark"; Data: boolean | null }; diff --git a/store.test.ts b/store.test.ts index aa2b479..39c1ccd 100644 --- a/store.test.ts +++ b/store.test.ts @@ -18,7 +18,7 @@ let state:Store.State = { TestL:{Points:[], Paths:[]}, TestR:{Points:[], Paths:[]} }, - Tests: [ + Test: [ { Name: "Patient A Asymmetric Notch", Plot: @@ -42,8 +42,8 @@ Deno.test("Initialize", async(t)=> await t.step("A test exists with 500 and 1k hz plots", ()=> { - assertEquals(state.Tests.length > 0, true); - const test = state.Tests[0]; + assertEquals(state.Test.length > 0, true); + const test = state.Test[0]; assertEquals(test.Plot.length > 1, true); assertEquals(test.Plot[0].Hz, 500); assertEquals(test.Plot[1].Hz, 1000); @@ -67,7 +67,7 @@ Deno.test("Initialize", async(t)=> await t.step("Live context values are correct", ()=> { - assertEquals(state.Live.Test, state.Tests[0]); + assertEquals(state.Live.Test, state.Test[0]); assertEquals(state.Live.Freq?.Hz, ColumnMapping[state.Freq.Value][0]); assertEquals(state.Live.Mark, undefined, "(User) Mark is undefined"); }); @@ -120,7 +120,7 @@ Deno.test("Make Marks", async(t)=> await t.step("Live context values are correct", ()=> { - assertEquals(state.Live.Test, state.Tests[0]); + assertEquals(state.Live.Test, state.Test[0]); assertEquals(state.Live.Freq?.Hz, ColumnMapping[state.Freq.Value][0]); assertEquals(state.Live.Mark?.Stim, state.Stim.Value); });