Skip to content

Instantly share code, notes, and snippets.

@MarcosHiramRojasSosa
Last active March 22, 2017 07:50
Show Gist options
  • Save MarcosHiramRojasSosa/1d504c79320edecd39135741e30d2b00 to your computer and use it in GitHub Desktop.
Save MarcosHiramRojasSosa/1d504c79320edecd39135741e30d2b00 to your computer and use it in GitHub Desktop.
proyecto Jerónimo
license: mit
lat lng
18.936447 -99.245601
18.936650 -99.245623
18.936944 -99.245848
18.939106 -99.246647
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.12.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.12.0/mapbox-gl.css' rel='stylesheet' />
<script src="selector.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
#map {
position:absolute;
width: 100%;
height: 100%;
}
svg {
position: absolute;
width: 100%;
height: 100%;
}
nav {
position: absolute;
top: 40px;
left: 20px;
z-index: 1;
}
#circle {
background-color: rgba(20, 20, 20, 0.1);
font-family: Helvetica, sans-serif;
color: #3b83bd;
padding: 5px 8px;
border-radius: 3px;
cursor: pointer;
border: 1px solid #111;
}
#circle.active {
background-color: rgba(250, 250, 250, 0.9);
}
</style>
</head>
<body>
<nav>
<a id="circle" class="active">draw circle</a>
</nav>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoibWFyc3JzIiwiYSI6ImNpZXBhYWdtMTAwMHp0ZWt1dXRnb2dheGYifQ.8MMS1nj0nyiGw-BF6dFB-g'
//Setup mapbox-gl map
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/marsrs/cisq39eli000r2xox70rxp4sr',
center: [-99.246835,18.938405],
zoom: 14,
})
map.dragPan.disable();
map.scrollZoom.disable();
// Setup our svg layer that we can manipulate with d3
var container = map.getCanvasContainer()
var svg = d3.select(container).append("svg")
var active = true;
var circleControl = new circleSelector(svg)
.projection(project)
.inverseProjection(function(a) {
return map.unproject({x: a[0], y: a[1]});
})
.activate(active);
d3.select("#circle").on("click", function() {
active = !active;
circleControl.activate(active)
if(active) {
map.dragPan.disable();
} else {
map.dragPan.enable();
}
d3.select(this).classed("active", active)
})
// Add zoom and rotation controls to the map.
map.addControl(new mapboxgl.Navigation());
function project(d) {
return map.project(getLL(d));
}
function getLL(d) {
return new mapboxgl.LngLat(+d.lng, +d.lat)
}
d3.csv("dots.csv", function(err, data) {
//console.log(data[0], getLL(data[0]), project(data[0]))
var dots = svg.selectAll("circle.dot")
.data(data)
dots.enter().append("circle").classed("dot", true)
.attr("r", 1)
.style({
fill: "#0082a3",
"fill-opacity": 0.6,
stroke: "#004d60",
"stroke-width": 1
})
.transition().duration(1000)
.attr("r", 6)
circleControl.on("update", function() {
svg.selectAll("circle.dot").style({
fill: function(d) {
var thisDist = circleControl.distance(d);
var circleDist = circleControl.distance()
if(thisDist < circleDist) {
return "#ff8eec";
} else {
return "#0082a3"
}
}
})
})
circleControl.on("clear", function() {
svg.selectAll("circle.dot").style("fill", "#0082a3")
})
function render() {
dots.attr({
cx: function(d) {
var x = project(d).x;
return x
},
cy: function(d) {
var y = project(d).y;
return y
},
})
circleControl.update(svg)
}
// re-render our visualization whenever the view changes
map.on("viewreset", function() {
render()
})
map.on("move", function() {
render()
})
// render our initial visualization
render()
})
</script>
</body>
/*
===============================================================
Circle Selection component
===============================================================
*/
function circleSelector(svg) {
var that = this;
var circleCenter, circleOuter; //control points
var circleSelected = false; //have we completed the circle?
var dragging = false; //track whether we are dragging
var active = false; // user can turn on/off this behavior
var container = svg; // the container we render our points in
// this will likely be overriden by leaflet projection
var project = d3.geo.mercator();
var unproject = d3.geo.mercator().invert;
//we expose events on our component
var dispatch = d3.dispatch("update", "clear");
// The user provides an svg element to listen on events
svg.on("mouseup.circle", function() {
if(!active) return;
if(dragging && circleSelected) return;
var p = d3.mouse(this);
var ll = unproject([p[0],p[1]])
if(circleCenter) {
// if we already have the circle's center and the circle
// is finished selecting, another click means destroy the circle
if(!circleSelected) {
// Set the outer point
circleOuter = ll;
circleSelected = true;
}
} else {
// We set the center to the initial click
circleCenter = ll;
circleOuter = ll;
}
// we let the user know
update()
})
svg.on("mousemove.circle", function() {
if(!active) return;
if(circleSelected) return;
// we draw a guideline for where the next point would go.
var p = d3.mouse(this);
var ll = unproject([p[0],p[1]])
circleOuter = ll;
update();
})
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
if(!active) return;
if(circleSelected) {
dragging = true;
var p = d3.mouse(svg.node());
var ll = unproject([p[0],p[1]])
if(i) {
circleOuter = ll;
} else {
var dlat = circleCenter.lat - ll.lat;
var dlng = circleCenter.lng - ll.lng;
circleCenter = ll;
circleOuter.lat -= dlat;
circleOuter.lng -= dlng;
}
update();
} else {
return false;
}
})
.on("dragend", function(d) {
// kind of a dirty hack...
setTimeout(function() {
dragging = false;
},100)
})
function update(g) {
if(g) container = g;
if(!circleCenter || !circleOuter) return;
var dist = distance(circleCenter, circleOuter)
var circleLasso = container.selectAll("circle.lasso").data([dist])
circleLasso.enter().append("circle").classed("lasso", true)
.on("click", function() {
if(!active) return;
// start over
circleCenter = null;
circleOuter = null;
circleSelected = false;
container.selectAll("circle.lasso").remove();
container.selectAll("circle.control").remove();
container.selectAll("line.lasso").remove();
dispatch.clear();
})
circleLasso
.attr({
cx: project(circleCenter).x,
cy: project(circleCenter).y,
r: dist
})
.style({
stroke: "#010",
fill: "#010",
"fill-opacity": 0.1
})
var line = container.selectAll("line.lasso").data([circleOuter])
line.enter().append("line").classed("lasso", true)
if(!circleSelected && circleCenter || dragging) {
line.attr({
x1: project(circleCenter).x,
y1: project(circleCenter).y,
x2: project(circleOuter).x,
y2: project(circleOuter).y
})
.style({
stroke: "#111",
"stroke-dasharray": "5 5"
})
} else {
line.remove();
}
var controls = container.selectAll("circle.control")
.data([circleCenter, circleOuter])
controls.enter().append("circle").classed("control", true)
controls.attr({
cx: function(d) { return project(d).x},
cy: function(d) { return project(d).y},
r: 8,
stroke: "#010",
fill: "#b7feb7",
"fill-opacity":0.9
})
.style({
"cursor": active ? "move" : null
})
.call(drag)
dispatch.update();
}
this.update = update;
this.projection = function(val) {
if(!val) return project;
project = val;
return this;
}
this.inverseProjection = function(val) {
if(!val) return unproject;
unproject = val;
return this;
}
this.activate = function(val) {
active = val;
return this;
}
this.distance = function(ll) {
if(!ll) ll = circleOuter;
return distance(circleCenter, ll)
}
function distance(ll0, ll1) {
var p0 = project(ll0)
var p1 = project(ll1)
var dist = Math.sqrt((p1.x - p0.x)*(p1.x - p0.x) + (p1.y - p0.y)*(p1.y-p0.y))
return dist;
}
d3.rebind(this, dispatch, "on")
return this;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment