Created by Victor Mejia
Software Dev @ LoopNet (CoStar Group)
I ♥ JavaScript
Tweeting @victorczm
Coding @victormejia
Blogging @ victormejia.github.io
===
src: @johnkpaul
Hello SVG!
var data = [
{ lang: 'JavaScript', value: 549385},
{ lang: 'Ruby', value: 453004},
{ lang: 'Java', value: 375857},
{ lang: 'PHP', value: 278937},
{ lang: 'Python', value: 247099},
{ lang: 'C++', value: 177001},
{ lang: 'C', value: 167175},
{ lang: 'CSS', value: 105897},
{ lang: 'C#', value: 76874},
{ lang: 'Objective-C', value: 75399},
{ lang: 'Shell', value: 70516},
{ lang: 'Perl', value: 47954},
{ lang: 'CoffeeScript', value: 27402},
{ lang: 'Go', value: 23334}
];
Data source: GitHub Archive
+
// (1) Select element
var el = d3.select('#chart'),
// (2) Grab element's dimensions
elWidth = parseInt(el.style('width'), 10),
elHeight = parseInt(el.style('height'), 10),
// (3) Declare margins for axis
margin = {top: 20, right: 10, bottom: 80, left: 40},
// (4) calculate width and height used for scaling
width = elWidth - margin.right - margin.left,
height = elHeight - margin.top - margin.bottom;
// (5) append svg element with added margins and group element inside
var svg = el.append("svg")
.attr("width", elWidth)
.attr("height", elHeight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
// now in our code we can just reference width and height
http://bl.ocks.org/mbostock/3019563
var el = d3.select('#chart');
// append an svg element
var svg = el.append('svg');
// append returns a new selection
svg.attr(...)
One element selected, one appended
// with many selected, can change all elements
var rect = svg.selectAll('rect')
.attr(..);
var data = [1, 3, 5, 7, 9];
var meetups = [
{ name: 'AngularJSOC', members: 286 },
{ name: 'OCMongoDB' , members: 326 }
];
var selection = svg.selectAll('rect')
.data(data); // this creates empty placeholders
// appending to the enter selection creates new elements
selection
.enter()
.append('rect')
.attr(/*...*/)
source: Thining With Joins
// create viz
var selection = svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr({
x: function (d, i) { ... },
y: function (d, i) { ... },
height: function (d) { ... },
width: ...,
fill: ...
});
var values = [2, 10, 3];
var max = d3.max(values); // 10
// if array of objects...
var maxRepoCount = d3.max(data, function (d) {
return d.value;
});
var values = [3, 1, 5, 8, 9, 2];
var max = d3.extent(values); // [1, 9]
var heightScale = d3.scale.linear()
.domain([0, d3.max(data, function (d) { return d.value})])
.range([height, 0]);
// ordinal scales for discrete data
var xScale = d3.scale.ordinal()
.domain(data.map(function (d) { return d.category; }))
.rangeRoundBands([0, width], 0.1); // useful for barcharts
selection
.attr({
x: function (d, i) {
return xScale(d.lang)
},
y: function (d, i) {
return yScale(d.value);
},
height: function (d) {
return height - yScale(d.value);
},
width: xScale.rangeBand(),
fill: fillColor
})
// create axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom") // place label below tick
.tickPadding(10); // padding b/n tick and label
var xAxisGroup = svg.append("g")
.attr({
class : 'axis',
transform: 'translate(' + [0, height] + ')'
}).call(xAxis);
// (1) initial attributes
var r = svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr(initialAttrs);
// (2) transition to final state
r.transition()
.delay(function (d, i){
return d * 25; // delay each element
})
.ease("linear") // also "elastic", "bounce", etc.
.duration(700) // entire transition
.attr(finalAttrs);
var r = svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr(...)
.on('mouseover', handleMouseover);
function handleMouseover(d, i) {
// this: element moused over
// d: datum
// i: index
}
.tooltip {
visibility: hidden;
background-color: #39393d;
}
.tooltip text {
fill: #fff;
font-size: 12px;
shape-rendering: crispEdges;
}
var tooltip = svg.append('g').attr({class: 'tooltip'});
tooltip.append('rect').attr({ height: '30', width: '100' });
tooltip.append('text').attr({ x: 10, y: 20 }); // relative to group element
function handleMouseover(d, i) {
// calculate x, y (add code to check for boundaries)
var pos = { x: xScale(d.lang), y: yScale(d.value) - 35};
var tooltip = svg.select('.tooltip')
.attr('transform': 'translate(' + [pos.x, pos.y + ')');
tooltip.select('text').text('Repos: ' + d.value);
tooltip.style('visibility', 'visible');
}
function handleMouseout(d, i) {
svg.select('.tooltip').style('visibility', 'hidden')
}
'use strict';
angular.module('d3AngularDemosApp')
.controller('BarChartCtrl', ['$scope', 'DataSvc',
function ($scope, DataSvc) {
$scope.ui = {};
$scope.refresh = function () {
$scope.ui.topRepos = [];
DataSvc.getTopRepos()
.then(function (data) {
$scope.ui.topRepos = data;
});
};
$scope.refresh();
}
]);
angular.module('app')
.directive('barchart', function () {
function linker(scope, element, attrs) {
// set up all the components (svg, scales, axis, .etc)
var el = element[0];
...
var svg = d3.select(el).append('svg')
...
// exclude setup code that needs the data
}
return {
template: '',
restrict: 'E',
replace: true,
link: linker,
scope: { // isolate scope
data: '=', // bi-directional data binding
x: '@', // the x property (string)
y: '@' // the y property (string)
}
};
});
scope.$watch('data', function (newData, oldData) {
var data = angular.copy(newData); // let's make a copy
scope.render(data);
}, true); // watch for object equality
scope.render = function (data) {
// (1) update scales, axis
// (2) transition new data
var rect = svg.selectAll('rect').data(data);
rect.enter().append('rect').attr(/*...*/);
rect.transition().attr(/*...*/);
// (3) remove any data not needed
rect.exit().remove();
}
// Browser onresize event
window.onresize = function() {
scope.$apply(); // launch a digest cycle
};
// resize chart when the width changes
scope.$watch(function () {
return el.clientWidth;
}, function () {
scope.resize();
});
scope.resize = function () {
// (1) update width
width = el.clientWidth - margin.right - margin.left;
// (2) update svg
var svg = d3.select(el).select('svg');
svg.attr('width', width + margin.right + margin.left);
// (3) update everything that is related to width
}
pull requests are welcome :)
© 2014 PEANUTS Worldwide LLC