Bootstrap + C3; Grid layout doesn't work on load - javascript

C3 version: 0.6.7
D3 version: 5
Browser: Firefox ESR
OS: Debian 9
I want to make a web page that has four rows of three donut charts each. I'm using Bootstrap with C3.js.
My code looks like this.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>U.S. presidential vote, 1972-2016, by race</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="css/c3.min.css" rel="stylesheet">
<style type="text/css">
.c3-chart-arcs-title {
font-size: 1.5rem;
}
</style>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="js/c3.min.js"></script>
<script type="text/javascript">
var dataDir = "vote-by-race";
d3.csv(dataDir + "/white.csv").then(function(data) {
var row;
data.forEach(function(d, i) {
if (i % 3 === 0) {
row = document.createElement("div");
row.className = "row";
}
var col = document.createElement("div");
col.className = "col-sm";
var chartDiv = document.createElement("div");
chartDiv.id = "chart" + i;
col.appendChild(chartDiv);
row.appendChild(col);
document.getElementById("charts").appendChild(row);
var chartDataObj = Object.assign({}, d);
delete chartDataObj["Year"];
var chart = c3.generate({
data: {
json: chartDataObj,
type: "donut",
colors: {
Democrat: "#2166ac",
Republican: "#b2182b",
Other: "#bbb"
}
},
tooltip: {
show: false
},
legend: {
show: false
},
donut: {
title: d["Year"],
label: {
format: function(value, ratio, id) {
return d3.format('.0%')(value / 100);
}
}
},
bindto: '#' + chartDiv.id
});
});
});
</script>
</head>
<body>
<div id="charts" class="container"></div>
</body>
</html>
My CSV...
Year,Democrat,Republican,Other
1972,32,66,2
1976,47,52,1
1980,35,56,9
1984,35,64,1
1988,40,59,1
1992,39,40,21
1996,43,46,11
2000,42,54,4
2004,41,58,1
2008,43,55,2
2012,39,59,2
2016,37,58,5
When I load the page in my browser, I see 12 donut charts in a single vertical column. But when I resize the browser window to its thinnest, then expand it again, I see four rows of three donut charts each.
How do I make the browser show four rows of three charts each when the charts are first loaded?

Related

Leaflet map with embedded Bootstrap Switch toggle

I am trying to add a bootstrap switch inside my leaflet.js map.
So far I have a working button (see snippet) but I want to use a switch instead.
See attached image:
So far it is a complete failure.
Among the things I have tried is the code below (which obviously does not work):
var customControl_2 = L.Control.extend({
options: {
position: 'topright'
},
onAdd: function (map) {
var container = L.DomUtil.create('input', 'mySwitch');
container = $("[class='mySwitch']").bootstrapSwitch({})
//container.onclick = function(){
// console.log('buttonClicked');
//}
return container;
}
});
map.addControl(new customControl_2());
Does anyone know how this should work please? As always, any help is greatly appreciated. If the same toggle switch can be achieved in some other way (ie without bootstrap) that is also going to be fine.
Many thanks!
<!DOCTYPE html>
<html>
<head>
<title>Leaflet</title>
<meta charset="utf-8" />
<!--jquery -->
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<!-- bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<!-- bootstrap switch -->
<link rel="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.js"></script>
<!--d3 -->
<script src='https://d3js.org/d3.v4.min.js'></script>
<!-- leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet.js"></script>
<style>
html,
body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id='map'></div>
<script type="text/javascript">
var map = L.map('map', {
minZoom: 0,
}).setView([37, -103], 3);
var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: "CartoDB"
}).addTo(map);
// Toggle button to turn layers on and off
var customControl = L.Control.extend({
options: {
position: 'topright'
},
onAdd: function(map) {
var container = L.DomUtil.create('input');
container.type = "button";
container.title = "Some title";
container.value = "Off";
container.style.backgroundColor = 'white';
container.style.backgroundSize = "80px 30px";
container.style.width = '80px';
container.style.height = '30px';
function toggle(button) {
if (button.value == "Off") {
button.value = "On"
button.innerHTML = "On"
removeLayers();
} else if (button.value == "On") {
button.value = "Off"
button.innerHTML = "Off"
addLayers();
}
}
container.onclick = function() {
toggle(this);
console.log('buttonClicked');
}
return container;
}
});
map.addControl(new customControl());
</script>
</body>
</html>
The $("[class='mySwitch']") finds Elements based on the string selector. You have to adjust the Bootstrap Switch example to your usage. In your case, you do not need a selector but you can directly pass the HTML Element you created, so that it is wrapped by jQuery and can be transformed by Bootstrap Switch: $(container).bootstrapSwitch({})
Do not try to transform your Control container directly, but embed a child checkbox input into that container:
var container = L.DomUtil.create('div');
// Use a child input.
var input = L.DomUtil.create('input');
input.type = "checkbox";
// Insert the input as child of container.
container.appendChild(input);
// Transform the input, not the container.
$(input).bootstrapSwitch({});
You have a typo in:
<link rel="https:....css">
…should be:
<link rel="stylesheet" href="https:....css">
Live result:
var map = L.map('map', {
minZoom: 0,
}).setView([37, -103], 3);
var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: "CartoDB"
}).addTo(map);
// Toggle button to turn layers on and off
var customControl = L.Control.extend({
options: {
position: 'topright'
},
onAdd: function(map) {
var container = L.DomUtil.create('div');
// Use a child input.
var input = L.DomUtil.create('input');
input.type = "checkbox";
input.title = "Some title";
input.value = "Off";
// Insert the input as child of container.
container.appendChild(input);
jQuery(input).bootstrapSwitch({
// http://bootstrapswitch.site/options.html
onSwitchChange: function(event) {
console.log('buttonClicked', event.target.checked);
}
});
return container;
}
});
map.addControl(new customControl());
html,
body,
#map {
height: 100%;
margin: 0;
}
<!--jquery -->
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<!-- bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!--script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script-->
<!-- bootstrap switch -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.js"></script>
<!-- leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet.js"></script>
<div id='map'></div>

Chart.js: Chart not resizing in iframe

I am trying to show multiple diagrams/charts at the same time using chart.js.
For my setup, I have one chart.html file which displays the diagram and a split.html file which creates multiple iframes (2 so far) and loads the chart.html in them.
When opening the chart.html directly, the resizing works, but when loaded in iframe it doesn't.
I could only imagine the error at chart.js since the sizing itself is already weird. It orients on the next "higher" element (div with fixed 100% width and height in my case) and setting width or height directly on the canvas doesnt change anything, see code below.
chart.html:
<html>
<head>
<script src="./node_modules/chart.js/dist/Chart.bundle.js"></script>
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./js/diagram.js"></script>
</head>
<body>
<div id="container" style="width:100%; height:100%;">
<canvas id="diagram"></canvas>
</div>
</body>
split.html:
<html>
<head>
<link rel="stylesheet" href="./css/splitter.css" />
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./js/splitter.js"></script>
</head>
<body>
<div id="content">
</div>
</body>
diagram.js:
$(document).ready(function() {
var ctx = document.getElementById("diagram");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: /** excluded (unimportance) **/
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
// Resize chart
$(window).resize(function() {
console.log("resize works!");
if(myChart) myChart.update();
});
});
splitter.js:
$(document).ready(function () {
const splits = 2;
switch (splits) {
case 2:
$("#content").append(
$('<iframe />')
.attr("id", "frame1")
.attr("src", "./chart.html")
.addClass("width50 height100")
);
$("#content").append(
$('<iframe />')
.attr("id", "frame2")
.attr("src", "./chart.html")
.addClass("width50 height100 left50")
);
break;
}
});
splitter.css:
iframe {
position: fixed;
border: none;
margin: 0;
padding: 0;
}
.width100 {
width: 100%;
}
.height100 {
height: 100%;
}
.width50 {
width: 50%;
}
.height50 {
height: 50%;
}
.left50 {
left: 50%;
}
.top50 {
top: 50%;
}
Change iframes to divs with modifiing your splitter.js:
$(document).ready(function () {
const splits = 2;
for(var i = 0; i < splits;i++){
var chartContainer = $('<div id="frame' + (i + 1) + '"></div>').appendTo("#content");
var canvas = $('<canvas class="diagram">').appendTo(chartContainer);
if(i === 0)
chartContainer.addClass('width50 height100');
else
chartContainer.addClass('width50 height100 left50');
}
});
It will add two divs to the content element instead of iframes and also put the canvases into the divs.
Than change your diagram.js to foreach over the canvases and make them work as a chart:
$('canvas.diagram').each(function(){
var ctx = $(this);
var myChart = new Chart(ctx, {
//here comes the chart configuration...
});
});
Change your css to align the two div next to each other with
.width50 {
width: 50%;
display: inline-block;
}
So the charts are now inside block elements and because of they're set to be responsive if you resize the window they will be resized automatically based on their parent elements' width (so you can remove the resizing part from your script too)

Google API Visualization Chart Not Working

