Skip to content

Instantly share code, notes, and snippets.

@peterlozano
Last active November 3, 2020 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterlozano/cfb0d67cfe8921ce6784 to your computer and use it in GitHub Desktop.
Save peterlozano/cfb0d67cfe8921ce6784 to your computer and use it in GitHub Desktop.
Los Angeles Neighborhoods Map.

Interactive map of neighborhoods in Los Angeles, CA.

Includes:

  • Leaflet mapbox tiles + d3.js svg overlay.
  • Zoom to bounds when clicking on a shape.
  • Mouse hover effects.
  • Tooltips using d3-tip.

Geographic shapes courtesy of LA Times http://boundaries.latimes.com/sets/

<!DOCTYPE html>
<html>
<head>
<title>Los Angeles Neighborhoods Map</title>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="map"></div>
</body>
<script>
var width = 960,
height = 500,
active = d3.select(null);
// Set map wrapper size.
d3.select('#map')
.style('width', width + 'px')
.style('height', height + 'px');
// Create Leftlet map and center in the desired position.
var map = L.map('map').setView([34.0000, -118.300], 10);
// Mapbox
var tiles = 'https://{s}.tiles.mapbox.com/v3/examples.map-i87786ca/{z}/{x}/{y}.png';
// Openstreetmap
//var tiles = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
// Add openstreetmap tile layer.
L.tileLayer(tiles, { maxZoom: 18 }).addTo(map);
/* Initialize the SVG layer */
map._initPathRoot();
// Create the svg element inside the div.
//var svg = d3.select("#map").select("svg");
var svg = d3.select(map.getPanes().overlayPane).append("svg");
var g = svg.append("g").attr("class", "leaflet-zoom-hide");
// Initialize tooltips.
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) { return d.properties.name; });
svg.call(tip);
// Use Leaflet to implement a D3 geometric transformation.
function projectPoint(x, y) {
var point = map.latLngToLayerPoint(new L.LatLng(y, x));
this.stream.point(point.x, point.y);
}
// Create a d3.geo.path to convert GeoJSON to SVG.
var transform = d3.geo.transform({point: projectPoint});
var path = d3.geo.path()
.projection(transform);
// Random color function.
var color = function(d) {
return 'blue';
};
// Load json and display.
d3.json("la.json", function(data) {
// Create a topojson feature using the geojson.
var neigh = topojson.feature(data, data.objects.la_county_neighborhoods_current);
var cname = 'neigh';
var neigh_path = g.selectAll('.' + cname)
.data(neigh.features)
.enter()
.append('path')
.attr('d', path)
.classed(cname, true)
.style('fill', color)
.style('fill-opacity', 0.1)
.style('stroke', 1)
.style('stroke-opacity', 0.3)
.attr('name', function(d) { return d.properties.name; })
.on('mouseover', function() {
if (active.node() === this) return;
tip.show(this.__data__);
d3.select(this)
.style('stroke', 1)
.style('fill', 'orange')
.style('fill-opacity', 0.7)
.style('stroke-opacity', 1);
})
.on('mouseout', function() {
if (active.node() === this) return;
tip.hide(this.__data__);
d3.select(this)
.transition().duration(250)
.style('stroke', 1)
.style('fill', color)
.style('fill-opacity', 0.1)
.style('stroke-opacity', 0.3);
})
.on("click", clicked);
// Set the map reset event.
map.on("viewreset", reset);
// Initialize.
reset();
// When the map reset event is called, recalculate the paths and svg size and position.
function reset() {
var bounds = path.bounds(neigh),
topLeft = bounds[0],
bottomRight = bounds[1];
svg.attr("width", bottomRight[0] - topLeft[0])
.attr("height", bottomRight[1] - topLeft[1])
.style("left", topLeft[0] + "px")
.style("top", topLeft[1] + "px");
g.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
neigh_path.attr('d', path);
}
function clicked(d) {
if (active.node() === this) return zoom_reset();
active.classed("active", false)
.style('fill', 'blue')
.style('fill-opacity', 0.1)
.style('stroke-opacity', 0.3);
active = d3.select(this)
.classed("active", true)
.style('fill', 'red')
.style('fill-opacity', 0.7);
var nbounds = d3.geo.bounds(d);
var southWest = L.latLng(nbounds[0][1], nbounds[0][0]),
northEast = L.latLng(nbounds[1][1], nbounds[1][0]),
neigh_bounds = L.latLngBounds(southWest, northEast);
map.fitBounds(neigh_bounds);
}
function zoom_reset() {
active.classed("active", false)
.style('fill', color)
.style('fill-opacity', 0.1)
.style('stroke-opacity', 0.3);
active = d3.select(null);
map.setView([34.0000, -118.300], 10);
}
});
</script>
</html>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
all: la.json
# Compose general json
la.json: la_county_neighborhoods_current.geojson
topojson \
-o la.json \
--id-property external_id \
--properties name=external_id \
-- \
la_county_neighborhoods_current.geojson
# LA Neighborhoods
# Source: http://boundaries.latimes.com/sets/
# No convertion to geojson required.
la_county_neighborhoods_current.geojson:
wget http://s3-us-west-2.amazonaws.com/boundaries.latimes.com/archive/1.0/boundary-set/la-county-neighborhoods-current.geojson
mv la-county-neighborhoods-current.geojson la_county_neighborhoods_current.geojson
# Cleanup
#
clean:
rm -rf la.json la-county-neighborhoods-current.geojson la_county_neighborhoods_current.geojson
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
path {
cursor: pointer;
}
@Finanklin
Copy link

Hello! Could you please directly give the data set "la.json"? I tried to download data from http://boundaries.latimes.com/sets/ but there are too many data sets. I do not know which one is the right one.

@simranmakandar
Copy link

Hello! Could you please directly give the data set "la.json"? I tried to download data from http://boundaries.latimes.com/sets/ but there are too many data sets. I do not know which one is the right one.

Hi Finanklin, you can download the ZIP (button on top-right) and see the la.json file in the folder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment