I am using D3.js to dynamically create svg elements. When I click a circle, I run this function:
.on("click", function(d) {
d3.select(this).select("rect").transition().duration(900).style("visibility", "visible");
d3.select(this).selectAll("tspan").transition().duration(900).style("visibility", "visible");
})
Aside from the fact that my transitions aren't working, clicking on the circle shows that circles children rectangle and tspan, all is well. However if I click another circle, the new rectangle and tspan show but I need the current one to hide. Wondering what the best/most efficient way to do this is with D3
If your circles have a class, say ".circle", you can do something like this:
.on("click", function(d) {
var clickedCircle = this;
d3.selectAll(".circle").each(function() {
var currCircle = this;
d3.select(this).select("rect").transition().duration(900).style("visibility", function() {
return (currCircle === clickedCircle) ? "visible" : "hidden";
});
});
});
And obviously do the same for your tspan element. This will hide all but your currently clicked circle.
Related
I'm working on a d3 force layout graph, with looks pretty like this.
What I want is the root node to be fixed not draggable. I fixed the root node in the json file by adding
"fixed": true
but it is still draggable. In my JS file there is the code
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on("click", click)
.call(force.drag);
If I remove the last line of this code, the whole graph isn't draggable anymore. I think 'force' is a global variable and determines, that the whole graph is draggable. But I want only the root node not to be draggable and the should be draggable. How can I do that?
You have to remove the drag event from the node you wish to stay fixed.
Here is an example : http://jsfiddle.net/qvco2Ljy/112/
I have looped through the data to give the first element a fixed attribute and also a donotmove attribute as when you drag and let go, perhaps you want the node to stay fixed (for children i mean), so using d.fixed here will cause a conflict :
graph.nodes.forEach(function(d, i) {
d.donotmove = false;
if (i == 0) {d.donotmove = true; d.fixed = true;}
})
And when calling drag events, check for the donotmove attribute like so :
var drag = d3.behavior.drag()
.origin(function(d) {
return d;
})
.on("dragstart", function(d) {
if (d.donotmove) return;
dragstarted(d)
})
.on("drag", function(d) {
if (d.donotmove) return;
dragged(d)
})
.on("dragend", function(d) {
if (d.donotmove) return;
dragended(d)
})
Hope that helps :)
I am working with a scatterplot in d3 and each dot on the graph represents a paper.
All dots are blue on the graph but on click I want that selected paper to change color eg (yellow). But when another dot is clicked I want that first dot to go back to blue and the newly selected dot to turn yellow. How would I achieve this? I have a function called clickHandler which is called when the circles are created at the on click attribute.
Here is a similar question d3 javascript alternate colors on click
But instead of the circle turning back to the original color on the second click of that circle I want it to turn back on a click of another circle.
The following code is from the question linked above, I was wondering would I be on the right track thinking this is the method I should be following for what I want?:
function clickHandler (d, i) {
var toggleColor = (function() {
var currentColor = "blue";
return function() {
currentColor = currentColor == "blue" ? "yellow" : "blue";
d3.select(this).style("fill", currentColor)
.style("stroke", "black");
}
})
}
Any help is greatly appreciated! Thanks in advance!
This can be as simple as:
function clickHandler (d, i) {
// reset all circle to blue
d3.selectAll('circle') //<-- or slap a class name on your circles and use that
.style('fill', 'blue');
// set selected one to yellow
d3.select(this)
.style('fill', 'yellow');
}
Hey Guys i need some help to find a way to integrate the switch of images into the fade function. For some reason the chords dont fade after the mouse hovers over the graph.
And to Look at the idea of loading (but not displaying) a series of images during initial page load, and then using the fade function simply to switch a pre-defined image area to show a different image.
This is my JS Bin
You should pass data bonded to the arc and it's index as parameter to the function which is returned by the fade function as shown below.
d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius))
.on('mouseover', function(d,i) {
fade(0.1)(d,i); //Changed line of code
overlayPic.classList.remove('hidden');
overlayPic.src = 'https://farm1.staticflickr.com/697/23125850325_b69a8530dd_n.jpg';
})
.on("mouseout", function(d,i){
fade(1)(d,i); //Changed line of code
overlayPic.classList.add('hidden');
});
Fade function expects that two params.
function fade(opacity) {
return function(g, i) { //Note that this code uses index i
svg.selectAll(".chord path")
.filter(function(d) { return d.source.index != i && d.target.index != i; })
.transition()
.style("opacity", opacity);
};
}
I have a hover effect implemented in d3 that selects several rectangles in an svg and changes their color:
var rect = d3.selectAll('.rect')
rect.transition()
.duration(1000)
.style('fill', red')
I only want this effect to be operating on one rectangle at a time. If I quickly hover over several rectangle is close succession, the effect is triggered on all the rectangles I've hovered over. How can I block other mouse hover events if there is currently another event being triggered?
You can have a global variable that acts as a semaphore:
var transitioning = false;
rect.append("...")
.on("mouseover", hover);
function hover() {
if(!transitioning) {
transitioning = true;
rect.transition()
.duration(1000)
.style('fill', 'red')
.each("end", function() { transitioning = false; });
}
}
Note that this assumes that all your transitions have the same duration and delay.
I have an SVG container with a number of elements each containing a rect and some text elements in a horizontal array.
I want to click on one element and drag to one of the others. The first element and element dragged over should highlight - as it would in a normal text editor selection.
at the end I want to know the first and last elements selected so that I can access their data.
I tried this using d3 drag behaviour but:
1. the intermediate elements can't be highlighted
2. the dragend does not tell me which element was the final one.
Also tried using mouse events but:
1. I can highlight each intermediate item but not easily remove the highlight if the mouse is moved back towards the beginning.
2. if the mouse is moved out of the container I can miss the mouse up events leaving highlighted elements.
3. I still don't really know upon which element I am finishing unless I collect all the mouse over events.
I don't actually want to move the selected elements - just know the first and last one selected.
I created this fiddle to illustrate the problem: http://jsfiddle.net/avowkind/up54b/5/
HTML
<svg class='demosvg' version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<rect width="400" height="220"></rect>
<g id="container" transform="translate(10,10)"></g>
</svg>
Javascript
var mydata = [1, 2, 3, 4, 5];
/* each box is a group with a rect and text
positioned according to the data value
on drag/drop we want to know the dragged element, and the one it is dropped on.
we would like to highlight all the intervening elements too.
Ultimately we just want a result e.g. 2 was dragged to 5
*/
var boxg = d3.select('#container').selectAll('g').data(mydata).enter()
.append('svg:g')
.attr('id', function (d, i) {
return "b" + d;
})
.attr('transform', function (d, i) { return "translate(" + d * 50 + ",80)";})
.call(d3.behavior.drag()
.on("dragstart", function (d, i) {d3.select(this).classed("selected", true); })
.on("drag", function (d, i) {
// which element are we over here - to highlight it
var el = document.elementFromPoint(d3.event.x, d3.event.y);
console.log(el);
})
.on("dragend", function (d, i) {
console.log(d);
console.log(this);
console.log(d3.event);
// turn off all highlights
d3.selectAll('#container g').classed("selected", false);
// Which box got dropped on here ?
})
);
boxg.append('svg:rect')
.classed('box', true)
.attr('width', 40).attr('height', 40);
boxg.append('svg:text')
.text(function(d,i) { return d; })
.attr('dx', 15).attr('dy', 20);
CSS
.demosvg { fill:silver;}
.box { fill:lightblue;}
text { fill:black;}
.selected .box{ fill:gold;}
Thanks Andrew