Display line in Mapbox GL from search result to nearest point on feature - mapbox-gl-js

I'd like to draw a line between two points: geocoder search result and nearest point on a featurecollection of points.
My geocoder search is working correctly and I can find the nearest point in my feature collection using turf.nearestPoint. I have tried to modify several different examples but
I cannot create a linestring from the two points and add it to the map.
My code:
https://jsfiddle.net/aventre/oxmkfh42/15/
`
<style>
#menu {
position: absolute;
background: #efefef;
padding: 10px;
font-family: 'Open Sans', sans-serif;
}
#info {
display: block;
position: relative;
margin: 0px auto;
width: 50%;
padding: 10px;
border: none;
border-radius: 3px;
font-size: 12px;
text-align: center;
color: #222;
background: #fff;
}
</style>
<pre id="info"></pre>
<div id='map' style='width: 100%; height: 700px;'></div>
<div id="menu">
<input id="cl8lwwv48002h14qidkgt1twz" type="radio" name="rtoggle" value="Map" checked="checked">
<label for="cl8lwwv48002h14qidkgt1twz">Map</label>
<input id="cl8m1m04n001l14o6gv40ynbf" type="radio" name="rtoggle" value="Sat">
<label for="cl8m1m04n001l14o6gv40ynbf">Satellite</label>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYXZlbnRyZSIsImEiOiJjazcwdTN1czkwMDY1M2xwc2Z1dDIxaWgwIn0.2a7GUY9_JPNpp4c0jDaMAA';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/aventre/cl8lwwv48002h14qidkgt1twz', // stylesheet location
center: [-78.66839943, 38.39604638], // starting position [lng, lat]
zoom: 13.5 // starting zoom
});
const fence = {
"type": "FeatureCollection",
"name": "NectarFencePoints",
"features": [{
"type": "Feature",
"properties": {
"distance": 0.0,
"angle": 245.64902626829135
},
"geometry": {
"type": "Point",
"coordinates": [-78.666611972264633, 38.394739637005529, 0.0]
}
},
{
"type": "Feature",
"properties": {
"distance": 25.0,
"angle": 245.64902626829135
},
"geometry": {
"type": "Point",
"coordinates": [-78.666691366204603, 38.394711225055076, 0.0]
}
},
{
"type": "Feature",
"properties": {
"distance": 50.0,
"angle": 271.26325988216735
},
"geometry": {
"type": "Point",
"coordinates": [-78.666778146733265, 38.394711020361669, 0.0]
}
}
]
};
var layerList = document.getElementById('menu');
var inputs = layerList.getElementsByTagName('input');
map.addControl(new mapboxgl.FullscreenControl());
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/aventre/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
map.on('click', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['loblolly-labels'] // replace this with the name of the layer
});
if (!features.length) {
return;
}
var feature = features[0];
var popup = new mapboxgl.Popup({
offset: [25, 25]
})
.setLngLat(feature.geometry.coordinates)
.setHTML('<h4>' + feature.properties.title + '</h4><p>' + feature.properties.description + '</p>')
.addTo(map);
});
map.on('mouseenter', 'loblolly-labels', function(e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.description;
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
// Populate the popup and set its coordinates
// based on the feature found.
popup.setLngLat(coordinates).setHTML(description).addTo(map);
});
map.on('mouseleave', 'loblolly-labels', function() {
map.getCanvas().style.cursor = '';
popup.remove();
});
var geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl
});
map.addControl(geocoder, 'top-left');
geocoder.on('result', (event) => {
/* Get the coordinate of the search result */
const searchResult = event.result.geometry;
const nearest = turf.nearestPoint(searchResult, fence)
const marker = new mapboxgl.Marker()
.setLngLat(nearest.geometry.coordinates)
.addTo(map);
map.addLayer({
'id': 'route',
'type': 'line',
'source': {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[nearest.lng, nearest.lat],
[searchResult.lng, searchResult.lat]
]
}
},
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#888',
'line-width': 8
}
}
});
});
</script>
`

Related

Hover effect for Countries

SO I am new to Mapbox but I am trying to make countries change color on hover. I have seen the hover tutorial on the Docs for states but I am having difficulty finding the right type, data, and source for countries. I have the Mapbox Countries v1 already added to the map from studio. When I try to run this code I get either that it can't find source:"country_boundaries" or "country-boundaries". I know it's something simple but appreciate the help. Thanks.
var hoveredStateId = null;
map.on('load', function () {
==>>map.addSource('states', {
==>>'type': 'geojson',
==>>'data': 'https://docs.mapbox.com/mapbox-gl-js/assets/us_states.geojson'
});
map.addLayer({
'id': 'state-fills',
==>>'type': 'fill',
==>>'source': 'states',
'layout': {},
'paint': {
'fill-color': '#627BC1',
'fill-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
1,
0.5
]
}
});
map.addLayer({
'id': 'state-borders',
==>>'type': 'line',
==>>'source': 'states',
'layout': {},
'paint': {
'line-color': '#627BC1',
'line-width': 2
}
});
Below you will find a complete example I've put together from findings at https://docs.mapbox.com/ and other places on the internet.
Please note that this uses Mapbox example token and http://geojson.xyz/ directly, you should download the data and host it yourself if used in an production environment.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Display a map on a webpage</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoid2l0dHJ1cCIsImEiOiJjbDc1NnFpaWIwYzZqM3VudGptdjUzNWZ1In0.R5FpTsM0CeaxLhq8i8Qmyg';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.5, 40], // starting position [lng, lat]
zoom: 0.31741259330687854
});
map.on('load', function () {
map.addSource('cbs', { // country-boundaries-simplified
'type': 'geojson',
'data': 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_countries.geojson'
});
map.addLayer({
"id": "cf", // country-fills
"type": "fill",
"source": "cbs",
"layout": {},
"paint": {
"fill-color": "#627BC1",
"fill-opacity": 0.5
}
});
map.addLayer({
"id": "cb", // country borders
"type": "line",
"source": "cbs",
"layout": {},
"paint": {
"line-color": "#627BC1",
"line-width": 2
}
});
map.addLayer({
"id": "cfh", // country-fills-hover",
"type": "fill",
"source": "cbs",
"layout": {},
"paint": {
"fill-color": "#FFFFFF",
"fill-opacity": 1
},
"filter": ["==", "name", ""]
});
// When the user moves their mouse over the page, we look for features
// at the mouse position (e.point) and within the states layer (states-fill).
// If a feature is found, then we'll update the filter in the state-fills-hover
// layer to only show that state, thus making a hover effect.
map.on("mousemove", function(e) {
var features = map.queryRenderedFeatures(e.point, { layers: ["cf"] });
if (features.length) {
map.getCanvas().style.cursor = 'pointer';
map.setFilter("cfh", ["==", "name", features[0].properties.name]);
} else {
map.setFilter("cfh", ["==", "name", ""]);
map.getCanvas().style.cursor = '';
}
});
// Reset the state-fills-hover layer's filter when the mouse leaves the map
map.on("mouseout", function() {
map.getCanvas().style.cursor = 'auto';
map.setFilter("cfh", ["==", "name", ""]);
});
map.on("click", function(e) {
var features = map.queryRenderedFeatures(e.point, { layers: ["cf"] });
if (features.length) {
console.log(e, features[0].properties.name);
}
});
});
</script>
</body>
</html>

Mapbox - Disable Clustering Entirely

I have started playing around with Mapbox, and things are working as I would like, except that I have not been able to figure out how to disable clustering. Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Add custom icons with Markers</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.0.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.0.0/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
.marker {
/*display: block;*/
border: none;
/*border-radius: 50%;*/
cursor: pointer;
padding: 0;
background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Map_pin_icon.svg/176px-Map_pin_icon.svg.png');
background-size: cover;
width: 20px;
height: 27px;
/*border-radius: 50%;*/
/*cursor: pointer;*/
}
</style>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoibmFiZWxla3QiLCJhIjoiY2p4ZXVubnQwMGVmcTN6cGU0c3JpZmM2diJ9.peecDCcSljWhChxCknv7AQ';
var coordinates = [
[6.73579, 78.72300],
[2.70886, 11.51694],
[34.05482, -57.09742],
[-39.05019, 89.79126],
[17.44893, 35.57014],
[23.60105, 168.12674],
[-4.87631, 72.99334],
[39.7392, -104.9903],
[39.79905,-105.78118],
[39.80266,-105.78692],
[39.79758,-105.78061],
[39.80314,-105.78978],
[39.80313,-105.78999],
[39.80103,-105.78272],
[39.80096,-105.78259],
[39.80187,-105.78407],
[39.80283,-105.78593],
[39.79937,-105.78134],
[39.80023,-105.78164],
[39.80272,-105.78765],
[39.80263,-105.78673],
[39.80264,-105.78676],
[39.80125,-105.78326],
[39.7976,-105.78028],
[39.80316,-105.7905],
]
var num_coordinates = Object.keys(coordinates).length
var geojson = {
"type": "FeatureCollection",
"features": []
}
for (var coord_ind = 0; coord_ind < num_coordinates; coord_ind++) {
geojson.features.push({
"type": "Feature",
"properties": {
"message": "Bar",
"iconSize": [300, 300]
},
"geometry": {
"type": "Point",
"coordinates": [coordinates[coord_ind][1], coordinates[coord_ind][0]] // Longitude then Latitude
}
})
}
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location
// style: 'mapbox://styles/mapbox/satellite-v9', // stylesheet location
center: [-99.66, 38.46], // starting position [lng, lat]
zoom: 5.5 // starting zoom
});
map.on('load', function() {
map.loadImage('https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Map_pin_icon.svg/176px-Map_pin_icon.svg.png', function(error, image) {
if (error) throw error;
map.addImage('pin', image);
map.addSource("photo_locations", {
type: "geojson",
data: geojson,
cluster: false,
clusterMaxZoom: 1, // Max zoom to cluster points on
clusterRadius: 1 // Radius of each cluster when clustering points (defaults to 50)
});
map.addLayer({
"id": "points",
"type": "symbol",
"source": "photo_locations",
"layout": {
"icon-image": "pin",
"icon-size": 0.12
}
});
});
});
</script>
</body>
</html>
You can see that I have cluster: false set for my source. However, if you display this in your browser, the pins are still clustered together. If you zoom in on the pin to the west of Denver, you will see it separate into multiple pins.
How can I get clustering to disable entirely so that each individual pin can be seen at any zoom level? Any thoughts are appreciated. Thanks!
As geografa suggested, adding "icon-allow-overlap": true does the trick. This needs to be added to the layout section of the layer. So I now have:
...
"layout": {
"icon-image": "pin",
"icon-size": 0.08,
"icon-allow-overlap": true
}
...

Get absolute pixel coordinates from LatLng

I need the absolute pixel coordinates from a LatLng coordinate in Leaflet. Just to make it clear, these coordinates are the pixel distance from the upper left corner till a LatLng coordinate on the map.
I read the The pixel origin chapter from the extending Leaflet Tutorial but I don't get it. latLngToLayerPoint or project conversion methods should do it - but I don't get the real pixel position:
const pixelPoint = map.project(feature.geometry.coordinates[0], map.getZoom());
const pixelOrigin = map.getPixelOrigin();
const pixelCoord = pixelPoint.subtract(pixelOrigin);
const layerPoint = map.latLngToLayerPoint(feature.geometry.coordinates[0]);
Here is the jsfiddle with my failed tests.
Your projection code is not the problem, it is the data format: leaflet assumes arrays as latlon, while in the geojson it is lonlat! Try swapping or use the L.latLng object.
var freeBus = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.00341892242432, 39.75383843460583],
[-105.0008225440979, 39.751891803969535]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": false
},
"id": 1
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.0008225440979, 39.751891803969535],
[-104.99820470809937, 39.74979664004068]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": true
},
"id": 2
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-104.99820470809937, 39.74979664004068],
[-104.98689651489258, 39.741052354709055]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": false
},
"id": 3
}
]
};
var map = L.map('map', {
center: [39.74739, -105],
zoom: 13
});
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.light'
}).addTo(map);
function onEachFeature(feature, layer) {
layer.bindPopup(
function(layer) {
// get pixel coordinates from first LatLng coordinate
const latlon = L.latLng(feature.geometry.coordinates[0][1], feature.geometry.coordinates[0][0]);
const pixelPoint = map.project(latlon, map.getZoom());
const pixelOrigin = map.getPixelOrigin();
const pixelCoord = pixelPoint.subtract(pixelOrigin);
const layerPoint = map.latLngToLayerPoint(latlon);
var popupContent = "<h1>Pixel coordinates</h1>";
popupContent += "<p>Point: " + pixelPoint + "</p>";
popupContent += "<p>Origin: " + pixelOrigin + "</p>";
popupContent += "<p>Diff: " + pixelCoord + "</p>";
popupContent += "<p>layerPoint: " + layerPoint + "</p>";
return popupContent;
}
);
}
L.geoJSON(freeBus, {
filter: function(feature, layer) {
if (feature.properties) {
// If the property "underConstruction" exists and is true, return false (don't render features under construction)
return feature.properties.underConstruction !== undefined ? !feature.properties.underConstruction : true;
}
return false;
},
onEachFeature: onEachFeature
}).addTo(map);
html, body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
position: absolute;
}
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css" rel="stylesheet"/>
<div id='map'></div>

Q: how to add "fade in" transition effect for Mapbox circle layer

I'm loading points from Geojson in batches and would like to add "fadeIn" effect or animation when the points first appear in Mapbox.
this.map.addLayer({
id: 'points',
type: 'circle',
paint: {
'circle-radius-transition': {duration: 300},
'circle-color': '#F98200',
'circle-stroke-color': '#D23B00',
'circle-stroke-opacity': 0.5,
},
source: 'points',
})
I tried circle-radius-transition but it does not seem to help.
You are on the right track with the paint properties. I think what you need is the circle-opacity-transition.
Follow these steps:
Add the points with 'circle-opacity': 0 as default opacity value
Set the 'circle-opacity-transition' as you wish
After the map is loaded change the layers 'circle-opacity' to 1 and your layer will be faded in.
map.addLayer({
"id": "point",
"source": "point",
"type": "circle",
"paint": {
"circle-radius": 20,
// here we define defaut opacity is zero
"circle-opacity": 0,
"circle-opacity-transition": {duration: 2000},
"circle-color": 'red'
}
});
You can check out this solution here: codepen
Joel's answer was perfect but the timeout has to be places inside the map load function else the circle layer will not be loaded if the map takes more time to load
Checkout the below code snippet
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9lbHN0dWVkbGUiLCJhIjoiY2ltbmI1OWNpMDAxNnV1bWFtMnpqYWJndyJ9.uDWVjgzU7EVS63OuVWSRuQ';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v9', //stylesheet location
center: [7.445683, 46.945966], // starting position
zoom: 9 // starting zoom
});
// the data we'll add as 'points'
var data = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"timestamp": "0",
"location-name": "Bern"
},
"geometry": {
"type": "Point",
"coordinates": [7.445683, 46.945966]
}
}]
}
// so if the map loads do the following
map.on('load', function() {
// add the data source with the information for the point
map.addSource('point', {
"type": "geojson",
"data": data
});
map.addLayer({
"id": "point",
"source": "point",
"type": "circle",
"paint": {
"circle-radius": 20,
// here we define defaut opacity is zero
"circle-opacity": 0,
"circle-opacity-transition": {
duration: 1500
},
"circle-color": 'red'
}
});
//Timeout shoud be within the map load function
setTimeout(function() {
map.setPaintProperty('point', 'circle-opacity', 1);
}, 1);
});
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.36.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.36.0/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
</body>
</html>
Unfortuntely the property-transition won't work in some cases, for example, when you want to toggle a layer on hover.
At least, in my case it does not work. This is my code, the elements pop like there's nothing.
map.addLayer({
'id': 'places-details',
'type': 'symbol',
'source': 'places',
'layout': {
'icon-image': '{icon}',
'text-field': '{data}',
'icon-size': .8,
'text-anchor': 'center',
},
'paint': {
'text-color': '#ffffff',
'icon-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
1, 0
],
'text-opacity': [
'case',
['boolean', ['feature-state', 'hover'], false],
1, 0
],
"text-opacity-transition": {
"duration": 3000,
"delay": 0
},
"icon-opacity-transition": {
"duration": 300,
"delay": 0
}
},
});

