Skip to content

Commit

Permalink
Disable download button and show tooltip at low zoom levels. [#37 #59] (
Browse files Browse the repository at this point in the history
#63)

* Added zoom state to disable downloads at low zooms

* added a simple floater when hovering over disabled button

* Added proper tooltip message and simple styling

* Download button is properly dis/enabled when page refreshes

* Added overturemaps-py shoutout

* Show tooltip on diabled button click

---------

Co-authored-by: ethaniannicelli <eti7075@rit.edu>
  • Loading branch information
eti7075 and ethaniannicelli authored Jun 7, 2024
1 parent 47d169b commit e057b29
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 22 deletions.
64 changes: 64 additions & 0 deletions site/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"pmtiles": "^3.0.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-floater": "^0.9.3",
"react-map-gl": "^7.1.7"
},
"devDependencies": {
Expand Down
11 changes: 9 additions & 2 deletions site/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ import { useState, useEffect } from "react";

function App() {
const [modeName, setModeName] = useState("theme-dark");
const [zoom, setZoom] = useState(0);

useEffect(() => {
keepTheme(setModeName);
}, [setModeName]);

return (
<MapProvider>
<Header mode={modeName} setMode={setModeName} />
<Map mode={modeName} />
<Header
mode={modeName}
setMode={setModeName}
zoom={zoom}
setZoom={setZoom}
/>
<Map mode={modeName} setZoom={setZoom} />
<Footer mode={modeName} />
</MapProvider>
);
}
Expand Down
10 changes: 9 additions & 1 deletion site/src/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import "maplibre-gl/dist/maplibre-gl.css";
import * as pmtiles from "pmtiles";
import maplibregl from "maplibre-gl";

import { useState, useEffect, useCallback, useRef } from "react";
import { Layer, GeolocateControl } from "react-map-gl/maplibre";
import InspectorPanel from "./InspectorPanel";
Expand Down Expand Up @@ -133,7 +134,7 @@ ThemeTypeLayer.propTypes = {
extrusion: PropTypes.bool,
};

export default function Map({ mode }) {
export default function Map({ mode, setZoom }) {
const mapRef = useRef();
const [cursor, setCursor] = useState("auto");
const [mapEntity, setMapEntity] = useState({});
Expand All @@ -144,6 +145,7 @@ export default function Map({ mode }) {
useEffect(() => {
const protocol = new pmtiles.Protocol();
maplibregl.addProtocol("pmtiles", protocol.tile);

return () => {
maplibregl.removeProtocol("pmtiles");
};
Expand Down Expand Up @@ -173,6 +175,10 @@ export default function Map({ mode }) {
}
}, []);

const handleZoom = (event) => {
setZoom(event.target.getZoom());
};

return (
<>
<div className={`map ${mode}`}>
Expand All @@ -185,6 +191,7 @@ export default function Map({ mode }) {
onClick={onClick}
cursor={cursor}
hash={true}
onZoom={handleZoom}
mapStyle={MAP_STYLE}
interactiveLayerIds={interactiveLayerIds}
initialViewState={INITIAL_VIEW_STATE}
Expand Down Expand Up @@ -318,6 +325,7 @@ export default function Map({ mode }) {
{Object.keys(mapEntity).length > 0 && (
<InspectorPanel entity={mapEntity} />
)}

<ThemeSelector visibleThemes={setVisibleThemes}></ThemeSelector>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions site/src/nav/DownloadButton.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@ svg.icon-refresh > path.secondary {
div.download-text {
padding-left: 1px;
}

div.download-zoom-tip {
border-radius: 10px;
}
88 changes: 71 additions & 17 deletions site/src/nav/DownloadButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ import {
import downloadIcon from "/download.svg";
import RefreshIcon from "../icons/icon-refresh.svg?react";
import "./DownloadButton.css";
import Floater from "react-floater";

function DownloadButton() {
const ZOOM_BOUND = 16;

function DownloadButton({ mode, zoom, setZoom }) {
const { myMap } = useMap();

const [loading, setLoading] = useState(false);
const [showFloater, setShowFloater] = useState(false);

useEffect(() => {
if (myMap) {
myMap.getBounds();
setZoom(myMap.getZoom());
}
}, [myMap]);

Expand Down Expand Up @@ -81,25 +86,74 @@ function DownloadButton() {
setLoading(false);
};

const handleToggleTooltip = () => {
if (zoom < ZOOM_BOUND) {
setShowFloater(!showFloater);
}
};

return (
<div className="button--download">
<button
className={`button button--primary ${loading ? "disabled" : ""}`}
onClick={handleDownloadClick}
>
<div className="wrapper">
<div className="download-icon">
{!loading ? (
<img className={"dl-img"} src={downloadIcon} />
) : (
<RefreshIcon />
)}
<div>
<Floater
styles={{
container: {
borderRadius: "10px",
padding: "10px",
color: mode === "theme-dark" ? "white" : "black",
fontSize: ".7rem",
background:
mode === "theme-dark"
? "var(--ifm-navbar-background-color)"
: "var(--ifm-color-secondary-light)",
},
arrow: {
color:
mode === "theme-dark"
? "var(--ifm-navbar-background-color)"
: "var(--ifm-color-secondary-light)",
},
}}
content={
<div>
The download button is disabled at zoom levels below {ZOOM_BOUND}.
This is done to prevent downloading large amounts of data. To
reenable the button, zoom further in. If you wish to download a
larger area of data points, consider using our python installer,
found at{" "}
<a
href={"https://github.com/OvertureMaps/overturemaps-py"}
target="_blank"
rel="noreferrer noopener"
>
our git repository
</a>
.
</div>
<div className="download-text">
{loading ? "Downloading..." : "Download Visible"}
}
open={showFloater}
target={".button--download"}
/>
<div className="button--download" onMouseDown={handleToggleTooltip}>
<button
className={`button button--primary ${
loading || zoom < ZOOM_BOUND ? "disabled" : ""
}`}
onClick={handleDownloadClick}
>
<div className="wrapper">
<div className="download-icon">
{!loading ? (
<img className={"dl-img"} src={downloadIcon} />
) : (
<RefreshIcon />
)}
</div>
<div className="download-text">
{loading ? "Downloading..." : "Download Visible"}
</div>
</div>
</div>
</button>
</button>
</div>
</div>
);
}
Expand Down
4 changes: 2 additions & 2 deletions site/src/nav/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import OvertureWordmark from "./OvertureWordmark";
import DarkModeToggle from "./DarkModeToggle";
import PropTypes from "prop-types";

export default function Header({ mode, setMode }) {
export default function Header({ zoom, mode, setMode, setZoom }) {
return (
<nav aria-label="Main" className="navbar navbar--fixed-top">
<div className="navbar__inner">
Expand All @@ -12,7 +12,7 @@ export default function Header({ mode, setMode }) {
</div>
<div className="navbar__items navbar__items--right">
<DarkModeToggle mode={mode} setMode={setMode} />
<DownloadButton />
<DownloadButton zoom={zoom} mode={mode} setZoom={setZoom} />
</div>
</div>
</nav>
Expand Down

0 comments on commit e057b29

Please sign in to comment.