Public
Edited
Mar 6, 2022
1 fork
1 star
Insert cell
Insert cell
<div id="chart"></div>
Insert cell
{

await update([shuffled,shuffledIds])
await startAnimation();
}
Insert cell
svg = {
const svgBackgroundColor = "#081c15",
numLines = 100,
lineWidth = 3,
svg = d3.select("#chart")
.append('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("background-color", svgBackgroundColor);
return svg;
}
Insert cell
container = d3.select('svg').append("g").attr('transform', `translate(${margin.top}, ${margin.left})`)
.attr("id", "container");
Insert cell
update = async (allData) => {

let data = allData[0]
let shuffledIds = allData[1];
x.domain(shuffledIds);
let rects = d3.select("#container").selectAll(".rects")
.data(data, d => d.id)
rects
.join(
enter => enter.append("rect")
.classed('rects', true)
.attr('x', d => x(d.id))
.attr('y', d => height - d.height)
.attr('width', x.bandwidth())
.attr('height', d => d.height)
.attr("fill", d => d.color)
.attr("stroke", d => d.color)
.attr("stroke-linecap", "round")
.attr("stroke-opacity", 0.1)
.style("opacity", d => d.status != "inactive" ? 1 : 0.6),
update => update.call(e => e.transition()
.duration(100)
.delay(0)
.attr('x', d => x(d.id))
.attr("stroke-opacity", 0.1)
.style("opacity", d => d.status != "inactive" ? 1 : 0.6)
)
)
}
Insert cell
startAnimation = async() => {
for (let x of animate()){
let ans = await x.then(d => d);
await update(animationStep(ans));
}
}
Insert cell
function* animate() {
for (let i = 0; i < result.length; i++) {
yield Promises.delay(50,i);
}
}
Insert cell
animationStep = (count) => {
let resultIds = result[count].data.map(d => d.id);

let updatedSet = new Set(resultIds);
let resultLocations = [];

if(result[count].type == 'conquer'){
//this part is where the halves are merged together, will update the domain for new bar locations
shuffled.forEach((d,i) => {
if(updatedSet.has(d.id)){
resultLocations.push(i);
}
})
resultLocations = resultLocations.sort(function(a, b) {return a - b;});
//get the old array indices for the updated items and then sort them and update shuffledIds
for(let i in resultIds){
let resultId = resultIds[i];
let newLocation = resultLocations[i];
shuffledIds[newLocation] = resultId;
}

}
//for the animation
shuffled.forEach(d => {
if(updatedSet.has(d.id)){
d.status = result[count].type;
}else{
d.status = "inactive";
}
})
return [shuffled,shuffledIds];
}
Insert cell
result = sortList(shuffled)
Insert cell
shuffled = {
return d3.shuffle(lineData);
}
Insert cell
shuffledIds = {
return shuffled.map(d => d.id); }
Insert cell
sortList = (data) => {
//merge sort function, returns steps for animation

let animationSteps = [];

const mergeSort = (d) => {
//for the animation
if(d.length){
let dCopy = JSON.parse(JSON.stringify(d));
let step = {type: "divide", data:dCopy};
animationSteps.push(step);
}
//base case
if(d.length < 2){
return d;
}
//divide the array in half
let midPoint = Math.floor(d.length/2);
let left = d.slice(0,midPoint);
let right = d.slice(midPoint,d.length);
//sort left and right sides recursively
left = mergeSort(left);
right = mergeSort(right);


let solution = [];
//merge the sorted halves together
while(left.length && right.length){
if(left[0].height < right[0].height){
solution.push(left.shift());
}else{
solution.push(right.shift());
}
}
while(left.length){
solution.push(left.shift());
}
while(right.length){
solution.push(right.shift());
}
//for visualization
if(solution.length){
let sCopy = JSON.parse(JSON.stringify(solution));
animationSteps.push({type: "conquer", data: sCopy});
}
return solution;
}
let mSort = mergeSort(data);
console.log(animationSteps);
return animationSteps;

}
Insert cell
Insert cell
margin = ({top: 10, bottom: 10, left: 10, right: 10})
Insert cell
numLines = 200
Insert cell
width = 800 - margin.left - margin.right
Insert cell
height = 400 - margin.top - margin.bottom
Insert cell
x = d3.scaleBand()
.range([0,width])
.domain(d3.range(numLines))
Insert cell
y = d3.scaleLinear()
.range([height,0])
.domain([0,numLines])
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more