Skip to content

Instantly share code, notes, and snippets.

@Alex-Devoid
Created January 24, 2020 20:30
Show Gist options
  • Select an option

  • Save Alex-Devoid/a062f99bdeccca612433c9fc961b9cbd to your computer and use it in GitHub Desktop.

Select an option

Save Alex-Devoid/a062f99bdeccca612433c9fc961b9cbd to your computer and use it in GitHub Desktop.
chuck, transition and remove 1000s of circles
<head>
<title>transition and delete</title>
<link rel="stylesheet" href="style/style.css" type="text/css" media="screen" />
<meta charset="utf-8">
</head>
<body>
<div id="main-wrapper">
<button type="button" name="button" onclick="transition()">transition</button>
<div id="chart"></div>
</div><!-- @end #main-wrapper -->
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
d3.selection.prototype.size = function() {
var n = 0;
this.each(function() { ++n; });
return n;
};
var margin = {top: 16, right: 0, bottom: 0, left: 0},
width = 950 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var node_radius = 5,
padding = 1,
cluster_padding = 10,
num_nodes = 200;
var svg = d3.select("#chart").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 mexico;
var usa;
var usa1;
var ven;
var canada;
var geoMercator = d3.geoMercator()
var path = d3.geoPath().projection(d3.geoMercator());
d3.json("https://gist.githubusercontent.com/Alex-Devoid/090691fe85351ebc8eefb0f21515fc2d/raw/e7f0904f2b48943bc90a3d50e5c244665fda6d97/110_admin.geojson", function(error, world) {
if (error) throw error;
d3.csv("https://gist.githubusercontent.com/Alex-Devoid/090691fe85351ebc8eefb0f21515fc2d/raw/e7f0904f2b48943bc90a3d50e5c244665fda6d97/mpp_courts_d3_texas.csv", function(errorData, mppData) {
if (errorData) throw errorData;
var lookup = {};
var sourceCountries = [];
//https://stackoverflow.com/questions/17780508/selecting-distinct-values-from-a-json
for (var item, i = 0; item = mppData[i++];) {
var country = item.source;
if (!(country in lookup)) {
lookup[country] = 1;
sourceCountries.push(country);
}
}
var destinations =
[{
name:'elPaso',
type: "Point",
coordinates: [-97.745015,26.020156],
},
{
name:'sanDiego',
type: "Point",
coordinates: [-117.035644,32.534302],
},
{
name:'Texas',
type: "Point",
coordinates: [-99.533056,27.455729],
}]
for (var i = 0; i < destinations.length; i++) {
destinations[i].point = geoMercator(destinations[i].coordinates)
}
console.log(sourceCountries)
var data1 = []
for (var i = 0; i < world.features.length; i++) {
for (var b = 0; b < sourceCountries.length; b++) {
if (world.features[i].properties.SOVEREIGNT === sourceCountries[b]){
data1.push({
"class": `${world.features[i].properties.SOVEREIGNT}_${destinations[0].name}`,
"source": {
"lat": path.centroid(world.features[i])[1],
"lon": path.centroid(world.features[i])[0]
},
"destination": {
"lat": destinations[0].point[1],
"lon": destinations[0].point[0]
}
},
{
"class": `${world.features[i].properties.SOVEREIGNT}_${destinations[1].name}`,
"source": {
"lat": path.centroid(world.features[i])[1],
"lon": path.centroid(world.features[i])[0]
},
"destination": {
"lat": destinations[1].point[1],
"lon": destinations[1].point[0]
}
},
{
"class": `${world.features[i].properties.SOVEREIGNT}_${destinations[2].name}`,
"source": {
"lat": path.centroid(world.features[i])[1],
"lon": path.centroid(world.features[i])[0]
},
"destination": {
"lat": destinations[2].point[1],
"lon": destinations[2].point[0]
}
}
)
}
}
}
svg.selectAll("path")
.data(world.features)
.enter().append("path")
.attr("d", path);
var projection = d3.geoMercator();
var curve = function(context) {
var custom = d3.curveLinear(context);
custom._context = context;
custom.point = function(x,y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1;
this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y);
this.x0 = x; this.y0 = y;
break;
case 1: this._point = 2;
default:
var x1 = this.x0 * 0.5 + x * 0.5;
var y1 = this.y0 * 0.5 + y * 0.5;
var m = 1/(y1 - y)/(x1 - x);
var r = -100; // offset of mid point.
var k = r / Math.sqrt(1 + (m*m) );
if (m == Infinity) {
y1 += r;
}
else {
y1 += k;
x1 += m*k;
}
this._context.quadraticCurveTo(x1,y1,x,y);
this.x0 = x; this.y0 = y;
break;
}
}
return custom;
}
var line = d3.line()
.x(function(d) {
return d.lon;
})
.y(function(d) {
return d.lat;
})
.curve(curve);
var route = svg.selectAll(null)
.data(data1)
.enter()
.append("path")
.attr("class", function(d){
return d.class
})
.datum(function(d) {
return [d.source,d.destination]; // d3.line expects an array where each item represnts a vertex.
})
.attr("d",line)
.style("stroke","yellow")
.style("fill","none")
.style("stroke-width",1.5)
// var testData = [{
//
// "source": "Honduras",
// "January": "10",
// "February": "5",
// "March": "10",
// "April": "0",
// "May": "10",
// "June": "10",
// "July": "10",
// "August": "10",
// "September": "10",
// "October": "10",
// "November": "10",
// "destination": "Texas"
// },
// {
//
// "source": "Venezuela",
// "January": "5",
// "February": "10",
// "March": "5",
// "April": "10",
// "May": "10",
// "June": "10",
// "July": "10",
// "August": "10",
// "September": "10",
// "October": "10",
// "November": "10",
// "destination": "Texas"
// }]
// **** this chunck is wrangling the csv into distict datapoints
var months =["January","February","March","April","May", "June","July","August","September","October","November"]
function sumKey(bills,key){
//https://stackoverflow.com/questions/44436041/how-to-sum-value-of-two-json-object-key
var res = bills.map(bill => Number(bill[key])).reduce((acc, bill) => bill + acc);
return res
}
function getMax(arr, prop) {
var max;
for (var i=0 ; i<arr.length ; i++) {
if (max == null || parseInt(arr[i][prop]) > parseInt(max[prop]))
max = arr[i];
}
return max;
}
var newTestArray = [];
console.log(mppData);
maxMonthArray = []
for (var b = 0; b < months.length; b++) {
var maxMonth = getMax(mppData, months[b]);
maxMonthArray.push(maxMonth[months[b]])
for (var i = 0; i < mppData.length; i++) {
for (var a = 0; a < Number(mppData[i][months[b]]); a++) {
newTestArray.push({
"id": a,
"source": mppData[i].source,
"destination": mppData[i].destination,
'month': b
})
}
}
}
//https://blog.abelotech.com/posts/array-conversion-2-dimensional-javascript/
function arrayTo2DArray2(list, howMany) {
var idx = 0
result = []
while (idx < list.length) {
if (idx % howMany === 0) result.push([])
result[result.length - 1].push(list[idx++])
}
return result
}
console.log('newTestArray');
console.log(newTestArray);
newTestArray.sort(function(a, b) {
return a.id - b.id;
});
newTestArray.sort(function(a, b) {
return a.month - b.month;
});
var chunckArray = []
for (var i = 0; i < maxMonthArray.length; i++) {
maxMonthArray[i]
for (var c = 0; c < Number(maxMonthArray[i]); c++) {
var chunck = newTestArray.filter(obj => obj.id === c && obj.month === i );
chunckArray.push(chunck)
}
}
console.log('chunckArray');
console.log(chunckArray);
var combineChunckArray = [];
for (var i = 0; i < chunckArray.length -4; i+= 4) {
combineChunckArray.push(chunckArray[i].concat(chunckArray[i+1],chunckArray[i+2],chunckArray[i+3]))
}
console.log('combineChunckArray.length');
console.log(combineChunckArray);
var combineChunckArrayLengths =[0]
var addLengths=0;
for (var i = 0; i < combineChunckArray.length; i++) {
for (var b = 0; b < combineChunckArray[i].length; b++) {
// console.log(i);
combineChunckArray[i][b].index = i
// combineChunckArray[i][b].index = i
}
}
for (var i = 0; i < combineChunckArray.length; i++) {
addLengths += combineChunckArray[i].length
combineChunckArrayLengths.push(addLengths)
}
console.log(combineChunckArrayLengths);
var arrayOfNewArrays = arrayTo2DArray2(newTestArray, 20)
// console.log('arrayOfNewArraysff');
// console.log(arrayOfNewArrays);
// for (var i = 0; i < arrayOfNewArrays.length; i++) {
//
//
// for (var d = 0; d < arrayOfNewArrays[i].length; d++) {
//
// arrayOfNewArrays[i][d].index = i
//
// }
//
// }
// console.log('arrayOfNewArraysff');
// console.log(arrayOfNewArrays);
function circlesLoop(newTestArrayIndex){
var multiCircles = svg.selectAll(".circle")
.data(newTestArrayIndex)
.enter().append("circle")
.attr("class", function(d,i){
// console.log(d);
return `c-${d.month}-${d.id}`})
.attr("id", function(d,i){
return `_${d.index}`})
.attr("r", function(d){
return 6;
})
.attr("fill", function(d){
return 'red';
})
}
function multipleTest(aT){
console.log(`${aT} > ${combineChunckArrayLengths[circleIndexCounter+1]}`);
if (aT >= combineChunckArrayLengths[circleIndexCounter+1] || aT == 0 ){
circleIndexCounter++
console.log("monthIndexCounter "+ circleIndexCounter);
console.log('combineChunckArray[circleIndexCounter].length');
console.log(combineChunckArray[circleIndexCounter].length);
console.log(combineChunckArray[circleIndexCounter]);
circlesLoop(combineChunckArray[circleIndexCounter])
}
}
//https://stackoverflow.com/questions/1230233/how-to-find-the-sum-of-an-array-of-numbers
var sumMaxMonths = maxMonthArray.reduce(function(acc, val) { return Number(acc) + Number(val) }, 0);
console.log('sumMaxMonths')
console.log(maxMonthArray)
// divide months in half
var arraySplit = [[],[],[],[],[],[],[],[],[],[],[],[]]
for (var i = 0; i < newTestArray.length; i++) {
arraySplit[newTestArray[i].month].push(newTestArray[i])
}
for (var i = 0; i < arraySplit.length; i++) {
// console.log(arraySplit[i].length);
}
//count twords the sum of the max values in each month
var counter = -1;
var circleIndexCounter = -1;
//migrants in a month
var a = -1;
var remainder;
//total migrants
var aT = 0;
// months
var m = 0;
//This loop transitions the circles
// over the path elements
(function loop() {
//newTestArray.length
if (counter++ > sumMaxMonths ) return;
setTimeout(function() {
if (m < 11) {
if (a++ >= maxMonthArray[m]) {
m++
a = 0
}
}
console.log(`.c-${m}-${a}`);
// if (remainder == 0) {
// console.log(remainder);
// }
console.log(aT);
multipleTest(aT)
var thisPolygon = d3.selectAll(`.c-${m}-${a}`)
aT += thisPolygon.nodes().length
// console.log(`.c-${m}-${a}`);
transition1( thisPolygon, counter);
loop()
}, 300)
}());
function transition1(elem,i) {
elem.transition()
.duration(3000)
.attrTween("transform", translateAlong())
.on('end', function(d){
if (d.index > 0) {
d3.selectAll(`#_${d.index-1}`).remove();
}
})
// Returns an attrTween for translating along the specified path element.
function translateAlong(path1) {
return function(d, i, a) {
// console.log(`.${d.source}_${d.destination}`);
var path = d3.select(`.${d.source}_${d.destination}`).node();
var l = path.getTotalLength();
var t0 = 0;
return function(t) {
var p0 = path.getPointAtLength(t0 * l); //previous point
var p = path.getPointAtLength(t * l); //current point
var angle = Math.atan2(p.y - p0.y, p.x - p0.x) * 180 / Math.PI; //angle for tangent
t0 = t;
//Shifting center to center of arrow
// xoffset and yoffset should be half the original width and height
var xoffset = 0,
yoffset = 0;
var centerX = p.x - xoffset;
var centerY = p.y - yoffset;
return "translate(" + centerX + "," + centerY + ")rotate(" + angle + " " + xoffset + " " + yoffset + ")";
};
};
}
}
});
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment