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
|
@@ -16660,30 +16660,41 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
16660
16660
|
|
|
16661
16661
|
const CONFIG = {
|
|
16662
16662
|
color: {
|
|
16663
|
+
background: "#fff7e0ff",
|
|
16663
16664
|
bands: {
|
|
16664
|
-
silhouette: { fillEven: "#
|
|
16665
|
-
workspace: { fillEven: "#
|
|
16665
|
+
silhouette: { fillEven: "#ffffff", fillOdd: "#ffffff", stroke: "#b1b1b1" },
|
|
16666
|
+
workspace: { fillEven: "#ffffff", fillOdd: "#ffffff", stroke: "#b1b1b1" }
|
|
16666
16667
|
},
|
|
16667
|
-
completion: { fill: "#
|
|
16668
|
+
completion: { fill: "#ccffcc", stroke: "#13da57" },
|
|
16668
16669
|
silhouetteMask: "#374151",
|
|
16669
16670
|
anchors: { invalid: "#7dd3fc", valid: "#475569" },
|
|
16670
|
-
|
|
16671
|
+
// validFill used here for placed composites
|
|
16672
|
+
piece: { draggingFill: "#8e7cc3", validFill: "#8e7cc3", invalidFill: "#d55c00", invalidStroke: "#dc2626", selectedStroke: "#674ea7", allGreenStroke: "#86efac", borderStroke: "#674ea7" },
|
|
16671
16673
|
ui: { light: "#60a5fa", dark: "#1d4ed8" },
|
|
16672
16674
|
blueprint: { fill: "#374151", selectedStroke: "#111827", badgeFill: "#000000", labelFill: "#ffffff" },
|
|
16673
|
-
tangramDecomposition: { stroke: "#fef2cc" }
|
|
16675
|
+
tangramDecomposition: { stroke: "#fef2cc" },
|
|
16676
|
+
primitiveColors: [
|
|
16677
|
+
// from seaborn "colorblind" palette, 6 colors, with red omitted
|
|
16678
|
+
"#0173b2",
|
|
16679
|
+
"#de8f05",
|
|
16680
|
+
"#029e73",
|
|
16681
|
+
"#cc78bc",
|
|
16682
|
+
"#ca9161"
|
|
16683
|
+
]
|
|
16674
16684
|
},
|
|
16675
16685
|
opacity: {
|
|
16676
|
-
blueprint: 0.
|
|
16686
|
+
blueprint: 0.6,
|
|
16677
16687
|
silhouetteMask: 0.25,
|
|
16678
16688
|
//anchors: { valid: 0.80, invalid: 0.50 },
|
|
16679
16689
|
anchors: { invalid: 0, valid: 0 },
|
|
16680
|
-
piece: { invalid:
|
|
16690
|
+
piece: { invalid: 1, dragging: 1, locked: 1, normal: 1 }
|
|
16681
16691
|
},
|
|
16682
16692
|
size: {
|
|
16683
|
-
stroke: { bandPx: 5, pieceSelectedPx:
|
|
16693
|
+
stroke: { bandPx: 5, pieceSelectedPx: 5, allGreenStrokePx: 10, pieceBorderPx: 2, tangramDecompositionPx: 1 },
|
|
16684
16694
|
anchorRadiusPx: { valid: 1, invalid: 1 },
|
|
16685
16695
|
badgeFontPx: 16,
|
|
16686
|
-
centerBadge: { fractionOfOuterR: 0.15, minPx: 20, marginPx: 4 }
|
|
16696
|
+
centerBadge: { fractionOfOuterR: 0.15, minPx: 20, marginPx: 4 },
|
|
16697
|
+
invalidMarker: { sizePx: 10, strokePx: 4 }
|
|
16687
16698
|
},
|
|
16688
16699
|
layout: {
|
|
16689
16700
|
grid: { stepPx: 20, unitPx: 40 },
|
|
@@ -16701,7 +16712,8 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
16701
16712
|
game: {
|
|
16702
16713
|
snapRadiusPx: 15,
|
|
16703
16714
|
showBorders: false,
|
|
16704
|
-
hideTouchingBorders: true
|
|
16715
|
+
hideTouchingBorders: true,
|
|
16716
|
+
silhouettesBelowPieces: true
|
|
16705
16717
|
}
|
|
16706
16718
|
};
|
|
16707
16719
|
|
|
@@ -17485,6 +17497,31 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17485
17497
|
function pathD(poly) {
|
|
17486
17498
|
return `M ${poly.map((pt) => `${pt.x} ${pt.y}`).join(" L ")} Z`;
|
|
17487
17499
|
}
|
|
17500
|
+
function getPieceColor(blueprint, usePrimitiveColors, defaultColor, primitiveColorIndices) {
|
|
17501
|
+
if (!usePrimitiveColors) {
|
|
17502
|
+
return defaultColor;
|
|
17503
|
+
}
|
|
17504
|
+
if ("kind" in blueprint) {
|
|
17505
|
+
const kind = blueprint.kind;
|
|
17506
|
+
const kindToIndex = {
|
|
17507
|
+
"square": 0,
|
|
17508
|
+
"smalltriangle": 1,
|
|
17509
|
+
"parallelogram": 2,
|
|
17510
|
+
"medtriangle": 3,
|
|
17511
|
+
"largetriangle": 4
|
|
17512
|
+
};
|
|
17513
|
+
const primitiveIndex = kindToIndex[kind];
|
|
17514
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
17515
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
17516
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
17517
|
+
if (color) {
|
|
17518
|
+
return color;
|
|
17519
|
+
}
|
|
17520
|
+
}
|
|
17521
|
+
return defaultColor;
|
|
17522
|
+
}
|
|
17523
|
+
return defaultColor;
|
|
17524
|
+
}
|
|
17488
17525
|
function BoardView(props) {
|
|
17489
17526
|
const {
|
|
17490
17527
|
controller,
|
|
@@ -17504,6 +17541,9 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17504
17541
|
dragInvalid,
|
|
17505
17542
|
lockedPieceId,
|
|
17506
17543
|
showTangramDecomposition,
|
|
17544
|
+
usePrimitiveColorsBlueprints,
|
|
17545
|
+
usePrimitiveColorsTargets,
|
|
17546
|
+
primitiveColorIndices,
|
|
17507
17547
|
svgRef,
|
|
17508
17548
|
setPieceRef,
|
|
17509
17549
|
onPiecePointerDown,
|
|
@@ -17514,6 +17554,144 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17514
17554
|
onCenterBadgePointerDown
|
|
17515
17555
|
} = props;
|
|
17516
17556
|
const VW = viewBox.w, VH = viewBox.h;
|
|
17557
|
+
const renderSilhouettes = () => layout.sectors.map((s) => {
|
|
17558
|
+
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
17559
|
+
if (showTangramDecomposition && sectorCfg?.silhouette.primitiveDecomposition) {
|
|
17560
|
+
const primitiveDecomposition = sectorCfg.silhouette.primitiveDecomposition;
|
|
17561
|
+
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
17562
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
17563
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
17564
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
17565
|
+
const primInfo = primitiveDecomposition[i];
|
|
17566
|
+
let fillColor = CONFIG.color.silhouetteMask;
|
|
17567
|
+
if (usePrimitiveColorsTargets && primInfo?.kind && primitiveColorIndices) {
|
|
17568
|
+
const kindToIndex = {
|
|
17569
|
+
"square": 0,
|
|
17570
|
+
"smalltriangle": 1,
|
|
17571
|
+
"parallelogram": 2,
|
|
17572
|
+
"medtriangle": 3,
|
|
17573
|
+
"largetriangle": 4
|
|
17574
|
+
};
|
|
17575
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
17576
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
17577
|
+
const colorIndex = primitiveColorIndices[primitiveIndex];
|
|
17578
|
+
const color = CONFIG.color.primitiveColors[colorIndex];
|
|
17579
|
+
if (color) {
|
|
17580
|
+
fillColor = color;
|
|
17581
|
+
}
|
|
17582
|
+
}
|
|
17583
|
+
}
|
|
17584
|
+
return /* @__PURE__ */ React.createElement(
|
|
17585
|
+
"path",
|
|
17586
|
+
{
|
|
17587
|
+
key: `prim-fill-${i}`,
|
|
17588
|
+
d: pathD(scaledPoly),
|
|
17589
|
+
fill: fillColor,
|
|
17590
|
+
opacity: CONFIG.opacity.silhouetteMask,
|
|
17591
|
+
stroke: "none"
|
|
17592
|
+
}
|
|
17593
|
+
);
|
|
17594
|
+
}));
|
|
17595
|
+
} else {
|
|
17596
|
+
const placedPolys = placedSilBySector.get(s.id) ?? [];
|
|
17597
|
+
if (!placedPolys.length) return null;
|
|
17598
|
+
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 })));
|
|
17599
|
+
}
|
|
17600
|
+
});
|
|
17601
|
+
const renderPieces = (piecesFilter) => {
|
|
17602
|
+
const piecesToRender = pieces;
|
|
17603
|
+
return piecesToRender.sort((a, b) => {
|
|
17604
|
+
if (draggingId === a.id) return 1;
|
|
17605
|
+
if (draggingId === b.id) return -1;
|
|
17606
|
+
return 0;
|
|
17607
|
+
}).map((p) => {
|
|
17608
|
+
const bp = controller.getBlueprint(p.blueprintId);
|
|
17609
|
+
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
17610
|
+
const isDragging = draggingId === p.id;
|
|
17611
|
+
const locked = p.sectorId && controller.isSectorCompleted(p.sectorId);
|
|
17612
|
+
const isConnectivityLocked = lockedPieceId === p.id;
|
|
17613
|
+
selectedPieceId === p.id;
|
|
17614
|
+
const isCarriedInvalid = isDragging && dragInvalid;
|
|
17615
|
+
const translateX = p.x - bb.min.x;
|
|
17616
|
+
const translateY = p.y - bb.min.y;
|
|
17617
|
+
const validFillColor = getPieceColor(
|
|
17618
|
+
bp,
|
|
17619
|
+
usePrimitiveColorsBlueprints || false,
|
|
17620
|
+
CONFIG.color.piece.validFill,
|
|
17621
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
17622
|
+
);
|
|
17623
|
+
const draggingFillColor = getPieceColor(
|
|
17624
|
+
bp,
|
|
17625
|
+
usePrimitiveColorsBlueprints || false,
|
|
17626
|
+
CONFIG.color.piece.draggingFill,
|
|
17627
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
17628
|
+
);
|
|
17629
|
+
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) => {
|
|
17630
|
+
const showBorders = shouldShowBorders();
|
|
17631
|
+
shouldUseSelectiveBorders(p.blueprintId);
|
|
17632
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
|
|
17633
|
+
"path",
|
|
17634
|
+
{
|
|
17635
|
+
d: pathD(poly),
|
|
17636
|
+
fill: isConnectivityLocked ? CONFIG.color.piece.invalidFill : isCarriedInvalid ? CONFIG.color.piece.invalidFill : isDragging ? draggingFillColor : validFillColor,
|
|
17637
|
+
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,
|
|
17638
|
+
stroke: "none",
|
|
17639
|
+
onPointerDown: (e) => onPiecePointerDown(e, p)
|
|
17640
|
+
}
|
|
17641
|
+
), showBorders);
|
|
17642
|
+
}), isDragging && isCarriedInvalid && "shape" in bp && bp.shape.length > 0 && (() => {
|
|
17643
|
+
const { cx, cy } = polysAABB$1(bp.shape);
|
|
17644
|
+
const size = CONFIG.size.invalidMarker.sizePx;
|
|
17645
|
+
const strokeWidth = CONFIG.size.invalidMarker.strokePx;
|
|
17646
|
+
const borderWidth = strokeWidth + 2;
|
|
17647
|
+
return /* @__PURE__ */ React.createElement("g", { key: "invalid-marker" }, /* @__PURE__ */ React.createElement(
|
|
17648
|
+
"line",
|
|
17649
|
+
{
|
|
17650
|
+
x1: cx - size,
|
|
17651
|
+
y1: cy - size,
|
|
17652
|
+
x2: cx + size,
|
|
17653
|
+
y2: cy + size,
|
|
17654
|
+
stroke: "white",
|
|
17655
|
+
strokeWidth: borderWidth,
|
|
17656
|
+
strokeLinecap: "round"
|
|
17657
|
+
}
|
|
17658
|
+
), /* @__PURE__ */ React.createElement(
|
|
17659
|
+
"line",
|
|
17660
|
+
{
|
|
17661
|
+
x1: cx - size,
|
|
17662
|
+
y1: cy - size,
|
|
17663
|
+
x2: cx + size,
|
|
17664
|
+
y2: cy + size,
|
|
17665
|
+
stroke: CONFIG.color.piece.invalidStroke,
|
|
17666
|
+
strokeWidth,
|
|
17667
|
+
strokeLinecap: "round"
|
|
17668
|
+
}
|
|
17669
|
+
), /* @__PURE__ */ React.createElement(
|
|
17670
|
+
"line",
|
|
17671
|
+
{
|
|
17672
|
+
x1: cx + size,
|
|
17673
|
+
y1: cy - size,
|
|
17674
|
+
x2: cx - size,
|
|
17675
|
+
y2: cy + size,
|
|
17676
|
+
stroke: "white",
|
|
17677
|
+
strokeWidth: borderWidth,
|
|
17678
|
+
strokeLinecap: "round"
|
|
17679
|
+
}
|
|
17680
|
+
), /* @__PURE__ */ React.createElement(
|
|
17681
|
+
"line",
|
|
17682
|
+
{
|
|
17683
|
+
x1: cx + size,
|
|
17684
|
+
y1: cy - size,
|
|
17685
|
+
x2: cx - size,
|
|
17686
|
+
y2: cy + size,
|
|
17687
|
+
stroke: CONFIG.color.piece.invalidStroke,
|
|
17688
|
+
strokeWidth,
|
|
17689
|
+
strokeLinecap: "round"
|
|
17690
|
+
}
|
|
17691
|
+
));
|
|
17692
|
+
})());
|
|
17693
|
+
});
|
|
17694
|
+
};
|
|
17517
17695
|
const centerView = controller.state.blueprintView;
|
|
17518
17696
|
const bps = centerView === "primitives" ? controller.state.primitives : controller.state.quickstash;
|
|
17519
17697
|
const QS_SLOTS = controller.state.cfg.maxQuickstashSlots;
|
|
@@ -17534,6 +17712,12 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17534
17712
|
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
17535
17713
|
const cx = bb.min.x + bb.width / 2;
|
|
17536
17714
|
const cy = bb.min.y + bb.height / 2;
|
|
17715
|
+
const fillColor = getPieceColor(
|
|
17716
|
+
bp,
|
|
17717
|
+
usePrimitiveColorsBlueprints || false,
|
|
17718
|
+
CONFIG.color.blueprint.fill,
|
|
17719
|
+
primitiveColorIndices || [0, 1, 2, 3, 4]
|
|
17720
|
+
);
|
|
17537
17721
|
return /* @__PURE__ */ React.createElement(
|
|
17538
17722
|
"g",
|
|
17539
17723
|
{
|
|
@@ -17545,7 +17729,7 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17545
17729
|
{
|
|
17546
17730
|
key: idx,
|
|
17547
17731
|
d: pathD(poly),
|
|
17548
|
-
fill:
|
|
17732
|
+
fill: fillColor,
|
|
17549
17733
|
opacity: CONFIG.opacity.blueprint,
|
|
17550
17734
|
stroke: "none",
|
|
17551
17735
|
strokeWidth: 0,
|
|
@@ -17569,7 +17753,7 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17569
17753
|
onPointerDown: (e) => {
|
|
17570
17754
|
onRootPointerDown(e);
|
|
17571
17755
|
},
|
|
17572
|
-
style: { background:
|
|
17756
|
+
style: { background: CONFIG.color.background, touchAction: "none", userSelect: "none" }
|
|
17573
17757
|
},
|
|
17574
17758
|
layout.sectors.map((s, i) => {
|
|
17575
17759
|
const done = !!controller.state.sectors[s.id].completedAt;
|
|
@@ -17579,35 +17763,7 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17579
17763
|
const work = layout.bands.workspace;
|
|
17580
17764
|
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" }));
|
|
17581
17765
|
}),
|
|
17582
|
-
|
|
17583
|
-
if (draggingId === a.id) return 1;
|
|
17584
|
-
if (draggingId === b.id) return -1;
|
|
17585
|
-
return 0;
|
|
17586
|
-
}).map((p) => {
|
|
17587
|
-
const bp = controller.getBlueprint(p.blueprintId);
|
|
17588
|
-
const bb = boundsOfBlueprint(bp, (k) => controller.getPrimitive(k));
|
|
17589
|
-
const isDragging = draggingId === p.id;
|
|
17590
|
-
const locked = p.sectorId && controller.isSectorCompleted(p.sectorId);
|
|
17591
|
-
const isConnectivityLocked = lockedPieceId === p.id;
|
|
17592
|
-
selectedPieceId === p.id;
|
|
17593
|
-
const isCarriedInvalid = isDragging && dragInvalid;
|
|
17594
|
-
const translateX = p.x - bb.min.x;
|
|
17595
|
-
const translateY = p.y - bb.min.y;
|
|
17596
|
-
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) => {
|
|
17597
|
-
const showBorders = shouldShowBorders();
|
|
17598
|
-
shouldUseSelectiveBorders(p.blueprintId);
|
|
17599
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
|
|
17600
|
-
"path",
|
|
17601
|
-
{
|
|
17602
|
-
d: pathD(poly),
|
|
17603
|
-
fill: isConnectivityLocked ? CONFIG.color.piece.invalidFill : isCarriedInvalid ? CONFIG.color.piece.invalidFill : isDragging ? CONFIG.color.piece.draggingFill : CONFIG.color.piece.validFill,
|
|
17604
|
-
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,
|
|
17605
|
-
stroke: "none",
|
|
17606
|
-
onPointerDown: (e) => onPiecePointerDown(e, p)
|
|
17607
|
-
}
|
|
17608
|
-
), showBorders);
|
|
17609
|
-
}));
|
|
17610
|
-
}),
|
|
17766
|
+
/* @__PURE__ */ React.createElement(React.Fragment, null, renderSilhouettes(), renderPieces()) ,
|
|
17611
17767
|
layout.sectors.map((s) => {
|
|
17612
17768
|
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
17613
17769
|
if (showTangramDecomposition && sectorCfg?.silhouette.primitiveDecomposition) {
|
|
@@ -17615,23 +17771,32 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17615
17771
|
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
17616
17772
|
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
17617
17773
|
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
17618
|
-
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) =>
|
|
17619
|
-
|
|
17620
|
-
{
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
17774
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-decomposed-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => {
|
|
17775
|
+
const primInfo = primitiveDecomposition[i];
|
|
17776
|
+
if (usePrimitiveColorsTargets && primInfo?.kind && primitiveColorIndices) {
|
|
17777
|
+
const kindToIndex = {
|
|
17778
|
+
"square": 0,
|
|
17779
|
+
"smalltriangle": 1,
|
|
17780
|
+
"parallelogram": 2,
|
|
17781
|
+
"medtriangle": 3,
|
|
17782
|
+
"largetriangle": 4
|
|
17783
|
+
};
|
|
17784
|
+
const primitiveIndex = kindToIndex[primInfo.kind];
|
|
17785
|
+
if (primitiveIndex !== void 0 && primitiveColorIndices[primitiveIndex] !== void 0) {
|
|
17786
|
+
primitiveColorIndices[primitiveIndex];
|
|
17787
|
+
}
|
|
17633
17788
|
}
|
|
17634
|
-
|
|
17789
|
+
return /* @__PURE__ */ React.createElement(
|
|
17790
|
+
"path",
|
|
17791
|
+
{
|
|
17792
|
+
key: `prim-fill-${i}`,
|
|
17793
|
+
d: pathD(scaledPoly),
|
|
17794
|
+
fill: "none",
|
|
17795
|
+
opacity: 0,
|
|
17796
|
+
stroke: "none"
|
|
17797
|
+
}
|
|
17798
|
+
);
|
|
17799
|
+
}));
|
|
17635
17800
|
} else {
|
|
17636
17801
|
const placedPolys = placedSilBySector.get(s.id) ?? [];
|
|
17637
17802
|
if (!placedPolys.length) return null;
|
|
@@ -17722,7 +17887,25 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
17722
17887
|
const by = layout.cy + blueprintRingR * Math.sin(theta);
|
|
17723
17888
|
return renderBlueprintGlyph(bp, bx, by);
|
|
17724
17889
|
}),
|
|
17725
|
-
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" })))
|
|
17890
|
+
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" }))),
|
|
17891
|
+
showTangramDecomposition && layout.sectors.map((s) => {
|
|
17892
|
+
const sectorCfg = controller.state.cfg.sectors.find((ss) => ss.id === s.id);
|
|
17893
|
+
if (!sectorCfg?.silhouette.primitiveDecomposition) return null;
|
|
17894
|
+
const primitiveDecomposition = sectorCfg.silhouette.primitiveDecomposition;
|
|
17895
|
+
const rect = rectForBand(layout, s, "silhouette", 1);
|
|
17896
|
+
const rawPolys = primitiveDecomposition.map((primInfo) => primInfo.polygon);
|
|
17897
|
+
const placedPolys = placeSilhouetteGridAlignedAsPolys(rawPolys, scaleS, { cx: rect.cx, cy: rect.cy });
|
|
17898
|
+
return /* @__PURE__ */ React.createElement("g", { key: `sil-borders-${s.id}`, pointerEvents: "none" }, placedPolys.map((scaledPoly, i) => /* @__PURE__ */ React.createElement(
|
|
17899
|
+
"path",
|
|
17900
|
+
{
|
|
17901
|
+
key: `prim-border-${i}`,
|
|
17902
|
+
d: pathD(scaledPoly),
|
|
17903
|
+
fill: "none",
|
|
17904
|
+
stroke: CONFIG.color.tangramDecomposition.stroke,
|
|
17905
|
+
strokeWidth: CONFIG.size.stroke.tangramDecompositionPx
|
|
17906
|
+
}
|
|
17907
|
+
)));
|
|
17908
|
+
})
|
|
17726
17909
|
);
|
|
17727
17910
|
}
|
|
17728
17911
|
|
|
@@ -19663,7 +19846,10 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
19663
19846
|
onPieceRemove,
|
|
19664
19847
|
onInteraction,
|
|
19665
19848
|
onTrialEnd,
|
|
19666
|
-
onControllerReady
|
|
19849
|
+
onControllerReady,
|
|
19850
|
+
usePrimitiveColorsBlueprints,
|
|
19851
|
+
usePrimitiveColorsTargets,
|
|
19852
|
+
primitiveColorIndices
|
|
19667
19853
|
} = props;
|
|
19668
19854
|
const [timeRemaining, setTimeRemaining] = React.useState(timeLimitMs > 0 ? Math.floor(timeLimitMs / 1e3) : 0);
|
|
19669
19855
|
const controller = React.useMemo(() => {
|
|
@@ -19987,7 +20173,7 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
19987
20173
|
justifyContent: "center",
|
|
19988
20174
|
alignItems: "center",
|
|
19989
20175
|
padding: "20px",
|
|
19990
|
-
background:
|
|
20176
|
+
background: CONFIG.color.background,
|
|
19991
20177
|
flex: "0 0 auto"
|
|
19992
20178
|
};
|
|
19993
20179
|
const headerContentStyle = {
|
|
@@ -20003,14 +20189,20 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
20003
20189
|
lineHeight: 1.5,
|
|
20004
20190
|
textAlign: "center"
|
|
20005
20191
|
};
|
|
20192
|
+
const scaleX = svgDimensions.width / viewBox.w;
|
|
20193
|
+
const rightEdgeOfSemicircleLogical = viewBox.w / 2 + layout.outerR;
|
|
20194
|
+
const distanceFromRightEdgeLogical = viewBox.w - rightEdgeOfSemicircleLogical;
|
|
20195
|
+
const distanceFromRightEdgePx = distanceFromRightEdgeLogical * scaleX;
|
|
20196
|
+
const charWidth = 24 * 0.6;
|
|
20197
|
+
const offsetLeft = charWidth * 5;
|
|
20006
20198
|
const timerStyle = {
|
|
20007
20199
|
position: "absolute",
|
|
20008
|
-
right:
|
|
20200
|
+
right: `${distanceFromRightEdgePx + offsetLeft}px`,
|
|
20009
20201
|
fontSize: "24px",
|
|
20010
20202
|
fontWeight: "bold",
|
|
20011
20203
|
fontFamily: "monospace",
|
|
20012
20204
|
color: "#333",
|
|
20013
|
-
|
|
20205
|
+
whiteSpace: "nowrap",
|
|
20014
20206
|
textAlign: "right"
|
|
20015
20207
|
};
|
|
20016
20208
|
const gameboardWrapperStyle = {
|
|
@@ -20055,6 +20247,9 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
20055
20247
|
onCenterBadgePointerDown,
|
|
20056
20248
|
showTangramDecomposition: showTangramDecomposition ?? false,
|
|
20057
20249
|
scaleS,
|
|
20250
|
+
usePrimitiveColorsBlueprints: usePrimitiveColorsBlueprints ?? false,
|
|
20251
|
+
usePrimitiveColorsTargets: usePrimitiveColorsTargets ?? false,
|
|
20252
|
+
primitiveColorIndices: primitiveColorIndices ?? [0, 1, 2, 3, 4],
|
|
20058
20253
|
...eventCallbacks
|
|
20059
20254
|
}
|
|
20060
20255
|
))));
|
|
@@ -20274,7 +20469,10 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
20274
20469
|
trialParams,
|
|
20275
20470
|
...params.instructions && { instructions: params.instructions },
|
|
20276
20471
|
...params.onInteraction && { onInteraction: params.onInteraction },
|
|
20277
|
-
...params.onTrialEnd && { onTrialEnd: params.onTrialEnd }
|
|
20472
|
+
...params.onTrialEnd && { onTrialEnd: params.onTrialEnd },
|
|
20473
|
+
...params.usePrimitiveColorsBlueprints !== void 0 && { usePrimitiveColorsBlueprints: params.usePrimitiveColorsBlueprints },
|
|
20474
|
+
...params.usePrimitiveColorsTargets !== void 0 && { usePrimitiveColorsTargets: params.usePrimitiveColorsTargets },
|
|
20475
|
+
...params.primitiveColorIndices !== void 0 && { primitiveColorIndices: params.primitiveColorIndices }
|
|
20278
20476
|
};
|
|
20279
20477
|
const root = clientExports.createRoot(display_element);
|
|
20280
20478
|
root.render(React.createElement(GameBoard, gameBoardProps));
|
|
@@ -20359,6 +20557,24 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
20359
20557
|
type: jspsych.ParameterType.FUNCTION,
|
|
20360
20558
|
default: void 0,
|
|
20361
20559
|
description: "Callback when trial completes with full data"
|
|
20560
|
+
},
|
|
20561
|
+
/** Whether to use distinct colors for each primitive shape type in blueprints */
|
|
20562
|
+
use_primitive_colors_blueprints: {
|
|
20563
|
+
type: jspsych.ParameterType.BOOL,
|
|
20564
|
+
default: false,
|
|
20565
|
+
description: "Whether each primitive shape type should have its own distinct color in the blueprint dock area"
|
|
20566
|
+
},
|
|
20567
|
+
/** Whether to use distinct colors for each primitive shape type in target tangrams */
|
|
20568
|
+
use_primitive_colors_targets: {
|
|
20569
|
+
type: jspsych.ParameterType.BOOL,
|
|
20570
|
+
default: false,
|
|
20571
|
+
description: "Whether each primitive shape type should have its own distinct color in target tangram silhouettes"
|
|
20572
|
+
},
|
|
20573
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
20574
|
+
primitive_color_indices: {
|
|
20575
|
+
type: jspsych.ParameterType.OBJECT,
|
|
20576
|
+
default: [0, 1, 2, 3, 4],
|
|
20577
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
20362
20578
|
}
|
|
20363
20579
|
},
|
|
20364
20580
|
data: {
|
|
@@ -20424,7 +20640,10 @@ var TangramConstructPlugin = (function (jspsych) {
|
|
|
20424
20640
|
show_tangram_decomposition: trial.show_tangram_decomposition,
|
|
20425
20641
|
instructions: trial.instructions,
|
|
20426
20642
|
onInteraction: trial.onInteraction,
|
|
20427
|
-
onTrialEnd: wrappedOnTrialEnd
|
|
20643
|
+
onTrialEnd: wrappedOnTrialEnd,
|
|
20644
|
+
usePrimitiveColorsBlueprints: trial.use_primitive_colors_blueprints,
|
|
20645
|
+
usePrimitiveColorsTargets: trial.use_primitive_colors_targets,
|
|
20646
|
+
primitiveColorIndices: trial.primitive_color_indices
|
|
20428
20647
|
};
|
|
20429
20648
|
const { root, display_element: element, jsPsych } = startConstructionTrial(display_element, params, this.jsPsych);
|
|
20430
20649
|
element.__reactContext = { root, jsPsych };
|