How to Generate Printable Driving Directions with Geoapify

by Geoapify

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js"></script>
<script src="https://unpkg.com/@geoapify/[email protected]/dist/index.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/6.5.0/turf.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css">
<link rel="stylesheet" href="https://unpkg.com/@geoapify/[email protected]/styles/styles.min.css">
<div class="demo-container">
  <div class="map-container">
    <div id="my-map"></div>
    <div class="controls"><div id="route-directions"></div></div>
  </div>
  <div class="route-direction-to-print-container">
    <div class="printable-driving-directions-title hidden" id="driving-directions-title">
      <h1>Printable Driving Directions</h1>
    </div>
    <div class="instructions-placeholder" id="instructions-placeholder">
      No waypoints have been selected. Please add at least two waypoints to
      generate driving directions.
    </div>
    <div class="route-preview-container" id="route-preview-container">
      <img class="route-preview hidden" id="route-preview" />
    </div>
    <div class="elevation-profile-container hidden" id="chart-container">
      <canvas
        id="route-elevation-chart"
        style="width: 100%; height: 100%"
      ></canvas>
    </div>
    <div id="instructions"></div>
  </div>
</div>

CSS

html,
body {
    width: 100%;
    height: 100%;
    margin: 0;
}

body {
    display: flex;
    flex-direction: column;
}

.demo-container {
    max-height: 100%;
}

.map-container {
    flex: 1;
    margin: 10px;
    box-shadow: 0px 0px 5px 3px rgb(0 0 0 / 10%);
    border-radius: 5px;
    position: relative;
    display: flex;
    height: 400px;
}

.controls {
    padding: 20px;
    display: flex;
    flex-direction: column;
    position: absolute;
    z-index: 2000;
    background: white;
    border-bottom-right-radius: 3px;
}

#instructions {
    flex: 1;
    max-width: 100%;
    margin: auto;
}

#my-map {
    flex: 1;
}

.route-direction-to-print-container {
    padding: 10px;
    padding-top: 20px;

    overflow-y: auto;
    display: block;
    position: relative;
}

.direction-waypoints {
    font-size: 18px;
    font-weight: 600;
    color: rgba(0, 0, 0, 0.8);
    margin-bottom: 30px;
}

.direction-waypoints.smaller {
    font-size: 16px;
    font-weight: 500;
}

.direction-waypoints .direction-waypoints-from-to{
    font-size: 12px;
    font-weight: 400;
}

.direction-instruction {
    display: flex;
    flex-direction: row;
    margin: 10px 0;

    color: rgba(0, 0, 0, 0.8);
}

.direction-instruction-number {
    margin-right: 20px;
}

.direction-instruction-icon {
    min-width: 40px;
    max-width: 40px;
    display: flex;
}

.direction-instruction-image {
    width: 300px;
    height: 200px;
    display: flex;
    margin-left: auto;
}

.button {
    height: 30px;
    margin-left: auto;
    background: grey;
    border: none;
    width: 100px;
    border-radius: 4px;
    color: #fff;
    padding: 5px 10px;
    font-size: 14px;
    font-weight: bold;
    cursor: pointer;
    align-items: center;
    gap: 5px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    transition: transform 0.2s, box-shadow 0.2s;

    position: absolute;
    top: 10px;
    right: 10px;
}

.button:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(0, 0, 0,...

JavaScript

// Initialize the Leaflet map object
// Create a map with the given HTML container ID and disable the default zoom control
var map = L.map('my-map', { zoomControl: false }).setView([48.1500327, 11.5753989], 10);

// Define the Geoapify API key
// Note: This API key is restricted to this demo. Obtain your own API key from https://myprojects.geoapify.com
var apiKey = "6dc7fb95a3b246cfa0f3bcef5ce9ed9a";

// Define the URL for map tiles, accounting for high-resolution (retina) displays
var mapURL = L.Browser.retina
    ? `https://maps.geoapify.com/v1/tile/{mapStyle}/{z}/{x}/{y}@2x.png?apiKey={apiKey}`
    : `https://maps.geoapify.com/v1/tile/{mapStyle}/{z}/{x}/{y}.png?apiKey={apiKey}`;

// Add a tile layer to the map
// Use Geoapify's tile service and specify options such as attribution and max zoom level
L.tileLayer(mapURL, {
    attribution: 'Powered by <a href="https://www.geoapify.com/" target="_blank">Geoapify</a> | <a href="https://openmaptiles.org/" rel="nofollow" target="_blank">© OpenMapTiles</a> <a href="https://www.openstreetmap.org/copyright" rel="nofollow" target="_blank">© OpenStreetMap</a> contributors',
    apiKey: apiKey, // Include the API key for authentication
    mapStyle: "osm-bright-smooth", // Specify the map style (find more styles at https://apidocs.geoapify.com/docs/maps/map-tiles/)
    maxZoom: 20 // Set the maximum zoom level for the map
}).addTo(map);

// Add a custom zoom control to the map
// Position the zoom control at the bottom-right corner
L.control.zoom({ position: 'bottomright' }).addTo(map);

// Initialize arrays and variables for managing markers, route layers, and instruction markers
let markers = []; // Array to store markers added to the map
let routeLayer; // Layer for displaying the route on the map
let routeShadowLayer; // Shadow layer for the route (optional for styling or effects)
let instructionMarkers = []; // Array to store markers associated with route instructions

// Define a custom icon for markers
const...