On Github victormejia / d3-angularoc
Created by Victor Mejia
Software Dev @ LoopNet (CoStar Group)
I ♥ JavaScript
Tweeting @victorczm
Coding @victormejia
Blogging @ victormejia.github.io
<barchart data="topRepos" fill="#2d323d"></barchart>
===
src: @johnkpaul
<svg width="500" height="300" class="light-border"></svg>(500, 300)(0, 0)
<rect width="40" height="200" x="230" y="100" fill="#1e8fc6"></rect>(500, 300)(0, 0)
<circle cx="150" cy="100" r="80" fill="#514f73"></circle>(500, 300)(0, 0)
<ellipse cx="250" cy="150" rx="50" ry="10" fill="#cc2309"></ellipse>(500, 300)(0, 0)
<text x="250" y="150" text-anchor="middle">Hello SVG!</text>Hello SVG!(500, 300)(0, 0)
<line x1="150" y1="200" x2="450" y2="300" stroke-width="9" stroke="#2d323d"></line>(500, 300)(0, 0)
<polyline points="20,200 110,50 320,200 470,90" stroke="#514f73" stroke-width="5" fill="none"></polyline>(500, 300)(0, 0)
<path d="M 400 100 L 100 200 L 200 100 z" fill="#514f73"></path>(500, 300)(0, 0)
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 heighthttp://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: '<div></div>', 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 }
<barchart data="ui.topRepos" x="lang" y="value" class="chart"></barchart>
pull requests are welcome :)
© 2014 PEANUTS Worldwide LLC