I'm pretty new to d3 and have been following this tutorial: http://christopheviau.com/d3_tutorial/
I'm stuck on the 'Binding Data' example - it's pretty simple but the code just won't produce anything. I've poked around here and haven't found the question listed so I thought I'd ask away.
Here's the code:
var dataset = [],
i = 0;
for(i = 0; i < 5; i++) {
dataset.push(Math.round(Math.random() * 100));
}
var sampleSVG = d3.select("#viz")
.append("svg")
.attr("width", 400)
.attr("height", 75);
sampleSVG.selectAll("circle")
.data(dataset)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("height", 40)
.attr("width", 75)
.attr("x", function (d, i) {
return i * 80
})
.attr("y", 20);
Other examples on the site work fine.
Thanks in advance - any ideas would be appreciated.
Unfortunately the code listed in the tutorial is incorrect. The svg element "circle" is specified by three attributes, "cx", x-axis coordinate of the center of the circle, "cy", y-axis coordinate of the center of the circle, and "r", the radius of the circle. I got this information from the w3 specification for an SVG circle.
I would recommend inspecting the JavaScript in the tutorial page to help iron out any other inconsistencies. Here it is:
<script type="text/javascript">
var dataset = [],
i = 0;
for(i=0; i<5; i++){
dataset.push(Math.round(Math.random()*100));
}
var sampleSVG = d3.select("#viz5")
.append("svg")
.attr("width", 400)
.attr("height", 100);
sampleSVG.selectAll("circle")
.data(dataset)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", function(d, i){return i*80+40})
.attr("cy", 50)
.on("mouseover", function(){d3.select(this).style("fill", "aliceblue");})
.on("mouseout", function(){d3.select(this).style("fill", "white");})
.on("mousedown", animateFirstStep);
function animateFirstStep(){
d3.select(this)
.transition()
.delay(0)
.duration(1000)
.attr("r", 10)
.each("end", animateSecondStep);
};
function animateSecondStep(){
d3.select(this)
.transition()
.duration(1000)
.attr("r", 40);
};
</script>
I also created a JSFiddle which you can utilize to get the basic idea that the author of the tutorial is trying to convey, with respect to utilizing d3.js data, here.
svg circles use cx, cy, and r - not x, y, height, and width. I've correct the example code below:
var dataset = [];
for(var i = 0; i < 5; i++) {
dataset.push(Math.round(Math.random() * 100));
}
var sampleSVG = d3.select("#viz")
.append("svg")
.attr("width", 400)
.attr("height", 400);
sampleSVG.selectAll("circle")
.data(dataset)
.enter().append("circle")
.style("stroke", "black")
.attr("r", 10)
.attr("cx", function (d, i) {
return i * 80 + 10;
})
.attr("cy", function (d, i) {
return d;
});
http://jsfiddle.net/q3P4v/7/
MDN on svg circles: https://developer.mozilla.org/en-US/docs/SVG/Element/circle
Related
I know that similar questions have been asked before here on stackoverflow, but I have fairly specific requirements. I'm trying to generate a pulsing dot for a D3 chart.
I modified some code on codepen.io and came up with this.
How would I do the same thing using a D3 transition() rather than the (cheesy) CSS classes?
Something more along the lines of:
circle = circle.transition()
.duration(2000)
.attr("stroke-width", 20)
.attr("r", 10)
.transition()
.duration(2000)
.attr('stroke-width', 0.5)
.attr("r", 200)
.ease('sine')
.each("end", repeat);
Feel free to fork my sample pen.
Thanks!
Have a look at the example on GitHub by whityiu
Note that this is using d3 version 3.
I have adapted that code to produce something like you are after in the fiddle below.
var width = 500,
height = 450,
radius = 2.5,
dotFill = "#700f44",
outlineColor = "#700f44",
pulseLineColor = "#e61b8a",
bgColor = "#000",
pulseAnimationIntervalId;
var nodesArray = [{
"x": 100,
"y": 100
}];
// Set up the SVG display area
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.attr("fill", bgColor)
.classed('visual-area', true);
var bgRect = d3.select("svg").append("rect")
.attr("width", width)
.attr("height", height);
var linkSet = null,
nodeSet = null;
// Create data object sets
nodeSet = svg.selectAll(".node").data(nodesArray)
.enter().append("g")
.attr("class", "node")
.on('click', function() {
// Clear the pulse animation
clearInterval(pulseAnimationIntervalId);
});
// Draw outlines
nodeSet.append("circle")
.classed("outline pulse", true)
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("fill", 'none')
.attr("stroke", pulseLineColor)
.attr("r", radius);
// Draw nodes on top of outlines
nodeSet.append("circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("fill", dotFill)
.attr("stroke", outlineColor)
.attr("r", radius);
// Set pulse animation on interval
pulseAnimationIntervalId = setInterval(function() {
var times = 100,
distance = 8,
duration = 1000;
var outlines = svg.selectAll(".pulse");
// Function to handle one pulse animation
function repeat(iteration) {
if (iteration < times) {
outlines.transition()
.duration(duration)
.each("start", function() {
d3.select(".outline").attr("r", radius).attr("stroke", pulseLineColor);
})
.attrTween("r", function() {
return d3.interpolate(radius, radius + distance);
})
.styleTween("stroke", function() {
return d3.interpolate(pulseLineColor, bgColor);
})
.each("end", function() {
repeat(iteration + 1);
});
}
}
if (!outlines.empty()) {
repeat(0);
}
}, 6000);
Fiddle
Here is my code:
<html>
<head>
<meta charset="UTF-8">
<title>circle</title>
</head>
<body>
<script src="http://d3js.org/d3.v4.min.js"></script>
<script>
var width = 400;
var height = 400;
var svg = d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
var circle1 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 45)
.style("fill","green");
circle1.transition()
.duration(1000) //延迟1000ms
.attr("cx", 300);
var circle2 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 45)
.style("fill","green");
circle2.transition()
.duration(1500)
.attr("cx", 300)
.style("fill", "red");
var circle3 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 45)
.style("fill","green");
circle3.transition()
.duration(2000)
.transition()
.ease("bounce")
.attr("cx", 300)
.style("fill", "red")
.attr("r", 25);
</script>
</body>
</html>
When I learn how to use the .ease("bounce")in d3 v4.x, the error is always jump out in html:45. In the official introduction: .ease("bounce") now should be used like this:
d3.easeBounce(t)
but it also doesn't work, so I don't know how to modify it. Could you give me a good introduction? Thanks!
The documentation on transition.ease([value]) tells us, that
The value must be specified as a function.
Therefore, you just need to pass in the easing function d3.easeBounce without actually calling it (note, that there are no parentheses following d3.easeBounce):
circle3.transition()
.duration(2000)
.transition()
.ease(d3.easeBounce) // Pass in the easing function
I agree with Altocumulus's answer, but I try to get rid of one of the middle.transition(), and it will run well.
circle3.transition()
.duration(2000)
.ease(d3.easeBounce)
Question: Is it possible for me to make each node individually, and then use the force layout to connect them? If not, how would I go about pre-placing the nodes? And if so, can I get some help with the syntax, please?
Context: I am new to D3, and am trying to make a force-directed graph for only five nodes as part of the landing page for an academic project. I am using this example and this example, and sort of want to make a combination of the two by putting my nodes in the arrays.
For example, could I do something like:
var w = 1300;
var h = 10000;
//An area for svg elements
var svgArea = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
//All the node definitions
var nodeMain = svgArea.append("a")
.attr("height", 300)
.attr("width", 300)
.append("circle")
.attr("r", 300)
.attr("cx", 650)
.attr("cy", 700)
.attr("fill", "orange");
var nodeMedia = svgArea.append("a")
.attr("height", 200)
.attr("width", 200)
.append("circle")
.attr("r", 200)
.attr("cx", 250)
.attr("cy", 1150)
.attr("fill", "orange");
var nodeRef = svgArea.append("a")
.attr("height", 200)
.attr("width", 200)
.append("circle")
.attr("r", 200)
.attr("cx", 1050)
.attr("cy", 1150)
.attr("fill", "orange");
//Nodes for the visualization
var nodes = [nodeMain, nodeMedia, nodeRef];
//Connected using indices of the array
var edges = [{source: 1, target: 0}, {source: 2, target: 0}];
//Force-directed
var connect = d3.layout.force()
.size([w, h])
.gravity(1)
.distance(100)
.charge(-50);
connect.nodes(nodes).links(edges);
var orb = svgArea.selectAll(".node").data(nodes)
.enter().append("g")
.call(force.drag);
var link = svgArea.selectAll(".link").data(edges)
.enter()
.append("line")
.attr("class", "link");
connect.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.source.x})
.attr("y2", function(d) {return d.source.y});
orb.attr("transform", function(d){ return "translate(" + d.x + "," + d.y + ")";});
});
connect.start();
(And in the event I asked a really silly question, would anyone mind directing me to some D3 resources where I can learn more of the concepts/syntax without emulating/relying purely on examples?)
Thank you in advance, everyone!
I have made slight changes in your code snippet and added necessary comments. Share your queries if any.
var w = 500;
var h = 500;
//An area for svg elements
var svgArea = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
//Nodes for the visualization
var nodes = [{
name: "Main",
x: 80,
y: 10
}, {
name: "Media",
x: 15,
y: 40
}, {
name: "Reference",
x: 60,
y: 60
}];
//Connected using indices of the array
var edges = [{
source: 1,
target: 0
}, {
source: 2,
target: 0
}];
//Force-directed
var connect = d3.layout.force()
.size([w, h])
.gravity(1)
.distance(150)
.charge(-200);
connect
.nodes(nodes)
.links(edges);
//Creating links
var link = svgArea.selectAll(".link")
.data(edges)
.enter()
.append("line")
.attr("class", "link")
.style("stroke", "black");
//Creating nodes
var orb = svgArea.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node");
orb.append("circle")
.attr("r", 10)
.style("fill", "orange");
//Adding Labels
orb.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) {
return d.name
});
//Adding images
orb.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -10)
.attr("y", -10)
.attr("width", 20)
.attr("height", 20);
orb.on("click",function(d){
alert("clicked "+d.name);
});
connect.on("tick", function() {
//Updating the link positions during force simulation.
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
});
//Updating the node position during force simulation
orb.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
connect.start();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
D3 has a rich documentation which is available here: GitHub
Fiddle: https://jsfiddle.net/gilsha/kv05y1hq/
If it's of any help I have the following Plunkers...
http://plnkr.co/edit/TiKKmvydqXNipe103juL?p=preview
http://plnkr.co/edit/ZSmvH05nnAD6cYZb0EM4?p=preview
The first one is to show/hide groups of elements when clicked on.
The second is to demonstrate drag/zoom.
Also the data is externalised into a json file and read in using...
d3.json("data.json", function(error, graph) {
This should enable you to reduce your node definitions down to one function.
I'm trying to create a circular avatar with D3.js but I cannot get my image to show up in my circle. I'm using a svg pattern def to attempt to fill the circle with an image.
Can anyone tell me what I'm doing wrong below? Thank you.
var config = {
"avatar_size" : 48
}
var body = d3.select("body");
var svg = body.append("svg")
.attr("width", 500)
.attr("height", 500);
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "grump_avatar")
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", 'images/avatars/avatar_grumpy.png')
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("x", 0)
.attr("y", 0);
var circle = svg.append("circle")
.attr("cx", config.avatar_size)
.attr("cy", config.avatar_size)
.attr("r", config.avatar_size)
.style("fill", "#fff")
.style("fill", "#grump_avatar");
"Fill" is a style property, you have to use CSS url() notation for the reference to the pattern element.
Once you fix that, you'll discover that you also have your sizes wrong -- unless your intention was to have four copies of the avatar tiled in the circle!
P.S. I would normally have left this just as a comment, and marked this for closure as a simple typo, but I wanted to try out Stack Snippets:
var config = {
"avatar_size" : 48
}
var body = d3.select("body");
var svg = body.append("svg")
.attr("width", 500)
.attr("height", 500);
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "grump_avatar")
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", 'http://placekitten.com/g/48/48')
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("x", 0)
.attr("y", 0);
var circle = svg.append("circle")
.attr("cx", config.avatar_size/2)
.attr("cy", config.avatar_size/2)
.attr("r", config.avatar_size/2)
.style("fill", "#fff")
.style("fill", "url(#grump_avatar)");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I've tried the circle plot example as the following:
var x=20, y=20, r=50;
var sampleSVG = d3.select("#viz")
.append("svg")
.attr("width", 800)
.attr("height", 600);
sampleSVG.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", r)
.attr("cx", x)
.attr("cy", y);
But I want to figure out how to plot without a loop a sequence of circles from an array like:
data = [
[10,20,30],
[20,30,15],
[30,10,25]
];
Maybe this example could help?
var data = [
[10,20,30],
[20,30,15],
[30,10,25]
];
var height = 300,
width = 500;
var svg = d3.select('body').append('svg')
.attr('height', height)
.attr('width', width)
.append('g')
.attr('transform', 'translate(30, 30)');
// Bind each nested array to a group element.
// This will create 3 group elements, each of which will hold 3 circles.
var circleRow = svg.selectAll('.row')
.data(data)
.enter().append('g')
.attr('transform', function(d, i) {
return 'translate(30,' + i * 60 + ')';
});
// For each group element 3 circle elements will be appended.
// This is done by binding each element in a nested array to a
// circle element.
circleRow.selectAll('.circle')
.data(function(d, i) { return data[i]; })
.enter().append('circle')
.attr('r', function(d) { return d; })
.attr('cx', function(d, i) { return i * 60; })
.attr('cy', 0);
Live Fiddle