A grid of London constituencies with the geographical representation of each constituency resized to fit within the same rectangular area. Hover over areas for the constituency name.
forked from tlfrd's block: London Constituency Grid Layout
license: mit | |
height: 500 |
A grid of London constituencies with the geographical representation of each constituency resized to fit within the same rectangular area. Hover over areas for the constituency name.
forked from tlfrd's block: London Constituency Grid Layout
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://d3js.org/topojson.v2.min.js"></script> | |
<script src="london-grid.js"></script> | |
<style> | |
body { | |
margin: 0; | |
} | |
.constituency { | |
fill: white; | |
stroke: black; | |
} | |
.hover-rect { | |
opacity: 0; | |
} | |
div.tooltip { | |
position: absolute; | |
text-align: center; | |
padding: 5px; | |
font: 12px monospace; | |
background-color: cyan; | |
border: 1px black solid; | |
pointer-events: none; | |
width: 80px; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var cfg = { | |
gridLength: 11, | |
gridHeight: 10, | |
padding: 6 | |
} | |
var margin = {top: 50, right: 200, bottom: 50, left: 200}; | |
var width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var rectWidth = (width / cfg.gridLength) - cfg.padding, | |
rectHeight = (height / cfg.gridHeight) - cfg.padding; | |
var url = "topo_wpc_london.json"; | |
function calculateCoords(d) { | |
var x = d.x * (rectWidth + cfg.padding); | |
var y = d.y * (rectHeight + cfg.padding); | |
return [x, y]; | |
} | |
var londonGridLookup = {}; | |
londonGrid.forEach(function(d) { | |
londonGridLookup[d.ons_code] = d; | |
}); | |
var constituencies = svg.append("g").attr("class", "constituencies"); | |
var div = d3.select("body").append("div") | |
.attr("class", "tooltip") | |
.style("opacity", 0); | |
d3.json(url, function(topoLondon) { | |
var geoLondon = topojson.feature(topoLondon, topoLondon.objects.wpc).features; | |
constituencies.selectAll(".constituency") | |
.data(geoLondon) | |
.enter().append("path") | |
.attr("class", "constituency") | |
.attr("d", d => localProjection(d, londonGridLookup[d.id].position)) | |
constituencies.selectAll("rect") | |
.data(geoLondon) | |
.enter().append("rect") | |
.attr("class", "hover-rect") | |
.attr("x", d => calculateCoords(londonGridLookup[d.id].position)[0]) | |
.attr("y", d => calculateCoords(londonGridLookup[d.id].position)[1]) | |
.attr("width", rectWidth) | |
.attr("height", rectHeight) | |
.on("mouseover", showLabel) | |
.on("mouseout", hideLabel); | |
}); | |
function localProjection(geometry, position) { | |
var centroid = d3.geoPath().centroid(geometry); | |
var topLeftCorner = calculateCoords(position), | |
topRightCorner = [calculateCoords(position)[0] + rectWidth, calculateCoords(position)[1] + rectHeight]; | |
var projection = d3.geoAlbers() | |
.center(centroid) | |
.rotate([0, 0]) | |
.fitExtent([topLeftCorner, topRightCorner], geometry); | |
var path = d3.geoPath() | |
.projection(projection); | |
return path(geometry); | |
} | |
function showLabel(d) { | |
var left = calculateCoords(londonGridLookup[d.id].position)[0] - rectWidth / 2, | |
right = calculateCoords(londonGridLookup[d.id].position)[1] - rectHeight ; | |
div.transition() | |
.duration(200) | |
.style("opacity", 0.8) | |
div.html(d.properties.PCON13NM) | |
.style("left", (left + margin.left) + "px") | |
.style("top", (right + margin.top) + "px") | |
} | |
function hideLabel() { | |
div.transition() | |
.duration(200) | |
.style("opacity", 0); | |
} | |
</script> | |
</body> |
var londonGrid = [ | |
{ | |
"ons_code": "E14000692", | |
"name": "Enfield Southgate", | |
"position": { | |
"x": 5, | |
"y": 0 | |
} | |
}, | |
{ | |
"ons_code": "E14000691", | |
"name": "Enfield North", | |
"position": { | |
"x": 6, | |
"y": 0 | |
} | |
}, | |
{ | |
"ons_code": "E14000731", | |
"name": "Harrow East", | |
"position": { | |
"x": 2, | |
"y": 1 | |
} | |
}, | |
{ | |
"ons_code": "E14000741", | |
"name": "Hendon", | |
"position": { | |
"x": 3, | |
"y": 1 | |
} | |
}, | |
{ | |
"ons_code": "E14000636", | |
"name": "Chipping Barnet", | |
"position": { | |
"x": 4, | |
"y": 1 | |
} | |
}, | |
{ | |
"ons_code": "E14000752", | |
"name": "Hornsey & Wood Green", | |
"position": { | |
"x": 5, | |
"y": 1 | |
} | |
}, | |
{ | |
"ons_code": "E14000687", | |
"name": "Edmonton", | |
"position": { | |
"x": 6, | |
"y": 1 | |
} | |
}, | |
{ | |
"ons_code": "E14000634", | |
"name": "Chingford & Woodford Green", | |
"position": { | |
"x": 7, | |
"y": 1 | |
} | |
}, | |
{ | |
"ons_code": "E14000906", | |
"name": "Ruislip, Northwood & Pinner", | |
"position": { | |
"x": 0, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000732", | |
"name": "Harrow West", | |
"position": { | |
"x": 1, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000592", | |
"name": "Brent North", | |
"position": { | |
"x": 2, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000727", | |
"name": "Hampstead & Kilburn", | |
"position": { | |
"x": 3, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000703", | |
"name": "Finchley & Golders Green", | |
"position": { | |
"x": 4, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000763", | |
"name": "Islington North", | |
"position": { | |
"x": 5, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14001002", | |
"name": "Tottenham", | |
"position": { | |
"x": 6, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14001013", | |
"name": "Walthamstow", | |
"position": { | |
"x": 7, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000759", | |
"name": "Ilford North", | |
"position": { | |
"x": 8, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000900", | |
"name": "Romford", | |
"position": { | |
"x": 9, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14000751", | |
"name": "Hornchurch & Upminster", | |
"position": { | |
"x": 10, | |
"y": 2 | |
} | |
}, | |
{ | |
"ons_code": "E14001007", | |
"name": "Uxbridge & Ruislip South", | |
"position": { | |
"x": 0, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000675", | |
"name": "Ealing North", | |
"position": { | |
"x": 1, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000591", | |
"name": "Brent Central", | |
"position": { | |
"x": 2, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000768", | |
"name": "Kensington", | |
"position": { | |
"x": 3, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000750", | |
"name": "Holborn & St Pancras", | |
"position": { | |
"x": 4, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000764", | |
"name": "Islington South & Finsbury", | |
"position": { | |
"x": 5, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000720", | |
"name": "Hackney North & Stoke Newington", | |
"position": { | |
"x": 6, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14001032", | |
"name": "West Ham", | |
"position": { | |
"x": 7, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000790", | |
"name": "Leyton & Wanstead", | |
"position": { | |
"x": 8, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000760", | |
"name": "Ilford South", | |
"position": { | |
"x": 9, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000657", | |
"name": "Dagenham & Rainham", | |
"position": { | |
"x": 10, | |
"y": 3 | |
} | |
}, | |
{ | |
"ons_code": "E14000737", | |
"name": "Hayes & Harlington", | |
"position": { | |
"x": 0, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000676", | |
"name": "Ealing Southall", | |
"position": { | |
"x": 1, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000674", | |
"name": "Ealing Central & Acton", | |
"position": { | |
"x": 2, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000629", | |
"name": "Chelsea & Fulham", | |
"position": { | |
"x": 3, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14001036", | |
"name": "Westminster North", | |
"position": { | |
"x": 4, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000553", | |
"name": "Bermondsey & Old Southwark", | |
"position": { | |
"x": 5, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000721", | |
"name": "Hackney South & Shoreditch", | |
"position": { | |
"x": 6, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000882", | |
"name": "Poplar & Limehouse", | |
"position": { | |
"x": 7, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000679", | |
"name": "East Ham", | |
"position": { | |
"x": 8, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000540", | |
"name": "Barking", | |
"position": { | |
"x": 9, | |
"y": 4 | |
} | |
}, | |
{ | |
"ons_code": "E14000701", | |
"name": "Feltham & Heston", | |
"position": { | |
"x": 0, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000593", | |
"name": "Brentford & Isleworth", | |
"position": { | |
"x": 1, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000726", | |
"name": "Hammersmith", | |
"position": { | |
"x": 2, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000887", | |
"name": "Putney", | |
"position": { | |
"x": 3, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000639", | |
"name": "Cities of London & Westminster", | |
"position": { | |
"x": 4, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14001008", | |
"name": "Vauxhall", | |
"position": { | |
"x": 5, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000555", | |
"name": "Bethnal Green & Bow", | |
"position": { | |
"x": 6, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000718", | |
"name": "Greenwich & Woolwich", | |
"position": { | |
"x": 7, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000696", | |
"name": "Erith & Thamesmead", | |
"position": { | |
"x": 8, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14000558", | |
"name": "Bexleyheath & Crayford", | |
"position": { | |
"x": 9, | |
"y": 5 | |
} | |
}, | |
{ | |
"ons_code": "E14001005", | |
"name": "Twickenham", | |
"position": { | |
"x": 1, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000896", | |
"name": "Richmond Park", | |
"position": { | |
"x": 2, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000998", | |
"name": "Tooting", | |
"position": { | |
"x": 3, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000549", | |
"name": "Battersea", | |
"position": { | |
"x": 4, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000673", | |
"name": "Dulwich & West Norwood", | |
"position": { | |
"x": 5, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000615", | |
"name": "Camberwell & Peckham", | |
"position": { | |
"x": 6, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000789", | |
"name": "Lewisham Deptford", | |
"position": { | |
"x": 7, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000690", | |
"name": "Eltham", | |
"position": { | |
"x": 8, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000869", | |
"name": "Old Bexley & Sidcup", | |
"position": { | |
"x": 9, | |
"y": 6 | |
} | |
}, | |
{ | |
"ons_code": "E14000770", | |
"name": "Kingston & Surbiton", | |
"position": { | |
"x": 1, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14001040", | |
"name": "Wimbledon", | |
"position": { | |
"x": 2, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14000823", | |
"name": "Mitcham & Morden", | |
"position": { | |
"x": 3, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14000978", | |
"name": "Streatham", | |
"position": { | |
"x": 4, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14000788", | |
"name": "Lewisham West & Penge", | |
"position": { | |
"x": 5, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14000787", | |
"name": "Lewisham East", | |
"position": { | |
"x": 6, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14000604", | |
"name": "Bromley & Chislehurst", | |
"position": { | |
"x": 7, | |
"y": 7 | |
} | |
}, | |
{ | |
"ons_code": "E14000984", | |
"name": "Sutton & Cheam", | |
"position": { | |
"x": 2, | |
"y": 8 | |
} | |
}, | |
{ | |
"ons_code": "E14000621", | |
"name": "Carshalton & Wallington", | |
"position": { | |
"x": 3, | |
"y": 8 | |
} | |
}, | |
{ | |
"ons_code": "E14000655", | |
"name": "Croydon North", | |
"position": { | |
"x": 4, | |
"y": 8 | |
} | |
}, | |
{ | |
"ons_code": "E14000654", | |
"name": "Croydon Central", | |
"position": { | |
"x": 5, | |
"y": 8 | |
} | |
}, | |
{ | |
"ons_code": "E14000551", | |
"name": "Beckenham", | |
"position": { | |
"x": 6, | |
"y": 8 | |
} | |
}, | |
{ | |
"ons_code": "E14000872", | |
"name": "Orpington", | |
"position": { | |
"x": 7, | |
"y": 8 | |
} | |
}, | |
{ | |
"ons_code": "E14000656", | |
"name": "Croydon South", | |
"position": { | |
"x": 4, | |
"y": 9 | |
} | |
} | |
] |