I am trying to do three transitions in onClick event of a Pie Chart. The first transition works but the second and the third one fail. I understood from Mike Bostocks comment on a similar question that "This means you are trying to modify a transition that has already started, or derive a transition from one that has ended. Please read the API Reference section on transition life cycles."
I still cant seem to understand the reason why this is happening.
Here is the relevant code:
self.primaryLabelText = self.arc.append("text")
.on("click", function (d: any) {
console.log("About to send::::" + getStudyLabel(d.index));
self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index));
self.showDialog();
// The amount we need to rotate:
var rotate = 180-(d.startAngle + d.endAngle)/2 / Math.PI * 180;
// Transition the pie chart
g.transition()
.attr("transform", "translate(" + self.width / 2 + "," + self.height / 2 + ") rotate(" + rotate + ")")
.duration(1000);
// Τransition the labels:
self.primaryLabelText.transition()
.attr("transform", function(dd: any) {
return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; })
.duration(1000);
self.secondaryLabelText.transition()
.attr("transform", function(dd: any) {
return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; })
.duration(1000);
})
.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + label.centroid(d) + ")";
})
.attr("dy", "-0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "15px")
.attr("text-anchor", "middle")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getStudyLabel(d.index);
}
});
What is the issue here?
The problem was that the primaryLabel and secondaryLabel I was trying to do transition on were not assigned correctly. I had the following assignment:
self.primaryLabelText = self.arc.append("text")
.on("click", function (d: any) {
self.rotateChart(d);
}).transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + self.label.centroid(d) + ")";
})
.attr("dy", "-0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "15px")
.attr("text-anchor", "middle")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getStudyLabel(d.index);
}
});
As a result of this, the variables contained the reference to the transitions and not the labels themselves as when you chain transitions it gets changed to a transition type object. So I changed that to this:
self.primaryLabelText = self.arc.append("text")
.on("click", function (d: any) {
self.rotateChart(d);
});
self.primaryLabelText.transition()
.duration(750)
.attr("transform", function (d: any) {
return "translate(" + self.label.centroid(d) + ")";
})
.attr("dy", "-0.75em")
.attr("font-family", "sans-serif")
.attr("font-size", "15px")
.attr("text-anchor", "middle")
.attr("class", "sponsor-pie-widget-label")
.text(function (d: any) {
if (d.endAngle - d.startAngle < 0.3) {
return "";
} else {
return getStudyLabel(d.index);
}
});
It all works now! :)
Related
I'm trying to use d3 and d3-cloud to display a keyword cloud. It works, but my only problem is that the words overlap, And I dont understand why. I think it comes from the fontSize, but I can't find what exactly. screen here
Below are my different methods :
private _populate(keyword: any) {
const dataset = kw.map(function (d: any) { return { text: d.text, size: d.value }; });
console.log(dataset);
d3.layout.cloud()
.size([this._width, this._height])
.words(dataset)
.padding(1)
.rotate(0)
.fontSize((d: any) => d.size / 100)
.on('end', () => {
this._drawWordCloud(dataset);
})
.start();
}
private _drawWordCloud(words: any) {
this._svg
.append("g")
.attr("transform", "translate(" + this._width / 2 + "," + this._height / 2 + ")")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", (d: any) => d.size + "px")
.style("fill", "#69b3a2")
.style("font-family", "Impact")
.attr("text-anchor", "middle")
.attr("transform", (d: any) => "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")")
.text((d: any) => d.text);
}
.fontSize((d: any) => d.size / 100) because my values are very high (~ 10000).
Someone can help me ? The various solutions (very few) that I have found do not work.
Thanks !
I finally found the solution. You have to add the font you want to use in the first method "_populate". In my case :
.font("Impact")
And we don't change the line in the second method :
.style("font-family", "Impact")
That's all ! I hope it can help other people
I am currently building a sunburst chart in D3JS and am trying to append circles to each node. You can view current project here: https://jsfiddle.net/mhxuo260/.
I am trying to position each of the circles in the top right hand corner of their respective node. Currently they will only position in the center which covers the node labels. I have been scouring the net in search for a clue but just haven't come up with anything yet. Any suggestion would be appreciated.
d3.json("flare.json", function(error, root) {
if (error) throw error;
var g = svg.selectAll("g")
.data(partition.nodes(root))
.enter().append("g");
path = g.append("path")
.attr("d", arc)
.attr('stroke', 'white')
.attr("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", magnify)
.each(stash);
var text = g.append("text")
// .attr("x", function(d) { return d.x; })
// .attr("dx", "6") // margin
// .attr("dy", ".35em") // vertical-align
.text(function(d) {
return d.name;
})
.attr('font-size', function(d) {
return '10px';
})
.attr("text-anchor", "middle")
.attr("transform", function(d) {
if (d.depth > 0) {
return "translate(" + arc.centroid(d) + ")" +
"rotate(" + getStartAngle(d) + ")";
} else {
return null;
}
})
.on("click", magnify);
var circle = g.append('circle')
.attr('cx', function(d) { return d.x })
.attr('cy', function(d) { return d.dy; })
.attr('r', '10')
.attr('fill', 'white')
.attr('stroke', 'lightblue')
.attr("transform", function(d) {
console.log(arc.centroid(d))
if (d.depth > 0) {
return "translate(" + arc.centroid(d) + ")" +
"rotate(" + getStartAngle(d) + ")";
} else {
return null;
}
});
You are using the ´´´arc.centroid´´´ function which always returns the x,y midpoint of the arc. All that function is doing is:
The midpoint is defined as (startAngle + endAngle) / 2 and (innerRadius + outerRadius) / 2
You just need to calculate a different position using these values depending on where you want it. Use the transform like this (sudo code):
.attr( "transform", function(d) {
var x = (startAngle + endAngle) / 2;
var y = (innerRadius + outerRadius) / 2;
return "translate(" + x +"," + y + ")";
});
You don't need to rotate your circle.
(FYI: javascript will convert arrays into strings by joining each number with commas, this is why arc.centroid returning an array works here)
i am trying to make a simple animation in d3 (i am new to it). i have made a word cloud presentation, and i will like it to "fly in" (small movement from left to right and then in center) when the page opens.
var text = d3.select("body").append("svg")
.attr("width", 1200)
.attr("height", 800)
.append("g")
.attr("transform", "translate(550,300)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.style("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
All you need to do is set the initial position to be off the page to the left, then add a transition to the desired end position. For example:
d3.select("svg > g")
.attr("transform", "translate(-550,300)")
.transition()
.attr("transform", "translate(550,300)");
I want to create word tag cloud using d3 .. I found a good example here but the problem that the words go outside the borders especially in case of large fonts and this screenshot for the problem
and here's my code
<script src="../lib/d3/d3.js"></script>
<script src="../d3.layout.cloud.js"></script>
<script>
var fill = d3.scale.category20();
d3.layout.cloud().size([600, 600])
.words([
"Hello", "world", "normally", "you", "want", "more", "words",
"than", "this"
].map(function(d) {
return {
text: d,
size: 10 + Math.random() * 90
};
}))
.padding(5)
.rotate(function() {
return ~~(Math.random() * 2) * 90;
})
.font("Impact")
.fontSize(function(d) {
return d.size;
})
.on("end", draw)
.start();
function draw(words) {
d3.select("body").append("svg")
.attr("width", 700)
.attr("height", 700)
.append("g")
.attr("transform", "translate(150,150)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) {
return d.size + "px";
})
.style("font-family", "Impact")
.style("fill", function(d, i) {
return fill(i);
})
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) {
return d.text;
});
}
</script>
anyone know a solution for this?
Just change the following line in draw():
.attr("transform", "translate(150,150)")
to:
.attr("transform", "translate(350,350)")
Since your SVG's size is 700x700, you want the g transform to be in the middle of the SVG as the text elements are anchored in the middle.
I am using D3 Cloud to build a word cloud (https://github.com/jasondavies/d3-cloud) and I would like to add an hover effect similar to http://www.jasondavies.com/wordcloud.
Here is the sample code. Complete code is at http://plnkr.co/edit/gNtHZ0lMRTP98mptm3W8?p=preview
var sizeScale = d3.scale.linear()
.domain([0, d3.max(frequency_list, function(d) { return d.freq} )]).range([10, 95]);
layout = d3.layout.cloud().size([w, h])
.words(frequency_list)
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return sizeScale(d.freq); })
.on("end",draw)
.start();
}
function draw(words) {
var fill = d3.scale.category20();
d3.select(container).remove();
d3.select("body").append(container)
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + [w/2, h/2] + ")")
.selectAll("text")
.data(words)
.enter().append("text")
.transition()
.duration(function(d) { return d.time} )
.attr('opacity', 1)
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "rotate(" + d.rotate + ")";
})
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
On the page you link to, he's using a :hover pseudo-class.
<style>
text:hover { opacity: .7 !important; }
</style>
Updated code here.