Created
May 6, 2018 07:49
-
-
Save lingyielia/ce2719ba65087e50a6e0bf01581dc312 to your computer and use it in GitHub Desktop.
JS Bin // source https://jsbin.com/xihewuk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>JS Bin</title> | |
<style id="jsbin-css"> | |
#map { | |
width: 650px; | |
height: 650px; | |
float: left; | |
display: inline-block; | |
} | |
.zipcode { | |
stroke: black; | |
stroke-width: 1px; | |
fill: none; | |
} | |
.legendbox { | |
background: rgba(255,255,255,0.7); | |
box-shadow: 0 0 15px rgba(0,0,0,0.2); | |
border-radius: 5px; | |
height: 45px; | |
width: 300px; | |
} | |
/* .leaflet-edit-move { | |
max-width: 16px; | |
max-height: 16px; | |
border-radius: 50%; | |
background: #ff7800; | |
border: 1px solid #000; | |
opacity: 0.85; | |
} | |
.leaflet-edit-resize { | |
max-width: 16px; | |
max-height: 16px; | |
border-radius: 50%; | |
background: #0078ff; | |
border: 1px solid #000; | |
opacity: 0.85; | |
} */ | |
</style> | |
</head> | |
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" | |
integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" | |
crossorigin=""/> | |
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js" | |
integrity="sha512-/Nsx9X4HebavoBvEBuyp3I7od5tA0UzAxs+j83KgC8PU0kgB4XiK4Lfe4y4cgBtaRJQEIFCW+oC506aPT2L1zw==" | |
crossorigin=""></script> | |
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css" /> --> | |
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script> --> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script> | |
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.css" /> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script> | |
<body> | |
</div> | |
<div id="map"> | |
</div> | |
<script id="jsbin-javascript"> | |
const ZIPCODE_URL = "https://raw.githubusercontent.com/lingyielia/D3-visual/master/data/nyc_zip.geojson"; | |
const count_url = "https://raw.githubusercontent.com/YukunVVan/DataViz-Project/master/DataPreprocess/defalt/casebyzip.json?token=AefhM2qQI6hcXfR-MdLqH2MW0YjflTl7ks5a93-mwA%3D%3D"; | |
function createBaseMap() { | |
let center = [40.7, -73.975], | |
cusp = [40.692908,-73.9896452] | |
baseLight = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', | |
{ minZoom: 10, }), | |
circle = L.circle(cusp, 1000, options={editable: true}), | |
dMap = L.map('map', { | |
center: center, | |
zoom: 10, | |
layers: [baseLight] | |
}), | |
svg = d3.select(dMap.getPanes().overlayPane).append("svg"), | |
g = svg.append("g").attr("class", "leaflet-zoom-hide"); | |
L.control.layers({ | |
"Light": baseLight, | |
}, | |
{ | |
"Selection": circle, | |
}).addTo(dMap); | |
let infoBox = L.control({position: 'bottomleft'}); | |
infoBox.onAdd = function (map) {var div = L.DomUtil.create('div', 'infobox'); return div;} | |
infoBox.addTo(dMap); | |
return [svg, g, dMap, circle]; | |
} | |
d3.queue() | |
.defer(d3.json, ZIPCODE_URL) | |
.defer(d3.json, count_url) | |
.await(createMap); | |
function createMap(error, zipcodes, countdata) { | |
let baseMap = createBaseMap(); | |
function projectPoint(x, y) { | |
let point = dMap.latLngToLayerPoint(new L.LatLng(y, x)); | |
this.stream.point(point.x, point.y); | |
} | |
let projection = d3.geoTransform({point: projectPoint}), | |
path = d3.geoPath().projection(projection), | |
svg = baseMap[0], | |
g = baseMap[1], | |
dMap = baseMap[2]; | |
let legendControl = L.control({position: 'topleft'}); | |
legendControl.onAdd = addLegendToMap; | |
legendControl.addTo(dMap); | |
dMap.on("zoomend", reproject); | |
reproject(); | |
function addLegendToMap(map) { | |
let div = L.DomUtil.create('div', 'legendbox'), | |
ndiv = d3.select(div) | |
.style("left", "50px") | |
.style("top", "-75px"), | |
lsvg = ndiv.append("svg"), | |
legend = lsvg.append("g") | |
.attr("class", "legend") | |
.attr("transform", "translate(0, 20)"); | |
legend.append("text") | |
.attr("class", "axis--map--caption") | |
.attr("y", -6); | |
return div; | |
}; | |
function reproject() { | |
bounds = path.bounds(zipcodes); | |
let 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"); | |
// Then also transform our map group | |
g.attr("transform", `translate(${-topLeft[0]}, ${-topLeft[1]})`); | |
// And update the actual D3 visual elements | |
let zipShapes = g.selectAll(".zipcode") | |
.data(zipcodes.features); // we rejoin the data | |
zipShapes | |
.enter().append("path") | |
.attr("class", "zipcode") | |
.merge(zipShapes) // and perform updates on both match and unmatches | |
.attr("d", path); | |
// Redraw the map | |
updateMap(g, zipcodes, countdata); | |
} | |
} | |
function updateMap(g, zipcodes, countdata) { | |
var countbyzip = {}, | |
counts = countdata.map(d => d.count), | |
maxCount = d3.max(counts), | |
color = d3.scaleThreshold() | |
.domain(d3.range(0, maxCount, maxCount/5)) | |
.range(d3.schemePurples[5]), | |
x = d3.scaleLinear() | |
.domain([0, maxCount]) | |
.rangeRound([50, 300]), | |
legend = d3.select(".legend"); | |
let boxes = legend.selectAll("rect") | |
.data(color.range().map(function(d) { | |
d = color.invertExtent(d); | |
return [(d[0]!==null?d[0]:x.domain()[0]), | |
(d[1]!==null?d[1]:x.domain()[1])]; | |
})); | |
boxes | |
.enter().append("rect") | |
.merge(boxes) | |
.attr("height", 6) | |
.attr("x", d => x(d[0])) | |
.attr("width", d => (x(d[1]) - x(d[0]))) | |
.attr("fill", d => 'rebeccapurple'); | |
countdata.forEach(function (d) { | |
countbyzip[d.zipcode] = +d.count; | |
}); | |
g.selectAll(".zipcode") | |
.data(zipcodes.features) | |
.style("fill", function(d) {return color(countbyzip[d.properties.zipcode]);}); | |
legend.call(d3.axisBottom(x) | |
.ticks(5, "s") | |
.tickSize(10,0) | |
.tickValues(color.domain())) | |
.select(".domain") | |
.remove(); | |
legend.select(".axis--map--caption") | |
.attr("x", x.range()[0]) | |
.text('Number of Complaints'); | |
} | |
</script> | |
<script id="jsbin-source-css" type="text/css">#map { | |
width: 650px; | |
height: 650px; | |
float: left; | |
display: inline-block; | |
} | |
.zipcode { | |
stroke: black; | |
stroke-width: 1px; | |
fill: none; | |
} | |
.legendbox { | |
background: rgba(255,255,255,0.7); | |
box-shadow: 0 0 15px rgba(0,0,0,0.2); | |
border-radius: 5px; | |
height: 45px; | |
width: 300px; | |
} | |
/* .leaflet-edit-move { | |
max-width: 16px; | |
max-height: 16px; | |
border-radius: 50%; | |
background: #ff7800; | |
border: 1px solid #000; | |
opacity: 0.85; | |
} | |
.leaflet-edit-resize { | |
max-width: 16px; | |
max-height: 16px; | |
border-radius: 50%; | |
background: #0078ff; | |
border: 1px solid #000; | |
opacity: 0.85; | |
} */</script> | |
<script id="jsbin-source-javascript" type="text/javascript">const ZIPCODE_URL = "https://raw.githubusercontent.com/lingyielia/D3-visual/master/data/nyc_zip.geojson"; | |
const count_url = "https://raw.githubusercontent.com/YukunVVan/DataViz-Project/master/DataPreprocess/defalt/casebyzip.json?token=AefhM2qQI6hcXfR-MdLqH2MW0YjflTl7ks5a93-mwA%3D%3D"; | |
function createBaseMap() { | |
let center = [40.7, -73.975], | |
cusp = [40.692908,-73.9896452] | |
baseLight = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', | |
{ minZoom: 10, }), | |
circle = L.circle(cusp, 1000, options={editable: true}), | |
dMap = L.map('map', { | |
center: center, | |
zoom: 10, | |
layers: [baseLight] | |
}), | |
svg = d3.select(dMap.getPanes().overlayPane).append("svg"), | |
g = svg.append("g").attr("class", "leaflet-zoom-hide"); | |
L.control.layers({ | |
"Light": baseLight, | |
}, | |
{ | |
"Selection": circle, | |
}).addTo(dMap); | |
let infoBox = L.control({position: 'bottomleft'}); | |
infoBox.onAdd = function (map) {var div = L.DomUtil.create('div', 'infobox'); return div;} | |
infoBox.addTo(dMap); | |
return [svg, g, dMap, circle]; | |
} | |
d3.queue() | |
.defer(d3.json, ZIPCODE_URL) | |
.defer(d3.json, count_url) | |
.await(createMap); | |
function createMap(error, zipcodes, countdata) { | |
let baseMap = createBaseMap(); | |
function projectPoint(x, y) { | |
let point = dMap.latLngToLayerPoint(new L.LatLng(y, x)); | |
this.stream.point(point.x, point.y); | |
} | |
let projection = d3.geoTransform({point: projectPoint}), | |
path = d3.geoPath().projection(projection), | |
svg = baseMap[0], | |
g = baseMap[1], | |
dMap = baseMap[2]; | |
let legendControl = L.control({position: 'topleft'}); | |
legendControl.onAdd = addLegendToMap; | |
legendControl.addTo(dMap); | |
dMap.on("zoomend", reproject); | |
reproject(); | |
function addLegendToMap(map) { | |
let div = L.DomUtil.create('div', 'legendbox'), | |
ndiv = d3.select(div) | |
.style("left", "50px") | |
.style("top", "-75px"), | |
lsvg = ndiv.append("svg"), | |
legend = lsvg.append("g") | |
.attr("class", "legend") | |
.attr("transform", "translate(0, 20)"); | |
legend.append("text") | |
.attr("class", "axis--map--caption") | |
.attr("y", -6); | |
return div; | |
}; | |
function reproject() { | |
bounds = path.bounds(zipcodes); | |
let 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"); | |
// Then also transform our map group | |
g.attr("transform", `translate(${-topLeft[0]}, ${-topLeft[1]})`); | |
// And update the actual D3 visual elements | |
let zipShapes = g.selectAll(".zipcode") | |
.data(zipcodes.features); // we rejoin the data | |
zipShapes | |
.enter().append("path") | |
.attr("class", "zipcode") | |
.merge(zipShapes) // and perform updates on both match and unmatches | |
.attr("d", path); | |
// Redraw the map | |
updateMap(g, zipcodes, countdata); | |
} | |
} | |
function updateMap(g, zipcodes, countdata) { | |
var countbyzip = {}, | |
counts = countdata.map(d => d.count), | |
maxCount = d3.max(counts), | |
color = d3.scaleThreshold() | |
.domain(d3.range(0, maxCount, maxCount/5)) | |
.range(d3.schemePurples[5]), | |
x = d3.scaleLinear() | |
.domain([0, maxCount]) | |
.rangeRound([50, 300]), | |
legend = d3.select(".legend"); | |
let boxes = legend.selectAll("rect") | |
.data(color.range().map(function(d) { | |
d = color.invertExtent(d); | |
return [(d[0]!==null?d[0]:x.domain()[0]), | |
(d[1]!==null?d[1]:x.domain()[1])]; | |
})); | |
boxes | |
.enter().append("rect") | |
.merge(boxes) | |
.attr("height", 6) | |
.attr("x", d => x(d[0])) | |
.attr("width", d => (x(d[1]) - x(d[0]))) | |
.attr("fill", d => 'rebeccapurple'); | |
countdata.forEach(function (d) { | |
countbyzip[d.zipcode] = +d.count; | |
}); | |
g.selectAll(".zipcode") | |
.data(zipcodes.features) | |
.style("fill", function(d) {return color(countbyzip[d.properties.zipcode]);}); | |
legend.call(d3.axisBottom(x) | |
.ticks(5, "s") | |
.tickSize(10,0) | |
.tickValues(color.domain())) | |
.select(".domain") | |
.remove(); | |
legend.select(".axis--map--caption") | |
.attr("x", x.range()[0]) | |
.text('Number of Complaints'); | |
} | |
</script></body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#map { | |
width: 650px; | |
height: 650px; | |
float: left; | |
display: inline-block; | |
} | |
.zipcode { | |
stroke: black; | |
stroke-width: 1px; | |
fill: none; | |
} | |
.legendbox { | |
background: rgba(255,255,255,0.7); | |
box-shadow: 0 0 15px rgba(0,0,0,0.2); | |
border-radius: 5px; | |
height: 45px; | |
width: 300px; | |
} | |
/* .leaflet-edit-move { | |
max-width: 16px; | |
max-height: 16px; | |
border-radius: 50%; | |
background: #ff7800; | |
border: 1px solid #000; | |
opacity: 0.85; | |
} | |
.leaflet-edit-resize { | |
max-width: 16px; | |
max-height: 16px; | |
border-radius: 50%; | |
background: #0078ff; | |
border: 1px solid #000; | |
opacity: 0.85; | |
} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const ZIPCODE_URL = "https://raw.githubusercontent.com/lingyielia/D3-visual/master/data/nyc_zip.geojson"; | |
const count_url = "https://raw.githubusercontent.com/YukunVVan/DataViz-Project/master/DataPreprocess/defalt/casebyzip.json?token=AefhM2qQI6hcXfR-MdLqH2MW0YjflTl7ks5a93-mwA%3D%3D"; | |
function createBaseMap() { | |
let center = [40.7, -73.975], | |
cusp = [40.692908,-73.9896452] | |
baseLight = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', | |
{ minZoom: 10, }), | |
circle = L.circle(cusp, 1000, options={editable: true}), | |
dMap = L.map('map', { | |
center: center, | |
zoom: 10, | |
layers: [baseLight] | |
}), | |
svg = d3.select(dMap.getPanes().overlayPane).append("svg"), | |
g = svg.append("g").attr("class", "leaflet-zoom-hide"); | |
L.control.layers({ | |
"Light": baseLight, | |
}, | |
{ | |
"Selection": circle, | |
}).addTo(dMap); | |
let infoBox = L.control({position: 'bottomleft'}); | |
infoBox.onAdd = function (map) {var div = L.DomUtil.create('div', 'infobox'); return div;} | |
infoBox.addTo(dMap); | |
return [svg, g, dMap, circle]; | |
} | |
d3.queue() | |
.defer(d3.json, ZIPCODE_URL) | |
.defer(d3.json, count_url) | |
.await(createMap); | |
function createMap(error, zipcodes, countdata) { | |
let baseMap = createBaseMap(); | |
function projectPoint(x, y) { | |
let point = dMap.latLngToLayerPoint(new L.LatLng(y, x)); | |
this.stream.point(point.x, point.y); | |
} | |
let projection = d3.geoTransform({point: projectPoint}), | |
path = d3.geoPath().projection(projection), | |
svg = baseMap[0], | |
g = baseMap[1], | |
dMap = baseMap[2]; | |
let legendControl = L.control({position: 'topleft'}); | |
legendControl.onAdd = addLegendToMap; | |
legendControl.addTo(dMap); | |
dMap.on("zoomend", reproject); | |
reproject(); | |
function addLegendToMap(map) { | |
let div = L.DomUtil.create('div', 'legendbox'), | |
ndiv = d3.select(div) | |
.style("left", "50px") | |
.style("top", "-75px"), | |
lsvg = ndiv.append("svg"), | |
legend = lsvg.append("g") | |
.attr("class", "legend") | |
.attr("transform", "translate(0, 20)"); | |
legend.append("text") | |
.attr("class", "axis--map--caption") | |
.attr("y", -6); | |
return div; | |
}; | |
function reproject() { | |
bounds = path.bounds(zipcodes); | |
let 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"); | |
// Then also transform our map group | |
g.attr("transform", `translate(${-topLeft[0]}, ${-topLeft[1]})`); | |
// And update the actual D3 visual elements | |
let zipShapes = g.selectAll(".zipcode") | |
.data(zipcodes.features); // we rejoin the data | |
zipShapes | |
.enter().append("path") | |
.attr("class", "zipcode") | |
.merge(zipShapes) // and perform updates on both match and unmatches | |
.attr("d", path); | |
// Redraw the map | |
updateMap(g, zipcodes, countdata); | |
} | |
} | |
function updateMap(g, zipcodes, countdata) { | |
var countbyzip = {}, | |
counts = countdata.map(d => d.count), | |
maxCount = d3.max(counts), | |
color = d3.scaleThreshold() | |
.domain(d3.range(0, maxCount, maxCount/5)) | |
.range(d3.schemePurples[5]), | |
x = d3.scaleLinear() | |
.domain([0, maxCount]) | |
.rangeRound([50, 300]), | |
legend = d3.select(".legend"); | |
let boxes = legend.selectAll("rect") | |
.data(color.range().map(function(d) { | |
d = color.invertExtent(d); | |
return [(d[0]!==null?d[0]:x.domain()[0]), | |
(d[1]!==null?d[1]:x.domain()[1])]; | |
})); | |
boxes | |
.enter().append("rect") | |
.merge(boxes) | |
.attr("height", 6) | |
.attr("x", d => x(d[0])) | |
.attr("width", d => (x(d[1]) - x(d[0]))) | |
.attr("fill", d => 'rebeccapurple'); | |
countdata.forEach(function (d) { | |
countbyzip[d.zipcode] = +d.count; | |
}); | |
g.selectAll(".zipcode") | |
.data(zipcodes.features) | |
.style("fill", function(d) {return color(countbyzip[d.properties.zipcode]);}); | |
legend.call(d3.axisBottom(x) | |
.ticks(5, "s") | |
.tickSize(10,0) | |
.tickValues(color.domain())) | |
.select(".domain") | |
.remove(); | |
legend.select(".axis--map--caption") | |
.attr("x", x.range()[0]) | |
.text('Number of Complaints'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment