diff --git a/.eslintignore b/.eslintignore index 457da68..1794051 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ coverage/ dist/ node_modules/ examples/ +docs/ webpack.config.js diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..7b2f944 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,82 @@ +name: Deploy docs to GitHub Pages + +on: + push: + # NOTE: `new/add-docs-page` is a TEMPORARY entry so the team can review a live + # deploy from the docs branch. Remove it before/at merge so main deploys only + # from main. + branches: [main] + # Validate the bundle + docs build on any PR that touches them, so reviewers + # get a green check without needing Pages enabled or a merge to main. The + # deploy job below is skipped for PRs. + pull_request: + paths: + - "docs/site/**" + - "src/**" + - ".github/workflows/docs.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +# One deploy at a time, but keep PR builds from cancelling a main deploy (and +# vice versa) by scoping the group per ref. +concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + # 1. Build the Orb browser bundle from source so the live demos stay in sync. + - name: Build Orb bundle + run: | + npm ci + npm run build:release + + # 2. Refresh the copies the docs site embeds. + - name: Sync bundle into docs site + run: | + cp dist/browser/orb.min.js docs/site/public/orb.min.js + cp dist/browser/orb.worker.min.js docs/site/public/orb.worker.min.js + # The module worker loads this shared vendor chunk as a sibling; without + # it the worker fails silently and layout simulation never runs. + cp dist/browser/orb.worker.vendor.min.js docs/site/public/orb.worker.vendor.min.js + + # 3. Build the VitePress site. + - name: Build docs + working-directory: docs/site + run: | + npm install + npm run build + + # 4. Package for Pages. Only needed for an actual deploy, so skip on PRs + # (where these steps would also fail until Pages is enabled). + - uses: actions/configure-pages@v5 + if: github.event_name != 'pull_request' + + - uses: actions/upload-pages-artifact@v3 + if: github.event_name != 'pull_request' + with: + path: docs/site/.vitepress/dist + + deploy: + needs: build + # Deploy only from main; PRs run the build job above for validation only. + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 2d5cd1a..34e3c2c 100644 --- a/README.md +++ b/README.md @@ -18,20 +18,28 @@ ![](./docs/assets/graph-example.png) -Orb is a graph visualization library. Read more about Orb in the following guides: +Orb is a graph visualization library. It renders interactive graphs on the 2D Canvas or on +WebGL, runs force-directed (CPU or GPU), circular, grid, and hierarchical layouts, plots +geo-located nodes on a map, and gives you full control over the style of every node and edge. -* [Handling nodes and edges](./docs/data.md) -* [Styling nodes and edges](./docs/styles.md) -* [Handling events](./docs/events.md) -* Using different views - * [Default view](./docs/view-default.md) - * [Map view](./docs/view-map.md) +## Documentation -## Install +Full guides, the API reference, and live interactive demos are on the documentation site: + +**https://memgraph.github.io/orb/** + +Some good places to start: + +* [Getting started](https://memgraph.github.io/orb/introduction/getting-started) +* [Graph data](https://memgraph.github.io/orb/concepts/data) - nodes, edges, and updates +* [Styling](https://memgraph.github.io/orb/concepts/styling) - colors, shapes, borders, labels +* [Events](https://memgraph.github.io/orb/concepts/events) and [Interaction](https://memgraph.github.io/orb/concepts/interaction) +* [Layouts](https://memgraph.github.io/orb/layouts/overview) - force, GPU, and static layouts +* [Canvas vs WebGL](https://memgraph.github.io/orb/rendering/renderers) +* [Map view](https://memgraph.github.io/orb/views/map) +* [API reference](https://memgraph.github.io/orb/reference/api) -> **Important note**: Please note that there might be breaking changes in minor version upgrades until -> the Orb reaches version 1.0.0, so we recommend to either set strict version (`@memgraph/orb: "0.x.y"`) -> of the Orb in your `package.json` or to allow only fix updates (`@memgraph/orb: "~0.x.y"`). +## Install ### With `npm` (recommended) @@ -39,24 +47,22 @@ Orb is a graph visualization library. Read more about Orb in the following guide npm install @memgraph/orb ``` -Below you can find a simple Typescript example using Orb to visualize a small graph. Feel -free to check other JavaScript examples in `examples/` directory. - ```typescript import { OrbView } from '@memgraph/orb'; + const container = document.getElementById('graph'); -const nodes: MyNode[] = [ +const nodes = [ { id: 1, label: 'Orb' }, { id: 2, label: 'Graph' }, { id: 3, label: 'Canvas' }, ]; -const edges: MyEdge[] = [ +const edges = [ { id: 1, start: 1, end: 2, label: 'DRAWS' }, { id: 2, start: 2, end: 3, label: 'ON' }, ]; -const orb = new OrbView(container); +const orb = new OrbView(container); // Initialize nodes and edges orb.data.setup({ nodes, edges }); @@ -73,69 +79,24 @@ orb.render(() => { > link. Graph simulation will use the main thread, which will affect performance. ```html - - - - - - - + ``` -Below you can find a simple JavaScript example using Orb to visualize a small graph. Feel -free to check other JavaScript examples in `examples/` directory. - -```html - - - - - Orb | Simple graph - - - - -
- - - -``` +See the [getting started guide](https://memgraph.github.io/orb/introduction/getting-started) +for a complete runnable example. ## Build ``` -npm run build +npm run build # type-check + emit (tsc) +npm run build:release # tsc + webpack browser bundle (dist/browser/) ``` ## Test @@ -146,30 +107,38 @@ npm run test ## Development -If you want to experiment, contribute, or simply play with the Orb locally, you can -set up your local development environment with: +If you want to experiment, contribute, or simply play with Orb locally: -* Installation of all project dependencies +* Install dependencies ``` npm install ``` -* Running webpack build in the watch mode +* Rebuild the browser bundle on change ``` npm run webpack:watch ``` -* Running a local http server that will serve Orb and `examples/` directory on `localhost:8080` +* Serve the built bundle from `dist/browser/` on `localhost:8082` ``` npm run serve ``` +* Lint + + ``` + npm run lint + ``` + +To work on the documentation site itself, see `docs/site/` (a self-contained VitePress +project with its own `package.json`). + ## License -Copyright (c) 2016-2022 [Memgraph Ltd.](https://memgraph.com) +Copyright (c) 2016-present [Memgraph Ltd.](https://memgraph.com) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the diff --git a/docs/assets/view-default-fixed.png b/docs/assets/view-default-fixed.png deleted file mode 100644 index ce8c710..0000000 Binary files a/docs/assets/view-default-fixed.png and /dev/null differ diff --git a/docs/assets/view-default-simulated.png b/docs/assets/view-default-simulated.png deleted file mode 100644 index a46d785..0000000 Binary files a/docs/assets/view-default-simulated.png and /dev/null differ diff --git a/docs/assets/view-map-example.png b/docs/assets/view-map-example.png deleted file mode 100644 index cd5506c..0000000 Binary files a/docs/assets/view-map-example.png and /dev/null differ diff --git a/docs/data.md b/docs/data.md deleted file mode 100644 index f07f26d..0000000 --- a/docs/data.md +++ /dev/null @@ -1,326 +0,0 @@ -# Handling graph data in Orb - -Graph data structure (nodes and edges) is the main part of Orb. Without the graph data -structure, there wouldn't be anything to render. Read the following guide to get to know -how to handle graph data in Orb. - -> Note: Please do not use `node.addEdge` and `node.removeEdge` because the general graph data -> structure might go out of sync. Always use `orb.data.(setup|merge|remove)` to change the -> graph data structure. - -## Setup nodes and edges - -To set up `nodes` and `edges`, there are a few requirements that Orb expects: - -- Node data object should be a JSON plain object with a defined unique `id`. The value of `id` can - be `any`. All other properties are up to you (e.g. `text` and `myField` in the above example). -- Edge data object should be a JSON plain object with defined unique `id`, `start` (id of - the source node), `end` (id of the target node). The value of `id` can be `any`. All other - properties are up to you. (e.g. `connects` in the above example). - -You can have your own `node` and `edge` types that satisfy those requirements: - -```typescript -export interface MyNode { - id: number; - text: string; - myField: number; -} - -export interface MyEdge { - id: number; - start: number; - end: number; - connects: string; -} -``` - -To initialize graph data structure use `orb.data.setup` function that receives `nodes` and -`edges`. Here is a simple example of it: - -```typescript -import { OrbView } from "@memgraph/orb"; - -const orb = new OrbView(container); - -const nodes: MyNode[] = [ - { id: 0, text: "Node A", myField: 12 }, - { id: 1, text: "Node B", myField: 77 }, -]; - -const edges: MyEdge[] = [ - { id: 0, start: 0, end: 1, connects: "A -> B" }, - { id: 1, start: 0, end: 0, connects: "A -> A" }, -]; - -orb.data.setup({ nodes, edges }); -``` - -Whenever `orb.data.setup` is called, any previous graph structure will be removed. - -### Node - -Node object (interface `INode`) is created on top of the node data that is provided via -`orb.data.setup` or `orb.data.merge` functions. - -#### Node information - -- `id` - Readonly unique `id` provided on init (same as `.getData().id`) -- `data` - User provided information on `orb.data.setup` or `orb.data.merge` -- `style` - Style properties like color, border, size (check more on [Styling guide](./styles.md)). -- `position` - Node `x` and `y` coordinate generated before first render -- `state` - Node state which can be selected (`GraphObjectState.SELECTED`), hovered - (`GraphObjectState.HOVERED`), or none (`GraphObjectState.NONE` - default) - -#### Node getters functions - -- `getId()` - Alias for `.id` -- `getData()` - Returns the node data -- `getPosition()` - Returns the node position -- `getStyle()` - Returns the node style -- `getState()` - Returns the node state -- `getCenter()` - Alias for `.position` -- `getRadius()` - Alias for `.getStyle().size` -- `getBorderedRadius()` - Alias for `.getStyle().size + .getStyle().borderWidth` -- `getInEdges()` - Returns a list of inbound edges connected to the node -- `getOutEdges()` - Returns a list of outbound edges connected to the node -- `getEdges()` - Returns a list of all edges connected to the node, inbound and outbound -- `getAdjacentNodes()` - Returns a list of adjacent nodes -- `getLabel()` - Returns the node label -- `getColor()` - Returns the node color - -#### Node setter/patch functions - -All of the setter/patch functions for nodes are able to accept the raw data of the corresponding type or the callback that returns this data. - -- `setData()` - Replaces the node data with the provided data -- `patchData()` - Replaces the node data entries with the provided ones -- `setPosition()` - Sets the node current position -- `setStyle()` - Sets the node current style -- `patchStyle()` - Replaces the node style entries with the provided ones -- `setState()` - Sets the node current state - -`position`, `style` and `state` setters can accept optional `options` argument. It can be used to skip the rerender on data change which can be useful for performance while changing the data of many nodes. - -Check the example to get to know node handling better: - -```typescript -import { OrbView } from "@memgraph/orb"; - -const orb = new OrbView(container); - -const nodes: MyNode[] = [ - { id: 0, text: "Node A", myField: 12 }, - { id: 1, text: "Node B", myField: 77 }, -]; - -orb.data.setup({ nodes }); - -const node = orb.data.getNodeById(0); -console.log(node.getId()); // Output: 0 -console.log(node.getData()); // Output: { id: 0, text: "Node A", myField: 12 } - -// Set node color to red -node.patchStyle({ color: "#FF0000" }); -console.log(node.getStyle()); // Output: { ..., color: '#FF0000' } -``` - -### Edge - -Edge object (interface `IEdge`) is created on top of the edge data that is provided via -`orb.data.setup` or `orb.data.merge` functions. - -#### Edge information - -- `id` - Readonly unique `id` provided on init (same as `.getData().id`) -- `data` - User provided information on `orb.data.setup` or `orb.data.merge` -- `start` - Readonly `start` provided on init (same as `.getData().start`) -- `end` - Readonly `end` provided on init (same as `.getData().end`) -- `startNode` - Reference to the start node (`INode`) that edge connects -- `endNode` - Reference to the end node (`INode`) that edge connects -- `style` - Style properties like color, border, size (check more on [Styling guide](./styles.md)). -- `state` - Edge state which can be selected (`GraphObjectState.SELECTED`), hovered - (`GraphObjectState.HOVERED`), or none (`GraphObjectState.NONE` - default) -- `type` - Edge line type which can be: - - straight (`EdgeType.STRAIGHT`) - if there are 1x, 3x, 5x, ... edges connecting nodes A and B, - one edge will be a straight line edge. If there are multiple edges, other edges will be curved - not to overlap with each other - - curved (`EdgeType.CURVED`) - if there is more than one edge connecting nodes A and B, some - of those edges will be curved, so they do not overlap with each other - - loopback (`EdgeType.LOOPBACK) - connects a node to itself - -#### Edge getters function - -- `getId()` - Alias for `.id` -- `getData()` - Getter for edge data -- `getPosition()` - Getter for edge position -- `getStyle()` - Getter for edge style -- `getState()` - Getter for edge state -- `getCenter()` - Gets the center edge position calculated by edge type and connected node positions -- `getWidth()` - Alias for `.style.width` -- `isLoopback()` - Checks if edge is a loopback type: connects a node to itself. -- `isStraight()` - Checks if edge is a straight line edge -- `isCurved()` - Checks if edge is a curved line edge. - -#### Edge setters/patch functions - -All of the setter/patch functions for edges are able to accept the raw data of the corresponding type or the callback that returns this data. - -- `setData()` - Replaces the edge data with the provided data -- `patchData()` - Replaces the edge data entries with the provided ones -- `setStyle()` - Sets the edge current style -- `patchStyle()` - Replaces the edge style entries with the provided ones -- `setState()` - Sets the edge current state - -`style` and `state` setters can accept optional `options` argument. It can be used to skip the rerender on data change which can be useful for performance while changing the data of many edges. - -Check the example to get to know edge handling better: - -```typescript -import { OrbView } from "@memgraph/orb"; - -const orb = new OrbView(container); - -const nodes: MyNode[] = [ - { id: 0, text: "Node A", myField: 12 }, - { id: 1, text: "Node B", myField: 77 }, -]; - -const edges: MyEdge[] = [ - { id: 0, start: 0, end: 1, connects: "A -> B" }, - { id: 1, start: 0, end: 0, connects: "A -> A" }, -]; - -orb.data.setup({ nodes, edges }); - -const edge = orb.data.geEdgeById(0); -console.log(edge.getId()); // Output: 0 -console.log(edge.getData()); // Output: { id: 0, start: 0, end: 1, connects: 'A -> B' } -console.log(edge.startNode.getData()); // Output: { id: 0, text: "Node A", myField: 12 } -console.log(edge.endNode.getData()); // Output: { id: 1, text: "Node B", myField: 77 } - -// Set edge line color to red -edge.patchStyle({ color: "#FF0000" }); -console.log(edge.getStyle()); // Output: { ..., color: '#FF0000' } -``` - -## Merge nodes and edges - -Merge `orb.data.merge` is a handy function to add new nodes and edges or even update the existing -ones. An update of a node or edge will happen if a node or edge with the same unique `id` already -exists in the graph structure. Check the example below: - -```typescript -import { OrbView } from "@memgraph/orb"; - -const orb = new OrbView(container); - -const nodes: MyNode[] = [ - { id: 0, text: "Node A", myField: 12 }, - { id: 1, text: "Node B", myField: 77 }, -]; - -const edges: MyEdge[] = [ - { id: 0, start: 0, end: 1, connects: "A -> B" }, - { id: 1, start: 0, end: 0, connects: "A -> A" }, -]; - -orb.data.setup({ nodes, edges }); -console.log(orb.data.getNodeCount()); // Output: 3 -console.log(orb.data.getNodeById(1)); // Output: { id: 1, text: "Node B", myField: 77 } - -orb.data.merge({ - nodes: [ - // This will be a new node in the graph because node with id = 2 doesn't exist - { id: 2, text: "Node C", myField: 82 }, - // This will update the node with id = 1 because it already exists. `node.data` will be updated. - { id: 1, text: "Node D", myField: 82 }, - ], - edges: [ - // This will update the edge with id = 1 because it already exists. `edge.data` will be updated, - // but also, edge will disconnect from previous nodes and connect to the new ones (0 -> 2). - { id: 1, start: 0, end: 2, connects: "A -> C" }, - // This will be a new edge in the graph because edge with id = 2 doesn't exist - { id: 2, start: 2, end: 1, connects: "C -> B" }, - // This edge will be dismissed because node with id = 7 doesn't exist - { id: 3, start: 2, end: 8, connects: "C -> ?" }, - ], -}); -console.log(orb.data.getNodeCount()); // Output: 3 -console.log(orb.data.getNodeById(1)); // Output: { id: 1, text: "Node D", myField: 82 } -``` - -## Remove nodes and edges - -To remove nodes or edges from a graph, you just need the `id`. Removing a node will also -remove all inbound and outbound edges to that node. Removing an edge will just remove that edge. - -```typescript -import { OrbView } from "@memgraph/orb"; - -const orb = new OrbView(container); - -const nodes: MyNode[] = [ - { id: 0, text: "Node A" }, - { id: 1, text: "Node B" }, -]; - -const edges: MyEdge[] = [ - { id: 0, start: 0, end: 1, text: "A -> B" }, - { id: 1, start: 0, end: 0, text: "A -> A" }, -]; - -orb.data.setup({ nodes, edges }); - -// After the removal of node with id 0, both edges will be removed too because they are -// connected to the removed edge -orb.data.remove({ nodeIds: [0] }); -``` - -You can remove just nodes, edges, or both: - -```typescript -// Remove just one node -orb.data.remove({ nodeIds: [0] }); - -// Remove multiple nodes and one edge -orb.data.remove({ nodeIds: [0, 1, 2], edgeIds: [0] }); - -// Remove just edges -orb.data.remove({ edgeIds: [0, 1, 2] }); -``` - -If you need to remove everything, you can do it with `remove` or even with `setup`: - -```typescript -const nodeIds = orb.data.getNodes().map((node) => node.getId()); -// No need to get edges because if we remove all the nodes, all the edges will be removed too -orb.data.remove({ nodeIds: nodeIds }); - -// Or use just setup with empty nodes and edges: -orb.data.setup({ nodes: [], edges: [] }); -``` - -## Other functions - -There are only three main functions to change the graph structure: `setup`, `merge`, and `remove`. -But couple more functions could be useful to you: - -```typescript -// Returns the list of all nodes/edges in the graph -const nodes = orb.data.getNodes(); -const edges = orb.data.getEdges(); - -// Returns the total number of nodes/edges in the graph -const nodeCount = orb.data.getNodeCount(); -const edgeCount = orb.data.getEdgeCount(); - -// Returns specific node or edge by id. If node or edge doesn't exist, it will return undefined -const node = orb.data.getNodeById(0); -const edge = orb.data.getEdgeById(0); - -// Get nearest node/edge to the position (x, y). Useful with events such as mouse click to -// check if node should be considered clicked or not -const nearestNode = orb.data.getNearestNode({ x: 0, y: 0 }); -const nearestEdge = orb.data.getNearestEdge({ x: 0, y: 0 }); -``` diff --git a/docs/events.md b/docs/events.md deleted file mode 100644 index 67a84bb..0000000 --- a/docs/events.md +++ /dev/null @@ -1,482 +0,0 @@ -Handling events in Orb -=== - -In the following section, you can find a list of all supported events that Orb emits along -with an example of each event type with its event data. - -# Events - -Below you can find all the event types (names) that Orb supports that you can -subscribe to: - -```typescript -export enum OrbEventType { - // Renderer events for drawing on canvas - RENDER_START = 'render-start', - RENDER_END = 'render-end', - // Simulation (D3) events for setting up node positions - SIMULATION_START = 'simulation-start', - SIMULATION_STEP = 'simulation-step', - SIMULATION_END = 'simulation-end', - // Mouse events: click, hover, move - NODE_CLICK = 'node-click', - NODE_HOVER = 'node-hover', - EDGE_CLICK = 'edge-click', - EDGE_HOVER = 'edge-hover', - MOUSE_CLICK = 'mouse-click', - MOUSE_MOVE = 'mouse-move', - // Zoom or pan (translate) change - TRANSFORM = 'transform', - // Mouse node drag events - NODE_DRAG_START = 'node-drag-start', - NODE_DRAG = 'node-drag', - NODE_DRAG_END = 'node-drag-end', - NODE_RIGHT_CLICK = 'node-right-click', - EDGE_RIGHT_CLICK = 'edge-right-click', - MOUSE_RIGHT_CLICK = 'mouse-right-click', - // DBL click events - NODE_DOUBLE_CLICK = 'node-double-click', - EDGE_DOUBLE_CLICK = 'edge-double-click', - MOUSE_DOUBLE_CLICK = 'mouse-double-click', -} -``` - -Subscribe to the events via `orb.events` in one of the two ways: - -```typescript -import { OrbEventType } from '@memgraph/orb'; - -orb.events.on(OrbEventType.RENDER_START, () => { - console.log('Render started'); -}); - -// Or use enum value directly -orb.events.on('render-start', () => { - console.log('Render started'); -}); -``` - -# Event examples - -In the following sections, you can find event subscription examples and what kind of data -you can get from each event. - -## Rendering events - -### Event `OrbEventType.RENDER_START` - -Event is emitted on each render call before the renderer starts drawing the graph on canvas. - -```typescript -import { OrbEventType } from '@memgraph/orb'; - -orb.events.on(OrbEventType.RENDER_START, () => { - console.log('Render started'); -}); -``` - -Event data for `OrbEventType.RENDER_START` is undefined. - -### Event `OrbEventType.RENDER_END` - -Event is emitted on each render call after the renderer completes drawing the graph on canvas. - -```typescript -import { OrbEventType, IOrbEventRenderEnd } from '@memgraph/orb'; - -orb.events.on(OrbEventType.RENDER_END, (event: IOrbEventRenderEnd) => { - console.log(`Render ended in ${event.durationMs} ms`); -}); -``` - -Event data for `OrbEventType.RENDER_END` has the following properties: - -```typescript -interface IOrbEventRenderEnd { - durationMs: number; -} -``` - -## Simulation events - -Simulation is a process where a view uses `d3` simulator to calculate node positions if positions -are not defined. The simulation could take some time to position all the nodes which is the reason -why there are three simulation events you can subscribe to: start, step (progress), and end. - -### Event `OrbEventType.SIMULATION_START` - -Event `OrbEventType.SIMULATION_START` is emitted once the simulator starts setting up node positions. - -```typescript -import { OrbEventType } from '@memgraph/orb'; - -orb.events.on(OrbEventType.SIMULATION_START, () => { - console.log(`Simulation started`); -}); -``` - -Event data for `OrbEventType.SIMULATION_START` is undefined. - -### Event `OrbEventType.SIMULATION_STEP` - -Event `OrbEventType.SIMULATION_STEP` is emitted on each simulation step. `d3` simulator runs -node positioning in iterations where each iteration is one simulation step. - -```typescript -import { OrbEventType, IOrbEventSimulationStep } from '@memgraph/orb'; - -orb.events.on(OrbEventType.SIMULATION_STEP, (event: IOrbEventSimulationStep) => { - console.log(`Simulation progress: ${event.progress}`); - // If you want to see each step of the simulation, add render here - orb.view.render(); -}); -``` - -Event data for `OrbEventType.SIMULATION_STEP` has the following properties: - -```typescript -interface IOrbEventSimulationStep { - progress: number; -} -``` - -### Event `OrbEventType.SIMULATION_END` - -Event `OrbEventType.SIMULATION_END` is emitted once the simulator ends with the final node positions. - -```typescript -import { OrbEventType, IOrbEventSimulationEnd } from '@memgraph/orb'; - -orb.events.on(OrbEventType.SIMULATION_END, (event: IOrbEventSimulationEnd) => { - console.log(`Simulation ended in ${event.durationMs} ms`); -}); -``` - -Event data for `OrbEventType.SIMULATION_END` has the following properties: - -```typescript -interface IOrbEventSimulationEnd { - durationMs: number; -} -``` - -## Mouse events - -### Event `OrbEventType.NODE_CLICK` - -Event is emitted on mouse click that selects the node. The event `OrbEventType.MOUSE_CLICK` will also be -triggered. - -```typescript -import { OrbEventType, IOrbEventNodeClick } from '@memgraph/orb'; - -orb.events.on(OrbEventType.NODE_CLICK, (event: IOrbEventNodeClick) => { - console.log(`Node clicked`, event.node); -}); -``` - -Event data for `OrbEventType.NODE_CLICK` has the following properties: - -```typescript -interface IOrbEventNodeClick { - node: INode; - event: PointerEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. - -### Event `OrbEventType.NODE_HOVER` - -Event is emitted on mouse move that hovers the node. The event `OrbEventType.MOUSE_MOVE` will also be -triggered. - -```typescript -import { OrbEventType, IOrbEventNodeHover } from '@memgraph/orb'; - -orb.events.on(OrbEventType.NODE_HOVER, (event: IOrbEventNodeHover) => { - console.log(`Node hovered`, event.node); -}); -``` - -Event data for `OrbEventType.NODE_HOVER` has the following properties: - -```typescript -interface IOrbEventNodeHover { - node: INode; - event: MouseEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. - -### Event `OrbEventType.EDGE_CLICK` - -Event is emitted on mouse click that selects the edge. The event `OrbEventType.MOUSE_CLICK` will also be -triggered. - -```typescript -import { OrbEventType, IOrbEventEdgeClick } from '@memgraph/orb'; - -orb.events.on(OrbEventType.EDGE_CLICK, (event: IOrbEventEdgeClick) => { - console.log(`Edge clicked`, event.edge); -}); -``` - -Event data for `OrbEventType.EDGE_CLICK` has the following properties: - -```typescript -interface IOrbEventEdgeClick { - edge: IEdge; - event: PointerEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. - -### Event `OrbEventType.EDGE_HOVER` _(not supported currently)_ - -Event is emitted on mouse move that hovers the edge. The event `OrbEventType.MOUSE_MOVE` will also be -triggered. - -> Note: The following event is not supported because of the performance issue to calculate -> the distance to the closest edge to hover it. - -```typescript -import { OrbEventType, IOrbEventEdgeHover } from '@memgraph/orb'; - -orb.events.on(OrbEventType.EDGE_HOVER, (event: IOrbEventEdgeHover) => { - console.log(`Edge hovered`, event.node); -}); -``` - -Event data for `OrbEventType.EDGE_HOVER` has the following properties: - -```typescript -interface IOrbEventEdgeHover { - edge: IEdge; - event: MouseEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. - -### Event `OrbEventType.MOUSE_CLICK` - -The event is emitted on a mouse click within the canvas. If there is a graph object (node or -edge) at the mouse click position, `OrbEventType.NODE_CLICK` and `OrbEventType.EDGE_CLICK` events -will be triggered too. - -```typescript -import { OrbEventType, IOrbEventMouseClick } from '@memgraph/orb'; - -orb.events.on(OrbEventType.MOUSE_CLICK, (event: IOrbEventMouseClick) => { - console.log(`Mouse clicked`, event); -}); -``` - -Event data for `OrbEventType.MOUSE_CLICK` has the following properties: - -```typescript -interface IOrbEventMouseClick { - subject?: INode | IEdge; - event: PointerEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. Property `subject` will be filled with either `INode` -or `IEdge` if the mouse click position is on top of the node or edge. The same objects are received in -the events `OrbEventType.NODE_CLICK` and `OrbEventType.EDGE_CLICK`. - -If you need to check if `subject` is a `INode` or `IEdge` use type check functions from orb: - -```typescript -import { isNode, isEdge, OrbEventType, IOrbEventMouseClick } from '@memgraph/orb'; - -orb.events.on(OrbEventType.MOUSE_CLICK, (event: IOrbEventMouseClick) => { - if (event.subject && isNode(event.subject)) { - console.log(`Mouse clicked on top of the node`, event.subject); - } - if (event.subject && isEdge(event.subject)) { - console.log(`Mouse clicked on top of the edge`, event.subject); - } -}); -``` - -### Event `OrbEventType.MOUSE_MOVE` - -Event is emitted on any mouse movement within the canvas. If there is a graph object (node or -edge) at the mouse position, `OrbEventType.NODE_HOVER` and `OrbEventType.EDGE_HOVER` events will -be triggered too. - -```typescript -import { OrbEventType, IOrbEventMouseMove } from '@memgraph/orb'; - -orb.events.on(OrbEventType.MOUSE_MOVE, (event: IOrbEventMouseMove) => { - console.log(`Mouse moved`, event); -}); -``` - -Event data for `OrbEventType.MOUSE_MOVE` has the following properties: - -```typescript -interface IOrbEventMouseMove { - subject?: INode | IEdge; - event: MouseEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. Property `subject` will be filled with either `INode` -or `IEdge` if the mouse position is on top of the node or edge. The same objects are received in the -events `OrbEventType.NODE_CLICK` and `OrbEventType.EDGE_CLICK`. - -If you need to check if `subject` is a `INode` or `IEdge` use type check functions from orb: - -```typescript -import { isNode, isEdge, OrbEventType, IOrbEventMouseMove } from '@memgraph/orb'; - -orb.events.on(OrbEventType.MOUSE_MOVE, (event: IOrbEventMouseMove) => { - if (event.subject && isNode(event.subject)) { - console.log(`Mouse moved over the node`, event.subject); - } - if (event.subject && isEdge(event.subject)) { - console.log(`Mouse moved over the edge`, event.subject); - } -}); -``` - -## Zoom and pan events - -### Event `OrbEventType.TRANSFORM` - -Event is emitted on any zoom or pan event. - -```typescript -import { OrbEventType, IOrbEventTransform } from '@memgraph/orb'; - -orb.events.on(OrbEventType.TRANSFORM, (event: IOrbEventTransform) => { - console.log(`Zoom or pan event`, event); -}); -``` - -Event data for `OrbEventType.TRANSFORM` has the following properties: - -```typescript -interface IOrbEventTransform { - transform: { x: number; y: number, k: number }; -} -``` - -Properties `x` and `y` are translation coordinates while `k` stands for zoom scale. If `OrbView` -is used, `transform` data is actually same as `ZoomTransform` type from `d3` library. - -## Node dragging events - -Node dragging events are events that are emitted on node dragging which starts with a mouse click and -hold, mouse movement, and ends with mouse click release. - -> Note: Node dragging events might not be enabled on some views, e.g. `OrbMapView` which currently -> has a fixed position for each node by `latitude` and `longitude` values. - -### Event `OrbEventType.NODE_DRAG_START` - -The event is emitted when node drag starts. If a user just clicks on a node, four events will be -triggered: `OrbEventType.NODE_DRAG_START`, `OrbEventType.NODE_DRAG_END`, `OrbEventType.NODE_CLICK`, -and `OrbEventType.MOUSE_CLICK`. If you want to listen just for drag then combine `OrbEventType.NODE_DRAG` -with `OrbEventType.NODE_DRAG_(START|END)`. - -```typescript -import { OrbEventType, IOrbEventNodeDragStart } from '@memgraph/orb'; - -orb.events.on(OrbEventType.NODE_DRAG_START, (event: IOrbEventNodeDragStart) => { - console.log(`Node drag started`, event); -}); -``` - -Event data for `OrbEventType.NODE_DRAG_START` has the following properties: - -```typescript -interface IOrbEventNodeDragStart { - node: INode; - event: MouseEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. - -### Event `OrbEventType.NODE_DRAG` - -Event is emitted on every mouse movement which is dragging a node with it. Event `OrbEventType.MOUSE_MOVE` -will also be triggered. - -```typescript -import { OrbEventType, IOrbEventNodeDrag } from '@memgraph/orb'; - -orb.events.on(OrbEventType.NODE_DRAG, (event: IOrbEventNodeDrag) => { - console.log(`Node dragged`, event); -}); -``` - -Event data for `OrbEventType.NODE_DRAG` has the following properties: - -```typescript -interface IOrbEventNodeDrag { - node: INode; - event: MouseEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. - -### Event `OrbEventType.NODE_DRAG_END` - -The event is emitted when node drag ends. If a user just clicks on a node, four events will -be triggered: `OrbEventType.NODE_DRAG_START`, `OrbEventType.NODE_DRAG_END`, `OrbEventType.NODE_CLICK`, -and `OrbEventType.MOUSE_CLICK`. If you want to listen just for drag then combine `OrbEventType.NODE_DRAG` -with `OrbEventType.NODE_DRAG_(START|END)`. - -```typescript -import { OrbEventType, IOrbEventNodeDragEnd } from '@memgraph/orb'; - -orb.events.on(OrbEventType.NODE_DRAG_END, (event: IOrbEventNodeDragEnd) => { - console.log(`Node drag ended`, event); -}); -``` - -Event data for `OrbEventType.NODE_DRAG_END` has the following properties: - -```typescript -interface IOrbEventNodeDragEnd { - node: INode; - event: MouseEvent; - localPoint: { x: number; y: number }; - globalPoint: { x: number; y: number }; -} -``` - -Property `localPoint` contains the coordinates in the system of node positions, while `globalPoint` -is the original mouse coordinate on the canvas. diff --git a/docs/site/.gitignore b/docs/site/.gitignore new file mode 100644 index 0000000..2c1fa99 --- /dev/null +++ b/docs/site/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.vitepress/dist/ +.vitepress/cache/ diff --git a/docs/site/.vitepress/config.ts b/docs/site/.vitepress/config.ts new file mode 100644 index 0000000..b868261 --- /dev/null +++ b/docs/site/.vitepress/config.ts @@ -0,0 +1,90 @@ +import { defineConfig } from 'vitepress'; + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + // Served from https://memgraph.github.io/orb/ on GitHub Pages. + base: '/orb/', + lang: 'en-US', + title: 'Orb', + description: 'A graph visualization library by Memgraph.', + cleanUrls: true, + + // Every page has real content now; fail the build on broken internal links. + ignoreDeadLinks: false, + + head: [ + ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }], + ['link', { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }], + [ + 'link', + { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500;600;700;800&family=Ubuntu+Mono:wght@400;700&display=swap', + }, + ], + ], + + themeConfig: { + nav: [ + { text: 'Guide', link: '/introduction/getting-started', activeMatch: '/(introduction|concepts|layouts|rendering|views)/' }, + { text: 'Reference', link: '/reference/api', activeMatch: '/reference/' }, + { text: 'npm', link: 'https://www.npmjs.com/package/@memgraph/orb' }, + ], + + sidebar: [ + { + text: 'Introduction', + items: [ + { text: 'What is Orb', link: '/introduction/what-is-orb' }, + { text: 'Getting started', link: '/introduction/getting-started' }, + ], + }, + { + text: 'Core concepts', + items: [ + { text: 'Graph data', link: '/concepts/data' }, + { text: 'Styling', link: '/concepts/styling' }, + { text: 'Events', link: '/concepts/events' }, + { text: 'Selection & interaction', link: '/concepts/interaction' }, + ], + }, + { + text: 'Layouts', + items: [ + { text: 'Overview', link: '/layouts/overview' }, + { text: 'Force layout', link: '/layouts/force' }, + { text: 'GPU layout', link: '/layouts/gpu' }, + { text: 'Static layouts', link: '/layouts/static' }, + ], + }, + { + text: 'Rendering', + items: [ + { text: 'Canvas vs WebGL', link: '/rendering/renderers' }, + { text: 'Performance', link: '/rendering/performance' }, + { text: 'SVG export', link: '/rendering/svg-export' }, + ], + }, + { + text: 'Views', + items: [ + { text: 'Default view', link: '/views/default' }, + { text: 'Map view', link: '/views/map' }, + ], + }, + { + text: 'Reference', + items: [{ text: 'API reference', link: '/reference/api' }], + }, + ], + + socialLinks: [{ icon: 'github', link: 'https://github.com/memgraph/orb' }], + + search: { provider: 'local' }, + + footer: { + message: 'Released under the Apache-2.0 License.', + copyright: 'Copyright © 2016-present Memgraph Ltd.', + }, + }, +}); diff --git a/docs/site/.vitepress/theme/Layout.vue b/docs/site/.vitepress/theme/Layout.vue new file mode 100644 index 0000000..336487c --- /dev/null +++ b/docs/site/.vitepress/theme/Layout.vue @@ -0,0 +1,15 @@ + + + diff --git a/docs/site/.vitepress/theme/components/ExampleGallery.vue b/docs/site/.vitepress/theme/components/ExampleGallery.vue new file mode 100644 index 0000000..5606084 --- /dev/null +++ b/docs/site/.vitepress/theme/components/ExampleGallery.vue @@ -0,0 +1,149 @@ + + +