D3js chained animations as function of JSON - d3.js

I am learning D3js and trying to chain some animations together.
Basically I have three svg elements that I want to simultaneously transition. There is a circle, a rectangle, and a text element.
For example, I am trying to make the circle transition from black to green, the rectangle transition from black to blue, and replace the text with a fade out, fade in effect.
I can do this one time, but I want a series of these animations to occur in sequence.
Here is the first fiddle of 1 transition working:
http://jsfiddle.net/mgcdanny/6nbRK/
Here is my attempt to sequence these using a for loop and JSON, but only the last transition happens:
http://jsfiddle.net/mgcdanny/U7StQ/
Perhaps this would be better as a series of enter(), update(), exit() commands?
Thanks for the help!
Fiddle 1 Code:
`
var svg = d3.select("body")
.append('svg')
.attr('width', 500)
.attr('height', 500)
var circle = d3.select("svg")
.append("circle")
.attr('cx', 10)
.attr('cy', 10)
.attr('r', 10)
var rect = d3.select("svg")
.append("rect")
.attr('width', 20)
.attr('height', 20)
.attr('x', 30)
.attr('y', 30)
var text = d3.select("svg")
.append("text")
.text("hello")
.attr("x",60)
.attr("y",60)
.attr('opacity',1)
var tran = svg.transition().duration(2000)
tran.select("rect").attr('fill', 'red')
tran.select("circle").attr('fill', 'blue')
tran.select("text").attr('opacity', 0)
//new transition
svg.transition()
.duration(2000)
.delay(2000)
.select("text")
.attr('opacity', 1)
.text("hello again!")
.attr("x",60)
.attr("y",60)
</script>
</body>
`
Fiddle 2 Code:
'
theData = [
{"words":"today", "rect_color": "red", "circle_color":"blue"},
{"words":"tomorrow", "rect_color": "green", "circle_color":"yellow"},
{"words":"Day After That", "rect_color": "purple", "circle_color":"brown"}]
var svg = d3.select("body")
.append('svg')
.attr('width', 500)
.attr('height', 500)
var circle = d3.select("svg")
.append("circle")
.attr('cx', 10)
.attr('cy', 10)
.attr('r', 10)
var rect = d3.select("svg")
.append("rect")
.attr('width', 20)
.attr('height', 20)
.attr('x', 30)
.attr('y', 30)
var text = d3.select("svg")
.append("text")
.text("hello")
.attr("x",60)
.attr("y",60)
.attr('opacity',1)
var tranFunc = function(object){
var tran = svg.transition().duration(2000)
tran.select("rect").attr('fill', object.rect_color)
tran.select("circle").attr('fill', object.circle_color)
tran.select("text").attr('opacity', 0)
var tran2 = tran
tran2.transition().select("text")
.attr('opacity', 1)
.text(object.words)
}
var allTran = function(list){
for(var i = 0; i < list.length; i++){
tranFunc(list[i])
}
}
allTran(theData)
</script>
'

Related

How to put function into my image in svg using d3?

I have an rectangle and an image in it. I am trying to put a function to the image ( If i clicked it, a link to an websited appeared ) but i cant find a proper way.
This is my code
var svgContainer = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
var g = d3.select("svg") .append("g")
var rectangle = g.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 300)
.attr("height", 200)
.style("fill","pink");
var text = g.append("text")
.attr("x",150)
.attr("y",100)
.attr("text-anchor","middle")
.text('Nam oc cho')
var img = g.append("image")
.attr("x",200)
.attr("y",85)
.attr("href","firefox.jpg")
.attr("height","20px")
.attr("width","20px")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Thanks

Changing the angle of a D3 doughnut chart to 180

