Skip to content

Instantly share code, notes, and snippets.

@Saigesp
Last active September 30, 2018 20: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 Saigesp/514a2c292c13ae53685c2f3e1971712e to your computer and use it in GitHub Desktop.
Save Saigesp/514a2c292c13ae53685c2f3e1971712e to your computer and use it in GitHub Desktop.
Flow GUI
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Premier</title>
</head>
<style>
body {
position: relative;
width: 100%;
margin: 0;
}
#board {
width: 100%;
height: 400px;
position: relative;
}
#board svg {
background: #e8e8e8;
}
/* Box */
.box {
fill: #f5f5f5;
font-size: 14px;
font-family: sans-serif;
stroke: #CCC;
}
/* Pins */
.pins .pin {
fill: white;
stroke: #cac9c9;
stroke-width: 2;
}
.pins .pin.to-link {
stroke: #ffa400;
}
.pins .pin.linkable {
stroke: #00b1ce;
}
</style>
<body>
<div id="board"></div>
</body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var oidcount = 0;
var data = {'nodes':[],'links':[]}; // Where to store data
// Creatables boxes
var boxes = [ // It will come from database
{
'category': 'source',
'_id': 'misp',
'type': 'misp',
'pin_in':[
],
'pin_out': [
{'type': 'kke', 'oid': 'misp', 'soid': 'misp-'+oidcount+'-kke-0'},
{'type': 'ioc', 'oid': 'misp', 'soid': 'misp-'+oidcount+'-ioc-0'},
]},
{
'category': 'source',
'_id': 'delfos',
'type': 'delfos',
'pin_in':[
],
'pin_out': [
{'type': 'ioc', 'oid': 'delfos', 'soid': 'delf-'+oidcount+'-kke-0'},
]},
{
'category': 'consumer',
'_id': 'consum',
'type': 'consum',
'pin_in':[
{'type': 'ioc', 'oid': 'consum', 'soid': 'consum-'+oidcount+'-ioc-0'},
{'type': 'nfc', 'oid': 'consum', 'soid': 'consum-'+oidcount+'-nfc-0'},
{'type': 'hdp', 'oid': 'consum', 'soid': 'consum-'+oidcount+'-hdp-0'},
],
'pin_out': [
]},
]
// Box properties
var boxprop = { // Maybe configurable
'width': 300,
'lineheight': 30,
'radius': 3,
'pin': {
'radius': 8,
'padding': 13,
'top': 4,
}
}
// Vars
var board = d3.select('#board');
var width = parseInt(board.style('width'), 10),
height = parseInt(board.style('height'), 10);
var svg = board.append('svg')
.datum(data)
.attr('width', width)
.attr('height', height);
var box = svg.selectAll('.box')
.data(data['nodes']);
var link = svg.selectAll('.link')
.data(data['links']);
var graphline = d3.line()
.x(function(d, i) {
xbox = d3.selectAll('.box').filter(function(s){ return s.oid == d.oid; }).data()[0].x; // Box's X position
if (i==0) return xbox + boxprop.width + boxprop.pin.padding + boxprop.pin.radius;
if (i==1) return xbox + boxprop.width +60;
if (i==2) return xbox - 60;
if (i==3) return xbox - boxprop.pin.padding - boxprop.pin.radius;
})
.y(function(d, i) {
var ind = 0,
boxdata = d3.selectAll('.box').filter(function(s){ return s.oid == d.oid; }).data(),
ybox = boxdata[0].y;
if(i <= 1) boxdata[0].pin_out.forEach(function(j,m){ if(j.soid==d.soid) ind = m; });
else boxdata[0].pin_in.forEach(function(j,m){ if(j.soid==d.soid) ind = m; });
return ybox + boxprop.pin.padding + boxprop.pin.top + (boxprop.lineheight*ind);
})
.curve(d3.curveBasis);
function appendNode(d){
node = {'pin_in':[],'pin_out':[], 'category': d.category, 'type': d.type, '_id': d._id };
node.oid = d._id + '-' + oidcount;
d.pin_out.forEach(function(j,m){
node.pin_out.push({'oid': node.oid, 'soid': node.oid +'-'+ j.type, 'type': j.type });
})
d.pin_in.forEach(function(j){
node.pin_in.push({'oid': node.oid, 'soid': node.oid +'-'+ j.type, 'type': j.type });
})
data['nodes'].push(node)
updateDashboard(data);
oidcount += 1;
}
// External HTML
function createDashboardControls(){
board.append('div')
.attr('class', 'buttons')
.selectAll('button')
.data(boxes)
.enter().append('button')
.attr('class', 'newbox')
.text(function(d){ return '+ '+d.type })
.on('click', function(d){
appendNode(d);
});
}
// Update Splines
function updateSplines(data){
datas = [];
data['links'].forEach(function(d,i){
datas.push([
{'oid': d.from.oid, 'soid': d.from.soid },
{'oid': d.from.oid, 'soid': d.from.soid },
{'oid': d.to.oid, 'soid': d.to.soid },
{'oid': d.to.oid, 'soid': d.to.soid },
]);
})
d3.selectAll('.link').remove();
var spline = svg.selectAll('.ĺink')
.data(datas).enter()
.append('path')
.attr('class',function(d){
return 'link';
})
.attr('stroke', '#CCC')
.attr('stroke-width', 2)
.attr('fill', 'transparent')
.attr('d', graphline )
}
// Update function
function updateDashboard(data){
console.log('global data: ',data);
// Nodes
var tbox = svg.selectAll('.box').data(data['nodes']).enter().append('g')
.attr('id', function(d){ return d.oid; })
.attr('class', 'wrap')
.call(d3.drag()
//.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.attr('transform', function(d){
d.x = d.x == undefined ? (width-boxprop.width)/2 + d3.randomUniform(1, 80)(): d.x;
d.y = d.y == undefined ? height/2 + d3.randomUniform(1, 80)(): d.y;
return 'translate('+(d.x)+','+(d.y)+')';
});
tbox.append('rect')
.attr('class', 'box')
.attr('width', boxprop.width)
.attr('rx', boxprop.radius)
.attr('ry', boxprop.radius)
.attr('height', function(d){
d.h = d3.max([d.pin_in.length, d.pin_out.length]) * 30;
return d.h;
});
tbox.append('text')
.attr('x', boxprop.width/2)
.attr('y', function(d){
return d.h/2 + 4;
})
.attr('text-anchor', 'middle')
.text(function(d){
return d.type + ' (' + d.category + ')';
});
var pins = tbox.append('g')
.attr('class', 'pins');
var pins_out = pins.append('g')
.attr('transform', 'translate('+(boxprop.width+boxprop.pin.padding)+',0)')
.attr('class', 'pins__out');
var pins_in = pins.append('g')
.attr('transform', 'translate('+(-boxprop.pin.padding)+',0)')
.attr('class', 'pins__in');
pins_out.selectAll('.pin--out')
.data(function(d){return d['pin_out'];})
.enter().append('circle')
.attr('class', 'pin pin--out')
.attr('r', boxprop.pin.radius)
.attr('cy', function(j,m){
console.log((boxprop.lineheight/2)+(m*boxprop.lineheight) + boxprop.pin.top);
return (boxprop.lineheight/2)+(m*boxprop.lineheight) + boxprop.pin.top;
})
.on('click', function(j){
if(d3.select(this).classed('to-link')){
d3.selectAll('.pin').classed('to-link', false);
d3.selectAll('.pin').classed('linkable', false);
}else{
d3.selectAll('.pin').classed('to-link', false);
d3.selectAll('.pin').classed('linkable', false);
d3.select(this).classed('to-link', true);
d3.selectAll('.pin--in').filter(function(d){ return d.type == j.type })
.classed('linkable', true)
.on('click', function(d){
data['links'].push({
'from': {'oid': j.oid, 'soid': j.soid},
'to': {'oid': d.oid, 'soid': d.soid}
});
updateSplines(data);
d3.selectAll('.pin').classed('to-link', false);
d3.selectAll('.pin').classed('linkable', false);
});
}
});
pins_in.selectAll('.pin--in')
.data(function(d){return d['pin_in'];})
.enter().append('circle')
.attr('class', 'pin pin--in')
.attr('r', boxprop.pin.radius)
.attr('cy', function(j,m){
return (boxprop.lineheight/2)+(m*boxprop.lineheight) + boxprop.pin.top;
});
pins_in.selectAll('.label--out')
.data(function(d){return d['pin_out'];})
.enter().append('text')
.attr('class', '.label .label--out')
.attr('text-anchor', 'end')
.attr('x', boxprop.width + 4)
.attr('font-size', '12px')
.attr('y', function(j,m){
return (boxprop.lineheight/2)+(m*boxprop.lineheight) + boxprop.pin.top + 3;
})
.text(function(j,m){
return j.type;
});
pins_in.selectAll('.label--in')
.data(function(d){return d['pin_in'];})
.enter().append('text')
.attr('class', '.label .label--in')
.attr('text-anchor', 'start')
.attr('x', 20)
.attr('font-size', '12px')
.attr('y', function(j,m){
return (boxprop.lineheight/2)+(m*boxprop.lineheight) + boxprop.pin.top + 3;
})
.text(function(j,m){
return j.type;
});
updateSplines(data);
}
// Tools functions
function dragstarted(d) {
d3.selectAll('.pin').classed('to-link', false);
d3.selectAll('.pin').classed('linkable', false);
d3.select(this).raise().classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("transform", function(){
d.x = d3.event.x;
d.y = d3.event.y;
return 'translate('+d.x+','+d.y+')'
});
updateSplines(data);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
function mousemove() {
var coordinates = [0, 0];
coordinates = d3.mouse(this);
}
createDashboardControls();
updateDashboard(data);
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment