D3 Legend Placement - javascript

I have a donut chart with lots of labels and need place the labels preferably in a an unorder list so they will resize based on the size of the parent element.
I am going off of this example: http://zeroviscosity.com/d3-js-step-by-step/step-3-adding-a-legend
I still don't fully understand D3 and working quick to use it. Thanks for any suggestions you have!!
Here is my code.
JS
(function(d3) {
'use strict';
var width = 760;
var height = 760;
var radius = Math.min(width, height) / 2;
var donutWidth = 275;
var legendRectSize = 18;
var legendSpacing = 4;
var color = d3.scale.category20b();
var svg = d3.select('#chart')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var arc = d3.svg.arc()
.innerRadius(radius - donutWidth)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function(d) { return d.count; })
.sort(null);
var tooltip = d3.select('#chart')
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'label');
tooltip.append('div')
.attr('class', 'count');
tooltip.append('div')
.attr('class', 'percent');
d3.json('http://localhost:8080/product_sales/123/2014.01.01/2014.12.31', function(error, data) {
console.log(dataset);
var dataset = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
var obj = {
count: data[key],
enabled:true,
label:key
};
dataset.push(obj);
}
}
var path = svg.selectAll('path')
.data(pie(dataset))
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.label);
})
.each(function(d) { this._current = d; });
path.on('mouseover', function(d) {
var total = d3.sum(dataset.map(function(d) {
return (d.enabled) ? d.count : 0;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
tooltip.select('.label').html(d.data.label);
tooltip.select('.count').html("$"+d.data.count);
tooltip.select('.percent').html(percent + '%');
tooltip.style('display', 'block');
});
path.on('mouseout', function() {
tooltip.style('display', 'none');
});
path.on('mousemove', function(d) {
console.log((d3.event.pageX - 100)+', '+(d3.event.pageY + 10));
tooltip.style('top', (d3.event.offsetY+10) + 'px')
.style('left', (d3.event.offsetX+10) + 'px');
});
var legend = svg.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = -2 * legendRectSize;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color)
.on('click', function(label) {
var rect = d3.select(this);
var enabled = true;
var totalEnabled = d3.sum(dataset.map(function(d) {
return (d.enabled) ? 1 : 0;
}));
if (rect.attr('class') === 'disabled') {
rect.attr('class', '');
} else {
if (totalEnabled < 2) return;
rect.attr('class', 'disabled');
enabled = false;
}
pie.value(function(d) {
if (d.label === label) d.enabled = enabled;
return (d.enabled) ? d.count : 0;
});
path = path.data(pie(dataset));
path.transition()
.duration(750)
.attrTween('d', function(d) {
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
});
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
});
})(window.d3);
HTML
<!doctype html>
<html>
<head>
<title>Pie</title>
<style>
h1{
font-size: 14px;
text-align: center;
}
#chart {
height: 760px;
margin: 0 auto;
position: relative;
width: 760px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
display: none;
font-family: sans-serif;
font-size: 14px;
left: 0;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 80px;
z-index: 10;
}
.legend {
font-size: 14px;
font-family: sans-serif;
float:left;
}
rect {
cursor: pointer;
stroke-width: 2;
}
rect.disabled {
fill: transparent !important;
}
</style>
</head>
<body>
<div id="chart"></div>
<script src="../bower_components/d3/d3.min.js"></script>
<script src="/js/tip/new.js"></script>
</body>
</html>

Related

Mouse hovering over circle data point using D3.js

I am trying to add a hover effect without success. How to show data when hovering over datapoint?
https://plnkr.co/edit/Va1Dw3hg2D5jPoNGKVWp?p=preview&preview
<!DOCTYPE html>
svg {
font: 12px sans-serif;
text-anchor: middle;
}
rect {
stroke: lightgray;
stoke-width: 1px;
fill: none;
}
.y.axis path {
fill: none;
stroke: none;
}
</style>
d3.csv('data.csv', function (error, rows) {
var data = [];
rows.forEach(function (d) {
var x = d[''];
delete d[''];
for (prop in d) {
var y = prop,
value = d[prop];
data.push({
x: x,
y: y,
value: +value,
});
}
});
var margin = {
top: 25,
right: 80,
bottom: 25,
left: 25,
},
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
domain = d3
.set(
data.map(function (d) {
return d.x;
})
)
.values(),
num = Math.sqrt(data.length),
color = d3.scale
.linear()
.domain([-1, 0, 1])
.range(['#B22222', '#fff', '#000080']);
var x = d3.scale.ordinal().rangePoints([0, width]).domain(domain),
y = d3.scale.ordinal().rangePoints([0, height]).domain(domain),
xSpace = x.range()[1] - x.range()[0],
ySpace = y.range()[1] - y.range()[0];
var svg = d3
.select('body')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr(
'transform',
'translate(' + margin.left + ',' + margin.top + ')'
);
var cor = svg
.selectAll('.cor')
.data(data)
.enter()
.append('g')
.attr('class', 'cor')
.attr('transform', function (d) {
return 'translate(' + x(d.x) + ',' + y(d.y) + ')';
});
cor
.append('rect')
.attr('width', xSpace)
.attr('height', ySpace)
.attr('x', -xSpace / 2)
.attr('y', -ySpace / 2);
cor
.filter(function (d) {
var ypos = domain.indexOf(d.y);
var xpos = domain.indexOf(d.x);
for (var i = ypos + 1; i < num; i++) {
if (i === xpos) return false;
}
return true;
})
.append('text')
.attr('y', 5)
.text(function (d) {
if (d.x === d.y) {
return d.x;
} else {
return d.value.toFixed(2);
}
})
.style('fill', function (d) {
if (d.value === 1) {
return '#000';
} else {
return color(d.value);
}
});
cor
.filter(function (d) {
var ypos = domain.indexOf(d.y);
var xpos = domain.indexOf(d.x);
for (var i = ypos + 1; i < num; i++) {
if (i === xpos) return true;
}
return false;
})
.append('circle')
.attr('r', function (d) {
return (width / (num * 2)) * (Math.abs(d.value) + 0.1);
})
.style('fill', function (d) {
if (d.value === 1) {
return '#000';
} else {
return color(d.value);
}
});
var aS = d3.scale
.linear()
.range([-margin.top + 5, height + margin.bottom - 5])
.domain([1, -1]);
var yA = d3.svg.axis().orient('right').scale(aS).tickPadding(7);
var aG = svg
.append('g')
.attr('class', 'y axis')
.call(yA)
.attr(
'transform',
'translate(' + (width + margin.right / 2) + ' ,0)'
);
var iR = d3.range(-1, 1.01, 0.01);
var h = height / iR.length + 3;
iR.forEach(function (d) {
aG.append('rect')
.style('fill', color(d))
.style('stroke-width', 0)
.style('stoke', 'none')
.attr('height', h)
.attr('width', 10)
.attr('x', 0)
.attr('y', aS(d));
});
});
</script>
Create a new div and give it some styles. also set the opacity to 0.
var popupDiv = d3
.select("#root")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
Next, you need to add a mouseenter and mouseout to your desired elements
d3.append("div") // Change this to your element(s)
.on("mouseenter", function (d, i) {
popupDiv.transition().duration(200).style("opacity", 0.9);
popupDiv
.html(i.Description) // Example of display a data item description
.style("left", d.pageX + "px") // X offset can be added here
.style("top", d.pageY + "px"); // Y offset can be added here
})
.on("mouseout", function (d, i) {
popupDiv.transition().duration(200).style("opacity", 0);
})
Bear in mind the first parameter d to the mouseenter and mouseout functions is the mouse event itself which is being used to find out the x and y position of the mouse. The second parameter i is the data attached to your element if you wanted to use any of the data for specific descriptions or colours etc.
These are the base styles I used when creating a popup
div.tooltip {
position: absolute;
text-align: center;
width: auto;
height: auto;
max-width: 200px;
padding: 8px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
z-index: 10;
}

Displaying selections to an SVG rectangle (JavaScript)

I saw this post last night and wanted to replicate it/make it better - because it interested me. However, I'm stuck on displaying the selections to an SVG rectangle. I thought by appending text to the function where the Lasso is called would work, however it doesn't. I've included the problematic code and would like to know where I've gone wrong for me to improve. Thanks.
If you need anymore code, holla.
var textBox = svg.append("g")
.attr("transform", "translate(5,385)");
textBox.append("rect")
.attr("height", 10)
.attr("width", 100)
.style("stroke", "black")
.style("fill", "none")
.style("stroke-width", 1);
var lasso_start = function() {
lasso.items()
.attr("r",7)
.classed("not_possible",true)
.classed("selected",false);
};
var lasso_draw = function() {
lasso.possibleItems()
.classed("not_possible",false)
.classed("possible",true);
lasso.notPossibleItems()
.classed("not_possible",true)
.classed("possible",false);
};
var lasso_end = function() {
lasso.items()
.classed("not_possible",false)
.classed("possible",false);
selected = lasso.selectedItems()
.classed("selected", true)
.attr("r", 13);
var selectedDots = selected.data().map(d=>d[0]);
};
var lasso = d3.lasso()
.closePathSelect(true)
.closePathDistance(100)
.items(circles)
.targetArea(area)
.on("start",lasso_start)
.on("draw",lasso_draw)
.on("end",function(d) {
textBox.append("text")
.attr("x", 10)
.attr("y", 20)
.text(lasso_end)
});
svg.call(lasso);
Modifying the block that I posted as an answer to this post to include the selections in a rect, here's a fork for the same:
https://bl.ocks.org/shashank2104/d58381c96971ff131c03e8832470085b/151651c9fa3e94fef46e243227924f4e4c90cf01
And a code snippet if that's convenient:
#import url('https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300');
#import url("https://fonts.googleapis.com/css?family=Lato:300");
text {
font-family: "Open Sans Condensed";
}
.axis path {
stroke: black;
}
.tick line {
visibility: hidden;
}
.border {
margin-top: 9px;
margin-left: 29px;
border: .5px solid black;
width: 325px;
height: 335px;
position: absolute;
}
.lasso path {
stroke: rgb(80,80,80);
stroke-width:2px;
}
.lasso .drawn {
fill-opacity:.05 ;
}
.lasso .loop_close {
fill:none;
stroke-dasharray: 4, 4;
}
.lasso .origin {
fill:#3399FF;
fill-opacity:.5;
}
.not_possible {
fill:rgb(200,200,200);
}
.textBox rect {
fill: steelblue;
}
text.selection {
font-size: 12px;
fill: #FFF;
letter-spacing: 0.1em;
font-weight: 300;
}
<!DOCTYPE html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-selection"),require("d3-drag")):"function"==typeof define&&define.amd?define(["exports","d3-selection","d3-drag"],n):n(t.d3=t.d3||{},t.d3,t.d3)}(this,function(t,n,r){"use strict";function e(t,n){return n={exports:{}},t(n,n.exports),n.exports}function o(){function t(t){function u(){p=[],h="",_.attr("d",null),m.attr("d",null),r.nodes().forEach(function(t){t.__lasso.possible=!1,t.__lasso.selected=!1,t.__lasso.hoverSelect=!1,t.__lasso.loopSelect=!1;var n=t.getBoundingClientRect();t.__lasso.lassoPoint=[Math.round(n.left+n.width/2),Math.round(n.top+n.height/2)]}),s&&r.on("mouseover.lasso",function(){this.__lasso.hoverSelect=!0}),i.start()}function l(){var t,n;"touchmove"===d3.event.sourceEvent.type?(t=d3.event.sourceEvent.touches[0].clientX,n=d3.event.sourceEvent.touches[0].clientY):(t=d3.event.sourceEvent.clientX,n=d3.event.sourceEvent.clientY);var s=d3.mouse(this)[0],u=d3.mouse(this)[1];""===h?(h=h+"M "+s+" "+u,v=[t,n],d=[s,u],b.attr("cx",s).attr("cy",u).attr("r",7).attr("display",null)):h=h+" L "+s+" "+u,p.push([t,n]);var l=Math.sqrt(Math.pow(t-v[0],2)+Math.pow(n-v[1],2)),f="M "+s+" "+u+" L "+d[0]+" "+d[1];_.attr("d",h),m.attr("d",f),a=l<=e,a&&o?m.attr("display",null):m.attr("display","none"),r.nodes().forEach(function(t){t.__lasso.loopSelect=!(!a||!o)&&c(p,t.__lasso.lassoPoint)<1,t.__lasso.possible=t.__lasso.hoverSelect||t.__lasso.loopSelect}),i.draw()}function f(){r.on("mouseover.lasso",null),r.nodes().forEach(function(t){t.__lasso.selected=t.__lasso.possible,t.__lasso.possible=!1}),_.attr("d",null),m.attr("d",null),b.attr("display","none"),i.end()}var h,v,d,p,g=t.append("g").attr("class","lasso"),_=g.append("path").attr("class","drawn"),m=g.append("path").attr("class","loop_close"),b=g.append("circle").attr("class","origin"),M=d3.drag().on("start",u).on("drag",l).on("end",f);n.call(M)}var n,r=[],e=75,o=!0,a=!1,s=!0,i={start:function(){},draw:function(){},end:function(){}};return t.items=function(n){if(!arguments.length)return r;r=n;var e=r.nodes();return e.forEach(function(t){t.__lasso={possible:!1,selected:!1}}),t},t.possibleItems=function(){return r.filter(function(){return this.__lasso.possible})},t.selectedItems=function(){return r.filter(function(){return this.__lasso.selected})},t.notPossibleItems=function(){return r.filter(function(){return!this.__lasso.possible})},t.notSelectedItems=function(){return r.filter(function(){return!this.__lasso.selected})},t.closePathDistance=function(n){return arguments.length?(e=n,t):e},t.closePathSelect=function(n){return arguments.length?(o=n===!0,t):o},t.isPathClosed=function(n){return arguments.length?(a=n===!0,t):a},t.hoverSelect=function(n){return arguments.length?(s=n===!0,t):s},t.on=function(n,r){if(!arguments.length)return i;if(1===arguments.length)return i[n];var e=["start","draw","end"];return e.indexOf(n)>-1&&(i[n]=r),t},t.targetArea=function(r){return arguments.length?(n=r,t):n},t}var a=e(function(t){function n(t,n,e){var o=t*n,a=r*t,s=a-t,i=a-s,u=t-i,l=r*n,f=l-n,c=l-f,h=n-c,v=o-i*c,d=v-u*c,p=d-i*h,g=u*h-p;return e?(e[0]=g,e[1]=o,e):[g,o]}t.exports=n;var r=+(Math.pow(2,27)+1)}),s=e(function(t){function n(t,n){var r=t+n,e=r-t,o=r-e,a=n-e,s=t-o,i=s+a;return i?[i,r]:[r]}function r(t,r){var e=0|t.length,o=0|r.length;if(1===e&&1===o)return n(t[0],r[0]);var a,s,i=e+o,u=new Array(i),l=0,f=0,c=0,h=Math.abs,v=t[f],d=h(v),p=r[c],g=h(p);d<g?(s=v,f+=1,f<e&&(v=t[f],d=h(v))):(s=p,c+=1,c<o&&(p=r[c],g=h(p))),f<e&&d<g||c>=o?(a=v,f+=1,f<e&&(v=t[f],d=h(v))):(a=p,c+=1,c<o&&(p=r[c],g=h(p)));for(var _,m,b,M,y,w=a+s,x=w-a,j=s-x,E=j,A=w;f<e&&c<o;)d<g?(a=v,f+=1,f<e&&(v=t[f],d=h(v))):(a=p,c+=1,c<o&&(p=r[c],g=h(p))),s=E,w=a+s,x=w-a,j=s-x,j&&(u[l++]=j),_=A+w,m=_-A,b=_-m,M=w-m,y=A-b,E=y+M,A=_;for(;f<e;)a=v,s=E,w=a+s,x=w-a,j=s-x,j&&(u[l++]=j),_=A+w,m=_-A,b=_-m,M=w-m,y=A-b,E=y+M,A=_,f+=1,f<e&&(v=t[f]);for(;c<o;)a=p,s=E,w=a+s,x=w-a,j=s-x,j&&(u[l++]=j),_=A+w,m=_-A,b=_-m,M=w-m,y=A-b,E=y+M,A=_,c+=1,c<o&&(p=r[c]);return E&&(u[l++]=E),A&&(u[l++]=A),l||(u[l++]=0),u.length=l,u}t.exports=r}),i=e(function(t){function n(t,n,r){var e=t+n,o=e-t,a=e-o,s=n-o,i=t-a;return r?(r[0]=i+s,r[1]=e,r):[i+s,e]}t.exports=n}),u=e(function(t){function n(t,n){var o=t.length;if(1===o){var a=r(t[0],n);return a[0]?a:[a[1]]}var s=new Array(2*o),i=[.1,.1],u=[.1,.1],l=0;r(t[0],n,i),i[0]&&(s[l++]=i[0]);for(var f=1;f<o;++f){r(t[f],n,u);var c=i[1];e(c,u[0],i),i[0]&&(s[l++]=i[0]);var h=u[1],v=i[1],d=h+v,p=d-h,g=v-p;i[1]=d,g&&(s[l++]=g)}return i[1]&&(s[l++]=i[1]),0===l&&(s[l++]=0),s.length=l,s}var r=a,e=i;t.exports=n}),l=e(function(t){function n(t,n){var r=t+n,e=r-t,o=r-e,a=n-e,s=t-o,i=s+a;return i?[i,r]:[r]}function r(t,r){var e=0|t.length,o=0|r.length;if(1===e&&1===o)return n(t[0],-r[0]);var a,s,i=e+o,u=new Array(i),l=0,f=0,c=0,h=Math.abs,v=t[f],d=h(v),p=-r[c],g=h(p);d<g?(s=v,f+=1,f<e&&(v=t[f],d=h(v))):(s=p,c+=1,c<o&&(p=-r[c],g=h(p))),f<e&&d<g||c>=o?(a=v,f+=1,f<e&&(v=t[f],d=h(v))):(a=p,c+=1,c<o&&(p=-r[c],g=h(p)));for(var _,m,b,M,y,w=a+s,x=w-a,j=s-x,E=j,A=w;f<e&&c<o;)d<g?(a=v,f+=1,f<e&&(v=t[f],d=h(v))):(a=p,c+=1,c<o&&(p=-r[c],g=h(p))),s=E,w=a+s,x=w-a,j=s-x,j&&(u[l++]=j),_=A+w,m=_-A,b=_-m,M=w-m,y=A-b,E=y+M,A=_;for(;f<e;)a=v,s=E,w=a+s,x=w-a,j=s-x,j&&(u[l++]=j),_=A+w,m=_-A,b=_-m,M=w-m,y=A-b,E=y+M,A=_,f+=1,f<e&&(v=t[f]);for(;c<o;)a=p,s=E,w=a+s,x=w-a,j=s-x,j&&(u[l++]=j),_=A+w,m=_-A,b=_-m,M=w-m,y=A-b,E=y+M,A=_,c+=1,c<o&&(p=-r[c]);return E&&(u[l++]=E),A&&(u[l++]=A),l||(u[l++]=0),u.length=l,u}t.exports=r}),f=e(function(t){function n(t,n){for(var r=new Array(t.length-1),e=1;e<t.length;++e)for(var o=r[e-1]=new Array(t.length-1),a=0,s=0;a<t.length;++a)a!==n&&(o[s++]=t[e][a]);return r}function r(t){for(var n=new Array(t),r=0;r<t;++r){n[r]=new Array(t);for(var e=0;e<t;++e)n[r][e]=["m",e,"[",t-r-1,"]"].join("")}return n}function e(t){return 1&t?"-":""}function o(t){if(1===t.length)return t[0];if(2===t.length)return["sum(",t[0],",",t[1],")"].join("");var n=t.length>>1;return["sum(",o(t.slice(0,n)),",",o(t.slice(n)),")"].join("")}function i(t){if(2===t.length)return[["sum(prod(",t[0][0],",",t[1][1],"),prod(-",t[0][1],",",t[1][0],"))"].join("")];for(var r=[],a=0;a<t.length;++a)r.push(["scale(",o(i(n(t,a))),",",e(a),t[0][a],")"].join(""));return r}function f(t){for(var e=[],a=[],s=r(t),u=[],l=0;l<t;++l)0===(1&l)?e.push.apply(e,i(n(s,l))):a.push.apply(a,i(n(s,l))),u.push("m"+l);var f=o(e),c=o(a),h="orientation"+t+"Exact",_=["function ",h,"(",u.join(),"){var p=",f,",n=",c,",d=sub(p,n);return d[d.length-1];};return ",h].join(""),m=new Function("sum","prod","scale","sub",_);return m(d,v,p,g)}function c(t){var n=x[t.length];return n||(n=x[t.length]=f(t.length)),n.apply(void 0,t)}function h(){for(;x.length<=_;)x.push(f(x.length));for(var n=[],r=["slow"],e=0;e<=_;++e)n.push("a"+e),r.push("o"+e);for(var o=["function getOrientation(",n.join(),"){switch(arguments.length){case 0:case 1:return 0;"],e=2;e<=_;++e)o.push("case ",e,":return o",e,"(",n.slice(0,e).join(),");");o.push("}var s=new Array(arguments.length);for(var i=0;i<arguments.length;++i){s[i]=arguments[i]};return slow(s);}return getOrientation"),r.push(o.join(""));var a=Function.apply(void 0,r);t.exports=a.apply(void 0,[c].concat(x));for(var e=0;e<=_;++e)t.exports[e]=x[e]}var v=a,d=s,p=u,g=l,_=5,m=1.1102230246251565e-16,b=(3+16*m)*m,M=(7+56*m)*m,y=f(3),w=f(4),x=[function(){return 0},function(){return 0},function(t,n){return n[0]-t[0]},function(t,n,r){var e,o=(t[1]-r[1])*(n[0]-r[0]),a=(t[0]-r[0])*(n[1]-r[1]),s=o-a;if(o>0){if(a<=0)return s;e=o+a}else{if(!(o<0))return s;if(a>=0)return s;e=-(o+a)}var i=b*e;return s>=i||s<=-i?s:y(t,n,r)},function(t,n,r,e){var o=t[0]-e[0],a=n[0]-e[0],s=r[0]-e[0],i=t[1]-e[1],u=n[1]-e[1],l=r[1]-e[1],f=t[2]-e[2],c=n[2]-e[2],h=r[2]-e[2],v=a*l,d=s*u,p=s*i,g=o*l,_=o*u,m=a*i,b=f*(v-d)+c*(p-g)+h*(_-m),y=(Math.abs(v)+Math.abs(d))*Math.abs(f)+(Math.abs(p)+Math.abs(g))*Math.abs(c)+(Math.abs(_)+Math.abs(m))*Math.abs(h),x=M*y;return b>x||-b>x?b:w(t,n,r,e)}];h()}),c=e(function(t){function n(t,n){for(var e=n[0],o=n[1],a=t.length,s=1,i=a,u=0,l=a-1;u<i;l=u++){var f=t[u],c=t[l],h=f[1],v=c[1];if(v<h){if(v<o&&o<h){var d=r(f,c,n);if(0===d)return 0;s^=0<d|0}else if(o===h){var p=t[(u+1)%a],g=p[1];if(h<g){var d=r(f,c,n);if(0===d)return 0;s^=0<d|0}}}else if(h<v){if(h<o&&o<v){var d=r(f,c,n);if(0===d)return 0;s^=d<0|0}else if(o===h){var p=t[(u+1)%a],g=p[1];if(g<h){var d=r(f,c,n);if(0===d)return 0;s^=d<0|0}}}else if(o===h){var _=Math.min(f[0],c[0]),m=Math.max(f[0],c[0]);if(0===u){for(;l>0;){var b=(l+a-1)%a,M=t[b];if(M[1]!==o)break;var y=M[0];_=Math.min(_,y),m=Math.max(m,y),l=b}if(0===l)return _<=e&&e<=m?0:1;i=l+1}for(var w=t[(l+a-1)%a][1];u+1<i;){var M=t[u+1];if(M[1]!==o)break;var y=M[0];_=Math.min(_,y),m=Math.max(m,y),u+=1}if(_<=e&&e<=m)return 0;var x=t[(u+1)%a][1];e<_&&w<o!=x<o&&(s^=1)}}return 2*s-1}t.exports=n;var r=f});t.lasso=o,Object.defineProperty(t,"__esModule",{value:!0})});</script>
</head>
<body>
<script>
var data = [["Arsenal",-0.0032967741593940836, 0.30399753945657115],["Chelsea", 0.2752159801936051, -0.0389675484210763], ["Liverpool",-0.005096951348655329, 0.026678627680541075], ["Manchester City",-0.004715381791104284, -0.12338379196523988], ["Manchester United",0.06877966010653305, -0.0850615090351779], ["Tottenham",-0.3379518099485709, -0.09933664174939877]];
var selectedTeams = [];
const colours = d3.scaleOrdinal()
.domain(data)
.range(["#F8B195", "#F67280", "#C06C84", "#6C5B7B", "#355C7D", "#2A363B"]);
var canvasW = 675;
var canvasH = 600;
var w = 365;
var h = 365;
var xPadding = 30;
var yPadding = 20;
var padding = 10;
var border = 0.5;
var bordercolor = 'black';
var xScale = d3.scaleLinear()
.range([xPadding, w - padding])
.domain([-1, 1]);
var yScale = d3.scaleLinear()
.range([h - yPadding, padding])
.domain([-1, 1]);
var svg = d3.select('body')
.append("svg")
.attr('width', canvasW)
.attr('height', canvasH);
var circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 7)
.attr("cx", function(d) { return xScale(d[1]); })
.attr("cy", function(d) { return yScale(d[2]); })
.attr("fill", function(d) {
var result = null;
if (data.indexOf(d) >= 0) {
result = colours(d);
} else {
result = "white";
}
return result;
});
var lasso_start = function() {
lasso.items()
.attr("r",7)
.classed("not_possible",true)
.classed("selected",false);
};
var lasso_draw = function() {
lasso.possibleItems()
.classed("not_possible",false)
.classed("possible",true);
lasso.notPossibleItems()
.classed("not_possible",true)
.classed("possible",false);
};
var modifyTextBox = function (selected) {
if(selected.length) {
var widths = [], textHeight = 0;
var texts = textBox.selectAll('text.selection')
.data(selected);
texts.exit().remove();
texts
.enter().append('text').attr('class', 'selection').attr('x', '3')
.merge(texts)
.attr('y', function (d, i) {
return i * 13 + 12;
}).text(function (d) { return d; });
textBox.selectAll('text.selection')
.each(function (d) {
widths.push(d3.select(this).node().getBBox().width);
textHeight = d3.select(this).node().getBBox().height;
});
var maxW = selected.length ? d3.max(widths) : 0;
textBox.style('display', null).select('rect').attr('width', maxW+10).attr('height', selected.length*textHeight);
} else {
textBox.style('display', 'none');
}
};
var lasso_end = function() {
lasso.items()
.classed("not_possible",false)
.classed("possible",false);
var selected = lasso.selectedItems()
.classed("selected", true)
.attr("r", 13);
var selectedDots = selected.data().map(d=>d[0]);
modifyTextBox(selectedDots);
};
var textBox = svg.append("g").classed('textBox', true).style('display', 'none');
textBox.append("rect")
.attr("height", 10)
.attr("width", 100)
.style("stroke-width", 1);
var area = svg.append("rect")
.attr("width", w)
.attr("height", h)
.style("opacity", 0);
var lasso = d3.lasso()
.closePathSelect(true)
.closePathDistance(100)
.items(circles)
.targetArea(area)
.on("start",lasso_start)
.on("draw",lasso_draw)
.on("end",lasso_end);
var legend = svg.selectAll(".legend")
.data(colours.domain())
.enter()
.append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 29 + ")"; });
legend.append("rect")
.attr("x", canvasW - 184)
.attr("y", 11)
.attr("width", 18)
.attr("height", 18)
.style("fill", colours);
legend.append("text")
.attr("x", canvasW - 194)
.attr("y", 20)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d[0];})
svg.call(lasso);
</script>
Relevant changes:
Based on the selections, I've added a function that adds texts to the textBox with an enter/exit/merge logic and assigns widths to the rect based on the maximum length of the text.
var modifyTextBox = function (selected) {
if(selected.length) {
var widths = [], textHeight = 0;
var texts = textBox.selectAll('text.selection')
.data(selected);
texts.exit().remove();
texts
.enter().append('text').attr('class', 'selection').attr('x', '3')
.merge(texts)
.attr('y', function (d, i) {
return i * 13 + 12;
}).text(function (d) { return d; });
textBox.selectAll('text.selection')
.each(function (d) {
widths.push(d3.select(this).node().getBBox().width);
textHeight = d3.select(this).node().getBBox().height;
});
var maxW = selected.length ? d3.max(widths) : 0;
textBox.style('display', null).select('rect').attr('width', maxW+10).attr('height', selected.length*textHeight);
} else {
textBox.style('display', 'none');
}
};
And calling this in the lasso_end function as: modifyTextBox(selectedDots);
And I've added some CSS for this textBox and the texts within it:
.textBox rect {
fill: steelblue;
}
text.selection {
font-size: 12px;
fill: #FFF;
letter-spacing: 0.1em;
font-weight: 300;
}
Feel free to play around with this function to position the rect (probably based on the mouse).
Hope this helps.

