Skip to content

Instantly share code, notes, and snippets.

@Hugoberry
Last active December 14, 2023 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hugoberry/9423b215bf16f484a18146a11dcb7d2b to your computer and use it in GitHub Desktop.
Save Hugoberry/9423b215bf16f484a18146a11dcb7d2b to your computer and use it in GitHub Desktop.
<head>
<script type="text/javascript">
mxBasePath = 'https://jgraph.github.io/mxgraph/javascript/src';
</script>
<script type="text/javascript" src="https://jgraph.github.io/mxgraph/javascript/src/js/mxClient.js"></script>
<script type="text/javascript">
function wrangle(data) {
var charactersMap = {};
return data.scenes.map(function(scene) {
return {
characters: scene.map(function(id) {
return characterById(id);
}).filter(function(d) {
return (d);
})
};
});
// Helper to get characters by ID from the raw data
function characterById(id) {
charactersMap = charactersMap || {};
charactersMap[id] = charactersMap[id] || data.characters.find(function(character) {
return character.id === id;
});
return charactersMap[id];
}
};
function main(container) {
const scenes = wrangle(data);
const sceneWidth = 14;
const width = scenes.length * sceneWidth * 4;
const height = 300;
var narrative = d3.layout.narrative()
.scenes(scenes)
.size([width, height])
.pathSpace(10)
.groupMargin(20)
.labelSize([110, 15])
.scenePadding([5, sceneWidth / 2, 5, sceneWidth / 2])
.labelPosition('left')
.layout();
mxEvent.disableContextMenu(container);
const graph = new mxGraph(container);
const model = graph.getModel();
// Disables basic selection and cell handling
graph.setEnabled(false);
graph.setConnectable(false);
graph.setCellsResizable(false);
const parent = graph.getDefaultParent();
var style =[];
style[mxConstants.STYLE_EDGE] = mxEdgeStyle.SegmentConnector;
style[mxConstants.STYLE_ENDARROW] = mxConstants.NONE;
style[mxConstants.STYLE_CURVED] = 1;
graph.getStylesheet().putDefaultEdgeStyle(style);
// Adds cells to the model in a single step
model.beginUpdate();
try {
// Dictionary to hold references to all appearance vertices
const appearanceVertices = {};
const introVertices = {};
// Draw scenes as rectangles (clusters)
const scenes = narrative.scenes();
scenes.forEach((scene, sceneIndex) => {
const cluster = graph.insertVertex(
parent, null, '', Math.round(scene.x) + 0.5, Math.round(scene.y) + 0.5, sceneWidth, scene.height,
'rounded=1;arcSize=30;');
cluster.setConnectable(false);
//cluster.setCellsResizable(false);
// Draw appearances as circles inside each cluster scene
scene.appearances.forEach((appearance, appearanceIndex) => {
const characterId = appearance.character.id;
const appearanceVertex = graph.insertVertex(
cluster, null, '', appearance.x - 2, appearance.y, 4, 4,
'shape=ellipse;fillColor=black;strokeColor=black;'
);
// Add this appearance to the dictionary with scene and character as the key
if (!appearanceVertices[characterId]) {
appearanceVertices[characterId] = {};
}
appearanceVertices[characterId][scene.start] = appearanceVertex;
});
});
// Function to get the vertex from appearanceVertices or introVertices
function getVertex(characterId, sceneStart, isSource) {
return isSource && sceneStart == null ?
introVertices[characterId] :
appearanceVertices[characterId] && appearanceVertices[characterId][sceneStart];
};
narrative.introductions().forEach(function(d) {
const x = Math.round(d.x);
const y = Math.round(d.y);
const label = d.character.name;
// Create a vertex for the introduction node
const intro = graph.insertVertex(parent, null, label, x, y, '', '', 'align=right');
introVertices[d.character.id] = intro;
});
// Draw links between the character appearances
const links = narrative.links();
links.forEach((link) => {
const sourceCharacterId = link.source.character.id;
const targetCharacterId = link.target.character.id;
const sourceSceneStart = link.source.scene ? link.source.scene.start : null;
const targetSceneStart = link.target.scene ? link.target.scene.start : null;
const sourceVertex = getVertex(sourceCharacterId, sourceSceneStart, true);
const targetVertex = getVertex(targetCharacterId, targetSceneStart, false);
if (sourceVertex && targetVertex) {
graph.insertEdge(parent, null, '', sourceVertex, targetVertex,'curved=1;endArrow=None');
}
});
} finally {
model.endUpdate();
}
var encoder = new mxCodec();
var result = encoder.encode(graph.getModel());
var xml = mxUtils.getXml(result);
console.log(xml);
};
</script>
</head>
<body onload="main(document.getElementById('graphContainer'))">
<div id="graphContainer" style="position:relative;overflow:hidden;width:100%;height:100%;cursor:default;">
</div>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment