Skip to content

Commit

Permalink
support node shape
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed May 19, 2020
1 parent 699c6bf commit 4d905dc
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 33 deletions.
3 changes: 2 additions & 1 deletion samples/data/labels.dot
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
digraph {
node1[label="Some Complicated Label"];
label = "The foo, the bar and the baz";
node1[label="Some Complicated Label",color=blue,fillcolor=orange];
node1 -> node2[label="An Edge",color=red];
node2 -> node3;
}
11 changes: 11 additions & 0 deletions samples/data/styles.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
digraph D {

A [shape=diamond]
B [shape=box]
C [shape=circle]

A -> B [style=dashed, color=grey]
A -> C [color="black:invis:black"]
A -> D [penwidth=5, arrowhead=none]

}
13 changes: 11 additions & 2 deletions samples/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@
</div>
<script>
// data from https://graphs.grevian.org/example
fetch('./data/full_digraph.dot')
fetch('./data/styles.dot')
.then((r) => r.text())
.then((data) => {
new Chart(document.getElementById('canvas').getContext('2d'), {
type: 'forceDirectedGraph',
data: ChartGraphsDotParser.parse(data),
options: {
elements: {
point: {
radius: 10,
hoverRadius: 12,
},
line: {
borderColor: 'black',
},
},
legend: {
display: false,
display: true,
},
},
});
Expand Down
131 changes: 101 additions & 30 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,131 @@
import parseAst from 'dotparser';

function parseGraph(ast, options) {
function parseGraph(ast) {
const graph = {};
const labels = [];
const nodes = [];
const nodeSet = new Map();
const edges = [];

const addNode = (node) => {
const addNode = (node, attrs = {}) => {
if (nodeSet.has(node)) {
return nodeSet.get(node);
}
const index = labels.length;
nodeSet.set(node, index);
labels.push(node);
nodes.push({
id: node,
});
labels.push(attrs.label || node);
nodes.push(
Object.assign(
{
id: node,
},
attrs
)
);
return index;
};

const edges = ast.children
const copyAttr = (attr_list, target, name, parser = String) => {
const attr = attr_list.find((d) => d.id === name);
if (attr) {
target[name] = parser(attr.eq);
}
};

ast.children
.filter((child) => child.type === 'attr_stmt' && child.target === 'graph')
.forEach((attr) => {
copyAttr(attr.attr_list, graph, 'label');
});

const shapes = {
diamond: 'rectRot',
box: 'rect',
circle: 'circle',
};
ast.children
.filter((child) => child.type === 'node_stmt')
.forEach((node) => {
const r = {};
copyAttr(node.attr_list, r, 'label');
copyAttr(node.attr_list, r, 'color');
copyAttr(node.attr_list, r, 'fillcolor');
copyAttr(node.attr_list, r, 'shape', (v) => shapes[v] || 'circle');
addNode(node.node_id.id, r);
});
ast.children
.filter((child) => child.type === 'edge_stmt')
.map((edge) => {
const nodeA = addNode(edge.edge_list[0].id);
const nodeB = addNode(edge.edge_list[1].id);
const r = {
source: nodeA,
target: nodeB,
};
const label = edge.attr_list.find((d) => d.id === 'label');
if (label) {
r.label = label.eq;
}
const weight = edge.attr_list.find((d) => d.id === 'weight');
if (weight) {
r.weight = Number.parseFloat(weight.eq);
}
return r;
.forEach((edge) => {
const r = {};
copyAttr(edge.attr_list, r, 'label');
copyAttr(edge.attr_list, r, 'color');
copyAttr(edge.attr_list, r, 'style');
copyAttr(edge.attr_list, r, 'weight', Number.parseFloat);
copyAttr(edge.attr_list, r, 'penwidth', Number.parseFloat);

let source = null;
edge.edge_list.forEach((edge, i) => {
const target = addNode(edge.id);
if (i > 0) {
edges.push(
Object.assign({}, r, {
source,
target,
})
);
}
source = target;
});
});

const style = {};
const createNodeStyle = (attr, target = attr) => {
if (nodes.some((n) => n[attr] != null)) {
style[target] = (ctx) => {
if (ctx.dataIndex >= 0) {
const item = ctx.dataset.data[ctx.dataIndex];
return item ? item[attr] : undefined;
}
};
}
};
const createEdgeStyle = (attr, target = attr) => {
if (edges.some((n) => n[attr] != null)) {
style[target] = (ctx) => {
if (ctx.dataIndex >= 0) {
const item = ctx.dataset.edges[ctx.dataIndex];
return item ? item[attr] : undefined;
}
};
}
};
createNodeStyle('fillcolor', 'pointBackgroundColor');
createNodeStyle('color', 'pointBorderColor');
createNodeStyle('shape', 'pointStyle');
createEdgeStyle('color', 'lineBorderColor');
createEdgeStyle('penwidth', 'lineBorderWidth');

return {
labels,
datasets: [
{
label: options.name || 'Graph',
data: nodes,
edges,
},
Object.assign(
{
label: 'Graph',
data: nodes,
edges,
},
style,
graph
),
],
};
}

export function parse(dot, options = {}) {
export function parse(dot) {
const ast = parseAst(dot)[0];
console.log(ast);
if (ast && (ast.type === 'graph' || ast.type === 'digraph')) {
const r = parseGraph(ast, options);
const r = parseGraph(ast);
console.log(r);
return r;
}
Expand Down

0 comments on commit 4d905dc

Please sign in to comment.