Hi Everett,
Thanks for getting back to me.
We want to use a map with colour overlays to show per data country, but then show the details in a separate table when a country is clicked.
So I use the modelUpdate method to pass the clicked country back to retool
window.Retool.modelUpdate({ sel_country_iso3: country.iso_3166_1_alpha_3 });
This works and I can then use the value for querying the data; however as this updates the same model that's used for the input to the custom component it causes the whole map to refresh
Model
{
data: {{map_data.value}},
sel_country_iso3: 'AUT',
map_center: [10,50],
map_zoom: 2
}
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Join local JSON data with vector tile geometries</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map canvas {
cursor: crosshair;
}
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
window.Retool.subscribe(function(model) {
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken = '####';
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/light-v11', //light-v11 Globe / light-v10 Projection / outdoors-v12 satellite-streets-v12
//Workaround for retool refreshing updating the data model
//Center and zoom are stored in the model
center: model.map_center,
zoom: model.map_zoom
});
map.on('load', () => {
// Add source for country polygons using the Mapbox Countries tileset
// The polygons contain an ISO 3166 alpha-3 code which can be used to for joining the data
// https://docs.mapbox.com/vector-tiles/reference/mapbox-countries-v1
map.addSource('countries', {
type: 'vector',
url: 'mapbox://mapbox.country-boundaries-v1'
});
// Build a GL match expression that defines the color for every vector tile feature
// Use the ISO 3166-1 alpha 3 code as the lookup key for the country shape
const matchExpressionColor = ['match', ['get', 'iso_3166_1_alpha_3']];
// Calculate color values for each country based on 'hdi' value
for (const row of model.data) {
// Convert the range of data values to a suitable color
const saturation = row['saturation'];
const hue = row['hue'];
const color = `hsl(${hue}, ${saturation}, 50%)`;
matchExpressionColor.push(row['country_iso'], color);
}
// Last value is the default, used where there is no data
matchExpressionColor.push('rgba(0, 0, 0, 0)');
// The mapbox.country-boundaries-v1 tileset includes multiple polygons for some
// countries with disputed borders. The following expression filters the
// map view to show the "US" perspective of borders for disputed countries.
// Other world views are available, for more details, see the documentation
// on the "worldview" feature property at
// https://docs.mapbox.com/data/tilesets/reference/mapbox-countries-v1/#--polygon---worldview-text
const WORLDVIEW = "US";
const worldview_filter = [ "all", [ "any", [ "==", "all", ["get", "worldview"] ], [ "in", WORLDVIEW, ["get", "worldview"] ] ] ];
// Add layer from the vector tile source to create the choropleth
// Insert it below the 'admin-1-boundary-bg' layer in the style
map.addLayer(
{
'id': 'countries-join',
'type': 'fill',
'source': 'countries',
'source-layer': 'country_boundaries',
'paint': {
'fill-color': matchExpressionColor,
'fill-opacity': 0.5
},
'metadata' :{
// 'color-val': matchExpressionColor,
'hello': 'World'
},
'filter': worldview_filter
},
'admin-1-boundary-bg'
);
map.on('mouseover', 'countries-join', function (e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
});
map.on('click', (e) => {
var feat = map.queryRenderedFeatures(e.point, { layers: ['countries-join'] });
var country = feat[0].properties;
// var meta = feat[0].layer.metadata;
// Fix for Kosovo ISO in Mapbox data
// country.find(e => e.iso_3166_1_alpha_3 === 'XKS').iso_3166_1_alpha_3 = 'XKX';
window.Retool.modelUpdate({ sel_country_iso3: country.iso_3166_1_alpha_3 });
//Workaround to store the current view as the above causes retool to refresh
window.Retool.modelUpdate({ map_center: map.getCenter() });
window.Retool.modelUpdate({ map_zoom: map.getZoom() });
});
});
})
</script>
</body>
</html>
Example Map data for setting colours:
[
{
"country_iso": "ABW",
"hue": 180,
"saturation": 0.179
},
{
"country_iso": "AFG",
"hue": 180,
"saturation": 0.463
},
{
"country_iso": "AGO",
"hue": 120,
"saturation": 0.132
},
{
"country_iso": "AIA",
"hue": 180,
"saturation": 0.280
},
{
"country_iso": "ALB",
"hue": 180,
"saturation": 1.209
},
{
"country_iso": "AND",
"hue": 0,
"saturation": 0.100
},
{
"country_iso": "ARE",
"hue": 240,
"saturation": 0.174
},
{
"country_iso": "ARG",
"hue": 180,
"saturation": 0.505
},
{
"country_iso": "ARM",
"hue": 180,
"saturation": 0.497
},
{
"country_iso": "ATG",
"hue": 180,
"saturation": 0.295
},
{
"country_iso": "AUS",
"hue": 180,
"saturation": 0.226
},
{
"country_iso": "AUT",
"hue": 240,
"saturation": 1.605
},
{
"country_iso": "AZE",
"hue": 180,
"saturation": 0.654
}
]