@decidables/detectable-elements 0.0.3

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/LICENSE.md +1112 -0
  3. package/README.md +1218 -0
  4. package/lib/detectableElements.esm.js +18385 -0
  5. package/lib/detectableElements.esm.js.map +1 -0
  6. package/lib/detectableElements.esm.min.js +13 -0
  7. package/lib/detectableElements.esm.min.js.map +1 -0
  8. package/lib/detectableElements.umd.js +18413 -0
  9. package/lib/detectableElements.umd.js.map +1 -0
  10. package/lib/detectableElements.umd.min.js +13 -0
  11. package/lib/detectableElements.umd.min.js.map +1 -0
  12. package/package.json +58 -0
  13. package/src/components/detectable-control.js +272 -0
  14. package/src/components/detectable-response.js +414 -0
  15. package/src/components/detectable-table.js +602 -0
  16. package/src/components/index.js +7 -0
  17. package/src/components/rdk-task.js +586 -0
  18. package/src/components/roc-space.js +1220 -0
  19. package/src/components/sdt-model.js +1835 -0
  20. package/src/detectable-element.js +121 -0
  21. package/src/equations/dc2far.js +182 -0
  22. package/src/equations/dc2hr.js +191 -0
  23. package/src/equations/facr2far.js +120 -0
  24. package/src/equations/hm2hr.js +121 -0
  25. package/src/equations/hmfacr2acc.js +161 -0
  26. package/src/equations/hrfar2c.js +179 -0
  27. package/src/equations/hrfar2d.js +162 -0
  28. package/src/equations/index.js +8 -0
  29. package/src/equations/sdt-equation.js +141 -0
  30. package/src/examples/double-interactive.js +171 -0
  31. package/src/examples/human.js +184 -0
  32. package/src/examples/index.js +6 -0
  33. package/src/examples/interactive.js +131 -0
  34. package/src/examples/model.js +203 -0
  35. package/src/examples/sdt-example.js +76 -0
  36. package/src/examples/unequal.js +43 -0
  37. package/src/index.js +6 -0
@@ -0,0 +1,414 @@
1
+
2
+ import {html, css} from 'lit';
3
+
4
+ import '@decidables/decidables-elements/button';
5
+
6
+ import DetectableElement from '../detectable-element';
7
+
8
+ /*
9
+ DetectableResponse element
10
+ <detectable-response>
11
+
12
+ Attributes:
13
+
14
+ */
15
+ export default class DetectableResponse extends DetectableElement {
16
+ static get properties() {
17
+ return {
18
+ feedback: {
19
+ attribute: 'feedback',
20
+ type: String,
21
+ reflect: true,
22
+ },
23
+ trial: {
24
+ attribute: 'trial',
25
+ type: Boolean,
26
+ reflect: true,
27
+ },
28
+ payoff: {
29
+ attribute: 'payoff',
30
+ type: String,
31
+ reflect: true,
32
+ },
33
+ hPayoff: {
34
+ attribute: 'hit-payoff',
35
+ type: Number,
36
+ reflect: true,
37
+ },
38
+ mPayoff: {
39
+ attribute: 'miss-payoff',
40
+ type: Number,
41
+ reflect: true,
42
+ },
43
+ faPayoff: {
44
+ attribute: 'false-alarm-payoff',
45
+ type: Number,
46
+ reflect: true,
47
+ },
48
+ crPayoff: {
49
+ attribute: 'correct-rejection-payoff',
50
+ type: Number,
51
+ reflect: true,
52
+ },
53
+ nrPayoff: {
54
+ attribute: 'no-response-payoff',
55
+ type: Number,
56
+ reflect: true,
57
+ },
58
+
59
+ state: {
60
+ attribute: false,
61
+ type: String,
62
+ reflect: false,
63
+ },
64
+ trialCount: {
65
+ attribute: false,
66
+ type: Number,
67
+ reflect: false,
68
+ },
69
+ trialTotal: {
70
+ attribute: false,
71
+ type: Number,
72
+ reflect: false,
73
+ },
74
+ };
75
+ }
76
+
77
+ constructor() {
78
+ super();
79
+
80
+ // Attributes
81
+ this.feedbacks = ['none', 'accuracy', 'outcome']; // Possible values for 'feedback'
82
+ this.feedback = 'outcome'; // What feedback to display
83
+ this.trial = false; // Show trial count?
84
+ this.payoffs = ['none', 'trial', 'total']; // Possible types of 'payoff' info
85
+ this.payoff = 'none'; // What payoff info to display
86
+
87
+ this.hPayoff = 0; // Hit payoff
88
+ this.mPayoff = 0; // Miss payoff
89
+ this.crPayoff = 0; // Correct Rejection payoff
90
+ this.faPayoff = 0; // False Alarm payoff
91
+ this.nrPayoff = 0; // No Response payoff
92
+
93
+ // Properties
94
+ this.states = ['off', 'waiting', 'feedback']; // Possible states
95
+ this.state = 'off'; // Current state
96
+
97
+ this.trialCount = 0; // Current trial
98
+ this.trialTotal = 0; // Total trials
99
+
100
+ // Private
101
+ this.signals = ['present', 'absent']; // Possible values of 'signal'
102
+ this.signal = undefined; // Signal for current trial
103
+ this.responses = ['present', 'absent']; // Possible values of 'response'
104
+ this.response = undefined; // Response for current trial
105
+ this.outcomes = ['h', 'm', 'fa', 'cr', 'nr']; // Possible values of 'outcome'
106
+ this.outcome = undefined; // Outcome for current trial
107
+ this.accuracies = ['c', 'e', 'nr']; // Possible values of 'accuracy'
108
+ this.accuracy = undefined; // Accuracy for current trial
109
+
110
+ this.h = 0; // Count of Hits
111
+ this.m = 0; // Count of Misses
112
+ this.cr = 0; // Count of Correct Rejections
113
+ this.fa = 0; // Count of False Alarms
114
+
115
+ this.c = 0; // Count of Correct trials
116
+ this.e = 0; // Count of Error trials
117
+
118
+ this.nr = 0; // Count of No Response trials
119
+ }
120
+
121
+ get trialPayoff() {
122
+ switch (this.outcome) {
123
+ case 'h':
124
+ return this.hPayoff;
125
+ case 'm':
126
+ return this.mPayoff;
127
+ case 'fa':
128
+ return this.faPayoff;
129
+ case 'cr':
130
+ return this.crPayoff;
131
+ case 'nr':
132
+ return this.nrPayoff;
133
+ default:
134
+ return undefined;
135
+ }
136
+ }
137
+
138
+ get totalPayoff() {
139
+ return ((this.h * this.hPayoff)
140
+ + (this.m * this.mPayoff)
141
+ + (this.cr * this.crPayoff)
142
+ + (this.fa * this.faPayoff)
143
+ + (this.nr * this.nrPayoff));
144
+ }
145
+
146
+ start(signal, trial) {
147
+ this.trialCount = trial;
148
+ this.state = 'waiting';
149
+ this.signal = signal;
150
+ this.response = undefined;
151
+ this.outcome = undefined;
152
+ }
153
+
154
+ stop() {
155
+ this.state = 'feedback';
156
+ if (this.response === undefined) {
157
+ this.outcome = 'nr';
158
+ this.nr += 1;
159
+ this.accuracy = 'nr';
160
+ }
161
+ }
162
+
163
+ present() {
164
+ this.responded('present');
165
+ }
166
+
167
+ absent() {
168
+ this.responded('absent');
169
+ }
170
+
171
+ responded(response) {
172
+ this.state = 'feedback';
173
+ this.response = response;
174
+ if (this.signal === 'present' && this.response === 'present') {
175
+ this.outcome = 'h';
176
+ this.h += 1;
177
+ this.accuracy = 'c';
178
+ this.c += 1;
179
+ } else if (this.signal === 'present' && this.response === 'absent') {
180
+ this.outcome = 'm';
181
+ this.m += 1;
182
+ this.accuracy = 'e';
183
+ this.e += 1;
184
+ } else if (this.signal === 'absent' && this.response === 'present') {
185
+ this.outcome = 'fa';
186
+ this.fa += 1;
187
+ this.accuracy = 'e';
188
+ this.e += 1;
189
+ } else if (this.signal === 'absent' && this.response === 'absent') {
190
+ this.outcome = 'cr';
191
+ this.cr += 1;
192
+ this.accuracy = 'c';
193
+ this.c += 1;
194
+ }
195
+
196
+ this.dispatchEvent(new CustomEvent('detectable-response', {
197
+ detail: {
198
+ trial: this.trialCount,
199
+ signal: this.signal,
200
+ response: this.response,
201
+ outcome: this.outcome,
202
+ payoff: this.trialPayoff,
203
+ h: this.h,
204
+ m: this.m,
205
+ fa: this.fa,
206
+ cr: this.cr,
207
+ nr: this.nr,
208
+ totalPayoff: this.totalPayoff,
209
+ },
210
+ bubbles: true,
211
+ }));
212
+ }
213
+
214
+ reset() {
215
+ this.state = 'off';
216
+ this.trialCount = 0;
217
+ this.signal = undefined;
218
+ this.response = undefined;
219
+ this.outcome = undefined;
220
+ this.accuracy = undefined;
221
+ this.h = 0;
222
+ this.m = 0;
223
+ this.cr = 0;
224
+ this.fa = 0;
225
+ this.nr = 0;
226
+ this.c = 0;
227
+ this.e = 0;
228
+ }
229
+
230
+ static get styles() {
231
+ return [
232
+ super.styles,
233
+ css`
234
+ :host {
235
+ display: inline-block;
236
+ }
237
+
238
+ /* Overall container */
239
+ .holder {
240
+ display: flex;
241
+
242
+ flex-direction: row;
243
+ }
244
+
245
+ /* Response buttons */
246
+ .responses {
247
+ display: flex;
248
+
249
+ flex-direction: column;
250
+
251
+ align-items: stretch;
252
+ justify-content: center;
253
+ }
254
+
255
+ .waiting[disabled] {
256
+ --decidables-button-background-color: var(---color-element-enabled);
257
+ }
258
+
259
+ .selected[disabled][name="present"] {
260
+ --decidables-button-background-color: var(---color-present);
261
+ }
262
+
263
+ .selected[disabled][name="absent"] {
264
+ --decidables-button-background-color: var(---color-absent);
265
+ }
266
+
267
+ /* Feedback messages */
268
+ .feedbacks {
269
+ display: flex;
270
+
271
+ flex-direction: column;
272
+
273
+ justify-content: center;
274
+ }
275
+
276
+ /* Trial feedback */
277
+ .trial {
278
+ text-align: center;
279
+ }
280
+
281
+ .trial .label {
282
+ font-weight: 600;
283
+ }
284
+
285
+ /* Outcome feedback */
286
+ .feedback {
287
+ display: flex;
288
+
289
+ flex-direction: column;
290
+
291
+ align-items: center;
292
+ justify-content: center;
293
+
294
+ width: 6rem;
295
+ height: 3.5rem;
296
+ padding: 0.375rem 0.75rem;
297
+ margin: 0.25rem;
298
+
299
+ text-align: center;
300
+
301
+ background-color: var(---color-element-background);
302
+ border: 1px solid var(---color-element-border);
303
+ }
304
+
305
+ .feedback.h {
306
+ background-color: var(---color-h-light);
307
+ }
308
+
309
+ .feedback.m {
310
+ background-color: var(---color-m-light);
311
+ }
312
+
313
+ .feedback.fa {
314
+ background-color: var(---color-fa-light);
315
+ }
316
+
317
+ .feedback.cr {
318
+ background-color: var(---color-cr-light);
319
+ }
320
+
321
+ .feedback.nr {
322
+ background-color: var(---color-nr-light);
323
+ }
324
+
325
+ .feedback.c {
326
+ background-color: var(---color-correct-light);
327
+ }
328
+
329
+ .feedback.e {
330
+ color: var(---color-text-inverse);
331
+
332
+ background-color: var(---color-error-light);
333
+ }
334
+
335
+ .feedback .outcome {
336
+ font-weight: 600;
337
+ line-height: 1.15;
338
+ }
339
+
340
+ :host([payoff="trial"]) .feedback,
341
+ :host([payoff="total"]) .feedback {
342
+ height: 4rem;
343
+ }
344
+
345
+ /* Payoff feedback */
346
+ .payoff {
347
+ text-align: center;
348
+ }
349
+
350
+ .payoff .label {
351
+ font-weight: 600;
352
+ }
353
+ `,
354
+ ];
355
+ }
356
+
357
+ render() {
358
+ return html`
359
+ <div class="holder">
360
+ <div class="responses">
361
+ <decidables-button name="present" class=${(this.state === 'feedback' && this.response === 'present') ? 'selected' : ((this.state === 'waiting') ? 'waiting' : '')} ?disabled=${this.state !== 'waiting' || this.interactive !== true} @click=${this.present.bind(this)}>Present</decidables-button>
362
+ <decidables-button name="absent" class=${(this.state === 'feedback' && this.response === 'absent') ? 'selected' : ((this.state === 'waiting') ? 'waiting' : '')} ?disabled=${this.state !== 'waiting' || this.interactive !== true} @click=${this.absent.bind(this)}>Absent</decidables-button>
363
+ </div>
364
+ ${(this.trial || this.feedback !== 'none' || this.payoff === 'total')
365
+ ? html`
366
+ <div class="feedbacks">
367
+ ${(this.trial)
368
+ ? html`
369
+ <div class="trial">
370
+ <span class="label">Trial: </span><span class="count">${this.trialCount}</span><span class="of"> of </span><span class="total">${this.trialTotal}</span>
371
+ </div>`
372
+ : html``}
373
+ ${(this.feedback !== 'none')
374
+ ? html`
375
+ <div class=${`feedback ${(this.state === 'feedback')
376
+ ? (this.feedback === 'outcome')
377
+ ? this.outcome
378
+ : this.accuracy
379
+ : ''}`}>
380
+ ${(this.state === 'feedback')
381
+ ? (this.feedback === 'outcome')
382
+ ? (this.outcome === 'h')
383
+ ? html`<span class="outcome">Hit</span>`
384
+ : (this.outcome === 'm')
385
+ ? html`<span class="outcome">Miss</span>`
386
+ : (this.outcome === 'fa')
387
+ ? html`<span class="outcome">False<br>Alarm</span>`
388
+ : (this.outcome === 'cr')
389
+ ? html`<span class="outcome">Correct<br>Rejection</span>`
390
+ : html`<span class="outcome">No<br>Response</span>`
391
+ : (this.accuracy === 'c')
392
+ ? html`<span class="outcome">Correct</span>`
393
+ : (this.accuracy === 'e')
394
+ ? html`<span class="outcome">Error</span>`
395
+ : html`<span class="outcome">No<br>Response</span>`
396
+ : ''}
397
+ ${(this.payoff === 'trial' || this.payoff === 'total')
398
+ ? html`<span class="payoff">${this.trialPayoff}</span>`
399
+ : html``}
400
+ </div>`
401
+ : html``}
402
+ ${(this.payoff === 'total')
403
+ ? html`
404
+ <div class="payoff">
405
+ <span class="label">Total: </span><span class="value">${this.totalPayoff}</span>
406
+ </div>`
407
+ : html``}
408
+ </div>`
409
+ : html``}
410
+ </div>`;
411
+ }
412
+ }
413
+
414
+ customElements.define('detectable-response', DetectableResponse);