Skip to content

Commit f09eb8f

Browse files
committed
initial h3 widgets example
1 parent 14d9c6e commit f09eb8f

File tree

5 files changed

+91
-13
lines changed

5 files changed

+91
-13
lines changed

h3-widgets/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
VITE_API_BASE_URL=https://gcp-us-east1.api.carto.com
33
# This API Access Token only grants access to demo data for the examples. Replace it with your own token.
44
# Go to app.carto.com -> Developers -> Credentials -> API Access Tokens.
5-
VITE_API_ACCESS_TOKEN=eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfbHFlM3p3Z3UiLCJqdGkiOiJkOTU4OWMyZiJ9.78MdzU2J6y-J6Far71_Mh7IQO9eYIZD9nECUiZJAVL4
5+
VITE_API_ACCESS_TOKEN=eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfNDd1dW5tZWciLCJqdGkiOiIxZDUxNjZjYiJ9.lclEIXHEr8neSmWFGr7vGaBBNSmuMntWJLqGjfdYclk

h3-widgets/index.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<div id="top-left">
1111
<div id="story-card">
1212
<p class="overline">✨👀 You're viewing</p>
13-
<h2>CARTO Spatial Features datasets in H3 (12M rows).</h2>
13+
<h2>CARTO Widgets for H3 (12M rows).</h2>
1414
<p>
1515
More info about
1616
<a
@@ -41,10 +41,15 @@ <h2>CARTO Spatial Features datasets in H3 (12M rows).</h2>
4141
</div>
4242

4343
<div class="widgets">
44-
<div class="formula-widget">
44+
<div class="widget formula-widget">
4545
<p class="overline">Total Population</p>
4646
<div id="formula-data"></div>
4747
</div>
48+
<div class="widget histogram-widget relative">
49+
<p class="overline">Urbanity categories</p>
50+
<p class="loader hidden">Loading...</p>
51+
<canvas id="histogram-data" height="300px"></canvas>
52+
</div>
4853
</div>
4954
</div>
5055
</div>

h3-widgets/index.ts

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,22 @@ import {Deck, MapViewState} from '@deck.gl/core';
55
import {H3TileLayer, BASEMAP, colorBins} from '@deck.gl/carto';
66
import { initSelectors } from './selectorUtils';
77
import { debounce, getSpatialFilterFromViewState } from './utils';
8-
import { h3QuerySource } from '@carto/api-client'
8+
import { h3QuerySource, WidgetSource } from '@carto/api-client'
9+
import Chart from 'chart.js/auto';
910

1011
const cartoConfig = {
12+
// @ts-expect-error misconfigured env variables
1113
apiBaseUrl: import.meta.env.VITE_API_BASE_URL,
14+
// @ts-expect-error misconfigured env variables
1215
accessToken: import.meta.env.VITE_API_ACCESS_TOKEN,
1316
connectionName: 'carto_dw'
1417
};
1518

1619
const INITIAL_VIEW_STATE: MapViewState = {
17-
latitude: 40.7128, // New York
18-
longitude: -74.006, // New York
19-
zoom: 7,
20+
// Spain
21+
latitude: 37.3753636,
22+
longitude: -5.9962577,
23+
zoom: 6,
2024
pitch: 0,
2125
bearing: 0,
2226
minZoom: 3.5,
@@ -36,6 +40,9 @@ let viewState = INITIAL_VIEW_STATE
3640
const variableSelector = document.getElementById('variable') as HTMLSelectElement;
3741
const aggMethodLabel = document.getElementById('agg-method') as HTMLSelectElement;
3842
const formulaWidget = document.getElementById('formula-data') as HTMLDivElement;
43+
const categoriesWidget = document.getElementById('categories-data') as HTMLCanvasElement;
44+
const histogramWidget = document.getElementById('histogram-data') as HTMLCanvasElement;
45+
let histogramChart: Chart;
3946

4047
aggMethodLabel.innerText = aggregationExp;
4148
variableSelector?.addEventListener('change', () => {
@@ -51,8 +58,8 @@ variableSelector?.addEventListener('change', () => {
5158
function render() {
5259
source = h3QuerySource({
5360
...cartoConfig,
54-
aggregationExp: `${aggregationExp} as value`,
55-
sqlQuery: `SELECT * FROM cartobq.public_account.derived_spatialfeatures_usa_h3int_res8_v1_yearly_v2`
61+
aggregationExp: `${aggregationExp} as value`,
62+
sqlQuery: `SELECT * FROM carto-demo-data.demo_tables.derived_spatialfeatures_esp_h3res8_v1_yearly_v2`
5663
});
5764
renderLayers();
5865
renderWidgets();
@@ -91,15 +98,61 @@ function renderLayers() {
9198
}
9299

93100
async function renderWidgets() {
94-
formulaWidget.innerHTML = '<span style="font-weight: 400; font-size: 14px;">Loading...</span>'
95101
const { widgetSource } = await source
96-
const formula = await widgetSource.getFormula({
102+
await Promise.all([
103+
renderFormula(widgetSource),
104+
renderHistogram(widgetSource)
105+
])
106+
}
107+
108+
async function renderFormula(ws: WidgetSource) {
109+
formulaWidget.innerHTML = '<span style="font-weight: 400; font-size: 14px;">Loading...</span>'
110+
const formula = await ws.getFormula({
97111
column: selectedVariable,
112+
operation: 'sum',
113+
spatialFilter: getSpatialFilterFromViewState(viewState),
114+
viewState,
115+
})
116+
formulaWidget.textContent = Intl.NumberFormat('en-US', {
117+
maximumFractionDigits: 0,
118+
// notation: 'compact'
119+
}).format(formula.value)
120+
}
121+
122+
const TICKS = [100, 500, 1000, 5000];
123+
124+
async function renderHistogram(ws: WidgetSource) {
125+
histogramWidget.parentElement?.querySelector('.loader')?.classList.toggle('hidden', false);
126+
histogramWidget.classList.toggle('hidden', true);
127+
128+
const categories = await ws.getCategories({
129+
column: 'urbanity',
98130
operation: 'count',
99131
spatialFilter: getSpatialFilterFromViewState(viewState),
100132
viewState,
101133
})
102-
formulaWidget.textContent = Intl.NumberFormat('en-US').format(formula.value)
134+
135+
histogramWidget.parentElement?.querySelector('.loader')?.classList.toggle('hidden', true);
136+
histogramWidget.classList.toggle('hidden', false);
137+
138+
if (histogramChart) {
139+
histogramChart.data.labels = categories.map((c) => c.name);
140+
histogramChart.data.datasets[0].data = categories.map((c) => c.value);
141+
histogramChart.update();
142+
} else {
143+
histogramChart = new Chart(histogramWidget, {
144+
type: 'bar',
145+
data: {
146+
labels: categories.map((c) => c.name),
147+
datasets: [
148+
{
149+
label: 'Urbanity category',
150+
data: categories.map((c) => c.value),
151+
}
152+
]
153+
},
154+
})
155+
}
103156
}
104157

105158
const debouncedRenderWidgets = debounce(renderWidgets, 500);

h3-widgets/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
"vite": "^4.5.0"
1515
},
1616
"dependencies": {
17+
"@carto/api-client": "^0.4.1-alpha.0",
1718
"@deck.gl/aggregation-layers": "^9.0.17",
1819
"@deck.gl/carto": "^9.0.17",
1920
"@deck.gl/core": "^9.0.17",
2021
"@deck.gl/extensions": "^9.0.17",
2122
"@deck.gl/geo-layers": "^9.0.17",
2223
"@deck.gl/layers": "^9.0.17",
2324
"@deck.gl/mesh-layers": "^9.0.17",
25+
"chart.js": "^4.4.7",
2426
"maplibre-gl": "^3.5.2"
2527
}
2628
}

h3-widgets/style.css

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ button:hover {
122122
border: #ccc 1px solid;
123123
}
124124

125-
.widgets {
125+
.widget {
126126
margin: 2rem 0;
127127
}
128128

@@ -131,3 +131,21 @@ button:hover {
131131
font-weight: 600;
132132
font-family: monospace;
133133
}
134+
135+
.relative { position: relative; }
136+
137+
.loader {
138+
font-size: 14px;
139+
font-weight: 400;
140+
141+
position: absolute;
142+
top: 50%;
143+
left: 50%;
144+
transform: translate(-50%, -50%);
145+
opacity: 1;
146+
transition: opacity 0.3s;
147+
}
148+
149+
.hidden {
150+
opacity: 0;
151+
}

0 commit comments

Comments
 (0)