How to Show D3.js Chart inside Liferay 7 MVC Portlet - d3.js

I am very new to Liferay.
I would like to show my graph created by D3.js inside of a portlet.
I have created the default MVC portlet.
However, I have no idea how to show my graph inside a MVC portlet.
Can you please advise?
<!DOCTYPE html>
<html>
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<body>
<div class="chart">
</div>
<script>
var data = [30, 86, 168, 281, 303, 365];
d3.select(".chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("width", function(d) { return d * 2 + "px"; })
.text(function(d) { return '$ ' + d; });
</script>
</body>
</html>

Related

Cannot get D3 .on('mouseover', ...) to work

I'm learning D3 and I'm trying to display data infomation on a scatterplot by hovering on the SVG circles. I take the data from a csv file (data is on the Solar System, with planet names, masses and radiuses) and all the circles show up correctly but when I try to console.log the data information (for instance the mass) on mouseover it does not log anything. The mouseover action is functioning OK but the console tells me that the value requested is "undefined".
Where did I mess up? This is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<style type="text/css">
body{
background-color: black;
}
#chart{
background-color: black;
width: 800px;
height: 500px;
border: solid 1px white;
}
svg{
background-color: white;
}
.dot{
stroke: red;
stroke-width: 1px;
}
</style>
<script type="text/javascript" src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var width = 800;
var height = 500;
var circles;
var svg = d3.select('#chart')
.append('svg')
.attr('width', width + 'px')
.attr('height', height + 'px');
d3.csv('astro.csv').then(function(data){
xScale = d3.scaleLinear()
.domain([0,500])
.range([0, 800]);
circles = svg.selectAll('.dot')
.data(data)
.enter()
.append('circle')
.attr('class', '.dot')
.attr('cx', function(d){
return xScale(d.mass);
})
.attr('cy', 100)
.attr('r', 20)
.on('mouseover', function(d){
console.log(d.mass);
})
});
</script>
</body>
</html>
Since D3 V6, all mouse event handlers has an event passed as the first argument and data as the second. In the V5 or earlier, your code will work.
V6 or higher:
.on('mouseover', (event, d) => console.log(d.mass));
V5 or earlier:
.on('mouseover', d => console.log(d.mass));

Pie Chart not rendering in dashboard area using D3 v5

I have been trying to render a simple two value pie chart using D3.JS v5 in the lower right corner to no avail. Can someone please assist me with this - the code can be found here:
Codepen
<body>
<div id = "orgChart"></div>
<div id = "mapChart"></div>
<div id = "pieChart"></div>
<script>
/******************************************************************************
Pie Chart
******************************************************************************/
function makePie() {
var widthPie = (window.innerWidth * 0.3) ,
heightPie = (window.innerHeight * 0.3);
var data = [
{name: "Males", count: 43, percent: 61 }
, {name: "Females", count: 27, percent: 39}
];
var pie = d3.pie().value(d=>d.count).padAngle(0.025)(data);
var arcMkr = d3.arc().innerRadius(20).outerRadius(35)
.cornerRadius(4);
var scC = d3.scaleOrdinal(d3.schemePastel1)
.domain(pie.map(d=>d.index));
var g = d3.select("#pieChart")
.append("g").attr("transform", "translate(widthPie/2, heightPie/2)");
g.selectAll("path.x").data(pie).enter().append("path")
.attr("d", arcMkr)
.attr("fill", d=> scC(d.index)).attr("stroke", "grey");
g.selectAll("text.x" ).data( pie ).enter().append( "text")
.text(d => d.data.name +": " + d.data.percent + "%")
.attr("x", d=>arcMkr.innerRadius(20).centroid(d)[0])
.attr("y", d=>arcMkr.innerRadius(20).centroid(d)[1])
.attr("font-family", "sans-serif").attr( "font-size", 8)
.attr("text-anchor", "middle")
;
}
makePie();
</script>
As #Tom Shanley has indicated in the comments, the reason of why your pie chart is not rendered as expected is because you need to create a SVG first.
Notice that I've also changed some CSS properties of #pieChart for improving the snippet visibility, although it is not necessary for your purposes.
<!DOCTYPE html>
<html lang = 'en'>
<head>
<meta charset = 'utf-8'>
<meta name = 'viewport' content = 'width = device-width, initial-scale = 1.0'>
<meta http-equiv = 'X-UA-Compatible' content = 'ie=edge'>
<meta name = 'author' content = "Tom Bellmer">
<meta name = 'date.created' content="03/05/2020">
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>Org Chart</title>
<style>
body{
background-color: #faf2e4;
font-family: sans-serif;
font-size: 1.2em;
}
text{font-size: .6em}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1px;
}
.node text {
font: 9px sans-serif;
font-weight: normal;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1px;
}
#orgChart{
position:absolute;
top: 10px;
left: 10px;
width: 65%;
height: 85%;
}
#mapChart{
position:absolute;
top: 10px;
left: 66%;
width: 34%;
height: 50%;
}
#pieChart{
position:absolute;
top: 51%;
left: 66%;
width: 34%;
height: 55%;
background-color: crimson;
}
circle {
/* fill: #FF8533; */
fill: steelblue;
fill-opacity: .8;
stroke: #fff;
}
circle:hover { fill: red;}
div.tooltip {
position: absolute;
text-align: center;
width: 130px;
height: 14px;
padding: 2px;
font: 11px sans-serif;
background: dodgerblue;
color: white;
border: 0px;
pointer-events: none;
}
svg g{
fill: white;
stroke: black;
}
svg text{fill: black;}
</style>
</head>
<body>
<div id = "orgChart"></div>
<div id = "mapChart"></div>
<div id = "pieChart"></div>
<script>
/******************************************************************************
Pie Chart
******************************************************************************/
function makePie() {
var widthPie = (window.innerWidth * 0.5) ,
heightPie = (window.innerHeight * 0.5);
var data = [
{name: "Males", count: 43, percent: 61 },
{name: "Females", count: 27, percent: 39}
];
var pie = d3.pie().value(d=>d.count).padAngle(0.025)(data);
var arcMkr = d3.arc().innerRadius(20).outerRadius(35)
.cornerRadius(4);
var scC = d3.scaleOrdinal(d3.schemePastel1)
.domain(pie.map(d=>d.index));
// Modified ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var svg = d3.select("#pieChart")
.append("svg")
.attr("width", widthPie)
.attr("height", heightPie);
var g = svg.append("g").attr("transform", `translate(${widthPie/2}, ${heightPie/2})`);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
g.selectAll("path.x").data(pie).enter().append("path")
.attr("d", arcMkr)
.attr("fill", d=> scC(d.index)).attr("stroke", "grey");
g.selectAll("text.x" ).data( pie ).enter().append( "text")
.text(d => d.data.name +": " + d.data.percent + "%")
.attr("x", d=>arcMkr.innerRadius(20).centroid(d)[0])
.attr("y", d=>arcMkr.innerRadius(20).centroid(d)[1])
.attr("font-family", "sans-serif").attr( "font-size", 8)
.attr("text-anchor", "middle");
}
makePie();
</script>
</body>

bBox of SVG is zero

Why the result of bBox.width, bBox.height are both 0? I expect them to be both 500px, how to rectify it?
<!DOCTYPE html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<!--script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.9/d3.js" type="text/JavaScript"></script-->
<style>
rect {
stroke: #9A8B7A;
stroke-width: 1px;
fill: #CF7D1C;
}
svg{
width: 500px;
height: 500px;
background:blue;
}
</style>
<body>
</body>
<script>
var svg = d3.select("body").append("svg");
var bBox = svg.node().getBBox();
console.log(bBox.width + 'x' + bBox.height);
</script>
Try getBoundingClientRect instead of getBBox.

