Skip to content

Commit

Permalink
Fix react d3 graph resize on window resize (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikugogoi authored Mar 20, 2023
1 parent d84cc0d commit 90eb420
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 30 deletions.
2 changes: 1 addition & 1 deletion packages/react-peer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"convert": "^4.10.0",
"d3": "^5.5.0",
"lodash": "^4.17.21",
"react-d3-graph": "^2.6.0"
"use-resize-observer": "^9.1.0"
},
"peerDependencies": {
"react": "^18.2.0"
Expand Down
37 changes: 20 additions & 17 deletions packages/react-peer/src/components/ForceDirectedGraph.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import React, { useRef, useCallback, useEffect, useState, useMemo } from "react"
import * as d3 from "d3";
import useResizeObserver from "use-resize-observer";
import throttle from "lodash/throttle";

const RESIZE_THROTTLE_TIME = 500; // ms

function ForceDirectedGraph ({
data,
Expand All @@ -10,7 +14,7 @@ function ForceDirectedGraph ({
nodeCharge = -250
}) {
const containerRef = useRef(null)
const [containerWidth, setContainerWidth] = useState(0)
const { width: containerWidth } = useResizeObserver({ ref: containerRef });

const { current: simulation } = useRef(d3.forceSimulation()
.force(
Expand Down Expand Up @@ -84,12 +88,6 @@ function ForceDirectedGraph ({
labelRef.current.attr("transform", transform);
}, [onClickNode])

const measuredRef = useCallback(node => {
if (node !== null) {
setContainerWidth(node.getBoundingClientRect().width);
}
}, []);

useEffect(() => {
// Set d3 SVG group references on mount
// SVG group for links
Expand All @@ -112,11 +110,11 @@ function ForceDirectedGraph ({
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);

nodeRef.current
.attr("cx", d => d.x)
.attr("cy", d => d.y);

labelRef.current
.attr("x", d => d.x)
.attr("y", d => d.y);
Expand All @@ -125,36 +123,41 @@ function ForceDirectedGraph ({
// Existing listener is replaced on registering new one
simulation.on("tick", onTick);

// Append the d3 root element to container div
// Append the d3 root element to container div
containerRef.current.append(svgRef.current.node());
}, []);

useEffect(() => {
svgRef.current.call(zoom);
}, [zoom])

const throttledUpdateViewBox = useMemo(
() => throttle((width, height) => {
svgRef.current.attr("viewBox", [0, 0, width, height])
simulation.force("center", d3.forceCenter(width / 2, height / 2));
zoom.extent([[0, 0], [width, height]])
}, RESIZE_THROTTLE_TIME),
[zoom]
);

useEffect(() => {
if (!containerWidth) {
return
}

svgRef.current.attr("viewBox", [0, 0, containerWidth, containerHeight])
simulation.force("center", d3.forceCenter(containerWidth / 2, containerHeight / 2));
zoom.extent([[0, 0], [containerWidth, containerHeight]])
throttledUpdateViewBox(containerWidth, containerHeight);
}, [
containerWidth,
containerHeight,
zoom
throttledUpdateViewBox
])

useEffect(() => {
update(data)
}, [data, update])

return (
<div ref={measuredRef}>
<div ref={containerRef} />
</div>
<div ref={containerRef} />
)
}

Expand Down
7 changes: 3 additions & 4 deletions packages/react-peer/src/components/GraphWithTooltip.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ const STYLES = {
}
}

// TODO: Change height on changing browser window size
const CONTAINER_HEIGHT = (window.innerHeight / 2) - 40
const DEFAULT_CONTAINER_HEIGHT = (window.innerHeight / 2) - 40

function GraphWithTooltip ({ data, nodeCharge }) {
function GraphWithTooltip ({ data, nodeCharge, containerHeight }) {
const [anchorEl, setAnchorEl] = useState(null)
const [hoveredNode, setHoveredNode] = useState(null)

Expand All @@ -26,7 +25,7 @@ function GraphWithTooltip ({ data, nodeCharge }) {
<Box>
<ForceDirectedGraph
data={data}
containerHeight={CONTAINER_HEIGHT}
containerHeight={containerHeight ?? DEFAULT_CONTAINER_HEIGHT}
onMouseOverNode={onMouseOverNode}
onMouseOutNode={() => setAnchorEl(null)}
nodeCharge={nodeCharge}
Expand Down
5 changes: 3 additions & 2 deletions packages/react-peer/src/components/NetworkGraph.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const STYLES = {
}
}

export function NetworkGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, sx, ...props }) {
export function NetworkGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, sx, containerHeight, ...props }) {
const peer = useContext(PeerContext);
const [isLoading, setIsLoading] = useState(false)
const [debugInfos, setDebugInfos] = useState([])
Expand All @@ -35,7 +35,7 @@ export function NetworkGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, sx,
setIsLoading(true)
setData({ nodes: [], links: [] })
peer.requestPeerInfo();

const updateSelfDebugInfo = async () => {
const selfDebugInfo = await peer.getInfo();
selfDebugInfo.selfInfo.isSelf = true;
Expand Down Expand Up @@ -119,6 +119,7 @@ export function NetworkGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, sx,
data={data}
peer={peer}
nodeCharge={-1000}
containerHeight={containerHeight}
/>
</Box>
</ScopedCssBaseline>
Expand Down
3 changes: 2 additions & 1 deletion packages/react-peer/src/components/PeersGraph.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import GraphWithTooltip from './GraphWithTooltip';
import { useThrottledCallback } from '../hooks/throttledCallback';
import { updateGraphDataWithDebugInfo } from '../utils';

export function PeersGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, ...props }) {
export function PeersGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, containerHeight, ...props }) {
const peer = useContext(PeerContext);
const [connections, setConnections] = useState([]);

Expand Down Expand Up @@ -85,6 +85,7 @@ export function PeersGraph ({ refreshInterval = DEFAULT_REFRESH_INTERVAL, ...pro
<Box mt={1} {...props}>
<GraphWithTooltip
data={data}
containerHeight={containerHeight}
/>
</Box>
</ScopedCssBaseline>
Expand Down
17 changes: 12 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2569,6 +2569,11 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"

"@juggle/resize-observer@^3.3.1":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==

"@leichtgewicht/ip-codec@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
Expand Down Expand Up @@ -17182,11 +17187,6 @@ react-app-polyfill@^3.0.0:
regenerator-runtime "^0.13.9"
whatwg-fetch "^3.6.2"

react-d3-graph@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/react-d3-graph/-/react-d3-graph-2.6.0.tgz#b994131e430b568e086970560ba8a26809113173"
integrity sha512-U72didZuPuYEqAi1n2bJvnph+9MviIw2x9I0eoxb1IKk3cyEwsJV96n3RL72z/7HDsa1FOvDKuOJE7ujSNZB/Q==

react-dev-utils@^12.0.1:
version "12.0.1"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73"
Expand Down Expand Up @@ -19871,6 +19871,13 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"

use-resize-observer@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/use-resize-observer/-/use-resize-observer-9.1.0.tgz#14735235cf3268569c1ea468f8a90c5789fc5c6c"
integrity sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==
dependencies:
"@juggle/resize-observer" "^3.3.1"

use@^3.1.0:
version "3.1.1"
resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz"
Expand Down

0 comments on commit 90eb420

Please sign in to comment.