var RadarChart = { draw: function(id, d, options) { var cfg = { radius: 5, w: 600, h: 600, factor: 1, factorLegend: 0.85, levels: 3, maxValue: 100, minValue: 0, radians: 2 * Math.PI, opacityArea: 0.5, ToRight: 5, TranslateX: 80, TranslateY: 30, ExtraWidthX: 100, ExtraWidthY: 100, color: d3.scaleOrdinal().range(["#6F257F", "#CA0D59"]) }; if ("undefined" !== typeof options) { for (var i in options) { if ("undefined" !== typeof options[i]) { cfg[i] = options[i]; } } } cfg.maxValue = 100; var allAxis = d[0].map(function(i, j) { return i.area; }); var total = allAxis.length; var radius = cfg.factor * Math.min(cfg.w / 2, cfg.h / 2); var Format = d3.format("%"); var scale = d3.scaleLinear().domain([cfg.minValue, cfg.maxValue]); 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; 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(((j + 1) * 100) / 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 - scale(parseFloat(Math.max(j.value, 0))) * cfg.factor * Math.sin((i * cfg.radians) / total)), (cfg.h / 2) * (1 - scale(parseFloat(Math.max(j.value, 0))) * 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", 0.7); }) .on("mouseout", function() { g.selectAll("polygon") .transition(200) .style("fill-opacity", cfg.opacityArea); }); series++; }); series = 0; var tooltip = d3 .select("body") .append("div") .attr("class", "toolTip"); 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 - scale(parseFloat(Math.max(j.value, 0))) * cfg.factor * Math.sin((i * cfg.radians) / total)), (cfg.h / 2) * (1 - scale(parseFloat(Math.max(j.value, 0))) * cfg.factor * Math.cos((i * cfg.radians) / total)) ]); return ( (cfg.w / 2) * (1 - scale(parseFloat(Math.max(j.value, 0))) * cfg.factor * Math.sin((i * cfg.radians) / total)) ); }) .attr("cy", function(j, i) { return ( (cfg.h / 2) * (1 - scale(parseFloat(Math.max(j.value, 0))) * cfg.factor * Math.cos((i * cfg.radians) / total)) ); }) .attr("data-id", function(j) { return j.area; }) .style("fill", "#fff") .style("stroke-width", "2px") .style("stroke", cfg.color(series)) .style("fill-opacity", 0.9) .on("mouseover", function(d) { console.log(d.area); tooltip .style("left", d3.event.pageX - 40 + "px") .style("top", d3.event.pageY - 80 + "px") .style("display", "inline-block") .html(d.area + "
" + d.value + ""); }) .on("mouseout", function(d) { tooltip.style("display", "none"); }); series++; }); } };