Skip to content

Commit

Permalink
Dependencies update, exposed new APIs (#77)
Browse files Browse the repository at this point in the history
* New build system, updating ogma and react

* Exposed two more layer APIs, fixed the tests, moved to vite for the build

* Removed typehead, fixed types

* Scripts and version

* gh-pages directory update

* web -> demo

* Trying to fix the coverage reports

* Fixed the react 18 mode

* Fixed the typings
  • Loading branch information
w8r authored Dec 4, 2023
1 parent f61ce27 commit 6de2692
Show file tree
Hide file tree
Showing 53 changed files with 4,918 additions and 1,671 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 4.3.3
current_version = 4.6.0
commit = False
tag = False
serialize =
Expand Down
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.3.3
4.6.0
File renamed without changes.
File renamed without changes.
7 changes: 3 additions & 4 deletions web/index.html → demo/index.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
<!DOCTYPE html>
<!doctype html>
<head>
<meta charset="utf-8" />
<title>React Ogma; component</title>
<link href="index-bundle.css" rel="stylesheet" />
<title>React Ogma component</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css"
/>
</head>
<body>
<div id="root"></div>
<script src="index-bundle.js" type="module"></script>
<script src="index.tsx" type="module"></script>
</body>
10 changes: 6 additions & 4 deletions web/index.tsx → demo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from "react";
import ReactDOM from "react-dom";
import { createRoot } from "react-dom/client";
import "./src/index.css";
import App from "./src/App";
import { GeistProvider, CssBaseline } from "@geist-ui/core";

ReactDOM.render(
const container = document.getElementById("root")!;
const root = createRoot(container);

root.render(
<React.StrictMode>
<GeistProvider>
<CssBaseline />
<App />
</GeistProvider>
</React.StrictMode>,
document.getElementById("root")
</React.StrictMode>
);
File renamed without changes
70 changes: 38 additions & 32 deletions web/src/App.tsx → demo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import OgmaLib, {
Node,
Point,
RawGraph,
Transformation,
NodeGrouping as NodeGroupingTransformation,
} from "@linkurious/ogma";
import { useEffect, useState, createRef } from "react";
import { useEffect, useState, createRef, useCallback } from "react";
// loading indicator
import { Loading } from "@geist-ui/core";
// for geo mode
Expand All @@ -19,7 +19,7 @@ import {
NodeGrouping,
Popup,
Geo,
NodeGroupingProps
NodeGroupingProps,
} from "../../src";

// cusotm components:
Expand All @@ -29,11 +29,16 @@ import { LayoutService } from "./components/Layout";
import { GraphOutlines } from "./components/GraphOutlines";
// control panel
import { Controls } from "./components/Controls";
import { MousePosition } from "./components/MousePosition";
import { Logo } from "./components/Logo";
import { UpdateGroupingButton } from "./components/UpdateGroupingButton";

// to enable geo mode integration
OgmaLib.libraries["leaflet"] = L;

type ND = unknown;
type ED = unknown;

export default function App() {
// graph state
const [graph, setGraph] = useState<RawGraph>();
Expand All @@ -45,33 +50,40 @@ export default function App() {

// ogma instance and grouping references
const ref = createRef<OgmaLib>();
const groupingRef = createRef<Transformation>();
const groupingRef = createRef<NodeGroupingTransformation<ND, ED>>();

// grouping and geo states
const [nodeGrouping, setNodeGrouping] = useState(true);
const [geoEnabled, setGeoEnabled] = useState(false);
// styling states
const [nodeSize, setNodeSize] = useState(5);
const [edgeWidth, setEdgeWidth] = useState(0.25);
const [groupingOptions, setGroupingOptions] = useState<NodeGroupingProps<any, any>>({
const [groupingOptions, setGroupingOptions] = useState<
NodeGroupingProps<any, any>
>({
groupIdFunction: (node) => {
const categories = node.getData("categories");
if (!categories) return undefined;
return categories[0] === "INVESTOR" ? "INVESTOR" : undefined;
},
nodeGenerator: (nodes) => {
return { data: { multiplier: nodes.size } };
}
},
disabled: true,
});


// UI layers
const [outlines, setOutlines] = useState(false);
const [tooltipPositon, setTooltipPosition] = useState<Point>({
x: -1e5,
y: -1e5,
x: 0,
y: 0,
});
const [target, setTarget] = useState<Node | Edge | null>();

const requestSetTooltipPosition = useCallback((pos: Point) => {
requestAnimationFrame(() => setTooltipPosition(pos));
}, []);

// load the graph
useEffect(() => {
setLoading(true);
Expand All @@ -83,16 +95,6 @@ export default function App() {
});
}, []);

function updateGrouping() {
setGroupingOptions({
...groupingOptions,
groupIdFunction: (node) => {
const categories = node.getData("categories");
return categories[0] === "INVESTOR" ? "INVESTOR" : "OTHER";
}
})
}

// nothing to render yet
if (loading) return <Loading />;

Expand All @@ -112,14 +114,14 @@ export default function App() {
})
.on("mousemove", () => {
const ptr = ogma.getPointerInformation();
setTooltipPosition(
ogma.view.screenToGraphCoordinates({ x: ptr.x, y: ptr.y })
requestSetTooltipPosition(
ogma.view.screenToGraphCoordinates({ x: ptr.x, y: ptr.y }),
);
setTarget(ptr.target);
})
// locate graph when the nodes are added
.on("addNodes", () =>
ogma.view.locateGraph({ duration: 250, padding: 50 })
ogma.view.locateGraph({ duration: 250, padding: 50 }),
);
}}
>
Expand All @@ -136,6 +138,15 @@ export default function App() {
{/* Layout */}
<LayoutService />

{/* Grouping */}
<NodeGrouping
ref={groupingRef}
disabled={!nodeGrouping && !geoEnabled}
groupIdFunction={groupingOptions.groupIdFunction}
nodeGenerator={groupingOptions.nodeGenerator}
duration={500}
/>

{/* context-aware UI */}
<Popup
position={() => (clickedNode ? clickedNode.getPosition() : null)}
Expand All @@ -155,20 +166,17 @@ export default function App() {
</Tooltip>
<GraphOutlines visible={outlines} />

{/* Grouping */}
<NodeGrouping
ref={groupingRef}
disabled={!nodeGrouping && !geoEnabled}
groupIdFunction={groupingOptions.groupIdFunction}
nodeGenerator={groupingOptions.nodeGenerator}
duration={500}
/>
{/* Geo mode */}
<Geo
enabled={geoEnabled}
longitudePath="properties.longitude"
latitudePath="properties.latitude"
/>
<MousePosition />
<UpdateGroupingButton
options={groupingOptions}
update={(options) => setGroupingOptions(options)}
/>
</Ogma>
<Controls
toggleNodeGrouping={(value) => setNodeGrouping(value)}
Expand All @@ -180,8 +188,6 @@ export default function App() {
geoEnabled={geoEnabled}
setGeoEnabled={setGeoEnabled}
/>
<button id="button" onClick={updateGrouping}>update grouping</button>

</div>
);
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ export function GraphOutlines({ visible = true }: GraphOutlinesProps) {
const render = useCallback((ctx: CanvasRenderingContext2D) => {
ctx.fillStyle = "rgba(157, 197, 187, 0.25)";
ctx.beginPath();
ogma.getNodes().forEach((node) => {
const { x, y } = node.getPosition();
const radius = node.getAttribute("radius");
ctx.moveTo(x, y);
ctx.arc(x, y, (radius as number) * 6, 0, 2 * Math.PI);
});
ogma
.getNodes()
.getAttributes(["x", "y", "radius"])
.forEach(({ x, y, radius }) => {
ctx.moveTo(x, y);
ctx.arc(x, y, (radius as number) * 6, 0, 2 * Math.PI);
});
ctx.fill();
}, []);

useEffect(() => {
const refresh = () => {
layerRef.current?.refresh();
};
ogma.events.on("nodesDragProgress", refresh);
ogma.events.on(["nodesDragProgress", "idle"], refresh);
return () => {
ogma.events.off(refresh);
};
Expand Down
11 changes: 7 additions & 4 deletions web/src/components/Layout.tsx → demo/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { NodeList } from "@linkurious/ogma";
import { useEffect } from "react";
import { useCallback, useEffect } from "react";
import { useOgma } from "../../../src";

// custom layout service based on the event of the nodes being added
export function LayoutService() {
const ogma = useOgma();
const onNodesAdded = (_evt: { nodes: NodeList }) => {
ogma.layouts.force({ locate: true });
};
const onNodesAdded = useCallback(
(_evt: { nodes: NodeList }) => {
ogma.events.once("idle", () => ogma.layouts.force({ locate: true }));
},
[ogma]
);

useEffect(() => {
// register listener
Expand Down
File renamed without changes.
8 changes: 8 additions & 0 deletions demo/src/components/MousePosition.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.position-control__container {
position: absolute;
top: 15px;
left: 20em;
color: #888;
padding: 0.5em;
font-size: x-small;
}
36 changes: 36 additions & 0 deletions demo/src/components/MousePosition.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Point, Layer as OgmaLayer } from "@linkurious/ogma";
import { useEffect, useState, useCallback, useRef } from "react";
import { useOgma, Layer } from "../../../src";
import "./MousePosition.css";

export const MousePosition = () => {
const ogma = useOgma();
const [position, setPosition] = useState<Point>({ x: 0, y: 0 });
const layerRef = useRef<OgmaLayer>(null);

const requestSetPosition = useCallback(
(pos: Point) => {
requestAnimationFrame(() => setPosition(pos));
},
[setPosition]
);

useEffect(() => {
const listener = () => {
const { x, y } = ogma.getPointerInformation();
requestSetPosition({ x, y });
};
ogma.events.on("mousemove", listener);
return () => {
ogma.events.off(listener);
};
}, [ogma]);

return (
<Layer className="position-control" ref={layerRef}>
<div className="position-control__container">
{position.x},&nbsp;{position.y}
</div>
</Layer>
);
};
File renamed without changes.
30 changes: 30 additions & 0 deletions demo/src/components/ShuffleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const ShuffleIcon = ({ width = 12, height = 12 }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
fill="currentColor"
strokeWidth="0"
style={{ overflow: "visible", color: "currentcolor" }}
viewBox="0 0 512 512"
>
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="32"
d="m400 304 48 48-48 48M400 112l48 48-48 48M64 352h85.19a80 80 0 0 0 66.56-35.62L256 256"
/>
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="32"
d="M64 160h85.19a80 80 0 0 1 66.56 35.62l80.5 120.76A80 80 0 0 0 362.81 352H416m0-192h-53.19a80 80 0 0 0-66.56 35.62L288 208"
/>
</svg>
);
};
16 changes: 16 additions & 0 deletions demo/src/components/UpdateGroupingButton.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.grouping-controls button {
position: fixed;
top: 60px;
right: 20px;
background-color: transparent;
border: 1px solid #ddd;
border-radius: 6px;
min-width: 18px;
color: #aaa;
cursor: pointer;
}

.grouping-controls button:hover {
border-color: #444;
color: #444;
}
30 changes: 30 additions & 0 deletions demo/src/components/UpdateGroupingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { FC, useCallback } from "react";
import { Layer, NodeGroupingProps } from "../../../src";
import "./UpdateGroupingButton.css";
import { ShuffleIcon } from "./ShuffleIcon";

type ND = { categories: string[] };
type ED = {};

export const UpdateGroupingButton: FC<{
options: NodeGroupingProps<ND, ED>;
update: (options: NodeGroupingProps<ND, ED>) => void;
}> = ({ options, update }) => {
const onClick = useCallback(() => {
update({
...options,
groupIdFunction: (node) => {
const categories = node.getData("categories");
return categories[0] === "INVESTOR" ? "INVESTOR" : "OTHER";
},
});
}, [options]);

return (
<Layer className="grouping-controls">
<button onClick={onClick}>
<ShuffleIcon />
</button>
</Layer>
);
};
File renamed without changes.
Loading

0 comments on commit 6de2692

Please sign in to comment.