|
//Developer: Narayana Swamy |
|
//emailID: narayanaswamy14@gmail.com |
|
|
|
d3 = d3 || {}; |
|
(function(){ |
|
"use strict"; |
|
|
|
d3.clusterpuritychart = function(){ |
|
|
|
var containerID, |
|
width, |
|
height, |
|
originalData, |
|
ParentG,LegendG,legendFilter= [], |
|
circleR = 0, |
|
innerRadius =0,eleInRow,noOfCategories,fixAngleLayout, |
|
colorScale = d3.scale.category10(), |
|
radiusScale = d3.scale.linear(), |
|
legendObj = d3.legend(), |
|
scale_temp = d3.scale.linear(), |
|
originalData2, |
|
MinMaxTotal = 0, |
|
margin = {top:20}, |
|
totalCount = 0, |
|
colorMap = {}; |
|
|
|
var pie = d3.layout.pie() |
|
.sort(null) |
|
.value(function(d) { |
|
return d.ele; |
|
}); |
|
|
|
var custLayout = d3.custumPieLayout() |
|
.sort(null) |
|
.value(function(d) { |
|
return d.ele; |
|
}); |
|
|
|
var arc = d3.svg.arc() |
|
.innerRadius(innerRadius); |
|
|
|
var chart = function(selection){ |
|
|
|
if(fixAngleLayout) |
|
custLayout.fixAngle((360/(noOfCategories- legendFilter.length))/(360/(2*Math.PI))); |
|
|
|
width = parseInt(d3.select('#'+containerID).style('width')); |
|
height = parseInt(d3.select('#'+containerID).style('height')); |
|
|
|
legendObj.legendOnclickMthod(chart.legendFilter); |
|
|
|
selection.each(function(data){ |
|
|
|
originalData = data; |
|
|
|
data.forEach(function(d){ |
|
d.values.forEach(function(e){ |
|
e.total = d.total; |
|
e.color = colorScale(e.type); |
|
if(!colorMap.hasOwnProperty(e.type)) |
|
colorMap[e.type] = {'key':e.type,'color':e.color}; |
|
}) |
|
}); |
|
|
|
var length = data.length, eleInRow = Math.ceil(Math.sqrt(length)); |
|
var container = d3.select(this); |
|
width = width - 100; |
|
var temp_width = data.length > eleInRow?width-0.5*(width/eleInRow):width; |
|
circleR = d3.min([temp_width,(height-margin.top)])/eleInRow; |
|
var x_offset = 0,y_offset=0; |
|
|
|
radiusScale |
|
.domain([0,d3.extent(data,function(d){return d.total})[1]]) |
|
.range([(circleR/2)*(1/data.length),circleR/2]); |
|
|
|
MinMaxTotal = radiusScale.domain(); |
|
|
|
container.attr('width',(circleR*eleInRow+0.5*circleR)+200) |
|
.attr('height',circleR*eleInRow + margin.top) |
|
|
|
if(!ParentG){ |
|
ParentG = container.append('g').attr('class','parentG') |
|
.attr('transform','translate('+(data.length > eleInRow?0.5*circleR:0)+','+margin.top+')'); |
|
LegendG = container.append('g').attr('class','legendG'); |
|
} |
|
|
|
LegendG.attr('transform','translate('+(width+50)+','+((circleR*eleInRow/2)-(Object.keys(colorMap).length*20)/2)+')') |
|
.datum(colorMap) |
|
.call(legendObj); |
|
|
|
var circleG = ParentG |
|
.attr('transform','translate('+(data.length > eleInRow?0.5*circleR:0)+','+margin.top+')') |
|
.selectAll('.circleG') |
|
.data(data |
|
.sort(function(a,b){ |
|
if(a.total < b.total) |
|
return 1; |
|
else if(a.total > b.total) |
|
return -1; |
|
else |
|
return 0; |
|
}) |
|
); |
|
|
|
circleG.enter() |
|
.append('g') |
|
.attr('class','circleG') |
|
.attr('transform',function(d,i){ |
|
return 'translate('+((i%eleInRow)*(circleR))+','+(Math.floor(i/eleInRow)*circleR)+')'; |
|
}) |
|
.append('circle') |
|
.attr('r',0) |
|
.attr('cx',circleR/2) |
|
.attr('cy',circleR/2) |
|
.style('fill','white') |
|
.style('stroke','black') |
|
.style('stroke-width','1px'); |
|
|
|
circleG.exit().transition().duration(0).remove(); |
|
|
|
circleG |
|
.attr('transform',function(d,i){ |
|
if(Math.floor(i/eleInRow)%2 === 1){ |
|
x_offset = 0.5*circleR; |
|
y_offset = 0.13*circleR*Math.floor(i/eleInRow); |
|
} |
|
else{ |
|
x_offset = 0; |
|
if(Math.floor(i/eleInRow)===0) |
|
y_offset = 0; |
|
else |
|
y_offset = 0.13*circleR*Math.floor(i/eleInRow); |
|
} |
|
return 'translate('+(((i%eleInRow)*(circleR))-x_offset)+','+((Math.floor(i/eleInRow)*circleR)-y_offset)+')'; |
|
}); |
|
|
|
circleG |
|
.selectAll('circle') |
|
.attr('r',0) |
|
.attr('cx',circleR/2) |
|
.attr('cy',circleR/2) |
|
.on('mouseover',function(d){ |
|
d3.select(this).style('stroke-width','2px') |
|
}) |
|
.on('mouseout',function(d){ |
|
d3.select(this).style('stroke-width','1px') |
|
}) |
|
.on('click',function(d){ |
|
d3.select(this).style('stroke-width','1px') |
|
if(originalData.length == 1) |
|
d3.select('#'+containerID).select('svg').datum(originalData2).call(chart); |
|
else{ |
|
originalData2 = originalData; |
|
d3.select('#'+containerID).select('svg').datum([d]).call(chart); |
|
} |
|
}) |
|
.transition() |
|
.duration(1000) |
|
.attr('r',circleR/2); |
|
|
|
circleG.each(chart.renderPieChart); |
|
|
|
}) |
|
d3.select(window).on('resize.'+containerID, chart.resize) |
|
}; |
|
|
|
chart.containerID = function(_){ |
|
containerID = _; |
|
return chart; |
|
}; |
|
chart.noOfCategories= function(_){ |
|
noOfCategories = _; |
|
return chart; |
|
}; |
|
chart.fixAngleLayout = function(_){ |
|
fixAngleLayout = _; |
|
return chart; |
|
}; |
|
chart.legendFilter = function(_){ |
|
if(legendFilter.indexOf(_) == -1) |
|
legendFilter.push(_); |
|
else |
|
legendFilter.splice(legendFilter.indexOf(_),1); |
|
|
|
d3.select('#'+containerID).select('svg').datum(originalData).call(chart); |
|
|
|
return chart; |
|
}; |
|
chart.change = function(_){ |
|
chart.fixAngleLayout(_); |
|
d3.select('#'+containerID).select('svg').datum(originalData).call(chart); |
|
return chart; |
|
}; |
|
|
|
chart.resize = function(){ |
|
d3.select('#'+containerID).select('svg').datum(originalData).call(chart); |
|
}; |
|
|
|
chart.renderPieChart = function(data){ |
|
|
|
scale_temp |
|
.domain(d3.extent(data.values,function(d){return d.ele;})) |
|
.range([parseInt(radiusScale(data.total)*0.2),parseInt(radiusScale(data.total))*(originalData.length==1?0.8:1.2)]); |
|
|
|
arc.outerRadius(function (d) { |
|
if(fixAngleLayout){ |
|
return scale_temp(d.value); |
|
} |
|
else{ |
|
return (radiusScale(d.data.total))*0.8; |
|
} |
|
}); |
|
|
|
var newData = data.values |
|
.filter(function(d){ |
|
if(legendFilter.indexOf(d.type) === -1) |
|
return true; |
|
else |
|
return false; |
|
}); |
|
|
|
var paths = d3.select(this) |
|
.selectAll('path') |
|
.data(fixAngleLayout?custLayout(newData):pie(newData)); |
|
|
|
paths.enter() |
|
.append("path") |
|
.attr('transform',function(d,i){ |
|
return 'translate('+(circleR/2)+','+(circleR/2)+')'; |
|
}) |
|
.attr("fill", function(d){ |
|
return d.data.color; |
|
}) |
|
.attr("stroke", "gray") |
|
.attr("class", "outlineArc") |
|
.attr("d", arc) |
|
.on('click',function(d){ |
|
console.log(originalData) |
|
if(originalData.length == 1) |
|
d3.select('#'+containerID).select('svg').datum(originalData2).call(chart); |
|
else{ |
|
originalData2 = originalData; |
|
d3.select('#'+containerID).select('svg').datum([d.parentData]).call(chart); |
|
} |
|
}) |
|
.each(function(d) { this._current = d; |
|
d.parentData = data; }); |
|
|
|
paths.exit().transition().duration(1000).remove(); |
|
|
|
paths |
|
.attr('transform',function(d,i){ |
|
return 'translate('+(circleR/2)+','+(circleR/2)+')'; |
|
}) |
|
.attr("fill", function(d){ |
|
return d.data.color; |
|
}) |
|
.transition() |
|
.duration(1000) |
|
.attrTween("d", arcTween) |
|
.each('end',function(d) { this._current = d; |
|
d.parentData = data; }); |
|
|
|
function arcTween(a) { |
|
var i = d3.interpolate(this._current, a); |
|
this._current = i(10); |
|
return function(t) { |
|
return arc(i(t)); |
|
}; |
|
} |
|
|
|
} |
|
|
|
return chart; |
|
}; |
|
|
|
d3.custumPieLayout = function(){ |
|
var sort,fixAngle, |
|
valueFun, |
|
sortcomparator, |
|
padAngle=0; |
|
|
|
var pieLayoutObj = function(startAngle,endAngle,padAngle,value,data){ |
|
this.startAngle =startAngle; |
|
this.endAngle =endAngle; |
|
this.padAngle = padAngle; |
|
this.value = value; |
|
this.data = data; |
|
}; |
|
|
|
var layout = function(data){ |
|
|
|
if(sortcomparator) |
|
data.sort(sortcomparator); |
|
|
|
var previousEndAngle = 0, |
|
outputObj = []; |
|
|
|
data.forEach(function(d){ |
|
outputObj.push(new pieLayoutObj(previousEndAngle,previousEndAngle+fixAngle,padAngle,valueFun(d),d)); |
|
previousEndAngle = previousEndAngle+fixAngle; |
|
}); |
|
|
|
return outputObj; |
|
|
|
}; |
|
|
|
layout.sort = function(_){ |
|
//if(typeof _ !== 'function') return; |
|
sortcomparator = _; |
|
return layout; |
|
} |
|
layout.fixAngle = function(_){ |
|
if(!arguments.length) return; |
|
fixAngle = _; |
|
return layout; |
|
} |
|
layout.value = function(_){ |
|
if(typeof _ !== 'function') return; |
|
valueFun = _; |
|
return layout; |
|
} |
|
layout.padAngle = function(_){ |
|
padAngle = _; |
|
return layout; |
|
} |
|
|
|
return layout; |
|
}; |
|
|
|
d3.legend = function () { |
|
|
|
var legendOnclickMthod, |
|
legendOnHoverMthod, |
|
legendOnmouseHoverMthod, |
|
legendOnmouseOutMthod, |
|
legendOndblclickMthod; |
|
|
|
var chart = function(selection){ |
|
|
|
selection.each(function(data){ |
|
|
|
|
|
var legend_container = d3.select(this); |
|
|
|
var wrap = legend_container.selectAll('.legendChart').data([data]); |
|
var wrapEnter = wrap.enter().append('g').attr('class', 'legendChart'); |
|
var gEnter = wrapEnter.append('g'); |
|
var g = wrap.select('g') |
|
.attr('transform','translate(10,30)'); |
|
|
|
wrapEnter.append('text').attr('x',0).attr('y',0).text('Interactive legend') |
|
var g_ci = g.selectAll('circle') |
|
.data(function(d){ |
|
return Object.keys(d) |
|
}); |
|
|
|
g_ci.exit().transition().remove(); |
|
|
|
g_ci.enter() |
|
.append('circle') |
|
.attr('r',function(d){return 10;}) |
|
.style('fill', function(d){return data[d].color}) |
|
.style('opacity',1) |
|
.style('stroke', function(d){return data[d].color}) |
|
.style('stroke-width',2) |
|
.attr('cx',function(d,i){ |
|
return 0; |
|
}) |
|
.attr('cy',function(d,i){ |
|
|
|
return Math.floor(i)*30; |
|
}) |
|
.on('mouseout',function(d){ |
|
d3.select(this).style('stroke-width',2) |
|
.style('stroke', function(d){return data[d].color}); |
|
}) |
|
.on('mouseover',function(d){ |
|
d3.select(this).style('stroke-width',3) |
|
.style('stroke', function(d){return 'black'}); |
|
}) |
|
.on('click',function(d){ |
|
if(d3.select(this).classed("disable_")){ |
|
d3.select(this).style("fill",data[d].color) |
|
.classed("disable_",false); |
|
legendOnclickMthod(data[d].key,true); |
|
} |
|
else |
|
{ |
|
d3.select(this).classed("disable_",true) |
|
.style("fill",'white'); |
|
legendOnclickMthod(data[d].key,false); |
|
} |
|
}); |
|
|
|
|
|
g_ci.style('fill', function(d){ |
|
if(d3.select(this).style('fill')=='rgb(255, 255, 255)') |
|
return 'white'; |
|
else |
|
return data[d].color; |
|
}) |
|
.style('stroke', function(d){return data[d].color}) |
|
.transition() |
|
.duration(1000) |
|
.attr('cx',function(d,i){ |
|
return 0; |
|
}) |
|
.attr('cy',function(d,i){ |
|
|
|
return Math.floor(i)*30; |
|
}); |
|
|
|
var g_txt = g.selectAll('text') |
|
.data(function(d){ return Object.keys(d)}); |
|
|
|
g_txt.exit().transition().remove(); |
|
|
|
g_txt.enter() |
|
.append('text'); |
|
|
|
g_txt.text(function(d){return data[d].key.substring(0,10)}) |
|
.attr('font-size','18px') |
|
.transition() |
|
.duration(1000) |
|
.attr('x',function(d,i){ |
|
return 30; |
|
}) |
|
.attr('y',function(d,i){ |
|
return i*30+5; |
|
}) |
|
|
|
}); |
|
|
|
//return chart; |
|
}; |
|
chart.legendOnclickMthod = function(_){ |
|
if(!arguments.length) return legendOnclickMthod; |
|
if(typeof _ != 'function') return legendOnclickMthod; |
|
legendOnclickMthod = _; |
|
return chart; |
|
}; |
|
chart.legendOndblclickMthod = function(_){ |
|
if(!arguments.length) return legendOndblclickMthod; |
|
if(typeof _ != 'function') return legendOndblclickMthod; |
|
legendOndblclickMthod = _; |
|
return chart; |
|
}; |
|
chart.legendOnmouseOutMthod = function(_){ |
|
if(!arguments.length) return legendOnmouseOutMthod; |
|
if(typeof _ != 'function') return legendOnmouseOutMthod; |
|
legendOnmouseOutMthod = _; |
|
return chart; |
|
}; |
|
chart.legendOnmouseHoverMthod = function(){ |
|
if(!arguments.length) return legendOnmouseHoverMthod; |
|
if(typeof _ != 'function') return legendOnmouseHoverMthod; |
|
legendOnmouseHoverMthod = _; |
|
return chart; |
|
}; |
|
|
|
return chart; |
|
|
|
}; |
|
|
|
})() |