D3.js PIE

In this example below you will see how to do a D3.js PIE with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by 1cco, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright 1cco ©
  • HTML
  • CSS
  • JavaScript
    #container
	form
		fieldset
			legend Type
			label
				input(type='radio', name='type', value='animation')
				| Animation
			label
				input(type='radio', name='type', value='interaction')
				| Interaction
			label
				input(type='radio', name='type', value='dynamic')
				| Dynamic
		fieldset
			legend Fruits
			label
				input(type='radio', name='dataset', value='apples', checked='')
				| Apples
			label
				input(type='radio', name='dataset', value='oranges')
				| Oranges
			label
				input(type='radio', name='dataset', value='pears')
				| Pears
	#value 1
	#dynamic
		form
			fieldset
				legend Pear
				div
				input#update(type='button', value='Update')
	#chart

/*Downloaded from https://www.codeseek.co/1cco/d3js-pie-KeNZey */
    @import "compass";
@import url("https://fonts.googleapis.com/css?family=Contrail+One");
$font-family: "Contrail One", sans-serif;
$color-blue: rgb(68,153,248);
body {
	font-family: $font-family;
	font-size: 20px;
	* {
		box-sizing: border-box;
	}
}
#container {
	width: 95%;
	margin: 0 auto;
}

form {
	@include display-flex;
	@include justify-content(space-between);
}

fieldset {
	background: #eee;
	border-radius: 8px;
	padding: 16px;
	margin: 16px auto;
	width: 45%;
}
legend {
	background: #eee;
	border: 1px solid #ccc;
	padding: 8px 16px;
	border-radius: 8px;
}
label {
	white-space: nowrap;
	@include align-content(space-between);
	+ label {
		margin-left: 0.5em;
	}
}
input {
	font-family: $font-family;
	font-size: 20px;
	&[type=radio] {
		margin-right: 0.2em;
	}
}
#value {
	position: absolute;
	border: 1px solid #ccc;
	padding: 8px;
	background: #eee;
	visibility: hidden;
	border-radius: 8px;
	user-select: none;
	-moz-user-select: none;
	-webkit-user-select: none;
	-ms-user-select: none;
	&:before {
		content: "Value:";
	}
}

#dynamic {
	visibility: hidden;
	fieldset {
		width: 95%;
	}
	input {
		&[type=text] {
			width: 98 / 5 * 1%;
			padding: 8px;
			border-radius: 8px;
			border: 1px solid #ccc;
			margin: 0 (1 / 5 * 1%);
		}
		&[type=button] {
			display: block;
			width: 50%;
			margin: 16px auto 0;
			padding: 8px;
			border-radius: 8px;
			background-color: $color-blue;
			color: #fff;
			cursor: pointer;
			transition: all 0.5s;
			&:hover {
				opacity: 0.5;
			}
		}
	}
}

#chart {
	width: 600px;
	margin: 0 auto;
}


/*Downloaded from https://www.codeseek.co/1cco/d3js-pie-KeNZey */
    /**
*  this project based on 
*  "Pie Chart Update, II" <http://bl.ocks.org/mbostock/1346410> 
*  by mbostock.
*/

var data = [
	{ 'apples': '53245', 'oranges': '21736', 'pears': '11927' },
	{ 'apples': '28479', 'oranges': '22103', 'pears': '30023' },
	{ 'apples': '19697', 'oranges': '21230', 'pears': '25263' },
	{ 'apples': '24037', 'oranges': '21563', 'pears': '58764' },
	{ 'apples': '40245', 'oranges': '22846', 'pears': '22837' }
];

var $dynamic = d3.select('#dynamic');
var $chart = d3.select('#chart');
var $value = d3.select("#value");
var selected1 = '', selected2 = '';

$dynamic.select("div").selectAll('input')
	.data(data)
	.enter()
	.append('input')
	.attr({
		'type': 'text',
		'name': function(d, i){
			return 't' + i
		},
		'value': function(d, i){
			return d.pears
		}
	});

var width = 600,
    height = 500,
    radius = Math.min(width, height) / 2;

var color = d3.scale.category20();

var pie = d3.layout.pie()
	.value(function(d) { return d.apples; })
	.sort(null);

var arc = d3.svg.arc()
	.innerRadius(radius - 140)
	.outerRadius(radius - 20);

var $svg = $chart.append("svg")
	.attr("width", width)
	.attr("height", height);

var $g = $svg.append("g")
	.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var path = $g.datum(data).selectAll("path")
	.data(pie)
	.enter().append("path")
	.attr("fill", function(d, i) { return color(i); })
	.attr("d", arc)
	.each(function(d) { this._current = d; }) // store the initial angles
	.on({
		"mouseenter": function (e) {
			if (selected1 !== 'interaction') {return;}
			$value.text(e.value).style({
				"visibility": "visible"
			});
		},
		"mouseleave": function () {
			if (selected1 !== 'interaction') {return;}
			$value.text("").style({
				"visibility": "hidden"
			});
		},
		"mousemove": function() {
			if (selected1 !== 'interaction') {return;}
			var pt = d3.mouse(this);
			var offset = $svg[0][0].getBoundingClientRect();
			var offset2 = $value[0][0].getBoundingClientRect();
			var sy = window.scrollY;
			var sx = window.scrollX;
			var left = pt[0] + offset.width / 2 + offset.left + sx;
			var top = pt[1] + offset.height / 2 + offset.top - offset2.height - 10 + sy;
			$value.style({
				"left": left + "px", 
				"top" : top + "px"
			});
		}
	});

d3.selectAll("input[name=dataset]").on("change", change);

d3.selectAll("input[name=type]").on("change", change2);

d3.select("#update").on("click", updatePear);

var timeout;
var noAnim = false;

function change() {
	var value = this.value;
	selected2 = value;
	if (timeout) clearTimeout(timeout);
	pie.value(function(d) { return d[value]; }); // change the value function
	path = path.data(pie); // compute the new angles
	noAnim 
		? path.attr("d", arc) 
		: path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}

function change2() {
	var value = this.value;
	selected1 = value;
	var count = 0;
	if (timeout) clearTimeout(timeout);
	switch (value) {
		case "animation":
			noAnim = false;
			(function loop () {
				// console.log(count);
				var fruits = "apples";
				switch (count) {
					case 0:
						fruits = "apples";
						break;
					case 1:
						fruits = "oranges";
						break;
					case 2:
						fruits = "pears";
						break;
				}
				d3.select('input[value="' + fruits + '"]').property("checked", true).each(change);
				count = (count + 1) % 3;
				timeout = setTimeout(loop, 1000);
			})();
			d3.selectAll('input[value="apples"],input[value="oranges"]').property("disabled", false);
			$value.style({"visibility":"hidden"});
			$dynamic.style({"visibility":"hidden"});
		break;
		case "interaction":
			noAnim = true;
			d3.selectAll('input[value="apples"],input[value="oranges"]').property("disabled", false);
			// d3.select("#value").style({"visibility":"visible"});
			$dynamic.style({"visibility":"hidden"});
		break;
			case "dynamic":
			noAnim = true;
			d3.selectAll('input[value="apples"],input[value="oranges"]').property("disabled", true);
			d3.select('input[value="pears"]').property("checked", true).each(change);
			$value.style({"visibility":"hidden"});
			$dynamic.style({"visibility":"visible"});
			break;
	}
}

function updatePear() {
	$dynamic.selectAll("input[type=text]")
		.each(function (d, i) {
			data[i].pears = this.value;
		});
	var value = "pears";
	if (timeout) clearTimeout(timeout);
	pie.value(function(d) { return d[value]; }); // change the value function
	path = path.data(pie); // compute the new angles
	path.attr("d", arc); // redraw the arcs
}


function type(d) {
	d.apples = +d.apples;
	d.oranges = +d.oranges;
	return d;
}

// Store the displayed angles in _current.
// Then, interpolate from _current to the new angles.
// During the transition, _current is updated in-place by d3.interpolate.
function arcTween(a) {
	var i = d3.interpolate(this._current, a);
	this._current = i(0);
	return function(t) {
		return arc(i(t));
	};
}

Comments