geo2square = {
let width = 960;
let height = 480;
let squareSize = 50;
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr('id', 'mapArea');
let bg = svg
.append('rect')
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr('fill', '#000');
let mapGroup = svg.append("g").attr("id", "map");
var projection = d3
.geoMercator()
.fitExtent([[0, 0], [width / 2, height]], areas);
var path = d3.geoPath().projection(projection);
//function to convert svg pixel coordinates to rectangle drawing instructions
var line = d3
.line()
.x(function(d) {
return d[0];
})
.y(function(d) {
return d[1];
});
//convert area of shapes to 0-1 range, and therefore colors
let areaScale = d3
.scaleLinear()
.domain(
d3.extent(areas.features, d => parseFloat(d.properties.area_numbe))
);
//operate on each geography
for (let i = 0; i < areas.features.length; i++) {
let area = areas.features[i];
//project coordinates to pixels
let projected = area.geometry.coordinates[0][0].map(projection);
//store drawing instruction for the geographic shape
area.properties.geoPath = path(area);
//store drawing instruction for the rectangular shape
area.properties.squarePath = line(
d3.geo2square(projected, squareSize, squareSize)
);
//store the left coordinate of the generated square
area.properties.squareX = d3.geo2square(
projected,
squareSize,
squareSize
)[0][0];
//store the top coordinate of the generated square
area.properties.squareY = d3.geo2square(
projected,
squareSize,
squareSize
)[0][1];
//use the community area number integer divided by 10 as a fake category
area.properties.category = Math.floor(
parseInt(area.properties.area_numbe) / 10
);
}
//we start in geography mode
let toggle = 0;
//draw shapes
mapGroup
.selectAll('.areas')
.data(areas.features)
.enter()
.append('path')
.attr('class', 'areas')
.attr('d', d => d.properties.geoPath)
.attr('opacity',1)
.attr('fill', d =>
d3.interpolateWarm(areaScale(parseFloat(d.properties.area_numbe)))
)
//when clicked....
.on('click', function(d) {
//check if we're in geography mode
if (toggle == 0) {
//if so, transform to square mode
d3.selectAll('.areas')
.data(areas.features)
//transition to transform, recolor, and slide the squares over
.transition()
.duration(1000)
.attr('opacity', function(e){
if (e.properties.area_numbe == 1){return 0}else{return 1}
})
.transition()
.duration(1000)
.attr('fill', d =>
d3.interpolateCool(areaScale(parseFloat(d.properties.area_numbe)))
)
//switch to square paths
.attr('d', function(e){
if (e.properties.area_numbe == 1){return d.properties.geoPath}else{return d.properties.squarePath}
})
//use category and transform to place square on the right half of the artboard
.attr(
'transform',
e =>
'translate(' +
(width / 2 +
(e.properties.category * squareSize - e.properties.squareX)) +
',0)'
)
//trigger a second transition to slide the squares to the vertical center
.transition()
.duration(1000)
//slide to the vertical centerline
.attr(
'transform',
e =>
'translate(' +
(width / 2 +
(e.properties.category * squareSize - e.properties.squareX)) +
',' +
(height / 2 - squareSize / 2 - e.properties.squareY) +
")"
);
//now we're in square mode!
toggle = 1;
} else {
//undo the transformations back to geography mode
mapGroup
.selectAll('.areas')
.data(areas.features)
.transition()
.duration(1500)
.attr('fill', d =>
d3.interpolateCool(areaScale(parseFloat(d.properties.area_numbe)))
)
.attr('d', d => d.properties.geoPath)
.attr('fill', d =>
d3.interpolateWarm(areaScale(parseFloat(d.properties.area_numbe)))
)
.attr('transform', "");
//now we're in geography mode again
toggle = 0;
}
});
return svg.node();
}