gethinode / hinode

A clean documentation and blog theme for your Hugo site based on Bootstrap 5
https://gethinode.com
MIT License
146 stars 52 forks source link

Add Leaflet javascript library to easily create interactive maps for your blog #169

Closed rimatech987 closed 1 year ago

rimatech987 commented 1 year ago

Is your feature request related to a problem? Please describe. N/A

Describe the solution you'd like Add Leaflet library inside the project to create marvelous interactive maps for your blog.

Describe alternatives you've considered N/A

Additional context Reference: https://leafletjs.com/download.html

markdumay commented 1 year ago

I'm a bit hesitant to add the library to the repository by default. However, you could add the dependency to your own project in a few steps. Let me know if this works for you. I published a demo repository to GitHub for your convenience.

Install Leaflet as development dependency

Run the following command from within your project folder to add Leaflet as a development dependency.

npm i -D leaflet

Mount the library to the assets folder

Ensure the leaflet.js file is included in the project's JavaScript bundle by adding a mount to config/_default/config.toml.

  [[module.mounts]]
    source = "node_modules/leaflet/dist"
    target = "assets/js/vendor/leaflet"
    includeFiles = "leaflet.js"

Import the css file

Similarly to the JavaScript bundle, add the following statement to assets/scss/app.scss to include the Leaflet's CSS file in your main style. Please note that the file extension .css is omitted.

// Import Leaflet
@import "leaflet/dist/leaflet";

Adjust the Content Security Policy

Leaflet requires access to OpenStreetMap. Adjust the Content Security Policy in config/_default/server.toml to enable the image access. You might need to adjust the settings of your hosting provider too (see netlify.toml in the repository root).

img-src 'self' https://i.vimeocdn.com https://i.ytimg.com https://tile.openstreetmap.org; \

Add the image map placeholder

Add an map placeholder to your (Markdown) content file. The following placeholder uses a 16x9 ratio and stretches across the main body.

<div id="map" class="ratio ratio-16x9 w-100"></div>

Initialize the map

Finally, initialize the map placeholder with the OpenStreetMap content. The following example uses London. The mapID refers to the ID of the placeholder. The code tests if an element with the map ID is present and initializes the placeholder accordingly. You can place the code in assets/js/leaflet.js, where Hinode will pick it up automatically.

const mapID = 'map'

if (document.getElementById(mapID) !== null) {
  const map = L.map(mapID).setView([51.505, -0.09], 13)

  const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
  }).addTo(map)
}

Test the map

From here on you should have a working map on your site. Run the following command to start a local development server.

npm run start

You can now modify the placeholder and map initialization as needed.

rimatech987 commented 1 year ago

Brilliant as ever.

I wanna explain briefly what my goal is.

I'd like to create a map with GPX track (I am attaching an example one for you to use test.zip) that allows users to see the waypoints on the map that I customize, the track and start/end of the route, and download the gpx.

I found this project Hugo Leaflet that should be less intrusive since you only need to insert the code within your markdown article and it fits perfectly with my needs.

GPX Track

Or use and add this plugin GPX plugin for Leaflet .

The "problem" with the latter is that if I wanted to add a map for each individual markdown article, I have to create a long list of maps inside the leaflet.js file resulting less intuitive and difficult in case you need to make a change to a map.

Would you have any way to create an example for me with the first project (Hugo Leaflet) to see if it might be the best choice or you think the second one is better?

rimatech987 commented 1 year ago

Hi @markdumay , any news here? I would be very happy if you can help me with this issue of gpx tracks.

rimatech987 commented 1 year ago

Hi @markdumay and everyone. I have followed all your instructions above but I cannot display a marker on the map. I just modified the assets/js/leaflet.js like this:

const mapID = 'map'

if (document.getElementById(mapID) !== null) {
  const map = L.map(mapID).setView([51.505, -0.09], 13)

  const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
  }).addTo(map)

var marker = L.marker([51.5, -0.09]).addTo(map);
}

but it doesn't show properly the marker.

Marker

and these are the errors shown on my browser.

Image

Error

It looks like there's no marker image in that path. Where should I put the image? Do I need to change the path somewhere?

markdumay commented 1 year ago

I revised the guide and code examples a little. The default marker requires a few images to be present in static/css/images. See the Leaflet installation guidelines - "Using a Downloaded Version of Leaflet" for more details. The following mount statement ensures these images are available for your site:

  [[module.mounts]]
    source = "node_modules/leaflet/dist/images"
    target = "static/css/images"
    includeFiles = "*.png"

I've included a demo repository for your convenience, which contains a fully working example. Supporting the additional features you requested is out of scope for this project, but hopefully the guide and demo repository are sufficient to get you started.

rimatech987 commented 1 year ago

Hi Mark, It runs perfectly. I'm able now to use most of the Leaflet options that I've tested till now useful for the projects I have in mind. Thank you again :+1:

I look forward to the implementation of additional deployment options such as GitHub pages and manual deployment.

rimatech987 commented 1 year ago

Hi @markdumay , Unfortunately, it doesn't work any more with the latest version v.0.16.3.

I get these errors if I don't set .css. as extension for @import "leaflet/dist/leaflet" Adding npm packages

ERROR render of "page" failed: execute of template failed: template: partials/head/head.html:6:7: executing "head" at <partial "head/stylesheet.html">: error calling partial: "/home/xxx/xxx/hinode/layouts/partials/head/stylesheet.html:38:8": execute of template failed: template: partials/head/stylesheet.html:38:8: executing "partials/head/stylesheet.html" at <partial "head/icons.html" (dict "css" $css)>: error calling partial: "/home/xxx/xxx/hinode/layouts/partials/head/icons.html:22:54": execute of template failed: template: partials/head/icons.html:22:54: executing "partials/head/icons.html" at <$css.Content>: error calling Content: TOCSS: failed to transform "css/main.css" (text/x-scss): "scss/bundle-1690042213324738765.scss:15:10": Invalid CSS after '...ort "components': expected 1 selector or at-rule, was '/alert.scss";' `

ERROR TOCSS: failed to transform "css/main.css" (text/x-scss): "scss/bundle-1690042213324738765.scss:15:10": Invalid CSS after '...ort "components': expected 1 selector or at-rule, was '/alert.scss";'

Error: error building site: TOCSS: failed to transform "css/main.css" (text/x-scss): "scss/bundle-1690042213324719352.scss:15:10": Invalid CSS after '...ort "components': expected 1 selector or at-rule, was '/alert.scss";'

Moreover, even setting the .css as an extension, it doesn't work. It doesn't show me any map, and these are the errors from my browser.

image

image

I appreciate you added interactive maps as components but it's too limited for me, as it provides very basic functionality.

The only way is to include npm packages directly into main site as before.

Can you fix it, please?

markdumay commented 1 year ago

Confirmed, the demo repo needs to be updated to work with Hugo modules. I have a local copy that's almost finished. I'll do some final testing and will update the guide accordingly.

markdumay commented 1 year ago

I have updated the repo to work with the latest version. The guide on https://gethinode.com/guides/packages/ has been updated too.

You could consider to adapt the new module approach too. The advantage would be that you could include the leaflet code on a page-by-page basis, reducing overhead for the other pages. The following documentation pages might be relevant:

rimatech987 commented 1 year ago

Great, now it seems to work as well as before. I only got these WARN messages, but they don't compromise the result.

WARN  File "js/critical" not found, skipping.
WARN  File "js/optional" not found, skipping.
WARN  File "js/vendor" not found, skipping.
WARN  File "js/critical" not found, skipping.
WARN  File "js/optional" not found, skipping.
WARN  File "js/vendor" not found, skipping.

You could consider to adapt the new module approach too. The advantage would be that you could include the leaflet code on a page-by-page basis, reducing overhead for the other pages.

A basic mod-leaflet module already exists. How can I add more features to this module?

In my case, I wanna use geoJSON as here or use more custom markers as here etc.

Before, I only had to enter the JS code in leaflet.js and that's all, but with these modules? How to do this?

P.S. Sorry but I'm not so good at coding.

markdumay commented 1 year ago

Great, now it seems to work as well as before.

Good to hear. I'll close this issue for now.

A basic mod-leaflet module already exists. How can I add more features to this module?

In this case, you could consider to fork the existing module. In your own my-leaflet you can modify the script in any way you want. Then simply import and configure my-leaflet in your own site, following the docs. Alternatively, you could replace the mounted leaflet.js with your own file.