Skip to content

Commit be6d02a

Browse files
authored
deckgl samples (#348)
* deckgl samples * deckgl samples * deckgl samples * Update deckgl samples, gitignore, and fix workflow checks * Update deckgl samples, gitignore, and fix workflow checks * deckgl samples * deckgl samples * deckgl samples * deckgl samples * deckgl samples * deckgl samples
1 parent ccb993b commit be6d02a

27 files changed

+1638
-1
lines changed

.DS_Store

8 KB
Binary file not shown.

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
**/node_modules/
33
**/test-results/
44
samples/.env
5+
.env
56

67
# Ignore dist files generated by build.
78
samples/*/dist/
@@ -19,3 +20,8 @@ firebase-debug.log
1920

2021
# Ignore all gha-creds-*.json files
2122
gha-creds-*.json
23+
samples/deckgl-editable-geojson
24+
samples/deckgl-kml-raster
25+
26+
/dist/
27+
.env

samples/app.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ cp "${SCRIPT_DIR}/${NAME}/style.css" "${APP_DIR}/style.css"
3030
cp "${SCRIPT_DIR}/${NAME}/package.json" "${APP_DIR}/package.json"
3131
cp "${SCRIPT_DIR}/${NAME}/tsconfig.json" "${APP_DIR}/tsconfig.json"
3232
cp "${SCRIPT_DIR}/${NAME}/README.md" "${APP_DIR}/README.md"
33-
cp "${SCRIPT_DIR}/.env" "${APP_DIR}/.env"
3433

3534
# Generate .eslintsrc.json
3635
touch "${APP_DIR}/.eslintsrc.json"

samples/deckgl-heatmap/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Google Maps JavaScript Sample
2+
3+
This sample is generated from @googlemaps/js-samples located at
4+
https://github.com/googlemaps-samples/js-api-samples.
5+
6+
## Setup
7+
8+
### Before starting run:
9+
10+
`$npm i`
11+
12+
### Run an example on a local web server
13+
14+
First `cd` to the folder for the sample to run, then:
15+
16+
`$npm start`
17+
18+
### Build an individual example
19+
20+
From `samples/`:
21+
22+
`$npm run build --workspace=sample-name/`
23+
24+
### Build all of the examples.
25+
26+
From `samples/`:
27+
`$npm run build-all`
28+
29+
## Feedback
30+
31+
For feedback related to this sample, please open a new issue on
32+
[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues).

samples/deckgl-heatmap/index.html

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<!doctype html>
2+
<!--
3+
@license
4+
Copyright 2019 Google LLC. All Rights Reserved.
5+
SPDX-License-Identifier: Apache-2.0
6+
-->
7+
<html>
8+
<head>
9+
<title>deck.gl HeatmapLayer and Google Maps Platform</title>
10+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
11+
12+
<!-- Use Material Design Progress indicator -->
13+
<link
14+
href="https://unpkg.com/[email protected]/dist/material-components-web.css"
15+
rel="stylesheet"
16+
/>
17+
<script src="https://unpkg.com/[email protected]/dist/material-components-web.min.js"></script>
18+
<script src="https://unpkg.com/[email protected]/dist.min.js"></script>
19+
<script src="https://unpkg.com/@deck.gl/[email protected]/dist.min.js"></script>
20+
21+
<link rel="stylesheet" href="style.css">
22+
23+
<script type="module" src="index.js" defer></script>
24+
</head>
25+
<body>
26+
<div
27+
role="progressbar"
28+
class="mdc-linear-progress"
29+
aria-label="Data Progress Bar"
30+
>
31+
<div class="mdc-linear-progress__buffer">
32+
<div class="mdc-linear-progress__buffer-bar"></div>
33+
<div class="mdc-linear-progress__buffer-dots"></div>
34+
</div>
35+
<div class="mdc-linear-progress__bar mdc-linear-progress__primary-bar">
36+
<span class="mdc-linear-progress__bar-inner"></span>
37+
</div>
38+
<div class="mdc-linear-progress__bar mdc-linear-progress__secondary-bar">
39+
<span class="mdc-linear-progress__bar-inner"></span>
40+
</div>
41+
</div>
42+
<script>
43+
var progress, progressDiv;
44+
progressDiv = document.querySelector(".mdc-linear-progress");
45+
progress = new mdc.linearProgress.MDCLinearProgress(progressDiv);
46+
progress.open();
47+
progress.determinate = false;
48+
progress.done = function () {
49+
progress.close();
50+
progressDiv.remove();
51+
};
52+
</script>
53+
54+
<h1>Bike Parking Heatmap</h1>
55+
56+
<div id="map"></div>
57+
58+
<div id="legend">
59+
<h4>Bike Parking Spaces</h4>
60+
<div><span style="background-color: #ffffe5;"></span>0 - 33</div>
61+
<div><span style="background-color: #ffffb2;"></span>34 - 66</div>
62+
<div><span style="background-color: #fecc5c;"></span>67 - 100</div>
63+
<div><span style="background-color: #fd8d3c;"></span>101 - 133</div>
64+
<div><span style="background-color: #f03b20;"></span>134 - 166</div>
65+
<div><span style="background-color: #bd0026;"></span>167+</div>
66+
</div>
67+
68+
<button id="toggleButton">Hide Heatmap Layer</button>
69+
70+
<script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
71+
({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});</script>
72+
73+
</body>
74+
</html>

samples/deckgl-heatmap/index.ts

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* @license
3+
* Copyright 2025 Google LLC. All Rights Reserved.
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
// Declare global namespace for Deck.gl to satisfy TypeScript compiler
8+
declare namespace deck {
9+
class HeatmapLayer {
10+
constructor(props: any);
11+
props: any;
12+
clone(props: any): HeatmapLayer;
13+
pickable: boolean; // Added pickable property
14+
}
15+
class GoogleMapsOverlay {
16+
constructor(props: any);
17+
setMap(map: google.maps.Map | null): void;
18+
setProps(props: any): void;
19+
}
20+
// Add other Deck.gl types used globally if needed
21+
}
22+
23+
24+
// Initialize and add the map
25+
let map: google.maps.Map;
26+
// Use global types for Deck.gl components
27+
let heatmapLayer: deck.HeatmapLayer;
28+
let googleMapsOverlay: deck.GoogleMapsOverlay;
29+
let marker: google.maps.marker.AdvancedMarkerElement | undefined;
30+
let infoWindow: google.maps.InfoWindow;
31+
32+
async function initMap(): Promise<void> {
33+
// Progress bar logic moved from index.html
34+
var progress, progressDiv = document.querySelector(".mdc-linear-progress");
35+
if (progressDiv) {
36+
// Assuming 'mdc' is globally available, potentially loaded via a script tag
37+
// If not, you might need to import it or add type definitions.
38+
// @ts-ignore
39+
progress = new mdc.linearProgress.MDCLinearProgress(progressDiv as HTMLElement);
40+
progress.open();
41+
progress.determinate = false;
42+
progress.done = function () {
43+
progress.close();
44+
progressDiv?.remove(); // Use optional chaining in case progressDiv is null
45+
};
46+
}
47+
48+
49+
// The location for the map center.
50+
const position = {lat:37.77325660358167, lng:-122.41712341793448}; // Using the center from original deckgl-polygon.js
51+
52+
// Request needed libraries.
53+
const {Map, InfoWindow} =
54+
await google.maps.importLibrary('maps') as google.maps.MapsLibrary;
55+
const {AdvancedMarkerElement} = await google.maps.importLibrary('marker') as google.maps.MarkerLibrary;
56+
57+
const mapDiv = document.getElementById('map');
58+
if (!mapDiv) {
59+
console.error('Map element not found!');
60+
return;
61+
}
62+
63+
// The map, centered at the specified position
64+
map = new Map(mapDiv, {
65+
zoom: 13, // Using the zoom from original deckgl-polygon.js
66+
center: position,
67+
tilt: 90, // Add tilt
68+
heading: -25, // Add heading
69+
mapId: '6b73a9fe7e831a00',
70+
fullscreenControl: false, // Disable fullscreen control
71+
clickableIcons: false, // Disable clicks on base map POIs
72+
});
73+
74+
// Deck.gl Layer and Overlay
75+
// Use global deck object
76+
heatmapLayer = new deck.HeatmapLayer({ // Assign to the outer heatmapLayer
77+
id: 'HeatmapLayer', // Change layer ID
78+
data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/sf-bike-parking.json', // Use the loaded data
79+
getPosition: (d: any) => d.COORDINATES, // Use 'any' for simplicity, or define a proper type
80+
getWeight: (d: any) => d.SPACES, // Use 'any' for simplicity, or define a proper type
81+
radiusPixels: 25, // Adjust radius as in user's example
82+
83+
visible: true,
84+
pickable: true,
85+
onHover: (info: any) => { // Use 'any' for info for simplicity, or define a proper type
86+
const tooltip = document.getElementById('tooltip');
87+
if (tooltip) {
88+
console.log('Hovered object:', info.object);
89+
if (info.object) {
90+
// Format data for tooltip (display ADDRESS, RACKS, SPACES)
91+
let tooltipContent = '<h4>Bike Parking Info:</h4>'; // Updated title
92+
if (info.object.ADDRESS !== undefined) {
93+
tooltipContent += `<strong>Address:</strong> ${info.object.ADDRESS}<br>`;
94+
}
95+
if (info.object.RACKS !== undefined) {
96+
tooltipContent += `<strong>Racks:</strong> ${info.object.RACKS}<br>`;
97+
}
98+
if (info.object.SPACES !== undefined) {
99+
tooltipContent += `<strong>Spaces:</strong> ${info.object.SPACES}<br>`;
100+
}
101+
tooltip.innerHTML = tooltipContent;
102+
tooltip.style.left = info.x + 'px';
103+
tooltip.style.top = info.y + 'px';
104+
tooltip.style.display = 'block';
105+
} else {
106+
tooltip.style.display = 'none';
107+
}
108+
console.log('Tooltip content set to:', tooltip.innerHTML);
109+
}
110+
}
111+
});
112+
113+
heatmapLayer.pickable = true; // Ensure pickable is true after creation
114+
115+
// Use global deck object
116+
googleMapsOverlay = new deck.GoogleMapsOverlay({ // Assign to the outer googleMapsOverlay
117+
layers: [heatmapLayer],
118+
controller: true // Enable Deck.gl to control map view
119+
});
120+
121+
googleMapsOverlay.setMap(map);
122+
123+
// Hide progress bar after data is loaded and layer is added
124+
if (progress) { // Check if progress is defined
125+
// Add a small delay to ensure the progress bar is removed
126+
setTimeout(() => {
127+
// @ts-ignore
128+
progress.done(); // hides progress bar
129+
}, 100); // 100ms delay
130+
}
131+
132+
// Create a single InfoWindow instance
133+
infoWindow = new InfoWindow();
134+
135+
// Add click listener to the map
136+
map.addListener('click', async (event: google.maps.MapMouseEvent) => {
137+
const latLng = event.latLng;
138+
if (!latLng) return; // Ensure latLng is not null
139+
140+
if (!marker) {
141+
// Create the marker on the first click
142+
marker = new AdvancedMarkerElement({
143+
map: map,
144+
position: latLng,
145+
gmpClickable: true,
146+
});
147+
148+
// Add click listener to the marker
149+
marker.addListener("click", () => {
150+
infoWindow.close();
151+
const content = `
152+
<div>Location: ${latLng.lat().toFixed(3)}, ${latLng.lng().toFixed(3)}</div>
153+
<div><a href="https://www.google.com/maps/search/?api=1&query=${latLng.lat()},${latLng.lng()}" target="_blank">Open in Google Maps</a></div>
154+
`;
155+
infoWindow.setContent(content);
156+
infoWindow.open(map, marker);
157+
});
158+
159+
// Open InfoWindow immediately on first click
160+
const content = `
161+
<div>Location: ${latLng.lat().toFixed(3)}, ${latLng.lng().toFixed(3)}</div>
162+
<div><a href="https://www.google.com/maps/search/?api=1&query=${latLng.lat()},${latLng.lng()}" target="_blank">Open in Google Maps</a></div>
163+
`;
164+
infoWindow.setContent(content);
165+
infoWindow.open(map, marker);
166+
167+
168+
} else {
169+
// Move the existing marker on subsequent clicks
170+
marker.position = latLng;
171+
// InfoWindow remains open
172+
const content = `
173+
<div>Location: ${latLng.lat().toFixed(3)}, ${latLng.lng().toFixed(3)}</div>
174+
<div><a href="https://www.google.com/maps/search/?api=1&query=${latLng.lat()},${latLng.lng()}" target="_blank">Open in Google Maps</a></div>
175+
`;
176+
infoWindow.setContent(content);
177+
infoWindow.open(map, marker);
178+
}
179+
});
180+
181+
182+
// Button functionality
183+
const toggleButton = document.getElementById('toggleButton');
184+
if (toggleButton) { // Check if toggleButton is found
185+
toggleButton.addEventListener('click', () => {
186+
const currentVisible = heatmapLayer.props.visible;
187+
// Create a new layer instance with toggled visibility and update the overlay
188+
const newLayer = heatmapLayer.clone({ visible: !currentVisible });
189+
googleMapsOverlay.setProps({
190+
layers: [newLayer]
191+
});
192+
heatmapLayer = newLayer; // Update the heatmapLayer variable
193+
194+
toggleButton.textContent = !currentVisible ? 'Hide Heatmap Layer' : 'Show Heatmap Layer';
195+
});
196+
}
197+
}
198+
199+
initMap();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "@js-api-samples/deckgl-heatmap",
3+
"version": "1.0.0",
4+
"scripts": {
5+
"build": "tsc && bash ../jsfiddle.sh deckgl-heatmap && bash ../app.sh deckgl-heatmap && bash ../docs.sh deckgl-heatmap && npm run build:vite --workspace=. && bash ../dist.sh deckgl-heatmap",
6+
"test": "tsc && npm run build:vite --workspace=.",
7+
"start": "tsc && vite build --base './' && vite",
8+
"build:vite": "vite build --base './'",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
13+
}
14+
}

0 commit comments

Comments
 (0)