I don't see why that behaviour was implemented.
Any good reason ?
In order to have a brushing function, a transparent rectangle that captures all mouse events has to be drawn over top of the graph. That prevents any mouse events from triggering the tooltip event handler on the main graph elements, and is the reason the dc.js API warns that leaving brushing behaviour "on" will disable all other interactive behaviour.
If you want both behaviours, consider using a focus + context layout. That example uses plain d3, but you could recreate it with dc.js. Just have two different views of the same data, one with the brush and one with the tooltips or other interactivity.
You can use https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events to block 'mouseover' event for brush so that tooltips are enabled. Then on chart you can create a custom 'mousedown' event and pass it to brush to enable selection
d3.select('.chartContainer').on('mousedown', function(){
brush_elm = self.scrubberContent.select(".brush").node();
new_click_event = new Event('mousedown');
new_click_event.pageX = d3.event.pageX;
new_click_event.clientX = d3.event.clientX;
new_click_event.pageY = d3.event.pageY;
new_click_event.clientY = d3.event.clientY;
brush_elm.dispatchEvent(new_click_event);
});
I had a similar issue using d3 code. I realized that moving the tooltip event after the brush event fixed the problem. For me, it looked like this:
svg.append("g")
.attr("class", "brush")
.call(brush);
svg.selectAll('circle')
.data(humidity_data)
.enter()
.append('circle')
.attr('class', 'humidity_point')
.attr('cx', function(d) {
return x(d['date'])
})
.attr('cy', function(d) {
return y(d['Humidity'])
})
.attr('r', 4)
.attr('fill', '#428bca')
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.Custody + '<br>' + d.City + ', ' + d.Country + '<br>' + d.Humidity + '%')
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(1500)
.style("opacity", 0);
});
This code allowed brushing, but retained the ability to hover over a circle element and see metadata.
Related
I am trying to add tooltip, it doesnt show for some reason. Please help. Here's the code https://codepen.io/gladiator_kris/pen/pojgEyQ?editors=0010
var tooltip = svg.append("div")
.attr("id", "tooltip")
.style("opacity", 0.8);
.on("mouseover", function(d) {
tooltip.style("display", "flex")
.html(function() {return 'tooltip'})
.style("left", (d3.event.pageX + 10)+"px")
.style("top", (d3.event.pageY - 28) + "px")
})
.on("mouseout", () => {
tooltip.style("display", "none")
});
Many Thanks!
The problem is caused by the fact that the tooltip is an HTML div, and is being appended to the SVG. div is not a valid SVG tag, so it is not displayed.
This can be fixed by appending the div to div#graph, as shown below:
var tooltip = d3.select("#Graph").append("div")
I'm using the following code in a series chart renderlet to get a D3 tooltip.
lines.on('renderlet', function(chart) {
chart.selectAll('g.x text')
.attr('transform', 'translate(-29,30) rotate(315)')
chart.selectAll('circle')
.on("mouseover", function(d) {
d3.select(this)
.transition()
.duration(500)
div.transition()
.duration(200)
.style("opacity", 0.9);
div.html("<table><thead><tr><th colspan='2' class='toolHead'>" + d.data.key[1] +
'</th></tr></thead><tbody>' + '<tr style="margin-top: 100px"><td class="toolHeadCol"><td colspan="2">' +
d.data.key[0] + '</td></tr>' + '<tr style="margin-top: 100px"><td class="toolHeadCol"><b>' + 'value: ' +
'</b></td> <td>' + d.y + '</td></tr></tbody></table>')
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function() {
d3.select(this)
.transition()
.duration(500)
.style('opacity', 0)
div.transition()
.duration(500)
.style("opacity", 0)
})
When hovered on a certain data point in line, tooltip gets displayed. Data point on the line(circle) acts as expected, but there are some problems with the corresponding horizontal and vertical grid lines.
They do not disappear on mouseout and stay until another circle is hovered upon.
Since its a series chart, there are multiple lines, and mouseover on a datapoint in one line does not seem to be affected by mouseover on another line. As shown in the below image:
As shown in image, the gridline on the blue line remains visible even when its is hovered up on orange line.
How do I fix these?
Here is the fiddle
I have a D3 timeseries chart made up of line path and at each data point i use a circle which is appended to the lines. The circles have a mouse enter event attached to it and when the mouse is moved over the circle it displays the tooltip with the information about that data point and i also change the class of the circle so that it looks highlighted.
The problem i have got is, when the mouse is over the circle and the circle is highlighted and the tooltip is showing, at the same time if i get some new data and the chart is updated, the circle my mouse is over does not disappear even when the mouse is removed off the circle and it shows that circle hanging in the middle without being attached to any line.
I have attached the image of the chart showing the problem.
Any help to fix this problem will be highly appreciated.
Image showing d3 issue
Here's the jsfiddle code showing the issue. Try pointing your mouse to the circle and wait for the chart to update every 5 seconds
(Moving this from the comment section)
Take a look at this: https://jsfiddle.net/xvLgq8mn/
In the updateChart function you select by the circle class:
// update the circles at each data points
svg.selectAll('.circle') // here you correctly select all with the circle class
.data(this.props.data)
.attr('class', 'circle all')
.transition()
.duration(500)
.attr('cx', (d) => { return this.axis.x(d.time);})
.attr('cy', (d) => { return this.axis.y(d.count);});
but here, on mouseover, you remove the circle class and replace it with circle--highlight:
group.selectAll()
.data(this.props.data)
.enter().append('circle')
.attr('class', 'circle all')
.attr('cx', (d) => { return this.axis.x(d.time);})
.attr('cy', (d) => { return this.axis.y(d.count);})
.attr('r', 4)
.on('mousemove', function(d) {
// START: Show tooltip
div.transition()
.duration(1000)
.style('opacity', 1);
div.html('<div class="date--time">'
+ d.time
+ '</div><div class="count">' + d.count + ' incidents</div>')
.style('left', (d3.event.pageX) + 'px')
.style('top', (d3.event.pageY - 70) + 'px');
d3.select(this)
.attr('r', 6)
.attr('class', 'circle--highlight'); // here you change the class from circle all
// to just circle--highlight,
// so when you are hovering a circle and the chart changes,
// the circle you have hovered won't be updated because
// it won't be selected due to the class difference
// END: Show tooltip
})
.on('mouseleave', function() {
// hide tooltip and return the circles to original style
div.transition()
.duration(500)
.style('opacity', 0);
// set the circle back to normal
d3.select(this)
.attr('r', 4)
.attr('class', 'circle all');
});
So a solution would be to also add the circle class along with the circle--highlight like this:
d3.select(this)
.attr('r', 6)
.attr('class', 'circle circle--highlight');
Or change your select in the updateChart like this:
svg.selectAll('circle')
but that would need many more adjustments to your script in order for it to work as expected.
Hope this helps! Good luck!
Original Code can be found at: http://bl.ocks.org/Guerino1/451f4c47842967dd813c8a64b24f7686
Problem: Applying .transition() code to different polygon sets appears to yield different results.
The following portion of the code seems to work as expected. Applying a transition causes the chevrons to transition onto the svg canvas, from left to right...
svgChevronsCanvas.selectAll("a")
.data(dataSet)
.enter().append("a")
.attr("xlink:href", function(d) { return d.link; })
.append("svg:polygon")
.attr("id", function(d,i){ return ("chevron_" + selectString.replace(/ /g,'_').replace(/#/g,'') + "_index_" + i); })
.attr("originalcolor", polygonPrimaryColor)
//.style("stroke","blue")
//.style("stroke-width",1)
.style("fill", polygonPrimaryColor)
.attr("points", chevronOrigin)
.on('mouseover', chevronMouseOver)
.on("mouseout", chevronMouseOut)
.on("click", chevronMouseOut)
.transition() // <------------------- TRANSITION HERE
.duration(3000)
.attr("points", calculateChevron);
The following code, which attempts to follow the same pattern as above does not seem to work as expected. Given the transition, I would expect the textboxes (in light blue below the chevrons), which are also drawn using D3 polygons, to transition onto their svg canvas from left to right, just like the chevron polygons in the above code...
svgTextboxesCanvas.selectAll("a")
.data(dataSet)
.enter().append("a")
.attr("xlink:href", function(d) { return d.link; })
.append("svg:polygon")
.attr("id", function(d,i){ return ("textbox_" + selectString.replace(/ /g,'_').replace(/#/g,'') + "_index_" + i); })
.attr("originalcolor", textboxColor)
.style("stroke", textboxColor)
.style("stroke-width",1)
.style("fill", textboxColor)
.attr("points", textboxesOrigin)
.on('mouseover', textboxMouseOver)
.on("mouseout", textboxMouseOut)
.on("click", textboxMouseOut)
.transition()
.duration(3000)
.attr("points", calculateTextbox);
Question: How do I properly add transitions to the D3 polygons that are built to look like rectangles (below the chevrons), in the latter set of code, and make them transition into the page just like the dark blue chevrons above them?
In the original code:
Make
var chevronGapSpace = 5;//this is the distance between each rectangle.
var slantDepth = 0;//to make the polygon rectangle.
Next, to make rectangle transition inside function calculateChevron change the calculations accordingly:
function calculateChevron(d, i){
return [
[(svgMargin) + i*(chevronDistance),chevronTopOffset],
[(svgMargin + chevronWidth - slantDepth) + i*(chevronDistance),chevronTop],
[(svgMargin + chevronWidth - slantDepth) + i*(chevronDistance),chevronPointY],
[(svgMargin + chevronWidth - slantDepth) + i*(chevronDistance),chevronBottom],
[(svgMargin) + i*(chevronDistance),chevronBottom],
[(svgMargin + slantDepth) + i*(chevronDistance),chevronPointY]
];
};
working code here
I'm coming to you today with another D3.js problem.
I have a simple bar chart.
When the mouse hovers a bar, a string is displayed on it.
This morning, I added a new transition that changes the background colour of the bar.
Now, the problem is the following:
If the .transition changing the background-color is placed under the one that displays the string, only the background colour changes, the string does not appear.
And if the .transition displaying the string is placed under the one that changes the background colour, only the string appears, without a change in the colour.
Here's a JSFiddle: http://jsfiddle.net/QbGRE/1/
d3.selectAll("div.bar")
.on("mouseover", function(d) {
d3.select(this)
.transition().duration(300)
.style("background-color", "#EE3B3B");
})
.on("mouseout", function(d) {
d3.select(this)
.transition().duration(300)
.style("background-color", "DarkRed");
});
d3.selectAll("div.line")
.append("div")
.attr("class","bar")
.style("width", function(d){return d.occurrence /10 + "px";})
.on("mouseover", function(d) {
d3.select(this)
.append("text").style("pointer-events", "none")
.text(function(d){return d.occurrence + " occurences";});
})
.on("mouseout", function(d) {
d3.select(this)
.select("text").remove();
});
Thank you all for your help, d3-savvy persons
The reason for this is that you're attaching mouse event handlers twice and the later ones overwrite the earlier ones. So first you're attaching the one that adds the text and then later you're attaching the one that changes the color which replaces the first.
The easiest way to fix this is to do everything you want to do on mouse events in one place:
.on("mouseover", function(d) {
d3.select(this)
.append("text").style("pointer-events", "none")
.text(function(d){return d.occurrence + " occurences";});
d3.select(this)
.transition().duration(300)
.style("background-color", "#EE3B3B");
})
.on("mouseout", function(d) {
d3.select(this)
.select("text").remove();
d3.select(this)
.transition().duration(300)
.style("background-color", "DarkRed");
});
Complete example here. Alternatively, you can use different namespaces for the event handlers:
.on("mouseover.text", function(d) {
// etc
});
.on("mouseover.color", function(d) {
// etc
});
Complete example here.