CartoLayer + Widget autorefresh
by VictorVelarde
HTML
<!DOCTYPE html>
<html>
<head>
<title>Auto refresh</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<script src="https://unpkg.com/@deck.gl/carto@latest/dist.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/[email protected]/dist/maplibre-gl.css" rel="stylesheet" />
<script src="https://unpkg.com/[email protected]/dist/html2canvas.min.js"></script>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
</head>
<body>
<div id="map">
<div id="basemap"></div>
</div>
<div class="loading-container">
<div id="loading-info">Loading data...</div>
<div id="spinner" class="spinner">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div id="widgets">
<div id="global-widget"></div>
<div id="viewport-widget"></div>
</div>
</div>
</body>
</html>
CSS
body {
margin: 0;
padding: 0;
}
#map {
position: relative;
width: 100vw;
height: 100vh;
z-index: 1;
}
#basemap {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.loading-container {
position: absolute;
top: 10px;
left: 10px;
height: 24px;
z-index: 100;
background: white;
border-radius: 24px;
box-shadow: rgba(0, 0, 0, 0.2) 1px 1px 5px;
}
#loading-info {
float: right;
margin: 4px 12px;
color: #2e71ff;
font-family: sans-serif;
font-size: 14px;
}
.spinner {
display: inline-block;
position: relative;
top: 0;
z-index: 100;
width: 20px;
height: 20px;
transition: opacity 0.3s ease-in-out;
}
.spinner div {
box-sizing: border-box;
display: inline-block;
position: absolute;
width: 16px;
height: 16px;
margin: 4px;
border: 2px solid #fff;
border-radius: 50%;
animation: spinner 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #2e71ff transparent transparent transparent;
box-shadow: 2px black;
}
.spinner div:nth-child(1) {
animation-delay: -0.45s;
}
.spinner div:nth-child(2) {
animation-delay: -0.3s;
}
.spinner div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
JavaScript
const accessToken = 'xxxx-update---';
deck.carto.setDefaultCredentials({
apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
accessToken
});
const spinner = document.getElementById('spinner');
const loadingInfo = document.getElementById('loading-info');
const globalWidget = document.getElementById('global-widget');
const viewportWidget = document.getElementById('viewport-widget');
let currentViewport
const deckgl = new deck.DeckGL({
container: "basemap",
map: maplibregl,
mapStyle: deck.carto.BASEMAP.VOYAGER,
initialViewState: {
latitude: 40,
longitude: -80,
zoom: 3
},
controller: true,
onViewStateChange: ({
viewState
}) => {
const bounds = new deck.WebMercatorViewport(viewState).getBounds()
currentViewport = turf.bboxPolygon(bounds)
console.log(currentViewport)
}
});
function renderLayer(data) {
return new deck.carto._CartoTileLayer({
data,
getFillColor: [238, 77, 90],
pointRadiusMinPixels: 2.5,
loadOptions: {
fetch: {
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
}
});
}
let previousUpdate = null;
const dataSource = {
connection: 'bqconn-front',
type: 'query',
source: 'SELECT * FROM `cartodb-on-gcp-frontend-team.victor.airports_enriched`'
}
async function fetchLayerData() {
const {
data
} = await deck.carto.fetchLayerData({
...dataSource,
format: 'tilejson',
headers: {
'Cache-Control': 'max-age=60'
}
})
const lastCache = (new URL(data.tiles)).searchParams.get('cache');
const lastUpdate = new Date(parseInt(lastCache));
console.log('last cache check: ', lastCache)
return {
tileJson: data.tiles,
lastUpdate
}
}
async function fetchData() {
spinner.style.opacity = 1;
const {
tileJson,
lastUpdate
} = await fetchLayerData()
if (previousUpdate < lastUpdate) {
previousUpdate = lastUpdate;
updateUI({
tileJson,
lastUpdate
})
}
...