Raruto / leaflet-elevation

Leaflet plugin that allows to add elevation profiles using d3js
GNU General Public License v3.0
255 stars 85 forks source link

Alternative way to load leaflet plugins (ref: leaflet-ui) #229

Closed brigghius closed 1 year ago

brigghius commented 1 year ago

Your environment

hi, I'm developing a multi track map and I'm using the example here.

now I declare the plugins inside the array in opts.map. is there another way to load the plugins while still making the map work? I created a library with the map inside, but on first loading it doesn't load the plugins, if I refresh it works

thanks

Raruto commented 1 year ago

Hi @brigghius,

if you want to get rid of:

https://github.com/Raruto/leaflet-elevation/blob/868179234d8e9b8f7beaea57d0e34d8bd79a2622/examples/leaflet-elevation_hoverable-tracks.html#L55-L70

you can just move all those declarations and use them as regular javascript files, like these:

https://github.com/Raruto/leaflet-elevation/blob/868179234d8e9b8f7beaea57d0e34d8bd79a2622/examples/leaflet-elevation_hoverable-tracks.html#L15-L17

Likewise if you are importing them as ESM modules, you may need to remove this listener for make it to work as intended:

// Uncomment this if you are using ESM modules
// import "leaflet";
// import "@raruto/leaflet-elevation";
// ...

let map = L.map('map', opts.map);
let routes;

/**
 * This event is fired by "leaflet-ui", plugins lazy loading is not a built-in feature of the "leaflet" library
 * 
 * @see https://github.com/Raruto/leaflet-ui/blob/a8975e8e15e91a6e407c1c1a861872c52d3dd441/src/leaflet-ui.js#L520
 */
// map.on('plugins_loaded', function(e) {

  routes = L.gpxGroup(tracks, {
    points: points,
    points_options: opts.points,
    elevation: true,
    elevation_options: opts.elevation,
    legend: true,
    distanceMarkers: true,
  });

  map.on('eledata_added eledata_clear', ({type}) => {
    let p = document.querySelector(".chart-placeholder");
    if (p) {
      p.style.display = type =='eledata_added' ? 'none' : '';
    }
  });

  routes.addTo(map);

  map.attributionControl.addAttribution('Map Data: &copy; <a href="https://github.com/adoroszlai">Attila Doroszlai</a> (<a href="https://github.com/adoroszlai/joebed/blob/gh-pages/LICENSE.md">MIT License</a>)');

// });

Have a nice day, Raruto

brigghius commented 1 year ago

Hi @brigghius,

if you want to get rid of:

https://github.com/Raruto/leaflet-elevation/blob/868179234d8e9b8f7beaea57d0e34d8bd79a2622/examples/leaflet-elevation_hoverable-tracks.html#L55-L70

you can just move all those declarations and use them as regular javascript files, like these:

https://github.com/Raruto/leaflet-elevation/blob/868179234d8e9b8f7beaea57d0e34d8bd79a2622/examples/leaflet-elevation_hoverable-tracks.html#L15-L17

Likewise if you are importing them as ESM modules, you may need to remove this listener for make it to work as intended:

// Uncomment this if you are using ESM modules
// import "leaflet";
// import "@raruto/leaflet-elevation";
// ...

let map = L.map('map', opts.map);
let routes;

/**
 * This event is fired by "leaflet-ui", plugins lazy loading is not a built-in feature of the "leaflet" library
 * 
 * @see https://github.com/Raruto/leaflet-ui/blob/a8975e8e15e91a6e407c1c1a861872c52d3dd441/src/leaflet-ui.js#L520
 */
// map.on('plugins_loaded', function(e) {

  routes = L.gpxGroup(tracks, {
    points: points,
    points_options: opts.points,
    elevation: true,
    elevation_options: opts.elevation,
    legend: true,
    distanceMarkers: true,
  });

  map.on('eledata_added eledata_clear', ({type}) => {
    let p = document.querySelector(".chart-placeholder");
    if (p) {
      p.style.display = type =='eledata_added' ? 'none' : '';
    }
  });

  routes.addTo(map);

  map.attributionControl.addAttribution('Map Data: &copy; <a href="https://github.com/adoroszlai">Attila Doroszlai</a> (<a href="https://github.com/adoroszlai/joebed/blob/gh-pages/LICENSE.md">MIT License</a>)');

// });

Have a nice day, Raruto

thanks, I did as you described, but I get the error "leaflet__WEBPACK_IMPORTED_MODULE_0__.gpxGroup is not a function" image image

I don't understand what I'm doing wrong

Raruto commented 1 year ago

@brigghius maybe a stupid question, but did you include this file too?

"@raruto/leaflet-elevation@2.2.8/libs/leaflet-gpxgroup.js"

Otherwise please try to create an example jsfiddle so that anyone out there can see more easily what could be the problem (any other platform you want is also fine, as long as we can test and edit online without wasting too much time..)

Greetings, Raruto

brigghius commented 1 year ago

hello, i fixed all the imports, both in the component and in the index, but i still have a problem that i don't understand.

when I select a track and activate the elevation, it gives me this error: image

I'm importing the elevation like this: index: image component: image

the error is here: image

do you have some advice?

Raruto commented 1 year ago

Hi @brigghius, this has already been reported before:

Since v2.x of the leaflet-elevation, also for performance reasons, you can chooise which handlers to import/use within your application. This library has a simple lazy loading mechanism that allows it to check if those files are present in the global scope (and automatically load them accordingly if not).

To get an idea of how you can proceed, also take a look at the code of the following example (which shows in detail how the loading of the "custom handlers" works):

https://github.com/Raruto/leaflet-elevation/blob/868179234d8e9b8f7beaea57d0e34d8bd79a2622/examples/leaflet-elevation_extended-ui.html#L255-L271

As you can see you are not forced to use the built "class functions" provided by this library, but you could also provide your own "custom handlers" (ie. class functions) to handle that graphs.

Have a nice day, Raruto

brigghius commented 1 year ago

I don't have problems with handlers, I want to use your leaflet-elevation.js but when it goes to search from url the distance.js doesn't find it, both using local elevation and from node module.

image

the link thus gives me an error, it does not find its own addressing

hupe13 commented 1 year ago

I'm hosting in my application all files local. The file hierarchy is like here.

brigghius commented 1 year ago

update: image

manually importing the local files, the error disappeared but I find myself with the other references in error like this: image image image image

Raruto commented 1 year ago

please try to create an example jsfiddle so that anyone out there can see more easily what could be the problem (any other platform you want is also fine, as long as we can test and edit online without wasting too much time..)

@brigghius only you know your current code, if you are looking for help please provide an open source example...

If we start from a common basis, it takes us much less time to understand what is going wrong.

Thanks in advance for your cooperation, Raruto

brigghius commented 1 year ago

please try to create an example jsfiddle so that anyone out there can see more easily what could be the problem (any other platform you want is also fine, as long as we can test and edit online without wasting too much time..)

@brigghius only you know your current code, if you are looking for help please provide an open source example...

If we start from a common basis, it takes us much less time to understand what is going wrong.

Thanks in advance for your cooperation, Raruto

the structure of my application is like this https://stackblitz.com/edit/angular-ivy-sccrw6

Raruto commented 1 year ago

the structure of my application is like this https://stackblitz.com/edit/angular-ivy-sccrw6

Hi @brigghius, please double check your code example, there are other previous errors which prevent from testing the demo.

brigghius commented 1 year ago

the structure of my application is like this https://stackblitz.com/edit/angular-ivy-sccrw6

Hi @brigghius, please double check your code example, there are other previous errors which prevent from testing the demo.

I had problems with stackblitz, sorry. I uploaded on git the application with which I run the tests. it is already with the configuration that gives me error.

https://github.com/brigghius/eleMap

thanks

Raruto commented 1 year ago

I had problems with stackblitz, sorry. I uploaded on git the application with which I run the tests. it is already with the configuration that gives me error.

https://github.com/brigghius/eleMap

@brigghius ok, thanks, but know that I'm not going to compile your code locally..

Try to re-upload an editable example online so potentially anyone else can see it and try to help you out.


I think you are importing the same files twice (to avoid compatibility issues choose only one for each "imported" resource):

src/index.html#L10-L21

<script src="assets/scripts/leaflet.js"></script>
<script src="assets/scripts/leaflet-ui.js"></script>
<script src="assets/scripts/d3.min.js"></script>
<script src="assets/scripts/togeojson.umd.js"></script>
<script src="assets/scripts/leaflet.geometryutil.js"></script>
<script src="assets/scripts/leaflet.almostover.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.css">
<script src="assets/scripts/leaflet-distance-marker.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.css">
<script src="assets/scripts/@raruto/leaflet-elevation/dist/leaflet-elevation.js"></script>
<script src="assets/scripts/gpx-by-file.js"></script>

src/app/mappa/mappa.component.ts#L2-L10

import * as L from 'leaflet';
//import "leaflet-ui/dist/leaflet-ui.js"
import "src/assets/scripts/d3.min.js";
import "src/assets/scripts/togeojson.umd.js";
import "src/assets/scripts/leaflet.geometryutil.js";
import "src/assets/scripts/leaflet.almostover.js";
import "src/assets/scripts/leaflet-distance-marker.js";
import "src/assets/scripts/@raruto/leaflet-elevation/dist/leaflet-elevation.js";
import "src/assets/scripts/gpx-by-file.js";

To avoid issues with the javascript bundler, try preferring static imports instead of importing those modules dynamically:

src/app/mappa/mappa.component.ts#L116-L124

      handlers: [                               // <-- A list of: Dynamic imports || "ClassName" || function Name() { return { /* a custom object definition */ } } 
        import("src/assets/scripts/@raruto/leaflet-elevation/src/handlers/distance.js"),                           // <-- same as: import("../src/handlers/distance.js") 
        import("src/assets/scripts/@raruto/leaflet-elevation/src/handlers/time.js"),                               // <-- same as: import("../src/handlers/time.js") 
        import("src/assets/scripts/@raruto/leaflet-elevation/src/handlers/altitude.js"),                           // <-- same as: import("../src/handlers/altitude.js") 
        import("src/assets/scripts/@raruto/leaflet-elevation/src/handlers/slope.js"),                              // <-- same as: import("../src/handlers/slope.js") 
        import("src/assets/scripts/@raruto/leaflet-elevation/src/handlers/speed.js"),                              // <-- same as: import("../src/handlers/speed.js") 
        import("src/assets/scripts/@raruto/leaflet-elevation/src/handlers/acceleration.js"),                       // <-- same as: import("../src/handlers/acceleration.js") 

      ],

eg.

import { Distance } from "src/assets/scripts/@raruto/leaflet-elevation/src/handlers/distance.js";
import { Time } from "src/assets/scripts/@raruto/leaflet-elevation/src/handlers/time.js"
...
  handlers: [
    Distance,
    Time,
    ...
  ]

Raruto

brigghius commented 1 year ago

@Raruto i found the problem. another map was used elsewhere in the application. If this was loaded before yours, the elevation map didn't load the plugins (empty network tab).

this is from the other map: image

Do you happen to have any idea how to fix this upload problem?

Raruto commented 1 year ago

If this was loaded before yours, the elevation map didn't load the plugins (empty network tab).

If you are importing the "plugins" code statically there is no reason for it to work differently than you say..

Do you happen to have any idea how to fix this upload problem?

If you don't provide a minimal example that reproduces the bug there is no way anyone else can help you (don't let me be rude by closing this issue, but this is open source code..)

brigghius commented 1 year ago

If you are importing the "plugins" code statically there is no reason for it to work differently than you say..

ok, i craete it: https://codesandbox.io/embed/gallant-rgb-k8khhd?fontsize=14&hidenavigation=1&theme=dark

so, i have 2 maps in the same component. the first loaded is a very simple map. if i eneble the elevation map, it don't load nothing and don't work.

Raruto commented 1 year ago

@brigghius so if this is your current code (ref: leaflet-ui plugins option):

plugins: [
  "d3@6.5.0/dist/d3.min.js",
  "@tmcw/togeojson@4.5.0/dist/togeojson.umd.js",
  "leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js",
  "leaflet-almostover@1.0.1/src/leaflet.almostover.js",
  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.css",
  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.js",
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.css",
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.js",

  "/assets/scripts/gpx-by-file.js"          // <-- NB: missing comma

  // "../libs/leaflet-distance-marker.css", // <-- local file not found
  // "../libs/leaflet-distance-marker.js",  // <-- local file not found
  // "../dist/leaflet-elevation.css",       // <-- local file not found
  // "../dist/leaflet-elevation.js",        // <-- local file not found
  // "../libs/leaflet-gpxgroup.js",         // <-- local file not found
]

you should at least update it as follows to make it work:

plugins: [
  "d3@6.5.0/dist/d3.min.js",
  "@tmcw/togeojson@4.5.0/dist/togeojson.umd.js",
  "leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js",
  "leaflet-almostover@1.0.1/src/leaflet.almostover.js",

  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.css", // <-- load file from unpkg.com
  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.js",  // <-- load file from unpkg.com
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.css",       // <-- load file from unpkg.com
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.js",        // <-- load file from unpkg.com
  // "@raruto/leaflet-elevation@2.2.7/libs/leaflet-gpxgroup.js",

  "/assets/scripts/gpx-by-file.js",                 // <-- load this file after "leaflet-elevation.js"
]

However, keep in mind that the correct path for /assets/scripts/gpx-by-file.js file will most likely be related to the folder you will publish and not to your current development src directory (but this is more a problem of knowing how to develop an Angular application..)

Have a nice day, Raruto

brigghius commented 1 year ago

@brigghius so if this is your current code (ref: leaflet-ui plugins option):

plugins: [
  "d3@6.5.0/dist/d3.min.js",
  "@tmcw/togeojson@4.5.0/dist/togeojson.umd.js",
  "leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js",
  "leaflet-almostover@1.0.1/src/leaflet.almostover.js",
  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.css",
  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.js",
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.css",
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.js",

  "/assets/scripts/gpx-by-file.js"          // <-- NB: missing comma

  // "../libs/leaflet-distance-marker.css", // <-- local file not found
  // "../libs/leaflet-distance-marker.js",  // <-- local file not found
  // "../dist/leaflet-elevation.css",       // <-- local file not found
  // "../dist/leaflet-elevation.js",        // <-- local file not found
  // "../libs/leaflet-gpxgroup.js",         // <-- local file not found
]

you should at least update it as follows to make it work:

plugins: [
  "d3@6.5.0/dist/d3.min.js",
  "@tmcw/togeojson@4.5.0/dist/togeojson.umd.js",
  "leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js",
  "leaflet-almostover@1.0.1/src/leaflet.almostover.js",

  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.css", // <-- load file from unpkg.com
  "@raruto/leaflet-elevation@2.2.7/libs/leaflet-distance-marker.js",  // <-- load file from unpkg.com
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.css",       // <-- load file from unpkg.com
  "@raruto/leaflet-elevation@2.2.7/dist/leaflet-elevation.js",        // <-- load file from unpkg.com
  // "@raruto/leaflet-elevation@2.2.7/libs/leaflet-gpxgroup.js",

  "/assets/scripts/gpx-by-file.js",                 // <-- load this file after "leaflet-elevation.js"
]

However, keep in mind that the correct path for /assets/scripts/gpx-by-file.js file will most likely be related to the folder you will publish and not to your current development src directory (but this is more a problem of knowing how to develop an Angular application..)

Have a nice day, Raruto

Hello, sorry i'm not understanding, i see no difference between the code i wrote and your suggestion. plugin order is that, "local file not found" is commented out, gpx-by-file is last in plugin order.

image image

I only get the malfunction when another leaflet map is loaded BEFORE the one with the elevation

Raruto commented 1 year ago

Sorry i'm not understanding, i see no difference between the code i wrote and your suggestion.

I only get the malfunction when another leaflet map is loaded BEFORE the one with the elevation

The following file which you developed throws a fatal error in the demo you posted earlier: /assets/scripts/gpx-by-file.js (so it's hard enough to replicate..)

The operation of the lazy loading of that plugin is almost all here leaflet-ui/src/leaflet-ui.js#L482-L521, debug it step by step to understand if it is something related to what you say.

brigghius commented 1 year ago

Sorry i'm not understanding, i see no difference between the code i wrote and your suggestion. I only get the malfunction when another leaflet map is loaded BEFORE the one with the elevation

The following file which you developed throws a fatal error in the demo you posted earlier: /assets/scripts/gpx-by-file.js (so it's hard enough to replicate..)

The operation of the lazy loading of that plugin is almost all here leaflet-ui/src/leaflet-ui.js#L482-L521, debug it step by step to understand if it is something related to what you say.

if i load only elevation map, i have no problem, also with gpx-by-file.js there is a problem when i load elevation AFTER another map is load, but if i load elevation before another map, elevation works good.

So i don't know how to fix this behavior

brigghius commented 1 year ago

Sorry i'm not understanding, i see no difference between the code i wrote and your suggestion. I only get the malfunction when another leaflet map is loaded BEFORE the one with the elevation

The following file which you developed throws a fatal error in the demo you posted earlier: /assets/scripts/gpx-by-file.js (so it's hard enough to replicate..)

The operation of the lazy loading of that plugin is almost all here leaflet-ui/src/leaflet-ui.js#L482-L521, debug it step by step to understand if it is something related to what you say.

ok, i have found the problem. Loading a leaflet map without plugins, your code goes here: https://github.com/Raruto/leaflet-ui/blob/a8975e8e15e91a6e407c1c1a861872c52d3dd441/src/leaflet-ui.js#L482-L506 it values lazyLoader.loader and when I load the map with the elevation and its plugins, it doesn't enter the if.

to fix this, I modified the first control like this: image

And so with "simple" maps it does not enter. Do you think it's a problem? Or could you change this if too?

Raruto commented 1 year ago

ok, i have found the problem. Loading a leaflet map without plugins, your code goes here: https://github.com/Raruto/leaflet-ui/blob/a8975e8e15e91a6e407c1c1a861872c52d3dd441/src/leaflet-ui.js#L482-L506 it values lazyLoader.loader and when I load the map with the elevation and its plugins, it doesn't enter the if.

Ok got it, so is the following assignment that does not allow you to load any new plugins the second time:


if (!lazyLoader.loader) {
  ...
  lazyLoader.loader = lazyLoader.loadSyncScripts([core_plugins, opts.plugins]);
}

lazyLoader.loader.then(() => this.fire('plugins_loaded'));

Do you think it's a problem?

Yes possible, as you see that library was not initially developed with a reactive framework in mind (and most of the time you don't need to re-instantiate many components in a plain html page).

Or could you change this if too?

You could try doing like the following:

// A) override default options

L.Map.mergeOptions({ plugins: undefined /* or any other value that evaluates to false */ });

const map_2 = L.Map.( 'map', { ... });
const map_1 = L.Map.( 'map', { ... });
// B) override default options for the first map

const map_1 = L.Map.( 'map', { plugins: undefined /* or any other value that evaluates to false */ });
const map_1 = L.Map.( 'map', { plugins: [ ... ] });

Or as usual, improval pull requests are welcome.

Raruto commented 1 year ago

@brigghius let me know if leaflet-ui@v0.6.0 solves this problem

brigghius commented 1 year ago

@brigghius let me know if leaflet-ui@v0.6.0 solves this problem

hello, it would seem solved with 0.6.0 (maybe you need to update the topic title to better index the issue) Thank you

Raruto commented 1 year ago

it would seem solved with 0.6.0 (maybe you need to update the topic title to better index the issue)

@brigghius I'm a bit lost here, but if you asked directly in the dedicated repository 👉 Raruto/leaflet-ui we would have saved ourselves a lot of additional reasoning..

👋 Raruto