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 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:
|
||||||
{
|
{
|
||||||
@ -41,8 +42,9 @@ 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);
|
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
|
//@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 ],
|
||||||
Name: "Patient A Asymmetric Notch",
|
[ 250, size*1.0, true ],
|
||||||
Sample:{
|
[ 500, size*2.0, true ],
|
||||||
Left:[15, 10, 15, 30, 40, 35, 20],
|
[1000, size*3.0, true ],
|
||||||
Right:[10, 10, 20, 40, 55, 40, 15]
|
[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 Controls =
|
export const ColumnLookup =(inFrequency)=>
|
||||||
{
|
{
|
||||||
Test:0,
|
for(let i=0; i<ColumnMapping.length; i++)
|
||||||
Channel: "left",
|
{
|
||||||
Frequency: 1,
|
const map = ColumnMapping[i];
|
||||||
Stimulus: 30
|
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
|
//@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`
|
||||||
|
Loading…
Reference in New Issue
Block a user