Leaflet wont work with Vue using browserify - leaflet

I'm new using browserify and VueJS. I have a project where I'd like to use the map service Leaflet. So as i show in the code down below I try to require it, I have pulled it in using npm. If I look in the compiled JS file i can find Leaflet there. So that seems to work..
I'll show a image of my resulting map when i try to initialize it in the browser:
Broken Leaflet map
So as you can see the tiles are behaving really wierd, and nothing works as it should. Draging the map does really strange things..
This is the code for the components JS.
var L = require('leaflet');
module.exports = {
data: function () {
return {
map: false,
samples: [],
messages: [],
customer_id: '',
year: ''
}
},
methods: {
fetch: function (id, year, successHandler) {
var that = this
that.$set('customer_id', id)
that.$set('year', year)
successHandler(id);
}
},
ready: function () {
var map = L.map('map').setView([41.3921, 2.1705], 13);
L.Icon.Default.imagePath = 'images/';
var osmTiles = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var attribution = '© OpenStreetMap contributors';
L.tileLayer(osmTiles, {
maxZoom: 18,
attribution: attribution
}).addTo(map);
},
route: {
data: function (transition) {
this.fetch(this.$route.params.customer_id, this.$route.params.year, function (data) {
transition.next({customer_id: data})
})
}
}}
Right now I tried require:ing the leaflet package in my components script file.
Somewhere along the line Leaflet breaks.. I get no errors in the console when viewing the map, but as you can see it doesn't look good.
I would be really happy for all the help i can get!
Edit:
I just tried using chart.js in my project, required in the same way as leaflet, works like a charm.. Can't understand why leaflet wont work.
/ Simon

You are missing the Leaflet style sheet. Add it (for the correct version) using a link tag:
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />

Related

Svelte / SvelteKit importing an npm library returns error when trying to work with Leaflet

I'm trying to learn Svelte / SvelteKit by porting over an existing Angular application. The app should show a Leaflet map with a heatmap layer as overlay. The map part works and is robust, even when I navigate or refresh Svelte handles it fine. The heatmap on the other hand only loads when the app initializes for the first time as you can see here:
However When I refresh I get this error and the whole Map.svelte component doesn't load at all anymore with the following error message in the console:
Uncaught (in promise) TypeError: Leaflet.heatLayer is not a function
I suspect it has to do with the way the lifecycle handles imports, because in my Angular app the imports don't have to be done in a life cycle method in order for them to work, whereas the only way to get Leaflet to even render in SvelteKit I have to do an async import.
Can anyone clarify what's going on with the Leaflet.heatlayer error and how I can fix it?
Map.svelte
<script lang="ts">
import type { HeatLayer, Map } from 'leaflet';
import { onMount } from 'svelte';
let Leaflet;
let map: Map;
let heatLayer: HeatLayer;
onMount(async () => {
Leaflet = await import('leaflet');
import('leaflet.heat');
const heatLatLngTuple = await fetchData(); // fetchData returns data from JSON file
const mapTiles = Leaflet.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
});
heatLayer = Leaflet.heatLayer(heatLatLngTuple, {. // THIS LINE IS CAUSING THE ERROR
radius: 20,
blur: 25,
minOpacity: 0,
maxZoom: 6,
max: 12
});
map = Leaflet.map('map', {
center: [51.505, -0.09],
zoom: 6,
layers: [mapTiles, heatLayer]
});
});
</script>
<div id="map" />
Things I've tried:
including 'leaflet-heat.js' from node_modules in a <script> tag in app.html
including 'leaflet-heat.js' from node_modules in a <script> tag in __layout.svelte
including 'leaflet-heat.js' from node_modules in a <script> tag in index.svelte
importing leaflet.heat at the top of Map.svelte with "import 'leaflet.heat'" <- THIS WORKED IN ANGULAR! but here it just results in this error
ReferenceError: window is not defined
putting a tick() before assigning heatLayer in Map.svelte
Resources:
My GitHub repo
Leaflet.heat
As this answer points out there is an additional way of importing that I didn't know about using
vite-plugin-iso-import
After getting that set up my component now works and after importing "leaflet.heat" with ?client added and moved to the top level of my imports. Here is the link to the FAQ with a detailed explanation.
After the changes my component now looks like this:
Map.svelte
<script lang="ts">
import type { HeatLayer, Map } from 'leaflet';
import { onMount } from 'svelte';
import Leaflet from 'leaflet?client'; // provides definition of 'L' needed by Leaflet
import 'leaflet.heat?client'; // Note the '?client' after the module name which makes sure 'leaflet.heat' always has access to the 'window' object
let map: Map;
let heatLayer: HeatLayer;
onMount(async () => {
const heatLatLngTuple = await fetchData();
const mapTiles = Leaflet.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
});
heatLayer = Leaflet.heatLayer(heatLatLngTuple, {. // THIS LINE IS CAUSING THE ERROR
radius: 20,
blur: 25,
minOpacity: 0,
maxZoom: 6,
max: 12
});
map = Leaflet.map('map', {
center: [51.505, -0.09],
zoom: 6,
layers: [mapTiles, heatLayer]
});
});
</script>
<div id="map" />
I had this same issue on refresh, you need import the module inside the on mount. It's not the same as your code. But you get that point.
onMount(async () => {
const leafletModule = await import('leaflet');
L = leafletModule.default;

Mapbox GL JS with Maki icons by Marker

I generated a list of Maki Icons I want to use via the original icon editor.
drawMarkers() {
let self = this;
const mapboxgl = require("mapbox-gl");
let data = this.draw.getAll();
data.features.forEach((feature) => {
if (feature.geometry.type == "Point") {
var icon = feature.properties.icon;
var title = feature.properties.title;
if (typeof title === "undefined") {
title = "Info";
} else {
var popup = new mapboxgl.Popup({ offset: 25 }) // add popups
.setHTML(`<h3>${title}</h3>`);
var marker = new mapboxgl.Marker({
color: '#333',
draggable: false,
scale: 1,
})
.setLngLat(feature.geometry.coordinates)
.setPopup(popup)
.addTo(self.map);
}
});
The Markers are showed correctly on the Mapbox.
The GeoJSON is like this:
"type":"FeatureCollection",
"features":[
{
"id":"c749de6a6eac6b1cfdda890e7c665e0d",
"type":"Feature",
"properties":{
"icon":"ferry",
"title":"This should show a Ferry icon",
"portColor":"#d9eb37"
},
"geometry":{
"coordinates":[
6.12,
22.44
],
"type":"Point"
}
},
I want the Maki Icons also added in the Marker, but I cannot find any documentation of how icons can be used inside the Mapbox Marker.
Who can help me out? I'm using the Mapbox GL JS for Web.
It depends on how you've created your map. You can either:
Create your own map style using the Maki icons you've generated. This is done using the Mapbox studio to create your custom map style, then adding it to your application.
Create custom markers that use the maki .svg files you've created. This can be done by passing a custom element to the new mapboxgl.Marker() function. So, instead of:
var marker = new mapboxgl.Marker({
color: '#333',
draggable: false,
scale: 1,
})
you would pass:
var marker = new mapboxgl.Marker(customElement)
where customElement uses the data from your icons variable.
I'm not sure if you're using plain JS here, but there's some examples on the mapbox docs of ways you can do this.
Because you've generated your own list of Maki icons, I'd suggest downloading them and maybe host them somewhere so that you can get away with creating your markers with <img src="link to hosted maki marker"/> or something of the sort

Error with Mapbox GL integration when adding markers: "Cannot read property 'coordinates' of undefined"

I've been working on creating a dynamically updated Mapbox GL integration inside Webflow's CMS. I've succeeded in creating an array of features that can be read by Mapbox's API, but these features won't show on the map because the coordinates are not being read by the function that creates the map markers.
I receive the following error Cannot read property 'coordinates' of undefined at map-test-page:139 which is where a longitude and latitude is assigned to the current marker via this line: .setLngLat(marker.geometry.coordinates)
Partial solution was found here, but the code I've integrated into my site doesn't have featuresIn or featuresAt functions which seem to be the only way to include a includeGeometry: true parameter.
I'm curious if I need to rethink how I've created markers and do something with a function like map.on('click', ...) reference here.
Here is a minimal version that reproduces my issue.
If you're familiar with the Webflow interface you can view a read-only version of the site.
Any help would be greatly appreciated!
Here is the Mapbox script I'm using on the page:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/strawpari/ckp2nu3dw6cwu17nt4kqwf1vv',
center: [-13.723969, 48.360542],
zoom: 2,
pitch: 0,
bearing: 0,
antialias: true,
interactive: true
});
var geojson = {
type: 'FeatureCollection',
features: farmerArray,
};
// add markers to map
geojson.features.forEach(function(marker) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 }) // add popups
.setHTML('<img src=\'' + marker.properties.image + '\' width=\'50\' height=\'50\' border-radius=\'50%\'>' + '<h3>' + marker.properties.title + '</h3><p>' + marker.properties.description + '</p>'))
.addTo(map);
});
And here is the code embedded in each CMS item that adds a farmer's information to the farmerArray which is being read by Mapbox. Text in double-quotations "" is a placeholder for the dynamic information populated by the CMS.
var farmerArrayItem =
JSON.stringify({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: ["longitude", "latitude"]
},
properties: {
title: "name",
description: "text",
image: "imagepath"
}
});
farmerArray.push(farmerArrayItem);
It doesn't appear that you have tried using the Developer Tools to debug your code. That's definitely a skill you should pick up.
With the dev tools, you will quickly see that the value of marker at the critical point is a string:
So you just need to use JSON.parse:
geojson.features.forEach(function(markerString) {
const marker = JSON.parse(markerString);
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)

how to create a jsfiddle using leaflet

I am struggling with jsfiddle trying to create a running example which uses leaflet.
because I was not successful I searched for some examples and found the following one working:
http://jsfiddle.net/kedar2a/LnzN2/2/
I then copied the example in a new fiddle
https://jsfiddle.net/aLn3ut5z/1/
but it is still not working...
when inserting the external resources, there was the following error:
jsfiddle.net says:
You're loading resources over HTTP not HTTPS, your fiddle will not
work. Do you wish to continue?
any suggestions what is wrong here?
p.s.: below is the code of the jsfiddle windows:
HTML:
<div id="map"></div>
CSS:
#map {
height: 500px;
width: 80%;
}
JAVASCRIPT:
// We’ll add a tile layer to add to our map, in this case it’s a OSM tile layer.
// Creating a tile layer usually involves setting the URL template for the tile images
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([19.04469, 72.9258], 12).addLayer(osm);
// Script for adding marker on map click
function onMapClick(e) {
var marker = L.marker(e.latlng, {
draggable: true,
title: "Resource location",
alt: "Resource Location",
riseOnHover: true
}).addTo(map)
.bindPopup(e.latlng.toString()).openPopup();
// Update marker on changing it's position
marker.on("dragend", function(ev) {
var chagedPos = ev.target.getLatLng();
this.bindPopup(chagedPos.toString()).openPopup();
});
}
map.on('click', onMapClick);
The Leaflet CDN doesn't support SSL yet. You can use something not requiring https, like playground-leaflet which is just a fork of JSBin with leaflet libraries easily selectable.
Alternatively, you could use Leaflet from cdnjs.net, which does support https.

Mapbox Filter Markers loaded via json

I am looking for solution to add filter (not checkbox) to my site. I have this code loading blank map from Mapbox and added Markers from JSON file. I was trying to add setFilter function, but probably I am using it wrong. I would like to filter items by category property from my JSON file.
<script>
L.mapbox.accessToken = '*************';
var baseLayer = L.mapbox.tileLayer('test****');
var markers = L.markerClusterGroup();
// CALL THE GEOJSON HERE
jQuery.getJSON("locations.geojson", function(data) {
var geojson = L.geoJson(data, {
onEachFeature: function (feature, layer) {
// USE A CUSTOM MARKER
layer.setIcon(L.mapbox.marker.icon({'marker-symbol': 'circle-stroked', 'marker-color': '004E90'}));
// ADD A POPUP
layer.bindPopup("<h1>" + feature.properties.title + "</h1><p>" + feature.properties.description + "</p><p><a href=' + feature.properties.website + '>" + feature.properties.website + "</a></p>");
layer.on('mouseover', function (e) {
this.openPopup();
});
layer.on('mouseout', function (e) {
this.closePopup();
});
}
});
markers.addLayer(geojson);
// CONSTRUCT THE MAP
var map = L.map('map', {
searchControl: {layer: markers},
zoom: 6,
center: [51.505, -0.09],
maxZoom: 13
})
.setView([62.965, 19.929], 5)
.fitBounds(markers.getBounds());
baseLayer.addTo(map);
markers.addTo(map);
L.control.fullscreen().addTo(map);
});
</script>
Could you please help me add filter buttons (something like here: https://www.mapbox.com/mapbox.js/example/v1.0.0/filtering-markers)
PS: I think I tried all examples from Mapbox website, yet seems my skills are very limited here.
Thank you
I was trying to add setFilter function, but probably I am using it wrong. I would like to filter items by category property from my JSON file.
This code example is using L.geoJson to load the markers into your map. Like the Mapbox example, you'll need to use L.mapbox.featureLayer instead, since it includes the setFilter function and L.geoJson does not.
tmcw's answer is correct, L.mapbox.featureLayer is confusing
this tutorial helped me!
https://www.mapbox.com/mapbox.js/example/v1.0.0/custom-marker-tooltip/