Skip to content

Commit

Permalink
Merge pull request #142 from vgihan/main
Browse files Browse the repository at this point in the history
feat(view): add transition in ClusterGraph
  • Loading branch information
vgihan authored Sep 12, 2022
2 parents c7f560d + 7466762 commit be0a8d6
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const NODE_GAP = 20;
export const COMMIT_HEIGHT = 50;
export const CLUSTER_HEIGHT = 50;
export const GRAPH_WIDTH = 100;
export const SVG_WIDTH = GRAPH_WIDTH + 4;
export const DETAIL_HEIGHT = 300;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
.cluster-container {
.cluster-box {
.cluster-graph_container {
.cluster-graph_cluster {
rx: 5;
stroke-width: 1;
stroke: rgb(13, 71, 161, 0.4);
fill: transparent;
}

.degree-box {
.cluster-graph_degree {
rx: 5;
fill: rgb(13, 71, 161, 0.4);
}

&:hover {
.cluster-box {
.cluster-graph_cluster {
stroke-width: 3;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MouseEvent, RefObject } from "react";
import type { RefObject } from "react";
import React, { useEffect, useRef } from "react";
import * as d3 from "d3";

Expand All @@ -8,13 +8,16 @@ import "./ClusterGraph.scss";

import { selectedDataUpdater } from "../VerticalClusterList.util";

import { getGraphHeight, getClusterSizes } from "./ClusterGraph.util";
import {
COMMIT_HEIGHT,
getGraphHeight,
getClusterSizes,
getSelectedIndex,
getClusterPosition,
} from "./ClusterGraph.util";
import {
CLUSTER_HEIGHT,
DETAIL_HEIGHT,
GRAPH_WIDTH,
NODE_GAP,
SVG_MARGIN,
SVG_WIDTH,
} from "./ClusterGraph.const";
import type {
Expand All @@ -25,66 +28,43 @@ import type {
const drawClusterBox = (container: SVGElementSelection<SVGGElement>) => {
container
.append("rect")
.attr("class", "cluster-box ")
.attr("class", "cluster-graph_cluster")
.attr("width", GRAPH_WIDTH)
.attr("height", COMMIT_HEIGHT)
.attr("x", SVG_MARGIN.left)
.attr("y", (d, i, prev) =>
i === 0
? SVG_MARGIN.top
: prev[i - 1].y.baseVal.value +
prev[i - 1].height.baseVal.value +
NODE_GAP +
(d.selected === d.cluster.commitNodeList[0].clusterId
? DETAIL_HEIGHT
: 0)
);
.attr("height", CLUSTER_HEIGHT);
};

const drawDegreeBox = (container: SVGElementSelection<SVGGElement>) => {
const widthScale = d3.scaleLinear().range([0, GRAPH_WIDTH]).domain([0, 10]);
container
.append("rect")
.attr("class", "degree-box")
.attr("class", "cluster-graph_degree")
.attr("width", (d) => widthScale(Math.min(d.clusterSize, 10)))
.attr("height", COMMIT_HEIGHT)
.attr("height", CLUSTER_HEIGHT)
.attr(
"x",
(d) =>
SVG_MARGIN.left +
GRAPH_WIDTH / 2 -
widthScale(Math.min(d.clusterSize, 10)) / 2
)
.attr("y", (d, i, prev) =>
i === 0
? SVG_MARGIN.top
: prev[i - 1].y.baseVal.value +
prev[i - 1].height.baseVal.value +
NODE_GAP +
(d.selected === d.cluster.commitNodeList[0].clusterId
? DETAIL_HEIGHT
: 0)
(d) => (GRAPH_WIDTH - widthScale(Math.min(d.clusterSize, 10))) / 2
);
};

const drawClusterGraph = (
svgRef: RefObject<SVGSVGElement>,
data: ClusterGraphElement[],
onClickCluster: (
this: SVGGElement,
event: MouseEvent,
d: ClusterGraphElement
) => void
onClickCluster: (_: PointerEvent, d: ClusterGraphElement) => void
) => {
console.log(data);
const group = d3
.select(svgRef.current)
.selectAll(".cluster-container")
.selectAll(".cluster-graph_container")
.data(data)
.enter()
.append("g")
.attr("class", "cluster-container")
.on("click", onClickCluster);
.join("g")
.on("click", onClickCluster)
.attr("class", "cluster-graph_container")
.attr("transform", (d, i) => getClusterPosition(d, i, true));
group
.transition()
.duration(300)
.ease(d3.easeLinear)
.attr("transform", (d, i) => getClusterPosition(d, i));

drawClusterBox(group);
drawDegreeBox(group);
};
Expand All @@ -98,42 +78,34 @@ type ClusterGraphProps = {
setSelectedData: React.Dispatch<React.SetStateAction<SelectedDataProps>>;
};

const getSelectedNextId = (
data: ClusterNode[],
selectedData: SelectedDataProps
) => {
const selectedId = selectedData?.commitNodeList[0].clusterId;
const selectedNextId =
data.findIndex((item) => item.commitNodeList[0].clusterId === selectedId) +
1;
return data[selectedNextId]?.commitNodeList[0]?.clusterId;
};
const ClusterGraph = ({
data,
selectedData,
setSelectedData,
}: ClusterGraphProps) => {
const svgRef = useRef<SVGSVGElement>(null);
const clusterSizes = getClusterSizes(data);
const graphHeight = getGraphHeight(clusterSizes);
const selectedNextId = getSelectedNextId(data, selectedData);
const selectedIndex = getSelectedIndex(data, selectedData);
const graphHeight =
getGraphHeight(clusterSizes) + (selectedIndex < 0 ? 0 : DETAIL_HEIGHT);

const clusterGraphElements = data.map((cluster, i) => ({
cluster,
clusterSize: clusterSizes[i],
selected: selectedNextId,
selected: selectedIndex,
}));

useEffect(() => {
const handleClickCluster = (_: MouseEvent, d: ClusterGraphElement) =>
const handleClickCluster = (_: PointerEvent, d: ClusterGraphElement) => {
setSelectedData(
selectedDataUpdater(d.cluster, d.cluster.commitNodeList[0].clusterId)
);
};
drawClusterGraph(svgRef, clusterGraphElements, handleClickCluster);
return () => {
destroyClusterGraph(svgRef);
};
}, [clusterGraphElements, setSelectedData]);
}, [clusterGraphElements, selectedIndex, setSelectedData]);

return <svg ref={svgRef} width={SVG_WIDTH} height={graphHeight} />;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type ClusterGraphElement = {
};

export type SVGElementSelection<T extends BaseType> = Selection<
T,
T | BaseType,
ClusterGraphElement,
SVGSVGElement | null,
unknown
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
import type { ClusterNode } from "types";
import type { ClusterNode, SelectedDataProps } from "types";

import { COMMIT_HEIGHT, NODE_GAP } from "./ClusterGraph.const";
import {
CLUSTER_HEIGHT,
DETAIL_HEIGHT,
NODE_GAP,
SVG_MARGIN,
} from "./ClusterGraph.const";
import type { ClusterGraphElement } from "./ClusterGraph.type";

export function getClusterSizes(data: ClusterNode[]) {
return data.map((node) => node.commitNodeList.length);
}

export function getGraphHeight(clusterSizes: number[]) {
return (
clusterSizes.length * COMMIT_HEIGHT +
clusterSizes.length * CLUSTER_HEIGHT +
clusterSizes.length * NODE_GAP +
NODE_GAP
);
}

export function getClusterPosition(
d: ClusterGraphElement,
i: number,
isPrev = false
) {
const curSelected = d.selected || Infinity;
const selected = isPrev ? Infinity : curSelected;
const margin = selected >= 0 && selected < i ? DETAIL_HEIGHT : 0;
const x = SVG_MARGIN.left;
const y = SVG_MARGIN.top + i * (CLUSTER_HEIGHT + NODE_GAP) + margin;
return `translate(${x}, ${y})`;
}

export function getSelectedIndex(
data: ClusterNode[],
selectedData: SelectedDataProps
) {
const selectedId = selectedData?.commitNodeList[0].clusterId;
const selectedIndex = data.findIndex(
(item) => item.commitNodeList[0].clusterId === selectedId
);
return selectedIndex;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
border-radius: $border--radius;
}

@mixin animate($animation, $duration, $method, $times) {
animation: $animation $duration $method $times;
}

@mixin keyframes($name) {
@keyframes #{$name} {
@content;
}
}

.summary__entire {
width: 85%;
margin-left: 20px;
Expand Down Expand Up @@ -158,9 +168,19 @@
.summary_detail_container {
height: 280px;
margin-top: 20px;
overflow: auto;
overflow: scroll;

&::-webkit-scrollbar {
display: none; /* Chrome, Safari, Opera*/
}

@include keyframes(open_detail) {
0% {
height: 0;
}
100% {
height: 280px;
}
}
@include animate(open_detail, 0.3s, linear, 1);
}

0 comments on commit be0a8d6

Please sign in to comment.