I used the Google Visualization API for making 3 graphs but only 1 graph is showing. However, when I refresh the page or go to a different browser, a different graph appears. How do I make every graph appear? I used #WhiteHat suggestion but it did not work. Here is the updated code after their suggestion:
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-66892235-1', 'auto');
ga('send', 'pageview');
</script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Analysis Tool</title>
{% load staticfiles %}
<!-- Bootstrap Core CSS -->
<link rel="stylesheet" type="text/css" href="{% static 'home/css/bootstrap.min.css' %}" />
<!-- Custom CSS -->
<link rel="stylesheet" type="text/css" href="{% static 'home/css/grayscale.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'home/css/style.css' %}" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- Custom Fonts -->
<link href="{% static 'home/font-awesome/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
<link href='http://fonts.googleapis.com/css?family=Lobster' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Raleway:300,400,500,600' rel='stylesheet' type='text/css'>
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" ></script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js" > </script>
<script type="text/javascript">
function printDiv(divName) {
var printContents = document.getElementById(divName).innerHTML;
console.log(printContents)
w=window.open();
w.document.write("<html><head><title>Print Page</title>");
w.document.write("{% load staticfiles %}")
w.document.write("<link rel='stylesheet' type='text/css' href='{% static 'home/css/bootstrap.min.css' %}' />")
w.document.write("<link rel='stylesheet' type='text/css' href='{% static 'home/css/style.css' %}' />")
w.document.write("<link href='http://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>")
w.document.write('</head><body>');
w.document.write(printContents);
w.document.write('</body></html>');
w.print();
w.close();
}
// Load the Visualization API and the piechart package.
google.charts.load('current', {callback: drawChart,packages: ['bar', 'corechart', 'line', 'table'] });
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
function drawChart() {
var djangoDataTable = {{ tableArr|safe }};
var dataTable = google.visualization.arrayToDataTable(djangoDataTable);
var djangoData1 = {{ deathHBV_Final|safe }}
var data1 = google.visualization.arrayToDataTable(djangoData1);
var djangoData2 = {{ hcc_Final|safe }}
var data2 = google.visualization.arrayToDataTable(djangoData2);
var djangoData3 = {{ cirrhosis_Final|safe }}
var data3 = google.visualization.arrayToDataTable(djangoData3);
var options3 = {
title: "Mortality Rate HBV",
titleTextStyle :{
fontSize:26,
fontName:'Raleway',
},
colors: ['#ff7f50','#49B7A8'],
width: 400,
height: 400,
vAxis: {
title:'Percentage (%)',
maxValue: 100,
},
hAxis:{
title:'Year',
},
legend:{
position:'none',
maxLines: 2,
}
};
var options4 = {
title: "Cirrhosis",
titleTextStyle :{
fontSize:26,
fontName:'Raleway',
},
colors: ['#ff7f50','#49B7A8'],
width: 400,
height: 400,
vAxis: {
title:'Percentage (%)',
maxValue: 100,
},
hAxis:{
title:'Year',
},
legend:{
position:'none',
maxLines: 2,
}
};
var options5 = {
title: "Liver Cancer",
titleTextStyle :{
fontSize:26,
fontName:'Raleway',
},
colors: ['#ff7f50','#49B7A8'],
width: 400,
height: 400,
vAxis: {
title:'Percentage (%)',
maxValue: 100,
},
hAxis:{
title:'Year',
},
legend:{
position:'none',
maxLines: 2,
}
};
var optionsTable = {
'showRowNumber': false,
'width': '100%',
'height': '100%',
'allowHtml': true,
};
var chart3 = new google.visualization.LineChart(document.getElementById('linechart1'));
chart3.draw(data1, options3);
if({{ ifCirr }} == 0){
var chart4 = new google.visualization.LineChart(document.getElementById('linechart2'));
chart4.draw(data3, options4);
}
var chart5 = new google.visualization.LineChart(document.getElementById('linechart3'));
chart5.draw(data2, options5);
for (y = 0; y < 4; y++){
dataTable.setCell(y,0,String(djangoDataTable[y+1][0]),null,{'style': ' font-size:20px;'})
}
for (j = 1; j < djangoDataTable[1].length; j += 2){
for (i = 0; i < 4; i++) {
dataTable.setCell(i,j,String(djangoDataTable[i+1][j]),null,{'style': 'background-color: rgba(255,127,80,0.7); font-size:18px;'})
}
}
for (j = 2; j < djangoDataTable[1].length; j += 2){
for (i = 0; i < 4; i++) {
dataTable.setCell(i,j,String(djangoDataTable[i+1][j]),null,{'style': 'background-color: #49b7a8; font-size:18px;'})
}
}
var table = new google.visualization.Table(document.getElementById('table_div'));
table.draw(dataTable, optionsTable);
}
$('#mailform').submit(function(){
var formAction = $("#selectmail").val() == "technical" ? "research.cs.alc#gmail.com" : "mtoy#stanford.edu";
$("#mailform").attr("action", "MAILTO:" + formAction);
});
</script>
first, it is recommended to use loader.js vs. the older library jsapi.
<script src="https://www.gstatic.com/charts/loader.js"></script>
vs.
<script src="https://www.google.com/jsapi"></script>
next, the load statement should only be called once per page load.
which is probably the reason for random chart selection.
and you can load all the packages you need in one call.
try replacing this...
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', {'packages':['corechart']});
google.load('visualization', '1', {'packages': ['corechart', 'bar']});
google.load('visualization', '1.1',{'packages': ['line']});
google.load("visualization", "1.0", {'packages':['table']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
with this...
google.charts.load('current', {
callback: drawChart,
packages: ['bar', 'corechart', 'line', 'table']
});

How do I detect when a node with a custom renderer is clicked or hovered over in sigma.js?

I am using sigma.js and have a custom node renderer that draws a node as a rectangle. Inside the rectangles are more shapes (basically just more rectangles and some text). I am also using the dragNodes plugin.
Right now, when a user wants to click on a node or drag it around the canvas, the user must go to the top left coordinate. However, the rectangle (the outermost one encompassing all the shapes inside it) represents the whole node. How do I modify my code to specify the dimensions of a node?
Also, although not shown in the code, if a user clicks inside a node rectangle (on one of the inner rectangles), I also want that to be detected and have a callback. Is this possible?
An example demonstrating my problem is shown here:
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.1.0/sigma.min.js"></script>
<script src="http://rawgit.com/jacomyal/sigma.js/master/plugins/sigma.plugins.dragNodes/sigma.plugins.dragNodes.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script>
$(document).ready(function() {
console.log('ready');
var g = { nodes: [], edges: [] };
g.nodes.push({
id: 'n1',
label: 'node1',
type: 'rtype',
x: Math.random(),
y: Math.random(),
size: 1,
color: '#666'
});
g.nodes.push({
id: 'n2',
label: 'node2',
type: 'rtype',
x: Math.random(),
y: Math.random(),
size: 1,
color: '#666'
});
sigma.renderers.def = sigma.renderers.canvas;
sigma.canvas.labels.rtype = function(node, context, settings) { };
sigma.canvas.nodes.rtype = function(node, context, settings) {
var prefix = settings('prefix') || '';
var size = node[prefix + 'size'];
var x = node[prefix + 'x'],
y = node[prefix + 'y'];
context.strokeStyle = 'rgb(0,0,0)';
context.strokeRect(x, y, 200, 200);
};
sigma.canvas.drawLabels = true;
var s = new sigma({
graph: g,
container: 'graph-container'
});
var dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
});
</script>
</head>
<body>
<div id="container">
<style>
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
}
</style>
<div id="graph-container"></div>
</div>
</body>
</html>

bootstrap layout with nvd3.js

I recently started to look into d3.js. Though im pretty new in html/css/javascript; my current goal is to build a simple (static) dashboard using nvd3.js (for easier graphs) and bootstrap as layout component.
I started off with nvd3.js example "pie.html" and try to arrange the graphs in one line using bootstraps grid system. I got it working with d3 only using the d3noob.org example. Sadly, its not working with nvd3.
I pasted the full code below:
<!DOCTYPE html>
<meta charset="utf-8">
<link href="nvd3/src/nv.d3.css" rel="stylesheet" type="text/css">
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<style>
body {
overflow-y:scroll;
}
text {
font: 12px sans-serif;
}
</style>
<div class="row">
<div class="span5" id="area1"></div>
<div class="span2"> This is some random text which should be in the middle of these two charts </div>
<div class="span5" id="area2"></div>
</div>
<body class='with-3d-shadow with-transitions'>
<!-- load the libraries -->
<script src="nvd3/lib/d3.v3.js"></script>
<script src="nvd3/nv.d3.js"></script>
<script src="nvd3/src/models/pie.js"></script>
<script src="nvd3/src/utils.js"></script>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
<script>
var testdata = [
{
key: "One",
y: 5
},
{
key: "Two",
y: 2
},
{
key: "Three",
y: 9
},
{
key: "Four",
y: 7
},
{
key: "Five",
y: 4
},
{
key: "Six",
y: 3
}
];
nv.addGraph(function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height / 2 - 40;
var chart = nv.models.pie()
.values(function(d) { return d })
.width(width)
.height(height);
d3.select("#area1").append("svg")
.datum([testdata])
.transition().duration(1200)
.attr('width', width)
.attr('height', height)
.call(chart);
return chart;
});
nv.addGraph(function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height / 2 - 40;
var chart = nv.models.pie()
.values(function(d) { return d })
.width(width)
.height(height)
.donut(true);
d3.select("#area2").append("svg")
.datum([testdata])
.transition().duration(1200)
.attr('width', width)
.attr('height', height)
.call(chart);
return chart;
});
</script>
</body>
What it looks like:
The d3+bootstrap example: https://gist.github.com/d3noob/6a3b59149cf3ebdb3fc4
What it should look like:
class "spanX" is outdated in Bootstrap 3.x
Using the class "col-xx-x" is making it work.

Categories