Integrate using the TypeScript driver
It is possible to control Gephi Lite in a tab or an iframe from another web page. This feature uses the browser Broadcast Channel API.
The main constraint of the BroadcastChannel API is that both the controlling web page and the controlled Gephi Lite
must be hosted on the same domain. Please read the Deploying Gephi Lite documentation page to
know more on how to host Gephi Lite on your servers.
To ease communicating with Gephi Lite, you can use the
@gephi/gephi-lite-broadcast NPM project from your
TypeScript or JavaScript codebase. At the moment, this driver supports:
- Read or import a Graphology graph
- Read, set or merge the
SerializedGraphDatasetobject (that fully describes the dataset) - Read, set or merge the
AppearanceStateobject (that describes everything from the Appearance menus in Gephi Lite) - Read or set the
FiltersStateobject (that describes the filters) - Read or set the selection (see Selection)
- Listen to events from Gephi Lite (see Events)
Example
The easiest way to dive into how to use the driver, is to look at how Gephi Lite itself uses it! Indeed, Gephi Lite
offers users to clone their current workspace in a new tab, using the @gephi/gephi-lite-broadcast package. This allows
duplicating a graph to compare two different appearance setups, for instance - or also "saving" a state before applying
some destructive modifications...
So, let's see how Gephi Lite uses the driver:
// This is the driver class, that allows all that:
import { GephiLiteDriver } from "@gephi/gephi-lite-broadcast";
// These are some internal Gephi Lite typings:
import {
AppearanceState,
FiltersState,
GraphDataset,
} from "@gephi/gephi-lite-sdk";
export async function openInNewTab({
dataset,
appearance,
filters,
}: {
dataset: GraphDataset;
appearance: AppearanceState;
filters: FiltersState;
}) {
// 1. Instantiate GephiLiteDriver (no name is given, so a random UUID will be
// used instead):
const driver = new GephiLiteDriver();
// 2. Open a new Gephi Lite in a new tab, and wait for it
await driver.openGephiLite({ baseUrl: location.pathname });
// 3. Set appearance and filters, then graph data, in the new Gephi Lite
// instance:
await Promise.all([driver.setAppearance(appearance), driver.setFilters(filters)]);
await driver.setGraphDataset(dataset);
// 4. Now that everything went fine, just destroy the driver (and close the
// Broadcast Channel listener on this side):
driver.destroy();
}
The code has been slightly redacted from its original version:
- Some code related to the internal logic of Gephi Lite has been removed for simplicity
- Comments have been added to clarify what it does
Then, this function is called in two different parts:
- For the
"Duplicate in a new tab"feature - For the Louvain edges ambiguity representation
Selection
Since version 1.1, the driver can read and set the selection in Gephi Lite. The selection is described as a
SerializedSelectionState object:
interface SerializedSelectionState {
nodeIds: string[];
edgeIds: string[];
}
// Read the current selection:
const { nodeIds, edgeIds } = await driver.getSelection();
// Select some nodes:
await driver.setSelection({ nodeIds: ["n1", "n2"], edgeIds: [] });
// Clear the selection:
await driver.setSelection({ nodeIds: [], edgeIds: [] });
Gephi Lite can only select nodes or edges at a time, not both:
getSelectionalways returns one empty array- If
setSelectionreceives both node and edge IDs, the node IDs win and the edge IDs are ignored
IDs that don't exist in the graph are ignored.
Events
The driver is an event emitter. Here are the events Gephi Lite sends:
newInstance: a Gephi Lite instance has opened on the driver's channel (openGephiLiteuses it to know when the new instance is ready)selectionUpdate: the selection has changed (from the user, fromsetSelection, or because selected items were removed from the graph). The listener receives the newSerializedSelectionState.
driver.on("selectionUpdate", ({ nodeIds, edgeIds }) => {
console.log("Selected nodes:", nodeIds);
console.log("Selected edges:", edgeIds);
});
selectionUpdate is only sent when the selection actually changes. So, calling setSelection with the current
selection (to echo back a selection you just received, for instance) sends no event, and does not create a loop.
How it works under the hood
This section is quite advanced, and is not necessary to use the driver. It's mostly here so that future maintainers can get more insights on what's going on in the codebase.
The BroadcastChannel API
So, basically, the BroadcastChannel allows for browser pages to broadcast messages on a "channel" (each channel being
identified with a given string), that every other browser contexts opened in the same browser and on the same domain at
the time can receive.
What Gephi Lite does
When Gephi Lite starts, it checks if it has a broadcast query param (the channel name). If it has, it opens a
BroadcastChannel on that channel name, and listens to all messages. It will react to
GephiLiteMethodBroadcastMessage
messages, that basically contain:
- a method name
- arguments for that method
- an optional identifier (that will be used for responses)
When Gephi Lite receives such a message, it will execute the asked method, and, if an identifier is given, will
broadcast the return of the method on the channel, in a
ReplyMessage.
Gephi Lite also broadcasts events on the channel, as
EventBroadcastMessage
messages, containing the event name and its data. The driver re-emits them, so that you can listen to them with
driver.on(...).
What the driver does
The @gephi/gephi-lite-broadcast package is mostly some
sugar to avoid having to write the messages by hand. Also, it waits for a reply from the related Gephi Lite instance
before resolving some promise, which helps to know whether things went well, basically.
So, when some method from the driver is called, for instance const graph = await driver.getGraph();, here is what
happens:
- The driver calls
its internal method:
this.callMethod<GetGraphMethod>("getGraph")and returns a new result promise - It creates a unique
messageIDand emits aMethodBroadcastMessage, usingthis.channel.postMessage({ ... }) - It then waits for a
MethodReplyMessagemessage from the Gephi Lite instance - If the reply comes, it resolves the result promise with the reply's payload
- If it doesn't (after some
timeout), it rejects the result promise with a timeout error
Implementing a new method for the driver
There are still some missing methods from the Gephi Lite driver, unfortunately. Here is a quick guide (mostly for maintainers) on how to implement a new method:
- A new "Method type", extending
BaseMethodmust be added inbroadcast/src/types.ts, and added to theGephiLiteMethodandGephiLiteMethodBroadcastMessageunion types. This will determine the arguments and response types of the new method. - A new "shortcut method" must be added directly to the
GephiLiteDriverclass. This will help TypeScript users discover this new method. It also can deal with serializing/deserializing inputs/outputs. - Finally, the actual code that tells Gephi Lite how it should handle these events must be added in the
BROADCAST_METHODScollection, under theBaseMethod's name. Hopefully, at this point, the typings will ensure the inputs and outputs are properly handled.
Et voilà! That's all it takes to implement a new Gephi Lite driver method.