Skip to content

Instantly share code, notes, and snippets.

@ghamarian
Created September 2, 2018 19:10
Show Gist options
  • Select an option

  • Save ghamarian/45b474bd5adaafb210ee75a54ba5259e to your computer and use it in GitHub Desktop.

Select an option

Save ghamarian/45b474bd5adaafb210ee75a54ba5259e to your computer and use it in GitHub Desktop.
force layout
document.onload = (function (d3, saveAs, Blob, undefined) {
"use strict";
// define graphcreator object
let GraphCreator = function (svg, nodes, edges) {
let thisGraph = this;
thisGraph.idct = 0;
thisGraph.nodes = nodes || [];
thisGraph.edges = edges || [];
thisGraph.state = {
selectedNode: null,
selectedEdge: null,
mouseDownNode: null,
mouseEnterNode: null,
mouseDownLink: null,
justDragged: false,
justScaleTransGraph: false,
lastKeyDown: -1,
shiftNodeDrag: false,
selectedText: null
};
// define arrow markers for graph links
let defs = svg.append('svg:defs');
defs.append('svg:marker')
.attr('id', 'end-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', "32")
.attr('markerWidth', 3.5)
.attr('markerHeight', 3.5)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M0,-5L10,0L0,5');
// define arrow markers for leading arrow
defs.append('svg:marker')
.attr('id', 'mark-end-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 7)
.attr('markerWidth', 3.5)
.attr('markerHeight', 3.5)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M0,-5L10,0L0,5');
thisGraph.svg = svg;
thisGraph.svgG = svg.append("g")
.classed(thisGraph.consts.graphClass, true);
let svgG = thisGraph.svgG;
// displayed when dragging between nodes
thisGraph.dragLine = svgG.append('svg:path')
.attr('class', 'link dragline hidden')
.attr('d', 'M0,0L0,0')
.style('marker-end', 'url(#mark-end-arrow)');
// svg nodes and edges
thisGraph.paths = svgG.append("g").selectAll("g");
thisGraph.circles = svgG.append("g").selectAll("g");
thisGraph.drag = d3.drag()
.subject(function (d) {
return {x: d.x, y: d.y};
})
.on("drag", function (args) {
thisGraph.state.justDragged = true;
thisGraph.dragmove.call(thisGraph, args);
})
.on("end", function (d) {
// todo check if edge-mode is selected
var mouse = d3.mouse(this);
var elem = document.elementFromPoint(mouse[0], mouse[1]);
if (thisGraph.state.shiftNodeDrag) {
thisGraph.dragEnd.call(thisGraph, d3.select(this), thisGraph.state.mouseEnterNode)
}
});
// listen for key events
d3.select(window).on("keydown", function () {
thisGraph.svgKeyDown.call(thisGraph);
})
.on("keyup", function () {
thisGraph.svgKeyUp.call(thisGraph);
});
svg.on("mousedown", function (d) {
thisGraph.svgMouseDown.call(thisGraph, d);
if (d3.event.shiftKey) {
d3.event.stopImmediatePropagation();
$('body').css('cursor', 'cell');
}
});
svg.on("mouseup", function (d) {
thisGraph.svgMouseUp.call(thisGraph, d);
});
// listen for dragging
let dragSvg = d3.zoom()
.on("zoom", function () {
if (d3.event.sourceEvent.shiftKey) {
// TODO the internal d3 state is still changing
return false;
} else {
thisGraph.zoomed.call(thisGraph);
}
return true;
})
.on("start", function () {
var ael = d3.select("#" + thisGraph.consts.activeEditId).node();
if (ael) {
ael.blur();
}
if (!d3.event.sourceEvent.shiftKey) d3.select('body').style("cursor", "move");
})
.on("end", function () {
d3.select('body').style("cursor", "auto");
});
svg.call(dragSvg).on("dblclick.zoom", null);
// listen for resize
window.onresize = function () {
thisGraph.updateWindow(svg);
};
// handle download data
d3.select("#download-input").on("click", function () {
let saveEdges = [];
thisGraph.edges.forEach(function (val, i) {
saveEdges.push({source: val.source.id, target: val.target.id});
});
let blob = new Blob([window.JSON.stringify({
"nodes": thisGraph.nodes,
"edges": saveEdges
})], {type: "text/plain;charset=utf-8"});
saveAs(blob, "mydag.json");
});
// handle uploaded data
d3.select("#upload-input").on("click", function () {
document.getElementById("hidden-file-upload").click();
});
d3.select("#hidden-file-upload").on("change", function () {
if (window.File && window.FileReader && window.FileList && window.Blob) {
let uploadFile = this.files[0];
let filereader = new window.FileReader();
filereader.onload = function () {
let txtRes = filereader.result;
// TODO better error handling
try {
let jsonObj = JSON.parse(txtRes);
thisGraph.deleteGraph(true);
thisGraph.nodes = jsonObj.nodes;
thisGraph.setIdCt(jsonObj.nodes.length + 1);
let newEdges = jsonObj.edges;
newEdges.forEach(function (e, i) {
newEdges[i] = {
source: thisGraph.nodes.filter(function (n) {
return n.id === e.source;
})[0],
target: thisGraph.nodes.filter(function (n) {
return n.id === e.target;
})[0]
};
});
thisGraph.edges = newEdges;
thisGraph.updateGraph();
} catch (err) {
window.alert("Error parsing uploaded file\nerror message: " + err.message);
return;
}
};
filereader.readAsText(uploadFile);
} else {
alert("Your browser won't let you save this graph -- try upgrading your browser to IE 10+ or Chrome or Firefox.");
}
});
// handle delete graph
d3.select("#delete-graph").on("click", function () {
thisGraph.deleteGraph(false);
});
d3.select("div#chartId")
.append("div")
.classed("svg-container", true) //container class to make it responsive
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 600 400")
//class to make it responsive
.classed("svg-content-responsive", true);
// thisGraph.d3cola = cola.d3adaptor()
// .linkDistance(30)
// .size([width, height]);
// init D3 force layout
thisGraph.force = d3.forceSimulation()
.force('charge', d3.forceManyBody().strength(-500))
.force('link', d3.forceLink().id((d) => d.id).distance(500))
// .force('x', d3.forceX(width / 2))
// .force('y', d3.forceY(height / 2))
.on('tick', function(){return thisGraph.tick();});
};
GraphCreator.prototype.setIdCt = function (idct) {
this.idct = idct;
};
GraphCreator.prototype.consts = {
selectedClass: "selected",
connectClass: "connect-node",
circleGClass: "conceptG",
graphClass: "graph",
activeEditId: "active-editing",
BACKSPACE_KEY: 8,
DELETE_KEY: 46,
ENTER_KEY: 13,
nodeRadius: 50
};
/* PROTOTYPE FUNCTIONS */
GraphCreator.prototype.dragmove = function (d) {
let thisGraph = this;
if (thisGraph.state.shiftNodeDrag) {
thisGraph.dragLine.attr('d', 'M' + d.x + ',' + d.y + 'L' + d3.mouse(thisGraph.svgG.node())[0] + ',' + d3.mouse(this.svgG.node())[1]);
} else {
d.x += d3.event.dx;
d.y += d3.event.dy;
thisGraph.updateGraph();
}
};
GraphCreator.prototype.deleteGraph = function (skipPrompt) {
let thisGraph = this,
doDelete = true;
if (!skipPrompt) {
doDelete = window.confirm("Press OK to delete this graph");
}
if (doDelete) {
thisGraph.nodes = [];
thisGraph.edges = [];
thisGraph.updateGraph();
}
};
/* select all text in element: taken from http://stackoverflow.com/questions/6139107/programatically-select-text-in-a-contenteditable-html-element */
GraphCreator.prototype.selectElementContents = function (el) {
let range = document.createRange();
range.selectNodeContents(el);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
};
/* insert svg line breaks: taken from http://stackoverflow.com/questions/13241475/how-do-i-include-newlines-in-labels-in-d3-charts */
GraphCreator.prototype.insertTitleLinebreaks = function (gEl, title) {
let words = title.split(/\s+/g),
nwords = words.length;
let el = gEl.append("text")
.attr("text-anchor", "middle")
.attr("dy", "-" + (nwords - 1) * 7.5);
for (let i = 0; i < words.length; i++) {
let tspan = el.append('tspan').text(words[i]);
if (i > 0)
tspan.attr('x', 0).attr('dy', '15');
}
};
// remove edges associated with a node
GraphCreator.prototype.spliceLinksForNode = function (node) {
let thisGraph = this,
toSplice = thisGraph.edges.filter(function (l) {
return (l.source === node || l.target === node);
});
toSplice.map(function (l) {
thisGraph.edges.splice(thisGraph.edges.indexOf(l), 1);
});
};
GraphCreator.prototype.replaceSelectEdge = function (d3Path, edgeData) {
let thisGraph = this;
d3Path.classed(thisGraph.consts.selectedClass, true);
if (thisGraph.state.selectedEdge) {
thisGraph.removeSelectFromEdge();
}
thisGraph.state.selectedEdge = edgeData;
};
GraphCreator.prototype.replaceSelectNode = function (d3Node, nodeData) {
let thisGraph = this;
d3Node.classed(this.consts.selectedClass, true);
if (thisGraph.state.selectedNode) {
thisGraph.removeSelectFromNode();
}
thisGraph.state.selectedNode = nodeData;
// TODO
clear_properties();
thisGraph.print_inputs(nodeData);
// $('.properties label').text(JSON.stringify(nodeData));
};
GraphCreator.prototype.removeSelectFromNode = function () {
let thisGraph = this;
thisGraph.circles.filter(function (cd) {
return cd.id === thisGraph.state.selectedNode.id;
}).classed(thisGraph.consts.selectedClass, false);
thisGraph.state.selectedNode = null;
};
GraphCreator.prototype.removeSelectFromEdge = function () {
let thisGraph = this;
thisGraph.paths.filter(function (cd) {
return cd === thisGraph.state.selectedEdge;
}).classed(thisGraph.consts.selectedClass, false);
thisGraph.state.selectedEdge = null;
};
GraphCreator.prototype.pathMouseDown = function (d3path, d) {
let thisGraph = this,
state = thisGraph.state;
// d3.event.stopPropagation();
state.mouseDownLink = d;
if (state.selectedNode) {
thisGraph.removeSelectFromNode();
}
let prevEdge = state.selectedEdge;
if (!prevEdge || prevEdge !== d) {
thisGraph.replaceSelectEdge(d3path, d);
} else {
thisGraph.removeSelectFromEdge();
}
};
// mousedown on node
GraphCreator.prototype.circleMouseDown = function (d3node, d) {
let thisGraph = this,
state = thisGraph.state;
// d3.event.stopPropagation();
state.mouseDownNode = d;
if (d3.event.shiftKey) {
state.shiftNodeDrag = d3.event.shiftKey;
// reposition dragged directed edge
thisGraph.dragLine.classed('hidden', false)
.attr('d', 'M' + d.x + ',' + d.y + 'L' + d.x + ',' + d.y);
return;
}
};
/* place editable text on node in place of svg text */
GraphCreator.prototype.changeTextOfNode = function (d3node, d) {
let thisGraph = this,
consts = thisGraph.consts,
htmlEl = d3node.node();
d3node.selectAll("text").remove();
let nodeBCR = htmlEl.getBoundingClientRect(),
curScale = nodeBCR.width / consts.nodeRadius,
placePad = 5 * curScale,
useHW = curScale > 1 ? nodeBCR.width * 0.71 : consts.nodeRadius * 1.42;
// replace with editableconent text
let d3txt = thisGraph.svg.selectAll("foreignObject")
.data([d])
.enter()
.append("foreignObject")
.attr("x", nodeBCR.left + placePad)
.attr("y", nodeBCR.top + placePad)
.attr("height", 2 * useHW)
.attr("width", useHW)
.append("xhtml:p")
.attr("id", consts.activeEditId)
.attr("contentEditable", "true")
.text(d.title)
.on("mousedown", function (d) {
d3.event.stopPropagation();
})
.on("keydown", function (d) {
d3.event.stopPropagation();
if (d3.event.keyCode == consts.ENTER_KEY && !d3.event.shiftKey) {
this.blur();
}
})
.on("blur", function (d) {
d.title = this.textContent;
thisGraph.insertTitleLinebreaks(d3node, d.title);
d3.select(this.parentElement).remove();
});
return d3txt;
};
GraphCreator.prototype.dragEnd = function (d3node, d) {
let thisGraph = this,
state = thisGraph.state,
consts = thisGraph.consts;
// reset the states
state.shiftNodeDrag = false;
d3node.classed(consts.connectClass, false);
let mouseDownNode = state.mouseDownNode;
let mouseEnterNode = state.mouseEnterNode;
if (state.justDragged) {
// dragged, not clicked
state.justDragged = false;
}
thisGraph.dragLine.classed("hidden", true);
if (!mouseDownNode || !mouseEnterNode) return;
if (mouseDownNode !== d) {
// we're in a different node: create new edge for mousedown edge and add to graph
let newEdge = {source: mouseDownNode, target: d};
let filtRes = thisGraph.paths.filter(function (d) {
if (d.source === newEdge.target && d.target === newEdge.source) {
thisGraph.edges.splice(thisGraph.edges.indexOf(d), 1);
}
return d.source === newEdge.source && d.target === newEdge.target;
});
if (!filtRes || !filtRes[0] || !filtRes[0].length) {
thisGraph.edges.push(newEdge);
thisGraph.updateGraph();
}
}
state.mouseDownNode = null;
state.mouseEnterNode = null;
return;
};
GraphCreator.prototype.print_inputs = function (nodeData) {
let thisGraph = this,
state = thisGraph.state,
consts = thisGraph.consts;
for (let key in nodeData['parameters']) {
let node_params = nodeData['parameters'][key];
switch (node_params['type']) {
case 'select':
add_input_select(key, node_params['options'], node_params['value']);
break;
case 'boolean':
add_input_select(key, ['true', 'false'], node_params['value']);
break;
case "integer" :
add_input_number(key, node_params, '1');
break;
case "float" :
add_input_number(key, node_params, 'any');
break;
default:
add_input(key, node_params['value'], node_params['type']);
}
}
// TODO fix
d3.selectAll("#properties select").on("change", function () {
for (let i in thisGraph.nodes) {
if (thisGraph.nodes[i].id === thisGraph.state.selectedNode.id) {
thisGraph.nodes[i].parameters[this.id].value = this.value;
}
}
});
d3.selectAll("#properties input").on("change", function () {
for (let i in thisGraph.nodes) {
if (thisGraph.nodes[i].id === thisGraph.state.selectedNode.id) {
thisGraph.nodes[i].parameters[this.id].value = this.value;
}
}
}
);
}
;
// mouseup on nodes
GraphCreator.prototype.circleMouseUp = function (d3node, d) {
let thisGraph = this,
state = thisGraph.state,
consts = thisGraph.consts;
// reset the states
state.shiftNodeDrag = false;
d3node.classed(consts.connectClass, false);
if (d3.event.shiftKey) {
// shift-clicked node: edit text content
let d3txt = thisGraph.changeTextOfNode(d3node, d);
let txtNode = d3txt.node();
thisGraph.selectElementContents(txtNode);
txtNode.focus();
} else {
if (state.selectedEdge) {
thisGraph.removeSelectFromEdge();
}
}
let prevNode = state.selectedNode;
if (!prevNode || prevNode.id !== d.id) {
thisGraph.replaceSelectNode(d3node, d);
} else {
thisGraph.removeSelectFromNode();
}
}; // end of circles mouseup
// mousedown on main svg
GraphCreator.prototype.svgMouseDown = function () {
this.state.graphMouseDown = true;
};
// mouseup on main svg
GraphCreator.prototype.svgMouseUp = function () {
let thisGraph = this,
state = thisGraph.state;
if (state.justScaleTransGraph) {
// dragged not clicked
state.justScaleTransGraph = false;
} else if (state.graphMouseDown && d3.event.shiftKey) {
// clicked not dragged from svg
// #TODO
console.log('adding ' + d3.select('input[name="node"]:checked').node().value);
let type = d3.select('input[name="node"]:checked').node().value;
let xycoords = d3.mouse(thisGraph.svgG.node()),
selected_item = d3.select('input[name="node"]:checked').node().value,
d = {
id: thisGraph.idct++,
title: selected_item,
x: xycoords[0],
y: xycoords[1],
parameters: $.extend(true, {}, core_layers[type])
};
console.log(d);
thisGraph.nodes.push(d);
thisGraph.updateGraph();
// make title of text immediently editable
let d3txt = thisGraph.changeTextOfNode(thisGraph.circles.filter(function (dval) {
return dval.id === d.id;
}), d),
txtNode = d3txt.node();
thisGraph.selectElementContents(txtNode);
txtNode.focus();
} else if (state.shiftNodeDrag) {
// dragged from node
state.shiftNodeDrag = false;
thisGraph.dragLine.classed("hidden", true);
}
state.graphMouseDown = false;
};
// keydown on main svg
GraphCreator.prototype.svgKeyDown = function () {
let thisGraph = this,
state = thisGraph.state,
consts = thisGraph.consts;
// make sure repeated key presses don't register for each keydown
if (state.lastKeyDown !== -1) return;
state.lastKeyDown = d3.event.keyCode;
let selectedNode = state.selectedNode,
selectedEdge = state.selectedEdge;
switch (d3.event.keyCode) {
case consts.BACKSPACE_KEY:
case consts.DELETE_KEY:
if ($(d3.event.srcElement).is("input")) {
break;
}
d3.event.preventDefault();
if (selectedNode) {
thisGraph.nodes.splice(thisGraph.nodes.indexOf(selectedNode), 1);
thisGraph.spliceLinksForNode(selectedNode);
state.selectedNode = null;
thisGraph.updateGraph();
} else if (selectedEdge) {
thisGraph.edges.splice(thisGraph.edges.indexOf(selectedEdge), 1);
state.selectedEdge = null;
thisGraph.updateGraph();
}
break;
}
};
GraphCreator.prototype.svgKeyUp = function () {
this.state.lastKeyDown = -1;
};
// call to propagate changes to graph
GraphCreator.prototype.updateGraph = function () {
let thisGraph = this,
consts = thisGraph.consts,
state = thisGraph.state;
thisGraph.paths = thisGraph.paths.data(thisGraph.edges, function (d) {
return String(d.source.id) + "+" + String(d.target.id);
});
let paths = thisGraph.paths;
// update existing paths
paths.style('marker-end', 'url(#end-arrow)')
.classed(consts.selectedClass, function (d) {
return d === state.selectedEdge;
})
// .attr("d", line([d.source.x, d.source.y, d.target.x, d.target.y]));
.attr("d", function (d) {
var da = [];
var middle = {x: (d.source.x + d.target.x) / 2, y: (d.source.y + d.target.y) / 1.7};
if (d.source.x < d.target.x)
da = [{x: d.source.x, y: d.source.y}, {x: (d.target.x - consts.nodeRadius), y: d.target.y}];
else {
da = [{x: d.source.x, y: d.source.y}, {x: (d.target.x + consts.nodeRadius), y: d.target.y}];
}
// if (Math.abs(d.source.x - d.target.x) > 300) {
// da.splice(1, 0, middle);
// }
var myline = d3.line().curve(d3.curveMonotoneX).x(d => d.x).y(d => d.y);
return myline(da);
});
// remove old links
paths.exit().remove();
// add new paths
paths = paths.enter()
.append("path")
.style('marker-end', 'url(#end-arrow)')
.classed("link", true)
.attr("d", function (d) {
var da = [];
var middle = {x: (d.source.x + d.target.x) / 2, y: (d.source.y + d.target.y) / 1.7};
if (d.source.x < d.target.x)
da = [{x: d.source.x, y: d.source.y}, {x: (d.target.x - consts.nodeRadius), y: d.target.y}];
else {
da = [{x: d.source.x, y: d.source.y}, {x: (d.target.x + consts.nodeRadius), y: d.target.y}];
}
// if (Math.abs(d.source.x - d.target.x) > 300) {
// da.splice(1, 0, middle);
// }
var myline = d3.line().curve(d3.curveMonotoneX).x(d => d.x).y(d => d.y);
return myline(da);
})
.merge(paths)
.on("mouseup", function (d) {
// state.mouseDownLink = null;
})
.on("mousedown", function (d) {
thisGraph.pathMouseDown.call(thisGraph, d3.select(this), d);
}
);
thisGraph.paths = paths;
// update existing nodes
thisGraph.circles = thisGraph.circles.data(thisGraph.nodes, function (d) {
return d.id;
});
// remove old nodes
thisGraph.circles.exit().remove();
thisGraph.circles.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
// add new nodes
let newGs = thisGraph.circles.enter()
.append("g").merge(thisGraph.circles);
newGs.classed(consts.circleGClass, true)
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
.on("mouseover", function (d) {
state.mouseEnterNode = d;
if (state.shiftNodeDrag) {
d3.select(this).classed(consts.connectClass, true);
}
})
.on("mouseout", function (d) {
state.mouseEnterNode = null;
d3.select(this).classed(consts.connectClass, false);
})
.on("mousedown", function (d) {
thisGraph.circleMouseDown.call(thisGraph, d3.select(this), d);
})
.call(thisGraph.drag)
.on("click", function (d) {
thisGraph.circleMouseUp.call(thisGraph, d3.select(this), d);
});
thisGraph.circles = newGs;
// newGs.append("circle")
// .attr("r", String(consts.nodeRadius));
newGs.append('rect')
.attr("rx", 6)
.attr("ry", 6)
.attr("x", d => -2 * consts.nodeRadius)
.attr("y", d => -consts.nodeRadius)
.attr("width", String(4 * consts.nodeRadius))
.attr("height", String(2 * consts.nodeRadius));
newGs.each(function (d) {
thisGraph.insertTitleLinebreaks(d3.select(this), d.title);
});
thisGraph.force.nodes(thisGraph.nodes)
.force('link').links(thisGraph.edges);
thisGraph.force.alphaTarget(0.3).restart();
};
GraphCreator.prototype.tick = function () {
// handles to link and node element groups
let thisGraph = this;
thisGraph.paths.attr('d', (d) => {
const deltaX = d.target.x - d.source.x;
const deltaY = d.target.y - d.source.y;
const dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
const normX = deltaX / dist;
const normY = deltaY / dist;
const sourcePadding = d.left ? 17 : 12;
const targetPadding = d.right ? 17 : 12;
const sourceX = d.source.x + (sourcePadding * normX);
const sourceY = d.source.y + (sourcePadding * normY);
const targetX = d.target.x - (targetPadding * normX);
const targetY = d.target.y - (targetPadding * normY);
return `M${sourceX},${sourceY}L${targetX},${targetY}`;
});
thisGraph.circles.attr('transform', (d) => `translate(${d.x},${d.y})`);
};
GraphCreator.prototype.zoomed = function () {
this.state.justScaleTransGraph = true;
d3.select("." + this.consts.graphClass)
// .attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
.attr("transform", d3.event.transform);
};
GraphCreator.prototype.updateWindow = function (svg) {
let docEl = document.documentElement,
bodyEl = document.getElementsByTagName('body')[0];
let x = window.innerWidth || docEl.clientWidth || bodyEl.clientWidth;
let y = window.innerHeight || docEl.clientHeight || bodyEl.clientHeight;
svg.attr("width", x).attr("height", y);
};
/**** MAIN ****/
// warn the user when leaving
window.onbeforeunload = function () {
return "Make sure to save your graph locally before leaving :-)";
};
let docEl = document.documentElement,
bodyEl = document.getElementsByTagName('body')[0];
let width = window.innerWidth || docEl.clientWidth || bodyEl.clientWidth,
height = window.innerHeight || docEl.clientHeight || bodyEl.clientHeight;
let xLoc = width / 2 - 25,
yLoc = 100;
// initial node data
let nodes = [{title: "new concept", id: 0, x: xLoc, y: yLoc},
{title: "new concept", id: 1, x: xLoc, y: yLoc + 200}];
let edges = [{source: nodes[1], target: nodes[0]}];
/** MAIN SVG **/
let svg = d3.select(".svg-container").append("svg")
.attr('viewBox', `87 0 ${width - 300} ${height}`)
.attr("width", width - 300)
.attr("height", height);
let graph = new GraphCreator(svg, nodes, edges);
var core_layers;
graph.setIdCt(2);
graph.updateGraph();
var promise = d3.json('./keraslayers');
promise.then(function (data) {
core_layers = data;
// TODO change to d3
for (var key in core_layers) {
var $label = $('<label for="' + key + '">').text(core_layers[key]['class_name']);
var $input = $('<input type="radio">').attr({id: key, name: 'node', value: key});
$('#form_radiob').append($input);
$('#form_radiob').append($label);
}
},
function (error) {
console.log('error loading core layers file');
});
function clear_properties() {
let myNode = document.getElementsByClassName("properties")[0];
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
}
function add_input(label_name, default_value, type_input) {
if (label_name != "class_name") {
add_label(label_name);
let in_t = d3.select(".properties").append("input")
.attr("type", type_input)
.attr("id", label_name)
.attr("name", label_name)
.attr("value", default_value);
}
}
function add_input_number(label_name, node_params, step) {
add_label(label_name);
let in_n = d3.select(".properties").append("input")
.attr("type", "number")
.attr("id", label_name)
.attr("name", label_name)
.attr("value", node_params['value'])
.attr("min", node_params['min'])
.attr("step", step);
let lab_err = d3.select(".properties").append("span")
.attr("classList", "validity");
}
function add_input_select(label_name, data, value) {
add_label(label_name);
var select = d3.select('.properties')
.append('select')
.attr('id', label_name)
.attr('class', 'select')
.on('change', onchange);
var options = select
.selectAll('option')
.data(data).enter()
.append('option')
.text(function (d) {
return d;
});
d3.select('#' + label_name).property('value', value);
function onchange() {
var selectValue = d3.select('select').property('value');
};
}
function add_label(label_name) {
let label = document.createTextNode(label_name);
document.getElementsByClassName("properties")[0].appendChild(label);
}
})
(window.d3, window.saveAs, window.Blob);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment