Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release'
Browse files Browse the repository at this point in the history
# Conflicts:
#	app/dashboard/components/elimination-tree/index.tsx
  • Loading branch information
ylimezhang committed Oct 12, 2024
2 parents a96ba49 + 8cc9458 commit 115e7ce
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 14 deletions.
30 changes: 28 additions & 2 deletions app/dashboard/components/elimination-tree/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import StepByStep from "@/app/dashboard/components/elimination-tree/step-by-step
import Tree from "../../../../components/tree";
import { useEffect, useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { ArrowLeft, ArrowRight } from "lucide-react";
import useMultiWinnerDataStore from "@/store/multi-winner-data";
import { ArrowLeft, ArrowRight, Undo2 } from "lucide-react";
import useMultiWinnerDataStore from "@/store/MultiWinnerData";
import TooltipWithIcon from "@/app/dashboard/components/Information-icon-text";

function EliminationTree() {
Expand All @@ -23,6 +23,8 @@ function EliminationTree() {
const [selectedWinnerId, setSelectedWinnerId] = useState<number>(0);
const [selectedStep, setSelectedStep] = useState<number>(1); // Ensure this is always defined

const [resetHiddenNodes, setResetHiddenNodes] = useState(false);

// Use useEffect to initialize selectedWinnerId when multiWinner loads
useEffect(() => {
if (multiWinner && multiWinner.length > 0) {
Expand Down Expand Up @@ -80,6 +82,14 @@ function EliminationTree() {
</Button>
);

const handleRevertAssertion = () => {
setResetHiddenNodes(true);
};

const handleResetComplete = () => {
setResetHiddenNodes(false);
};

return (
<div className="border border-gray-300 rounded-lg p-6 h-auto flex flex-col justify-between pl-10">
<div className="flex items-center justify-between">
Expand All @@ -100,6 +110,7 @@ function EliminationTree() {
<CandidateListBar
selectedWinnerId={selectedWinnerId}
handleSelectWinner={(id: number) => {
handleRevertAssertion();
setSelectedStep(1); // Reset step
setSelectedWinnerId(id);
}}
Expand All @@ -119,8 +130,23 @@ function EliminationTree() {
key={`${selectedWinnerId}-${selectedStep}`}
nextComponent={NextComponent}
backComponent={BackComponent}
resetHiddenNodes={resetHiddenNodes}
onResetComplete={handleResetComplete}
/>
</div>
<div className="w-48 flex flex-col gap-4">
<div>
<div className="font-bold">Applied Assertion: </div>
<div>{data.process[selectedStep].assertion}</div>
</div>

<div>
<Button onClick={handleRevertAssertion}>
Revert Assertion
<Undo2 className="ml-2 h-4 w-4" />
</Button>
</div>
</div>
</div>
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions components/tree/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
interface TreeNode {
id: number;
name: string;
eliminated?: boolean; // eliminated children
cut?: boolean; // Cut children
children?: TreeNode[];
_children?: TreeNode[]; // Hidden children when collapsed
collapsedCount?: number; // Count of collapsed children
hide?: boolean; // 隐藏节点及其子节点
}

// Function to toggle the children (collapse/expand)
Expand Down
76 changes: 64 additions & 12 deletions components/tree/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,19 @@ interface TreeProps {
data: TreeNode;
nextComponent: React.ReactNode;
backComponent: React.ReactNode;
resetHiddenNodes: boolean;
onResetComplete: () => void;
}
const dimensions = { width: 400, height: 400 };

export default function Tree({
data,
nextComponent,
backComponent,
resetHiddenNodes,
onResetComplete,
}: TreeProps) {
// TODO: 应该在这个文件里面操作cut的操作,这样每次通过key就重新渲染,重置操作了
const svgRef = useRef<SVGSVGElement | null>(null);
const gRef = useRef<SVGGElement | null>(null);
const zoomBehaviorRef = useRef<d3.ZoomBehavior<
Expand All @@ -40,6 +45,28 @@ export default function Tree({
const [treeData, setTreeData] = useState(data);
const [currentZoom, setCurrentZoom] = useState<number>(1);

useEffect(() => {
if (resetHiddenNodes) {
const resetNodes = (node: TreeNode) => {
node.hide = false;
if (node.children) {
node.children.forEach(resetNodes);
}
};
resetNodes(treeData);
setTreeData({ ...treeData });
onResetComplete();
}
}, [resetHiddenNodes, treeData, onResetComplete]);

function markNodeAndChildrenAsHidden(node: TreeNode) {
node.hide = true; // 设置当前节点为hide
if (node.children) {
node.children.forEach((child) => markNodeAndChildrenAsHidden(child)); // 递归设置子节点为hide
}
setTreeData({ ...treeData });
}

useEffect(() => {
if (svgRef.current) {
const svgElement = d3.select(svgRef.current);
Expand Down Expand Up @@ -68,7 +95,7 @@ export default function Tree({

// Draw links
g.selectAll("line")
.data(links)
.data(links.filter((link) => !link.target.data.hide))
.enter()
.append("line")
.attr("x1", (d) => (d.source as d3.HierarchyPointNode<TreeNode>).x)
Expand All @@ -77,40 +104,65 @@ export default function Tree({
.attr("y2", (d) => (d.target as d3.HierarchyPointNode<TreeNode>).y)
// .attr("stroke", "#e9bc39")
.attr("stroke", (d) =>
d.source.data.cut || d.target.data.cut ? "#d4d4d4" : "#e9bc39",
d.source.data.eliminated ||
d.target.data.eliminated ||
d.source.data.cut ||
d.target.data.cut
? "#d4d4d4"
: "#e9bc39",
) // Set stroke to black if cut is true
.attr("stroke-width", 3);

// 暂时先用X
g.selectAll("text.cut-marker")
g.selectAll("foreignObject.cut-marker")
.data(links)
.enter()
.filter((d: any) => d.source.data.cut || d.target.data.cut) // Only add 'X' for cut links
.append("text")
// .filter((d: d3.HierarchyLink<TreeNode>) => !!d.target.data.cut) // Only add scissors for cut links
.filter(
(d: d3.HierarchyLink<TreeNode>) =>
!!d.target.data.cut && !d.target.data.hide, // 只为未隐藏的目标节点添加剪刀图标
)
.append("foreignObject")
.attr("class", "cut-marker")
.attr(
"x",
(d) =>
((d.source as d3.HierarchyPointNode<TreeNode>).x +
(d.target as d3.HierarchyPointNode<TreeNode>).x) /
2,
2 -
12, // Offset to center the icon
)
.attr(
"y",
(d) =>
((d.source as d3.HierarchyPointNode<TreeNode>).y +
(d.target as d3.HierarchyPointNode<TreeNode>).y) /
2,
2 -
12, // Offset to center the icon
)
.attr("text-anchor", "middle")
.attr("font-size", "14px")
.attr("fill", "red")
.text("X");
.attr("width", 24)
.attr("height", 24)
.attr("class", "cursor-pointer")
.html(
`
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scissors">
<circle cx="6" cy="6" r="3"/>
<path d="M8.12 8.12 12 12"/>
<path d="M20 4 8.12 15.88"/>
<circle cx="6" cy="18" r="3"/>
<path d="M14.8 14.8 20 20"/>
</svg>
`,
)
.on("click", (event, d) => {
markNodeAndChildrenAsHidden(d.target.data);
// setTreeData({ ...treeData });
});

// Create groups for each node
const groups = g
.selectAll("g")
.data(nodes)
.data(nodes.filter((node) => !node.data.hide))
.enter()
.append("g")
.attr("transform", (d) => `translate(${d.x},${d.y})`)
Expand Down

0 comments on commit 115e7ce

Please sign in to comment.