如何将十六进制应用于整个世界

时间:2016-06-17 11:48:27

标签: leaflet cartodb turfjs

如何将hex应用于整个世界。我在互联网上找到了this示例,但无法将其应用于整个世界var bbox = [-180, -90, 180, 90];,但它无法按预期运行。

/////////////////////////////////////////////////////////////////////////////////////////////
//setting up the map//
/////////////////////////////////////////////////////////////////////////////////////////////

// set center coordinates
var centerlat = 40.758896;
var centerlon = -73.985130;

// set default zoom level
var zoomLevel = 11;

// initialize map
var map = L.map('map').setView([centerlat, centerlon], zoomLevel);

// set source for map tiles
ATTR = '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
  '<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a> | ' +
  '&copy; <a href="http://cartodb.com/attributions">CartoDB</a>';

CDB_URL = 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png';

// add tiles to map
L.tileLayer(CDB_URL, {
  attribution: ATTR
}).addTo(map);

/////////////////////////////////////////////////////////////////////////////////////////////
//generating the GeoJSON objects//
/////////////////////////////////////////////////////////////////////////////////////////////

//create some GeoJSON points to be sampled (function below)
var dotcount = 200000;
var dots = make_dots(dotcount);

//parameters for hex grid
var bbox = [-74.035492, 40.706523, -73.908463, 40.825095];
var cellWidth = 0.3;
var units = 'miles';

//create hex grid and count points within each cell
var hexgrid = turf.hexGrid(bbox, cellWidth, units);
var hexcounts = turf.count(hexgrid, dots, 'pt_count');
L.geoJson(hexcounts, {
  onEachFeature: onEachHex
}).addTo(map);

function getRandomCoordinates(radius, uniform) {
  // Generate two random numbers
  var a = Math.random(),
    b = Math.random();

  // Flip for more uniformity.
  if (uniform) {
    if (b < a) {
      var c = b;
      b = a;
      a = c;
    }
  }

  // It's all triangles.
  return [
    b * radius * Math.cos(2 * Math.PI * a / b),
    b * radius * Math.sin(2 * Math.PI * a / b)
  ];
}

function getRandomLocation(latitude, longitude, radiusInMeters) {
  var randomCoordinates = getRandomCoordinates(radiusInMeters, true);

  // Earths radius in meters via WGS 84 model.
  var earth = 6378137;

  // Offsets in meters.
  var northOffset = randomCoordinates[0],
    eastOffset = randomCoordinates[1];

  // Offset coordinates in radians.
  var offsetLatitude = northOffset / earth,
    offsetLongitude = eastOffset / (earth * Math.cos(Math.PI * (latitude / 180)));

  // Offset position in decimal degrees.
  return {
    latitude: latitude + (offsetLatitude * (180 / Math.PI)),
    longitude: longitude + (offsetLongitude * (180 / Math.PI))
  }
}

/*function make_dots() {
  var dots = {
    type: "FeatureCollection",
    features: []
  };

  for (var i = 0; i < dotcount; ++i) {
    var loc = getRandomLocation(40.767915, -73.972321, 1000);

    var t = L.marker([loc.latitude, loc.longitude]);

    dots.features.push(t.toGeoJSON());
  }

  return dots;
}
*/

/////////////////////////////////////////////////////////////////////////////////////////////
//legend//
/////////////////////////////////////////////////////////////////////////////////////////////

//create legend
var hexlegend = L.control({
  position: 'topright'
});
//generate legend contents
hexlegend.onAdd = function(map) {
  //set up legend grades and labels
  var div = L.DomUtil.create('div', 'info legend'),
    grades = [1, 2, 5, 10, 20, 50, 100],
    labels = ['<strong>Point Count</strong>'],
    from, to;

  //iterate through grades and create a color field and label for each
  for (var i = 0; i < grades.length; i++) {
    from = grades[i];
    to = grades[i + 1];
    labels.push(
      '<i style="background:' + getColor(from + 0.5) + '"></i> ' + from + (to ? '&ndash;' + to : '+'));
  }
  div.innerHTML = labels.join('<br>');
  return div;
};
hexlegend.addTo(map);

/////////////////////////////////////////////////////////////////////////////////////////////
//styling functions//
/////////////////////////////////////////////////////////////////////////////////////////////

//highlight style
var hexStyleHighlight = {
  color: "#336",
  weight: 2,
  opacity: 1,
};

//create color ramp
function getColor(y) {
  return y == undefined ? '#888' :
    y < 1 ? '#ffffe9' :
    y < 2 ? '#edf8b1' :
    y < 5 ? '#c7e9b4' :
    y < 10 ? '#7fcdbb' :
    y < 20 ? '#41b6c4' :
    y < 50 ? '#1d91c0' :
    y < 100 ? '#225ea8' :
    '#0c2c84';
}

//create style, with fillColor picked from color ramp
function style(feature) {
  return {
    fillColor: getColor(feature.properties.pt_count),
    color: "#888",
    weight: 0.5,
    opacity: 1,
    fillOpacity: 0.4//0.8
  };
}

//attach styles and popups to the hex layer
function highlightHex(e) {
  var layer = e.target;
  layer.setStyle(hexStyleHighlight);
  if (!L.Browser.ie && !L.Browser.opera) {
    layer.bringToFront();
  }
}

function resetHexHighlight(e) {
  var layer = e.target;
  var hexStyleDefault = style(layer.feature);
  layer.setStyle(hexStyleDefault);
}

function onEachHex(feature, layer) {
  layer.on({
    mouseover: highlightHex,
    mouseout: resetHexHighlight
  });
  var hexStyleDefault = style(layer.feature);
  layer.setStyle(hexStyleDefault);
  //for the sake of grammar
  if (feature.properties.pt_count == 1) {
    var be_verb = "There is";
    var point_s = "point";
  } else {
    var be_verb = "There are";
    var point_s = "points";
  }
  layer.bindPopup(be_verb + ' <b>' + feature.properties.pt_count + '</b> ' + point_s + ' in this cell.');

}

/////////////////////////////////////////////////////////////////////////////////////////////
//synthetic GeoJSON functions//
/////////////////////////////////////////////////////////////////////////////////////////////

//cheapo normrand function
function normish(mean, range) {
  var num_out = ((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() - 4) / 4) * range + mean;
  return num_out;
}

//create geojson data with random ~normal distribution
function make_dots(dotcount) {

  var dots = {
    type: "FeatureCollection",
    features: []
  };

  for (var i = 0; i < dotcount; ++i) {

    //set up random variables
    /*x = normish(0, 4);
    y = normish(0, 4);

    //create points randomly distributed about center coordinates
    var g = {
        "type": "Point",
            "coordinates": [((x * 0.11) + centerlon), ((y * 0.1) + centerlat)]
    };

    //create feature properties, roughly proportional to distance from center coordinates
    var p = {
        "id": i,
            "popup": "Dot_" + i,
            "year": parseInt(Math.sqrt(x * x + y * y) * 60 * (1 - Math.random() / 1.5) + 1900),
            "size": Math.round((parseFloat(Math.abs((normish(y*y, 2) + normish(x*x, 2)) * 50) + 10)) * 100) / 100
    };*/

    var loc = getRandomLocation(40.769996, -73.973007, 5000);

    var t = L.marker([loc.latitude, loc.longitude]);

    dots.features.push(t.toGeoJSON());

    //create features with proper geojson structure        
    //dots.features.push({
    //    "geometry" : g,
    //    "type": "Feature",
    //    "properties": p
    //});
  }
  return dots;
}
html,
body,
#map {
  height: 100%;
  width: 100%;
  padding: 0px;
  margin: 0px;
}

.info {
  padding: 6px 8px;
  font: 14px/16px Arial, Helvetica, sans-serif;
  background: white;
  background: rgba(255, 255, 255, 0.8);
  box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
  border-radius: 5px;
}

.legend {
  text-align: left;
  line-height: 18px;
  color: #555;
}

.legend i {
  width: 18px;
  height: 18px;
  float: left;
  margin-right: 8px;
  opacity: 0.7;
}

.legend .colorcircle {
  border-radius: 50%;
  width: 15px;
  height: 15px;
  margin-top: 0px;
}
<script src="https://api.mapbox.com/mapbox.js/plugins/turf/v2.0.2/turf.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet"/>

<div id="map"></div>

编辑:我没有使用作为第三方库的turf.js,而是尝试使用L.multiPolygon创建自己的六边形,一切正常,但它只适用于地图的一小部分,如果我在浏览器中添加更多六边形崩溃。所以我想避免一次加载所有的十六进制,但只能在屏幕上看到。我找到了一种方法L.PolyUtil.clipPolygon,但我不确定它是如何工作的,这里是jsfiddle

/////////////////////////////////////////////////////////////////////////////////////////////
//setting up the map//
/////////////////////////////////////////////////////////////////////////////////////////////
// set center coordinates
var lat = 35.15;
var lng = 33.35;
var R = 500;

// set default zoom level
var zoomLevel = 13;

// initialize map
var map = L.map('map').setView([lat, lng], zoomLevel);

// set source for map tiles
ATTR = '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
    '<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a> | ' +
    '&copy; <a href="http://cartodb.com/attributions">CartoDB</a>';

CDB_URL = 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png';

// add tiles to map
L.tileLayer(CDB_URL, {
    attribution: ATTR,
    noWrap: true
}).addTo(map);

var b = new L.Circle([lat, lng], R).getBounds();
var r = (b._northEast.lat - b._southWest.lat) / 2;
var h = (b._northEast.lng - b._southWest.lng) / 2;
var d = Math.sqrt(3 * h * h / 4);

var grid_x = 100;
var grid_y = 100;

var la = lat;
var lo = lng;
var multiPolygonLatLongs = [];
for (var i = 0; i < grid_x; i++) {
    for (var j = 0; j < grid_y; j++) {
        multiPolygonLatLongs.push([
            [la + r, lo],
            [la + r / 2, lo + d],
            [la - r / 2, lo + d],
            [la - r, lo],
            [la - r / 2, lo - d],
            [la + r / 2, lo - d]
        ]);
        lo += d * 2;
    }
    lo = i % 2 == 0 ? lng + d : lng;
    la += r * 1.5;
}

var p1 = map.getPixelOrigin();
var bounds =  map.getPixelBounds();

var clipped = L.PolyUtil.clipPolygon(multiPolygonLatLongs, bounds);

L.multiPolygon(clipped, {
    weight: 1,
    opacity: 0.2,
    fill: false
}).addTo(map);
html, body, #map {
      height: 100%;
      width:100%;
      padding:0px;
      margin:0px;
   } 
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet"/>

<div id="map"></div>

1 个答案:

答案 0 :(得分:2)

您可以使用类似这样的查询在CartoDB中执行此操作:

SELECT 
  CDB_HexagonGrid(
    ST_Transform(
      ST_SetSRID(  
        ST_MakeEnvelope(
          -179.99,
          -89.99,
          179.99,
          89.99),
        4326),
      3857),
    150000) 
  AS the_geom_webmercator

在编辑器中运行它,然后点击&#39;从查询&#39;

创建数据集

之后,您可以将该图层用作CartoDB中的任何其他图层。检查this example,了解如何使用cartodb.createLayer()加载自定义互动功能。

另外,如果你想下载geoJSON格式的数据而不是在Leaflet中使用,你可以使用类似的东西:

var sql=new cartodb.SQL({user:'USERNAME', format:'geojson'});
  sql.execute("SELECT * FROM table_name").done(function(geojson){
    data=geojson;
  });

之后,您可以在Leaflet中将十六进制网格用作geoJSON layer