state started

This commit is contained in:
Seth Trowbridge 2022-11-27 23:56:37 -05:00
parent 2d023fade1
commit 1336ad6d63
5 changed files with 130 additions and 955 deletions

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"deno.enable": true,
"deno.unstable": true
}

10
app.js
View File

@ -3,6 +3,7 @@ import * as TW from "https://esm.sh/@twind/core@1.0.1";
import TWPreTail from "https://esm.sh/@twind/preset-tailwind@1.0.1"; import TWPreTail from "https://esm.sh/@twind/preset-tailwind@1.0.1";
import TWPreAuto from "https://esm.sh/@twind/preset-autoprefix@1.0.1"; import TWPreAuto from "https://esm.sh/@twind/preset-autoprefix@1.0.1";
/** @type {TW.TwindConfig} */
const Configure = { const Configure = {
theme: theme:
{ {
@ -42,7 +43,8 @@ const Configure = {
"stroke-draw", "stroke-draw",
{ {
"vector-effect": "non-scaling-stroke", "vector-effect": "non-scaling-stroke",
"stroke-linecap":"square" "stroke-linecap": "square",
"fill": "none"
}, },
], ],
[ [
@ -77,8 +79,10 @@ render(html`
<${UI.Button} inactive>Right<//> <${UI.Button} inactive>Right<//>
<${UI.Button} disabled>Right<//> <${UI.Button} disabled>Right<//>
<${UI.Chart}> <${UI.Chart}>
<svg class="overflow-visible stroke(blue-700 bold draw)"> <svg class="absolute top-0 w-full h-full overflow-visible stroke(blue-700 bold draw)">
<${UI.Mark} /> <${UI.Mark} right=${true} x=${"20%"} y="20%" />
<${UI.Mark} right=${false} x=${"10%"} y="20%" response=${true} />
<${UI.Mark} right=${false}/>
</svg> </svg>
<//> <//>
`, ShadowDiv); `, ShadowDiv);

File diff suppressed because one or more lines are too long

120
store.js
View File

@ -1,31 +1,109 @@
//@ts-check //@ts-check
/** @typedef {[f1:ListEntry, f2:ListEntry, f3:ListEntry, f4:ListEntry, f5:ListEntry, f6:ListEntry, f7:ListEntry]} FreqList */
/** @typedef {number|TestMark} ListEntry */
/** @typedef {{Name:string, Sample:{Left:FreqList, Right:FreqList}, Answer?:{Left:FreqList, Right:FreqList}}} Test */
/** @typedef {{Stim:number|null, Resp:boolean}|null} TestMark*/
/** @type FreqList */ const size = 100/6;
export const Frequencies = [500, 1000, 2000, 3000, 4000, 6000, 8000]; /** @typedef {[frequency:number, position:number, normal:boolean]} ColumnMapping */
/** @type Array<Test> */ /** @type {Array<ColumnMapping>} */
export const Tests = [ export const ColumnMapping = [
[ 125, size*0.0, true ],
[ 250, size*1.0, true ],
[ 500, size*2.0, true ],
[1000, size*3.0, true ],
[2000, size*4.0, true ],
[3000, size*4.5, false],
[4000, size*5.0, true ],
[6000, size*5.5, false],
[8000, size*6.0, true ]
];
/** @type {(inFrequency:number)=>ColumnMapping|false} */
export const ColumnLookup =(inFrequency)=>
{
for(let i=0; i<ColumnMapping.length; i++)
{
const map = ColumnMapping[i];
if(map[0] == inFrequency){ return map; }
}
return false;
}
/** @typedef {{Stim:number, Resp:boolean}} TestFrequencySample */
/** @typedef {{Hz:number, TestL:TestFrequencySample, TestR:TestFrequencySample, UserL?:TestFrequencySample, UserR?:TestFrequencySample}} TestFrequency */
/** @typedef {{Name:string, Plot:Array<TestFrequency>}} Test */
/** @typedef {{Test?:Test, Freq?:TestFrequency, Mark?:TestFrequencySample}} Context */
/** @typedef {{Chan:"left"|"right", Freq:number, Stim:number, Selection:Context, Tests:Array<Test>}} State */
/** @type {State} */
export const Initial =
{
Chan: "left",
Freq: 3,
Stim: 30,
Selection:
{
Test: undefined,
Freq: undefined,
Mark: undefined
},
Tests: [
{ {
Name: "Patient A Asymmetric Notch", Name: "Patient A Asymmetric Notch",
Sample:{ Plot:
Left:[15, 10, 15, 30, 40, 35, 20], [
Right:[10, 10, 20, 40, 55, 40, 15] { Hz: 500, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 50, Resp: true } },
{ Hz: 1000, TestL: { Stim: 50, Resp: true }, TestR: { Stim: 55, Resp: true } }
]
} }
} ]
];
export const Controls =
{
Test:0,
Channel: "left",
Frequency: 1,
Stimulus: 30
}; };
function Reducer(inState, inAction) /** @typedef {{Name:"Mark", Data:boolean|undefined}} ActionMark */
/** @typedef {{Name:"Test", Data:number}} ActionTest*/
/** @typedef {ActionMark|ActionTest} Action */
/** @typedef {(inState:State, inAction:Action)=>State} Reducer */
/** @type {Reducer} */
export function Reducer(inState, inAction)
{
const clone = {...inState};
switch(inAction.Name)
{
case "Test" :
{ {
let selTest = clone.Tests[inAction.Data];
let selFreq = undefined;
let selMark = undefined;
const column = ColumnLookup(clone.Freq);
if(column)
{
let hz = column[0];
let plot;
for(let i=0; i<selTest.Plot.length; i++)
{
plot = selTest.Plot[i];
if(plot.Hz == hz)
{
selFreq = plot;
if(clone.Chan == "left" && selFreq.UserL)
{
selMark = selFreq.UserL;
}
else if(clone.Chan == "right" && selFreq.UserR)
{
selMark = selFreq.UserR;
}
}
}
}
const freq = test.Plot[]
//clone.Selection = {...clone.Selection, Test:clone.Tests[inAction.Data]}
break;
}
case "Mark" :
{
if(clone.Test)
{
clone.Test.Plot
}
}
}
return clone;
} }

46
ui.js
View File

@ -1,10 +1,11 @@
//@ts-check //@ts-check
import React from "https://esm.sh/preact@10.11.3/compat"; import React from "https://esm.sh/preact@10.11.3/compat";
/// <reference types="https://esm.sh/v99/htm@3.1.1/preact/index.d.ts"/>
import { html } from "https://esm.sh/htm@3.1.1/preact"; import { html } from "https://esm.sh/htm@3.1.1/preact";
import { ColumnMapping, ColumnLookup } from "./store.js";
/** @typedef {({children}:{children:React.ReactNode})=>JSX.Element} BasicElement */ /** @typedef {({children}:{children:React.ReactNode})=>JSX.Element} BasicElement */
/** @type {({children, icon, light, disabled, inactive}:{children:React.ReactNode, icon?:JSX.Element, light:boolean, disabled:boolean, inactive:boolean})=>JSX.Element} */
export function Button({children, icon, light, disabled, inactive}) export function Button({children, icon, light, disabled, inactive})
{ {
const [LightGet, LightSet] = React.useState(light); const [LightGet, LightSet] = React.useState(light);
@ -38,36 +39,23 @@ export function Button({children, icon, light, disabled, inactive})
/** @type {BasicElement} */ /** @type {BasicElement} */
export function Chart({children}) export function Chart({children})
{ {
const inset = 20 const inset = 20;
/** @type {Array<JSX.Element>} */
const size = 1/6; const rules = [];
/** @type {Record<string, [position:number, normal:boolean]>} */ ColumnMapping.forEach(([label, position, normal])=>
const rulesXMapping = {
"125": [size*0.0, true ],
"250": [size*1.0, true ],
"500": [size*2.0, true ],
"1000": [size*3.0, true ],
"2000": [size*4.0, true ],
"3000": [size*4.5, false],
"4000": [size*5.0, true ],
"6000": [size*5.5, false],
"8000": [size*6.0, true ]
};
const rulesX = Object.entries(rulesXMapping).map(([label, [position, normal]])=>
{ {
return html` rules.push(html`
<span class="block absolute top-[-${inset}px] left-[${position*100}%] w-0 h-[calc(100%+${inset*2}px)] border-r(1 slate-400) ${!normal && "border-dashed"}"> <span class="block absolute top-[-${inset}px] left-[${position}%] w-0 h-[calc(100%+${inset*2}px)] border-r(1 slate-400) ${!normal && "border-dashed"}">
<span class="block absolute top-0 left-0 -translate-x-1/2 -translate-y-full pb-${normal ? 4 : 1}">${label}</span> <span class="block absolute top-0 left-0 -translate-x-1/2 -translate-y-full pb-${normal ? 4 : 1}">${label}</span>
</span>`; </span>`);
}); });
const rulesY = [];
const rulesYMin = -10; const dbMin = -10;
const rulesYMax = 120; const dbMax = 120;
for(let db = rulesYMin; db <= rulesYMax; db+=10) for(let db = dbMin; db <= dbMax; db+=10)
{ {
const percent = ((db-rulesYMin) / (rulesYMax-rulesYMin))*100; rules.push(html`
rulesY.push(html` <span class="block absolute left-[-${inset}px] top-[${((db-dbMin) / (dbMax-dbMin))*100}%] h-0 w-[calc(100%+${inset*2}px)] border-b(${db == 0 ? "2 black" : "1 slate-400"})">
<span class="block absolute left-[-${inset}px] top-[${percent}%] h-0 w-[calc(100%+${inset*2}px)] border-b(${db == 0 ? "2 black" : "1 slate-400"})">
<span class="block absolute top-0 left-0 -translate-x-full -translate-y-1/2 pr-2">${db}</span> <span class="block absolute top-0 left-0 -translate-x-full -translate-y-1/2 pr-2">${db}</span>
</span> </span>
`); `);
@ -83,8 +71,7 @@ export function Chart({children})
</span> </span>
<div class=${`relative top-[${inset}px] left-[${inset}px] w-[calc(100%-${inset*2}px)] h-[calc(100%-${inset*2}px)]`}> <div class=${`relative top-[${inset}px] left-[${inset}px] w-[calc(100%-${inset*2}px)] h-[calc(100%-${inset*2}px)]`}>
<span class="block absolute top-0 left-[-${inset}px] w-[calc(100%+${inset*2}px)] h-[27%] bg-black opacity-10"></span> <span class="block absolute top-0 left-[-${inset}px] w-[calc(100%+${inset*2}px)] h-[27%] bg-black opacity-10"></span>
${ rulesX } ${ rules }
${ rulesY }
<div class="absolute top-0 left-0 w-full h-full"> <div class="absolute top-0 left-0 w-full h-full">
${ children } ${ children }
</div> </div>
@ -94,6 +81,7 @@ export function Chart({children})
`; `;
} }
/** @type {Record<string, BasicElement>} */ /** @type {Record<string, BasicElement>} */
const Glyph = { const Glyph = {
Arrow:({children})=> html` Arrow:({children})=> html`