diff --git a/src/components/MapContainer/Controls/ZoomControl.tsx b/src/components/MapContainer/Controls/ZoomControl.tsx new file mode 100644 index 0000000..e76e82a --- /dev/null +++ b/src/components/MapContainer/Controls/ZoomControl.tsx @@ -0,0 +1,22 @@ +import React, { useContext, useEffect } from 'react' +import Zoom from 'ol/control/Zoom' +import MapContext from '../Map/MapContext' + +const ZoomControl: React.FC = () => { + const { map } = useContext(MapContext) + + useEffect(() => { + if (!map.controls) return + + const zoomControl = new Zoom({}) + + // map.controls.push(zoomSliderControl) + map.controls.push(zoomControl) + // eslint-disable-next-line consistent-return + return () => map.controls.remove(zoomControl) + }, [map]) + + return null +} + +export default ZoomControl diff --git a/src/components/MapContainer/Controls/index.tsx b/src/components/MapContainer/Controls/index.tsx index 3a25ff6..8c2c663 100644 --- a/src/components/MapContainer/Controls/index.tsx +++ b/src/components/MapContainer/Controls/index.tsx @@ -1,4 +1,5 @@ import Controls from './Controls' import FullScreenControl from './FullScreenControl' +import ZoomControl from './ZoomControl' -export { Controls, FullScreenControl } +export { Controls, FullScreenControl, ZoomControl } diff --git a/src/components/MapContainer/Layers/TileLayer.tsx b/src/components/MapContainer/Layers/TileLayer.tsx index ba31d11..feed9d7 100644 --- a/src/components/MapContainer/Layers/TileLayer.tsx +++ b/src/components/MapContainer/Layers/TileLayer.tsx @@ -16,6 +16,7 @@ const TileLayer: React.FC = ({ zIndex = 0 }: Props) => { const tileLayer = new OLTileLayer({ source: osm(), + maxZoom: 50, zIndex, }) diff --git a/src/components/MapContainer/Map/Map.tsx b/src/components/MapContainer/Map/Map.tsx index 38dcd82..c1a299c 100644 --- a/src/components/MapContainer/Map/Map.tsx +++ b/src/components/MapContainer/Map/Map.tsx @@ -8,9 +8,21 @@ interface Props { children?: React.ReactNode zoom: number center: number[] + minZoom: number + maxZoom: number + projection: string } -const Map: React.FC = ({ children, zoom, center }: Props) => { +// ol/control/(minresolution, maxresolution) can be added +// if considered necessary in future +const Map: React.FC = ({ + children, + zoom, + center, + maxZoom, + minZoom, + projection, +}: Props) => { const mapRef = useRef() as React.MutableRefObject const [map, setMap] = useState({}) @@ -18,7 +30,13 @@ const Map: React.FC = ({ children, zoom, center }: Props) => { // pass map state into mapcontext for access in layers. useEffect(() => { const options = { - view: new ol.View({ zoom, center }), + view: new ol.View({ + center, + zoom, + minZoom, + maxZoom, + projection, + }), layers: [], controls: [], overlays: [], @@ -29,7 +47,7 @@ const Map: React.FC = ({ children, zoom, center }: Props) => { setMap(mapObject) return () => mapObject.setTarget(undefined) - }, [zoom, center]) + }, [center, zoom, minZoom, maxZoom, projection]) return ( diff --git a/src/components/MapContainer/MapContainer.tsx b/src/components/MapContainer/MapContainer.tsx index 76af9cb..d5be035 100644 --- a/src/components/MapContainer/MapContainer.tsx +++ b/src/components/MapContainer/MapContainer.tsx @@ -3,9 +3,10 @@ import { fromLonLat } from 'ol/proj' import { GoogleSpreadsheet } from 'google-spreadsheet' import Map from './Map' import './contain.css' +import './olmin.css' import config from '../../config/config' import { Layers, TileLayer, VectorLayer, GoogleSheetsLayer } from './Layers' -import { Controls, FullScreenControl } from './Controls' +import { Controls, FullScreenControl, ZoomControl } from './Controls' import orca from './orcapin.png' const doc = new GoogleSpreadsheet(config.spreadsheetId) @@ -14,9 +15,12 @@ doc.useApiKey(config.apiKey) const MapContainer: React.FC = () => { const [coordinates, setCoordinates] = useState([[0, 0]]) const [googleSheetcoordinates, setgoogleSheetcoordinates] = useState([[0, 0]]) - const [zoom, setZoom] = useState(0) + const [zoom, setZoom] = useState(2) const [center, setCenter] = useState([0, 0]) + const [minZoom, setminZoom] = useState(0) + const [maxZoom, setmaxZoom] = useState(1900) const [showLayer, setShowLayer] = useState(true) + const projectionStandard = 'EPSG:3857' useEffect(function effectFunction() { async function loadSpreadsheet() { @@ -34,7 +38,8 @@ const MapContainer: React.FC = () => { ]) setZoom(9) setCenter([-122.4713, 47.7237]) - + setminZoom(0) + setmaxZoom(1900) // TODO: this currently returns a single row from a sheet with 2+ entries, so only one map point is returned from sheets. const rows = await sheet.getRows() @@ -75,7 +80,13 @@ const MapContainer: React.FC = () => {
- + {showLayer && } @@ -83,6 +94,7 @@ const MapContainer: React.FC = () => { +
@@ -98,7 +110,13 @@ const MapContainer: React.FC = () => {
- + {showLayer && ( @@ -111,6 +129,7 @@ const MapContainer: React.FC = () => { +
diff --git a/src/components/MapContainer/olmin.css b/src/components/MapContainer/olmin.css new file mode 100644 index 0000000..a30cd83 --- /dev/null +++ b/src/components/MapContainer/olmin.css @@ -0,0 +1,267 @@ +.ol-box { + box-sizing: border-box; + border-radius: 2px; + border: 2px solid #00f; + } + .ol-mouse-position { + top: 8px; + right: 8px; + position: absolute; + } + .ol-scale-line { + background: rgba(0, 60, 136, 0.3); + border-radius: 4px; + bottom: 8px; + left: 8px; + padding: 2px; + position: absolute; + } + .ol-scale-line-inner { + border: 1px solid #eee; + border-top: none; + color: #eee; + font-size: 10px; + text-align: center; + margin: 1px; + will-change: contents, width; + transition: all 0.25s; + } + .ol-scale-bar { + position: absolute; + bottom: 8px; + left: 8px; + } + .ol-scale-step-marker { + width: 1px; + height: 15px; + background-color: #000; + float: right; + z-index: 10; + } + .ol-scale-step-text { + position: absolute; + bottom: -5px; + font-size: 12px; + z-index: 11; + color: #000; + text-shadow: -2px 0 #fff, 0 2px #fff, 2px 0 #fff, 0 -2px #fff; + } + .ol-scale-text { + position: absolute; + font-size: 14px; + text-align: center; + bottom: 25px; + color: #000; + text-shadow: -2px 0 #fff, 0 2px #fff, 2px 0 #fff, 0 -2px #fff; + } + .ol-scale-singlebar { + position: relative; + height: 10px; + z-index: 9; + box-sizing: border-box; + border: 1px solid #000; + } + .ol-unsupported { + display: none; + } + .ol-unselectable, + .ol-viewport { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + } + .ol-selectable { + -webkit-touch-callout: default; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + } + .ol-grabbing { + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + .ol-grab { + cursor: move; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } + .ol-control { + position: absolute; + background-color: rgba(255, 255, 255, 0.4); + border-radius: 4px; + padding: 2px; + } + .ol-control:hover { + background-color: rgba(255, 255, 255, 0.6); + } + .ol-zoom { + top: 0.5em; + left: 0.5em; + } + .ol-rotate { + top: 0.5em; + right: 0.5em; + transition: opacity 0.25s linear, visibility 0s linear; + } + .ol-rotate.ol-hidden { + opacity: 0; + visibility: hidden; + transition: opacity 0.25s linear, visibility 0s linear 0.25s; + } + .ol-zoom-extent { + top: 4.643em; + left: 0.5em; + } + .ol-full-screen { + right: 0.5em; + top: 0.5em; + } + .ol-control button { + display: block; + margin: 1px; + padding: 0; + color: #fff; + font-size: 1.14em; + font-weight: 700; + text-decoration: none; + text-align: center; + height: 1.375em; + width: 1.375em; + line-height: 0.4em; + background-color: rgba(0, 60, 136, 0.5); + border: none; + border-radius: 2px; + } + .ol-control button::-moz-focus-inner { + border: none; + padding: 0; + } + .ol-zoom-extent button { + line-height: 1.4em; + } + .ol-compass { + display: block; + font-weight: 400; + font-size: 1.2em; + will-change: transform; + } + .ol-touch .ol-control button { + font-size: 1.5em; + } + .ol-touch .ol-zoom-extent { + top: 5.5em; + } + .ol-control button:focus, + .ol-control button:hover { + text-decoration: none; + background-color: rgba(0, 60, 136, 0.7); + } + .ol-zoom .ol-zoom-in { + border-radius: 2px 2px 0 0; + } + .ol-zoom .ol-zoom-out { + border-radius: 0 0 2px 2px; + } + .ol-attribution { + text-align: right; + bottom: 0.5em; + right: 0.5em; + max-width: calc(100% - 1.3em); + } + .ol-attribution ul { + margin: 0; + padding: 0 0.5em; + color: #000; + text-shadow: 0 0 2px #fff; + } + .ol-attribution li { + display: inline; + list-style: none; + } + .ol-attribution li:not(:last-child):after { + content: " "; + } + .ol-attribution img { + max-height: 2em; + max-width: inherit; + vertical-align: middle; + } + .ol-attribution button, + .ol-attribution ul { + display: inline-block; + } + .ol-attribution.ol-collapsed ul { + display: none; + } + .ol-attribution:not(.ol-collapsed) { + background: rgba(255, 255, 255, 0.8); + } + .ol-attribution.ol-uncollapsible { + bottom: 0; + right: 0; + border-radius: 4px 0 0; + } + .ol-attribution.ol-uncollapsible img { + margin-top: -0.2em; + max-height: 1.6em; + } + .ol-attribution.ol-uncollapsible button { + display: none; + } + .ol-zoomslider { + top: 4.5em; + left: 0.5em; + height: 200px; + } + .ol-zoomslider button { + position: relative; + height: 10px; + } + .ol-touch .ol-zoomslider { + top: 5.5em; + } + .ol-overviewmap { + left: 0.5em; + bottom: 0.5em; + } + .ol-overviewmap.ol-uncollapsible { + bottom: 0; + left: 0; + border-radius: 0 4px 0 0; + } + .ol-overviewmap .ol-overviewmap-map, + .ol-overviewmap button { + display: inline-block; + } + .ol-overviewmap .ol-overviewmap-map { + border: 1px solid #7b98bc; + height: 150px; + margin: 2px; + width: 150px; + } + .ol-overviewmap:not(.ol-collapsed) button { + bottom: 1px; + left: 2px; + position: absolute; + } + .ol-overviewmap.ol-collapsed .ol-overviewmap-map, + .ol-overviewmap.ol-uncollapsible button { + display: none; + } + .ol-overviewmap:not(.ol-collapsed) { + background: rgba(255, 255, 255, 0.8); + } + .ol-overviewmap-box { + border: 2px dotted rgba(0, 60, 136, 0.7); + } + .ol-overviewmap .ol-overviewmap-box:hover { + cursor: move; + } + /*# sourceMappingURL=ol.css.map */ + \ No newline at end of file