Skip to content

Commit

Permalink
Add update functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Cook committed Nov 6, 2013
1 parent 186c3b7 commit f0b7cb6
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 66 deletions.
2 changes: 1 addition & 1 deletion README.md
@@ -1,6 +1,6 @@
#Radial Bar Chart

A [D3](http://d3js.org) reusable radial bar chart ([examples](http://prcweb.co.uk/radialbarchart/))
A [D3](http://d3js.org) reusable radial bar chart ([examples](http://prcweb.co.uk/radialbarchart/)).

###Simple example
```javascript
Expand Down
3 changes: 0 additions & 3 deletions example.html
Expand Up @@ -67,16 +67,13 @@
<script src="js/d3.v3.min.js"></script>
<script src="js/radialBarChart.js"></script>
<script>

d3.json('data/data.json', function(err, data) {
var chart = radialBarChart()
.barHeight(250)
.reverseLayerOrder(true)
.capitalizeLabels(true)
.barColors(['#B66199', '#9392CB', '#76D9FA', '#BCE3AD', '#FFD28C', '#F2918B'])
// .barColors(['#EEB945', '#E67323']) // Yellow/orange
.domain([0,10])
// .colorLabels(true)
.tickValues([1,2,3,4,5,6,7,8,9,10])
.tickCircleValues([1,2,3,4,5,6,7,8,9]);

Expand Down
166 changes: 104 additions & 62 deletions js/radialBarChart.js
Expand Up @@ -10,6 +10,7 @@ function radialBarChart() {
var tickValues = undefined;
var colorLabels = false;
var tickCircleValues = [];
var transitionDuration = 1000;

// Scales & other useful things
var numBars = null;
Expand All @@ -36,6 +37,75 @@ function radialBarChart() {
return 'translate('+ +x +','+ +y +')';
}

function initChart(container) {
var g = d3.select(container)
.append('svg')
.style('width', 2 * barHeight + margin.left + margin.right)
.style('height', 2 * barHeight + margin.top + margin.bottom)
.append('g')
.classed('radial-barchart', true)
.attr('transform', svgTranslate(margin.left + barHeight, margin.top + barHeight));

// Concentric circles at specified tick values
g.append('g')
.classed('tick-circles', true)
.selectAll('circle')
.data(tickCircleValues)
.enter()
.append('circle')
.attr('r', function(d) {return barScale(d);})
.style('fill', 'none');
}

function renderOverlays(container) {
var g = d3.select(container).select('svg g.radial-barchart');

// Spokes
g.append('g')
.classed('spokes', true)
.selectAll('line')
.data(keys)
.enter()
.append('line')
.attr('y2', -barHeight)
.attr('transform', function(d, i) {return svgRotate(i * 360 / numBars);});

// Axis
var axisScale = d3.scale.linear().domain(domain).range([0, -barHeight]);
var axis = d3.svg.axis().scale(axisScale).orient('right');
if(tickValues)
axis.tickValues(tickValues);
g.append('g')
.classed('axis', true)
.call(axis);

// Outer circle
g.append('circle')
.attr('r', barHeight)
.classed('outer', true)
.style('fill', 'none');

// Labels
var labels = g.append('g')
.classed('labels', true);

labels.append('def')
.append('path')
.attr('id', 'label-path')
.attr('d', 'm0 ' + -labelRadius + ' a' + labelRadius + ' ' + labelRadius + ' 0 1,1 -0.01 0');

labels.selectAll('text')
.data(keys)
.enter()
.append('text')
.style('text-anchor', 'middle')
.style('fill', function(d, i) {return colorLabels ? barColors[i % barColors.length] : null;})
.append('textPath')
.attr('xlink:href', '#label-path')
.attr('startOffset', function(d, i) {return i * 100 / numBars + 50 / numBars + '%';})
.text(function(d) {return capitalizeLabels ? d.toUpperCase() : d;});
}

function chart(selection) {
selection.each(function(d) {

Expand All @@ -44,89 +114,55 @@ function radialBarChart() {
if(reverseLayerOrder)
d.reverse();

var g = d3.select(this)
.append('svg')
.append('g')
.classed('radial-barchart', true)
.attr('transform', svgTranslate(margin.left + barHeight, margin.top + barHeight));

// Concentric circles at specified tick values
g.append('g')
.classed('tick-circles', true)
.selectAll('circle')
.data(tickCircleValues)
.enter()
.append('circle')
.attr('r', function(d) {return barScale(d);})
.style('fill', 'none');
var g = d3.select(this).select('svg g.radial-barchart');

// check whether chart has already been created
var update = g[0][0] !== null; // true if data is being updated

if(!update)
initChart(this);

g = d3.select(this).select('svg g.radial-barchart');

// Layer enter/exit/update
var layers = g.selectAll('g.layer')
.data(d)
.data(d);

layers
.enter()
.append('g')
.attr('class', function(d, i) {
return 'layer-' + i;
})
.classed('layer', true);

layers
layers.exit().remove();

// Segment enter/exit/update
var segments = layers
.selectAll('path')
.data(function(d) {
var m = d3.map(d.data);
return m.values();
})
});

segments
.enter()
.append('path')
.attr('d', d3.svg.arc().innerRadius(0).outerRadius(or).startAngle(sa).endAngle(ea))
.style('fill', function(d, i) {
if(!barColors) return;
return barColors[i % barColors.length];
});

// Spokes
g.append('g')
.classed('spokes', true)
.selectAll('line')
.data(keys)
.enter()
.append('line')
.attr('y2', -barHeight)
.attr('transform', function(d, i) {return svgRotate(i * 360 / numBars);});

// Axis
var axisScale = d3.scale.linear().domain(domain).range([0, -barHeight]);
var axis = d3.svg.axis().scale(axisScale).orient('right');
if(tickValues)
axis.tickValues(tickValues);
g.append('g')
.classed('axis', true)
.call(axis);

// Outer circle
g.append('circle')
.attr('r', barHeight)
.classed('outer', true)
.style('fill', 'none');

// Labels
var labels = g.append('g')
.classed('labels', true);

labels.append('def')
.append('path')
.attr('id', 'label-path')
.attr('d', 'm0 ' + -labelRadius + ' a' + labelRadius + ' ' + labelRadius + ' 0 1,1 -0.01 0');
segments.exit().remove();

labels.selectAll('text')
.data(keys)
.enter()
.append('text')
.style('text-anchor', 'middle')
.style('fill', function(d, i) {return colorLabels ? barColors[i % barColors.length] : null;})
.append('textPath')
.attr('xlink:href', '#label-path')
.attr('startOffset', function(d, i) {return i * 100 / numBars + 50 / numBars + '%';})
.text(function(d) {return capitalizeLabels ? d.toUpperCase() : d;});
segments
.transition()
.duration(transitionDuration)
.attr('d', d3.svg.arc().innerRadius(0).outerRadius(or).startAngle(sa).endAngle(ea))

if(!update)
renderOverlays(this);
});

}
Expand Down Expand Up @@ -197,5 +233,11 @@ function radialBarChart() {
return chart;
};

chart.transitionDuration = function(_) {
if (!arguments.length) return transitionDuration;
transitionDuration = _;
return chart;
};

return chart;
}
112 changes: 112 additions & 0 deletions update-example.html
@@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Radial Bar Chart example</title>
<style>

#chart {
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 14px;
}
#chart path {
fill: none;
}

/* layers */
#chart .layer-0 path {
fill: steelblue;
}
#chart .layer-1 path {
fill: white !important;
opacity: 0.3;
stroke-width: 2px;
stroke: #999;
}

/* Outer circle, tick-circles and spokes */
#chart circle.outer {
stroke: #aaa;
stroke-dasharray: 4, 4;
}
#chart .tick-circles circle {
stroke: #ddd;
stroke-dasharray: 2, 2;
}
#chart .spokes line {
stroke: #666;
stroke-width: 0.2;
}

/* Axis */
#chart .axis text {
font-size: 11px;
}
#chart .axis path {
stroke: #999;
shape-rendering: crispEdges;
}
#chart .axis line {
stroke: #999;
shape-rendering: crispEdges;
}

/* Labels */
#chart .labels text {
fill: #333;
font-size: 10px;
font-weight: 500;
}

/* update button */
#update {
width: 100px;
height: 30px;
cursor: pointer;
}

</style>
</head>

<body>
<button type="button" id="update">Update</button>
<div id="chart"></div>

<script src="js/d3.v3.min.js"></script>
<script src="js/radialBarChart.js"></script>
<script>

var data = null;
var keys = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

function initData() {
data = [{data: {}}];
for(var i=0; i<keys.length; i++)
data[0].data[keys[i]] = Math.random() * 10;
};

function update() {
initData();

d3.select('#chart')
.datum(data)
.call(chart);
}

d3.select('#update')
.on('click', update);

var chart = radialBarChart()
.barHeight(250)
.reverseLayerOrder(true)
.capitalizeLabels(true)
.barColors(['#B66199', '#9392CB', '#76D9FA', '#BCE3AD', '#FFD28C', '#F2918B'])
.domain([0,10])
.tickValues([1,2,3,4,5,6,7,8,9,10])
.tickCircleValues([1,2,3,4,5,6,7,8,9]);

update();

</script>
</body>
</html>

0 comments on commit f0b7cb6

Please sign in to comment.