Reputation: 1363
I'm trying to display the percentages of a polygonal shape within a radar graph by hovering on its name in the legend.
You can see that the first brand name is being hovered over in the legend and that the corresponding polygonal shape in the graph is selected as a result. I'd like the shape to be surrounded by its values (in %) at each of its angles.
I wrote this code that puts all the percentages at the right places and set their opacity
to 0
// percentages
var pourcents = g.selectAll(".pourcentage")
.data(data)
.enter()
.append("g")
.attr("class","pourcentage");
pourcents.selectAll(".pourcentagetext")
.data(function(d,i) {return d[1]})
.enter().append("text")
.text(function (d,i) { if (d.value == 0) {"fill", "none"} else {return Format(d.value)}})
.attr("x", function(d,i){ return rScale(d.value + 0.05)* Math.cos(angleSlice*i - Math.PI/2) })
.attr("y", function(d,i){ return rScale(d.value + 0.05) * Math.sin(angleSlice*i - Math.PI/2) })
.attr("class", "pourcentagetext")
.attr("id", function (d,i) {return "per" + i})
.style("font-size", 10)
.style("opacity", 0);
How can I select a group of percentages corresponding to a specific shape and make them appear with it ?
Edit: the code for the polygonal shapes:
blobWrapper.append("path")
.attr("class", "radarArea")
.attr("d", function(d,i) { return radarLine(d[1])})
.style("fill", function(d,i) { return color(i); })
.style("fill-opacity", cfg.opacityArea)
.attr("id", function (d,i) {return "tag" + i})
I operate the selection and make them appear by setting an id
:
legende.on("mouseover", function(d, i, j) {d3.select("#tag" + i)
.transition()
.duration(100)
.style("fill-opacity", 1);
How can I do the same type of selection but with a group of corresponding percentages ?
Upvotes: 0
Views: 497
Reputation: 948
Nice chart you have
How can I do the same type of selection but with a group of corresponding percentages ?
i said earlier you can add a class, select that class using
d3.selectAll(/*class_name*/).each(function(){})
then do something on each of that
if you using
d3.select('id')
you just select one element
that its why it work on path
, not on text
with using #per1,#per2 etc
what its that? why you not name it with same class or group it?
see this. i hope you will understand
var data = [
[[{name: "Bonpoint"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0.8},
{axis: "Cachemire", value: 0.6},
{axis: "Soie", value: 0.20},
{axis: "Angora", value: 0.20},
{axis: "Autres", value: 0.20},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0.20}]],
[[{name: "Petit Bateau"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0.40},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0.20}]],
[[{name: "Bobo Choses"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0.20},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0.40},
{axis: "Acrylique", value: 0.40},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0}]],
[[{name: "BeBe"}], [
{axis: "Coton", value: 0.40},
{axis: "Laine", value: 0},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0.20},
{axis: "Acrylique", value: 0.80},
{axis: "Viscose", value: 0.40},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0.80}]],
[[{name: "Familiar"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0.20},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0.40}]],
[[{name: "Miki House"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0.40}]],
[[{name: "Uniqlo"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0.20},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0.20},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0.20},
{axis: "Polyester", value: 0.40}]],
[[{name: "Baby GAP"}], [
{axis: "Coton", value: 1},
{axis: "Laine", value: 0},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0.20},
{axis: "Viscose", value: 0},
{axis: "Polyuréthane", value: 0.20},
{axis: "Polyester", value: 0.40}]],
[[{name: "Lucien Zazou"}], [
{axis: "Coton", value: 0.80},
{axis: "Laine", value: 0},
{axis: "Cachemire", value: 0},
{axis: "Soie", value: 0},
{axis: "Angora", value: 0},
{axis: "Autres", value: 0},
{axis: "Nylon", value: 0},
{axis: "Acrylique", value: 0.20},
{axis: "Viscose", value: 0.20},
{axis: "Polyuréthane", value: 0},
{axis: "Polyester", value: 0.60}]],
];
var color = d3.scaleOrdinal().range(["#00baff", "#0014fe", "#00ff9c", "#f4bf02", "#ffa600", "#ff0000", "#ff00c4", "#ee693e", "#99958f"]);
radarChart(".radarChart", data);
function radarChart(id, data, options)
{
var cfg = {w: 700,
h: 700,
margin: {top: 20, right: 20, bottom: 20, left: 20},
levels: 5,
labelFactor: 1.35,
wrapWidth: 60,
opacityArea: 0.2,
dotRadius: 2,
opacityCircles: 0.1,
strokeWidth: 1,
roundStrokes: true,
areaName: "areaName",
ratio: 1.8,
color:function(d){
return 'black'
}
}
if('undefined' !== typeof options)
{for(var i in options)
{if ('undefined' !== typeof options[i]){cfg[i] = options[i]} } }
var maxValue = d3.max(data, function(i){return d3.max(i[1].map(function(o)
{return o.value}))} );
var minValue = d3.min(data, function(i) {return d3.min(i[1].map(function(o) {return o.value}))});
var areaName = cfg["areaName"];
// Variables for when creating the axis
var allAxis = (data[0][1].map(function(i, j) {return i.axis})),
total = allAxis.length, // autant d'axes que d''axis' indiqués dans data
radius = (cfg.h/3), //rayon du cercle le plus éloigné
innerRadius = (radius / cfg.levels) * cfg.ratio,
Format = d3.format('.0%'), //affiche en pourcentage, arrondi à l'entier
angleSlice = Math.PI * 2 / total; // L'écart entre chaque part de camembert
// Radius scale
var rScale =d3.scaleLinear().range([innerRadius,radius]).domain([0,maxValue]);
// Svg
var svg = d3.select("body")
.append("svg")
.attr("width", cfg.w + cfg.margin.left + cfg.margin.right)
.attr("height", cfg.h + cfg.margin.top + cfg.margin.bottom)
.attr("class", "radar");
// g
var g = svg.append("g")
.attr("transform", "translate(" + (cfg.w/2 + cfg.margin.left) + "," + (cfg.h/2 - cfg.margin.top) + ")");
// GRID
var axisGrid = g.append("g").attr("class", "axisWrapper");
// Grid variables
var inconnu = 2.13 //ratio: 1.8
var distance = cfg.ratio * inconnu ;
var step = distance / (cfg.levels + 1)
// drawing the Grid
axisGrid.selectAll(".levels")
.data(d3.range(0, distance, step)) //nombres et écart (1) de cercles à partir du centre
.append("circle")
.attr("class", "gridCircle")
.attr("r", function(d, i){return innerRadius + (radius /cfg.levels * d)})
.style("fill", "white")
.style("stroke", "lightgrey")
.style("stroke-width", 0.2)
.style("fill-opacity", 0);
// Axis displaying the percentages (not displayed atm)
axisGrid.selectAll(".axisLabel")
.data(d3.range(1, cfg.levels+1)) // à partir du 2è cercle jusqau'au 5ème
.enter()
.append("text")
.attr("class", "axisLabel")
.attr("x", -10)
.attr("y", function(d){return innerRadius + (radius /(cfg.levels * 1.575) * d)})
.attr("dy", "0.4em")
.style("font-size", "10px")
.attr("fill", "#737373")
.text(function(d,i) { return Format((d/cfg.levels))})
.style("display", "none");
// Drawing the axis
var axis = axisGrid.selectAll(".axis")
.data(allAxis)
.enter()
.append("g")
.attr("class", "axis");
axis.append("line")
.attr("x1", function(d, i){return rScale(0) * Math.cos(angleSlice*i - Math.PI/2) }) //x du point de départ des lignes
.attr("y1", function(d, i){return rScale(0) * Math.sin(angleSlice*i - Math.PI/2) }) //y du points de départ des lignes
.attr("x2", function(d, i){ return rScale(maxValue) * Math.cos(angleSlice*i - Math.PI/2); })
.attr("y2", function(d, i){ return rScale(maxValue) * Math.sin(angleSlice*i - Math.PI/2); })
.attr("class", "line")
.style("stroke", "lightgrey")
.style("stroke-width", 1)
.attr("display", "none");
// Legend (brand names)
var legende = svg.selectAll("noms")
.data(data)
.enter()
.append("text")
.text(function(d) {return d[0].map(function (o) {return o.name})})
.attr("class", "legende")
.style("font-family", "helvetica")
.style("fill-opacity", 0.8)
.attr("x", 0)
.attr("y", function (d,i) {return 12 + i * 20})
.attr("id", function (d,i) {return "leg" + i})
.style("font-size", 10)
.style("fill", function(d,i) { return color(i)})
.style("opacity", 1);
// Put all the percentages at the right place (opacity set to 0 atm)
var pourcents = g.selectAll(".pourcentage")
.data(data)
.enter()
.append("g")
.attr('class',function(d) {return d[0].map(function (o,i) {return "pourcentage"+d.name})})
// .attr("class","pourcentage");
pourcents.selectAll(".pourcentagetext")
.data(function(d,i) {return d[1]})
.enter().append("text")
.attr("x", function(d,i){ return rScale(d.value + 0.05)* Math.cos(angleSlice*i - Math.PI/2) })
.attr("y", function(d,i){ return rScale(d.value + 0.05) * Math.sin(angleSlice*i - Math.PI/2) })
.attr("id", function (d,i) {return "per" + i})
.attr("class", "per" + "pct" )
.style("font-size", 10)
.text(function (d,i) { if (d.value == 0) {"fill", "none"} else {return Format(d.value)}})
.style("opacity", 0);
// Drawing the lines of the blobs (polygonal shapes)
var radarLine = d3.radialLine()
.curve(d3.curveLinearClosed)
.radius(function(d) { return rScale(d.value); })
.angle(function(d,i) { return i*angleSlice });
if(cfg.roundStrokes) {radarLine.curve(d3.curveLinearClosed)}
var blobWrapper = g.selectAll(".radarWrapper")
.data(data)
.enter().append("g")
.attr("class", "radarWrapper");
//mouseover
var m_over= function(d,i,j){
d3.selectAll(".radarArea")
.transition().duration(100)
.style("fill-opacity", 0);
d3.selectAll(".radarStroke")
.transition().duration(100)
.style("stroke-width", 0);
d3.select("#tag" + i)
.transition()
.duration(100)
.style("fill-opacity", 1);
d3.selectAll(".cir" + i)
.transition()
.duration(100)
.style("fill-opacity", 1);
d3.selectAll(".cir_txt" + i)
.transition()
.duration(100)
.style("fill-opacity", 1);
d3.select(this).style("font-size", 12);
d3.selectAll(".cir_txt" + i).each(function (d,i) {return d3.select(this).style("opacity",1)})
d3.selectAll(".cir" + i).each(function (d,i) {return d3.select(this).style("opacity",1)})
d3.select("#tag" + i).each(function (d,i) {return d3.select("#per").style("opacity", 1)})
}
var m_out= function(d, i) {d3.selectAll(".radarArea")
.transition().duration(500)
.style("fill-opacity", cfg.opacityArea);
d3.selectAll(".radarStroke")
.transition().duration(500)
.style("stroke-width", 0.1);
d3.select("#tag" + i)
.transition()
.duration(700)
.style("fill-opacity", cfg.opacityArea);
d3.selectAll(".cir" + i).each(
function(d,i){
return d3.select(this).style("opacity",0)
}).transition()
.duration(700)
.style("fill-opacity", cfg.opacityArea)
d3.selectAll(".cir_txt" + i).each(
function(d,i){
return d3.select(this).style("opacity",0)
}).transition()
.duration(700)
.style("fill-opacity", cfg.opacityArea)
}
// Drawing the blobs
blobWrapper.append("g")
.attr("id", function (d,i) {return "tog" + i})
.append("path")
.attr("class", "radarArea")
.attr("d", function(d,i) { return radarLine(d[1])})
.style("fill", function(d,i) { return color(i); })
.style("fill-opacity", cfg.opacityArea)
.attr("id", function (d,i) {return "tag" + i})
.on("mouseover",m_over)
.on("mouseout",m_out);
// Drawing the strokes of the blobs
blobWrapper.append("path")
.attr("class", "radarStroke")
.attr("d", function(d,i) { return radarLine(d[1]); })
.style("stroke-width", 0.1)
.style("stroke", function(d,i) { return color(i); })
.style("fill", "none")
.attr("id", function (d,i) {return "rad" + i});
// Add points (small circles) at every blobs angles (not displayed atm)
data.forEach(function(d,i){
var idx = i
d3.select("#tog" + i).selectAll(".circle")
.data(function(d,i,j){return d[1]})
.enter()
.append('circle')
.attr('class', 'cir'+i )
.attr("r", cfg.dotRadius)
.attr("cx", function(d,i){ return rScale(d.value) * Math.cos(angleSlice*i - Math.PI/2) })
.attr("cy", function(d,i){ return rScale(d.value) * Math.sin(angleSlice*i - Math.PI/2); })
.style("fill", function(d,i,j) { if (d.value === 0) {return "none"} else {return cfg.color(j)}})
.style("fill-opacity", 0)
.style("fill", color(idx))
d3.select("#tog" + i).selectAll("text")
.data(function(d,i,j) {return d[1]})
.enter().append("text")
.attr('class', 'cir_txt'+i )
.attr("x", function(d,i){ return rScale(d.value) * Math.cos(angleSlice*i - Math.PI/2) })
.attr("y", function(d,i){ return rScale(d.value) * Math.sin(angleSlice*i - Math.PI/2); })
.style("fill", function(d,i,j) { if (d.value == 0) {return "none"} else {return cfg.color(j)}})
.style("fill-opacity", 1)
.attr("dx", -25)
//.attr("dy", -10)
.attr("text-anchor", "right")
.style("font-weight", "bold")
.text( function(d,i,j) { if (d.value == 0) {return "none"} else {return Format(d.value)}})
.style("fill-opacity", 0);
})
// Set a mouseover function for the legend
legende.on("mouseover",m_over)
.on("mouseout",m_out);
// Add a white circle at the center, inside the inner circle
var centercircle = g.append("circle").attr("r", innerRadius + 1.5).raise().style("fill", "white").style("opacity", 1).style("stroke-width", 1).style("stroke", "lightgrey");
// Names of the textiles (one at the end of each axis)
axis.append("text")
.attr("class", "legend")
.style("font-size", "11px")
.attr("text-anchor", "middle")
.attr("dy", "0.35em")
.attr("x", function(d, i){ return rScale(maxValue * cfg.labelFactor) * Math.cos(angleSlice*i - Math.PI/2); })
.attr("y", function(d, i){ return rScale(maxValue * cfg.labelFactor) * Math.sin(angleSlice*i - Math.PI/2); })
.text(function(d){return d})
.attr("id", function(d,i) {return "mat" + i});
}
body {font-family: 'Open Sans', sans-serif;
font-size: 11px;
font-weight: 300;
fill: #242424;
text-align: center;
cursor: default;}
.legend {font-family: 'Open Sans', sans-serif;
fill: #333333;}
.tooltip {fill: #333333;}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="radarChart"></div>
</body>
</html>
Upvotes: 1