forked from kiansheik's block: My Final Project Draft
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
.node {}
.link { stroke: #999; stroke-opacity: .6; stroke-width: 1px; }
.hull {
opacity: 0.23;
stroke-width: 2px;
stroke-linejoin: round;
}
button {
background: #ededed;
cursor: pointer;
}
button:focus {
background: #e5e5e5;
outline: none;
-webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
-moz-box-shadow: inset 0px 0px 5px #c1c1c1;
box-shadow: inset 0px 0px 5px #c1c1c1;
}
button:active {
background: #e5e5e5;
-webkit-box-shadow: inset 0px 0px 5px #c1c1c1;
-moz-box-shadow: inset 0px 0px 5px #c1c1c1;
box-shadow: inset 0px 0px 5px #c1c1c1;
outline: none;
}
.lasso path {
stroke: rgb(80,80,80);
stroke-width:2px;
}
.lasso .drawn {
fill-opacity:.05 ;
}
.lasso .loop_close {
fill:none;
stroke-dasharray: 4,4;
}
.lasso .origin {
fill:#3399FF;
fill-opacity:.5;
}
.not_possible {
fill: rgb(200,200,200);
}
.possible {
fill: #EC888C;
}
.selected {
fill: steelblue;
}
.not-hovered {
opacity:0;
}
.dragdiv {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
}
.dragdivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
.smsvg:hover{
background-color: #ecf4ff4f;
}
</style>
</head>
<body>
<div class="dragdiv" id="mydiv">
<!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
<div class="dragdivheader" id="mydivheader"><button onclick="prevSM()"><</button> Selections <button onclick="nextSM()">></button></div>
</div>
<!-- <div class="dragdiv" id="yeardiv">
<div class="dragdivheader" id="yeardivheader">Year:</div>
</div> -->
<svg></svg>
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script>
<script src="https://d3js.org/d3-selection-multi.v1.js"></script>
<script src="d3-lasso.min.js"></script>
<script type="text/javascript">
var graph = null, sim = null, radius = 5, fname = 'emails.json', current_year = 0, distc = 100, strenc = 0.23;
function getTranslation(transform) {
// Create a dummy g for calculation purposes only. This will never
// be appended to the DOM and will be discarded once this function
// returns.
var g = document.createElementNS("https://www.w3.org/2000/svg", "g");
// Set the transform attribute to the provided string value.
g.setAttributeNS(null, "transform", transform);
// consolidate the SVGTransformList containing all transformations
// to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
// its SVGMatrix.
var matrix = g.transform.baseVal.consolidate().matrix;
// As per definition values e and f are the ones for the translation.
return [matrix.e, matrix.f];
}
var selections = [], hulls = [];
var colors = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select("svg"),
width = window.innerWidth-10,//+svg.attr("width"),
height = window.innerHeight-230,//+svg.attr("height"),
node,
link;
svg.attr("width", width),
svg.attr("height", height),
svg.append('defs').append('marker')
// .attrs({'id':'arrowhead',
// 'viewBox':'-0 -5 10 10',
// 'refX':13,
// 'refY':0,
// 'orient':'auto',
// 'markerWidth':13,
// 'markerHeight':13,
// 'xoverflow':'visible'})
// .append('svg:path')
// .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
// .attr('fill', '#999')
// .style('stroke','none');
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {return d.id;}).distance(distc).strength(strenc))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
sim = simulation;
d3.json(fname, function (error, graphl) {
if (error) throw error;
console.log('years', graphl.years)
graph = graphl
baseGraph = deepcopy(graph)
update(graph.years[current_year], graph.nodes);
// yeardiv = d3.select('#yeardiv')
// yeardiv.selectAll('button').data([...Array(graph.years.length).keys()])
// .enter()
// .append('button')
// .text(function(d){ return d+1})
// .on('click', function(d){yeardiv.selectAll('div').text("Year: "+(d+1));current_year = d;restart(graph.years[d]);})
// for(var i = 1;i<graph.years.length;i++){
// setTimeout(function(){update(graph.years[i], graph.nodes)}, 3000*i);
// }
for(var i=0;i<7;i++){
insertSM(graph, i, 200, 200)
}
})
function restart(links) {
links = deepcopy(links)
prevCol = link.style('stroke')
prevWidth = link.style('stroke-width')
// Apply the general update pattern to the links.
// link.transition().attr('filter', 'blurMe').duration(300).ease(d3.easeBounce);
link = link.data(links);
link.exit()
.style('stroke', 'red')
.transition()
.attr("stroke-opacity", 0)
// .attrTween("x1", function(d) { return function() { return d.source.x; }; })
// .attrTween("x2", function(d) { return function() { return d.target.x; }; })
// .attrTween("y1", function(d) { return function() { return d.source.y; }; })
// .attrTween("y2", function(d) { return function() { return d.target.y; }; })
.style('stroke', prevCol)
.style('stroke-width',prevWidth)
.attr('filter', null)
.remove()
.duration(1200)
.ease(d3.easeBounce);
link = link.enter().insert("line", "* + .node").call(function(link) { link.transition().attr("stroke-opacity", 1); }).attr("class", "link")
.attr('marker-end','url(#arrowhead)').merge(link);
// Update and restart the simulation.
sim.force("link", d3.forceLink().id(function (d) {return d.id;}).distance(distc).strength(strenc));
sim.force("link").links(links);
sim.restart();
}
function update(links, nodes) {
links = deepcopy(links);nodes = deepcopy(nodes)
console.log(links)
svg.append('filter')
.attr('id', 'blurMe')
.append('feGaussianBlur')
.attr('in', 'SourceGraphic')
.attr('stdDeviation', 5)
link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link")
.attr('marker-end','url(#arrowhead)')
link.append("title")
.text(function (d) {return d.type;});
edgepaths = svg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attrs({
'class': 'edgepath',
'fill-opacity': 0,
'stroke-opacity': 0,
'id': function (d, i) {return 'edgepath' + i}
})
.style("pointer-events", "none");
edgelabels = svg.selectAll(".edgelabel")
.data(links)
.enter()
.append('text')
.style("pointer-events", "none")
.attrs({
'class': 'edgelabel',
'id': function (d, i) {return 'edgelabel' + i},
'font-size': 10,
'fill': '#aaa'
});
edgelabels.append('textPath')
.attr('xlink:href', function (d, i) {return '#edgepath' + i})
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("startOffset", "50%")
.text(function (d) {return d.type});
node = svg.selectAll(".node")
.data(nodes, function(d) { return(d); })
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
//.on("end", dragended)
);
var circs = node.append("circle")
.attr("r", 5)
.style("fill", 'grey')
.on('mouseover', function(d){
d3.select(this).style('fill','steelblue');
d3.select(this.parentNode).select('text').style('display', null);})
.on('mouseout', function(){
d3.select(this).style('fill','grey');
d3.select(this.parentNode).select('text').style('display', 'none')});
node.append("title")
.text(function (d) {return d.id;});
// On node hover, examine the links to see if their
// source or target properties match the hovered node.
node.on('mouseover', function(d) {
link.style('stroke-width', function(l) {
if (d === l.source || d === l.target)
return 4;
else
return 2;
});
// link.style('stroke', function(l) {
// if (d === l.source || d === l.target)
// return 'black';
// else
// return 'grey';
// });
});
// Set the stroke width back to normal when mouse leaves the node.
node.on('mouseout', function() {
link.style('stroke-width', 2);
});
var text = node.append("text")
.attr("dy", -3)
.text(function (d) {return d.name+" "+d.label;})
.style('display', 'none')
simulation
.nodes(nodes)
.on("tick", ticked);
simulation.force("link")
.links(links);
// Lasso functions
var lasso_start = function() {
simulation.stop();
lasso.items()
.classed("not_possible",true)
.classed("selected",false)
.attr("r",5); // reset size
};
var lasso_draw = function() {
// Style the possible dots
lasso.possibleItems()
.classed("not_possible",false)
.classed("possible",true);
// Style the not possible dot
lasso.notPossibleItems()
.classed("not_possible",true)
.classed("possible",false);
};
var lasso_end = function() {
if(lasso.selectedItems()._groups[0].length > 0){
// Reset the color of all dots
lasso.items()
.classed("not_possible",false)
.classed("possible",false);
// Style the selected dots
lasso.selectedItems()
.classed("selected"+(selections.length+1),true)
.attr("r",7);
d3.select('#mydiv')
.append('p')
.classed('selectionRow'+(selections.length+1),true)
.text('Group '+(selections.length+1))
.style('color', colors(selections.length+1));
hulls.push(svg.insert("path", ":first-child")
.attr("class", "hull"+(selections.length+1))
.classed('hull', true));
selections.push(lasso.selectedItems());
//color dots to hull groups
// for(var i=0;i<selections.length;i++){
// var selgroup = d3.selectAll(".selected"+selections.length);
// selgroup.select('circle')
// .attr('fill', colors(i+1));
// }
// Reset the style of the not selected dots
lasso.notSelectedItems()
.selectAll('circle')
.attr("r",5);
drawHulls();
}
simulation.restart();
};
var lasso = d3.lasso()
.closePathSelect(true)
.closePathDistance(100)
.items(circs)
.targetArea(svg)
.on("start",lasso_start)
.on("draw",lasso_draw)
.on("end",lasso_end);
svg.call(lasso);
}
function drawHulls(){
for(var i=0;i<selections.length;i++){
var vertices = selections[i]._groups[0].map(function(d){d3.select(d).style('fill', colors(i+1));return getTranslation(d3.select(d.parentNode).attr('transform'))});
var cHull = d3.polygonHull(vertices);
if(vertices.length >=3){
hulls[i]
.datum(cHull)
.attr("d", function(d) { return "M" + d.join("L") + "Z"; })
.attr('fill', colors(i+1));
}
}
}
function ticked() {
link
.attr("x1", function (d) {return Math.max(Math.min(d.source.x, width-radius*2), 0);})
.attr("y1", function (d) {return Math.max(Math.min(d.source.y, height-radius*2), 0);})
.attr("x2", function (d) {return Math.max(Math.min(d.target.x, width-radius*2), 0);})
.attr("y2", function (d) {return Math.max(Math.min(d.target.y, height-radius*2), 0);});
node
.attr("transform", function (d) {return "translate(" + Math.max(radius, Math.min(width - (radius), d.x)) + ", " + Math.max(radius, Math.min(height - (radius), d.y)) + ")";});
edgepaths.attr('d', function (d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
});
edgelabels.attr('transform', function (d) {
if (d.target.x < d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
}
else {
return 'rotate(0)';
}
});
drawHulls();
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart()
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
// function dragended(d) {
// if (!d3.event.active) simulation.alphaTarget(0);
// d.fx = undefined;
// d.fy = undefined;
// }
function deepcopy(obj){
return JSON.parse(JSON.stringify(obj))
}
function insertSM(smgraph, smli, smheight, smwidth){
var smsimulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {return d.id;}).distance(distc/9).strength(strenc))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(smwidth / 2, smheight / 2));
var links = deepcopy(smgraph.years[smli]), nodes = deepcopy(smgraph.nodes);
var smsvg = d3.selectAll('body')
.append('svg')
.attr('width', smwidth)
.attr('height', smheight)
.attr('gid', smli)
.classed('smsvg', true)
.on('click', function(d, i){
restart(graph.years[smli])
});
var link = smsvg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link")
.attr('marker-end','url(#arrowhead)')
var edgepaths = smsvg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attrs({
'class': 'edgepath',
'fill-opacity': 0,
'stroke-opacity': 0,
'id': function (d, i) {return smli+'smliedgepath' + i}
})
.style("pointer-events", "none");
var node = smsvg.selectAll(".node")
.data(nodes, function(d) { return(d); })
.enter()
.append("g")
.attr("class", "node")
// .call(d3.drag()
// .on("start", dragstarted)
// .on("drag", dragged)
// //.on("end", dragended)
// );
var circs = node.append("circle")
.attr("r", 2)
.style("fill", 'grey');
// On node hover, examine the links to see if their
// source or target properties match the hovered node.
smsimulation
.nodes(nodes)
.on("tick", smticked);
smsimulation.force("link")
.links(links);
function smticked() {
link
.attr("x1", function (d) {return Math.max(Math.min(d.source.x, smwidth), 0);})
.attr("y1", function (d) {return Math.max(Math.min(d.source.y, smheight), 0);})
.attr("x2", function (d) {return Math.max(Math.min(d.target.x, smwidth), 0);})
.attr("y2", function (d) {return Math.max(Math.min(d.target.y, smheight), 0);});
node
.attr("transform", function (d) {return "translate(" + Math.max(2, Math.min(smwidth, d.x)) + ", " + Math.max(2, Math.min(smheight, d.y)) + ")";});
}
}
// Make the DIV element draggable:
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
function nextSM(){
start = +d3.select('.smsvg:last-child').attr('gid')+1;
if (start < graph.years.length){
sms = d3.selectAll('.smsvg').remove().exit();
for(var i = start; i<start+7;i++){
insertSM(graph, i, 200, 200)
}
}
}
function prevSM(){
start = Math.max(0,(+d3.select('.smsvg').attr('gid'))-7);
sms = d3.selectAll('.smsvg').remove().exit();
for(var i = start; i<start+7;i++){
insertSM(graph, i, 200, 200)
}
}
</script>
</body>
</html>
Modified http://d3js.org/d3.v4.min.js to a secure url
Modified http://d3js.org/d3-selection-multi.v1.js to a secure url
https://d3js.org/d3.v4.min.js
https://d3js.org/d3-selection-multi.v1.js