logo My Digital Garden

Open Layer Map in Astro

By James Kolean on Apr 24, 2023
Source repository: https://gitlab.com/jameskolean/openlayers-astro
Demo: https://jameskolean.gitlab.io/openlayers-astro/
JavaScript
banner

If you’re looking for a versatile and powerful mapping tool, OpenLayers is definitely worth considering. OpenLayers is an open-source JavaScript library that allows you to create interactive maps on the web. It’s highly customizable and provides a wide range of functionalities, from basic zooming and panning to advanced features such as geolocation, routing, and vector editing. OpenLayers supports a variety of map services, including OpenStreetMap, Bing Maps, and Google Maps, and can display different types of data such as points, lines, and polygons. One of the most significant benefits of OpenLayers is that it’s entirely free, making it an attractive choice for personal and commercial projects. Whether you’re building a map-based application or need to display geographic information on your website, OpenLayers is a powerful and flexible tool worth exploring.

Create a file src/components/MapWrapper.tsx to integrate the OpenLayer JS library in React (or Preact in this example). We are using Preact over React for efficiency.

import Map from "ol/Map";
import OSM from "ol/source/OSM";
import styles from "./Map.module.css";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import View from "ol/View";
import {
    fromLonLat
} from "ol/proj";
import {
    useEffect,
    useRef,
    useState
} from "preact/hooks";

interface Props {
    class ? : string;
}

function MapWrapper(props: Props) {
    const [map, setMap] = useState < Map > ();
    const [featuresLayer, setFeaturesLayer] =
    useState < VectorLayer < VectorSource >> ();
    useEffect(() => {
        const initalFeaturesLayer = new VectorLayer({
            source: new VectorSource(),
        });

        const initialMap = new Map({
            target: mapElement.current ?? undefined,
            layers: [
                new TileLayer({
                    source: new OSM(),
                }),
                initalFeaturesLayer,
            ],
            view: new View({
                projection: "EPSG:3857",
                center: fromLonLat([-88.913, 48.0]),
                zoom: 10,
            }),
            controls: [],
        });
        setMap(initialMap);
        setFeaturesLayer(initalFeaturesLayer);
    }, []);
    const mapElement = useRef < HTMLDivElement > (null);

    return ( <
        div ref = {
            mapElement
        }
        className = {
            `${props.class} ${styles.mapWrapper}`
        } >
        <
        /div>
    );
}

export default MapWrapper;

The MapWrapper function takes in a set of properties (Props) and returns a div element that will contain the map. The useState hook creates two states: map and featuresLayer. These states keep track of the map instance, the layer that displays features, and the currently selected coordinate on the map. The useEffect hook holds the initial map created with some default settings. The VectorLayer manages features on the map. We use the OpenStreetMap tiles layer to show the terrain overlay. We connect the Map to the Html with a ref mapElement div.

Finally, the ref attribute attaches the mapElement div to the React component to render the OpenLayers map inside it. Overall, this code provides a basic example of how to set up an OpenLayers map in a React component using hooks such as useState, useEffect, and useRef. Adding more code and functionality can extend this component to include features such as zooming, panning, and adding markers or polygons to the map.

The project is also configured for UNit and Cypress testing.

// vite.config.ts
import {
    defineConfig
} from "vitest/config"

export default defineConfig({
    test: {
        coverage: {
            provider: "c8", // or 'istanbul'
            reporter: ["text", "json", "html"],
        },
    },
})
// cypress.config.js
import {
    defineConfig
} from "cypress"

export default defineConfig({
    e2e: {
        supportFile: false,
    },
    reporter: "mochawesome",
})
© Copyright 2023 Digital Garden cultivated by James Kolean.