Skip to content

Instantly share code, notes, and snippets.

@ramiroaznar
Last active January 4, 2018 08:41
Show Gist options
  • Select an option

  • Save ramiroaznar/e2e263c00e791e4057062be26d46a018 to your computer and use it in GitHub Desktop.

Select an option

Save ramiroaznar/e2e263c00e791e4057062be26d46a018 to your computer and use it in GitHub Desktop.
Histogram widget as legend with CARTO.js v4

Hitogram colors added thanks to @IagoLast. UPDATE: this is not working as expected, I recommend using this other approach.

<!DOCTYPE html>
<html>
<head>
<title>Histogram widget as legend with CARTO.js v4</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" href="https://cartodb.com/assets/favicon.ico" />
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
<!-- leaflet + jquery -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- chartjs -->
<script src="http://www.chartjs.org/dist/2.7.1/Chart.bundle.js"></script>
<script src="http://www.chartjs.org/samples/latest/utils.js"></script>
<!-- carto.js -->
<script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.0-beta.10/carto.min.js"></script>
<style>
* {
box-sizing: border-box;
}
body,
* {
margin: 0;
padding: 0;
}
#map {
position: absolute;
height: 100%;
width: 100%;
z-index: 0;
}
#histogram {
position: absolute;
bottom: 12px;
left: 12px;
height: auto;
width: auto;
padding: 20px 24px;
background: white;
box-shadow: 0 0 16px rgba(0, 0, 0, 0.12);
border-radius: 4px;
opacity: 0.8;
z-index: 1;
width: 450px;
}
#histogram>h1 {
font: 800 12px/16px 'Montserrat';
text-transform: uppercase;
color: #2D3C43;
margin-bottom: 12px;
}
</style>
</head>
<body>
<!-- map div -->
<div id="map"></div>
<!-- histogram div -->
<div id="histogram">
<h1>Airbnb price distribution in Madrid</h1>
<canvas id="chart" width="400" height="400"></canvas>
</div>
<script type="text/cartocss" id="style">
#layer {
marker-width: 5;
marker-fill: ramp([price], cartocolor(Sunset), equal(10));
marker-fill-opacity: 0.7;
marker-allow-overlap: true;
marker-line-width: 0;
marker-comp-op: multiply;
}
</script>
<script type="text/sql" id="query">
SELECT
*
FROM
listings
WHERE
price < 150
</script>
<script>
function main() {
// get styles & query
const style = $("#style").text(),
query = $("#query").text(),
// add map variable
map = L.map('map', {
zoomControl: false,
center: [40.43, -3.7],
zoom: 13
});
// add Voyager Basemap
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '&copy;<a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy;<a href="https://carto.com/attribution">CARTO</a>'
}).addTo(map);
// Adding Voyager Labels
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '&copy;<a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy;<a href="https://carto.com/attribution">CARTO</a>',
zIndex: 100
}).addTo(map);
// add client
const client = new carto.Client({
apiKey: 'API_KEY',
username: 'ramirocartodb'
});
// add CARTO layer
const airbnbDataset = new carto.source.SQL(query),
airbnbStyle = new carto.style.CartoCSS(style),
airbnbLayer = new carto.layer.Layer(airbnbDataset, airbnbStyle);
// Listen for metadata changes
airbnbLayer.on('metadataChanged', metadata => {
histogram.setMetadata(metadata);
histogram.render();
});
client.addLayer(airbnbLayer);
client.getLeafletLayer().addTo(map);
// get histogram dataview
const histogramDataview = new carto.dataview.Histogram(airbnbDataset, 'price', { bins: 7 });
// Create an histogram widget
const histogram = new HistogramWidget();
// When the data is changed render the histogram
histogramDataview.on('dataChanged', data => {
histogram.render(data);
});
client.addDataview(histogramDataview);
const bboxFilter = new carto.filter.BoundingBoxLeaflet(map);
histogramDataview.addFilter(bboxFilter);
}
// create HistogramWidget function
function HistogramWidget() {
this.metadata = { colors: ['red'] }
this.element = document.getElementById("chart").getContext("2d");
this.options = {
legend: {
display: false,
},
title: {
display: true,
text: 'Average price ($)',
position: 'bottom',
},
scales: {
yAxes: [{
barPercentage: 0.2,
gridLines: {
display: false,
}
}],
xAxes: [{
barPercentage: 1,
gridLines: {
display: false,
}
}]
},
elements: {
rectangle: {
borderSkipped: 'left',
}
}
};
}
// get colors
HistogramWidget.prototype.setMetadata = function (metadata) {
this.metadata.colors = metadata.styles[0]._buckets.map(element => element.value);
}
// render data
HistogramWidget.prototype.render = function (data) {
if (!data) {
return this._lastData && this.render(this._lastData);
}
this._lastData = data;
const bins = data.bins;
const labels = data.bins.map(bin => Math.round(bin.avg));
const frequencies = data.bins.map(bin => bin.freq);
new Chart(this.element, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Total',
data: frequencies,
backgroundColor: this.metadata.colors,
borderWidth: 0
}]
},
options: this.options,
});
}
window.onload = main;
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment