Skip to content

Instantly share code, notes, and snippets.

@oriolbx
Last active June 13, 2018 07:06
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 oriolbx/541ace6b87533f9efabac440a300ef6f to your computer and use it in GitHub Desktop.
Save oriolbx/541ace6b87533f9efabac440a300ef6f to your computer and use it in GitHub Desktop.
CARTO.js v4: Category widget
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width">
<!-- Include Carto.js -->
<script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
<!-- Include Leaflet -->
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css" rel="stylesheet">
<!-- Include d3 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.0/d3.min.js"></script>
<style>
.wrapper {
width: 100%;
height: 100vh; /*view port height*/
display: grid;
/* small screens */
grid-template-areas:
"map"
"widget";
grid-template-rows: 10fr 2fr;
}
@media (min-width: 700px) {
.wrapper{
grid-template-areas:
"map widget";
grid-template-columns: 10fr 2fr;
grid-template-rows: auto;
}
}
#map {
grid-area: map;
border-radius: 10px;
}
#box {
grid-area: widget;
border-radius: 10px;
padding: 5px 10px 5px 10px;
border: 1px solid palegreen;
background-color: #FFF;
}
/* set styles to the <h4> tag of the element with id= box */
#box h4 {
text-align: center;
font-size: 24px;
font-style: italic;
}
/* set styles to the <p> tag of the element with id= box */
#box p {
text-align: center;
font-size: 18px;
color: dodgerblue;
}
</style>
</head>
<body>
<div class='wrapper'>
<div id="map"></div>
<div id="box"></div>
</div>
<script>
const map = L.map('map').setView([30, 0], 3);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
// define client
const client = new carto.Client({
apiKey: 'default_public',
username: 'oboix'
});
// define source of data using a SQL query
const source = new carto.source.SQL(`
SELECT * FROM populated_places_spf
`);
// define CartoCSS code to style data on map
const style = new carto.style.CartoCSS(`
#layer[adm0name = "Spain"]{
marker-fill: #fbb4ae;
marker-allow-overlap: true;
}
#layer[adm0name = "Portugal"]{
marker-fill: #ccebc5;
marker-allow-overlap: true;
}
#layer[adm0name = "France"]{
marker-fill: #b3cde3;
marker-allow-overlap: true;
}`);
// create CARTO layer from source and style variables
const Cartolayer = new carto.layer.Layer(source, style);
// add CARTO layer to the client
client.addLayer(Cartolayer);
// get tile from client and add them to the map object
client.getLeafletLayer().addTo(map);
// create formula dataview using pop_max column values
// SUM formula
const categoryDataview = new carto.dataview.Category(source, 'adm0name', {
limit: 10,
operation: carto.operation.SUM,
operationColumn: 'pop_max'
});
// define variable that will store an array of values
let categoriesArray = [];
// when there is a change on the data, execute function to
// display result from dataview in DOM element
categoryDataview.on('dataChanged', function(data){
categoriesArray = [];
// data.categories is an array of objects -> [{},{},{},...]
let categories = data.categories;
// Use D3.js library to format text with comma separator for thousands
let commaSeparator = d3.format(",");
// set values array
categories.forEach(function(data){
categoriesArray.push(data.value)
});
// use categoriesArray values to define the domain of the data
let x = d3.scaleLinear()
.domain([0, d3.max(categoriesArray)])
.range([0, 420]);
// define bar charts to create the category widgets
// define variable that will be the D3 bar chart
let chart = d3.select('#box')
.selectAll("div")
.data(categories)
.style("width", function(d) { return x(d.value) + "px"; })
.style("height", 20)
.style("background", '#9DE0AD')
.style('cursor','pointer')
.text(function(d) {
return d.name + ':' + commaSeparator(d.value);
})
.on('click', function(d){
source.setQuery(`
SELECT * FROM populated_places_spf
WHERE adm0name IN (\'${d.name}\'`)
});
// exit
chart.exit().remove();
// ENTER again, updates data
chart.enter()
.append("div")
.style("width", function(d) { return x(d.value) + "px"; })
.style("height", 20)
.style("background", '#9DE0AD')
.style('cursor','pointer')
.text(function(d) {
return d.name + ':' + commaSeparator(d.value);
})
.on('click', function(d){
source.setQuery(`
SELECT * FROM populated_places_spf
WHERE adm0name = \'${d.name}\'`
)
});
});
// add category dataview to client
client.addDataview(categoryDataview);
// Set bounding box filter
const bboxFilter = new carto.filter.BoundingBoxLeaflet(map);
// add filter to formula dataview, so when the BBOX change, the formula data view will be recalculated
categoryDataview.addFilter(bboxFilter);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment