diff --git a/people/static/js/network.js b/people/static/js/network.js
new file mode 100644
index 0000000..1ab6b44
--- /dev/null
+++ b/people/static/js/network.js
@@ -0,0 +1,112 @@
+
+// Global reference to Cytoscape graph - needed for `save_image`
+var cy;
+
+var network_style = [
+ {
+ selector: 'node[name]',
+ style: {
+ label: 'data(name)',
+ 'text-halign': 'center',
+ 'text-valign': 'center',
+ 'font-size': 8,
+ 'background-color': function (ele) {
+ switch (ele.data('kind')) {
+ case 'person':
+ return '#0099cc'
+ default:
+ return '#669933'
+ }
+ },
+ 'shape': function (ele) {
+ switch (ele.data('kind')) {
+ case 'person':
+ return 'ellipse'
+ default:
+ return 'rectangle'
+ }
+ }
+ }
+ },
+ {
+ selector: 'edge',
+ style: {
+ 'mid-target-arrow-shape': 'triangle',
+ 'curve-style': 'straight',
+ 'width': 1,
+ }
+ }
+]
+
+/**
+ * Save the network as an image using the browser's normal file download flow.
+ */
+function save_image() {
+ saveAs(cy.png(), 'graph.png');
+}
+
+/**
+ * Populate a Cytoscape network from :class:`Person` and :class:`Relationship` JSON embedded in page.
+ */
+function get_network() {
+ // Initialise Cytoscape graph
+ // See https://js.cytoscape.org/ for documentation
+ cy = cytoscape({
+ container: document.getElementById('cy'),
+ style: network_style
+ });
+
+ // Load people and add to graph
+ var person_set = JSON.parse(document.getElementById('person-set-data').textContent);
+
+ for (var person of person_set) {
+ cy.add({
+ group: 'nodes',
+ data: {
+ id: 'person-' + person.pk.toString(),
+ name: person.name,
+ kind: 'person'
+ }
+ })
+ }
+
+ // Load organisations and add to graph
+ var organisation_set = JSON.parse(document.getElementById('organisation-set-data').textContent);
+
+ for (var item of organisation_set) {
+ cy.add({
+ group: 'nodes',
+ data: {
+ id: 'organisation-' + item.pk.toString(),
+ name: item.name,
+ kind: 'organisation'
+ }
+ })
+ }
+
+ // Load relationships and add to graph
+ var relationship_set = JSON.parse(document.getElementById('relationship-set-data').textContent);
+
+ for (var relationship of relationship_set) {
+ cy.add({
+ group: 'edges',
+ data: {
+ id: 'relationship-' + relationship.pk.toString(),
+ source: 'person-' + relationship.source.pk.toString(),
+ target: 'person-' + relationship.target.pk.toString()
+ }
+ })
+ }
+
+ // Optimise graph layout
+ var layout = cy.layout({
+ name: 'cose',
+ randomize: true,
+ animate: false,
+ idealEdgeLength: function (edge) { return 64; }
+ });
+
+ layout.run();
+}
+
+$(window).on('load', get_network());
diff --git a/people/templates/people/network.html b/people/templates/people/network.html
index 40f664e..9aeced5 100644
--- a/people/templates/people/network.html
+++ b/people/templates/people/network.html
@@ -67,100 +67,6 @@
integrity="sha512-Qlv6VSKh1gDKGoJbnyA5RMXYcvnpIqhO++MhIM2fStMcGT9i2T//tSwYFlcyoRRDcDZ+TYHpH8azBBCyhpSeqw=="
crossorigin="anonymous">
-
+ {% load staticfiles %}
+
{% endblock %}
\ No newline at end of file