state started
This commit is contained in:
parent
2d023fade1
commit
1336ad6d63
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.unstable": true
|
||||
}
|
12
app.js
12
app.js
@ -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 TWPreAuto from "https://esm.sh/@twind/preset-autoprefix@1.0.1";
|
||||
|
||||
/** @type {TW.TwindConfig} */
|
||||
const Configure = {
|
||||
theme:
|
||||
{
|
||||
@ -41,8 +42,9 @@ const Configure = {
|
||||
[
|
||||
"stroke-draw",
|
||||
{
|
||||
"vector-effect":"non-scaling-stroke",
|
||||
"stroke-linecap":"square"
|
||||
"vector-effect": "non-scaling-stroke",
|
||||
"stroke-linecap": "square",
|
||||
"fill": "none"
|
||||
},
|
||||
],
|
||||
[
|
||||
@ -77,8 +79,10 @@ render(html`
|
||||
<${UI.Button} inactive>Right<//>
|
||||
<${UI.Button} disabled>Right<//>
|
||||
<${UI.Chart}>
|
||||
<svg class="overflow-visible stroke(blue-700 bold draw)">
|
||||
<${UI.Mark} />
|
||||
<svg class="absolute top-0 w-full h-full overflow-visible stroke(blue-700 bold draw)">
|
||||
<${UI.Mark} right=${true} x=${"20%"} y="20%" />
|
||||
<${UI.Mark} right=${false} x=${"10%"} y="20%" response=${true} />
|
||||
<${UI.Mark} right=${false}/>
|
||||
</svg>
|
||||
<//>
|
||||
`, ShadowDiv);
|
899
squarespace.html
899
squarespace.html
File diff suppressed because one or more lines are too long
122
store.js
122
store.js
@ -1,31 +1,109 @@
|
||||
//@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 */
|
||||
export const Frequencies = [500, 1000, 2000, 3000, 4000, 6000, 8000];
|
||||
/** @type Array<Test> */
|
||||
export const Tests = [
|
||||
{
|
||||
Name: "Patient A Asymmetric Notch",
|
||||
Sample:{
|
||||
Left:[15, 10, 15, 30, 40, 35, 20],
|
||||
Right:[10, 10, 20, 40, 55, 40, 15]
|
||||
}
|
||||
}
|
||||
const size = 100/6;
|
||||
/** @typedef {[frequency:number, position:number, normal:boolean]} ColumnMapping */
|
||||
/** @type {Array<ColumnMapping>} */
|
||||
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 ]
|
||||
];
|
||||
|
||||
export const Controls =
|
||||
/** @type {(inFrequency:number)=>ColumnMapping|false} */
|
||||
export const ColumnLookup =(inFrequency)=>
|
||||
{
|
||||
Test:0,
|
||||
Channel: "left",
|
||||
Frequency: 1,
|
||||
Stimulus: 30
|
||||
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",
|
||||
Plot:
|
||||
[
|
||||
{ Hz: 500, TestL: { Stim: 30, Resp: true }, TestR: { Stim: 50, Resp: true } },
|
||||
{ Hz: 1000, TestL: { Stim: 50, Resp: true }, TestR: { Stim: 55, Resp: true } }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
48
ui.js
48
ui.js
@ -1,10 +1,11 @@
|
||||
//@ts-check
|
||||
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 */
|
||||
|
||||
/** @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})
|
||||
{
|
||||
const [LightGet, LightSet] = React.useState(light);
|
||||
@ -38,36 +39,23 @@ export function Button({children, icon, light, disabled, inactive})
|
||||
/** @type {BasicElement} */
|
||||
export function Chart({children})
|
||||
{
|
||||
const inset = 20
|
||||
|
||||
const size = 1/6;
|
||||
/** @type {Record<string, [position:number, normal:boolean]>} */
|
||||
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]])=>
|
||||
const inset = 20;
|
||||
/** @type {Array<JSX.Element>} */
|
||||
const rules = [];
|
||||
ColumnMapping.forEach(([label, position, normal])=>
|
||||
{
|
||||
return 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"}">
|
||||
rules.push(html`
|
||||
<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>`;
|
||||
</span>`);
|
||||
});
|
||||
const rulesY = [];
|
||||
const rulesYMin = -10;
|
||||
const rulesYMax = 120;
|
||||
for(let db = rulesYMin; db <= rulesYMax; db+=10)
|
||||
|
||||
const dbMin = -10;
|
||||
const dbMax = 120;
|
||||
for(let db = dbMin; db <= dbMax; db+=10)
|
||||
{
|
||||
const percent = ((db-rulesYMin) / (rulesYMax-rulesYMin))*100;
|
||||
rulesY.push(html`
|
||||
<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"})">
|
||||
rules.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 top-0 left-0 -translate-x-full -translate-y-1/2 pr-2">${db}</span>
|
||||
</span>
|
||||
`);
|
||||
@ -83,8 +71,7 @@ export function Chart({children})
|
||||
</span>
|
||||
<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>
|
||||
${ rulesX }
|
||||
${ rulesY }
|
||||
${ rules }
|
||||
<div class="absolute top-0 left-0 w-full h-full">
|
||||
${ children }
|
||||
</div>
|
||||
@ -94,6 +81,7 @@ export function Chart({children})
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
/** @type {Record<string, BasicElement>} */
|
||||
const Glyph = {
|
||||
Arrow:({children})=> html`
|
||||
|
Loading…
Reference in New Issue
Block a user