So I am trying to add links on a radial calendar using D3, where each day on the calendar contains a link that would show more details about that specific day. I am using this calendar as a base: http://jsfiddle.net/dmann99/q63WN/
For example, let's say I want to add a link to "google.com" on the days that are filled in (weekends).
// Draw faint arcs for each day (weekends filled, else outlined).
vis.selectAll("g.AllDays")
.data(dates)
.enter().append("svg:g")
.attr("class", "AllDays")
.attr("transform", "translate(" + r1 + "," + r1 + ")")
.append("svg:path")
.attr("stroke", function(d, i) { return d3.hsl(0,0.25,0.75) })
.attr("fill", function(d, i) {
return (d.getDay()==5||d.getDay()==6)?"#cccccc":"#ffffff";
})
.attr("d", arc)
;
Is there a way for me to add a link on the specific days that are filled in and not the whole calendar?
I tried adding something like this, but it didn't work:
.on("click", function() { window.open("http://google.com"); });
Any help is appreciated.
the pointer-events style property seems to be the key here (i.e. it doesn't work without it)
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointer-events
.filter (function(d) { return d.getDay() ==5 || d.getDay() ==6; })
.on("click", function() { window.open("http://google.com", "_blank"); })
css rule needed:
.WeekLine {
pointer-events: none
}
It was originally working with just the javascript change above when clicking weekend nodes around the edge of the display, but the .WeekLine circles were intercepting the mouse events for clicks in the interior of the display.
http://jsfiddle.net/q63WN/5/
(so pointer-events was still the thing to fiddle with, I just focused on the wrong elements to start with...)
Related
I'm trying to include tooltips on a map I'm making in D3, imitating this code:
http://bl.ocks.org/lhoworko/7753a11efc189a936371
And here is the map I'm working on:
https://pantherfile.uwm.edu/schro333/public/2016_electoral_map/
As you can see here, I have tooltips working, and they display the correct name when the user hovers over a state, but the position relative to the cursor is really off. I'm not sure why this is.
Relevant code:
svgContainer.selectAll("pathCodes")
.data(json.features)
.enter()
.append("path")
.attr("id",
function(d){
var stateNameId = d.properties.name.toString();
stateNameId = stateNameId.replace(/\s+/g, '');
return stateNameId;
}) // this function returns the name of the state with spaces stripped and assigns it to individual polygon as id
.attr("d", pathCodes)
.attr("stroke", "black") // state outline color
.attr("stroke-width", "1") // state outline width
.attr("class", "noparty") // default to no party
.style("fill", politicalParties[0].color) // default fill is that of no party
/////////////
.on('mousemove', function(d) {
var mouse = d3.mouse(svgContainer.node());
tooltip.classed('hidden', false)
.attr('style', 'left:' + (mouse[0]) +
'px; top:' + (mouse[1]) + 'px')
.html(d.properties.name);
})
.on('mouseout', function() {
tooltip.classed('hidden', true);
});
/////////////
You get the wrong position because the X/Y position you are using is based off the SVG and not the actual location of the SVG on the page.
You can use
var loc = document.getElementById("states-map").getBoundingClientRect();
console.log(loc.top); //add this to the top
to get the offset. Not sure the d3 way to do it.
I'm trying to surround the mouse point with a circle, much like a crosshair, and have this circle track the mouses movement. So far the best strategy I have is using D3 enter-update-exit:
Append circle on mouse point underpinned by data.
on mouse move add another circle to data array with data = new mouse point.
if data array exceeds 1, shift() the first value out.
update visualisation.
jsfiddle here - http://jsfiddle.net/hiwilson1/kur2bbv9/1/ - though I think it's largely irrelevent as this strategy is fundamentally flawed. The circle appears as though it's lagging behind the cursor and flickers. A lot. Which I don't want.
Key part of code here:
function onMove() {
var m = d3.mouse(this);
var point = {x: m[0], y: m[1]};
area.push(point)
document.getElementById("svg").onmousedown = function() {
mouseDown++;
addNode(m);
};
document.getElementById("svg").onmouseup = function() {
mouseDown--;
};
if (mouseDown > 0) {
addNode(m);
}
//if theres two circles, remove the first leaving just the second.
if (area.length > 1) {
area.shift();
}
var crosshair = svg.selectAll(".area")
.data([area])
crosshair
.attr("class", "area")
.attr("cx", m[0])
.attr("cy", m[1])
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-width", "3px")
.attr("r", 30)
crosshair.enter()
.append("circle")
.attr("class", "area")
.attr("cx", m[0])
.attr("cy", m[1])
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-width", "3px")
.attr("r", 30)
crosshair.exit().remove()
};
Is there another way of accomplishing this? Happy to accept non D3 strategies.
I couldn't get your JSfiddle to display anything, so I'm not sure if I'm totally missing the point, but could you just use a custom CSS cursor on top of your SVG element? It seems that .cur cursor files have the most wide-spread support. That would be a native alternative for custom hacks (thus giving better performance), and it would also degradate gracefully on un-supported browsers.
I am creating a heatmap for Ukraine with some economic indicators.
The Map
Depending on what radio-button is checked, a different colorscale is used to visualize
the different values/indicators.
d3.selectAll('.radio').on('change', function(){
if (document.getElementById('none').checked) {
areas.transition().duration(250)
.attr('fill','steelblue');}
else if (document.getElementById('agr').checked) {
areas.transition().duration(250)
.attr('fill', function(d){return colorScaleagr(d.properties.agricindx)});}
.... and so on.
Right now the tooltip (div) only shows the name of the region that is hovered over. I'd like to display also the value for the region, corresponding to the indicator that is selected at the moment. The tooltip's content (the name) is determined within an event-handler of the path/map element.
var areas = group.append('path')
.attr('d',path)
.attr('class', function(d) { return "subunit" + d.id; })
.attr('fill','steelblue')
.attr('stroke', 'white')
.attr('stroke-width', '1px')
.attr('opacity','0.8')
// Hover & Tooltip
.on("mouseover", function(d) {
d3.select(this).transition().duration(200).style("opacity", 1);
div.transition().duration(300).style("opacity", 1)
div.html(d.properties.name )
.style("left", (d3.mouse(this)[0] + 330) + "px")
.style("top", (d3.mouse(this)[1] + 15) + "px");
})
.on("mousemove", function(d) {
div.html(d.properties.name)
.style("left", (d3.mouse(this)[0] + 350) + "px")
.style("top", (d3.mouse(this)[1] + 25) + "px");
})
.on("mouseout", function(d) {
d3.select(this).transition().duration(200).style("opacity", 0.8);
div.transition().duration(300).style("opacity", 0)
});
So my question now is: How can i take into account the status of the radio-button,
whithin the path-element (area) , since the data for the single entities (regions)
is stored there. If I try to manipulate the tooltip within the radio-buttion selection, the data is not available to me. I hope I made myself understand :). I appreciate any help.
I think I understand what you are trying to do so here's an attempt of what I would do:
format you data as an object with key/value pairs as follow: 'none': 10, 'agr': 4, etc...
Store the key from the different radio buttons as a global variable that you update on the radio change function.
When creating your tooltip on the mouseover function, print the correct value by calling d[key], i.e. d['agr'].
Hope that helps!
In Mike Bostocks example http://bost.ocks.org/mike/nations/ there is so much data that putting the names of the countries there would make it chaotic, but for a smaller project I would like to display it.
I found this in the source:
var dot = svg.append("g")
.attr("class", "dots")
.selectAll(".dot")
.data(interpolateData(2004))
.enter().append("circle")
.attr("class", "dot")
.style("fill", function(d) { return color(d); })
.text(function(d) { return d.name; })
.call(position)
.sort(order);
dot.append("title")
.text(function(d) { return d.name; });
But somehow a title never shows up. Does anybody have an idea, how to display the name, next to the bubble?
As the other answer suggests, you need to group your elements together. In addition, you need to append a text element -- the title element only displays as a tooltip in SVG. The code you're looking for would look something like this.
var dot = svg.append("g")
.attr("class", "dots")
.selectAll(".dot")
.data(interpolateData(2004))
.enter()
.append("g")
.attr("class", "dot")
.call(position)
.sort(order);
dot.append("circle")
.style("fill", function(d) { return color(d); });
dot.append("text")
.attr("y", 10)
.text(function(d) { return d.name; });
In the call to position, you would need to set the transform attribute. You may have to adjust the coordinates of the text element.
Unfortunately grouping the text and circles together will not help in this case. The bubbles are moved by changing their position attributes (cx and cy), but elements do not have x and y positions to move. They can only be moved with a transform-translate. See: https://www.dashingd3js.com/svg-group-element-and-d3js
Your options here are:
1) rewrite the position function to calculate the position difference (change in x and change in y) between the elements current position and its new position and apply that to the . THIS WOULD BE VERY DIFFICULT.
or 2) Write a parallel set of instructions to setup and move the tags. Something like:
var tag = svg.append("g")
.attr("class", "tag")
.selectAll(".tag")
.data(interpolateData(2004))
.enter().append("text")
.attr("class", "tag")
.attr("text-anchor", "left")
.style("fill", function(d) { return color(d); })
.text(function(d) { return d.name; })
.call(tagposition)
.sort(order);
You will need a separate tagposition function since text needs 'x' and 'y' instead of 'cx', 'cy', and 'r' attributes. Don't forget to update the "displayYear" function to change the tag positions as well. You will probably want to offset the text from the bubbles, but making sure the text does not overlap is a much more complicated problem: http://bl.ocks.org/thudfactor/6688739
PS- I called them tags since 'label' already means something in that example.
you have to wrap the circle element and text together , it should look like
<country>
<circle ></circle>
<text></text>
</country>
I have a set of randomly plotted diamonds, squares & circles on my canvas. I have one of each lined in a straight line which is created by my go variable. I wish to use the onclick function upon this variable to filter or make the shapes disappear depending on which parameter I give it. e.g. squares will only show squares on the canvas etc.
So far I have started with this basic example:
.on("click", function(d){ if (d.shape == 'square') { return alert('success') ;} })
I then moved onto this:
.on("click", function(d){ if (d.shape =='circle') { return d3.selectAll(".node").filter(function(d) {return d.country === 'USA'} ) } ;})
When I have applied that, it doesnt result to any errors or actions. I'm pretty sure I'm going in the right direction, just would like some help getting there
http://jsfiddle.net/Zc4z9/19/
Thanks, in advance!
You are doing nothing with your selection. If you need to hide it just add .style("display", "none")
.on("click", function(d){
if (d.shape =='circle') {
d3.selectAll(".node")
.filter(function(d) {return d.country === 'USA'} )
.style("display", "none");
}
})