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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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 TangramPrepPlugin = (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
|
))));
|
|
@@ -20221,7 +20416,9 @@ var TangramPrepPlugin = (function (jspsych) {
|
|
|
20221
20416
|
quickstashMacros,
|
|
20222
20417
|
primitiveOrder,
|
|
20223
20418
|
onInteraction,
|
|
20224
|
-
onTrialEnd
|
|
20419
|
+
onTrialEnd,
|
|
20420
|
+
usePrimitiveColorsBlueprints,
|
|
20421
|
+
primitiveColorIndices
|
|
20225
20422
|
} = params;
|
|
20226
20423
|
const { onInteraction: _, onTrialEnd: __, ...trialParams } = params;
|
|
20227
20424
|
const PRIMITIVE_BLUEPRINTS_ORDERED = [...PRIMITIVE_BLUEPRINTS].sort((a, b) => primitiveOrder.indexOf(a.kind) - primitiveOrder.indexOf(b.kind));
|
|
@@ -20313,7 +20510,9 @@ var TangramPrepPlugin = (function (jspsych) {
|
|
|
20313
20510
|
...params.instructions && { instructions: params.instructions },
|
|
20314
20511
|
onControllerReady: handleControllerReady,
|
|
20315
20512
|
...onInteraction && { onInteraction },
|
|
20316
|
-
...onTrialEnd && { onTrialEnd }
|
|
20513
|
+
...onTrialEnd && { onTrialEnd },
|
|
20514
|
+
...usePrimitiveColorsBlueprints !== void 0 && { usePrimitiveColorsBlueprints },
|
|
20515
|
+
...primitiveColorIndices !== void 0 && { primitiveColorIndices }
|
|
20317
20516
|
}));
|
|
20318
20517
|
return { root, display_element, jsPsych };
|
|
20319
20518
|
}
|
|
@@ -20379,6 +20578,18 @@ var TangramPrepPlugin = (function (jspsych) {
|
|
|
20379
20578
|
onTrialEnd: {
|
|
20380
20579
|
type: jspsych.ParameterType.FUNCTION,
|
|
20381
20580
|
default: void 0
|
|
20581
|
+
},
|
|
20582
|
+
/** Whether to use distinct colors for each primitive shape type in blueprints */
|
|
20583
|
+
use_primitive_colors_blueprints: {
|
|
20584
|
+
type: jspsych.ParameterType.BOOL,
|
|
20585
|
+
default: false,
|
|
20586
|
+
description: "Whether each primitive shape type should have its own distinct color in the blueprint dock area"
|
|
20587
|
+
},
|
|
20588
|
+
/** Indices mapping primitives to colors from the color palette */
|
|
20589
|
+
primitive_color_indices: {
|
|
20590
|
+
type: jspsych.ParameterType.OBJECT,
|
|
20591
|
+
default: [0, 1, 2, 3, 4],
|
|
20592
|
+
description: "Array of 5 integers indexing into primitiveColors array, mapping [square, smalltriangle, parallelogram, medtriangle, largetriangle] to colors"
|
|
20382
20593
|
}
|
|
20383
20594
|
},
|
|
20384
20595
|
data: {
|
|
@@ -20423,7 +20634,9 @@ var TangramPrepPlugin = (function (jspsych) {
|
|
|
20423
20634
|
primitiveOrder: trial.primitive_order,
|
|
20424
20635
|
instructions: trial.instructions,
|
|
20425
20636
|
onInteraction: trial.onInteraction,
|
|
20426
|
-
onTrialEnd: wrappedOnTrialEnd
|
|
20637
|
+
onTrialEnd: wrappedOnTrialEnd,
|
|
20638
|
+
usePrimitiveColorsBlueprints: trial.use_primitive_colors_blueprints,
|
|
20639
|
+
primitiveColorIndices: trial.primitive_color_indices
|
|
20427
20640
|
};
|
|
20428
20641
|
const { root, display_element: element, jsPsych } = startPrepTrial(display_element, params, this.jsPsych);
|
|
20429
20642
|
element.__reactContext = { root, jsPsych };
|