This is a dramatically improved version of TOPOJSON points - OK Prisons. More presentation bells and whistles added. Plenty more to add. Some data (demographics) are random placeholder data. Latitudes and longitudes will be refined, and community work locations color will be corrected.
xxxxxxxxxx
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Oklahoma prisons</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script src="https://d3js.org/queue.v1.min.js"></script>
<script src="d3.v3.min.js"></script>
<script src="topojson.v1.min.js"></script>
<script src="queue.v1.min.js"></script>
<style type="text/css">
html {
font-family: Georgia, 'Times New Roman', Times, serif;
}
.state {
fill: #EEEFF1;
}
.county-border {
fill: none;
stroke: #919599;
}
.state-border {
fill: none;
stroke: #919599;
}
.prison {
fill-opacity: 0.75;
stroke-width: 1px;
stroke: #000;
}
#prisoninfo {
position: absolute;
max-width: 260px;
}
h3 {
-webkit-margin-before: 0em;
-webkit-margin-after: 0em;
margin-bottom: 0em;
padding-bottom: 0em;
}
li {
list-style: none;
}
.reference {
stroke: black;
}
</style>
</head>
<body>
<div id="prisoninfo"></div>
<script type="text/javascript">
var referencetime = 2500, referencedelay = 5000;
var width = 1000, height = 550;
//color by https://colorbrewer2.org
var minimum = "#DC2E1D", medium = "#9D2115", maximum = "#008837", community = "#A6DBA0", privateprison = "#C2A5CF";
var color = d3.scale.ordinal().domain([1, 2, 3, 4, 5]).range([maximum, maximum, maximum, community, privateprison]);
//https://www.ngs.noaa.gov/PUBS_LIB/ManualNOSNGS5.pdf
var projection = d3.geo.conicConformal().parallels([35 + 34 / 60, 36 + 46 / 60]).rotate([98 + 00 / 60, -35 - 00 / 60]).scale(6000).translate([width / 2, height / 2]);
var radius = d3.scale.sqrt().domain([0, 2526]).range([0, 16]);
var path = d3.geo.path().projection(projection);
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var div = d3.select("body").append("div").attr("id", "prisoninfo").style("opacity", 0);
var LYP = 45 * height / 100, LXP = 22 * width / 100;
//color title
svg.append("text").attr("class", "label").attr("x", LXP - 200).attr("y", LYP + 110).style("text-anchor", "start").style("font-weight", "bold").text("Prison Type");
//color legend
// svg.append("circle").attr("cx", LXP-175).attr("cy", LYP + 25 + 110).attr("r", 11).style("fill", minimum).attr("stroke", "#000");
// svg.append("text").attr("class", "label").attr("x", LXP-155).attr("y", LYP + 140).style("text-anchor", "start").text("Minimum");
svg.append("circle").attr("cx", LXP - 205).attr("cy", LYP + 25 + 110).attr("r", 11).style("fill", maximum).attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP - 185).attr("y", LYP + 140).style("text-anchor", "start").text("Institutional");
svg.append("circle").attr("cx", LXP-205).attr("cy", LYP + 50 + 110).attr("r", 11).style("fill", medium).attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP-185).attr("y", LYP + 165).style("text-anchor", "start").text("Community Work");
svg.append("circle").attr("cx", LXP - 205).attr("cy", LYP + 75 + 110).attr("r", 11).style("fill", community).attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP - 185).attr("y", LYP + 190).style("text-anchor", "start").text("Community Corrections");
svg.append("circle").attr("cx", LXP - 205).attr("cy", LYP + 100 + 110).attr("r", 11).style("fill", privateprison).attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP - 185).attr("y", LYP + 215).style("text-anchor", "start").text("Private");
//capacity title
svg.append("text").attr("class", "label").attr("x", LXP - 25).attr("y", LYP + 110).style("text-anchor", "start").style("font-weight", "bold").text("Capacity");
//capacity legend
svg.append("circle").attr("cx", LXP).attr("cy", LYP + 30 + 110).attr("r", 16.63).style("fill", "#EEEFF1").attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP + 25).attr("y", LYP + 140).style("text-anchor", "start").text("2,526");
svg.append("circle").attr("cx", LXP).attr("cy", LYP + 55 + 110).attr("r", 12.78).style("fill", "#EEEFF1").attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP + 25).attr("y", LYP + 165).style("text-anchor", "start").text("1,756+");
svg.append("circle").attr("cx", LXP).attr("cy", LYP + 76 + 110).attr("r", 8.93).style("fill", "#EEEFF1").attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP + 25).attr("y", LYP + 187).style("text-anchor", "start").text("786+");
svg.append("circle").attr("cx", LXP).attr("cy", LYP + 91 + 110).attr("r", 5.06).style("fill", "#EEEFF1").attr("stroke", "#000");
svg.append("text").attr("class", "label").attr("x", LXP + 25).attr("y", LYP + 208).style("text-anchor", "start").text("216+");
queue().defer(d3.json, "ok-counties2.json").defer(d3.json, "corrections.json").await(ready);
function ready(error, ok, corrections) {
//state
svg.append("path").attr("class", "state").datum(topojson.feature(ok, ok.objects.counties)).attr("d", path);
//county border
svg.append("path").attr("class", "county-border").datum(topojson.mesh(ok, ok.objects.counties, function(a, b) {
return a !== b;
})).attr("d", path);
//state border
svg.append("path").attr("class", "state-border").datum(topojson.mesh(ok, ok.objects.counties, function(a, b) {
return a === b;
})).attr("d", path);
//corrections data
var corrections = topojson.feature(corrections, corrections.objects.corrections);
//prisons
svg.selectAll(".prison").data(corrections.features.sort(function(a, b) {
return b.properties.opened - a.properties.opened;
})).enter().append("path").attr("class", "prison").attr("d", path.pointRadius(3))
//mouseover
.on("mouseover", function(d) {
div.transition().duration(1500).style("opacity", .9);
div.html("<h3>" + d.properties.name + "</h3><ul><li>Security level: " + d.properties.level + "</li><li>Capacity: " + d.properties.capacity + "</li><li>Gender: " + d.properties.gender + "</li><li>Opened: " + d.properties.opened + "</li><li>Inmate demographics: <ul><li>Black: " + d.properties.black + "%</li><li>Hispanic: " + d.properties.hispanic + "%</li><li>White: " + d.properties.white + "%</li></ul></li></ul>").style("left", 20 + "px").style("top", 92 + "px")
d3.select(this).select("path").transition().duration(1000).attr("d", path.pointRadius(30));
})
//click for touch devices
.on("click", function(d) {
div.transition().duration(1500).style("opacity", .9);
div.html("<h3>" + d.properties.name + "</h3><ul><li>Security level: " + d.properties.level + "</li><li>Capacity: " + d.properties.capacity + "</li><li>Gender: " + d.properties.gender + "</li><li>Opened: " + d.properties.opened + "</li><li>Inmate demographics: <ul><li>Black: " + d.properties.black + "%</li><li>Hispanic: " + d.properties.hispanic + "%</li><li>White: " + d.properties.white + "%</li></ul></li></ul>").style("left", 20 + "px").style("top", 92 + "px")
})
//transition animation to capacity size
.transition().duration(1500).delay(function(d, i) {
return i * 100;
}).attr("d", path.pointRadius(function(d) {
return 5 + radius(d.properties.capacity);
})).style("fill", function(d) {
return color(d.properties.levelno);
});
//lexington and joseph harp
svg.append("line").attr("class", "reference").attr("x1", "470").attr("y1", "450").attr("x2", "580").attr("y2", "270").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
svg.append("text").attr("class", "label").attr("x", "470").attr("y", "460").style("text-anchor", "middle").text("(top) Lexington A & R").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
svg.append("text").attr("class", "label").attr("x", "470").attr("y", "480").style("text-anchor", "middle").text("(bottom) Joseph Harp").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
//osp and joseph harp
svg.append("line").attr("class", "reference").attr("x1", "690").attr("y1", "500").attr("x2", "731").attr("y2", "274").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
svg.append("text").attr("class", "label").attr("x", "690").attr("y", "515").style("text-anchor", "middle").text("(top) Oklahoma State Penitentiary").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
svg.append("text").attr("class", "label").attr("x", "690").attr("y", "535").style("text-anchor", "middle").text("(bottom) Jackie Brannon").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
//jess dunn and eddie warrior
svg.append("line").attr("class", "reference").attr("x1", "800").attr("y1", "450").attr("x2", "748").attr("y2", "169").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
svg.append("text").attr("class", "label").attr("x", "800").attr("y", "460").style("text-anchor", "middle").text("(top) Jess Dunn").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
svg.append("text").attr("class", "label").attr("x", "800").attr("y", "480").style("text-anchor", "middle").text("(bottom) Dr. Eddie Warrior").style("opacity", 0).transition().duration(referencetime).delay(referencedelay).style("opacity", .9);
}
</script>
Modified http://d3js.org/d3.v3.min.js to a secure url
Modified http://d3js.org/topojson.v1.min.js to a secure url
Modified http://d3js.org/queue.v1.min.js to a secure url
https://d3js.org/d3.v3.min.js
https://d3js.org/topojson.v1.min.js
https://d3js.org/queue.v1.min.js