Skip to content

Instantly share code, notes, and snippets.

@earthbound19
Forked from christopherlovell/mondrian.html
Created May 9, 2018 23:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save earthbound19/7f6c7887f508cb8e2eb24ea67074dd4d to your computer and use it in GitHub Desktop.
Save earthbound19/7f6c7887f508cb8e2eb24ea67074dd4d to your computer and use it in GitHub Desktop.
D3 Mondrian Generator
<!DOCTYPE html>
<html lang="en">
<head>
<title>Mondrian Generator</title>
<script src="https://d3js.org/d3.v4.js" charset="utf-8"></script>
<style>
</style>
</head>
<body>
<script>
var w = 500;
var h = 360;
var padding = 30;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("style", "outline: thick solid black;");
var colours = ['red', 'blue', 'yellow', 'white', 'black']
var colour_prob = [0.125, 0.125, 0.125, 0.5, 0.125] // probability of appearance of each colour
// cumulative colour probabilities
var colour_cum_prob = [];
colour_prob.reduce(function(a,b,i) { return colour_cum_prob[i] = a+b; },0);
var fractions = [1/5, 2/5, 3/5, 4/5] // hard coded split fractions
var tol = 100; // height/width tolerance on which to split
var recurs = 7; // level of recursion
function update(){
// initialise array of rectangles with a single, giant rectangle (..square)
var rectangles = [{"x": 0, "y": 0, "width": w, "height": h}]
// console.log("rect start", JSON.stringify(rectangles));
var j = 0; // recursion counter
while(j < recurs){
j++;
n = rectangles.length; // number of initial rectangles in this loop
to_remove = []; // array of indices of rectangles to remove
// loop through existing rectangles
for(var i=0; i<n; i++){
// test if rectangle already small
if(rectangles[i]['width'] > tol && rectangles[i]['height'] > tol){
to_remove.push(i); // save for removal later
// calculate split fraction
var frac = fractions[Math.floor(Math.random() * fractions.length)];
var x = rectangles[i]['x'];
var y = rectangles[i]['y'];
// decide whether to cut vertically or horizontally
if(Math.random() > 0.5) {
var width = rectangles[i]['width'] * frac;
var height = rectangles[i]['height'];
rectangles.push({"x": x + width, "y": y, "width": rectangles[i]['width'] - width, height});
}
else {
var width = rectangles[i]['width'];
var height = rectangles[i]['height'] * frac;
rectangles.push({"x": x, "y": y + height, "width": width, "height": rectangles[i]['height'] - height});
}
rectangles.push({"x": x, "y": y, "width": width, "height": height});
}
}
// remove old rectangles (loop in reverse order to avoid messing up indexing)
for(var i=to_remove.length-1; i>=0; i--){
rectangles.splice(to_remove[i], 1);
}
}
for(i=0; i < rectangles.length; i++){
var condition = Math.random()
colourIndex = colour_cum_prob.findIndex( function(elem) {return elem > condition} );
svg.append("rect")
.attr("x", rectangles[i]['x'] )
.attr("y", rectangles[i]['y'] )
.attr("width", rectangles[i]['width'] )
.attr("height", rectangles[i]['height'] )
.attr("fill", colours[colourIndex])
.attr("stroke-width", 6)
.attr("stroke", "black");
}
}
update();
/*
To Do:
- choose colour scheme (drop down list)
- choose recursion level
- resize box
- animate on refresh
*/
</script>
<div id="option">
<input name="updateButton"
type="button"
value="Update"
onclick="update()" />
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment