html label inside d3 element - javascript

I have written the following code (it's a toy example, here on jsfiddle) to show a label when hovering a shape:
var lbl;
var svg = d3.select("#chart").append("svg")
.attr("width", 200)
.attr("height", 200);
svg.append("rect")
.attr("x", 50)
.attr("y", 0)
.attr("width",50)
.attr("height",50)
.attr("label","first line"+"<br/>"+"second line")
.style("fill", "yellow")
.on("mouseover",function() {
var th=d3.select(this);
lbl=svg.append("text")
.attr("x", th.attr("x")*1+th.attr("width")/2)
.attr("y", th.attr("y")*1+th.attr("height")/2)
.attr("dy", "0.5em")
.style("text-anchor", "middle")
.style("visibility", "visible")
.attr("pointer-events", "none")
.text(th.attr("label"));
})
.on("mouseout",function(){
lbl.remove();
});
How can I render the label in html format?

You can make a div and give css position:absolute
so that you can now position it w.r.t. the top and left calculated.
Also set the text within the div like .html("your html<br> text")
var th=d3.select(this);
lbl=d3.select("#chart").append("div")
.attr("class", "tooltip")
.style("left", (th.attr("x")*1+th.attr("width")/2) + "px")
.style("top", (th.attr("y")*1+th.attr("height")/2) + "px")
.html(th.attr("label"));
working code here

Related

D3.js heatmap with color

Hi I am trying to add in a color scale for my heat map. I Specifically want to use d3.schemeRdYlBu this color scheme but I am having a hard time implementing it. At the moment it just does black. I also have a hover feature with this so I would like that to still work but i am more concerned with just getting the color to work. Obviously having the lower numbers be blue and the higher numbers be red to indicate temp
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<!-- Load color palettes -->
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 80, right: 25, bottom: 30, left: 40},
width = 1000 - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/Nataliemcg18/Data/master/NASA_Surface_Temperature.csv", function(data) {
// Labels of row and columns -> unique identifier of the column called 'group' and 'variable'
var myGroups = d3.map(data, function(d){return d.group;}).keys()
var myVars = d3.map(data, function(d){return d.variable;}).keys()
// Build X scales and axis:
var x = d3.scaleBand()
.range([ 0, width ])
.domain(myGroups)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickSize(0))
.select(".domain").remove()
// Build Y scales and axis:
var y = d3.scaleBand()
.range([ height, 0 ])
.domain(myVars)
.padding(0.05);
svg.append("g")
.style("font-size", 15)
.call(d3.axisLeft(y).tickSize(0))
.select(".domain").remove()
// Build color scale
var myColor = (d3.schemeRdYlBu[2])
// create a tooltip
var tooltip = d3.select("#my_dataviz")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover = function(d) {
tooltip
.style("opacity", 1)
d3.select(this)
.style("stroke", "green")
.style("opacity", 1)
}
var mousemove = function(d) {
tooltip
.html("The exact value of this cell is: " + d.value, )
.style("left", (d3.mouse(this)[0]+70) + "px")
.style("top", (d3.mouse(this)[1]) + "px")
}
var mouseleave = function(d) {
tooltip
.style("opacity", 0)
d3.select(this)
.style("stroke", "none")
.style("opacity", 0.8)
}
// add the squares
svg.selectAll()
.data(data, function(d) {return d.group+':'+d.variable;})
.enter()
.append("rect")
.attr("x", function(d) { return x(d.group) })
.attr("y", function(d) { return y(d.variable) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", x.bandwidth() )
.attr("height", y.bandwidth() )
.style("fill", function(d) { return myColor(d.value)} )
.style("stroke-width", 4)
.style("stroke", "none")
.style("opacity", 0.8)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave)
})
// Add title to graph
svg.append("text")
.attr("x", 0)
.attr("y", -50)
.attr("text-anchor", "left")
.style("font-size", "22px")
.text("A d3.js heatmap");
// Add subtitle to graph
svg.append("text")
.attr("x", 0)
.attr("y", -20)
.attr("text-anchor", "left")
.style("font-size", "14px")
.style("fill", "grey")
.style("max-width", 400)
.text("A short description of the take-away message of this chart.");
</script>
You can use arrow function instead of the regular function to use your own binding of this for accessing myColor variable.
<!DOCTYPE html>
<meta charset="utf-8" />
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<!-- Load color palettes -->
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = { top: 80, right: 25, bottom: 30, left: 40 },
width = 1000 - margin.left - margin.right,
height = 1000 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3
.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv(
"https://raw.githubusercontent.com/Nataliemcg18/Data/master/NASA_Surface_Temperature.csv",
function (data) {
// Labels of row and columns -> unique identifier of the column called 'group' and 'variable'
var myGroups = d3
.map(data, function (d) {
return d.group;
})
.keys();
var myVars = d3
.map(data, function (d) {
return d.variable;
})
.keys();
// Build X scales and axis:
var x = d3.scaleBand().range([0, width]).domain(myGroups).padding(0.05);
svg
.append("g")
.style("font-size", 15)
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickSize(0))
.select(".domain")
.remove();
// Build Y scales and axis:
var y = d3.scaleBand().range([height, 0]).domain(myVars).padding(0.05);
svg
.append("g")
.style("font-size", 15)
.call(d3.axisLeft(y).tickSize(0))
.select(".domain")
.remove();
// Build color scale
var myColor = d3.schemeRdYlBu[3][2];
// create a tooltip
var tooltip = d3
.select("#my_dataviz")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px");
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover = function (d) {
tooltip.style("opacity", 1);
d3.select(this).style("stroke", "green").style("opacity", 1);
};
var mousemove = function (d) {
tooltip
.html("The exact value of this cell is: " + d.value)
.style("left", d3.mouse(this)[0] + 70 + "px")
.style("top", d3.mouse(this)[1] + "px");
};
var mouseleave = function (d) {
tooltip.style("opacity", 0);
d3.select(this).style("stroke", "none").style("opacity", 0.8);
};
// add the squares
svg
.selectAll()
.data(data, function (d) {
return d.group + ":" + d.variable;
})
.enter()
.append("rect")
.attr("x", function (d) {
return x(d.group);
})
.attr("y", function (d) {
return y(d.variable);
})
.attr("rx", 4)
.attr("ry", 4)
.attr("width", x.bandwidth())
.attr("height", y.bandwidth())
.style("fill", (d) => {
return myColor;
})
.style("stroke-width", 4)
.style("stroke", "none")
.style("opacity", 0.8)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave);
}
);
// Add title to graph
svg
.append("text")
.attr("x", 0)
.attr("y", -50)
.attr("text-anchor", "left")
.style("font-size", "22px")
.text("A d3.js heatmap");
// Add subtitle to graph
svg
.append("text")
.attr("x", 0)
.attr("y", -20)
.attr("text-anchor", "left")
.style("font-size", "14px")
.style("fill", "grey")
.style("max-width", 400)
.text("A short description of the take-away message of this chart.");
</script>
This is another way to get the desired results
var myColor = d3.scaleSequential()
.interpolator( d3.interpolateRdYlBu)
.domain([1.37, -.81])