Applying zoom in matrix scatterplot d3.js v4

Here is a plunkr of a matrix scatterplot in d3 V4
http://plnkr.co/edit/7meh4sMhxItcQtCaAtZP?p=preview
(It may take some time to load and display)
I am looking forward to zoom the plot in order to see the cluttered points in a convenient way.
I have used d3.zoom() to rescale the axis but the circles are not being plotted accordingly.
Here is the problem description:
Initially, all the axis are set with different ranges (like top y-axis is having range from 4.5-7.5 , below that y-axis range is from 2.0-4.0 .. )
Now after zooming it, (i.e when scrolling mouse over the circles), all the axis are set in the same ranges that leads to all circles oriented diagonally.
Is there a workaround for that so that we can zoom the axis accordingly and visualize it nicely !!
Thanks. Any help would highly appreciated.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
padding: 10px;
}
.axis,
.frame {
shape-rendering: crispEdges;
}
.axis line {
stroke: #ddd;
}
.axis path {
display: none;
}
.cell text {
font-weight: bold;
text-transform: capitalize;
}
.frame {
fill: none;
stroke: #aaa;
}
circle {
fill-opacity: .7;
}
circle.hidden {
fill: #ccc !important;
}
.extent {
fill: #000;
fill-opacity: .125;
stroke: #fff;
}
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 80px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var tooltipDiv;
d3.helper = {};
var zoomable = true;
var new_xScale;
var new_yScale;
d3.helper.tooltip = function (param1, param2) {
var bodyNode = d3.select('body').node();
function tooltip(selection) {
selection.on('mouseover.tooltip', function (point) {
// Clean up lost tooltips
d3.select('body').selectAll('div.tooltip').remove();
// Append tooltip
tooltipDiv = d3.select('body')
.append('div')
.attr('class', 'tooltip');
var absoluteMousePos = d3.mouse(bodyNode);
//console.log('absoluteMousePos', absoluteMousePos);
tooltipDiv
.style('left', (absoluteMousePos[0] + 10) + 'px')
.style('top', (absoluteMousePos[1] - 30) + 'px');
var line = '';
//var temp_key = d3.keys(point);
var temp_key = [param1, param2];
// _.each(d3.keys(point), function (key, index) {
temp_key.forEach(function (key, index) {
if (index != temp_key.length - 1) {
line += key + ': ' + point[key] + '</br>';
} else {
line += key + ': ' + point[key];
}
});
tooltipDiv.html(line);
})
.on('mousemove.tooltip', function () {
// Move tooltip
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv
.style("left", (absoluteMousePos[0] + 10) + 'px')
.style("top", absoluteMousePos[1] < 80 ? absoluteMousePos[1] + 10 :(absoluteMousePos[1] - 70) + 'px');
})
.on('mouseout.tooltip', function () {
// Remove tooltip
tooltipDiv.remove();
});
}
tooltip.attr = function (_x) {
if (!arguments.length) return attrs;
attrs = _x;
return this;
};
tooltip.style = function (_x) {
if (!arguments.length) return styles;
styles = _x;
return this;
};
return tooltip;
};
var width = 500,
size = 150,
padding = 20;
var x = d3.scaleLinear().rangeRound([padding / 2, size - padding / 2]);
var y = d3.scaleLinear().rangeRound([size - padding / 2, padding / 2]);
var xAxis = d3.axisBottom()
.scale(x)
.ticks(7);
var yAxis = d3.axisLeft()
.scale(y)
.ticks(7);
var color = d3.scaleOrdinal(d3.schemeCategory10);
d3.json("flowers.json", function (data) {
var attr2Domain = {},
attrs= ['sepal length', 'sepal width', 'petal length','petal width']
n = attrs.length;
attrs.forEach(function (attr) {
attr2Domain[attr] = d3.extent(data, function (ele) {
return ele[attr];
});
});
xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);
var svg = d3.select("body")
.append("svg")
.attr("width", size * n + padding)
.attr("height", size * n + padding)
.append("g")
.attr("transform", "translate(" + padding + "," + padding / 2 + ")");
svg.selectAll(".x.axis")
.data(attrs)
.enter().append("g")
.attr("class", "x axis")
.attr("transform", function (d, i) {
return "translate(" + (n - i - 1) * size + ",0)";
})
.each(function (d) {
x.domain(attr2Domain[d]);
d3.select(this).call(xAxis);
});
svg.selectAll(".y.axis")
.data(attrs)
.enter().append("g")
.attr("class", "y axis")
.attr("transform", function (d, i) {
return "translate(0," + i * size + ")";
})
.each(function (d) {
y.domain(attr2Domain[d]);
d3.select(this).call(yAxis);
});
var cell = svg.selectAll(".cell")
.data(cross(attrs, attrs))
.enter()
.append("g")
.attr("class", "cell")
.attr("classx", function(d){ return d.x; })
.attr("classy", function(d){ return d.y; })
.attr("transform", function (d) {
return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")";
});
// Titles for the diagonal.
cell.filter(function (d) {
return d.i === d.j;
})
.append("text")
.attr("x", padding)
.attr("y", padding)
.attr("dy", ".71em")
.style("fill", "black")
.text(function (d) {
return d.x;
});
cell.each(plot);
// plot each cell
function plot(p) {
cell = d3.select(this);
x.domain(attr2Domain[p.x]);
y.domain(attr2Domain[p.y]);
cell.append("rect")
.attr("class", "frame")
.attr("x", padding / 2)
.attr("y", padding / 2)
.attr("width", size - padding)
.style("pointer-events", "none")
.attr("height", size - padding);
var circles = cell.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function (d) {
return x(d[p.x]);
})
.attr("cy", function (d) {
return y(d[p.y]);
})
.attr("r", 4)
//.style("fill", "green");
.style("fill", function (d) {
return color(d.species);
});
circles.on('mousemove', function(){
var param1 = d3.select(this.parentNode).attr("classx");
var param2 = d3.select(this.parentNode).attr("classy");
circles.call(d3.helper.tooltip(param1, param2));
});
}
//--------------------------------------------- applying zoom----------
applyZoom();
function applyZoom() {
if (zoomable) {
var zoom = d3.zoom()
.on("zoom", zoomed);
svg.call(zoom).on("dblclick.zoom", null);
}
}
function zoomed() {
console.log('zoomed');
new_xScale = d3.event.transform.rescaleX(x);
new_yScale = d3.event.transform.rescaleY(y);
console.log("new_xScale", x);
svg.selectAll(".x.axis")
.each(function (d) {
x.domain(attr2Domain[d]);
d3.select(this).call(xAxis.scale(new_xScale));
});
svg.selectAll(".y.axis")
.each(function (d) {
y.domain(attr2Domain[d]);
d3.select(this).call(yAxis.scale(new_yScale));
});
cell.each(plotly);
}
function plotly(p) {
console.log("plotly", p);
//return x(d[p.x])
svg.selectAll("circle")
.attr("cx", function (d) {
return new_xScale(d[p.x]);
})
.attr("cy", function (d) {
return new_yScale(d[p.y]);
});
}
});
function cross(a, b) {
var c = [], n = a.length, m = b.length, i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
c.push({x: a[i], i: i, y: b[j], j: j});
}
}
return c;
}
</script>
I think move'new_xScale = d3.event.transform.rescaleX(x)' after 'x.domain(attr2Domain[d])' inside each function should work. The same as y.
Thanks

D3 text not centered on nodes?

I have a jsfiddle with a scatter plot, on which the corresponding text will not align with the dots.
I believe that this chunk should be displaying the names at the same coordinates as the circles:
.attr("x", function(d){return timeScale(d[1]);})
.attr("y", function(d){return rankScale(d[0]);})
This is the same code I used to place the circles.
Do I misunderstand something?
Since you are (for whatever reason) translating the circles, you should apply the same translate to the texts:
textSelection.attr("transform", "translate("+transRight+","+transDown+")")
Alternatively, don't translate the circles.
Here is your updated fiddle: https://jsfiddle.net/yv3ts1fw/
And here a Stack snippet with the same code:
function call() {
$.ajax({
url: "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/cyclist-data.json",
data: {
format: 'json'
},
complete: function(xhr, textStatus) {
//console.log(xhr.status);
//console.log(textStatus);
},
error: function() {
$('#container').html('<p>An error has occurred</p>');
},
success: (data) => {
pushArray(data);
},
type: 'GET'
});
}
call();
var timeArray = [];
function pushArray(data) {
data = JSON.parse(data);
for (var i = 0; i < data.length; i++) {
var tempArray = [];
tempArray.push(i);
var hms = data[i].Time;
var a = hms.split(':');
var seconds = ((+a[0]) * 60 + (+a[1]));
tempArray.push(seconds);
timeArray.push(tempArray);
}
var w = $(window).width();
var h = $(window).height();
var margin = {
top: h / 5,
left: w / 10
};
h = h * .8;
w = w * .9;
var svgW = w * .8;
var svgH = h * .8;
w = w * .6;
h = h * .6;
var rankScale = d3.scaleLinear()
.domain([1, 35])
.range([0, h]);
var axisRankScale = d3.scaleLinear()
.domain([35, 1])
.range([h, 0]);
var timeScale = d3.scaleLinear()
.domain([2200, 2400])
.range([0, w]);
var xAxis = d3.axisBottom()
.scale(timeScale);
var yAxis = d3.axisLeft()
.scale(axisRankScale);
var toolTip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var transDown = 20;
var transRight = 100;
//h = 700;
// h=h*1.2;
//w=w*1.2;
//w= 300;
var theBody = d3.select("#container")
.append("svg")
.attr("height", svgH * 1.4)
.attr("width", w * 1.6)
.attr("transform", "translate(50, 50)")
.append("g")
.attr("transform", "translate(20, 20)");
theBody.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 50)
.attr("x", -(h / 2))
//.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Rank");
theBody.append("text")
.attr("y", h + margin.top)
.attr("x", w / 1.5)
.style("text-anchor", "middle")
.text("Seconds");
theBody.selectAll("foo")
.data(timeArray)
.enter()
.append("text")
.text(function(d) {
var index = d[0];
var _this = data[index];
return _this.Name;
})
.attr("x", function(d) {
return timeScale((d[1]));
})
.attr("y", function(d) {
return rankScale((d[0]));
})
.attr("font-size", "10px")
.attr("transform", "translate(" + (transRight + 16) + "," + transDown + ")");
theBody.selectAll("circle")
.data(timeArray)
.enter()
.append("circle")
.attr("cx", function(d) {
return timeScale(d[1]);
})
.attr("cy", function(d) {
return rankScale((d[0]));
})
.attr("r", 10)
.attr("fill", "green")
.attr("stroke", "black")
.attr("transform", "translate(" + transRight + "," + transDown + ")")
.on("mouseout", function() {
toolTip.style("opacity", 0.0);
})
.on("mouseover", function(d) {
var index = d[0];
var _this = data[index];
var time = _this.Time,
name = _this.Name,
year = _this.Year,
dope = _this.Doping;
if (dope === "") {
dope = "No doping allegations!";
}
toolTip.html(name + "<br>" + year + "<br>" + time + " <br>---<br>" + dope)
.style("opacity", 1)
.style("left", ((d3.event.pageX) + 40) + "px")
.style("top", ((d3.event.pageY) + 0) + "px");
});
}; // end pushArray main
svg {
border: solid;
}
#container {
border: solid green;
width: 100vw;
height: 100vh;
}
div.tooltip {
display: flex;
position: absolute;
justify-content: center;
align-items: center;
text-align: center;
width: 12vw;
height: 25vh;
padding: 2px;
font: 12px sans-serif;
font-weight: bold;
background: rgb(255, 82, 80);
border: 0px;
border-radius: 8px;
pointer-events: none;
opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="container">
<div>tour de france
<div></div>
PS: in your text selection, don't do theBody.selectAll("text"), because you already have texts in that SVG. Instead of that, select something that doesn't exist, like theBody.selectAll("foo").

Legend to be aligned after pie chart but getting aligned before

Hello I want to right align my legend after the pie chart. But with my codes they are getting aligned to left before pie chart. What CSS changes should I make to do this.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<style type="text/css">
/* #container {
margin: 5%;
height: 50%;
width: 50%;
}*/
#chart {
position: absolute;
background-color: #eee;
/* height: 50%;
width: 50%; */
}
#chart legend{
position: absolute;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
position: absolute;
text-align: center;
width: 10%;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" viewBox="0 0 960 500" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
["192.168.12.1", 20],
["76.09.45.34", 40],
["34.91.23.76", 80],
["192.168.19.32", 16],
["192.168.10.89", 50],
["192.178.34.07", 18],
["192.168.12.98", 30]];
var data = data.map(function(d) {
return {
IP: d[0],
count: d[1]
};
});
var width = 500,
height = 300;
var radius = Math.min(width, height) / 2 - 50;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/2 + "," + height/2 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} }) //We can define any value for (d.data.count >__ according to our need. Like if we have smaller values less than 10 then no need to dislay them as they can be overlapped on pie slice margins)// If not needed to display make this comment
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", "translate(" + width * 1/4 + "," + height * 1/4 + ")")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
var targetHeight = container.height();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>
Please give some idea how to solve this problem. I am stuck in this code.
Thanks for help in advance.
You need to add x and y attributes to the legend.
legend.attr("x", width - 65)
.attr("y", 25)
Here is the full code and working example for you

Categories