I need to make my doughnut chart a horizontal graph like in this image >
this is the code that i use for other doughnut charts
var dataset = {
hddrives: [total - value, value],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range([secondColor, mainColor]);
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 70);
var svg = d3.select(divName).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
//Draw the Circle
svg.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 65)
.attr("fill", "#F6FBF3");
var path = svg.selectAll("path")
.data(pie(dataset.hddrives))
.enter().append("path")
.attr("class", "arc")
.attr("fill", function (d, i) { return color(i); })
.attr("d", arc);
svg.append("text")
.attr("dy", "0em")
.style("text-anchor", "middle")
.attr("class", "inside")
.attr("font-size", "30px")
.text(function (d) { return value; });
svg.append("text")
.attr("dy", "1.5em")
.style("text-anchor", "middle")
.attr("class", "data")
.text(function (d) { return nomeGtin; });
}
I tried messing around with the attr values and the arc value, but without success, any ideas on how to approach this? Thanks
That isn't much of a donut chart, it's now a stacked bar chart (with a single bar). The pie and arc helpers aren't much help for that, they are concerned with calculating angles and circular things; you are now dealing with rectangles. d3.stack could help, but is probably overkill. Here's a quicky where I've just done the math (ie positioning) myself:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.17" data-semver="3.5.17" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
</head>
<body>
<script>
var width = 500,
height = 200,
w = 300,
h = 100;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
var total = 0,
l = 0,
// fake random data
raw = d3.range(5).map(function(d){
var v = Math.random() * 10;
total += v;
return v;
}),
// calculate percents and cumulative position
data = raw.map(function(d){
var rv = {
v: d,
l: l,
p: d/total
}
l += rv.p;
return rv;
});
// scale and color
var s = d3.scale.linear()
.range([0, w])
.domain([0, 1]),
c = d3.scale.category20();
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', function(d){
return s(d.l) + width/2 - w/2; // place based on cumulative
})
.attr('width', function(d){
return s(d.p); // width from scale
})
.attr('height', h)
.attr('y', height/2 - h/2)
.style('fill', function(d,i){
return c(i);
})
.style('stroke', 'white')
.style('stroke-width', '2px');
</script>
</body>
</html>

d3 click to center content at position of element or click

I have been trying to get the basics of how I make a pannable zoomable, and click to center zoom on element d3 work. This example is what I want to do but I am having trouble translating it outside of the geo context: https://bl.ocks.org/mbostock/2206340
What I have accomplished is the first two parts pan and zoom, see a basic fiddle here https://jsfiddle.net/e9fbn2xp/
How can I accomplish centering the the circle in the center of the viewable window, so it looks like the circle is zoomed to? Note that although this is a fixed position circle I will eventually have dynamic data, so ideally I could reference the circles position dynamically.
Here is my code:
HTML (note that this is React JSX syntax but that should be irrelevant to question)
<div style={{width: 800}}>
<svg style={{border: '1px solid black'}} id="viz" width="800" height="800">
</svg>
</div>
JAVASCRIPT
var svg = d3.select("#viz")
var width = svg.attr("width");
var height = svg.attr("height");
var testLayer = svg.append('g');
var aRect = testLayer.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", 800)
.attr("width", 800)
.attr("fill", 'green');
var aCircle = testLayer.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", 200)
.attr("cy", 200)
.on("mousedown", zoomToMe);
function zoomToMe(){
console.log("do the zoom")
}
var zoom = d3.zoom()
.scaleExtent([.5, 40])
.translateExtent([[0, 0], [width, height]])
.on("zoom", zoomed);
svg.call(zoom);
function zoomed() {
testLayer.attr("transform", d3.event.transform);
}
svg.on("click", function() {
var coords = d3.mouse(this);
})
I got a working solution and thought I would share the code in case others find it useful. It is a fairly different approach then my original but accomplishes the three goals, pan, mouse zoom, zoom to element. While these are three simple static circles the same concept should work with a dynamic dataset.
fiddle: https://jsfiddle.net/uc7oprx3/5/
HTML
<svg id="viz" width="400" height="400" />
JAVASCRIPT
var zoom = d3.zoom()
.scaleExtent([0.3,2])
.on("zoom", zoomed);
var svg = d3.select("#viz")
var width = svg.attr("width");
var height = svg.attr("height");
var zoomer = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.call(zoom);
var g = svg.append("g");
var aCircle = g.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", 200)
.attr("cy", 200)
.on("mousedown", () => centerNode(200, 200));
var bCircle = g.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", 400)
.attr("cy", 400)
.on("mousedown", () => centerNode(400, 400));
var cCircle = g.append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", 40)
.attr("cx", 600)
.attr("cy", 600)
.on("mousedown", () => centerNode(600, 600));
function zoomed() {
g.attr("transform", d3.event.transform);
}
function centerNode(xx, yy){
g.transition()
.duration(500)
.attr("transform", "translate(" + (width/2 - xx) + "," + (height/2 - yy) + ")scale(" + 1 + ")")
.on("end", function(){ zoomer.call(zoom.transform, d3.zoomIdentity.translate((width/2 - xx),(height/2 - yy)).scale(1))});
}

Progress bar with text messages

Have below piece of code for drawing progress-bar,but not able to append text like below image, beginnig of rectangle "E" end of rectangle "F" and top/bottom of rectangle as shown in the image, how we
can append text beginning of rectangle by giving negative value for x but d3 does not consume negative values for this.
var self = this;
var progressWidth = this.getInteger("progressWidth");
var progressFill = this.getString("progressFill");
var progressBarWidth = this.getInteger("progressBarWidth");
var progressBarHeight = this.getInteger("progressBarHeight");
var isRoundCorners = this.getBoolean("isRoundCorners");
var backgroundFill = this.getString("backgroundFill");
var roundedCorners = 0;
var progressWidthValue = 0;
if(!progressBarWidth) {
progressBarWidth = 250;
}
if(!progressBarHeight) {
progressBarHeight = 15
}
if(progressWidth) {
progressWidthValue = (progressBarWidth * progressWidth)/100;
}
if(!progressFill) {
progressFill = 'blue';
}
if(isRoundCorners) {
roundedCorners = 10;
} else {
roundedCorners = 0;
}
if(!backgroundFill) {
backgroundFill = '#D8D8D8';
}
var svg = args.svg;
svg = svg
.append('svg');
// .attr('height', 100)
// .attr('width', 500);
svg.append('rect')
.attr('class', 'bg-rect')
.attr('rx', roundedCorners)
.attr('ry', roundedCorners)
.attr('fill', backgroundFill)
.attr('height', progressBarHeight)
.attr('width', progressBarWidth)
.attr('x', 0);
var progress = svg.append('rect')
.attr('class', 'progress-rect')
.attr('fill', progressFill)
.attr('height', progressBarHeight)
.attr('width', 0)
.attr('rx', roundedCorners)
.attr('ry', roundedCorners)
.attr('x', 0);
progress.transition()
.duration(1000)
.attr('width',progressWidthValue);
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/c4Sm3.png
You can append text to the svg with x and y values like that :
svg.append('rect')
.attr('class', 'bg-rect')
.attr('rx', 5)
.attr('ry', 5)
.attr('fill', 'blue')
.attr('height', 10)
.attr('width', rectWidth)
.attr('x', xRect)
.attr('y', 20);
svg.append('text')
.attr('color', 'red')
.attr('x', 5)
.attr('y', 30)
.text('A')
svg.append('text')
.attr('color', 'red')
.attr('x', rectWidth + xRect)
.attr('y', 30)
.text('B')
see http://jsfiddle.net/k76yx4am/

How to fill half of the rectangle with color in d3.js

Hi want a rectangle of width 250, and i want to fill the rectangle with the color based on the input value.I tried to create one rectangle of gray and another one of color skyblue on the same position to acheive this but it update the rectangle only. cant create another rectangle on the previous one. what to do.? My Js fiddle is http://jsfiddle.net/sSqmV/ i want to create an second rectangle of sky blue over the previous one of white color to acheive my task.
var chart = d3.select("div.dev1").append("svg")
.attr("width", 292)
.attr("height", 300);
var dataset = [0, 1, 2];
var dataset2 = [0, 1, 2,3];
var rects1 = chart.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 10)
.attr("y", function (d, i) { return (i + 1) * 60; })
.attr("height", 6)
.attr("width", 250)
.attr("fill", "white");
var rects = chart.selectAll("rect")
.data(dataset2)
.enter()
.append("rect")
.attr("x", 10)
.attr("y", function (d, i) { return (i + 1) * 60; })
.attr("height", 6)
.attr("width", 250)
.attr("fill", "skyblue");
var texts = chart.selectAll("text").data(dataset2).enter().append("text")
.text("18% of the questions were ANSWERED")
.attr("x", 10)
.attr("y", function (d, i) { return 90+(i*60); });
You can do something like this:
var chart = d3.select("div.dev1").append("svg")
.attr("width", 292)
.attr("height", 300);
var dataset = [0, 1, 2];
var dataset2 = [0, 1, 2, 3];
var rects = chart.selectAll(".rect1")
.data(dataset2)
.enter()
.append("rect")
.attr('class', 'rect1')
.attr("x", 10)
.attr("y", function (d, i) {
return (i + 1) * 60;
})
.attr("height", 6)
.attr("width", 250)
.attr("fill", "skyblue");
var rects1 = chart.selectAll(".rect")
.data(dataset)
.enter()
.append("rect")
.attr('class', 'rect')
.attr("x", 10)
.attr("y", function (d, i) {
return (i + 1) * 60;
})
.attr("height", 6)
.attr("width", 125)
.attr("fill", "white");
var texts = chart.selectAll("text").data(dataset2).enter().append("text")
.text("18% of the questions were ANSWERED")
.attr("x", 10)
.attr("y", function (d, i) {
return 90 + (i * 60);
});
Here is jsfiddle: http://jsfiddle.net/cuckovic/sSqmV/2/

Resources