Good day.
I have an angular 4 component that draws a D3 v4 graph. The graph is drawn fine but the problem comes when I try to trigger a change on a mouseover over. So for example when I mouse over a circle on the line graph I want a the rectangle to shrink(just for this example)Please any assistance will be appreciated below is an excerpt of the code that is not working:
g.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 2)
.attr("cx", function (d) {
return x(d.time);
})
.attr("cy", function (d) {
return y(d.value);
})
.on("mouseover",update)
var div = this.svg.append("rect")
.attr("class", "tooltip")
.attr("width", "100px")
.attr("height", "200px")
.style("fill", "steelblue")
.style("opacity", 1)
.enter().append("text").enter()
.text("foo");
function update()
{
div.setAttribute("width","10px");
}
The above code draws a blue rectangle over the graph but on mosueover there is no change in size.
Related
I made d3.js pie chart and related legend with population data popu. When I hover over pie segments I achieved to enlarge related legend square parts and the pie segment itself (larger outerRadius). Now I am trying to do contrary. When I hover over square of legend I want to enlarge square itself and related pie segment as well. Something like this example here https://www.amcharts.com/demos/pie-chart-with-legend/. I will write down just part of the code related to pie chart problem that I have.
var pie = d3.pie()
.value(function(d) {return d.pop})(popu);
var seg = d3.arc()
.innerRadius(100)
.outerRadius(150)
.padAngle(.1)
.padRadius(45);
var segover = d3.arc()
.innerRadius(100)
.outerRadius(170)
.padAngle(.1)
.padRadius(45);
So this part is working great.
svg.append("g")
.attr("class", "pieChart")
.attr("transform", "translate(1250,570)")
.selectAll("path")
.data(pie)
.append("path")
.attr("class", "pie")
.attr("id", function(d){return d.data.id})
.attr("d", seg)
.on("mouseenter", function(d){
d3.select(this)
.transition(10)
.duration(100)
.attr("d", segover)
})
Then I tried to change pie chart segment when hovering on legend related segments.
var pieEl = svg.selectAll(".pie");
var piePath = pieEl.nodes();
svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(-50,280)")
.selectAll(".mySquers")
.data(pie)
.enter()
.append("rect")
.attr("class", "rec")
.attr("x", 100)
.attr("y", function(d,i){ return 100 + i*25})
.attr("width", "15")
.attr("height", "15")
.attr("id", function(d,i){ return (popu[d,i].id)})
.style("fill",function(d,i){
if (this.id == piePath[i].id){
return piePath[i].getAttribute("fill")
}
})
.on("mouseenter", function(d){
for (var i=0; i<piePath.length; i++){
if (piePath[i].id == d.data.id){
piePath[i].setAttribute("d", segover);
}}
})
When I tray to setAttribute("d", segover) in DOM instead of d attribute written as string as usually (d="M144.58.....") I have a function (d="function(pie){ _e);}" and on hover pie segment dissapear. But for example if I set attribute fill to red on hover it change and segment is painted. So the notation of code is good. Is there some behavior of d path generated with d3.arc() that I am missing? Any suggestion is welcome.
I think you should be passing your data as an argument in your function. Normally, it is taken as default argument when you return the function directly.
piePath[i].setAttribute("d", segover(*data associated with segment*));
svg.append("g")
.attr("class", "pieChart")
.attr("transform", "translate(1250,570)")
.selectAll("path")...
.attr("d", seg) // this is same as : attr("d", seg(d))
.on("mouseenter", function(d){
d3.select(this)
.transition(10)
.duration(100)
.attr("d", segover) // same here
})
I have some data with 2 attributes: colour and value
I use the D3 enter selection to create circle elements, and append them to the body of the page. Their fill colour is determined by the "colour" attribute.
Then, I append text elements to the page. The text contents are determined by the "value" attribute.
Here is what I am working with:
// Set up svg element
var svg = d3.select("body")
.append("svg")
.attr("width", 300)
.attr("height", 300)
.style("background", "lightblue");
var dataset = [
{"colour":"red", "value":"First set of text"},
{"colour":"green", "value":"Second attempt"},
{"colour":"blue", "value":"Third and final!"}
];
// Create circles from the data
// On mouseover, give them a border (remove on mouseout)
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("r", 40)
.attr("cy", function(d, i) { return i*80 + 40; })
.attr("cx", 50)
.style("fill", function(d) {return d.colour;})
// HERE
// Can I somehow show and hide the text component that is
// associated with this circle when the circle is hovered, rather
// than the text itself?
.on("mouseover", function(d) {
d3.select(this).style("stroke", "black")
.style("stroke-width", 2)
})
.on("mouseout", function(d) {d3.select(this).style("stroke", "none")});
// Now add the text for each circle
// Same thing with mouseover and mouseout
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("y", function(d, i) { return i*80 + 40; })
.attr("x", 50)
.style("opacity", 0)
.on("mouseover", function(d) {d3.select(this).style("opacity", 1)})
.on("mouseout", function(d) {d3.select(this).style("opacity", 0)})
.text(function(d) { return d.value;});
I would like for the text to be hidden, until the associated circle is hovered over. How can I connect the text element with a particular circle, so that I can toggle whether the text is shown by hovering over the circle?
This fiddle below is an outline of what I am trying to do, and what I have got so far. I have the text showing up only when hovered, but not when the circle is hovered.
https://jsfiddle.net/aj4zpn6z/
There are several ways for achieving this. Since both circles and texts use the same dataset, my solution uses filter.
First, let's name the variables for the texts and circles:
var circles = svg.selectAll("circle")
//etc...
var texts = svg.selectAll("text")
//etc...
Then, inside the circles mouseover function, we filter the texts that have the same colour attribute:
.on("mouseover", function(d){
d3.select(this).style("stroke", "black").style("stroke-width", 2);
var tempTexts = texts.filter(function(e){
return e.colour === d.colour
});
tempTexts.style("opacity", 1);
});
This is your updated fiddle: https://jsfiddle.net/wxh95e9u/
I have put together a D3 line chart and added threshold encoding using clip path / clipping. The only problem I am facing is I am not able to add tooltips to this chart. I want a tooltip when I hover anywhere in the chart and the corresponding y axis value on the chart shows up in the tooltip.
I have added threshold encoding using this example by Mike Bostock.
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return _config.xScale(d.vtc); })
.y(function(d) { return _config.yScale(d.values); });
svg.append("clipPath")
.attr("id", "clip-above")
.append("rect")
.attr("width", _config.width)
.attr("height", _config.yScale(55));
svg.append("clipPath")
.attr("id", "clip-below")
.append("rect")
.attr("y", _config.yScale(55))
.attr("width", _config.width)
.attr("height", _config.height - _config.yScale(55));
svg.selectAll(".line")
.data(["above", "below"])
.enter().append("path")
.attr("class", function(d) { return "line " + d; })
.attr("clip-path", function(d) { return "url(#clip-" + d + ")"; })
.datum(data)
.attr("d", line);
I didn't know how to go about adding a tooltip for this particular chart as there is clip rectangle over the path and the path is broken down into above and below segment to give the colour effects.
Do we have a unified way to add a tooltip to normal path and this one? If yes I would like to know some sources/links I can look at.
Something like this, but not that complicated (without any indicator on the line, just the tooltip)
My CODEPEN LINK
You can add mouseOver handler for the line and translate back the mouse y position to yAxis value using the .invert function of d3 linear scale. Now, you can dynamically add a tooltip text element and set the position, value to it
Here is the updated Codepen link
NOTE: You still need to increase the capture area of the line. This can be done by adding a transparent stroke to the line.
svg.selectAll(".line")
.data(["above", "below"])
.enter().append("path")
.attr("class", function(d) { return "line " + d; })
.attr("clip-path", function(d) { return "url(#clip-" + d + ")"; })
.datum(data)
.attr("d", line)
.on("mouseover", function() {
var mousePos = d3.mouse(this);
var yAxisValue = _config.yScale.invert(mousePos[1]);
svg.selectAll(".tooltip").data([mousePos])
.enter().append("text")
.classed("tooltip", true)
.attr("x", function(d) { return d[0]})
.attr("y", function(d) { return d[1]})
.text(yAxisValue);
})
.on("mouseout", function() {
svg.selectAll(".tooltip").data([]).exit().remove();
});
I have built a multi series line chart using the D3 library. I have been trying to work on animating the line chart so I can give out one line at a time and not all 5 of them together. Can anybody give me some ideas as to how I can go about with this? I have tried using transition() but I seem to be using it wrong. This is what I have done so far -
var city = svg.selectAll(".city")
.data(years)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line");`
d3.transition().selectAll(".line")
.duration(500)
.ease("linear")
.attr("d", function(d){return line(d.values); })
.style("stroke", function(d) {return color(d.name); })
.attrTween("d",pathTween);
function pathTween() {
var interpolate = d3.scale.quantile()
.domain([0,1])
.range(d3.range(1,years.length+1));
return function(t){
return line(data.slice(0,interpolate(t)));
};
D3 transitions have a .delay() method that allows you to set a delay before each transition starts. In your case (having each line start separately) it would look like this:
d3.transition().selectAll(".line")
.duration(500)
.delay(function(d, i) { return i * 500; })
.ease("linear")
.attr("d", function(d){return line(d.values); })
.style("stroke", function(d) {return color(d.name); });
This takes the index of each line (i) and offsets the start of the transition depending on that.
I am basically trying to clip a chart containing "path" elements representing data points.
It seems like, path elements are not initially "transformed" and remain at (0,0) and are thus clipped by rectangle surrounding entire chart.
Basically, I have replaced "circle" elements as drawn in D3 Brush Example with "path" elements of symbol type "circle".
.append("circle")
.attr("class", "point")
.attr("clip-path", "url(#clip)")
.attr("r", function(d){return Math.floor(Math.random() * (20 - 5 + 1) + 5);})
.attr("cx", function(d) { return x(d.index); })
.attr("cy", function(d) { return y(d.value); })
replaced with
.append("path")
.attr("class", "point")
.attr("clip-path","url(#clip)")
.attr("d", d3.svg.symbol().type("circle"))
Here is jsfiddle. As you can see, only lower right quarter of the circle is visible and rest have been clipped out. What is going on? What is the solution?
Edit:
Also, the actual "clipping" is not working for those circles(paths). Why is that? Why does it work for "circle" but not for "path"?