Reputation: 31
I'm posting to see if anyone can give me some light on this 'problem/issue'. I'm using react-leaflet and also leaflet-elevation, a 'plug-in' that creates an elevation graph and also adds some extra things
As you can see from the image below, the L.control.elevation is being interpreted (I've imported it like this: import "leaflet.elevation/dist/Leaflet.Elevation-0.0.2.min.js";
but compiling I get this:
Error message from the console.
Thanks.
EDITING: Adding some more info
So in terms of code:
Map Component (updated)
import React from "react";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import L from "leaflet";
import 'leaflet.elevation/dist/Leaflet.Elevation-0.0.2.min.js'
import "./Map.css";
const Map = () => {
function InitProfile() {
var elevation_options = {
// Default chart colors: theme lime-theme, magenta-theme, ...
theme: "lightblue-theme",
// Chart container outside/inside map container
detached: true,
// if (detached), the elevation chart container
elevationDiv: "#elevation-div",
// if (!detached) autohide chart profile on chart mouseleave
autohide: false,
// if (!detached) initial state of chart profile control
collapsed: false,
// if (!detached) control position on one of map corners
position: "topright",
// Toggle close icon visibility
closeBtn: true,
// Autoupdate map center on chart mouseover.
followMarker: true,
// Autoupdate map bounds on chart update.
autofitBounds: true,
// Chart distance/elevation units.
imperial: false,
// [Lat, Long] vs [Long, Lat] points. (leaflet default: [Lat, Long])
reverseCoords: false,
// Acceleration chart profile: true || "summary" || "disabled" || false
acceleration: false,
// Slope chart profile: true || "summary" || "disabled" || false
slope: false,
// Speed chart profile: true || "summary" || "disabled" || false
speed: false,
// Altitude chart profile: true || "summary" || "disabled" || false
altitude: true,
// Display time info: true || "summary" || false
time: true,
// Display distance info: true || "summary" || false
distance: true,
// Summary track info style: "inline" || "multiline" || false
summary: "multiline",
// Download link: "link" || false || "modal"
downloadLink: "link",
// Toggle chart ruler filter
ruler: true,
// Toggle chart legend filter
legend: true,
// Toggle "leaflet-almostover" integration
almostOver: true,
// Toggle "leaflet-distance-markers" integration
distanceMarkers: false,
// Toggle "leaflet-hotline" integration
hotline: true,
// Display track datetimes: true || false
timestamps: false,
// Display track waypoints: true || "markers" || "dots" || false
waypoints: true,
// Toggle custom waypoint icons: true || { associative array of <sym> tags } || false
wptIcons: {
"": L.divIcon({
className: "elevation-waypoint-marker",
html: '<i class="elevation-waypoint-icon"></i>',
iconSize: [30, 30],
iconAnchor: [8, 30],
}),
},
// Toggle waypoint labels: true || "markers" || "dots" || false
wptLabels: true,
// Render chart profiles as Canvas or SVG Paths
preferCanvas: true,
};
// Instantiate map (leaflet-ui).
var map = useMap();
// Instantiate elevation control.
var controlElevation = L.control.elevation(elevation_options).addTo(map);
// Load track from url (allowed data types: "*.geojson", "*.gpx", "*.tcx")
// controlElevation.load(
// "https://raruto.github.io/leaflet-elevation/examples/via-emilia.gpx"
// );
}
return (
<MapContainer
id="map"
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={false}
>
<InitProfile />
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[51.505, -0.09]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
);
};
export default Map;
Map.css
#map {
height: 75vh;
}
App.js
import './App.css';
import Map from "./components/Map"
function App() {
return (
<>
<Map />
</>
);
}
export default App;
And the error: (NOW irrelevant, was missing the import for leaflet.elevation)
Uncaught TypeError: leaflet__WEBPACK_IMPORTED_MODULE_1___default(...).control.elevation is not a function
at InitProfile (Map.jsx:111:1)
at renderWithHooks (react-dom.development.js:16175:1)
at mountIndeterminateComponent (react-dom.development.js:20913:1)
at beginWork (react-dom.development.js:22416:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4161:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4210:1)
at invokeGuardedCallback (react-dom.development.js:4274:1)
at beginWork$1 (react-dom.development.js:27405:1)
at performUnitOfWork (react-dom.development.js:26513:1)
at workLoopSync (react-dom.development.js:26422:1)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<!-- leaflet -->
<style>
html,
body,
#map,
#elevation-div {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
#map {
height: 75%;
}
#elevation-div {
height: 25%;
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
</style>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/leaflet.css"
integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""
/>
<link
rel="stylesheet"
href="https://unpkg.com/@raruto/leaflet-elevation@latest/dist/leaflet-elevation.css"
/>
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script
src="https://unpkg.com/[email protected]/dist/leaflet.js"
integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""
></script>
<script src="https://unpkg.com/leaflet-ui@latest/dist/leaflet-ui.js"></script>
<script src="https://unpkg.com/@raruto/leaflet-elevation@latest/dist/leaflet-elevation.js"></script>
<!-- end leaflet -->
<!-- D3js -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<!-- End D3js -->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
I've also had to "npm i" d3 and leaflet.elevation.
The problem at the moment is that the ".load()" function for the L.control.elevation object is not getting recognised
Uncaught TypeError: controlElevation.load is not a function
at InitProfile (Map.jsx:88:1)
at renderWithHooks (react-dom.development.js:16175:1)
at mountIndeterminateComponent (react-dom.development.js:20913:1)
at beginWork (react-dom.development.js:22416:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4161:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4210:1)
at invokeGuardedCallback (react-dom.development.js:4274:1)
at beginWork$1 (react-dom.development.js:27405:1)
at performUnitOfWork (react-dom.development.js:26513:1)
at workLoopSync (react-dom.development.js:26422:1)
and this:
App running, but with two instances of the leaflet.elevation.
Upvotes: 2
Views: 1050
Reputation: 1
A little bit late on this topic, but this solution should work:
import { useEffect } from "react";
import { MapContainer, TileLayer, useMap } from "react-leaflet";
import L from "leaflet";
import "leaflet.elevation/dist/Leaflet.Elevation-0.0.2.min.js"; // [email protected]
import "./Map.css";
import myGeoJson from "./myGeoJson.json";
function InitProfile() {
// Instantiate map (leaflet-ui).
var map = useMap();
// Instantiate elevation control.
var elevation_options = {};
var controlElevation = L.control.elevation(elevation_options).addTo(map);
useEffect(() => {
L.geoJson(myGeoJson, {
onEachFeature: controlElevation.addData.bind(controlElevation),
}).addTo(map);
return () => {
controlElevation.remove();
};
}, [map, controlElevation]);
}
export default function Map() {
return (
<MapContainer id="map" center={[-44.968683, 168.957614]} zoom={13} scrollWheelZoom={false}>
<InitProfile />
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
);
}
Cleaning up the controlElevation should avoid multiple instances of the graph. Only script necessary in the index.html is the D3js, no need to include Leaflet there as it is already loaded in the component.
Upvotes: 0
Reputation: 43
About the second instance of the elevation chart, you should comment out the React.StrictMode
tag in the index.js file, and leave only the App
tag.
Reproducing answer from here: Why is my React component is rendering twice?
Upvotes: 0