{
let container = html`<div style='height:600px;' />`;
yield container;
let map = new mapboxgl.Map({
container,
center: [13.7964765, 25.7144583],
zoom: 2,
maxZoom: 20,
style: "mapbox://styles/mapbox/" + style,
projection: { name: projection },
scrollZoom: true,
cooperativeGestures: true
});
map.on("load", () => {
map.setFog({});
map.loadImage(
"https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png",
(error, image) => {
if (error) throw error;
map.addImage("custom-marker", image);
map.addSource("points", {
type: "geojson",
data: gischat_twitter_user_locs
});
map.addLayer({
id: "points",
type: "symbol",
source: "points",
layout: {
"icon-image": "custom-marker",
"icon-size": [
"interpolate",
["linear"],
["zoom"],
0,
0.1,
3,
0.3,
5,
0.4,
7,
0.7,
10,
0.8,
12,
1
],
"icon-allow-overlap": true
// get the title name from the source's "title" property
// "text-field": ["get", "username"],
// "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
// "text-offset": [0, 1.25],
// "text-anchor": "top"
}
});
const popups = [];
const mouseEnter = (e) => {
//clear existing popups
popups.forEach((p) => p.remove());
popups.length = 0;
const coordinates = e.features[0].geometry.coordinates.slice();
let description = "";
e.features.forEach((f) => {
const props = f.properties;
description += `
<div style="display:flex">
<div style="flex:1; max-width:50px;">
<img src="${props.profile_image_url}" class="profile"/>
</div>
<div style="flex:1">
<strong>${props.name}</strong> <a href="https://www.twitter.com/${props.username}" target="_blank">@${props.username}</a> · <br/>
${props.location}
</div>
</div>
`;
});
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
const popup = new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
popups.push(popup);
};
map.on("mouseenter", "points", mouseEnter);
// Change the cursor to a pointer when the mouse is over the places layer.
map.on("mouseenter", "points", () => {
map.getCanvas().style.cursor = "pointer";
});
// Change it back to a pointer when it leaves.
map.on("mouseleave", "points", () => {
map.getCanvas().style.cursor = "";
});
if ("ontouchstart" in document.documentElement) {
// content for touch-screen (mobile) devices
map.on("click", "points", mouseEnter);
}
}
);
});
map.addControl(new mapboxgl.NavigationControl(), "top-right");
//Make it spin
// At low zooms, complete a revolution every two minutes.
const secondsPerRevolution = 90;
// Above zoom level 5, do not rotate.
const maxSpinZoom = 5;
// Rotate at intermediate speeds between zoom levels 3 and 5.
const slowSpinZoom = 3;
let userInteracting = false;
let spinEnabled = true;
let spinTimeout = 0;
function spinGlobe() {
const zoom = map.getZoom();
// console.log(autoSpin);
if (spinEnabled && !userInteracting && zoom < maxSpinZoom && autoSpin) {
let distancePerSecond = 360 / secondsPerRevolution;
if (zoom > slowSpinZoom) {
// Slow spinning at higher zooms
const zoomDif = (maxSpinZoom - zoom) / (maxSpinZoom - slowSpinZoom);
distancePerSecond *= zoomDif;
}
const center = map.getCenter();
center.lng += distancePerSecond;
// Smoothly animate the map over one second.
// When this animation is complete, it calls a 'moveend' event.
map.easeTo({ center, duration: 1000, easing: (n) => n });
setTimeout(() => {
spinGlobe();
}, 1000);
}
}
function delayedSpinGlobe() {
clearTimeout(spinTimeout);
spinTimeout = setTimeout(() => {
spinGlobe();
}, 3000);
}
// Pause spinning on interaction
map.on("mousedown", () => {
userInteracting = true;
});
map.on("zoomstart", () => {
userInteracting = true;
});
// Restart spinning the globe when interaction is complete
map.on("mouseup", () => {
userInteracting = false;
delayedSpinGlobe();
});
// These events account for cases where the mouse has moved
// off the map, so 'mouseup' will not be fired.
map.on("dragend", () => {
userInteracting = false;
delayedSpinGlobe();
});
map.on("pitchend", () => {
userInteracting = false;
delayedSpinGlobe();
});
map.on("rotateend", () => {
userInteracting = false;
delayedSpinGlobe();
});
map.on("zoomend", () => {
userInteracting = false;
delayedSpinGlobe();
});
// // When animation is complete, start spinning if there is no ongoing interaction
// map.on("moveend", () => {
// delayedSpinGlobe();
// });
//make it spin on startup
spinGlobe();
// Be careful to clean up the map's resources using \`map.remove()\` whenever?
// this cell is re-evaluated.
invalidation.then(() => map.remove());
}