Files
carto.js/examples/public/misc/hexagon-aggregation-leaflet.html
2020-06-13 18:34:34 +08:00

128 lines
4.9 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Hexagon aggregation | CARTO</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
<!-- Include Leaflet -->
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet/dist/leaflet.css" rel="stylesheet">
<!-- Include CARTO.js -->
<script src="../../../dist/public/carto.js"></script>
<link href="../style.css" rel="stylesheet">
</head>
<body>
<div id="map"></div>
<!-- Description -->
<aside class="toolbox">
<div class="box">
<header>
<h1>Create an hexagonal grid</h1>
<button class="github-logo js-source-link"></button>
</header>
<section>
<p class="description open-sans">Aggregate your points in hexagons.</p>
</section>
<footer class="js-footer"></footer>
</div>
<!-- Set legend of the map -->
<div class="box legend">
<h2 class="h2">Number of points aggregated in hexagons</h2>
<ul class="category open-sans">
<li><div class="circle" style="background: #04817E "></div><p>1-2</p></li>
<li><div class="circle" style="background: #39AB7E "></div><p>>2</p></li>
<li><div class="circle" style="background: #8BD16D"></div><p>>9</p></li>
<li><div class="circle" style="background: #EDEF5D"></div><p>>30</p></li>
</ul>
</div>
</aside>
<script>
// set map with initial zoom and coodinates view
const map = L.map('map').setView([40, -80], 7);
// disable scroll wheel zoom
map.scrollWheelZoom.disable();
// add basemaps to map
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
// set CARTO client
const client = new carto.Client({
apiKey: 'default_public',
username: 'public'
});
// set SQL query to create the grid of hexagons
/*
To create the grid of hexagons we must use a SQL query that generates that grid for a specific
zoom level. We will use the zoom level 9 to create a grid of hexagons that will have a side size
of 12 pixel units.
We use the CARTO function CDB_HexagonGrid(geometry, side measure) to create the hexagon grid
where "geometry" is defined by the PostGIS function ST_Expand: "ST_Expand(!bbox!, CDB_XYZ_Resolution(9) * 12)"
and "side measure" is defined by "CDB_XYZ_Resolution(9) * 12)", where the function
CDB_XYZ_Resolution(zoom level) returns the pixel resolution of tiles at a given zoom level.
The geometry defined in "ST_Expand(!bbox!, CDB_XYZ_Resolution(9) * 12)" returns the geometry of
the bounding box that is defined by mapnik's !bbox! token and that is expanded in all directions a
distance of CDB_XYZ_Resolution(9) * 12 units
*/
const source = new carto.source.SQL(`
-- Create hexagon grid
WITH hgrid AS (
SELECT CDB_HexagonGrid(
ST_Expand(!bbox!, CDB_XYZ_Resolution(9) * 12),
CDB_XYZ_Resolution(9) * 12) as cell
)
-- select the data from the "virtual table" hgrid, which has been created
-- using the "WITH" statement of PostgreSQL,
-- that intesects with the dataset of points "stormevents_locations_2014"
SELECT hgrid.cell as the_geom_webmercator,
count(1) as agg_value,
row_number() over () as cartodb_id
FROM hgrid, (SELECT * FROM stormevents_locations_2014) i
WHERE ST_Intersects(i.the_geom_webmercator, hgrid.cell)
GROUP BY hgrid.cell
`);
// define styles of layer. We will style the color of the geometry based on the value
// of the column "agg_value" of the SQL query.
const style = new carto.style.CartoCSS(`
#layer {
[agg_value > 0] {
polygon-fill: #04817E;
}
[agg_value > 2] {
polygon-fill: #39AB7E;
}
[agg_value > 9] {
polygon-fill: #8BD16D;
}
[agg_value > 30] {
polygon-fill: #EDEF5D;
}
}
#layer::outline {
line-width: 1;
line-color: #FFFFFF;
line-opacity: 1;
}
`);
// set the CARTO layer using the source and style defines previously
const layer = new carto.layer.Layer(source, style);
// add CARTO layer to the client
client.addLayer(layer);
// retrieve tiles from CARTO to the map
client.getLeafletLayer().addTo(map);
</script>
</body>
</html>