block by emeeks 5218414

Constrained Voronoi with Derived Areas

Full Screen

index.html


<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  <script type="text/javascript" src="//d3js.org/d3.v2.min.js"></script>
    <style type="text/css">
        circle {
            stroke: #EFEDF5;
            fill: #EFEDF5;
        }
        line {
            stroke: #EFEDF5;
            pointer-events: none
        }
        path{
            stroke: black
        }
    </style>
</head>
<body>
<select id="colorSelect" onchange="setColor('menu')">
  <option value="density">Density</option>
  <option value="equity">Equity</option>
  <option value="area">Area</option>
  <option value="statecode">State</option>
    <option value="green">Green</option>
  <option value="unpaved">Unpaved</option>
</select>
<div id="chart">
</div>
<script type="text/javascript">

statesKey = {"AZ": 9,"CA": 9,"CO": 8,"DC": 3,"FL": 4,"GA": 4,"IL": 5,"MA": 1,"MI": 5,"NC": 4,"NM": 6,"NV": 9,"NY": 2,"OH": 5,"OR": 10,"PA": 3,"TN": 4,"TX": 6,"VA": 3,"WA": 10,"WI": 5};

    w = 960,
        h = 960,
        links = [],
        voronoiVertices = [],
        color = d3.scale.quantize().domain([7000, 10000]).range(d3.range(2, 9));


    var numVertices = 50;
