@decidables/accumulable-elements 0.1.3 → 0.2.0
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.
- package/CHANGELOG.md +20 -0
- package/README.md +72 -33
- package/lib/accumulableElements.esm.js +587 -282
- package/lib/accumulableElements.esm.js.map +1 -1
- package/lib/accumulableElements.esm.min.js +298 -121
- package/lib/accumulableElements.esm.min.js.map +1 -1
- package/lib/accumulableElements.umd.js +587 -282
- package/lib/accumulableElements.umd.js.map +1 -1
- package/lib/accumulableElements.umd.min.js +298 -121
- package/lib/accumulableElements.umd.min.js.map +1 -1
- package/package.json +4 -4
- package/src/components/accumulable-control.js +4 -4
- package/src/components/accumulable-response.js +6 -24
- package/src/components/ddm-fit-worker.js +2 -2
- package/src/components/ddm-fit.js +6 -4
- package/src/components/ddm-model.js +130 -62
- package/src/components/ddm-parameters.js +61 -4
- package/src/equations/azv2pc.js +35 -8
- package/src/equations/azvt02m.js +44 -10
- package/src/examples/human.js +156 -71
- package/src/examples/interactive.js +39 -9
- package/src/examples/model.js +95 -93
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decidables/accumulable-elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "accumulable-elements: Web Components for visualizing the Diffusion Decision Model",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web component",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"gulp": "^5.0.0"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@decidables/accumulable-math": "^0.
|
|
57
|
-
"@decidables/decidables-elements": "^0.
|
|
56
|
+
"@decidables/accumulable-math": "^0.2.0",
|
|
57
|
+
"@decidables/decidables-elements": "^0.5.0",
|
|
58
58
|
"@lit-labs/motion": "^1.0.7",
|
|
59
59
|
"@observablehq/plot": "^0.6.16",
|
|
60
60
|
"bayes.js": "https://github.com/akrawitz/bayes.js.git#commit=c7b091b75f85a86b6a3965a983b31e23d9ef456f",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"lit": "^3.2.1",
|
|
63
63
|
"regenerator-runtime": "^0.14.1"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "0320347d03a20fb478784fe296c82f11018c276b"
|
|
66
66
|
}
|
|
@@ -198,7 +198,7 @@ export default class AccumulableControl extends AccumulableElement {
|
|
|
198
198
|
render() {
|
|
199
199
|
return html`
|
|
200
200
|
<div class="holder">
|
|
201
|
-
${this.trials
|
|
201
|
+
${this.trials != null
|
|
202
202
|
? html`<decidables-slider class="trials" min="1" max="100" step="1" .value=${this.trials} @change=${this.setTrials.bind(this)} @input=${this.setTrials.bind(this)}>Trials</decidables-slider>`
|
|
203
203
|
: html``}
|
|
204
204
|
${this.resample
|
|
@@ -210,13 +210,13 @@ export default class AccumulableControl extends AccumulableElement {
|
|
|
210
210
|
</div>
|
|
211
211
|
`
|
|
212
212
|
: html``}
|
|
213
|
-
${this.duration
|
|
213
|
+
${this.duration != null
|
|
214
214
|
? html`<decidables-slider class="duration" min="10" max="2000" step="10" .value=${this.duration} @change=${this.setDuration.bind(this)} @input=${this.setDuration.bind(this)}>Duration</decidables-slider>`
|
|
215
215
|
: html``}
|
|
216
|
-
${this.coherence
|
|
216
|
+
${this.coherence != null
|
|
217
217
|
? html`<decidables-slider class="coherence" min="0" max="1" step=".01" .value=${this.coherence} @change=${this.setCoherence.bind(this)} @input=${this.setCoherence.bind(this)}>Coherence</decidables-slider>`
|
|
218
218
|
: html``}
|
|
219
|
-
${this.color
|
|
219
|
+
${this.color != null
|
|
220
220
|
? html`
|
|
221
221
|
<decidables-toggle class="color" @change=${this.chooseColor.bind(this)}>
|
|
222
222
|
<span slot="label">Emphasis</span>
|
|
@@ -95,9 +95,7 @@ export default class AccumulableResponse extends AccumulableElement {
|
|
|
95
95
|
this.startTime = undefined; // Start time of current trial
|
|
96
96
|
this.rt = undefined; // RT for current trial
|
|
97
97
|
|
|
98
|
-
this.
|
|
99
|
-
this.errorCount = 0; // Count of Error Trials
|
|
100
|
-
this.nrCount = 0; // Count of No Response trials
|
|
98
|
+
this.data = {};
|
|
101
99
|
|
|
102
100
|
this.trials = []; // Record of trials in block
|
|
103
101
|
this.alignState();
|
|
@@ -117,14 +115,13 @@ export default class AccumulableResponse extends AccumulableElement {
|
|
|
117
115
|
}
|
|
118
116
|
|
|
119
117
|
get totalPayoff() {
|
|
120
|
-
return ((this.correctCount * this.correctPayoff)
|
|
121
|
-
+ (this.errorCount * this.errorPayoff)
|
|
122
|
-
+ (this.nrCount * this.nrPayoff));
|
|
118
|
+
return ((this.data.correctCount * this.correctPayoff)
|
|
119
|
+
+ (this.data.errorCount * this.errorPayoff)
|
|
120
|
+
+ (this.data.nrCount * this.nrPayoff));
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
alignState() {
|
|
126
|
-
|
|
127
|
-
Object.assign(this, stats);
|
|
124
|
+
this.data = DDMMath.trials2stats(this.trials);
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
start(signal, trial) {
|
|
@@ -141,7 +138,6 @@ export default class AccumulableResponse extends AccumulableElement {
|
|
|
141
138
|
this.state = 'feedback';
|
|
142
139
|
if (this.response === undefined) {
|
|
143
140
|
this.outcome = 'nr';
|
|
144
|
-
this.nrCount += 1;
|
|
145
141
|
this.rt = undefined;
|
|
146
142
|
|
|
147
143
|
this.trials.push({
|
|
@@ -170,10 +166,8 @@ export default class AccumulableResponse extends AccumulableElement {
|
|
|
170
166
|
this.response = response;
|
|
171
167
|
if (this.signal === this.response) {
|
|
172
168
|
this.outcome = 'correct';
|
|
173
|
-
this.correctCount += 1;
|
|
174
169
|
} else if (this.signal !== this.response) {
|
|
175
170
|
this.outcome = 'error';
|
|
176
|
-
this.errorCount += 1;
|
|
177
171
|
}
|
|
178
172
|
this.trials.push({
|
|
179
173
|
trial: this.trialCount,
|
|
@@ -194,16 +188,7 @@ export default class AccumulableResponse extends AccumulableElement {
|
|
|
194
188
|
outcome: this.outcome,
|
|
195
189
|
payoff: this.trialPayoff,
|
|
196
190
|
|
|
197
|
-
|
|
198
|
-
errorCount: this.errorCount,
|
|
199
|
-
nrCount: this.nrCount,
|
|
200
|
-
accuracy: this.accuracy,
|
|
201
|
-
meanRT: this.meanRT,
|
|
202
|
-
correctMeanRT: this.correctMeanRT,
|
|
203
|
-
errorMeanRT: this.errorMeanRT,
|
|
204
|
-
sdRT: this.sdRT,
|
|
205
|
-
correctSDRT: this.correctSDRT,
|
|
206
|
-
errorSDRT: this.errorSDRT,
|
|
191
|
+
data: this.data,
|
|
207
192
|
|
|
208
193
|
totalPayoff: this.totalPayoff,
|
|
209
194
|
},
|
|
@@ -218,9 +203,6 @@ export default class AccumulableResponse extends AccumulableElement {
|
|
|
218
203
|
this.signal = undefined;
|
|
219
204
|
this.response = undefined;
|
|
220
205
|
this.outcome = undefined;
|
|
221
|
-
this.correctCount = 0;
|
|
222
|
-
this.errorCount = 0;
|
|
223
|
-
this.nrCount = 0;
|
|
224
206
|
|
|
225
207
|
this.trials = [];
|
|
226
208
|
this.alignState();
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
import DDMMath from '@decidables/accumulable-math';
|
|
4
4
|
|
|
5
5
|
self.onmessage = (event) => {
|
|
6
|
-
const params = DDMMath.data2ez({...event.data, s: DDMMath.s});
|
|
6
|
+
const params = DDMMath.data2ez({...event.data, s: DDMMath.s.DEFAULT});
|
|
7
7
|
|
|
8
8
|
// ##### Arbitrary default values!!!
|
|
9
9
|
const a = !isNaN(params.a) ? params.a : 1.5;
|
|
10
10
|
const z = !isNaN(params.z) ? params.z : 0.5;
|
|
11
11
|
const v = !isNaN(params.v) ? params.v : 0.1;
|
|
12
12
|
const t0 = !isNaN(params.t0) ? params.t0 : 100;
|
|
13
|
-
const s = !isNaN(params.s) ? params.s : DDMMath.s;
|
|
13
|
+
const s = !isNaN(params.s) ? params.s : DDMMath.s.DEFAULT;
|
|
14
14
|
|
|
15
15
|
const predicted = {
|
|
16
16
|
accuracy: DDMMath.azv2pC(a, z, v),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import {html, css} from 'lit';
|
|
3
3
|
|
|
4
|
+
import DDMMath from '@decidables/accumulable-math';
|
|
5
|
+
|
|
4
6
|
// Special Web Worker import for rollup-plugin-web-worker-loader
|
|
5
7
|
import DDMFitWorker from 'web-worker:./ddm-fit-worker'; /* eslint-disable-line import/no-unresolved */
|
|
6
8
|
|
|
@@ -22,10 +24,10 @@ export default class DDMFit extends AccumulableElement {
|
|
|
22
24
|
constructor() {
|
|
23
25
|
super();
|
|
24
26
|
|
|
25
|
-
this.a =
|
|
26
|
-
this.z =
|
|
27
|
-
this.v =
|
|
28
|
-
this.t0 =
|
|
27
|
+
this.a = DDMMath.a.DEFAULT;
|
|
28
|
+
this.z = DDMMath.z.DEFAULT;
|
|
29
|
+
this.v = DDMMath.v.DEFAULT;
|
|
30
|
+
this.t0 = DDMMath.t0.DEFAULT;
|
|
29
31
|
|
|
30
32
|
this.observed = {};
|
|
31
33
|
this.predicted = {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import {css, html} from 'lit';
|
|
3
3
|
import * as d3 from 'd3';
|
|
4
4
|
|
|
5
5
|
import DDMMath from '@decidables/accumulable-math';
|
|
@@ -147,10 +147,10 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
147
147
|
this.human = false;
|
|
148
148
|
this.trials = 10;
|
|
149
149
|
|
|
150
|
-
this.a =
|
|
151
|
-
this.z =
|
|
152
|
-
this.v =
|
|
153
|
-
this.t0 =
|
|
150
|
+
this.a = DDMMath.a.DEFAULT;
|
|
151
|
+
this.z = DDMMath.z.DEFAULT;
|
|
152
|
+
this.v = DDMMath.v.DEFAULT;
|
|
153
|
+
this.t0 = DDMMath.t0.DEFAULT;
|
|
154
154
|
|
|
155
155
|
// this.s = null;
|
|
156
156
|
// this.sz = null;
|
|
@@ -218,7 +218,7 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
218
218
|
while ((path.at(-1).e > bounds.lower) && (path.at(-1).e < bounds.upper)) {
|
|
219
219
|
path.push({
|
|
220
220
|
t: path.at(-1).t + (this.precision * 1000),
|
|
221
|
-
e: path.at(-1).e + drift + DDMMath.s * random(),
|
|
221
|
+
e: path.at(-1).e + drift + DDMMath.s.DEFAULT * random(),
|
|
222
222
|
});
|
|
223
223
|
}
|
|
224
224
|
return path;
|
|
@@ -527,10 +527,25 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
527
527
|
|
|
528
528
|
.t0z .point {
|
|
529
529
|
fill: var(---color-element-emphasis);
|
|
530
|
+
stroke-width: 0;
|
|
530
531
|
|
|
531
532
|
r: 6px;
|
|
532
533
|
}
|
|
533
534
|
|
|
535
|
+
/* Make larger targets for touch users */
|
|
536
|
+
.interactive .touch {
|
|
537
|
+
stroke: #000000;
|
|
538
|
+
stroke-dasharray: none;
|
|
539
|
+
stroke-opacity: 0;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
@media (pointer: coarse) {
|
|
543
|
+
.interactive .touch {
|
|
544
|
+
stroke-linecap: round;
|
|
545
|
+
stroke-width: 12;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
534
549
|
.measure {
|
|
535
550
|
stroke-width: 2;
|
|
536
551
|
}
|
|
@@ -731,18 +746,18 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
731
746
|
// Clamp t0
|
|
732
747
|
t0 = (shift === 'z')
|
|
733
748
|
? timeScale.invert(event.subject.x)
|
|
734
|
-
: (t0 <
|
|
735
|
-
?
|
|
736
|
-
: (t0 >
|
|
737
|
-
?
|
|
749
|
+
: (t0 < DDMMath.t0.MIN)
|
|
750
|
+
? DDMMath.t0.MIN
|
|
751
|
+
: (t0 > DDMMath.t0.MAX)
|
|
752
|
+
? DDMMath.t0.MAX
|
|
738
753
|
: t0;
|
|
739
754
|
// Clamp z
|
|
740
755
|
z = (shift === 't0')
|
|
741
756
|
? (evidenceScale.invert(event.subject.y) + (this.a / 2)) / this.a
|
|
742
|
-
: (z <
|
|
743
|
-
?
|
|
744
|
-
: (z >
|
|
745
|
-
?
|
|
757
|
+
: (z < DDMMath.z.MIN)
|
|
758
|
+
? DDMMath.z.MIN
|
|
759
|
+
: (z > DDMMath.z.MAX)
|
|
760
|
+
? DDMMath.z.MAX
|
|
746
761
|
: z;
|
|
747
762
|
this.t0 = t0;
|
|
748
763
|
this.z = z;
|
|
@@ -777,10 +792,10 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
777
792
|
let v = ((evidenceScale.invert(event.y) - this.startingPoint)
|
|
778
793
|
/ (timeScale.invert(event.x) - this.t0)) * 1000;
|
|
779
794
|
// Clamp drift rate
|
|
780
|
-
v = (v <
|
|
781
|
-
?
|
|
782
|
-
: (v >
|
|
783
|
-
?
|
|
795
|
+
v = (v < DDMMath.v.MIN)
|
|
796
|
+
? DDMMath.v.MIN
|
|
797
|
+
: (v > DDMMath.v.MAX)
|
|
798
|
+
? DDMMath.v.MAX
|
|
784
799
|
: v;
|
|
785
800
|
this.v = v;
|
|
786
801
|
this.alignState();
|
|
@@ -806,20 +821,17 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
806
821
|
const element = event.currentTarget;
|
|
807
822
|
d3.select(element).classed('dragging', true);
|
|
808
823
|
})
|
|
809
|
-
.on('drag', (event
|
|
824
|
+
.on('drag', (event) => {
|
|
810
825
|
this.drag = true;
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
? -0.005
|
|
821
|
-
: boundary;
|
|
822
|
-
this.a = Math.abs(boundary * 2);
|
|
826
|
+
const boundary = evidenceScale.invert(event.y);
|
|
827
|
+
let a = Math.abs(boundary * 2);
|
|
828
|
+
// Clamp a
|
|
829
|
+
a = (a < DDMMath.a.MIN)
|
|
830
|
+
? DDMMath.a.MIN
|
|
831
|
+
: (a > DDMMath.a.MAX)
|
|
832
|
+
? DDMMath.a.MAX
|
|
833
|
+
: a;
|
|
834
|
+
this.a = a;
|
|
823
835
|
this.alignState();
|
|
824
836
|
this.dispatchEvent(new CustomEvent('ddm-model-a', {
|
|
825
837
|
detail: {
|
|
@@ -1530,6 +1542,8 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1530
1542
|
});
|
|
1531
1543
|
boundaryEnter.append('line')
|
|
1532
1544
|
.classed('line', true);
|
|
1545
|
+
boundaryEnter.append('line')
|
|
1546
|
+
.classed('line touch', true);
|
|
1533
1547
|
// MERGE
|
|
1534
1548
|
const boundaryMerge = boundaryEnter.merge(boundaryUpdate)
|
|
1535
1549
|
.attr('tabindex', this.interactive ? 0 : null)
|
|
@@ -1537,25 +1551,33 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1537
1551
|
.on('keydown', this.interactive
|
|
1538
1552
|
? (event, datum) => {
|
|
1539
1553
|
if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
1540
|
-
let a = this
|
|
1554
|
+
let {a} = this;
|
|
1541
1555
|
switch (event.key) {
|
|
1542
1556
|
case 'ArrowUp':
|
|
1543
1557
|
a += (datum.bound === 'upper')
|
|
1544
|
-
? event.shiftKey
|
|
1545
|
-
|
|
1558
|
+
? event.shiftKey
|
|
1559
|
+
? DDMMath.a.STEP
|
|
1560
|
+
: DDMMath.a.JUMP
|
|
1561
|
+
: event.shiftKey
|
|
1562
|
+
? -DDMMath.a.STEP
|
|
1563
|
+
: -DDMMath.a.JUMP;
|
|
1546
1564
|
break;
|
|
1547
1565
|
case 'ArrowDown':
|
|
1548
1566
|
a += (datum.bound === 'upper')
|
|
1549
|
-
? event.shiftKey
|
|
1550
|
-
|
|
1567
|
+
? event.shiftKey
|
|
1568
|
+
? -DDMMath.a.STEP
|
|
1569
|
+
: -DDMMath.a.JUMP
|
|
1570
|
+
: event.shiftKey
|
|
1571
|
+
? DDMMath.a.STEP
|
|
1572
|
+
: DDMMath.a.JUMP;
|
|
1551
1573
|
break;
|
|
1552
1574
|
default:
|
|
1553
1575
|
}
|
|
1554
|
-
// Clamp
|
|
1555
|
-
a = (a <
|
|
1556
|
-
?
|
|
1557
|
-
: (a >
|
|
1558
|
-
?
|
|
1576
|
+
// Clamp a
|
|
1577
|
+
a = (a < DDMMath.a.MIN)
|
|
1578
|
+
? DDMMath.a.MIN
|
|
1579
|
+
: (a > DDMMath.a.MAX)
|
|
1580
|
+
? DDMMath.a.MAX
|
|
1559
1581
|
: a;
|
|
1560
1582
|
this.a = a;
|
|
1561
1583
|
this.alignState();
|
|
@@ -1591,6 +1613,18 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1591
1613
|
.attr('y2', (datum) => {
|
|
1592
1614
|
return evidenceScale(datum.value);
|
|
1593
1615
|
});
|
|
1616
|
+
boundaryMerge.select('.line.touch')
|
|
1617
|
+
.transition()
|
|
1618
|
+
.duration(this.drag ? 0 : transitionDuration)
|
|
1619
|
+
.ease(d3.easeCubicOut)
|
|
1620
|
+
.attr('x1', timeScale(this.scale.time.min))
|
|
1621
|
+
.attr('x2', timeScale(this.scale.time.max))
|
|
1622
|
+
.attr('y1', (datum) => {
|
|
1623
|
+
return evidenceScale(datum.value);
|
|
1624
|
+
})
|
|
1625
|
+
.attr('y2', (datum) => {
|
|
1626
|
+
return evidenceScale(datum.value);
|
|
1627
|
+
});
|
|
1594
1628
|
// EXIT
|
|
1595
1629
|
boundaryUpdate.exit().remove();
|
|
1596
1630
|
|
|
@@ -1605,8 +1639,12 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1605
1639
|
.classed('drift', true);
|
|
1606
1640
|
driftEnter.append('line')
|
|
1607
1641
|
.classed('line', true);
|
|
1642
|
+
driftEnter.append('line')
|
|
1643
|
+
.classed('line touch', true);
|
|
1608
1644
|
driftEnter.append('path')
|
|
1609
1645
|
.classed('arrow', true);
|
|
1646
|
+
driftEnter.append('path')
|
|
1647
|
+
.classed('arrow touch', true);
|
|
1610
1648
|
// MERGE
|
|
1611
1649
|
const driftMerge = driftEnter.merge(driftUpdate)
|
|
1612
1650
|
.attr('tabindex', this.interactive ? 0 : null)
|
|
@@ -1614,21 +1652,25 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1614
1652
|
.on('keydown', this.interactive
|
|
1615
1653
|
? (event) => {
|
|
1616
1654
|
if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
1617
|
-
let v = this
|
|
1655
|
+
let {v} = this;
|
|
1618
1656
|
switch (event.key) {
|
|
1619
1657
|
case 'ArrowUp':
|
|
1620
|
-
v += event.shiftKey
|
|
1658
|
+
v += event.shiftKey
|
|
1659
|
+
? DDMMath.v.STEP
|
|
1660
|
+
: DDMMath.v.JUMP;
|
|
1621
1661
|
break;
|
|
1622
1662
|
case 'ArrowDown':
|
|
1623
|
-
v -= event.shiftKey
|
|
1663
|
+
v -= event.shiftKey
|
|
1664
|
+
? DDMMath.v.STEP
|
|
1665
|
+
: DDMMath.v.JUMP;
|
|
1624
1666
|
break;
|
|
1625
1667
|
default:
|
|
1626
1668
|
}
|
|
1627
1669
|
// Clamp z
|
|
1628
|
-
v = (v <
|
|
1629
|
-
?
|
|
1630
|
-
: (v >
|
|
1631
|
-
?
|
|
1670
|
+
v = (v < DDMMath.v.MIN)
|
|
1671
|
+
? DDMMath.v.MIN
|
|
1672
|
+
: (v > DDMMath.v.MAX)
|
|
1673
|
+
? DDMMath.v.MAX
|
|
1632
1674
|
: v;
|
|
1633
1675
|
this.v = v;
|
|
1634
1676
|
this.alignState();
|
|
@@ -1663,12 +1705,20 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1663
1705
|
});
|
|
1664
1706
|
driftMerge.select('.line')
|
|
1665
1707
|
.attr('x2', timeScale(200));
|
|
1708
|
+
driftMerge.select('.line.touch')
|
|
1709
|
+
.attr('x2', timeScale(200));
|
|
1666
1710
|
driftMerge.select('.arrow')
|
|
1667
1711
|
.attr('d', `
|
|
1668
1712
|
M ${timeScale(200) - this.rem * 0.5},${-this.rem * 0.5}
|
|
1669
1713
|
l ${this.rem * 0.5},${this.rem * 0.5}
|
|
1670
1714
|
l ${-this.rem * 0.5},${this.rem * 0.5}
|
|
1671
1715
|
`);
|
|
1716
|
+
driftMerge.select('.arrow.touch')
|
|
1717
|
+
.attr('d', `
|
|
1718
|
+
M ${timeScale(200) - this.rem * 0.5},${-this.rem * 0.5}
|
|
1719
|
+
l ${this.rem * 0.5},${this.rem * 0.5}
|
|
1720
|
+
l ${-this.rem * 0.5},${this.rem * 0.5}
|
|
1721
|
+
`);
|
|
1672
1722
|
// EXIT
|
|
1673
1723
|
driftUpdate.exit().remove();
|
|
1674
1724
|
|
|
@@ -1683,8 +1733,10 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1683
1733
|
.classed('t0z', true);
|
|
1684
1734
|
t0zEnter.append('line')
|
|
1685
1735
|
.classed('line', true);
|
|
1736
|
+
t0zEnter.append('line')
|
|
1737
|
+
.classed('line touch', true);
|
|
1686
1738
|
t0zEnter.append('circle')
|
|
1687
|
-
.classed('point', true);
|
|
1739
|
+
.classed('point touch', true);
|
|
1688
1740
|
// MERGE
|
|
1689
1741
|
const t0zMerge = t0zEnter.merge(t0zUpdate)
|
|
1690
1742
|
.attr('tabindex', this.interactive ? 0 : null)
|
|
@@ -1692,21 +1744,25 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1692
1744
|
.on('keydown', this.interactive
|
|
1693
1745
|
? (event) => {
|
|
1694
1746
|
if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
1695
|
-
let z = this
|
|
1747
|
+
let {z} = this;
|
|
1696
1748
|
switch (event.key) {
|
|
1697
1749
|
case 'ArrowUp':
|
|
1698
|
-
z += event.shiftKey
|
|
1750
|
+
z += event.shiftKey
|
|
1751
|
+
? DDMMath.z.STEP
|
|
1752
|
+
: DDMMath.z.JUMP;
|
|
1699
1753
|
break;
|
|
1700
1754
|
case 'ArrowDown':
|
|
1701
|
-
z -= event.shiftKey
|
|
1755
|
+
z -= event.shiftKey
|
|
1756
|
+
? DDMMath.z.STEP
|
|
1757
|
+
: DDMMath.z.JUMP;
|
|
1702
1758
|
break;
|
|
1703
1759
|
default:
|
|
1704
1760
|
}
|
|
1705
1761
|
// Clamp z
|
|
1706
|
-
z = (z <
|
|
1707
|
-
?
|
|
1708
|
-
: (z >
|
|
1709
|
-
?
|
|
1762
|
+
z = (z < DDMMath.z.MIN)
|
|
1763
|
+
? DDMMath.z.MIN
|
|
1764
|
+
: (z > DDMMath.z.MAX)
|
|
1765
|
+
? DDMMath.z.MAX
|
|
1710
1766
|
: z;
|
|
1711
1767
|
this.z = z;
|
|
1712
1768
|
this.alignState();
|
|
@@ -1722,18 +1778,22 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1722
1778
|
let t0 = this.t0; /* eslint-disable-line prefer-destructuring */
|
|
1723
1779
|
switch (event.key) {
|
|
1724
1780
|
case 'ArrowRight':
|
|
1725
|
-
t0 += event.shiftKey
|
|
1781
|
+
t0 += event.shiftKey
|
|
1782
|
+
? DDMMath.t0.STEP
|
|
1783
|
+
: DDMMath.t0.JUMP;
|
|
1726
1784
|
break;
|
|
1727
1785
|
case 'ArrowLeft':
|
|
1728
|
-
t0 -= event.shiftKey
|
|
1786
|
+
t0 -= event.shiftKey
|
|
1787
|
+
? DDMMath.t0.STEP
|
|
1788
|
+
: DDMMath.t0.JUMP;
|
|
1729
1789
|
break;
|
|
1730
1790
|
default:
|
|
1731
1791
|
}
|
|
1732
1792
|
// Clamp t0
|
|
1733
|
-
t0 = (t0 <
|
|
1734
|
-
?
|
|
1735
|
-
: (t0 >
|
|
1736
|
-
?
|
|
1793
|
+
t0 = (t0 < DDMMath.t0.MIN)
|
|
1794
|
+
? DDMMath.t0.MIN
|
|
1795
|
+
: (t0 > DDMMath.t0.MAX)
|
|
1796
|
+
? DDMMath.t0.MAX
|
|
1737
1797
|
: t0;
|
|
1738
1798
|
this.t0 = t0;
|
|
1739
1799
|
this.alignState();
|
|
@@ -1765,6 +1825,14 @@ export default class DDMModel extends DecidablesMixinResizeable(AccumulableEleme
|
|
|
1765
1825
|
.attr('x2', (datum) => { return timeScale(datum.t0); })
|
|
1766
1826
|
.attr('y1', (datum) => { return evidenceScale(datum.startingPoint); })
|
|
1767
1827
|
.attr('y2', (datum) => { return evidenceScale(datum.startingPoint); });
|
|
1828
|
+
t0zMerge.select('.line.touch')
|
|
1829
|
+
.transition()
|
|
1830
|
+
.duration(this.drag ? 0 : transitionDuration)
|
|
1831
|
+
.ease(d3.easeCubicOut)
|
|
1832
|
+
.attr('x1', timeScale(0))
|
|
1833
|
+
.attr('x2', (datum) => { return timeScale(datum.t0); })
|
|
1834
|
+
.attr('y1', (datum) => { return evidenceScale(datum.startingPoint); })
|
|
1835
|
+
.attr('y2', (datum) => { return evidenceScale(datum.startingPoint); });
|
|
1768
1836
|
t0zMerge.select('.point')
|
|
1769
1837
|
.transition()
|
|
1770
1838
|
.duration(this.drag ? 0 : transitionDuration)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {html, css} from 'lit';
|
|
3
3
|
|
|
4
4
|
import '@decidables/decidables-elements/slider';
|
|
5
|
+
import DDMMath from '@decidables/accumulable-math';
|
|
5
6
|
|
|
6
7
|
import AccumulableElement from '../accumulable-element';
|
|
7
8
|
|
|
@@ -113,6 +114,26 @@ export default class DDMParameters extends AccumulableElement {
|
|
|
113
114
|
decidables-slider div {
|
|
114
115
|
margin-bottom: 0.25rem;
|
|
115
116
|
}
|
|
117
|
+
|
|
118
|
+
.a {
|
|
119
|
+
--decidables-slider-background-color: var(---color-a-light);
|
|
120
|
+
--decidables-slider-color: var(---color-a);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.z {
|
|
124
|
+
--decidables-slider-background-color: var(---color-z-light);
|
|
125
|
+
--decidables-slider-color: var(---color-z);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.v {
|
|
129
|
+
--decidables-slider-background-color: var(---color-v-light);
|
|
130
|
+
--decidables-slider-color: var(---color-v);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.t0 {
|
|
134
|
+
--decidables-slider-background-color: var(---color-t0-light);
|
|
135
|
+
--decidables-slider-color: var(---color-t0);
|
|
136
|
+
}
|
|
116
137
|
`,
|
|
117
138
|
];
|
|
118
139
|
}
|
|
@@ -121,16 +142,52 @@ export default class DDMParameters extends AccumulableElement {
|
|
|
121
142
|
return html`
|
|
122
143
|
<div class="holder">
|
|
123
144
|
${this.a != null
|
|
124
|
-
? html`<decidables-slider class="a"
|
|
145
|
+
? html`<decidables-slider class="a"
|
|
146
|
+
?disabled=${!this.interactive}
|
|
147
|
+
scale
|
|
148
|
+
min=${DDMMath.a.MIN}
|
|
149
|
+
max=${DDMMath.a.MAX}
|
|
150
|
+
step=${DDMMath.a.STEP}
|
|
151
|
+
.value=${+this.a.toFixed(2)}
|
|
152
|
+
@change=${this.setBoundarySeparation.bind(this)}
|
|
153
|
+
@input=${this.setBoundarySeparation.bind(this)}
|
|
154
|
+
><div>Boundary Separation<br><span class="math-var">a</span></div></decidables-slider>`
|
|
125
155
|
: html``}
|
|
126
156
|
${this.z != null
|
|
127
|
-
? html`<decidables-slider class="z"
|
|
157
|
+
? html`<decidables-slider class="z"
|
|
158
|
+
?disabled=${!this.interactive}
|
|
159
|
+
scale
|
|
160
|
+
min=${DDMMath.z.MIN}
|
|
161
|
+
max=${DDMMath.z.MAX}
|
|
162
|
+
step=${DDMMath.z.STEP}
|
|
163
|
+
.value=${+this.z.toFixed(2)}
|
|
164
|
+
@change=${this.setStartingPoint.bind(this)}
|
|
165
|
+
@input=${this.setStartingPoint.bind(this)}
|
|
166
|
+
><div>Starting Point<br><span class="math-var">z</span></div></decidables-slider>`
|
|
128
167
|
: html``}
|
|
129
168
|
${this.v != null
|
|
130
|
-
? html`<decidables-slider class="v"
|
|
169
|
+
? html`<decidables-slider class="v"
|
|
170
|
+
?disabled=${!this.interactive}
|
|
171
|
+
scale
|
|
172
|
+
min=${DDMMath.v.MIN}
|
|
173
|
+
max=${DDMMath.v.MAX}
|
|
174
|
+
step=${DDMMath.v.STEP}
|
|
175
|
+
.value=${+this.v.toFixed(2)}
|
|
176
|
+
@change=${this.setDriftRate.bind(this)}
|
|
177
|
+
@input=${this.setDriftRate.bind(this)}
|
|
178
|
+
><div>Drift Rate<br><span class="math-var">v</span></div></decidables-slider>`
|
|
131
179
|
: html``}
|
|
132
180
|
${this.t0 != null
|
|
133
|
-
? html`<decidables-slider class="t0"
|
|
181
|
+
? html`<decidables-slider class="t0"
|
|
182
|
+
?disabled=${!this.interactive}
|
|
183
|
+
scale
|
|
184
|
+
min=${DDMMath.t0.MIN}
|
|
185
|
+
max=${DDMMath.t0.MAX}
|
|
186
|
+
step=${DDMMath.t0.STEP}
|
|
187
|
+
.value=${+this.t0.toFixed(0)}
|
|
188
|
+
@change=${this.setNondecisionTime.bind(this)}
|
|
189
|
+
@input=${this.setNondecisionTime.bind(this)}
|
|
190
|
+
><div>Nondecision Time<br><span class="math-var">t₀</span></div></decidables-slider>`
|
|
134
191
|
: html``}
|
|
135
192
|
</div>`;
|
|
136
193
|
}
|