Mapbox Leaflet Polyline being created outside of map and not visible

When putting this example in a bootstrap template, the polyline and circle do not show up. When I inspect $('path'), I see that the lines are actually way up to the top left, and not visible. I've spent probably 3 hours and still haven't figured out what the issue is.
As you can see, things like markers show up fine, but polylines and circles etc. don't display on the map.
Here's the repo: https://github.com/zylajoel/polyExample
The relevant files are:
<!-- index.html -->
<div class="content-wrap">
<!-- main page content. the place to put widgets in. usually consists of .row > .col-md-* > .widget. -->
<main id="content" class="content" role="main">
<div class="map-container">
<div id='map'>
</div>
</div>
</main>
</div>
// index.js
L.mapbox.accessToken = 'pk.eyJ1Ijoiam9lbHp5bGEiLCJhIjoiZDU4YTUxMDQ4NDM3OTZkZDA5OThiMzYzNjA0ODRmN2EifQ.CWKDLwKY-bUz_6XYT5bGpg';
var map = L.mapbox.map('map',
'mapbox.satellite',
{
center: [35.2269, -80.8433],
zoom: 2,
featureLayer: true,
tileLayer: true,
gridLayer: true
});
// add some markers
L.marker([37.9, -77], {
icon: L.mapbox.marker.icon({
'marker-size': 'large',
'marker-symbol': 'bus',
'marker-color': '#fa0'
})
}).addTo(map);
// with popup
L.marker([10.9, -50], {
icon: L.mapbox.marker.icon({
'marker-size': 'large',
'marker-symbol': 'bus',
'marker-color': '#fa0'
})
// this should be a handlebars template
}).addTo(map).bindPopup('<p>Hello world!<br />This is a nice popup.</p>');
//.openPopup();
// make a point via geojson
var geoJSONExample = { "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
"properties": {"prop0": "value0"}
}
]};
var geoJSONExample1 = { "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates": [95.0, 10]},
"properties": {"prop0": "value0"}
}
]};
L.geoJson(geoJSONExample, {
pointToLayer: L.mapbox.marker.style,
}).addTo(map);
L.geoJson(geoJSONExample1, {
pointToLayer: L.mapbox.marker.style,
}).addTo(map);
// draw a line HELP
var thePolyline = L.polyline([[102.0, 0.5], [95.0, 10], [10.9, -50]], {
color: 'red'
});
thePolyline.addTo(map);
// draw a line HELP
var pointA = new L.LatLng(28.635308, 77.22496);
var pointB = new L.LatLng(28.984461, 77.70641);
var pointList = [pointA, pointB];
var firstpolyline = new L.Polyline(pointList, {
color: 'red',
weight: 3,
opacity: 0.5,
smoothFactor: 1
});
firstpolyline.addTo(map);
var circle = L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(map);
// application.css
#map {
width: 100%;
height: 100%;
}
.map-container {
height: 500px;
padding: 10px;
width: 100%;
}
Any ideas?
The problem is that Leaflet is conflicting with the CSS of the Single App Template you're using. The CSS in css/application.css is resetting the dimensions of the svg elements.
You need to change the css/application.css and remove the width and height properties of the svg selector :
svg {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Trying to get SVG to act like a greedy block in all browsers */
display: block;
/* Remove these: */
/* width: 100%; */
/* height: 100%; */
}
If you still need to reset the dimensions of other svg elements, just use a different selector.