This repository has been archived by the owner on Nov 21, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c246da5
commit ddb0582
Showing
3 changed files
with
448 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
//Practically all this code comes from https://github.com/alangrafu/radar-chart-d3 | ||
//I only made some additions and aesthetic adjustments to make the chart look better | ||
//(of course, that is only my point of view) | ||
//Such as a better placement of the titles at each line end, | ||
//adding numbers that reflect what each circular level stands for | ||
//Not placing the last level and slight differences in color | ||
// | ||
//For a bit of extra information check the blog about it: | ||
//http://nbremer.blogspot.nl/2013/09/making-d3-radar-chart-look-bit-better.html | ||
|
||
var RadarChart = { | ||
draw: function(id, d, options){ | ||
var cfg = { | ||
radius: 5, | ||
w: 600, | ||
h: 600, | ||
factor: 1, | ||
factorLegend: .85, | ||
levels: 3, | ||
maxValue: 0, | ||
radians: 2 * Math.PI, | ||
opacityArea: 0.5, | ||
ToRight: 5, | ||
TranslateX: 80, | ||
TranslateY: 30, | ||
ExtraWidthX: 100, | ||
ExtraWidthY: 100, | ||
color: d3.scale.category10() | ||
}; | ||
|
||
if('undefined' !== typeof options){ | ||
for(var i in options){ | ||
if('undefined' !== typeof options[i]){ | ||
cfg[i] = options[i]; | ||
} | ||
} | ||
} | ||
cfg.maxValue = Math.max(cfg.maxValue, d3.max(d, function(i){return d3.max(i.map(function(o){return o.value;}))})); | ||
var allAxis = (d[0].map(function(i, j){return i.axis})); | ||
var total = allAxis.length; | ||
var radius = cfg.factor*Math.min(cfg.w/2, cfg.h/2); | ||
var Format = d3.format('%'); | ||
d3.select(id).select("svg").remove(); | ||
|
||
var g = d3.select(id) | ||
.append("svg") | ||
.attr("width", cfg.w+cfg.ExtraWidthX) | ||
.attr("height", cfg.h+cfg.ExtraWidthY) | ||
.append("g") | ||
.attr("transform", "translate(" + cfg.TranslateX + "," + cfg.TranslateY + ")"); | ||
; | ||
|
||
var tooltip; | ||
|
||
//Circular segments | ||
for(var j=0; j<cfg.levels-1; j++){ | ||
var levelFactor = cfg.factor*radius*((j+1)/cfg.levels); | ||
g.selectAll(".levels") | ||
.data(allAxis) | ||
.enter() | ||
.append("svg:line") | ||
.attr("x1", function(d, i){return levelFactor*(1-cfg.factor*Math.sin(i*cfg.radians/total));}) | ||
.attr("y1", function(d, i){return levelFactor*(1-cfg.factor*Math.cos(i*cfg.radians/total));}) | ||
.attr("x2", function(d, i){return levelFactor*(1-cfg.factor*Math.sin((i+1)*cfg.radians/total));}) | ||
.attr("y2", function(d, i){return levelFactor*(1-cfg.factor*Math.cos((i+1)*cfg.radians/total));}) | ||
.attr("class", "line") | ||
.style("stroke", "grey") | ||
.style("stroke-opacity", "0.75") | ||
.style("stroke-width", "0.3px") | ||
.attr("transform", "translate(" + (cfg.w/2-levelFactor) + ", " + (cfg.h/2-levelFactor) + ")"); | ||
} | ||
|
||
//Text indicating at what % each level is | ||
for(var j=0; j<cfg.levels; j++){ | ||
var levelFactor = cfg.factor*radius*((j+1)/cfg.levels); | ||
g.selectAll(".levels") | ||
.data([1]) //dummy data | ||
.enter() | ||
.append("svg:text") | ||
.attr("x", function(d){return levelFactor*(1-cfg.factor*Math.sin(0));}) | ||
.attr("y", function(d){return levelFactor*(1-cfg.factor*Math.cos(0));}) | ||
.attr("class", "legend") | ||
.style("font-family", "sans-serif") | ||
.style("font-size", "10px") | ||
.attr("transform", "translate(" + (cfg.w/2-levelFactor + cfg.ToRight) + ", " + (cfg.h/2-levelFactor) + ")") | ||
.attr("fill", "#737373") | ||
.text(Format((j+1)*cfg.maxValue/cfg.levels)); | ||
} | ||
|
||
series = 0; | ||
|
||
var axis = g.selectAll(".axis") | ||
.data(allAxis) | ||
.enter() | ||
.append("g") | ||
.attr("class", "axis"); | ||
|
||
axis.append("line") | ||
.attr("x1", cfg.w/2) | ||
.attr("y1", cfg.h/2) | ||
.attr("x2", function(d, i){return cfg.w/2*(1-cfg.factor*Math.sin(i*cfg.radians/total));}) | ||
.attr("y2", function(d, i){return cfg.h/2*(1-cfg.factor*Math.cos(i*cfg.radians/total));}) | ||
.attr("class", "line") | ||
.style("stroke", "grey") | ||
.style("stroke-width", "1px"); | ||
|
||
axis.append("text") | ||
.attr("class", "legend") | ||
.text(function(d){return d}) | ||
.style("font-family", "sans-serif") | ||
.style("font-size", "11px") | ||
.attr("text-anchor", "middle") | ||
.attr("dy", "1.5em") | ||
.attr("transform", function(d, i){return "translate(0, -10)"}) | ||
.attr("x", function(d, i){return cfg.w/2*(1-cfg.factorLegend*Math.sin(i*cfg.radians/total))-60*Math.sin(i*cfg.radians/total);}) | ||
.attr("y", function(d, i){return cfg.h/2*(1-Math.cos(i*cfg.radians/total))-20*Math.cos(i*cfg.radians/total);}); | ||
|
||
|
||
d.forEach(function(y, x){ | ||
dataValues = []; | ||
g.selectAll(".nodes") | ||
.data(y, function(j, i){ | ||
dataValues.push([ | ||
cfg.w/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)), | ||
cfg.h/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total)) | ||
]); | ||
}); | ||
dataValues.push(dataValues[0]); | ||
g.selectAll(".area") | ||
.data([dataValues]) | ||
.enter() | ||
.append("polygon") | ||
.attr("class", "radar-chart-serie"+series) | ||
.style("stroke-width", "2px") | ||
.style("stroke", cfg.color(series)) | ||
.attr("points",function(d) { | ||
var str=""; | ||
for(var pti=0;pti<d.length;pti++){ | ||
str=str+d[pti][0]+","+d[pti][1]+" "; | ||
} | ||
return str; | ||
}) | ||
.style("fill", function(j, i){return cfg.color(series)}) | ||
.style("fill-opacity", cfg.opacityArea) | ||
.on('mouseover', function (d){ | ||
z = "polygon."+d3.select(this).attr("class"); | ||
g.selectAll("polygon") | ||
.transition(200) | ||
.style("fill-opacity", 0.1); | ||
g.selectAll(z) | ||
.transition(200) | ||
.style("fill-opacity", .7); | ||
}) | ||
.on('mouseout', function(){ | ||
g.selectAll("polygon") | ||
.transition(200) | ||
.style("fill-opacity", cfg.opacityArea); | ||
}); | ||
series++; | ||
}); | ||
series=0; | ||
|
||
|
||
d.forEach(function(y, x){ | ||
g.selectAll(".nodes") | ||
.data(y).enter() | ||
.append("svg:circle") | ||
.attr("class", "radar-chart-serie"+series) | ||
.attr('r', cfg.radius) | ||
.attr("alt", function(j){return Math.max(j.value, 0)}) | ||
.attr("cx", function(j, i){ | ||
dataValues.push([ | ||
cfg.w/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)), | ||
cfg.h/2*(1-(parseFloat(Math.max(j.value, 0))/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total)) | ||
]); | ||
return cfg.w/2*(1-(Math.max(j.value, 0)/cfg.maxValue)*cfg.factor*Math.sin(i*cfg.radians/total)); | ||
}) | ||
.attr("cy", function(j, i){ | ||
return cfg.h/2*(1-(Math.max(j.value, 0)/cfg.maxValue)*cfg.factor*Math.cos(i*cfg.radians/total)); | ||
}) | ||
.attr("data-id", function(j){return j.axis}) | ||
.style("fill", cfg.color(series)).style("fill-opacity", .9) | ||
.on('mouseover', function (d){ | ||
newX = parseFloat(d3.select(this).attr('cx')) - 10; | ||
newY = parseFloat(d3.select(this).attr('cy')) - 5; | ||
|
||
tooltip | ||
.attr('x', newX) | ||
.attr('y', newY) | ||
.text(Format(d.value)) | ||
.transition(200) | ||
.style('opacity', 1); | ||
|
||
z = "polygon."+d3.select(this).attr("class"); | ||
g.selectAll("polygon") | ||
.transition(200) | ||
.style("fill-opacity", 0.1); | ||
g.selectAll(z) | ||
.transition(200) | ||
.style("fill-opacity", .7); | ||
}) | ||
.on('mouseout', function(){ | ||
tooltip | ||
.transition(200) | ||
.style('opacity', 0); | ||
g.selectAll("polygon") | ||
.transition(200) | ||
.style("fill-opacity", cfg.opacityArea); | ||
}) | ||
.append("svg:title") | ||
.text(function(j){return Math.max(j.value, 0)}); | ||
|
||
series++; | ||
}); | ||
//Tooltip | ||
tooltip = g.append('text') | ||
.style('opacity', 0) | ||
.style('font-family', 'sans-serif') | ||
.style('font-size', '13px'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> | ||
<title>Radar chart</title> | ||
<script src="http://d3js.org/d3.v3.min.js"></script> | ||
<script src="RadarChart.js"></script> | ||
<style> | ||
body { | ||
overflow: hidden; | ||
margin: 0; | ||
font-size: 14px; | ||
font-family: "Helvetica Neue", Helvetica; | ||
} | ||
|
||
#chart { | ||
position: absolute; | ||
top: 50px; | ||
left: 100px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="body"> | ||
<div id="chart"></div> | ||
</div> | ||
|
||
<script type="text/javascript" src="script.js"></script> | ||
|
||
</body> | ||
</html> |
Oops, something went wrong.