ok it kinda renders
This commit is contained in:
parent
c79fb7de78
commit
354ecd33a6
6 changed files with 80 additions and 48 deletions
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# matter
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.1.17. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
10
package.json
10
package.json
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"d3": "^7.9.0",
|
||||
"nanoid": "^5.0.7",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
|
@ -11,6 +12,13 @@
|
|||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||
"sass": "^1.77.6",
|
||||
"vite": "^5.3.2"
|
||||
"vite": "^5.3.2",
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"name": "matter",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
|
@ -19,3 +19,11 @@ text {
|
|||
fill: #666;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.nodeContainer {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid gray;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
59
src/App.tsx
59
src/App.tsx
|
@ -2,8 +2,10 @@ import * as d3 from "d3";
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import styles from "./App.module.scss";
|
||||
import { createPortal } from "react-dom";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
interface NodeInfo extends d3.SimulationNodeDatum {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
@ -16,7 +18,7 @@ const nodes: NodeInfo[] = [
|
|||
{ name: "F" },
|
||||
{ name: "G" },
|
||||
{ name: "H" },
|
||||
];
|
||||
].map((node) => ({ ...node, id: nanoid() }));
|
||||
|
||||
const links = [
|
||||
{ source: 0, target: 1 },
|
||||
|
@ -31,7 +33,6 @@ const links = [
|
|||
|
||||
export default function App() {
|
||||
const svgRef = useRef();
|
||||
const simulationRef = useRef();
|
||||
|
||||
// Resize listener
|
||||
const [rect, setRect] = useState<DOMRectReadOnly | null>(null);
|
||||
|
@ -46,25 +47,7 @@ export default function App() {
|
|||
const [simulationNodes, setSimulationNodes] = useState(() => nodes);
|
||||
const ticked = useCallback((simulation: d3.Simulation<NodeInfo, any>) => {
|
||||
const nodes = simulation.nodes();
|
||||
// setSimulationNodes(nodes);
|
||||
// d3.select("svg .links")
|
||||
// .selectAll("line")
|
||||
// .data(links)
|
||||
// .join("line")
|
||||
// .attr("x1", (d) => d.source.x)
|
||||
// .attr("x2", (d) => d.target.x)
|
||||
// .attr("y1", (d) => d.source.y)
|
||||
// .attr("y2", (d) => d.target.y);
|
||||
|
||||
d3.select("svg .nodes")
|
||||
.selectAll("rect")
|
||||
.data(nodes)
|
||||
.join("rect")
|
||||
// .append("foreignObject")
|
||||
.text((d) => d.name)
|
||||
.attr("x", (d) => d.x)
|
||||
.attr("y", (d) => d.y)
|
||||
.attr("dy", (d) => 5);
|
||||
setSimulationNodes([...nodes]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -72,13 +55,11 @@ export default function App() {
|
|||
|
||||
const simulation = d3
|
||||
.forceSimulation<NodeInfo>(nodes)
|
||||
.force("charge", d3.forceManyBody())
|
||||
.force("charge", d3.forceManyBody().strength(-500))
|
||||
.force("link", d3.forceLink(links))
|
||||
.force("center", d3.forceCenter(rect.width / 2, rect.height / 2));
|
||||
|
||||
simulation.on("tick", () => ticked(simulation));
|
||||
|
||||
simulationRef.current = simulation;
|
||||
}, [ticked, rect]);
|
||||
|
||||
return (
|
||||
|
@ -89,15 +70,19 @@ export default function App() {
|
|||
<g className="links" />
|
||||
<g className="nodes">
|
||||
{simulationNodes.map((node, idx) => {
|
||||
console.log("node", node);
|
||||
return (
|
||||
<text
|
||||
key={idx}
|
||||
<g key={idx}>
|
||||
<foreignObject
|
||||
width={120}
|
||||
height={80}
|
||||
x={(node.x ?? 0).toString()}
|
||||
y={(node.y ?? 0).toString()}
|
||||
>
|
||||
{node.name}
|
||||
</text>
|
||||
<div data-xmlns="http://www.w3.org/1999/xhtml" id={node.id}>
|
||||
<Counter />
|
||||
</div>
|
||||
</foreignObject>
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
|
@ -107,13 +92,6 @@ export default function App() {
|
|||
);
|
||||
}
|
||||
|
||||
function ForeignObjectWrapper({ id }) {
|
||||
const el = useMemo(() => {
|
||||
return document.getElementById(id);
|
||||
}, [id]);
|
||||
return createPortal(<Counter />, el);
|
||||
}
|
||||
|
||||
function Counter() {
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
|
@ -133,13 +111,14 @@ function Counter() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="btn__container">
|
||||
<button className="control__btn" onClick={increase}>
|
||||
+
|
||||
</button>
|
||||
<div className={styles.nodeContainer}>
|
||||
<button className="control__btn" onClick={decrease}>
|
||||
-
|
||||
</button>
|
||||
{counter}
|
||||
<button className="control__btn" onClick={increase}>
|
||||
+
|
||||
</button>
|
||||
<button className="reset" onClick={reset}>
|
||||
Reset
|
||||
</button>
|
||||
|
|
|
@ -1,5 +1,27 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
// Enable latest features
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue