{
const svgBackgroundColor = "#081c15",
mazeEnterColor = "#f8961e",
mazeExitColor = "#faedcd",
mazePathColor = "#333d29",
mazeWallColor = "#95d5b2",
mazeWallWidth = 4,
svg = d3.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("background-color", svgBackgroundColor),
container = svg.append("g")
.attr("transform",`translate(${margin.left},${margin.top})`),
container2 = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`),
numRows = mazeWidth,
numCols = mazeHeight,
y = d3.scaleBand()
.range([0,width])
.domain(d3.range(numRows)),
x = d3.scaleBand()
.range([0, height])
.domain(d3.range(numCols)),
update = (edges, mazeLines,diffIds,borderEdges) => {
let lines = container.selectAll(".mazePathLines")
.data(mazeLines)
lines
.join(
enter => enter.append("path")
.classed('mazePathLines', true)
.attr("d", d => {
let x1 = x(d.source % numCols) + x.bandwidth();
let y1 = y(Math.floor(d.source/numCols)) + y.bandwidth();
let x2 = x(d.target % numCols) + x.bandwidth();
let y2 = y(Math.floor(d.target/numCols)) + y.bandwidth();
return d3.line()([[x1,y1],[x2,y2]]);
})
.attr("stroke", mazePathColor)
.attr("stroke-width", 7)
.attr("fill", mazePathColor)
.style('opacity', .5)
)
//maze walls - perpendicular to maze lines
let walls = container.selectAll(".walls")
.data(diffIds)
walls
.join(
enter => enter.append("path")
.classed('walls', true)
.attr("d", d => {
let x1 = d.source % numCols;
let y1 = Math.floor(d.source/numCols);
let x2 = d.target % numCols;
let y2 = Math.floor(d.target/numCols);
let perps = getPerpendicularLine(x,y,x1,y1,x2,y2);
return d3.line()(perps);
})
.attr("stroke", mazeWallColor)
.attr("stroke-width", mazeWallWidth)
.attr("fill", mazeWallColor)
.style('opacity', .6)
)
let borders = container2.selectAll('.borders')
.data(borderEdges)
borders
.join(
enter => enter.append('path')
.classed("borders", true)
.attr("d", d => {
let x1 = x(d.x1);
let y1 = y(d.y1);
let x2 = x(d.x1);
let y2 = y(d.y1);
switch(d.side){
case "top":
x1 = x1 + x.bandwidth()/2;
x2 = x2 + x.bandwidth()/2 + x.bandwidth();
y1 = y1 + y.bandwidth()/2;
y2 = y2 + y.bandwidth()/2;
break;
case "bottom":
x1 = x1 + x.bandwidth()/2;
x2 = x2 + x.bandwidth()/2 + x.bandwidth();
y1 = y1 + y.bandwidth()/2 + y.bandwidth();
y2 = y2 + y.bandwidth()/2 + y.bandwidth();
break;
case "left":
x1 = x1 + x.bandwidth()/2;
y1 = y1 + y.bandwidth()/2;
x2 = x2 + x.bandwidth()/2;
y2 = y2 + y.bandwidth()/2 + y.bandwidth();
break;
case "right":
x1 = x1 + x.bandwidth()/2 + x.bandwidth();
y1 = y1 + y.bandwidth()/2;
x2 = x2 + x.bandwidth()/2 + x.bandwidth();
y2 = y2 + y.bandwidth()/2 + y.bandwidth();
break;
}
return d3.line()([[x1,y1],[x2,y2]])
})
.attr("stroke", d => d.type == "wall" ? mazeWallColor : (d.type == "exit" ? mazeExitColor : mazeEnterColor))
.attr("stroke-width", d => d.type == "wall" ? mazeWallWidth : 8)
)
// let rects = container.selectAll("rect")
// .data(graph.nodes)
// .join("rect")
// .style("opacity", 0)
// .transition()
// .duration(500)
// .delay((d,i) => i * 500)
// .attr('x', d => x(d.id%numCols) + x.bandwidth()/2)
// .attr('y', d => y(Math.floor(d.id/numCols)) + y.bandwidth()/2)
// .attr("width", x.bandwidth())
// .attr("height", y.bandwidth())
// .attr('fill', "red")
// .style('stroke', 'red')
// .style("stroke-opacity", 0)
// .style("opacity", 1);
}
let rightEdges = d3.range(numRows).map(d => {
return {x1: numCols-1, y1: d, x2: numCols-1, y2: d+1, side: "right", "type": "wall"};
})
let bottomEdges = d3.range(numRows).map(d => {
return {x1: d, y1: numCols-1, x2: d+1, y2: numCols-1, side: "bottom","type": "wall"};
})
let topEdges = d3.range(numRows).map(d => {
return {x1: d, y1: 0, x2: d+1, y2: 0, side: "top","type": "wall"};
})
let leftEdges = d3.range(numRows).map(d => {
return {x1: 0, y1: d, x2: 0, y2: d+1, side: "left","type": "wall"};
})
let borders = rightEdges.concat(bottomEdges,topEdges,leftEdges);
d3.shuffle(borders);
//random enter and exit spots
let enter = borders.pop();
let exit = borders.pop();
enter.type = "enter";
exit.type = "exit";
borders.push(enter);
borders.push(exit);
let maze = kruskalMaze();
let mazeEdgeIds = new Set(Array.from(maze).map(d => d.id));
//subtract maze path edges from the graph edges to get the walls
let diffIds = Array.from(graph.edges).filter(d => !(mazeEdgeIds.has(d.id)))
update(graph.nodes,maze,diffIds,borders);
yield svg.node();
}