Custom JavaScript Controls
==========================
The Python and R bindings cover the common options, but every figure
they produce is a live ``LightGraph`` instance with a full JavaScript
API — you can wire your own buttons, dashboards, or page logic to it.
This page shows how to reach the instance from each host and what you
can do with it.
The instance API
----------------
Whichever way a graph was created, its container element carries the
instance as ``container.lightgraph`` (in hand-written JavaScript you
also get it back from ``new lightGraph.LightGraph(...)``). The instance
offers:
* **Methods** — ``setData({nodes, edges})``, ``updateConfig(partial)``,
``zoomToFit(padding?)``, ``getSelection()``, ``selectNodes(ids)``,
``egoFilter(nodeId, depth?)`` / ``clearEgoFilter()`` /
``getVisibleNodes()``, ``settle(ticks?)``, ``resize()``,
``destroy()``.
* **Events** — ``on(event, cb)`` / ``off(event, cb)`` for
``nodeClick`` (``{node}``), ``selectionChange`` (array of selected
nodes), ``dataLoad``, ``egoFilter``, and ``destroy``.
Live example
------------
The toolbar above this graph is plain HTML — three buttons and a status
label — talking to the instance. Click a node or use the buttons:
.. raw:: html
The wiring is just event handlers calling instance methods:
.. code-block:: javascript
var graph = new lightGraph.LightGraph(document.getElementById('graph'), {
nodes: nodes, edges: edges, config: config
});
var status = document.getElementById('status');
document.getElementById('btn-starks').onclick = function () {
graph.clearEgoFilter();
graph.selectNodes(['Eddard', 'Catelyn', 'Robb', 'Sansa',
'Arya', 'Bran', 'Rickon', 'Jon']);
};
document.getElementById('btn-tyrion').onclick = function () {
graph.egoFilter('Tyrion', 2);
};
document.getElementById('btn-reset').onclick = function () {
graph.clearEgoFilter();
graph.selectNodes([]);
graph.zoomToFit();
};
graph.on('nodeClick', function (e) {
status.textContent = 'Clicked ' + e.node.id;
});
graph.on('selectionChange', function (selected) {
if (selected.length) status.textContent = selected.length + ' selected';
});
graph.on('egoFilter', function () {
status.textContent = graph.getVisibleNodes().length + ' nodes visible';
});
(The full page is generated by ``docs/tools/gen_example_embeds.py`` if
you want to copy it as a starting point.)
From R: ``htmlwidgets::onRender``
---------------------------------
R's htmlwidgets framework has a standard hook for attaching JavaScript
to a rendered widget. The hook receives the widget's DOM element, so
the instance is one property away:
.. code-block:: r
library(lightgraph)
library(htmlwidgets)
data(got)
w <- lightgraph(edges = got, node_metric = lg_pagerank(got),
edge_weight_to_width = TRUE)
onRender(w, "
function(el, x) {
var graph = el.lightgraph;
graph.on('nodeClick', function (e) {
console.log('clicked', e.node.id);
});
graph.egoFilter('Tyrion', 2);
}
")
This works in the RStudio viewer, in R Markdown documents, and in Shiny
(wrap the widget in ``renderLightgraph()`` as usual — the ``onRender``
hook travels with it, and ``nodeClick`` handlers can call
``Shiny.setInputValue()`` to send selections back to the server).
From Python: extend the generated page
--------------------------------------
``net_vis()`` returns a :class:`~lightgraph.NetworkVisualization` whose
``.html`` property is a complete, self-contained page. Append your own
script before saving it. One detail: the page initializes the graph
asynchronously, so poll until the instance appears on the container
(id ``lightGraph``):
.. code-block:: python
from lightgraph import net_vis, datasets, pagerank
edges = datasets.got()
vis = net_vis(edges=edges, node_metric=pagerank(edges))
controls = """
"""
html = vis.html.replace('