//    vertices = d3.range(numVertices).map(function(d) { return {x: d.x, y: d.y}; })

	d3.json("neighborhoods.json", function(json) {

/* vertices = [{x: 0, y: 1, narea: 10}, {x: 100, y: 100, narea: 10}, {x: 0, y: 100, narea: 100}, {x: 100, y: 0, narea: 500}, {x: 0, y: 1, narea: 500}, {x: 100, y: 100, narea: 10}, {x: 0, y: 100, narea: 10}, {x: 100, y: 0, narea: 10},
    {x: 0, y: 1, narea: 10}, {x: 100, y: 100, narea: 10}, {x: 0, y: 100, narea: 100}, {x: 100, y: 0, narea: 500}, {x: 0, y: 1, narea: 500}, {x: 100, y: 100, narea: 10}, {x: 0, y: 100, narea: 10}, {x: 100, y: 0, narea: 10},
    {x: 0, y: 1, narea: 10}, {x: 100, y: 100, narea: 10}, {x: 0, y: 100, narea: 100}, {x: 100, y: 0, narea: 500}, {x: 0, y: 1, narea: 500}, {x: 100, y: 100, narea: 10}, {x: 0, y: 100, narea: 10}, {x: 100, y: 0, narea: 10}
    ]
    */
    vertices = json;

    sizeMin = d3.min(vertices, function (d) { return d["area"];});
    sizeMax = d3.max(vertices, function (d) { return d["area"];});
	sizeMed = (sizeMin + sizeMax ) / 2;    
    var prevEventScale = 1;

    
    xMin = d3.min(vertices, function (d) { return d["x"];});
    xMax = d3.max(vertices, function (d) { return d["x"];});

    yMin = d3.min(vertices, function (d) { return d["y"];});
    yMax = d3.max(vertices, function (d) { return d["y"];});
	
    sizeRamp = d3.scale.linear().domain([sizeMin,sizeMed,sizeMax]).range([-50,-250,-1000]);

    xRamp = d3.scale.linear().domain([xMin,xMax]).range([225,700]).clamp(true)
    yRamp = d3.scale.linear().domain([yMin,yMax]).range([700,225]).clamp(true)
    
    for ( n in vertices) {
        vertices[n]["x"] = xRamp(vertices[n]["x"]);
        vertices[n]["y"] = yRamp(vertices[n]["y"]);
        vertices[n]["statecode"] = statesKey[vertices[n]["state"]];
    }
/*    var zoom = d3.behavior.zoom().on("zoom", function(d,i) {
        if (d3.event.scale > prevEventScale) {
            vertices.push(function(d) { return {x: d.x, y: d.y}; })
        } else if (vertices.length > 2) {
            vertices.pop();
        }
        force.nodes(vertices).start()
        prevEventScale = d3.event.scale;
    });
*/

    var svg = d3.select("#chart")
            .append("svg")
            .attr("width", w)
            .attr("height", h)
            .attr("class", "Purples")
//            .call(zoom)

	circleClip = svg.append("svg:clipPath").attr("id", "clipper").append("circle").attr("cx", w / 2).attr("cy", h / 2).attr("r", 325);

    force = self.force = d3.layout.force()
            .charge(function (d, i) { return sizeRamp(vertices[i].area)})
            .size([w, h])
            .on("tick", update);

    force.nodes(vertices).start();

    circle = svg.selectAll("g.nodes");
    path = svg.selectAll("path");
    link = svg.selectAll("line");
	})
	
    function update(e) {
        voronoiVertices = vertices.map(function(o){return [o.x,  o.y, o]})

        path = path.data(d3.geom.voronoi(voronoiVertices))
        path.enter().append("path") //group all the path elements first so they have the lowest z-order
            .attr("class", function(d, i) { return "q"+color(d3.geom.polygon(d).area())+"-9"; })
            .attr("d", function(d) { return "M" + d.join("L") + "Z"; })
            .attr("clip-path", "url(#clipper)")
	        .style("stroke", "white")
	        .style("stroke-width", 3)
        path.attr("class", function(d, i) { return "q"+color(d3.geom.polygon(d).area())+"-9"; })
            .attr("d", function(d) { return "M" + d.join("L") + "Z"; })
            .attr("clip-path", "url(#clipper)")
        path.exit().remove();

        
        circle = circle.data(vertices)
        circleEnter = circle.enter().append("g")
              .call(force.drag)
              .attr("class", "nodes")
              .attr("r", 0)
              .attr("transform", function (d) { return "translate("+d.x+","+d.y+")"});
        
//              .attr("cy", function(d) { return d.y; })
		circleEnter.append("circle")
              .transition().duration(1000).attr("r", 5);
		text1 = circleEnter.append("text")
		.attr("opacity", 0)
		.style("fill", "white")
		.style("stroke", "white")
		.style("stroke-width", "3")
		.text(function (d,i) {return vertices[i].name})
        .transition().duration(1000).attr("opacity", .75);
		text2 = circleEnter.append("text")
		.attr("opacity", 0)
		.style("fill", "black")
		.text(function (d,i) {return vertices[i].name})
        .transition().duration(1000).attr("opacity", 1);

		
        circle.attr("transform", function (d) { return "translate("+d.x+","+d.y+")"});
        circle.exit().transition().attr("opacity", 0).remove();

        links = []
        d3.geom.delaunay(voronoiVertices).forEach(function(d) {
            links.push(edge(d[0], d[1]));
            links.push(edge(d[1], d[2]));
            links.push(edge(d[2], d[0]));
        });

        link = link.data(links)
        link.enter().append("line")
        link.attr("x1", function(d) { return d.source[2].x; })
            .attr("y1", function(d) { return d.source[2].y; })
            .attr("x2", function(d) { return d.target[2].x; })
            .attr("y2", function(d) { return d.target[2].y; })
            .style("stroke", "none")

        link.exit().remove()

        circleClip.attr("r", function() { return d3.max(vertices, function (d) { return d["x"] - (w / 2) + (w / 20);}) } );
    }

    function edge(a, b) {
        return {
            source: a,
            target: b
        };
    
    }

    function setColor(inputString) {
        if (inputString == "menu") {
	    	inputString = document.getElementById("colorSelect").value;
        }
        colorMin = d3.min(vertices, function (d) { return d[inputString];});
        colorMax = d3.max(vertices, function (d) { return d[inputString];});
    	colorMed = (colorMin + colorMax ) / 2;    
//        colorRamp = d3.scale.linear().domain([colorMin,colorMed,colorMax]).range(["blue","yellow","red"]);
        colorRamp = d3.scale.linear().domain([1,100,400]).range(["green","yellow","purple"]);
        
        path.style("fill", function(d, i) { return colorRamp(vertices[i][inputString])})
        text1.text(function (d,i) {return vertices[i][inputString]})
        text2.text(function (d,i) {return vertices[i][inputString]})
    }
</script>
</body>
</html>