jspsych-tangram 0.0.12 → 0.0.14
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/construct/index.browser.js +283 -64
- package/dist/construct/index.browser.js.map +1 -1
- package/dist/construct/index.browser.min.js +11 -11
- package/dist/construct/index.browser.min.js.map +1 -1
- package/dist/construct/index.cjs +283 -64
- package/dist/construct/index.cjs.map +1 -1
- package/dist/construct/index.d.ts +36 -0
- package/dist/construct/index.js +283 -64
- package/dist/construct/index.js.map +1 -1
- package/dist/index.cjs +394 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +84 -0
- package/dist/index.js +394 -94
- package/dist/index.js.map +1 -1
- package/dist/nback/index.browser.js +112 -37
- package/dist/nback/index.browser.js.map +1 -1
- package/dist/nback/index.browser.min.js +11 -11
- package/dist/nback/index.browser.min.js.map +1 -1
- package/dist/nback/index.cjs +112 -37
- package/dist/nback/index.cjs.map +1 -1
- package/dist/nback/index.d.ts +24 -0
- package/dist/nback/index.js +112 -37
- package/dist/nback/index.js.map +1 -1
- package/dist/prep/index.browser.js +278 -65
- package/dist/prep/index.browser.js.map +1 -1
- package/dist/prep/index.browser.min.js +11 -11
- package/dist/prep/index.browser.min.js.map +1 -1
- package/dist/prep/index.cjs +278 -65
- package/dist/prep/index.cjs.map +1 -1
- package/dist/prep/index.d.ts +24 -0
- package/dist/prep/index.js +278 -65
- package/dist/prep/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/components/board/BoardView.tsx +372 -124
- package/src/core/components/board/GameBoard.tsx +39 -44
- package/src/core/components/board/useGameBoard.ts +52 -0
- package/src/core/components/index.ts +4 -2
- package/src/core/components/pieces/BlueprintRing.tsx +100 -67
- package/src/core/components/pieces/useBlueprintRing.ts +39 -0
- package/src/core/config/config.ts +25 -10
- package/src/plugins/tangram-construct/ConstructionApp.tsx +7 -1
- package/src/plugins/tangram-construct/index.ts +22 -1
- package/src/plugins/tangram-nback/NBackApp.tsx +88 -29
- package/src/plugins/tangram-nback/index.ts +14 -0
- package/src/plugins/tangram-prep/PrepApp.tsx +7 -1
- package/src/plugins/tangram-prep/index.ts +14 -0
- package/tangram-construct.min.js +11 -11
- package/tangram-nback.min.js +11 -11
- package/tangram-prep.min.js +11 -11
package/dist/index.cjs
CHANGED
|
@@ -7,30 +7,41 @@ var uuid = require('uuid');
|
|
|
7
7
|
|
|
8
8
|
const CONFIG = {
|
|
9
9
|
color: {
|
|
10
|
+
background: "#fff7e0ff",
|
|
10
11
|
bands: {
|
|
11
|
-
silhouette: { fillEven: "#
|
|
12
|
-
workspace: { fillEven: "#
|
|
12
|
+
silhouette: { fillEven: "#ffffff", fillOdd: "#ffffff", stroke: "#b1b1b1" },
|
|
13
|
+
workspace: { fillEven: "#ffffff", fillOdd: "#ffffff", stroke: "#b1b1b1" }
|
|
13
14
|
},
|
|
14
|
-
completion: { fill: "#
|
|
15
|
+
completion: { fill: "#ccffcc", stroke: "#13da57" },
|
|
15
16
|
silhouetteMask: "#374151",
|
|
16
17
|
anchors: { invalid: "#7dd3fc", valid: "#475569" },
|
|
17
|
-
|
|
18
|
+
// validFill used here for placed composites
|
|
19
|
+
piece: { draggingFill: "#8e7cc3", validFill: "#8e7cc3", invalidFill: "#d55c00", invalidStroke: "#dc2626", selectedStroke: "#674ea7", allGreenStroke: "#86efac", borderStroke: "#674ea7" },
|
|
18
20
|
ui: { light: "#60a5fa", dark: "#1d4ed8" },
|
|
19
21
|
blueprint: { fill: "#374151", selectedStroke: "#111827", badgeFill: "#000000", labelFill: "#ffffff" },
|
|
20
|
-
tangramDecomposition: { stroke: "#fef2cc" }
|
|
22
|
+
tangramDecomposition: { stroke: "#fef2cc" },
|
|
23
|
+
primitiveColors: [
|
|
24
|
+
// from seaborn "colorblind" palette, 6 colors, with red omitted
|
|
25
|
+
"#0173b2",
|
|
26
|
+
"#de8f05",
|
|
27
|
+
"#029e73",
|
|
28
|
+
"#cc78bc",
|
|
29
|
+
"#ca9161"
|
|
30
|
+
]
|
|
21
31
|
},
|
|
22
32
|
opacity: {
|
|
23
|
-
blueprint: 0.
|
|
33
|
+
blueprint: 0.6,
|
|
24
34
|
silhouetteMask: 0.25,
|
|
25
35
|
//anchors: { valid: 0.80, invalid: 0.50 },
|
|
26
36
|
anchors: { invalid: 0, valid: 0 },
|
|
27
|
-
piece: { invalid:
|
|
37
|
+
piece: { invalid: 1, dragging: 1, locked: 1, normal: 1 }
|
|
28
38
|
},
|
|
29
39
|
size: {
|
|
30
|
-
stroke: { bandPx: 5, pieceSelectedPx:
|
|
40
|
+
stroke: { bandPx: 5, pieceSelectedPx: 5, allGreenStrokePx: 10, pieceBorderPx: 2, tangramDecompositionPx: 1 },
|
|
31
41
|
anchorRadiusPx: { valid: 1, invalid: 1 },
|
|
32
42
|
badgeFontPx: 16,
|
|
33
|
-
centerBadge: { fractionOfOuterR: 0.15, minPx: 20, marginPx: 4 }
|
|
43
|
+
centerBadge: { fractionOfOuterR: 0.15, minPx: 20, marginPx: 4 },
|
|
44
|
+
invalidMarker: { sizePx: 10, strokePx: 4 }
|
|
34
45
|
},
|
|
35
46
|
layout: {
|
|
36
47
|
grid: { stepPx: 20, unitPx: 40 },
|
|
@@ -48,7 +59,8 @@ const CONFIG = {
|
|
|
48
59
|
game: {
|
|
49
60
|
snapRadiusPx: 15,
|
|
50
61
|
showBorders: false,
|
|
51
|
-
hideTouchingBorders: true
|
|
62
|
+
hideTouchingBorders: true,
|
|
63
|
+
silhouettesBelowPieces: true
|
|
52
64
|
}
|
|
53
65
|
};
|
|
54
66
|
|
|
@@ -832,6 +844,31 @@ var unlockedIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAYAAA
|
|
|
832
844
|
function pathD(poly) {
|
|
833
845
|
return `M ${poly.map((pt) => `${pt.x} ${pt.y}`).join(" L ")} Z`;
|
|
834
846
|
}
|
|
847
|
+
function getPieceColor(blueprint, usePrimitiveColors, defaultColor, primitiveColorIndices) {
|
|
848
|
+
if (!usePrimitiveColors) {
|
|
849
|
+
return defaultColor;
|
|
850
|
+
}
|
|
851
|
+
if ("kind" in blueprint) {
|
|
852
|
+
const kind = blueprint.kind;
|
|
853
|
+
const kindToIndex = {
|
|
854
|
+
"square": 0,
|
|
855
|
+
"smalltriangle": 1,
|
|
856
|
+
"parallelogram": 2,
|
|
857
|
+
"medtriangle": 3,
|
|
858
|
+
"largetriangle": 4
|
|
859
|
+
};
|
|
860
|
+
const primitiveIndex = kindToIndex[kind];
|
|
861
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
862
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
863
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
864
|
+
if (color) {
|
|
865
|
+
return color;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return defaultColor;
|
|
869
|
+
}
|
|
870
|
+
return defaultColor;
|
|
871
|
+
}
|
|
835
872
|
function BoardView(props) {
|
|
836
873
|
const {
|
|
837
874
|
controller,
|
|
@@ -851,6 +888,9 @@ function BoardView(props) {
|
|
|
851
888
|
dragInvalid,
|
|
852
889
|
lockedPieceId,
|
|
853
890
|
showTangramDecomposition,
|
|
891
|
+
usePrimitiveColorsBlueprints,
|
|
892
|
+
usePrimitiveColorsTargets,
|
|
893
|
+
primitiveColorIndices,
|
|
854
894
|
svgRef,
|
|
855
895
|
setPieceRef,
|
|
856
896
|
onPiecePointerDown,
|
|
@@ -861,6 +901,144 @@ function BoardView(props) {
|
|
|
861
901
|
onCenterBadgePointerDown
|
|
862
902
|
} = props;
|
|
863
903
|
const VW = viewBox.w, VH = viewBox.h;
|
|
904
|
+
const renderSilhouettes = () => layout.sectors.map((s) => {
|
|
905
|
+
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
906
|
+
if (showTangramDecomposition && sectorCfg?.silhouette.primitiveDecomposition) {
|
|
907
|
+
const primitiveDecomposition = sectorCfg.silhouette.primitiveDecomposition;
|
|
908
|
+
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
909
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
910
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
911
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
912
|
+
const primInfo = primitiveDecomposition[i];
|
|
913
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
914
|
+
if (usePrimitiveColorsTargets && primInfo?.kind && primitiveColorIndices) {
|
|
915
|
+
const kindToIndex = {
|
|
916
|
+
"square": 0,
|
|
917
|
+
"smalltriangle": 1,
|
|
918
|
+
"parallelogram": 2,
|
|
919
|
+
"medtriangle": 3,
|
|
920
|
+
"largetriangle": 4
|
|
921
|
+
};
|
|
922
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
923
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
924
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
925
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
926
|
+
if (color) {
|
|
927
|
+
fillColor = color;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return /* @__PURE__ */ React.createElement(
|
|
932
|
+
"path",
|
|
933
|
+
{
|
|
934
|
+
key: `prim-fill-${i}`,
|
|
935
|
+
d: pathD(scaledPoly),
|
|
936
|
+
fill: fillColor,
|
|
937
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
938
|
+
stroke: "none"
|
|
939
|
+
}
|
|
940
|
+
);
|
|
941
|
+
}));
|
|
942
|
+
} else {
|
|
943
|
+
const placedPolys = placedSilBySector.get(s.id) ?? [];
|
|
944
|
+
if (!placedPolys.length) return null;
|
|
945
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-${s.id}`, pointerEvents: "none" }, placedPolys.map((poly, i) => /* @__PURE__ */ React.createElement("path", { key: i, d: pathD(poly), fill: CONFIG.color.silhouetteMask, opacity: CONFIG.opacity.silhouetteMask })));
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
const renderPieces = (piecesFilter) => {
|
|
949
|
+
const piecesToRender = pieces;
|
|
950
|
+
return piecesToRender.sort((a, b) => {
|
|
951
|
+
if (draggingId === a.id) return 1;
|
|
952
|
+
if (draggingId === b.id) return -1;
|
|
953
|
+
return 0;
|
|
954
|
+
}).map((p) => {
|
|
955
|
+
const bp = controller.getBlueprint(p.blueprintId);
|
|
956
|
+
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
957
|
+
const isDragging = draggingId === p.id;
|
|
958
|
+
const locked = p.sectorId && controller.isSectorCompleted(p.sectorId);
|
|
959
|
+
const isConnectivityLocked = lockedPieceId === p.id;
|
|
960
|
+
selectedPieceId === p.id;
|
|
961
|
+
const isCarriedInvalid = isDragging && dragInvalid;
|
|
962
|
+
const translateX = p.x - bb.min.x;
|
|
963
|
+
const translateY = p.y - bb.min.y;
|
|
964
|
+
const validFillColor = getPieceColor(
|
|
965
|
+
bp,
|
|
966
|
+
usePrimitiveColorsBlueprints || false,
|
|
967
|
+
CONFIG.color.piece.validFill,
|
|
968
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
969
|
+
);
|
|
970
|
+
const draggingFillColor = getPieceColor(
|
|
971
|
+
bp,
|
|
972
|
+
usePrimitiveColorsBlueprints || false,
|
|
973
|
+
CONFIG.color.piece.draggingFill,
|
|
974
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
975
|
+
);
|
|
976
|
+
return /* @__PURE__ */ React.createElement("g", { key: p.id, ref: setPieceRef(p.id), transform: `translate(${translateX}, ${translateY})`, style: { cursor: locked ? "default" : clickMode ? "pointer" : "grab" }, pointerEvents: clickMode && isDragging ? "none" : "auto" }, ("shape" in bp ? bp.shape : []).map((poly, idx) => {
|
|
977
|
+
const showBorders = shouldShowBorders();
|
|
978
|
+
shouldUseSelectiveBorders(p.blueprintId);
|
|
979
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
|
|
980
|
+
"path",
|
|
981
|
+
{
|
|
982
|
+
d: pathD(poly),
|
|
983
|
+
fill: isConnectivityLocked ? CONFIG.color.piece.invalidFill : isCarriedInvalid ? CONFIG.color.piece.invalidFill : isDragging ? draggingFillColor : validFillColor,
|
|
984
|
+
opacity: isConnectivityLocked ? CONFIG.opacity.piece.invalid : isCarriedInvalid ? CONFIG.opacity.piece.invalid : isDragging ? CONFIG.opacity.piece.dragging : locked ? CONFIG.opacity.piece.locked : CONFIG.opacity.piece.normal,
|
|
985
|
+
stroke: "none",
|
|
986
|
+
onPointerDown: (e) => onPiecePointerDown(e, p)
|
|
987
|
+
}
|
|
988
|
+
), showBorders);
|
|
989
|
+
}), isDragging && isCarriedInvalid && "shape" in bp && bp.shape.length > 0 && (() => {
|
|
990
|
+
const { cx, cy } = polysAABB$1(bp.shape);
|
|
991
|
+
const size = CONFIG.size.invalidMarker.sizePx;
|
|
992
|
+
const strokeWidth = CONFIG.size.invalidMarker.strokePx;
|
|
993
|
+
const borderWidth = strokeWidth + 2;
|
|
994
|
+
return /* @__PURE__ */ React.createElement("g", { key: "invalid-marker" }, /* @__PURE__ */ React.createElement(
|
|
995
|
+
"line",
|
|
996
|
+
{
|
|
997
|
+
x1: cx - size,
|
|
998
|
+
y1: cy - size,
|
|
999
|
+
x2: cx + size,
|
|
1000
|
+
y2: cy + size,
|
|
1001
|
+
stroke: "white",
|
|
1002
|
+
strokeWidth: borderWidth,
|
|
1003
|
+
strokeLinecap: "round"
|
|
1004
|
+
}
|
|
1005
|
+
), /* @__PURE__ */ React.createElement(
|
|
1006
|
+
"line",
|
|
1007
|
+
{
|
|
1008
|
+
x1: cx - size,
|
|
1009
|
+
y1: cy - size,
|
|
1010
|
+
x2: cx + size,
|
|
1011
|
+
y2: cy + size,
|
|
1012
|
+
stroke: CONFIG.color.piece.invalidStroke,
|
|
1013
|
+
strokeWidth,
|
|
1014
|
+
strokeLinecap: "round"
|
|
1015
|
+
}
|
|
1016
|
+
), /* @__PURE__ */ React.createElement(
|
|
1017
|
+
"line",
|
|
1018
|
+
{
|
|
1019
|
+
x1: cx + size,
|
|
1020
|
+
y1: cy - size,
|
|
1021
|
+
x2: cx - size,
|
|
1022
|
+
y2: cy + size,
|
|
1023
|
+
stroke: "white",
|
|
1024
|
+
strokeWidth: borderWidth,
|
|
1025
|
+
strokeLinecap: "round"
|
|
1026
|
+
}
|
|
1027
|
+
), /* @__PURE__ */ React.createElement(
|
|
1028
|
+
"line",
|
|
1029
|
+
{
|
|
1030
|
+
x1: cx + size,
|
|
1031
|
+
y1: cy - size,
|
|
1032
|
+
x2: cx - size,
|
|
1033
|
+
y2: cy + size,
|
|
1034
|
+
stroke: CONFIG.color.piece.invalidStroke,
|
|
1035
|
+
strokeWidth,
|
|
1036
|
+
strokeLinecap: "round"
|
|
1037
|
+
}
|
|
1038
|
+
));
|
|
1039
|
+
})());
|
|
1040
|
+
});
|
|
1041
|
+
};
|
|
864
1042
|
const centerView = controller.state.blueprintView;
|
|
865
1043
|
const bps = centerView === "primitives" ? controller.state.primitives : controller.state.quickstash;
|
|
866
1044
|
const QS_SLOTS = controller.state.cfg.maxQuickstashSlots;
|
|
@@ -881,6 +1059,12 @@ function BoardView(props) {
|
|
|
881
1059
|
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
882
1060
|
const cx = bb.min.x + bb.width / 2;
|
|
883
1061
|
const cy = bb.min.y + bb.height / 2;
|
|
1062
|
+
const fillColor = getPieceColor(
|
|
1063
|
+
bp,
|
|
1064
|
+
usePrimitiveColorsBlueprints || false,
|
|
1065
|
+
CONFIG.color.blueprint.fill,
|
|
1066
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
1067
|
+
);
|
|
884
1068
|
return /* @__PURE__ */ React.createElement(
|
|
885
1069
|
"g",
|
|
886
1070
|
{
|
|
@@ -892,7 +1076,7 @@ function BoardView(props) {
|
|
|
892
1076
|
{
|
|
893
1077
|
key: idx,
|
|
894
1078
|
d: pathD(poly),
|
|
895
|
-
fill:
|
|
1079
|
+
fill: fillColor,
|
|
896
1080
|
opacity: CONFIG.opacity.blueprint,
|
|
897
1081
|
stroke: "none",
|
|
898
1082
|
strokeWidth: 0,
|
|
@@ -916,7 +1100,7 @@ function BoardView(props) {
|
|
|
916
1100
|
onPointerDown: (e) => {
|
|
917
1101
|
onRootPointerDown(e);
|
|
918
1102
|
},
|
|
919
|
-
style: { background:
|
|
1103
|
+
style: { background: CONFIG.color.background, touchAction: "none", userSelect: "none" }
|
|
920
1104
|
},
|
|
921
1105
|
layout.sectors.map((s, i) => {
|
|
922
1106
|
const done = !!controller.state.sectors[s.id].completedAt;
|
|
@@ -926,35 +1110,7 @@ function BoardView(props) {
|
|
|
926
1110
|
const work = layout.bands.workspace;
|
|
927
1111
|
return /* @__PURE__ */ React.createElement("g", { key: `bands-${s.id}` }, controller.state.cfg.target === "workspace" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("path", { d: wedgePath(layout.cx, layout.cy, sil[0], sil[1], s.start, s.end), fill: baseSil, stroke: CONFIG.color.bands.silhouette.stroke, strokeWidth: CONFIG.size.stroke.bandPx, pointerEvents: "none" }), /* @__PURE__ */ React.createElement("path", { d: wedgePath(layout.cx, layout.cy, work[0], work[1], s.start, s.end), fill: done ? CONFIG.color.completion.fill : baseWork, stroke: done ? CONFIG.color.completion.stroke : CONFIG.color.bands.workspace.stroke, strokeWidth: CONFIG.size.stroke.bandPx, pointerEvents: "none" })) : /* @__PURE__ */ React.createElement("path", { d: wedgePath(layout.cx, layout.cy, sil[0], sil[1], s.start, s.end), fill: done ? CONFIG.color.completion.fill : baseSil, stroke: done ? CONFIG.color.completion.stroke : CONFIG.color.bands.silhouette.stroke, strokeWidth: CONFIG.size.stroke.bandPx, pointerEvents: "none" }));
|
|
928
1112
|
}),
|
|
929
|
-
|
|
930
|
-
if (draggingId === a.id) return 1;
|
|
931
|
-
if (draggingId === b.id) return -1;
|
|
932
|
-
return 0;
|
|
933
|
-
}).map((p) => {
|
|
934
|
-
const bp = controller.getBlueprint(p.blueprintId);
|
|
935
|
-
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
936
|
-
const isDragging = draggingId === p.id;
|
|
937
|
-
const locked = p.sectorId && controller.isSectorCompleted(p.sectorId);
|
|
938
|
-
const isConnectivityLocked = lockedPieceId === p.id;
|
|
939
|
-
selectedPieceId === p.id;
|
|
940
|
-
const isCarriedInvalid = isDragging && dragInvalid;
|
|
941
|
-
const translateX = p.x - bb.min.x;
|
|
942
|
-
const translateY = p.y - bb.min.y;
|
|
943
|
-
return /* @__PURE__ */ React.createElement("g", { key: p.id, ref: setPieceRef(p.id), transform: `translate(${translateX}, ${translateY})`, style: { cursor: locked ? "default" : clickMode ? "pointer" : "grab" }, pointerEvents: clickMode && isDragging ? "none" : "auto" }, ("shape" in bp ? bp.shape : []).map((poly, idx) => {
|
|
944
|
-
const showBorders = shouldShowBorders();
|
|
945
|
-
shouldUseSelectiveBorders(p.blueprintId);
|
|
946
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
|
|
947
|
-
"path",
|
|
948
|
-
{
|
|
949
|
-
d: pathD(poly),
|
|
950
|
-
fill: isConnectivityLocked ? CONFIG.color.piece.invalidFill : isCarriedInvalid ? CONFIG.color.piece.invalidFill : isDragging ? CONFIG.color.piece.draggingFill : CONFIG.color.piece.validFill,
|
|
951
|
-
opacity: isConnectivityLocked ? CONFIG.opacity.piece.invalid : isCarriedInvalid ? CONFIG.opacity.piece.invalid : isDragging ? CONFIG.opacity.piece.dragging : locked ? CONFIG.opacity.piece.locked : CONFIG.opacity.piece.normal,
|
|
952
|
-
stroke: "none",
|
|
953
|
-
onPointerDown: (e) => onPiecePointerDown(e, p)
|
|
954
|
-
}
|
|
955
|
-
), showBorders);
|
|
956
|
-
}));
|
|
957
|
-
}),
|
|
1113
|
+
/* @__PURE__ */ React.createElement(React.Fragment, null, renderSilhouettes(), renderPieces()) ,
|
|
958
1114
|
layout.sectors.map((s) => {
|
|
959
1115
|
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
960
1116
|
if (showTangramDecomposition && sectorCfg?.silhouette.primitiveDecomposition) {
|
|
@@ -962,23 +1118,32 @@ function BoardView(props) {
|
|
|
962
1118
|
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
963
1119
|
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
964
1120
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
965
|
-
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
966
|
-
|
|
967
|
-
{
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
1121
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
1122
|
+
const primInfo = primitiveDecomposition[i];
|
|
1123
|
+
if (usePrimitiveColorsTargets && primInfo?.kind && primitiveColorIndices) {
|
|
1124
|
+
const kindToIndex = {
|
|
1125
|
+
"square": 0,
|
|
1126
|
+
"smalltriangle": 1,
|
|
1127
|
+
"parallelogram": 2,
|
|
1128
|
+
"medtriangle": 3,
|
|
1129
|
+
"largetriangle": 4
|
|
1130
|
+
};
|
|
1131
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
1132
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
1133
|
+
primitiveColorIndices[primitiveIndex];
|
|
1134
|
+
}
|
|
980
1135
|
}
|
|
981
|
-
|
|
1136
|
+
return /* @__PURE__ */ React.createElement(
|
|
1137
|
+
"path",
|
|
1138
|
+
{
|
|
1139
|
+
key: `prim-fill-${i}`,
|
|
1140
|
+
d: pathD(scaledPoly),
|
|
1141
|
+
fill: "none",
|
|
1142
|
+
opacity: 0,
|
|
1143
|
+
stroke: "none"
|
|
1144
|
+
}
|
|
1145
|
+
);
|
|
1146
|
+
}));
|
|
982
1147
|
} else {
|
|
983
1148
|
const placedPolys = placedSilBySector.get(s.id) ?? [];
|
|
984
1149
|
if (!placedPolys.length) return null;
|
|
@@ -1069,7 +1234,25 @@ function BoardView(props) {
|
|
|
1069
1234
|
const by = layout.cy + blueprintRingR * Math.sin(theta);
|
|
1070
1235
|
return renderBlueprintGlyph(bp, bx, by);
|
|
1071
1236
|
}),
|
|
1072
|
-
controller.state.endedAt && /* @__PURE__ */ React.createElement("g", { pointerEvents: "none" }, /* @__PURE__ */ React.createElement("circle", { cx: layout.cx, cy: layout.cy, r: layout.outerR - 3, fill: "none", stroke: CONFIG.color.piece.allGreenStroke, strokeWidth: CONFIG.size.stroke.allGreenStrokePx, opacity: 0 }, /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "0", to: "1", dur: "160ms", fill: "freeze" }), /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "1", to: "0", begin: "560ms", dur: "520ms", fill: "freeze" })))
|
|
1237
|
+
controller.state.endedAt && /* @__PURE__ */ React.createElement("g", { pointerEvents: "none" }, /* @__PURE__ */ React.createElement("circle", { cx: layout.cx, cy: layout.cy, r: layout.outerR - 3, fill: "none", stroke: CONFIG.color.piece.allGreenStroke, strokeWidth: CONFIG.size.stroke.allGreenStrokePx, opacity: 0 }, /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "0", to: "1", dur: "160ms", fill: "freeze" }), /* @__PURE__ */ React.createElement("animate", { attributeName: "opacity", from: "1", to: "0", begin: "560ms", dur: "520ms", fill: "freeze" }))),
|
|
1238
|
+
showTangramDecomposition && layout.sectors.map((s) => {
|
|
1239
|
+
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
1240
|
+
if (!sectorCfg?.silhouette.primitiveDecomposition) return null;
|
|
1241
|
+
const primitiveDecomposition = sectorCfg.silhouette.primitiveDecomposition;
|
|
1242
|
+
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
1243
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
1244
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
1245
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-borders-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => /* @__PURE__ */ React.createElement(
|
|
1246
|
+
"path",
|
|
1247
|
+
{
|
|
1248
|
+
key: `prim-border-${i}`,
|
|
1249
|
+
d: pathD(scaledPoly),
|
|
1250
|
+
fill: "none",
|
|
1251
|
+
stroke: CONFIG.color.tangramDecomposition.stroke,
|
|
1252
|
+
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
1253
|
+
}
|
|
1254
|
+
)));
|
|
1255
|
+
})
|
|
1073
1256
|
);
|
|
1074
1257
|
}
|
|
1075
1258
|
|
|
@@ -2954,7 +3137,10 @@ function GameBoard(props) {
|
|
|
2954
3137
|
onPieceRemove,
|
|
2955
3138
|
onInteraction,
|
|
2956
3139
|
onTrialEnd,
|
|
2957
|
-
onControllerReady
|
|
3140
|
+
onControllerReady,
|
|
3141
|
+
usePrimitiveColorsBlueprints,
|
|
3142
|
+
usePrimitiveColorsTargets,
|
|
3143
|
+
primitiveColorIndices
|
|
2958
3144
|
} = props;
|
|
2959
3145
|
const [timeRemaining, setTimeRemaining] = React.useState(timeLimitMs > 0 ? Math.floor(timeLimitMs / 1e3) : 0);
|
|
2960
3146
|
const controller = React.useMemo(() => {
|
|
@@ -3278,7 +3464,7 @@ function GameBoard(props) {
|
|
|
3278
3464
|
justifyContent: "center",
|
|
3279
3465
|
alignItems: "center",
|
|
3280
3466
|
padding: "20px",
|
|
3281
|
-
background:
|
|
3467
|
+
background: CONFIG.color.background,
|
|
3282
3468
|
flex: "0 0 auto"
|
|
3283
3469
|
};
|
|
3284
3470
|
const headerContentStyle = {
|
|
@@ -3294,14 +3480,20 @@ function GameBoard(props) {
|
|
|
3294
3480
|
lineHeight: 1.5,
|
|
3295
3481
|
textAlign: "center"
|
|
3296
3482
|
};
|
|
3483
|
+
const scaleX = svgDimensions.width / viewBox.w;
|
|
3484
|
+
const rightEdgeOfSemicircleLogical = viewBox.w / 2 + layout.outerR;
|
|
3485
|
+
const distanceFromRightEdgeLogical = viewBox.w - rightEdgeOfSemicircleLogical;
|
|
3486
|
+
const distanceFromRightEdgePx = distanceFromRightEdgeLogical * scaleX;
|
|
3487
|
+
const charWidth = 24 * 0.6;
|
|
3488
|
+
const offsetLeft = charWidth * 5;
|
|
3297
3489
|
const timerStyle = {
|
|
3298
3490
|
position: "absolute",
|
|
3299
|
-
right:
|
|
3491
|
+
right: `${distanceFromRightEdgePx + offsetLeft}px`,
|
|
3300
3492
|
fontSize: "24px",
|
|
3301
3493
|
fontWeight: "bold",
|
|
3302
3494
|
fontFamily: "monospace",
|
|
3303
3495
|
color: "#333",
|
|
3304
|
-
|
|
3496
|
+
whiteSpace: "nowrap",
|
|
3305
3497
|
textAlign: "right"
|
|
3306
3498
|
};
|
|
3307
3499
|
const gameboardWrapperStyle = {
|
|
@@ -3346,6 +3538,9 @@ function GameBoard(props) {
|
|
|
3346
3538
|
onCenterBadgePointerDown,
|
|
3347
3539
|
showTangramDecomposition: showTangramDecomposition ?? false,
|
|
3348
3540
|
scaleS,
|
|
3541
|
+
usePrimitiveColorsBlueprints: usePrimitiveColorsBlueprints ?? false,
|
|
3542
|
+
usePrimitiveColorsTargets: usePrimitiveColorsTargets ?? false,
|
|
3543
|
+
primitiveColorIndices: primitiveColorIndices ?? [0, 1, 2, 3, 4],
|
|
3349
3544
|
...eventCallbacks
|
|
3350
3545
|
}
|
|
3351
3546
|
))));
|
|
@@ -3565,7 +3760,10 @@ function startConstructionTrial(display_element, params, _jsPsych) {
|
|
|
3565
3760
|
trialParams,
|
|
3566
3761
|
...params.instructions && { instructions: params.instructions },
|
|
3567
3762
|
...params.onInteraction && { onInteraction: params.onInteraction },
|
|
3568
|
-
...params.onTrialEnd && { onTrialEnd: params.onTrialEnd }
|
|
3763
|
+
...params.onTrialEnd && { onTrialEnd: params.onTrialEnd },
|
|
3764
|
+
...params.usePrimitiveColorsBlueprints !== void 0 && { usePrimitiveColorsBlueprints: params.usePrimitiveColorsBlueprints },
|
|
3765
|
+
...params.usePrimitiveColorsTargets !== void 0 && { usePrimitiveColorsTargets: params.usePrimitiveColorsTargets },
|
|
3766
|
+
...params.primitiveColorIndices !== void 0 && { primitiveColorIndices: params.primitiveColorIndices }
|
|
3569
3767
|
};
|
|
3570
3768
|
const root = client.createRoot(display_element);
|
|
3571
3769
|
root.render(React.createElement(GameBoard, gameBoardProps));
|
|
@@ -3650,6 +3848,24 @@ const info$2 = {
|
|
|
3650
3848
|
type: jspsych.ParameterType.FUNCTION,
|
|
3651
3849
|
default: void 0,
|
|
3652
3850
|
description: "Callback when trial completes with full data"
|
|
3851
|
+
},
|
|
3852
|
+
/** Whether to use distinct colors for each primitive shape type in blueprints */
|
|
3853
|
+
use_primitive_colors_blueprints: {
|
|
3854
|
+
type: jspsych.ParameterType.BOOL,
|
|
3855
|
+
default: false,
|
|
3856
|
+
description: "Whether each primitive shape type should have its own distinct color in the blueprint dock area"
|
|
3857
|
+
},
|
|
3858
|
+
/** Whether to use distinct colors for each primitive shape type in target tangrams */
|
|
3859
|
+
use_primitive_colors_targets: {
|
|
3860
|
+
type: jspsych.ParameterType.BOOL,
|
|
3861
|
+
default: false,
|
|
3862
|
+
description: "Whether each primitive shape type should have its own distinct color in target tangram silhouettes"
|
|
3863
|
+
},
|
|
3864
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
3865
|
+
primitive_color_indices: {
|
|
3866
|
+
type: jspsych.ParameterType.OBJECT,
|
|
3867
|
+
default: [0, 1, 2, 3, 4],
|
|
3868
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
3653
3869
|
}
|
|
3654
3870
|
},
|
|
3655
3871
|
data: {
|
|
@@ -3715,7 +3931,10 @@ class TangramConstructPlugin {
|
|
|
3715
3931
|
show_tangram_decomposition: trial.show_tangram_decomposition,
|
|
3716
3932
|
instructions: trial.instructions,
|
|
3717
3933
|
onInteraction: trial.onInteraction,
|
|
3718
|
-
onTrialEnd: wrappedOnTrialEnd
|
|
3934
|
+
onTrialEnd: wrappedOnTrialEnd,
|
|
3935
|
+
usePrimitiveColorsBlueprints: trial.use_primitive_colors_blueprints,
|
|
3936
|
+
usePrimitiveColorsTargets: trial.use_primitive_colors_targets,
|
|
3937
|
+
primitiveColorIndices: trial.primitive_color_indices
|
|
3719
3938
|
};
|
|
3720
3939
|
const { root, display_element: element, jsPsych } = startConstructionTrial(display_element, params, this.jsPsych);
|
|
3721
3940
|
element.__reactContext = { root, jsPsych };
|
|
@@ -3733,7 +3952,9 @@ function startPrepTrial(display_element, params, jsPsych) {
|
|
|
3733
3952
|
quickstashMacros,
|
|
3734
3953
|
primitiveOrder,
|
|
3735
3954
|
onInteraction,
|
|
3736
|
-
onTrialEnd
|
|
3955
|
+
onTrialEnd,
|
|
3956
|
+
usePrimitiveColorsBlueprints,
|
|
3957
|
+
primitiveColorIndices
|
|
3737
3958
|
} = params;
|
|
3738
3959
|
const { onInteraction: _, onTrialEnd: __, ...trialParams } = params;
|
|
3739
3960
|
const PRIMITIVE_BLUEPRINTS_ORDERED = [...PRIMITIVE_BLUEPRINTS].sort((a, b) => primitiveOrder.indexOf(a.kind) - primitiveOrder.indexOf(b.kind));
|
|
@@ -3825,7 +4046,9 @@ function startPrepTrial(display_element, params, jsPsych) {
|
|
|
3825
4046
|
...params.instructions && { instructions: params.instructions },
|
|
3826
4047
|
onControllerReady: handleControllerReady,
|
|
3827
4048
|
...onInteraction && { onInteraction },
|
|
3828
|
-
...onTrialEnd && { onTrialEnd }
|
|
4049
|
+
...onTrialEnd && { onTrialEnd },
|
|
4050
|
+
...usePrimitiveColorsBlueprints !== void 0 && { usePrimitiveColorsBlueprints },
|
|
4051
|
+
...primitiveColorIndices !== void 0 && { primitiveColorIndices }
|
|
3829
4052
|
}));
|
|
3830
4053
|
return { root, display_element, jsPsych };
|
|
3831
4054
|
}
|
|
@@ -3891,6 +4114,18 @@ const info$1 = {
|
|
|
3891
4114
|
onTrialEnd: {
|
|
3892
4115
|
type: jspsych.ParameterType.FUNCTION,
|
|
3893
4116
|
default: void 0
|
|
4117
|
+
},
|
|
4118
|
+
/** Whether to use distinct colors for each primitive shape type in blueprints */
|
|
4119
|
+
use_primitive_colors_blueprints: {
|
|
4120
|
+
type: jspsych.ParameterType.BOOL,
|
|
4121
|
+
default: false,
|
|
4122
|
+
description: "Whether each primitive shape type should have its own distinct color in the blueprint dock area"
|
|
4123
|
+
},
|
|
4124
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
4125
|
+
primitive_color_indices: {
|
|
4126
|
+
type: jspsych.ParameterType.OBJECT,
|
|
4127
|
+
default: [0, 1, 2, 3, 4],
|
|
4128
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
3894
4129
|
}
|
|
3895
4130
|
},
|
|
3896
4131
|
data: {
|
|
@@ -3935,7 +4170,9 @@ class TangramPrepPlugin {
|
|
|
3935
4170
|
primitiveOrder: trial.primitive_order,
|
|
3936
4171
|
instructions: trial.instructions,
|
|
3937
4172
|
onInteraction: trial.onInteraction,
|
|
3938
|
-
onTrialEnd: wrappedOnTrialEnd
|
|
4173
|
+
onTrialEnd: wrappedOnTrialEnd,
|
|
4174
|
+
usePrimitiveColorsBlueprints: trial.use_primitive_colors_blueprints,
|
|
4175
|
+
primitiveColorIndices: trial.primitive_color_indices
|
|
3939
4176
|
};
|
|
3940
4177
|
const { root, display_element: element, jsPsych } = startPrepTrial(display_element, params, this.jsPsych);
|
|
3941
4178
|
element.__reactContext = { root, jsPsych };
|
|
@@ -3955,6 +4192,8 @@ function NBackView({ params }) {
|
|
|
3955
4192
|
instructions,
|
|
3956
4193
|
button_text,
|
|
3957
4194
|
duration,
|
|
4195
|
+
usePrimitiveColors,
|
|
4196
|
+
primitiveColorIndices,
|
|
3958
4197
|
onTrialEnd
|
|
3959
4198
|
} = params;
|
|
3960
4199
|
const trialStartTime = React.useRef(Date.now());
|
|
@@ -4010,7 +4249,12 @@ function NBackView({ params }) {
|
|
|
4010
4249
|
...data,
|
|
4011
4250
|
accuracy,
|
|
4012
4251
|
tangram_id: tangram.tangramID,
|
|
4013
|
-
is_match: isMatch
|
|
4252
|
+
is_match: isMatch,
|
|
4253
|
+
show_tangram_decomposition,
|
|
4254
|
+
use_primitive_colors: usePrimitiveColors,
|
|
4255
|
+
primitive_color_indices: primitiveColorIndices,
|
|
4256
|
+
duration,
|
|
4257
|
+
button_text
|
|
4014
4258
|
};
|
|
4015
4259
|
if (onTrialEnd) {
|
|
4016
4260
|
onTrialEnd(trialData);
|
|
@@ -4064,35 +4308,77 @@ function NBackView({ params }) {
|
|
|
4064
4308
|
if (show_tangram_decomposition) {
|
|
4065
4309
|
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
4066
4310
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, centerPos);
|
|
4067
|
-
return /* @__PURE__ */ React.createElement("g", { key: "sil-decomposed", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4311
|
+
return /* @__PURE__ */ React.createElement("g", { key: "sil-decomposed", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
4312
|
+
const primInfo = primitiveDecomposition[i];
|
|
4313
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
4314
|
+
if (usePrimitiveColors && primInfo?.kind && primitiveColorIndices) {
|
|
4315
|
+
const kindToIndex = {
|
|
4316
|
+
"square": 0,
|
|
4317
|
+
"smalltriangle": 1,
|
|
4318
|
+
"parallelogram": 2,
|
|
4319
|
+
"medtriangle": 3,
|
|
4320
|
+
"largetriangle": 4
|
|
4321
|
+
};
|
|
4322
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
4323
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
4324
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
4325
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
4326
|
+
if (color) {
|
|
4327
|
+
fillColor = color;
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4082
4330
|
}
|
|
4083
|
-
|
|
4331
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: `prim-${i}` }, /* @__PURE__ */ React.createElement(
|
|
4332
|
+
"path",
|
|
4333
|
+
{
|
|
4334
|
+
d: pathD(scaledPoly),
|
|
4335
|
+
fill: fillColor,
|
|
4336
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
4337
|
+
stroke: "none"
|
|
4338
|
+
}
|
|
4339
|
+
), /* @__PURE__ */ React.createElement(
|
|
4340
|
+
"path",
|
|
4341
|
+
{
|
|
4342
|
+
d: pathD(scaledPoly),
|
|
4343
|
+
fill: "none",
|
|
4344
|
+
stroke: CONFIG.color.tangramDecomposition.stroke,
|
|
4345
|
+
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
4346
|
+
}
|
|
4347
|
+
));
|
|
4348
|
+
}));
|
|
4084
4349
|
} else {
|
|
4085
4350
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(mask, scaleS, centerPos);
|
|
4086
|
-
return /* @__PURE__ */ React.createElement("g", { key: "sil-unified", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4351
|
+
return /* @__PURE__ */ React.createElement("g", { key: "sil-unified", pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
4352
|
+
const primInfo = primitiveDecomposition[i];
|
|
4353
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
4354
|
+
if (usePrimitiveColors && primInfo?.kind && primitiveColorIndices) {
|
|
4355
|
+
const kindToIndex = {
|
|
4356
|
+
"square": 0,
|
|
4357
|
+
"smalltriangle": 1,
|
|
4358
|
+
"parallelogram": 2,
|
|
4359
|
+
"medtriangle": 3,
|
|
4360
|
+
"largetriangle": 4
|
|
4361
|
+
};
|
|
4362
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
4363
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
4364
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
4365
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
4366
|
+
if (color) {
|
|
4367
|
+
fillColor = color;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4094
4370
|
}
|
|
4095
|
-
|
|
4371
|
+
return /* @__PURE__ */ React.createElement(
|
|
4372
|
+
"path",
|
|
4373
|
+
{
|
|
4374
|
+
key: `sil-${i}`,
|
|
4375
|
+
d: pathD(scaledPoly),
|
|
4376
|
+
fill: fillColor,
|
|
4377
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
4378
|
+
stroke: "none"
|
|
4379
|
+
}
|
|
4380
|
+
);
|
|
4381
|
+
}));
|
|
4096
4382
|
}
|
|
4097
4383
|
};
|
|
4098
4384
|
return /* @__PURE__ */ React.createElement("div", { style: {
|
|
@@ -4101,7 +4387,7 @@ function NBackView({ params }) {
|
|
|
4101
4387
|
alignItems: "center",
|
|
4102
4388
|
justifyContent: "center",
|
|
4103
4389
|
padding: "20px",
|
|
4104
|
-
background: "#
|
|
4390
|
+
background: "#fff7e0ff"
|
|
4105
4391
|
} }, instructions && /* @__PURE__ */ React.createElement(
|
|
4106
4392
|
"div",
|
|
4107
4393
|
{
|
|
@@ -4191,6 +4477,18 @@ const info = {
|
|
|
4191
4477
|
default: 3e3,
|
|
4192
4478
|
description: "Duration in milliseconds to display tangram and accept responses"
|
|
4193
4479
|
},
|
|
4480
|
+
/** Whether to use distinct colors for each primitive shape type */
|
|
4481
|
+
use_primitive_colors: {
|
|
4482
|
+
type: jspsych.ParameterType.BOOL,
|
|
4483
|
+
default: false,
|
|
4484
|
+
description: "Whether each primitive shape type should have its own distinct color in the displayed tangram"
|
|
4485
|
+
},
|
|
4486
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
4487
|
+
primitive_color_indices: {
|
|
4488
|
+
type: jspsych.ParameterType.OBJECT,
|
|
4489
|
+
default: [0, 1, 2, 3, 4],
|
|
4490
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
4491
|
+
},
|
|
4194
4492
|
/** Callback fired when trial ends */
|
|
4195
4493
|
onTrialEnd: {
|
|
4196
4494
|
type: jspsych.ParameterType.FUNCTION,
|
|
@@ -4257,6 +4555,8 @@ class TangramNBackPlugin {
|
|
|
4257
4555
|
instructions: trial.instructions,
|
|
4258
4556
|
button_text: trial.button_text,
|
|
4259
4557
|
duration: trial.duration,
|
|
4558
|
+
usePrimitiveColors: trial.use_primitive_colors,
|
|
4559
|
+
primitiveColorIndices: trial.primitive_color_indices,
|
|
4260
4560
|
onTrialEnd: wrappedOnTrialEnd
|
|
4261
4561
|
};
|
|
4262
4562
|
const { root, display_element: element, jsPsych } = startNBackTrial(display_element, params, this.jsPsych);
|