jspsych-tangram 0.0.13 → 0.0.15
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/dist/afc/index.browser.js +17751 -0
- package/dist/afc/index.browser.js.map +1 -0
- package/dist/afc/index.browser.min.js +42 -0
- package/dist/afc/index.browser.min.js.map +1 -0
- package/dist/afc/index.cjs +443 -0
- package/dist/afc/index.cjs.map +1 -0
- package/dist/afc/index.d.ts +169 -0
- package/dist/afc/index.js +441 -0
- package/dist/afc/index.js.map +1 -0
- package/dist/construct/index.browser.js +8 -2
- package/dist/construct/index.browser.js.map +1 -1
- package/dist/construct/index.browser.min.js +10 -10
- package/dist/construct/index.browser.min.js.map +1 -1
- package/dist/construct/index.cjs +8 -2
- package/dist/construct/index.cjs.map +1 -1
- package/dist/construct/index.js +8 -2
- package/dist/construct/index.js.map +1 -1
- package/dist/index.cjs +379 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +178 -12
- package/dist/index.js +379 -12
- package/dist/index.js.map +1 -1
- package/dist/nback/index.browser.js +6 -4
- package/dist/nback/index.browser.js.map +1 -1
- package/dist/nback/index.browser.min.js +8 -8
- package/dist/nback/index.browser.min.js.map +1 -1
- package/dist/nback/index.cjs +6 -4
- package/dist/nback/index.cjs.map +1 -1
- package/dist/nback/index.js +6 -4
- package/dist/nback/index.js.map +1 -1
- package/dist/prep/index.browser.js +8 -2
- package/dist/prep/index.browser.js.map +1 -1
- package/dist/prep/index.browser.min.js +10 -10
- package/dist/prep/index.browser.min.js.map +1 -1
- package/dist/prep/index.cjs +8 -2
- package/dist/prep/index.cjs.map +1 -1
- package/dist/prep/index.js +8 -2
- package/dist/prep/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/components/board/GameBoard.tsx +13 -42
- package/src/core/components/board/useGameBoard.ts +52 -0
- package/src/core/components/index.ts +4 -2
- package/src/core/components/pieces/BlueprintRing.tsx +0 -25
- package/src/core/components/pieces/useBlueprintRing.ts +39 -0
- package/src/index.ts +2 -1
- package/src/plugins/tangram-afc/AFCApp.tsx +341 -0
- package/src/plugins/tangram-afc/index.ts +140 -0
- package/src/plugins/tangram-nback/NBackApp.tsx +3 -3
- package/tangram-construct.min.js +10 -10
- package/tangram-nback.min.js +8 -8
- package/tangram-prep.min.js +10 -10
package/dist/index.cjs
CHANGED
|
@@ -3476,14 +3476,20 @@ function GameBoard(props) {
|
|
|
3476
3476
|
lineHeight: 1.5,
|
|
3477
3477
|
textAlign: "center"
|
|
3478
3478
|
};
|
|
3479
|
+
const scaleX = svgDimensions.width / viewBox.w;
|
|
3480
|
+
const rightEdgeOfSemicircleLogical = viewBox.w / 2 + layout.outerR;
|
|
3481
|
+
const distanceFromRightEdgeLogical = viewBox.w - rightEdgeOfSemicircleLogical;
|
|
3482
|
+
const distanceFromRightEdgePx = distanceFromRightEdgeLogical * scaleX;
|
|
3483
|
+
const charWidth = 24 * 0.6;
|
|
3484
|
+
const offsetLeft = charWidth * 5;
|
|
3479
3485
|
const timerStyle = {
|
|
3480
3486
|
position: "absolute",
|
|
3481
|
-
right:
|
|
3487
|
+
right: `${distanceFromRightEdgePx + offsetLeft}px`,
|
|
3482
3488
|
fontSize: "24px",
|
|
3483
3489
|
fontWeight: "bold",
|
|
3484
3490
|
fontFamily: "monospace",
|
|
3485
3491
|
color: "#333",
|
|
3486
|
-
|
|
3492
|
+
whiteSpace: "nowrap",
|
|
3487
3493
|
textAlign: "right"
|
|
3488
3494
|
};
|
|
3489
3495
|
const gameboardWrapperStyle = {
|
|
@@ -3760,7 +3766,7 @@ function startConstructionTrial(display_element, params, _jsPsych) {
|
|
|
3760
3766
|
return { root, display_element, jsPsych: _jsPsych };
|
|
3761
3767
|
}
|
|
3762
3768
|
|
|
3763
|
-
const info$
|
|
3769
|
+
const info$3 = {
|
|
3764
3770
|
name: "tangram-construct",
|
|
3765
3771
|
version: "1.0.0",
|
|
3766
3772
|
parameters: {
|
|
@@ -3892,7 +3898,7 @@ class TangramConstructPlugin {
|
|
|
3892
3898
|
this.jsPsych = jsPsych;
|
|
3893
3899
|
}
|
|
3894
3900
|
static {
|
|
3895
|
-
this.info = info$
|
|
3901
|
+
this.info = info$3;
|
|
3896
3902
|
}
|
|
3897
3903
|
/**
|
|
3898
3904
|
* Launches the trial by invoking startConstructionTrial
|
|
@@ -4043,7 +4049,7 @@ function startPrepTrial(display_element, params, jsPsych) {
|
|
|
4043
4049
|
return { root, display_element, jsPsych };
|
|
4044
4050
|
}
|
|
4045
4051
|
|
|
4046
|
-
const info$
|
|
4052
|
+
const info$2 = {
|
|
4047
4053
|
name: "tangram-prep",
|
|
4048
4054
|
version: "1.0.0",
|
|
4049
4055
|
parameters: {
|
|
@@ -4131,7 +4137,7 @@ class TangramPrepPlugin {
|
|
|
4131
4137
|
this.jsPsych = jsPsych;
|
|
4132
4138
|
}
|
|
4133
4139
|
static {
|
|
4134
|
-
this.info = info$
|
|
4140
|
+
this.info = info$2;
|
|
4135
4141
|
}
|
|
4136
4142
|
/**
|
|
4137
4143
|
* Launches the trial by invoking startPrepTrial
|
|
@@ -4323,7 +4329,7 @@ function NBackView({ params }) {
|
|
|
4323
4329
|
{
|
|
4324
4330
|
d: pathD(scaledPoly),
|
|
4325
4331
|
fill: fillColor,
|
|
4326
|
-
opacity: CONFIG.opacity.silhouetteMask,
|
|
4332
|
+
opacity: usePrimitiveColors ? CONFIG.opacity.piece.normal : CONFIG.opacity.silhouetteMask,
|
|
4327
4333
|
stroke: "none"
|
|
4328
4334
|
}
|
|
4329
4335
|
), /* @__PURE__ */ React.createElement(
|
|
@@ -4364,7 +4370,7 @@ function NBackView({ params }) {
|
|
|
4364
4370
|
key: `sil-${i}`,
|
|
4365
4371
|
d: pathD(scaledPoly),
|
|
4366
4372
|
fill: fillColor,
|
|
4367
|
-
opacity: CONFIG.opacity.silhouetteMask,
|
|
4373
|
+
opacity: usePrimitiveColors ? CONFIG.opacity.piece.normal : CONFIG.opacity.silhouetteMask,
|
|
4368
4374
|
stroke: "none"
|
|
4369
4375
|
}
|
|
4370
4376
|
);
|
|
@@ -4377,7 +4383,7 @@ function NBackView({ params }) {
|
|
|
4377
4383
|
alignItems: "center",
|
|
4378
4384
|
justifyContent: "center",
|
|
4379
4385
|
padding: "20px",
|
|
4380
|
-
background: "#
|
|
4386
|
+
background: "#fff7e0ff"
|
|
4381
4387
|
} }, instructions && /* @__PURE__ */ React.createElement(
|
|
4382
4388
|
"div",
|
|
4383
4389
|
{
|
|
@@ -4427,7 +4433,7 @@ function NBackView({ params }) {
|
|
|
4427
4433
|
)));
|
|
4428
4434
|
}
|
|
4429
4435
|
|
|
4430
|
-
const info = {
|
|
4436
|
+
const info$1 = {
|
|
4431
4437
|
name: "tangram-nback",
|
|
4432
4438
|
version: "1.0.0",
|
|
4433
4439
|
parameters: {
|
|
@@ -4520,7 +4526,7 @@ class TangramNBackPlugin {
|
|
|
4520
4526
|
this.jsPsych = jsPsych;
|
|
4521
4527
|
}
|
|
4522
4528
|
static {
|
|
4523
|
-
this.info = info;
|
|
4529
|
+
this.info = info$1;
|
|
4524
4530
|
}
|
|
4525
4531
|
/**
|
|
4526
4532
|
* Launches the trial by invoking startNBackTrial
|
|
@@ -4554,6 +4560,368 @@ class TangramNBackPlugin {
|
|
|
4554
4560
|
}
|
|
4555
4561
|
}
|
|
4556
4562
|
|
|
4563
|
+
function startAFCTrial(display_element, params, _jsPsych) {
|
|
4564
|
+
const root = client.createRoot(display_element);
|
|
4565
|
+
root.render(React.createElement(AFCView, { params }));
|
|
4566
|
+
return { root, display_element, jsPsych: _jsPsych };
|
|
4567
|
+
}
|
|
4568
|
+
function AFCView({ params }) {
|
|
4569
|
+
const {
|
|
4570
|
+
tangramLeft,
|
|
4571
|
+
tangramRight,
|
|
4572
|
+
instructions,
|
|
4573
|
+
buttonTextLeft,
|
|
4574
|
+
buttonTextRight,
|
|
4575
|
+
showTangramDecomposition,
|
|
4576
|
+
usePrimitiveColors,
|
|
4577
|
+
primitiveColorIndices,
|
|
4578
|
+
onTrialEnd
|
|
4579
|
+
} = params;
|
|
4580
|
+
const trialStartTime = React.useRef(Date.now());
|
|
4581
|
+
const [hasResponded, setHasResponded] = React.useState(false);
|
|
4582
|
+
const handleResponse = (choice) => {
|
|
4583
|
+
if (hasResponded) return;
|
|
4584
|
+
setHasResponded(true);
|
|
4585
|
+
const rt = Date.now() - trialStartTime.current;
|
|
4586
|
+
if (onTrialEnd) {
|
|
4587
|
+
onTrialEnd({
|
|
4588
|
+
rt,
|
|
4589
|
+
response: choice,
|
|
4590
|
+
show_tangram_decomposition: showTangramDecomposition,
|
|
4591
|
+
use_primitive_colors: usePrimitiveColors,
|
|
4592
|
+
primitive_color_indices: primitiveColorIndices,
|
|
4593
|
+
button_text_left: buttonTextLeft,
|
|
4594
|
+
button_text_right: buttonTextRight
|
|
4595
|
+
});
|
|
4596
|
+
}
|
|
4597
|
+
};
|
|
4598
|
+
return /* @__PURE__ */ React.createElement("div", { style: {
|
|
4599
|
+
display: "flex",
|
|
4600
|
+
flexDirection: "column",
|
|
4601
|
+
alignItems: "center",
|
|
4602
|
+
justifyContent: "center",
|
|
4603
|
+
padding: "20px",
|
|
4604
|
+
background: "#fff7e0ff",
|
|
4605
|
+
minHeight: "100vh"
|
|
4606
|
+
} }, instructions && /* @__PURE__ */ React.createElement(
|
|
4607
|
+
"div",
|
|
4608
|
+
{
|
|
4609
|
+
style: {
|
|
4610
|
+
maxWidth: "800px",
|
|
4611
|
+
width: "100%",
|
|
4612
|
+
marginBottom: "30px",
|
|
4613
|
+
textAlign: "center",
|
|
4614
|
+
fontSize: "18px",
|
|
4615
|
+
lineHeight: "1.5"
|
|
4616
|
+
},
|
|
4617
|
+
dangerouslySetInnerHTML: { __html: instructions }
|
|
4618
|
+
}
|
|
4619
|
+
), /* @__PURE__ */ React.createElement("div", { style: {
|
|
4620
|
+
display: "flex",
|
|
4621
|
+
flexDirection: "row",
|
|
4622
|
+
gap: "50px",
|
|
4623
|
+
justifyContent: "center",
|
|
4624
|
+
alignItems: "flex-start",
|
|
4625
|
+
flexWrap: "wrap"
|
|
4626
|
+
} }, /* @__PURE__ */ React.createElement(
|
|
4627
|
+
TangramOption,
|
|
4628
|
+
{
|
|
4629
|
+
tangram: tangramLeft,
|
|
4630
|
+
buttonText: buttonTextLeft,
|
|
4631
|
+
onClick: () => handleResponse("left"),
|
|
4632
|
+
disabled: hasResponded,
|
|
4633
|
+
showDecomposition: showTangramDecomposition,
|
|
4634
|
+
usePrimitiveColors,
|
|
4635
|
+
primitiveColorIndices
|
|
4636
|
+
}
|
|
4637
|
+
), /* @__PURE__ */ React.createElement(
|
|
4638
|
+
TangramOption,
|
|
4639
|
+
{
|
|
4640
|
+
tangram: tangramRight,
|
|
4641
|
+
buttonText: buttonTextRight,
|
|
4642
|
+
onClick: () => handleResponse("right"),
|
|
4643
|
+
disabled: hasResponded,
|
|
4644
|
+
showDecomposition: showTangramDecomposition,
|
|
4645
|
+
usePrimitiveColors,
|
|
4646
|
+
primitiveColorIndices
|
|
4647
|
+
}
|
|
4648
|
+
)));
|
|
4649
|
+
}
|
|
4650
|
+
function TangramOption({
|
|
4651
|
+
tangram,
|
|
4652
|
+
buttonText,
|
|
4653
|
+
onClick,
|
|
4654
|
+
disabled,
|
|
4655
|
+
showDecomposition,
|
|
4656
|
+
usePrimitiveColors,
|
|
4657
|
+
primitiveColorIndices
|
|
4658
|
+
}) {
|
|
4659
|
+
if (!tangram) {
|
|
4660
|
+
return /* @__PURE__ */ React.createElement("div", { style: { width: 300, height: 300, background: "#eee" } }, "No Tangram Data");
|
|
4661
|
+
}
|
|
4662
|
+
const CANON = /* @__PURE__ */ new Set([
|
|
4663
|
+
"square",
|
|
4664
|
+
"smalltriangle",
|
|
4665
|
+
"parallelogram",
|
|
4666
|
+
"medtriangle",
|
|
4667
|
+
"largetriangle"
|
|
4668
|
+
]);
|
|
4669
|
+
const filteredTans = tangram.solutionTans.filter((tan) => {
|
|
4670
|
+
const tanName = tan.name ?? tan.kind;
|
|
4671
|
+
return CANON.has(tanName);
|
|
4672
|
+
});
|
|
4673
|
+
const mask = filteredTans.map((tan) => {
|
|
4674
|
+
const polygon = tan.vertices.map(([x, y]) => ({ x: x ?? 0, y: -(y ?? 0) }));
|
|
4675
|
+
return polygon;
|
|
4676
|
+
});
|
|
4677
|
+
const primitiveDecomposition = filteredTans.map((tan) => ({
|
|
4678
|
+
kind: tan.name ?? tan.kind,
|
|
4679
|
+
polygon: tan.vertices.map(([x, y]) => ({ x: x ?? 0, y: -(y ?? 0) }))
|
|
4680
|
+
}));
|
|
4681
|
+
const DISPLAY_SIZE = 300;
|
|
4682
|
+
const viewport = {
|
|
4683
|
+
w: DISPLAY_SIZE,
|
|
4684
|
+
h: DISPLAY_SIZE
|
|
4685
|
+
};
|
|
4686
|
+
const scaleS = React.useMemo(() => {
|
|
4687
|
+
const u = inferUnitFromPolys$1(mask);
|
|
4688
|
+
return u ? CONFIG.layout.grid.unitPx / u : 1;
|
|
4689
|
+
}, [mask]);
|
|
4690
|
+
const centerPos = {
|
|
4691
|
+
cx: viewport.w / 2,
|
|
4692
|
+
cy: viewport.h / 2
|
|
4693
|
+
};
|
|
4694
|
+
const pathD = (poly) => {
|
|
4695
|
+
if (!poly || poly.length === 0) return "";
|
|
4696
|
+
const moves = poly.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`);
|
|
4697
|
+
return moves.join(" ") + " Z";
|
|
4698
|
+
};
|
|
4699
|
+
const renderSilhouette = () => {
|
|
4700
|
+
if (showDecomposition) {
|
|
4701
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
4702
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, centerPos);
|
|
4703
|
+
return /* @__PURE__ */ React.createElement("g", { key: "sil-decomposed", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
4704
|
+
const primInfo = primitiveDecomposition[i];
|
|
4705
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
4706
|
+
if (usePrimitiveColors && primInfo?.kind && primitiveColorIndices) {
|
|
4707
|
+
const kindToIndex = {
|
|
4708
|
+
"square": 0,
|
|
4709
|
+
"smalltriangle": 1,
|
|
4710
|
+
"parallelogram": 2,
|
|
4711
|
+
"medtriangle": 3,
|
|
4712
|
+
"largetriangle": 4
|
|
4713
|
+
};
|
|
4714
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
4715
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
4716
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
4717
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
4718
|
+
if (color) {
|
|
4719
|
+
fillColor = color;
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: `prim-${i}` }, /* @__PURE__ */ React.createElement(
|
|
4724
|
+
"path",
|
|
4725
|
+
{
|
|
4726
|
+
d: pathD(scaledPoly),
|
|
4727
|
+
fill: fillColor,
|
|
4728
|
+
opacity: usePrimitiveColors ? CONFIG.opacity.piece.normal : CONFIG.opacity.silhouetteMask,
|
|
4729
|
+
stroke: "none"
|
|
4730
|
+
}
|
|
4731
|
+
), /* @__PURE__ */ React.createElement(
|
|
4732
|
+
"path",
|
|
4733
|
+
{
|
|
4734
|
+
d: pathD(scaledPoly),
|
|
4735
|
+
fill: "none",
|
|
4736
|
+
stroke: CONFIG.color.tangramDecomposition.stroke,
|
|
4737
|
+
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
4738
|
+
}
|
|
4739
|
+
));
|
|
4740
|
+
}));
|
|
4741
|
+
} else {
|
|
4742
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(mask, scaleS, centerPos);
|
|
4743
|
+
return /* @__PURE__ */ React.createElement("g", { key: "sil-unified", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
4744
|
+
const primInfo = primitiveDecomposition[i];
|
|
4745
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
4746
|
+
if (usePrimitiveColors && primInfo?.kind && primitiveColorIndices) {
|
|
4747
|
+
const kindToIndex = {
|
|
4748
|
+
"square": 0,
|
|
4749
|
+
"smalltriangle": 1,
|
|
4750
|
+
"parallelogram": 2,
|
|
4751
|
+
"medtriangle": 3,
|
|
4752
|
+
"largetriangle": 4
|
|
4753
|
+
};
|
|
4754
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
4755
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
4756
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
4757
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
4758
|
+
if (color) {
|
|
4759
|
+
fillColor = color;
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
return /* @__PURE__ */ React.createElement(
|
|
4764
|
+
"path",
|
|
4765
|
+
{
|
|
4766
|
+
key: `sil-${i}`,
|
|
4767
|
+
d: pathD(scaledPoly),
|
|
4768
|
+
fill: fillColor,
|
|
4769
|
+
opacity: usePrimitiveColors ? CONFIG.opacity.piece.normal : CONFIG.opacity.silhouetteMask,
|
|
4770
|
+
stroke: "none"
|
|
4771
|
+
}
|
|
4772
|
+
);
|
|
4773
|
+
}));
|
|
4774
|
+
}
|
|
4775
|
+
};
|
|
4776
|
+
return /* @__PURE__ */ React.createElement("div", { style: {
|
|
4777
|
+
display: "flex",
|
|
4778
|
+
flexDirection: "column",
|
|
4779
|
+
alignItems: "center",
|
|
4780
|
+
gap: "20px"
|
|
4781
|
+
} }, /* @__PURE__ */ React.createElement(
|
|
4782
|
+
"svg",
|
|
4783
|
+
{
|
|
4784
|
+
width: viewport.w,
|
|
4785
|
+
height: viewport.h,
|
|
4786
|
+
viewBox: `0 0 ${viewport.w} ${viewport.h}`,
|
|
4787
|
+
style: {
|
|
4788
|
+
display: "block",
|
|
4789
|
+
background: CONFIG.color.bands.silhouette.fillEven,
|
|
4790
|
+
border: `${CONFIG.size.stroke.bandPx}px solid ${CONFIG.color.bands.silhouette.stroke}`,
|
|
4791
|
+
borderRadius: "8px"
|
|
4792
|
+
}
|
|
4793
|
+
},
|
|
4794
|
+
renderSilhouette()
|
|
4795
|
+
), /* @__PURE__ */ React.createElement(
|
|
4796
|
+
"button",
|
|
4797
|
+
{
|
|
4798
|
+
className: "jspsych-btn",
|
|
4799
|
+
onClick,
|
|
4800
|
+
disabled,
|
|
4801
|
+
style: {
|
|
4802
|
+
padding: "12px 30px",
|
|
4803
|
+
fontSize: "16px",
|
|
4804
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
4805
|
+
opacity: disabled ? 0.5 : 1
|
|
4806
|
+
}
|
|
4807
|
+
},
|
|
4808
|
+
buttonText
|
|
4809
|
+
));
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4812
|
+
const info = {
|
|
4813
|
+
name: "tangram-afc",
|
|
4814
|
+
version: "1.0.0",
|
|
4815
|
+
parameters: {
|
|
4816
|
+
/** Left tangram specification to display */
|
|
4817
|
+
tangram_left: {
|
|
4818
|
+
type: jspsych.ParameterType.COMPLEX,
|
|
4819
|
+
default: void 0,
|
|
4820
|
+
description: "TangramSpec object defining left target shape to display"
|
|
4821
|
+
},
|
|
4822
|
+
/** Right tangram specification to display */
|
|
4823
|
+
tangram_right: {
|
|
4824
|
+
type: jspsych.ParameterType.COMPLEX,
|
|
4825
|
+
default: void 0,
|
|
4826
|
+
description: "TangramSpec object defining right target shape to display"
|
|
4827
|
+
},
|
|
4828
|
+
/** HTML content to display above the tangrams as instructions */
|
|
4829
|
+
instructions: {
|
|
4830
|
+
type: jspsych.ParameterType.STRING,
|
|
4831
|
+
default: "",
|
|
4832
|
+
description: "HTML content to display above the tangrams as instructions"
|
|
4833
|
+
},
|
|
4834
|
+
/** Text to display on left response button */
|
|
4835
|
+
button_text_left: {
|
|
4836
|
+
type: jspsych.ParameterType.STRING,
|
|
4837
|
+
default: "Select Left",
|
|
4838
|
+
description: "Text to display on left response button"
|
|
4839
|
+
},
|
|
4840
|
+
/** Text to display on right response button */
|
|
4841
|
+
button_text_right: {
|
|
4842
|
+
type: jspsych.ParameterType.STRING,
|
|
4843
|
+
default: "Select Right",
|
|
4844
|
+
description: "Text to display on right response button"
|
|
4845
|
+
},
|
|
4846
|
+
/** Whether to show tangram decomposed into individual primitives with borders */
|
|
4847
|
+
show_tangram_decomposition: {
|
|
4848
|
+
type: jspsych.ParameterType.BOOL,
|
|
4849
|
+
default: false,
|
|
4850
|
+
description: "Whether to show tangram decomposed into individual primitives with borders"
|
|
4851
|
+
},
|
|
4852
|
+
/** Whether to use distinct colors for each primitive shape type */
|
|
4853
|
+
use_primitive_colors: {
|
|
4854
|
+
type: jspsych.ParameterType.BOOL,
|
|
4855
|
+
default: false,
|
|
4856
|
+
description: "Whether each primitive shape type should have its own distinct color in the displayed tangram"
|
|
4857
|
+
},
|
|
4858
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
4859
|
+
primitive_color_indices: {
|
|
4860
|
+
type: jspsych.ParameterType.OBJECT,
|
|
4861
|
+
default: [0, 1, 2, 3, 4],
|
|
4862
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
4863
|
+
},
|
|
4864
|
+
/** Callback fired when trial ends */
|
|
4865
|
+
onTrialEnd: {
|
|
4866
|
+
type: jspsych.ParameterType.FUNCTION,
|
|
4867
|
+
default: void 0,
|
|
4868
|
+
description: "Callback when trial completes with full data"
|
|
4869
|
+
}
|
|
4870
|
+
},
|
|
4871
|
+
data: {
|
|
4872
|
+
/** Reaction time in milliseconds */
|
|
4873
|
+
rt: {
|
|
4874
|
+
type: jspsych.ParameterType.INT,
|
|
4875
|
+
description: "Milliseconds between trial start and button click"
|
|
4876
|
+
},
|
|
4877
|
+
/** Response choice */
|
|
4878
|
+
response: {
|
|
4879
|
+
type: jspsych.ParameterType.STRING,
|
|
4880
|
+
description: "Which button was clicked: 'left' or 'right'"
|
|
4881
|
+
}
|
|
4882
|
+
},
|
|
4883
|
+
citations: ""
|
|
4884
|
+
};
|
|
4885
|
+
class TangramAFCPlugin {
|
|
4886
|
+
constructor(jsPsych) {
|
|
4887
|
+
this.jsPsych = jsPsych;
|
|
4888
|
+
}
|
|
4889
|
+
static {
|
|
4890
|
+
this.info = info;
|
|
4891
|
+
}
|
|
4892
|
+
/**
|
|
4893
|
+
* Launches the trial by invoking startAFCTrial
|
|
4894
|
+
* with the display element, parameters, and jsPsych instance.
|
|
4895
|
+
*/
|
|
4896
|
+
trial(display_element, trial) {
|
|
4897
|
+
const wrappedOnTrialEnd = (data) => {
|
|
4898
|
+
if (trial.onTrialEnd) {
|
|
4899
|
+
trial.onTrialEnd(data);
|
|
4900
|
+
}
|
|
4901
|
+
const reactContext = display_element.__reactContext;
|
|
4902
|
+
if (reactContext?.root) {
|
|
4903
|
+
reactContext.root.unmount();
|
|
4904
|
+
}
|
|
4905
|
+
display_element.innerHTML = "";
|
|
4906
|
+
this.jsPsych.finishTrial(data);
|
|
4907
|
+
};
|
|
4908
|
+
const params = {
|
|
4909
|
+
tangramLeft: trial.tangram_left,
|
|
4910
|
+
tangramRight: trial.tangram_right,
|
|
4911
|
+
instructions: trial.instructions,
|
|
4912
|
+
buttonTextLeft: trial.button_text_left,
|
|
4913
|
+
buttonTextRight: trial.button_text_right,
|
|
4914
|
+
showTangramDecomposition: trial.show_tangram_decomposition,
|
|
4915
|
+
usePrimitiveColors: trial.use_primitive_colors,
|
|
4916
|
+
primitiveColorIndices: trial.primitive_color_indices,
|
|
4917
|
+
onTrialEnd: wrappedOnTrialEnd
|
|
4918
|
+
};
|
|
4919
|
+
const { root, display_element: element, jsPsych } = startAFCTrial(display_element, params, this.jsPsych);
|
|
4920
|
+
element.__reactContext = { root, jsPsych };
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
|
|
4924
|
+
exports.TangramAFCPlugin = TangramAFCPlugin;
|
|
4557
4925
|
exports.TangramConstructPlugin = TangramConstructPlugin;
|
|
4558
4926
|
exports.TangramNBackPlugin = TangramNBackPlugin;
|
|
4559
4927
|
exports.TangramPrepPlugin = TangramPrepPlugin;
|