const accountId = props.accountId ?? "agency.near"; const GraphContainer = styled.div` display: flex; justify-content: center; align-items: center; width: 100%; height: ${(props) => props.height || "325px"}; `; const [agentBuilders, setAgentBuilders] = useState( props.agentBuilders || [ "zodiac-ellipse.near", "zenieverse.near", "zavodil.near", "your-account.near", "yemariamyene21.tg", "wua.near", "web3_qianglu.near", "visualise_crypto.near", "tukpsyche.near", "toughport6739.near", "toolblox.near", "testai.near", "svntax.near", "sukrucildirr.near", "squaredish4141.near", "souheila_jutsu.near", "solar_liora.near", "snpark.near", "smartpool.near", "slimedragon.near", "simplegarden7738.near", "silentbob.near", "sachinanand.near", "rudedish8392.near", "root.near", "ridgerock.near", "realmadao.near", "rambo_lamport.near", "raixon-sherif.near", "r1c0ch37.near", "prizrak.near", "poolofgreed.near", "plugrel.near", "pivortex.near", "pierre-dev.near", "papajams.near", "owng.near", "oupiou.near", "orbit-bitwanderer.near", "orangejoe.near", "operator69.near", "oluwatobig.near", "olddad.near", "oilinup.near", "nescrow_dispute.near", "nescrow_compliance.near", "near.ai", "near-ai-dev.near", "near-ai-agents.near", "ncd-cn.near", "nate.near", "minamoto.near", "microchipgnu.mintbase.near", "michael-gold.near", "marti_honest.tg", "manyherb24.near", "maleibis6865.near", "maguila.near", "luna_grilka.near", "lucyfer1865.near", "lucasmetapool.near", "lfgser.near", "learn-agent.learnclub.near", "kurodenjiro.near", "kirikiritest1.near", "kirikiri.near", "kenzo3040.near", "kcameau.near", "kapyshonchik.near", "kantian.near", "kakoilogin.tg", "jral.near", "joshford.near", "josefophe.near", "johnnydoe.near", "johnimmanuel.near", "jayzalowitznear.near", "jayzalowitz.near", "jaswinder.near", "jass-mintbase.near", "jasonbalayev.near", "jarrodbarnes.near", "intellex_agents_owner_1.near", "humanant4494.near", "hodinhdung.near", "hoangvietanh.near", "hdapps.near", "hasung.near", "hanui.near", "gnearai.near", "gklimov.near", "ghostoshi.near", "getaiceo.near", "gagdiez.near", "frol.near", "foxy-merlin.near", "flmel.near", "flatirons.near", "fineapp2174.near", "fattienay.near", "f8bbc7a0a2a9a22f089fa1e0f3e43cad8b748781b0bc0212a66f2b515ffbc154", "eric3.near", "edwardtay.near", "ecvm.near", "earth_fixed.near", "duonghb.near", "duitkripto.near", "dsauce.near", "dleer.near", "djsail.near", "diurnal-echo.near", "devpad.near", "devbot.near", "deoxicit.near", "denbite.near", "demi-god.near", "deepbank5218.near", "dc1312.near", "datablock.near", "darkseal4894.near", "dapplets.near", "dailies.near", "cyberabyss.near", "cuongdcdev.near", "crans.near", "cloudleopard.near", "clearsite1518.near", "clearn.near", "cije.near", "charaf.near", "calmhost9934.near", "calebjacob.near", "cakrakahn.near", "c7eecd2861c5efd169b7c1a92f4a2c75889e912dd1aa195f6c49c38021697d93", "c2719b55f87cb65016a651981273020fe4fad83b382fe1bc672b646d469739ad", "bytesun.near", "builder106.near", "buildagents.near", "bucanero.near", "bild96.near", "bernardomafra.near", "beb88244909852f2901dfeb3fc7d17b11f7a2718ff0454e3bc4ac88a1d503911", "bafnetwork.near", "badisland7754.near", "b22f098cdd279a9397e12a73005fc0c5fcbf3765dca491989ceb6ec856629b77", "au.near", "antonlomonos.near", "amiranasri.near", "alomonos.near", "aiml.near", "aiguy.near", "ai-creator.near", "ai-aaron.near", "agentic.near", "agent.raidvault.near", "aeliana_nebulous.near", "aden1998.near", "ab2eda0b1f5ced2534ff33ce4f85c9f426f84480cfcb23261cef560bf0fb4450", "aaravdev.near", "a283cb5de1d7d812f281eeaacf6e13729d80a66a651bf9fca44f1ff3b4547478", "9968.near", "777b79a24b0afac4f59eb0d6e1a0a6427fea2e550119b6d12d5658ca8dcb6091", "673c02d11b89cd95a81db821633ca88763b8c0175a60c4344be05b70897beb6b", "585d4519bd4bdaa4a1b5e0c93146dd4089ee0fa0b93eac11980c5e8b16ff4491", "57bf9b9f13dcad2bc08acf39d165d8299ded0174d90176cf907793b93a8748a8", "4deb2b333f603cfd8ea91235d122a3316c0581aacfd62adfa4f98aeb717a744b", "4db2a117ec660f53fda1aac24269f4d8772b831c47dddb7bb09956dc30e8bb08", "3823b5b2b0b8d5c49159c37d11b5b70ebb38483bcc45378020e707aa5b72fd8f", "36fd2808256e5edaaf2a189ea2370c54b0adc4c0a9d8d54bcc96e66d32e42250", "31236c2dd9582d0e5a798a843159c2b104a145454419cd0f63c4347e505fd9ad", "2f172066f80b20617a293dc3abf2aebeaed2d31e64762e0fe216fbf011cc85fc", "26d20b7457535c25b79a54689554fd674e5f8ae2f1d9fd8abd69cc1c71a7da1f", "20a5c087b0ec13cf25e473b0918015b4fb925de02ae75c961065c5213af5683e", "1t_hacks.near", "132426a54bb6eb6df4c81d9464c8e0022a18ae4a57808be278fbf4a6eb7fe8c7", "10aa82ff17270ea1784a4661865717d0ee3bdd0298f06f5e6722c4f73f23b14a", "0x8f84f5d6ad33f0da3bb.near", "0af67cec57087e2ab7ce09186c5a90431e9c64a9cd60811ed4cb85e13fdf4d76", ] ); const graphId = props.graphId ?? "follow"; const generatePaths = () => { return ( props.paths ?? agentBuilders.map((accountId) => { return `${accountId}/graph/${graphId}`; }) ); }; const paths = generatePaths(); const data = Social.getr(paths, "final"); const [nodesState, setNodesState] = useState(null); const [focus, setFocus] = useState(null); const debug = false; useEffect(() => { setNodesState(data); }, [data]); if (!nodesState) { return <GraphContainer></GraphContainer>; } const [selectedAccountId, setSelectedAccountId] = useState(accountId); const [message, setMessage] = useState(null); useEffect(() => { if (!nodesState) { return; } const nodes = {}; const edges = []; const createNodesAndEdges = (accountId, graphData) => { if (!agentBuilders.includes(accountId)) return; if (!(accountId in nodes)) { nodes[accountId] = { id: accountId, size: 139, }; } Object.values(graphData).forEach((links) => { Object.keys(links).forEach((memberId) => { if (!agentBuilders.includes(memberId)) return; if (!(memberId in nodes)) { nodes[memberId] = { id: memberId, size: 139, }; } edges.push({ source: accountId, target: memberId, value: 1, }); }); }); }; if (agentBuilders.length === 1) { const accountId = agentBuilders[0]; createNodesAndEdges(accountId, { [graphId]: nodesState }); } else if (agentBuilders.length > 1) { Object.entries(nodesState).forEach(([accountId, graphData]) => { createNodesAndEdges(accountId, graphData.graph); }); } setMessage({ nodes: Object.values(nodes), edges, }); }, [nodesState, agentBuilders]); useEffect(() => { if (selectedAccountId) { if (agentBuilders.includes(selectedAccountId)) { setAgentBuilders(agentBuilders.filter((it) => it !== selectedAccountId)); } else { setAgentBuilders([...agentBuilders, selectedAccountId]); } } }, [selectedAccountId]); const graphEdge = Social.keys( `${context.accountId}/graph/${graphId}/${accountId}`, undefined, { values_only: true, } ); const inverseEdge = Social.keys( `${accountId}/graph/${graphId}/${context.accountId}`, undefined, { values_only: true, } ); const loading = graphEdge === null || inverseEdge === null; const attested = graphEdge && Object.keys(graphEdge).length; const inverse = inverseEdge && Object.keys(inverseEdge).length; let height = props.height || 325; const code = ` <!DOCTYPE html> <meta charset="utf-8"> <!-- Load d3.js --> <script src="https://d3js.org/d3.v6.js"></script> <div class="container"> <svg id="graph" width="100%" height="auto" viewBox="0 0 650 325" preserveAspectRatio="xMidYMid meet" style="display: block; margin: auto;"> </div> <style> .container { display: flex; justify-content: center; align-items: center; height: 100vh; width: 100%; } </style> <script> const run = (data) => { const width = 650; const height = \`${height}\`; let dragIsOn = false; const links = data.edges.map(d => ({...d})); const nodes = data.nodes.map(d => ({...d})); const simulation = d3.forceSimulation(nodes) .force("link", d3.forceLink(links).id(d => d.id)) .force("charge", d3.forceManyBody().strength(-500)) .force("collide", d3.forceCollide().radius(d => Math.sqrt(d.size) )) .force("center", d3.forceCenter(width / 2, height / 2)) .on("tick", ticked); simulation.force("collide") .strength(.7) .radius(d => Math.sqrt(d.size)) .iterations(1); const svg = d3.select("#graph") .attr("width", width) .attr("height", height) .attr("viewBox", [0, 0, width, height]) .attr("style", "max-width: 100%; height: auto;"); const link = svg.append("g") .attr("stroke", "#999") .attr("stroke-opacity", 0.6) .selectAll() .data(links) .join("line") .attr("stroke-width", 1); const node = svg.append("g") .selectAll("g") .data(nodes) .enter() .append("g"); node .append("image") .attr("xlink:href", (d) => \`https://i.near.social/magic/thumbnail/https://near.social/magic/img/account/\${d.id}\`) // Set the image URL based on your data .attr("x", (d) => -Math.sqrt(d.size) - 5) .attr("y", (d) => -Math.sqrt(d.size) - 5) .attr("clip-path", d => \`circle(\${Math.sqrt(d.size) + 5}px at \${Math.sqrt(d.size) + 5} \${Math.sqrt(d.size) + 5})\`) .attr("width", (d) => 2 * Math.sqrt(d.size) + 10); node .append("circle") .attr("r", d => Math.sqrt(d.size) + 5) .attr("fill", "none"); node.append("title") .text(d => d.id); node.call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); node.on("mouseover", handleMouseOver) .on("mouseout", handleMouseOut) .on("click", handleMouseClick); function handleMouseClick(e) { const d = e.target.__data__; window.top.postMessage({ handler: "click", data: d.id }, "*"); } function handleMouseOver(d) { d = d.target.__data__; link.attr("stroke-opacity", e => (e.source === d || e.target === d) ? 1 : 0.1); node.attr("opacity", function (n) { return n === d || isConnected(d, n) ? 1: 0.3; }); window.top.postMessage({ handler: "mouseover", data: d.id }, "*"); } function handleMouseOut() { if (dragIsOn) { return; } link .attr("stroke-opacity", 0.6); node.attr("opacity", 1); window.top.postMessage({ handler: "mouseout", data: "out" }, "*"); } function isConnected(a, b) { return links.some(function (link) { return (link.source === a && link.target === b) || (link.source === b && link.target === a); }); } function ticked() { link .attr("x1", d => d.source.x) .attr("y1", d => d.source.y) .attr("x2", d => d.target.x) .attr("y2", d => d.target.y); node.attr("transform", d => \`translate(\${d.x}, \${d.y})\`) } function dragstarted(event) { dragIsOn = true; if (!event.active) simulation.alphaTarget(0.3).restart(); event.subject.fx = event.subject.x; event.subject.fy = event.subject.y; } function dragged(event) { event.subject.fx = event.x; event.subject.fy = event.y; } function dragended(event) { if (!event.active) simulation.alphaTarget(0); event.subject.fx = null; event.subject.fy = null; dragIsOn = false; handleMouseOut(); } return simulation; }; let simulation = null; window.addEventListener("message", (event) => { if (simulation) { simulation.stop(); d3.select("#graph").selectAll("*").remove(); } if (event.data) { simulation = run(event.data); } }); </script> `; const [onMessage] = useState(() => { return (data) => { if (data) { switch (data.handler) { case "click": setSelectedAccountId(data.data); break; } } }; }); return ( <> <GraphContainer height={height}> <iframe className="w-100 h-100" style={{ display: "flex", justifyContent: "center", alignItems: "center", minHeight: "325px", maxWidth: "888px", width: "100%", }} srcDoc={code} message={message} onMessage={onMessage} /> </GraphContainer> </> );