d3js simple barchart not showing

I've copied the code below from the example provided here https://scrimba.com/casts/cast-1953
However, no graph is shown. I also get no errors in the console.
When I enter d3 in the console an object is returned, so d3 is found.
What am I missing?
<head>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<script type="text/javascript">
var data = [30, 86, 168, 281, 303, 365];
d3.select(".chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("width", function (d) { return d + "px"; })
.text(function (d) { return d; });
</script>
</head>
<body>
<div class="chart"></div>
</body>
Instead using script in head, try to use at the bottom of the page or use when page is ready.
<head>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<div class="chart"></div>
<script type="text/javascript">
var data = [30, 86, 168, 281, 303, 365];
d3.select(".chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("width", function (d) { return d + "px"; })
.text(function (d) { return d; });
</script>
You must place the body before the script like so:
<body>
<div class="chart"></div>
</body>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.chart div {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<script type="text/javascript">
var data = [30, 86, 168, 281, 303, 365];
d3.select(".chart")
.selectAll("div")
.data(data)
.enter()
.append("div")
.style("width", function(d) {
return d + "px";
})
.text(function(d) {
return d;
});
</script>

Binding on click events to context menu list elements

I am generating dynamic context menus that appear when the user right clicks on a shape. I have managed to create the context menu, but I am having trouble catching the click event when the user selects an entry from the menu.
The event keeps binding to the right click action to create the context menu instead of a left click on the list items within the menu itself.
I have dug around SO a bunch and been unable to unearth something that will get me the rest of the way.
What I want is for the console.log function in this example to trigger when the user clicks a list element and pass the name of the item clicked. In a perfect world it would not trigger on the initial right click, but I'll take what I can get.
<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<style>
.context-menu {
position: absolute;
display: none;
background-color: #f2f2f2;
border-radius: 4px;
font-family: Arial, sans-serif;
font-size: 14px;
min-width: 150px;
border: 1px solid #d4d4d4;
z-index:1200;
}
.context-menu ul {
list-style-type: none;
margin: 4px 0px;
padding: 0px;
cursor: default;
}
.context-menu ul li {
padding: 4px 16px;
}
.context-menu ul li:hover {
background-color: #4677f8;
color: #fefefe;
}
</style>
<script>
var fruits = ["Apple", "Orange", "Banana", "Grape"];
var svgContainer = d3.select("body")
.append("svg")
.attr("width", 200)
.attr("height", 200);
var circle = svgContainer
.append("circle")
.attr("cx", 30)
.attr("cy", 30)
.attr("r", 20)
.on('contextmenu', function(d,i) {
// create the div element that will hold the context menu
d3.selectAll('.context-menu').data([1])
.enter()
.append('div')
.attr('class', 'context-menu');
// close menu
d3.select('body').on('click.context-menu', function() {
d3.select('.context-menu').style('display', 'none');
});
// this gets executed when a contextmenu event occurs
d3.selectAll('.context-menu')
.html('')
.append('ul')
.selectAll('li')
.data(fruits).enter()
.append('li')
// THIS IS WHAT I CAN NOT GET TO WORK THE WAY I WANT IT TO WORK
.on('click' , console.log( function(d) { return d; } + " clicked!"))
.text(function(d) { return d; });
d3.select('.context-menu').style('display', 'none');
// show the context menu
d3.select('.context-menu')
.style('left', (d3.event.pageX - 2) + 'px')
.style('top', (d3.event.pageY - 2) + 'px')
.style('display', 'block');
d3.event.preventDefault();
});
</script>
</body>
</html>
Here is a plunkr demonstrating the code (I can't figure out why I couldn't get it to run with jsfiddle): http://run.plnkr.co/plunks/paPKKlUFtQCGpOmjQztS/
Please see this fiddle
I basically updated your click listener to this:
.on('click' , function(d) { console.log(d); return d; })
It seems to be working fine.

Resources