diff options
Diffstat (limited to 'pages')
-rw-r--r-- | pages/index.tsx | 109 |
1 files changed, 50 insertions, 59 deletions
diff --git a/pages/index.tsx b/pages/index.tsx index 12c42a1..42170a1 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -40,7 +40,6 @@ import { ThemeContext, ThemeContextProps } from '../util/themecontext' import SpriteText from 'three-spritetext' import ReconnectingWebSocket from 'reconnecting-websocket' -import { sendJson } from 'next/dist/next-server/server/api-utils' // react-force-graph fails on import when server-rendered // https://github.com/vasturiano/react-force-graph/issues/155 @@ -73,16 +72,6 @@ export default function Home() { return <GraphPage /> } -function normalizeLinkEnds(link: OrgRoamLink | LinkObject): [string, string] { - // we need to cover both because force-graph modifies the original data - // but if we supply the original data on each render, the graph will re-render sporadically - const sourceId = - typeof link.source === 'object' ? (link.source.id! as string) : (link.source as string) - const targetId = - typeof link.target === 'object' ? (link.target.id! as string) : (link.target as string) - return [sourceId, targetId] -} - export function GraphPage() { const [threeDim, setThreeDim] = usePersistantState('3d', false) const [tagColors, setTagColors] = usePersistantState<TagColors>('tagCols', {}) @@ -104,7 +93,6 @@ export function GraphPage() { const currentGraphDataRef = useRef<GraphData>({ nodes: [], links: [] }) const updateGraphData = (orgRoamGraphData: OrgRoamGraphReponse) => { - const currentGraphData = currentGraphDataRef.current const oldNodeById = nodeByIdRef.current tagsRef.current = orgRoamGraphData.tags ?? [] const nodesByFile = orgRoamGraphData.nodes.reduce<NodesByFile>((acc, node) => { @@ -177,30 +165,29 @@ export function GraphPage() { }, {}) const nodes = [...orgRoamGraphData.nodes, ...nonExistantNodes] - const orgRoamGraphDataWithFileLinksAndBadNdes = { + const orgRoamGraphDataProcessed = { nodes, links, } - if (!currentGraphData.nodes.length) { + const currentGraphData = currentGraphDataRef.current + if (currentGraphData.nodes.length === 0) { // react-force-graph modifies the graph data implicitly, // so we make sure there's no overlap between the objects we pass it and // nodeByIdRef, linksByNodeIdRef - const orgRoamGraphDataClone = JSON.parse( - JSON.stringify(orgRoamGraphDataWithFileLinksAndBadNdes), - ) + const orgRoamGraphDataClone = JSON.parse(JSON.stringify(orgRoamGraphDataProcessed)) currentGraphDataRef.current = orgRoamGraphDataClone setGraphData(orgRoamGraphDataClone) return } const newNodes = [ - ...currentGraphData.nodes.map((node: NodeObject) => { + ...currentGraphData.nodes.flatMap((node: NodeObject) => { const newNode = nodeByIdRef.current[node?.id!] ?? false if (!newNode) { - return + return [] } - return { ...node, ...newNode } + return [{ ...node, ...newNode }] }), ...Object.keys(nodeByIdRef.current) .filter((id) => !oldNodeById[id]) @@ -225,7 +212,7 @@ export function GraphPage() { target: newNodes[nodeIndex![target]], } }) - const fg = graphRef.current + setGraphData({ nodes: newNodes as NodeObject[], links: newerLinks }) } useEffect(() => { @@ -240,7 +227,7 @@ export function GraphPage() { const scopeRef = useRef<Scope>({ nodeIds: [] }) const behaviorRef = useRef(initialBehavior) behaviorRef.current = behavior - const WebSocketRef = useRef<any>(null) + const WebSocketRef = useRef<ReconnectingWebSocket | null>(null) scopeRef.current = scope const followBehavior = ( @@ -288,7 +275,7 @@ export function GraphPage() { return } - // if the node is in the scopednodes, add it to scope instead of replacing it + // if the node is in the scoped nodes, add it to scope instead of replacing it if ( !sr.nodeIds.includes(emacsNode) || !sr.nodeIds.some((scopeId: string) => { @@ -315,11 +302,10 @@ export function GraphPage() { useEffect(() => { // initialize websocket WebSocketRef.current = new ReconnectingWebSocket('ws://localhost:35903') - WebSocketRef.current.addEventListener('open', (event: any) => { + WebSocketRef.current.addEventListener('open', () => { console.log('Connection with Emacs established') }) WebSocketRef.current.addEventListener('message', (event: any) => { - const fg = graphRef.current const bh = behaviorRef.current const message = JSON.parse(event.data) switch (message.type) { @@ -359,7 +345,8 @@ export function GraphPage() { if (!fg || scope.nodeIds.length > 1) { return } - if (!scope.nodeIds.length) { + if (!scope.nodeIds.length && physics.gravityOn) { + fg.zoomToFit() return } setTimeout(() => { @@ -499,15 +486,16 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { sendMessageToEmacs('create', { id: node.id, title: node.title, ref: node.properties.ROAM_REFS }) } + const contextMenu = useDisclosure() + const openContextMenu = (node: OrgRoamNode, event: any) => { setContextPos([event.pageX, event.pageY]) setRightClickedNode(node) - onOpen() + contextMenu.onOpen() } const handleClick = (click: string, node: OrgRoamNode, event: any) => { switch (click) { - //mouse.highlight: case mouse.local: { handleLocal(node, behavior.localSame) break @@ -523,6 +511,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { break } } + const findNthNeighbors = (ids: string[], n: number) => { let queue = [ids[0]] let todo: string[] = [] @@ -583,11 +572,6 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { hiddenNodeIdsRef.current = {} const filteredNodes = graphData?.nodes ?.filter((nodeArg) => { - //sometimes there will be some undefined nodes in the mix - // should probably fix the actual issue, but this is a fix - if (!nodeArg) { - return - } const node = nodeArg as OrgRoamNode if ( filter.tagsBlacklist.length && @@ -739,7 +723,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { graphRef.current?.d3ReheatSimulation() }, [physics, scope.nodeIds.length]) - //shitty handler to check for doubleClicks + // shitty handler to check for doubleClicks const lastNodeClickRef = useRef(0) const [opacity, setOpacity] = useState(1) @@ -821,9 +805,6 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { } const getLinkColor = (sourceId: string, targetId: string, needsHighlighting: boolean) => { - // I'm so sorry - // if we are matching the node color and don't have a highlight color - // or we don't have our own scheme and we're not being highlighted if (!visuals.linkHighlight && !visuals.linkColorScheme && !needsHighlighting) { const nodeColor = getLinkNodeColor(sourceId, targetId) return getThemeColor(nodeColor) @@ -857,7 +838,6 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { } const getNodeColor = (node: OrgRoamNode) => { - const isHighlightingHappening = !!highlightedNodes.length const needsHighlighting = highlightedNodes[node.id!] || previouslyHighlightedNodes[node.id!] // if we are matching the node color and don't have a highlight color // or we don't have our own scheme and we're not being highlighted @@ -893,17 +873,6 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { return highlightColors[getNodeColorById(node.id as string)][visuals.nodeHighlight](opacity) } - const hexToRGBA = (hex: string, opacity: number) => - 'rgba(' + - (hex = hex.replace('#', '')) - .match(new RegExp('(.{' + hex.length / 3 + '})', 'g'))! - .map(function (l) { - return parseInt(hex.length % 2 ? l + l : l, 16) - }) - .concat(isFinite(opacity) ? opacity : 1) - .join(',') + - ')' - const labelTextColor = useMemo( () => getThemeColor(visuals.labelTextColor), [visuals.labelTextColor, emacsTheme], @@ -929,14 +898,13 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { } const [dragging, setDragging] = useState(false) - const { isOpen, onOpen, onClose } = useDisclosure() const graphCommonProps: ComponentPropsWithoutRef<typeof TForceGraph2D> = { graphData: scope.nodeIds.length ? scopedGraphData : filteredGraphData, width: windowWidth, height: windowHeight, backgroundColor: theme.colors.gray[visuals.backgroundColor], - warmupTicks: scope.nodeIds.length === 1 ? 100 : 0, + warmupTicks: scope.nodeIds.length === 1 ? 100 : scope.nodeIds.length > 1 ? 20 : 0, nodeLabel: (node) => (node as OrgRoamNode).title, nodeColor: (node) => { return getNodeColor(node as OrgRoamNode) @@ -971,7 +939,6 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { nodeTitle.length > visuals.labelLength ? nodeTitle.substring(0, visuals.labelLength) + '...' : nodeTitle - // const label = 'label' const fontSize = visuals.labelFontSize / (0.75 * Math.min(Math.max(0.5, globalScale), 3)) const textWidth = ctx.measureText(label).width const bckgDimensions = [textWidth * 1.1, fontSize].map((n) => n + fontSize * 0.5) as [ @@ -1020,7 +987,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { linkDirectionalArrowLength: visuals.arrows ? visuals.arrowsLength : undefined, linkDirectionalArrowRelPos: visuals.arrowsPos, linkDirectionalArrowColor: visuals.arrowsColor - ? (link) => getThemeColor(visuals.arrowsColor) + ? () => getThemeColor(visuals.arrowsColor) : undefined, linkColor: (link) => { const sourceId = typeof link.source === 'object' ? link.source.id! : (link.source as string) @@ -1070,7 +1037,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { onNodeClick: (nodeArg: NodeObject, event: any) => { const node = nodeArg as OrgRoamNode - onClose() + contextMenu.onClose() const isDoubleClick = event.timeStamp - lastNodeClickRef.current < 400 lastNodeClickRef.current = event.timeStamp if (isDoubleClick) { @@ -1079,7 +1046,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { return handleClick('click', node, event) }, onBackgroundClick: () => { - onClose() + contextMenu.onClose() setHoverNode(null) if (scope.nodeIds.length === 0) { return @@ -1106,11 +1073,11 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { handleClick('right', node, event) }, onNodeDrag: (node) => { - onClose() + contextMenu.onClose() setHoverNode(node) setDragging(true) }, - onNodeDragEnd: (node) => { + onNodeDragEnd: () => { setHoverNode(null) setDragging(false) }, @@ -1118,7 +1085,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { return ( <Box overflow="hidden"> - {isOpen && ( + {contextMenu.isOpen && ( <ContextMenu scope={scope} node={rightClickedNode!} @@ -1126,7 +1093,7 @@ export const Graph = forwardRef(function (props: GraphProps, graphRef: any) { background={false} coordinates={contextPos} handleLocal={handleLocal} - menuClose={onClose} + menuClose={contextMenu.onClose.bind(contextMenu)} openNodeInEmacs={openNodeInEmacs} deleteNodeInEmacs={deleteNodeInEmacs} createNodeInEmacs={createNodeInEmacs} @@ -1186,3 +1153,27 @@ function isLinkRelatedToNode(link: LinkObject, node: NodeObject | null) { function numberWithinRange(num: number, min: number, max: number) { return Math.min(Math.max(num, min), max) } + +function normalizeLinkEnds(link: OrgRoamLink | LinkObject): [string, string] { + // we need to cover both because force-graph modifies the original data + // but if we supply the original data on each render, the graph will re-render sporadically + const sourceId = + typeof link.source === 'object' ? (link.source.id! as string) : (link.source as string) + const targetId = + typeof link.target === 'object' ? (link.target.id! as string) : (link.target as string) + return [sourceId, targetId] +} + +function hexToRGBA(hex: string, opacity: number) { + return ( + 'rgba(' + + (hex = hex.replace('#', '')) + .match(new RegExp('(.{' + hex.length / 3 + '})', 'g'))! + .map(function (l) { + return parseInt(hex.length % 2 ? l + l : l, 16) + }) + .concat(isFinite(opacity) ? opacity : 1) + .join(',') + + ')' + ) +} |