Skip to content

Instantly share code, notes, and snippets.

@leonardobareno
Last active November 27, 2017 23:47
Show Gist options
  • Save leonardobareno/3f42ff75b1a9aea5b845351c7e6be6df to your computer and use it in GitHub Desktop.
Save leonardobareno/3f42ff75b1a9aea5b845351c7e6be6df to your computer and use it in GitHub Desktop.
GeoJSON Bogota
license: mit
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
@import url(http://fonts.googleapis.com/css?family=Open+Sans+Condensed:300|Josefin+Slab|Arvo|Lato|Vollkorn|Abril+Fatface|Old+Standard+TT|Droid+Sans|Lobster|Inconsolata|Montserrat|Playfair+Display|Karla|Alegreya|Libre+Baskerville|Merriweather|Lora|Archivo+Narrow|Neuton|Signika|Questrial|Fjalla+One|Bitter|Varela+Round);
.background {
fill: #eee;
pointer-events: all;
}
.map-layer {
fill: #fff;
stroke: #aaa;
}
.effect-layer{
pointer-events:none;
}
text{
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 300;
}
text.big-text{
font-size: 30px;
font-weight: 400;
}
.effect-layer text, text.dummy-text{
font-size: 12px;
}
</style>
<body>
<svg></svg>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
centered;
// Define color scale
var color = d3.scale.linear()
.domain([1, 20])
.clamp(true)
.range(['#fff', '#409A99']);
var projection = d3.geo.mercator()
.scale(75000)
// Customize the projection to make the center of Thailand become the center of the map
.rotate([74.0712581087617,-4.61742011111319])
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
// Set svg width & height
var svg = d3.select('svg')
.attr('width', width)
.attr('height', height);
// Add background
svg.append('rect')
.attr('class', 'background')
.attr('width', width)
.attr('height', height)
.on('click', clicked);
var g = svg.append('g');
var effectLayer = g.append('g')
.classed('effect-layer', true);
var mapLayer = g.append('g')
.classed('map-layer', true);
var dummyText = g.append('text')
.classed('dummy-text', true)
.attr('x', 10)
.attr('y', 30)
.style('opacity', 0);
var bigText = g.append('text')
.classed('big-text', true)
.attr('x', 20)
.attr('y', 45);
// Load map data
d3.json('bogota.json', function(error, mapData) {
var features = mapData.features;
// Update color scale domain based on data
color.domain([0, d3.max(features, nameLength)]);
// Draw each province as a path
mapLayer.selectAll('path')
.data(features)
.enter().append('path')
.attr('d', path)
.attr('vector-effect', 'non-scaling-stroke')
.style('fill', fillFn)
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', clicked);
});
// Get province name
function nameFn(d){
return d && d.properties ? d.properties.LOC : null;
}
// Get province name length
function nameLength(d){
var n = nameFn(d);
return n ? n.length : 0;
}
// Get province color
function fillFn(d){
return color(nameLength(d));
}
// When clicked, zoom in
function clicked(d) {
var x, y, k;
// Compute centroid of the selected path
if (d && centered !== d) {
var centroid = path.centroid(d);
x = centroid[0];
y = centroid[1];
k = 4;
centered = d;
} else {
x = width / 2;
y = height / 2;
k = 1;
centered = null;
}
// Highlight the clicked province
mapLayer.selectAll('path')
.style('fill', function(d){return centered && d===centered ? '#D5708B' : fillFn(d);});
// Zoom
g.transition()
.duration(750)
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')');
}
function mouseover(d){
// Highlight hovered province
d3.select(this).style('fill', 'orange');
// Draw effects
textArt(nameFn(d));
}
function mouseout(d){
// Reset province color
mapLayer.selectAll('path')
.style('fill', function(d){return centered && d===centered ? '#D5708B' : fillFn(d);});
// Remove effect text
effectLayer.selectAll('text').transition()
.style('opacity', 0)
.remove();
// Clear province name
bigText.text('');
}
// Gimmick
// Just me playing around.
// You won't need this for a regular map.
var BASE_FONT = "'Helvetica Neue', Helvetica, Arial, sans-serif";
var FONTS = [
"Open Sans",
"Josefin Slab",
"Arvo",
"Lato",
"Vollkorn",
"Abril Fatface",
"Old StandardTT",
"Droid+Sans",
"Lobster",
"Inconsolata",
"Montserrat",
"Playfair Display",
"Karla",
"Alegreya",
"Libre Baskerville",
"Merriweather",
"Lora",
"Archivo Narrow",
"Neuton",
"Signika",
"Questrial",
"Fjalla One",
"Bitter",
"Varela Round"
];
function textArt(text){
// Use random font
var fontIndex = Math.round(Math.random() * FONTS.length);
var fontFamily = FONTS[fontIndex] + ', ' + BASE_FONT;
bigText
.style('font-family', fontFamily)
.text(text);
// Use dummy text to compute actual width of the text
// getBBox() will return bounding box
dummyText
.style('font-family', fontFamily)
.text(text);
var bbox = dummyText.node().getBBox();
var textWidth = bbox.width;
var textHeight = bbox.height;
var xGap = 3;
var yGap = 1;
// Generate the positions of the text in the background
var xPtr = 0;
var yPtr = 0;
var positions = [];
var rowCount = 0;
while(yPtr < height){
while(xPtr < width){
var point = {
text: text,
index: positions.length,
x: xPtr,
y: yPtr
};
var dx = point.x - width/2 + textWidth/2;
var dy = point.y - height/2;
point.distance = dx*dx + dy*dy;
positions.push(point);
xPtr += textWidth + xGap;
}
rowCount++;
xPtr = rowCount%2===0 ? 0 : -textWidth/2;
xPtr += Math.random() * 10;
yPtr += textHeight + yGap;
}
var selection = effectLayer.selectAll('text')
.data(positions, function(d){return d.text+'/'+d.index;});
// Clear old ones
selection.exit().transition()
.style('opacity', 0)
.remove();
// Create text but set opacity to 0
selection.enter().append('text')
.text(function(d){return d.text;})
.attr('x', function(d){return d.x;})
.attr('y', function(d){return d.y;})
.style('font-family', fontFamily)
.style('fill', '#777')
.style('opacity', 0);
selection
.style('font-family', fontFamily)
.attr('x', function(d){return d.x;})
.attr('y', function(d){return d.y;});
// Create transtion to increase opacity from 0 to 0.1-0.5
// Add delay based on distance from the center of the <svg> and a bit more randomness.
selection.transition()
.delay(function(d){
return d.distance * 0.01 + Math.random()*1000;
})
.style('opacity', function(d){
return 0.1 + Math.random()*0.4;
});
}
</script>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment