19

Is it possible to use SVG image as the base map for leaflet.js ?

In my case I have huge svg file and I wish to allow my users to use all of leaflet's features such as zoom, markers, layers.

amitdar
  • 917
  • 3
  • 13
  • 35

2 Answers2

23

Yes, you can just use imageOverlay, like this

// create the map
var map = L.map('map', {
  center: [40.75, -74.2],
  zoom: 13
});

var imageUrl = 'https://www.amcharts.com/lib/3/maps/svg/australiaHigh.svg',
  imageBounds = [
    [40.712216, -74.22655],
    [40.773941, -74.12544]
  ];

L.imageOverlay(imageUrl, imageBounds).addTo(map);
#map {
  height: 400px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<div id="map"></div>
Adam Azad
  • 11,171
  • 5
  • 29
  • 70
Rob Imig
  • 496
  • 4
  • 10
  • Thanks!! How did you calculate the bounds ? – amitdar Jan 21 '16 at 06:44
  • I updated the fiddle. It's up to you, could just do `imageBounds = [[0, 0], [100, 100]];` and then just pass `center: [50, 50], zoom: 1` to leaflet to keep it simple. – Rob Imig Jan 21 '16 at 15:46
  • Pardon my ignorance (and thanks for your great answer) but what does setting the bounds and then passing center and zoom like the above comment do? – Kristopher Dec 13 '16 at 17:59
  • 2
    It seems that adding `crs: L.CRS.Simple` lets you specify things in pixels instead of lat/long. – Josh Santangelo Sep 02 '17 at 02:21
  • I'm using leaflet in Android and showing image on webview. I'm loading the image from local cache. I'm not using remote URL as an `imageUrl`. In my case, `imageUrl` contain the location of local cache. For `.svg` it won't work – Papan Mar 09 '19 at 06:57
  • 1
    @Papan Just get the `height/width` coordinates from svg with this method - `getBBox()` – Grzegorz T. Sep 21 '20 at 08:13
  • If you are having difficulties with the zoom, I recommend to export as PNG and use then the same way as an image overlay, it will work like a charm, e.g. https://jsfiddle.net/user2314737/Lfzrqvet/ – Timothy Dalton Jan 02 '21 at 15:45
0

Translate SVG to leaflet coordinates

In addition to Rob Imig's answer: you probably want to place markers relative to your svg coordinates.

Based on the official leaflet simple CRS example:

  1. check your SVG's intrinsic width/height or viewBox values
  2. apply these values to the bounds like so:
const bounds = [[0, 0], [svgHeight, svgWidth]];  

So we need to swap x/y order as explained by
IvanSanchez ("Leaflet+GeoJSON: Why are lat-lng coordinates in the wrong order?")

Leaflet uses lat-lng (or northing-easting)

const map = L.map('map', {
  crs: L.CRS.Simple,
  minZoom: -2,
  maxZoom: 20
});

const bounds = [
  [0, 0],
  [607, 756]
];
const image = L.imageOverlay('https://upload.wikimedia.org/wikipedia/commons/b/bb/Mayor_of_London_constituency_results_2000.svg', bounds).addTo(map);

var marker = L.marker([303.5, 378]).addTo(map);
marker.bindPopup("<b>Hello world!</b><br>I am a popup. SVG coordinates: x: 378; y:303.5").openPopup();


map.fitBounds(bounds);
html,
body {
  height: 100%;
  margin: 0;
}

.leaflet-container {
  width: 100%;
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 756/607;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>

<div id='map'></div>

In the above example the intrinsic dimensions are:
width: 756
height: 607

We can place a marker at the horizontal and vertical center like so:

var marker = L.marker([ svgHeight/2, svgWidth/2]).addTo(map);  

Play around with codepen example

herrstrietzel
  • 11,541
  • 2
  • 12
  • 34