Related
I'm new to d3 (and javascript) and this is my first time posting a question on Stackoverflow. Please let me know if my question is unclear or inappropriate. I would be very appreciated if you give any advice or help.
I'am having a difficulty with filtering nodes in force directed graph. I have searched and used the code posted on other question (D3 force-directed graph - filter nodes and associated links) to hide nodes and its associated links. However, I wasn't able to hide nodes whose links are all invisible.
Here's what I'm trying to do:
If all the links with that node are invisible, the node should also be invisible. Otherwise, if any link related to that node is visible, the node should be visible. I have found this code from jsfiddle.net (zhanghuancs/cuYu8/) but I was not able to use this code on mine.(I cound't figure out how to link jsfiddle code here.)
Could anyone help me?
Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Force Layout</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.1.0.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.11.0/jquery-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="https://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<style id="compiled-css" type="text/css">
.node {
stroke: #fff;
stroke-width: 0.5px;
}
.link {
stroke: #999;
stroke-opacity: .1;
}
d3-tip {
line-height: 1;
color: black;
}
div {
display: inline-block;
}
form {
display: inline-block;
}
svg {
border: solid 1px blue;
}
body,
.container {
background-color: white;
margin: 5px;
}
.graphContainer {
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
}
#sidebar{
position: absolute;
z-index: 2;
background-color: #FFF;
padding: 10px;
margin: 5px;
border: 1px solid #6895b4;
min-height: 3px;
width: 100px;
top:45px;
right:220px;
}
.item-group {
margin-bottom: 5px;
}
.item-group .item-label {
width: 90px;
text-align: right;
font-family: Arial,sans-serif;
font-size: 14px;
font-weight: bold;
position: relative;
min-height: 1px;
margin-top: 5px;
display: inline;
padding-right: 5px;
font-size: .90em;
}
.checkbox-interaction-group {
margin-left: 10px;
margin-top: 5px;
clear: both;
}
.checkbox-container {
display: block;
min-height: 30px;
vertical-align: middle;
margin-left: 10px;
}
.checkbox-container label{
display:inline;
margin-bottom: 0px;
}
</style>
</head>
<body>
<div id="container" class="container">
<div id="sidebar" style="display: none;">
<div class="item-group">
<label class="item-label">Filter</label>
<div id="filterContainer" class="filterContainer checkbox-interaction-group"></div>
</div>
</div>
<div id="graphContainer" class="graphContainer">
<script type="application/json" id="patent">
{
"nodes":[
{"label": "label1","title":"label1","group": "group1", "type": "label1", "s":1},
{"label": "label2","title":"label2","group": "group1", "type": "label2","s":1},
{"label": "label3","title":"label3","group": "group1", "type": "label3","s":1},
{"id":"5712454", "title": "title1", "group": "group2", "s":0},
{"id":"5497941", "title": "title2", "group": "group2", "s":0},
{"id":"5517952", "title": "title3", "group": "group2", "s":0},
{"id":"4854277", "title": "title4", "group": "group2", "s":0},
{"id":"9556782", "title": "title5", "group": "group2", "s":0}
],
"links":[
{"source": 3, "target": 0, "value": 1},
{"source": 3, "target": 1, "value": 1},
{"source": 3, "target": 2, "value": 1},
{"source": 4, "target": 0, "value": 1},
{"source": 5, "target": 2, "value": 1},
{"source": 6, "target": 1, "value": 1},
{"source": 7, "target": 2, "value": 1},
{"source": 7, "target": 0, "value": 1},
{"source": 6, "target": 2, "value": 1},
{"source": 5, "target": 1, "value": 1}
]
}
</script>
<!-- TODO: Missing CoffeeScript 2 -->
<script type="text/javascript">
//Constants for the SVG
var width = window.innerWidth,
height = window.innerHeight-47;
//Set up the colour scale
var color = d3.scale.category10();
//Set up the force layout
var force = d3.layout.force()
.charge(-200)
.linkDistance(20)
.size([width, height]);
// Set up zoom behavior
var zoom = d3.behavior.zoom().scaleExtent([0.1,5]).on("zoom",redraw);
//Append a SVG to the body of the html page. Assign this SVG as an object to svg
var svg = d3.select("body")
.append("svg")
.attr("width", width-240)
.attr("height", height)
.call(zoom)
.on("dblclick.zoom",null)
.append('g');
var svg2 = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", height);
//Set up tooltip
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function (d) {
return d.title + "</span>";
})
svg.call(tip);
//Read the data from the mis element
var patent = document.getElementById('patent').innerHTML;
graph = JSON.parse(patent);
//Creates the graph data structure out of the json data
force.nodes(graph.nodes)
.links(graph.links)
.start()
.friction(0.5);
//Create all the line svgs but without locations yet
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function (d) {return Math.sqrt(d.value);
});
//Do the same with the circles for the nodes - no
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("path")
.attr("class", "node")
.attr("d", d3.svg.symbol()
.type(function(d) { return d3.svg.symbolTypes[d.s]; }))
.style("fill", function (d) {return color(d.group);})
.call(force.drag)
.on('dblclick', connectedNodes)
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.on("click", function(d){
if (d3.event.shiftKey) {
var url = "https://patents.google.com/patent/US"+ d.id
alert("Redirecting you to " + url)
window.open(url,"", "width=800,height=800");
}
});
var label = svg.selectAll(".mytext")
.data(graph.nodes)
.enter()
.append("text")
.text(function (d) { return d.label; })
.style("text-anchor", "middle")
.style("fill","gray")
.style("font-family", "Arial")
.style("font-size", 8);
//Zoom and Pan function
function redraw() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
var drag = force.drag()
.on("dragstart", function(d) {
d3.event.sourceEvent.stopPropagation();
});
//Now we are giving the SVGs co-ordinates - the force layout is generating the co-ordinates which this code is using to update the attributes of the SVG elements
force.on("tick", function () {
link.attr("x1", function (d) {return d.source.x;})
.attr("y1", function (d) {return d.source.y;})
.attr("x2", function (d) {return d.target.x;})
.attr("y2", function (d) {return d.target.y;});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
label.attr("x", function(d){ return d.x; })
.attr("y", function (d) {return d.y - 10; });
});
//Highlight function
//Toggle stores whether the highlighting is on
var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < graph.nodes.length; i++) {
linkedByIndex[i + "," + i] = 1;
};
graph.links.forEach(function (d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
//This function looks up whether a pair are neighbours
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function connectedNodes() {
if (toggle == 0) {
//Reduce the opacity of all but the neighbouring nodes
d = d3.select(this).node().__data__;
node.style("opacity", function (o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1;
});
label.style("opacity", function (o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1;
});
link.style("opacity", function (o) {
return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1;
});
//Reduce the op
toggle = 1;
} else {
//Put them back to opacity=1
node.style("opacity", 1);
link.style("opacity", 1);
label.style("opacity",1);
toggle = 0;
}
}
//Search function
var optArray = [];
for (var i = 0; i < graph.nodes.length; i++) {
optArray.push(graph.nodes[i].title);
}
optArray = optArray.sort();
$(function () {
$("#search").autocomplete({
source: optArray
});
});
window.searchNode = searchNode;
function searchNode() {
//find the node
var selectedVal = document.getElementById('search').value;
if (selectedVal == "none") {
node.style("stroke", "white").style("stroke-width", "1");
} else {
var selected = node.filter(function (d, i) {
return d.title != selectedVal;
});
selected.style("opacity", "0");
link.style("opacity", "0");
label.style("opacity", "0");
d3.selectAll(".node, .link").transition()
.duration(2000)
.style("opacity", 1);
label.transition()
.duration(2000)
.style("opacity",1);
var selectedNode = node
.filter(function (d, i) { return d.title == selectedVal; })
.datum();
var scale = zoom.scale();
var desiredPosition = { x: (width-240)/2, y: height/2}; // constants, set to svg center point
zoom.translate([desiredPosition.x - selectedNode.x*scale, desiredPosition.y - selectedNode.y*scale]);
zoom.event(svg);
}
}
//Legend
var legend = svg2.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", 5)
.attr("y",5)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 30)
.attr("y", 13)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d });
// call method to create filter
createFilter();
// method to create filter
function createFilter(){
d3.select(".filterContainer").selectAll("div")
.data(["label1","label2","label3"])
.enter()
.append("div")
.attr("class", "checkbox-container")
.append("label")
.each(function(d) {
// create checkbox for each data
d3.select(this).append("input")
.attr("type", "checkbox")
.attr("id", function(d) {return "chk_" + d;})
.attr("checked", true)
.on("click", function(d, i) {
// register on click event
var lVisibility = this.checked? "visible":"hidden";
filterGraph(d, lVisibility);
})
d3.select(this).append("span")
.text(function(d){return d;});
});
$("#sidebar").show(); // show sidebar
}
var hidden_nodes =[];
// Method to filter graph
function filterGraph(aType, aVisibility){
// change the visibility of the node
// if all the links with that node are invisibile, the node should also be invisible
// otherwise if any link related to that node is visibile, the node should be visible
// change the visibility of the connection link
node.style("visibility", function(o) {
var lOriginalVisibility = $(this).css("visibility");
if (o.type == aType) {
if (aVisibility == "hidden")
{
hidden_nodes.push(o.title);
}
else
{
index = hidden_nodes.indexOf(o.title);
if (index > -1)
{
hidden_nodes.splice(index, 1);
}
}
}
return o.type === aType ? aVisibility : lOriginalVisibility;
});
label.style("visibility", function(o) {
var lOriginalVisibility = $(this).css("visibility");
if (o.type == aType) {
if (aVisibility == "hidden")
{
hidden_nodes.push(o.title);
}
else
{
index = hidden_nodes.indexOf(o.title);
if (index > -1)
{
hidden_nodes.splice(index, 1);
}
}
}
return o.type === aType ? aVisibility : lOriginalVisibility;
});
link.attr("display", function (o) {
////Here the structure of the the link can vary, sometimes it is o["source"]["name"], sometimes it is o["source"]["name"], check it out before you fill in.
var source_name = o["source"]["title"];
var target_name = o["target"]["title"];
var result = hidden_nodes.indexOf(source_name) != -1 || hidden_nodes.indexOf(target_name) != -1 ? "none" : "auto"
return result;
})
;
}
</script>
</div>
</body>
</html>
I would like help to correct my code to click the marker circle element to pause or resume transition of this element along the line. My code moves marker along a line and I can pause and resume this transition using on click on button element but I would like to be able to click on the marker circle itself, not the button. I have used various references including :
http://www.nytimes.com/interactive/2013/09/25/sports/americas-cup-course.html
http://jsfiddle.net/meetamit/UJuWX/3/
http://jsfiddle.net/Y62Hq/2/
D3 tween - pause and resume controls
I would ultimately like to be able animate a marker along a geo path, pause and resume this at points along the path and click through on these points.
this is my code so far:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Need help</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-queue.v3.min.js"></script>
<style type="text/css">
body{
font-family:"Helvetica Neue", Helvetica, sans-serif;
color: red;
}
button {
position: absolute;
top: 15px;
left: 10px;
background: #004276;
padding-right: 26px;
border-radius: 2px;
cursor: pointer;
}
circle {
fill: steelblue;
stroke: pink;
stroke-width: 3px;
}
.point{
fill:green;
}
.line{
fill: none;
stroke: red;
stroke-width: 4;
stroke-dasharray: 4px,8px;
}
</style>
</head>
<body>
<button>Start</button>
<script>
var w = 960,
h = 500;
var duration = 10000;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var line = d3.line()
.x(function(d){return (d)[0];})
.y(function(d){return (d)[1];});
var data =
[
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
//path to animate
var linepath = svg.append("path")
.data([data])
.attr("d", line)
.attr('class', 'line')
.attr("d", function(d){
console.log(this);
return line(d)
});
var points = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 7)
.attr("transform", function(d) { return "translate(" + (d) + ")"; })
.attr("class", "point");
var pauseValues = {
lastTime: 0,
currentTime: 0
};
var marker = svg.append("circle")
.attr("r", 19)
.attr("transform", "translate(" + (data[0]) + ")")
.on('click', function(d,i){
d3.select(this)
.style("fill", "orange")
.transition()
});
function transition() {
marker.transition()
.duration(duration - (duration * pauseValues.lastTime))
.attrTween("transform", translateAlong(linepath.node()))
.on("end", function(){
pauseValues = {
lastT: 0,
currentT: 0
};
transition()
});
}
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
t += pauseValues.lastTime;
var p = path.getPointAtLength(t * l);
pauseValues.currentTime = t;
return "translate(" + p.x + "," + p.y + ")";
};
};
}
d3.select('button').on('click',function(d,i){
var self = d3.select(this);
if (self.text() == "Pause"){
self.text('Start');
marker.transition()
.duration(0);
setTimeout(function(){
pauseValues.lastTime = pauseValues.currentTime;
}, 100);
}else{
self.text('Pause');
transition();
}
});
</script>
</body>
</html>
To check if the circle is moving in the click function use d3.active(), which...
... returns null if there is no such active transition on the specified node.
Like this:
.on('click', function(d, i) {
if (d3.active(this)) {
marker.transition();
setTimeout(function() {
pauseValues.lastTime = pauseValues.currentTime;
}, 100);
} else {
transition();
}
});
Here is your code with that change:
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-queue.v3.min.js"></script>
<style type="text/css">
body {
font-family: "Helvetica Neue", Helvetica, sans-serif;
color: red;
}
button {
position: absolute;
top: 15px;
left: 10px;
background: #004276;
padding-right: 26px;
border-radius: 2px;
cursor: pointer;
}
circle {
fill: steelblue;
stroke: pink;
stroke-width: 3px;
}
.point {
fill: green;
}
.line {
fill: none;
stroke: red;
stroke-width: 4;
stroke-dasharray: 4px, 8px;
}
</style>
<body>
<button>Start</button>
<script>
var w = 960,
h = 500;
var duration = 10000;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var line = d3.line()
.x(function(d) {
return (d)[0];
})
.y(function(d) {
return (d)[1];
});
var data = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
//path to animate
var linepath = svg.append("path")
.data([data])
.attr("d", line)
.attr('class', 'line')
.attr("d", function(d) {
return line(d)
});
var points = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 7)
.attr("transform", function(d) {
return "translate(" + (d) + ")";
})
.attr("class", "point");
var pauseValues = {
lastTime: 0,
currentTime: 0
};
var marker = svg.append("circle")
.attr("r", 19)
.attr("transform", "translate(" + (data[0]) + ")")
.on('click', function(d, i) {
if (d3.active(this)) {
marker.transition();
setTimeout(function() {
pauseValues.lastTime = pauseValues.currentTime;
}, 100);
} else {
transition();
}
});
function transition() {
marker.transition()
.duration(duration - (duration * pauseValues.lastTime))
.attrTween("transform", translateAlong(linepath.node()))
.on("end", function() {
pauseValues = {
lastT: 0,
currentT: 0
};
transition()
});
}
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
t += pauseValues.lastTime;
var p = path.getPointAtLength(t * l);
pauseValues.currentTime = t;
return "translate(" + p.x + "," + p.y + ")";
};
};
}
d3.select('button').on('click', function(d, i) {
var self = d3.select(this);
if (self.text() == "Pause") {
self.text('Start');
marker.transition()
.duration(0);
setTimeout(function() {
pauseValues.lastTime = pauseValues.currentTime;
}, 100);
} else {
self.text('Pause');
transition();
}
});
</script>
</body>
I have a parallel coordinates visualization and I've added a table below that represents all the data in the visualization.
I want to filter the table based on the selection of the parallel coordinates visualization. So, just showing the data highlighted in the parallel coordinates visualization.
Any ideas on how to do that?
I've tried in the brush section to highlight the cells in the table in red adding a style in for the tags, but it doesn't seem to work. See code below:
// Add and store a brush for each axis.
g.append("g")
.attr("class", "brush")
.each(function(d) {
d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brushstart", brushstart).on("brush", brush));
d3.selectAll("td").style('bgcolor', 'red');
})
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
I've tried to add the highlight of the cells in the brush function. Here I achieve for all the cells to turn red, but I don't know how to highlight only the ones selected in the selection.
function brush() {
var actives = dimensions.filter(function(p) {
return !y[p].brush.empty();
}),
extents = actives.map(function(p) {
return y[p].brush.extent();
});
foreground.style("display", function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? null : "none";
});
d3.selectAll("td").style('background-color', 'red');
}
See code below, which you can find also in the following link GitHub:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.background path {
fill: none;
stroke: #ddd;
shape-rendering: crispEdges;
}
.foreground path {
fill: none;
stroke: steelblue;
stroke-width: 2;
}
.brush .extent {
fill-opacity: .3;
stroke: #fff;
shape-rendering: crispEdges;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
cursor: move;
}
.tooltip {
background-color: rgba(220,220,220,0.5);
color: #333;
margin: 10px;
height: 25px;
padding-right: 10px;
padding-left: 10px;
padding-top: 10px;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
td, th {
padding: 1px 4px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Fuente original: https://bl.ocks.org/jasondavies/1341281
var margin = {
top: 30,
right: 10,
bottom: 10,
left: 10
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangePoints([0, width], 1),
y = {},
dragging = {};
var line = d3.svg.line(),
axis = d3.svg.axis().orient("left"),
background,
foreground;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var notas = [
{
"Nombre": "Emily",
"Matematicas": "10",
"Ciencias": "10",
"Historia": "8",
"Geografia": "8",
"Lengua": "10"
},
{
"Nombre": "Cooper",
"Matematicas": "10",
"Ciencias": "7",
"Historia": "2",
"Geografia": "8",
"Lengua": "10"
}];
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip")
.attr("class","tooltip");
// Extract the list of dimensions and create a scale for each.
x.domain(dimensions = d3.keys(notas[0]).filter(function(d) {
return d != "Nombre" && (y[d] = d3.scale.linear()
.domain(d3.extent(notas, function(p) {
return +p[d];
}))
.range([height, 0]));
}));
// Add grey background lines for context.
background = svg.append("g")
.attr("class", "background")
.selectAll("path")
.data(notas)
.enter().append("path")
.attr("d", path);
// Add blue foreground lines for focus.
foreground = svg.append("g")
.attr("class", "foreground")
.selectAll("path")
.data(notas)
.enter().append("path")
.attr("d", path)
.on("mouseover", function(n){
d3.select(this)
.transition().duration(100)
.style({'stroke' : '#F00'});
tooltip.text(n.Nombre);
return tooltip.style("visibility", "visible");
})
.on("mousemove", function(){
return tooltip
.style("top", (event.pageY-10)+"px")
.style("left",(event.pageX+10)+"px");
})
.on("mouseout", function(d){
d3.select(this)
.transition().duration(100)
.style({'stroke': 'steelblue' })
.style({'stroke-width' : '2'});
return tooltip.style("visibility", "hidden");
});
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function(d) {
return "translate(" + x(d) + ")";
})
.call(d3.behavior.drag()
.origin(function(d) {
return {
x: x(d)
};
})
.on("dragstart", function(d) {
dragging[d] = x(d);
background.attr("visibility", "hidden");
})
.on("drag", function(d) {
dragging[d] = Math.min(width, Math.max(0, d3.event.x));
foreground.attr("d", path);
dimensions.sort(function(a, b) {
return position(a) - position(b);
});
x.domain(dimensions);
g.attr("transform", function(d) {
return "translate(" + position(d) + ")";
})
})
.on("dragend", function(d) {
delete dragging[d];
transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")");
transition(foreground).attr("d", path);
background
.attr("d", path)
.transition()
.delay(500)
.duration(0)
.attr("visibility", null);
}));
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function(d) {
d3.select(this).call(axis.scale(y[d]));
})
.append("text")
.style("text-anchor", "middle")
.attr("y", -9)
.text(function(d) {
return d;
});
// Add and store a brush for each axis.
g.append("g")
.attr("class", "brush")
.each(function(d) {
d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brushstart", brushstart).on("brush", brush));
})
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
function position(d) {
var v = dragging[d];
return v == null ? x(d) : v;
}
function transition(g) {
return g.transition().duration(500);
}
// Returns the path for a given data point.
function path(d) {
return line(dimensions.map(function(p) {
return [position(p), y[p](d[p])];
}));
}
function brushstart() {
d3.event.sourceEvent.stopPropagation();
}
// Handles a brush event, toggling the display of foreground lines.
function brush() {
var actives = dimensions.filter(function(p) {
return !y[p].brush.empty();
}),
extents = actives.map(function(p) {
return y[p].brush.extent();
});
foreground.style("display", function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? null : "none";
});
}
// The table generation function
function tabulate(data, columns) {
var table = d3.select("body").append("table")
.attr("style", "margin-left: 250px"),
thead = table.append("thead"),
tbody = table.append("tbody");
// append the header row
thead.append("tr")
.selectAll("th")
.data(columns)
.enter()
.append("th")
.text(function(column) { return column; });
// create a row for each object in the data
var rows = tbody.selectAll("tr")
.data(notas)
.enter()
.append("tr");
// create a cell in each row for each column
var cells = rows.selectAll("td")
.data(function(row) {
return columns.map(function(column) {
return {column: column, value: row[column]};
});
})
.enter()
.append("td")
.attr("style", "font-family: Courier") // sets the font style
.html(function(d) { return d.value; });
return table;
}
// render the table
var peopleTable = tabulate(notas, ["Nombre", "Matematicas","Ciencias", "Historia","Geografia", "Lengua"]);
</script>
</body>
</html>
I've added also the code in JSFiddle but it doesn't display anything. I'm not sure what I'm doing wrong. I'm not familiar with JSFiddle, so I might be doing something wrong.
I've tried also to use divgrid (DivGrid) and with the following code I can see how when I attempt to brush the table gets updated. The problem is that it doesn't get updated with the data I need. I just have it to show 5 records.
<script src="divgrid.js"></script>
...
// Handles a brush event, toggling the display of foreground lines.
function brush() {
var actives = dimensions.filter(function(p) {
return !y[p].brush.empty();
}),
extents = actives.map(function(p) {
return y[p].brush.extent();
});
foreground.style("display", function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? null : "none";
});
//d3.selectAll("td").style('background-color', 'red');
var grid = d3.divgrid();
d3.select('body')
.datum(notas.slice(0,5))
.call(grid);
}
The problems I have (I think) is that (1) the update of the table is not really in the right place as it is only updating when starting to brush, not when brushing over the lines and (2) I need to find a way to pickup the data from the lines that are selected. I've added to code in github as a reference (GitHub)
Any ideas?
Thanks
I need to represent each data in rectangle. I used grid layout using the below one
http://bl.ocks.org/herrstucki/5684816 My data is really huge its around 1700. When i tries to plot, its taking long time and sometime the browser hangs. Here is my plunker https://plnkr.co/edit/Xzr3RoQlm7DSiIuexmFz Please help
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: Helvetica;
font-size: 10px;
}
.point, .rect {
fill: #222;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="d3-grid.js"></script>
<script>
var rects = [];
var width = 960,
height = 500;
var rectGrid = d3.layout.grid()
.bands()
.size([360, 360])
.padding([0.1, 0.1]);
var svg = d3.select("body").append("svg")
.attr({
width: width,
height: height
})
.append("g")
.attr("transform", "translate(0,0)");
for(var i=0; i<1700; i++){
push();
}
function update() {
var rect = svg.selectAll(".rect")
.data(rectGrid(rects));
rect.enter().append("rect")
.attr("class", "rect")
.attr("width", rectGrid.nodeSize()[0])
.attr("height", rectGrid.nodeSize()[1])
.attr("transform", function(d) { return "translate(" + (d.x)+ "," + d.y + ")"; })
.style("opacity", 1e-6);
rect.transition()
.attr("width", rectGrid.nodeSize()[0])
.attr("height", rectGrid.nodeSize()[1])
.attr("transform", function(d) { return "translate(" + (d.x)+ "," + d.y + ")"; })
.style("opacity", 1);
rect.exit().transition()
.style("opacity", 1e-6)
.remove();
}
function push() {
rects.push({});
update();
}
</script>
You need to wait for one set of updates and transitions to finish before starting the next round. Borrowing from this question and applying it to your code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: Helvetica;
font-size: 10px;
}
.point, .rect {
fill: #222;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://rawgit.com/interactivethings/d3-grid/master/d3-grid.js"></script>
<script>
var rects = [];
var width = 960,
height = 500;
var rectGrid = d3.layout.grid()
.bands()
.size([360, 360])
.padding([0.1, 0.1]);
var svg = d3.select("body").append("svg")
.attr({
width: width,
height: height
})
.append("g")
.attr("transform", "translate(0,0)");
var rectC = 1;
rects.push({});
function update() {
var rect = svg.selectAll(".rect")
.data(rectGrid(rects));
rect.enter().append("rect")
.attr("class", "rect")
.attr("width", rectGrid.nodeSize()[0])
.attr("height", rectGrid.nodeSize()[1])
.attr("transform", function(d) { return "translate(" + (d.x)+ "," + d.y + ")"; })
.style("opacity", 1e-6);
var transitions = 0;
rect
.transition()
.duration(50)
.attr("width", rectGrid.nodeSize()[0])
.attr("height", rectGrid.nodeSize()[1])
.attr("transform", function(d) { return "translate(" + (d.x)+ "," + d.y + ")"; })
.style("opacity", 1)
.each( "start", function() {
transitions++;
}).each( "end", function() {
if( --transitions === 0 ) {
rects.push({});
rectC += 1;
if (rectC < 1700) update();
}
});
rect.exit().transition()
.style("opacity", 1e-6)
.remove();
}
update();
</script>
I have trouble to add paths to a g element created by the nodes with selectAll:
// define the nodes
var node = svg.selectAll(".node").data(force.nodes()).enter()
.append("g").attr("id", function(d) {
return d.id;
}).attr("class", "node").style("fill", function(d) {
return color(d.group);
}).call(force.drag);
// add the nodes
...
// add the links and the arrows
var path = node.selectAll("g").data(force.links(), function(d) {
return d.id
}).append("path")
// .attr("class", function(d) { return "link " + d.type; })
.attr("class", "link").attr("marker-end", "url(#end)");
The input data looks like this:
{
"nodes": [
{
"id": 0,
"name": "N1",
"group": 4
},
{
"id": 1,
"name": "N2",
"group": 1
},
{
"id": 2,
"name": "N3",
"group": 1
}
],
"links": [
{
"id": 0,
"source": 0,
"target": 1
},
{
"id": 0,
"source": 0,
"target": 2
}
]
}
I'm trying to modify this example
My goal is that a node has a mouse over (.node:hover) including all the out-going links. With my simple data it would look like that node N1 would have a mouse over including the two links.
Thanks for your help!
Here is all the code:
<!DOCTYPE html>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.js"></script>
<style>
.node {
opacity: 0.8;
stroke: #fff;
stroke-width: 1.5px;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
stroke-width: 0px;
}
.node:hover {
opacity: 1;
}
path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
</style>
<body>
<script>
// get the data
d3.json("data2.json", function(error, graph) {
var color = d3.scale.category20();
var width = 960, height = 500;
var force = d3.layout.force().nodes(graph.nodes).links(graph.links)
.size([ width, height ]).linkDistance(300).charge(-300).on(
"tick", tick).start();
var svg = d3.select("body").append("svg").attr("width", width)
.attr("height", height);
// build the arrow.
svg.append("svg:defs").selectAll("marker").data([ "end" ]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String).attr("viewBox", "0 -5 10 10").attr("refX", 15)
.attr("refY", -1.5).attr("markerWidth", 6).attr(
"markerHeight", 6).attr("orient", "auto").append(
"svg:path").attr("d", "M0,-5L10,0L0,5");
// define the nodes
var node = svg.selectAll(".node").data(force.nodes()).enter()
.append("g").attr("id", function(d) {
return d.id;
}).attr("class", "node").style("fill", function(d) {
return color(d.group);
}).call(force.drag);
// add the nodes
node.append("circle").attr("r", function(d) {
return 3 * d.group
});
// add the text
node.append("text").attr("x", 12).attr("dy", ".35em").style(
"color", "black").text(function(d) {
return d.name;
});
// add the links and the arrows
var path = node.selectAll("g").data(force.links(), function(d) {
return d.id
}).append("path")
// .attr("class", function(d) { return "link " + d.type; })
.attr("class", "link").attr("marker-end", "url(#end)");
// add the curvy lines
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x, dy = d.target.y
- d.source.y, dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + ","
+ dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
});
</script>
</body>
</html>
I solved my issue with mouseover and mouseout:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="author" content="myborobudur">
<meta name="date" content="2014-09-02T00:00:00+01:00">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Job Recommender: d3js Graph Study</title>
<script src="http://d3js.org/d3.v3.js"></script>
<style>
.node {
opacity: 0.8;
stroke: #fff;
stroke-width: 1.5px;
}
.text {
pointer-events: none;
font: 12px sans-serif;
stroke-width: 0px;
color: #000;
}
.node:hover {
opacity: 1;
}
path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<h2>Job Recommender: d3js Graph Study</h2>
<script>
function selectLinks(thisObject) {
changeLinkStyle(thisObject, function(node, link) {
link.style("stroke", node.attr("fillColor"));
link.style("stroke-width", "10px");
link.style("opacity", "0.5");
link.attr("marker-end", "");
});
}
function deSelectLinks(thisObject) {
changeLinkStyle(thisObject, function(node, link) {
link.style("stroke", "#666");
link.style("stroke-width", "1.5px");
link.style("opacity", "1");
link.attr("marker-end", "url(#end)");
});
}
function changeLinkStyle(thisObject, changeStyle) {
var source = d3.select(thisObject);
var sourceId = d3.select(thisObject).attr('id');
d3.selectAll('.link').each(function(d, i) {
var link = d3.select(this);
var linkSourceId = link.attr('source');
if (linkSourceId === sourceId) {
changeStyle.call(undefined, source, link);
}
});
}
// get the data
d3.json("data.json", function(error, graph) {
var color = d3.scale.category20();
var width = 1200, height = 800;
var force = d3.layout.force().nodes(graph.nodes).links(graph.links)
.size([ width, height ])
.linkDistance(300)
.charge(-300)
.on("tick", tick)
.start();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// build the arrow.
svg.append("svg:defs").selectAll("marker")
.data([ "end" ]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
// add the links and the arrows
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", "link")
.attr("source", function(d) { return d.source.id })
.attr("marker-end", "url(#end)");
// define the nodes
var node = svg.selectAll(".node").data(force.nodes())
.enter().append("g").call(force.drag);
// add the nodes
node.append("circle").attr("id", function(d) { return d.id })
.attr("fillColor", function(d) { return color(d.group); })
.attr("onmouseover", "selectLinks(this)")
.attr("onmouseout", "deSelectLinks(this)")
.attr("class", "node")
.attr("r", function(d) { return 3 * d.group })
.style("fill", function(d) { return color(d.group); });
// add the text
node.append("text").attr("x", 12)
.attr("dy", ".35em")
.attr("class", "text")
.text(function(d) { return d.name; });
// add the curvy lines
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
});
</script>
</body>
</html>