d3-zoom breaks when cursor is over an inner svg element

I have implemented d3-zoom by following this brief tutorial.
I'm using https://d3js.org/d3.v5.min.js. This is my first project with d3.
My goal is to have a kind of floor plan showing booth tables at a venue. Similar to the tutorial, I've drawn shape elements from an array. In my case I've entered an array of booth information into a grid of elements.
The zoom functionality works just fine, except when my cursor is over the border or fill of one of my rectangles, or on the text of a element. If the point of my cursor is touching any of these elements, the zooming behavior stops working.
Try to zoom with the mousewheel with your cursor in blank space versus touching a shape or text.
I've tried to fit a console.log in somewhere to see what's not getting passed in the event, but have had trouble even finding where I can get the event argument.
Any help greatly appreciated! Here is my code:
var svg = d3.select("#venue-svg"); // this is my svg element
// the zoom rectangle. from the tutorial: 'The zoom behavior is applied
// to an invisible rect overlaying the SVG element; this ensures that it
// receives input, and that the pointer coordinates are not affected by
// the zoom behavior’s transform.'
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.style("fill", "none")
.style("pointer-events", "all")
.call(
d3
.zoom()
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed)
);
function zoomed() {
g.attr("transform", d3.event.transform);
}
// a parent <g> that holds everything else and is targeted
// for the transform (from the tutorial).
var g = svg.append("g");
// the groups that hold each booth table, associated org name, etc.
var tables = g
.selectAll("g")
.data(venueBooths)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + d.x + " " + d.y + ")";
});
var tableRects = tables
.append("rect")
.attr("stroke", "steelblue")
.attr("stroke-width", "2px")
.attr("width", function(d) {
return d.w;
})
.attr("height", function(d) {
return d.h;
})
.attr("fill", "none")
.attr("fill", function(d) {
return $.isEmptyObject(d.reservation) ? "none" : "#FF5733";
})
.attr("id", function(d) {
return "table-" + d.id;
});
tables
.append("text")
.text(function(d) {
return "Booth " + d.id;
})
.attr("dx", 5)
.attr("dy", 60)
.attr("font-size", "8px");
tables
.append("text")
.text(function(d) {
return d.reservation.orgName ? d.reservation.orgName : "Available";
})
.attr("dy", 15)
.attr("dx", 5)
.attr("font-size", "9px")
.attr("font-weight", "bold");
Try creating the rect in the end such that the DOM looks like this:
<svg>
<g></g>
<rect></rect>
</svg>
Since the zoom function is attached to the large rectangle, creating the smaller boxes above it prevents a zoom event from propagating to the large rectangle below them. It works for the boxes with a fill: none; since it behaves like a hollow box.
Try modifying the code to something like:
var svg = d3.select("#venue-svg"); // this is my svg element
// the zoom rectangle. from the tutorial: 'The zoom behavior is applied
// to an invisible rect overlaying the SVG element; this ensures that it
// receives input, and that the pointer coordinates are not affected by
// the zoom behavior’s transform.'
function zoomed() {
g.attr("transform", d3.event.transform);
}
// a parent <g> that holds everything else and is targeted
// for the transform (from the tutorial).
var g = svg.append("g");
// the groups that hold each booth table, associated org name, etc.
var tables = g
.selectAll("g")
.data(venueBooths)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + d.x + " " + d.y + ")";
});
var tableRects = tables
.append("rect")
.attr("stroke", "steelblue")
.attr("stroke-width", "2px")
.attr("width", function(d) {
return d.w;
})
.attr("height", function(d) {
return d.h;
})
.attr("fill", "none")
.attr("fill", function(d) {
return $.isEmptyObject(d.reservation) ? "none" : "#FF5733";
})
.attr("id", function(d) {
return "table-" + d.id;
});
tables
.append("text")
.text(function(d) {
return "Booth " + d.id;
})
.attr("dx", 5)
.attr("dy", 60)
.attr("font-size", "8px");
tables
.append("text")
.text(function(d) {
return d.reservation.orgName ? d.reservation.orgName : "Available";
})
.attr("dy", 15)
.attr("dx", 5)
.attr("font-size", "9px")
.attr("font-weight", "bold");
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.style("fill", "none")
.style("pointer-events", "all")
.call(
d3
.zoom()
.scaleExtent([1 / 2, 4])
.on("zoom", zoomed)
);

Embed a svg shape in d3tip tooltip

I'm working with the popular tip library d3-tip.js, an example of it can be found here. Typically, the tip contains text that is defined dynamically like this:
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
html = "";
html += "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";
return html;
})
However, lets say I have a legend like this:
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
I would like to somehow append a small svg rect inside the d3 toolip. This way when you hover over a graph with different classes (i.e. grouped bar chart) the tooltip will have a svg rect of matching color in addition to the html text. Ideally by using an existing legend variable, as seen above.
If it's not possible, then just explain why and I can accept that as an answer as well.
For clarity, here is a rough idea of what I'm going for visually:
It's easy to create an SVG inside a d3.tip tooltip. Actually, you just have to use the same logic of any other D3 created SVG: select the container and append the SVG to it.
In the following demo, in your var tip, I'll create an empty div with a given ID. In this case, the div has an ID named mySVGtooltip:
var tool_tip = d3.tip()
.attr("class", "d3-tip")
.offset([20, 40])
.html("<div id='mySVGtooltip'></div>");
After that, it's just a matter of, inside the mouseover event, selecting that div by ID and appending the SVG to it:
var legendSVG = d3.select("#mySVGtooltip")
.append("svg")
.attr("width", 160)
.attr("height", 50);
Here is the demo, hover over the circles:
var svg = d3.select("body")
.append("svg")
.attr("width", 300)
.attr("height", 300);
var tool_tip = d3.tip()
.attr("class", "d3-tip")
.offset([20, 40])
.html("<div id='mySVGtooltip'></div>");
svg.call(tool_tip);
var data = [20, 10, 30, 15, 35];
var circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle");
circles.attr("cy", 50)
.attr("cx", function(d, i) {
return 30 + 55 * i
})
.attr("r", function(d) {
return d
})
.attr("fill", "lightgreen")
.attr("stroke", "dimgray")
.on('mouseover', function(d) {
tool_tip.show();
var legendSVG = d3.select("#mySVGtooltip")
.append("svg")
.attr("width", 160)
.attr("height", 50);
var legend = legendSVG.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10);
legend.append("text")
.attr("x", 80)
.attr("text-anchor", "middle")
.attr("y", 16)
.attr("font-size", 14)
.text("Age Group:");
legend.append("rect")
.attr("y", 25)
.attr("x", 10)
.attr("width", 19)
.attr("height", 19)
.attr("fill", "goldenrod");
legend.append("text")
.attr("x", 35)
.attr("y", 40)
.text(function() {
return d + " years and over";
});
})
.on('mouseout', tool_tip.hide);
.d3-tip {
line-height: 1;
background: gainsboro;
border: 1px solid black;
font-size: 12px;
}
p {
font-family: Helvetica;
}
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
Notice that, in this very simple demo, I'm using the datum (d) passed to the anonymous function by the mouseover event. I'm seeing in your question that you have your own data. Thus, change the code in my demo accordingly.

D3.js How to add tooltip in my legend using line graph

I draw a line graph using D3.js and i am using tooltip in line graph,but i am also using tooltip in legends but enable to show the tooltip in legends,i wrote given code,it is possible to show the tooltip in legends.
var dates=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31];
var legend = canvas.append("g")
.attr("class", "legend")
// .attr("transform", "translate(70,10)");
var legendRect = legend.selectAll('rect').data(dates);
legendRect.enter()
.append("rect")
.attr("x", function (d,i){return i*14;})
.attr("width", 12)
.attr("height", 20)
.attr("y", 10)
.style("fill","steelblue")
legend.selectAll("text")
.data(dates)
.enter()
.append("text")
.attr("x", function (d,i){return i*14;})
.attr("y", 25)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.text(function(d) {
return d;
})
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(formatTime(d.key) + "<br/>" + d.value)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY-28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
Iam adding tooltip in text but enable to show the tooltip in my values(I have only problem in legend tooltip)
Check out this code. It does exactly what you want.
This is also a great example.

D3.js IE vs Chrome SVG not showing

I have a simple D3 donut diagram with a .mouseover() event that updates an SVG:text element at the center of the donut hole. It works great...
Until I encounter users with IE 9, 10 and 11. These browsers won't render the center label. Is there a way to accommodate IE and show the center label in both browsers?
The HTML page is based on HTML5BoilerPlate with the various shims to detect old browsers.
The D3 script seems pretty straight forward.
d3.json("data/census.php", function(error, dataset) {
var h = 220, w = 295;
var outerRadius = h / 2, innerRadius = w / 4;
var color = d3.scale.category20b();
var svg= d3.select("#dailycensus")
.append("svg")
.data([dataset])
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie()
.value(function(d,i) { return +dataset[i].Census; });
var arcs = svg.selectAll("g.slice")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice");
var syssum = d3.sum(dataset, function(d,i) { return +dataset[i].Census; });
var tip = d3.tip()
.attr("class", "d3-tip")
.html(String);
var formatter = d3.format(".1%");
svg.append("text")
.attr("id", "hospital")
.attr("class", "label")
.attr("y", -10)
.attr("x", 0)
.html("Health System Census"); // Default label text
svg.append("text")
.attr("id", "census")
.attr("class", "census")
.attr("y", 40)
.attr("x", 0)
.html(syssum); // Default label value
arcs.append("svg:path")
.call(tip) // Initialize the tooltip in the arc context
.attr("fill", function(d,i) { return color(i); }) // Color the arc
.attr("d", arc)
.on("mouseover", function(d,i) {
tip.show( formatter(dataset[i].Census/syssum) );
// Update the doughnut hole label with slice meta data
svg.select("#hospital").remove();
svg.select("#census").remove();
svg.append("text")
.attr("id", "hospital")
.attr("class", "label")
.attr("y", -10)
.attr("x", 0)
.html(dataset[i].Facility);
svg.append("text")
.attr("id", "census")
.attr("class", "census")
.attr("y", 40)
.attr("x", 0)
.html(+dataset[i].Census);
})
.on("mouseout", function(d) {
tip.hide();
// Return the doughnut hole label to the default label
svg.select("#hospital").remove();
svg.select("#census").remove();
svg.append("text")
.attr("id", "hospital")
.attr("class", "label")
.attr("y", -10)
.attr("x", 0)
.html("Health System Census");
svg.append("text")
.attr("id", "census")
.attr("class", "census")
.attr("y", 40)
.attr("x", 0)
.html(syssum);
})
Replace all the .html calls with .text calls. Generally innerHTML is for HTML things although browsers are giving it SVG support as everybody keeps expecting it to work.
It's not immediately clear what is causing the issue, however setting the .text property instead resolves the issue after testing with Fiddler:
svg.append("text")
.attr("id", "hospital")
.attr("class", "label")
.attr("y", -10)
.attr("x", 0)
.text(dataset[i].Facility);
svg.append("text")
.attr("id", "census")
.attr("class", "census")
.attr("y", 40)
.attr("x", 0)
.text(+dataset[i].Census);
})
After investigating the <text /> elements directly in the Developer Tools you can see that setting the .innerHTML property doesn't render the results you'd expect, however .textContent does.
If this is working as expected in both Chrome and Firefox, I'll gladly open up an interop bug for the IE team to look into. We've been doing some SVG work lately, so I may find that this has already been discussed.
I had the same issue and innerSvg polyfill helps me. Now html() in SVG works in IE.

Categories

Resources