Home > Mobile >  SVG Zoom Issue Desktop vs Mobile with leaflet.js
SVG Zoom Issue Desktop vs Mobile with leaflet.js

Time:12-27

I've tried to use iphone capture

CodePudding user response:

Display the variables w and h you will see what small variables are returned. To increase them I increased them by * 5 for this I used fitBounds and it should now scale to the viewer window and at the same time it is possible to zoom.

To be able to also click more than once on the zoom, I changed map.getMaxZoom () - 1 to map.getMaxZoom () - 2

var map = L.map("image-map", {
  minZoom: 1, // tried 0.1,-4,...
  maxZoom: 4,
  center: [0, 0],
  zoom: 2,
  crs: L.CRS.Simple
});

function getMeta(url) {
  const img = new Image();
  img.addEventListener("load", function () {
    var w = this.naturalWidth * 5;
    var h = this.naturalHeight * 5;

    var southWest = map.unproject([0, h], map.getMaxZoom() - 2);
    var northEast = map.unproject([w, 0], map.getMaxZoom() - 2);
    var bounds = new L.LatLngBounds(southWest, northEast);

    // add the image overlay,
    // so that it covers the entire map
    L.imageOverlay(img.src, bounds).addTo(map);

    // tell leaflet that the map is exactly as big as the image
    // map.setMaxBounds(bounds);
    map.fitBounds(bounds);
  });
  img.src = url;
}

getMeta("https://fractalcitta.github.io/assets/images/bhikkhu-patimokkha.svg");

You don't need to increase (w, h) * 5 but just change to map.getMaxZoom () - 4

And one more important thing that you should always do with svg, which is optimizing these files. I always use this site - svgomg

Second version width async/promise ----------

let map = L.map("map", {
  crs: L.CRS.Simple,
  minZoom: 1,
  maxZoom: 4,
});

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.addEventListener("load", () => resolve(img));
    img.addEventListener("error", reject);
    img.src = url;
  });
}

async function getImageData(url) {
  const img = await loadImage(url);
  return { img, width: img.naturalWidth, height: img.naturalHeight };
}

async function showOnMap(url) {
  const { img, width, height } = await getImageData(url);

  const southWest = map.unproject([0, height], map.getMaxZoom() - 4);
  const northEast = map.unproject([width, 0], map.getMaxZoom() - 4);

  const bounds = new L.LatLngBounds(southWest, northEast);
  L.imageOverlay(img.src, bounds).addTo(map);

  map.fitBounds(bounds);
}

showOnMap(
  "https://fractalcitta.github.io/assets/images/bhikkhu-patimokkha.svg"
);

The third approach to the problem, I hope the last one ;)

You need a little description of what's going on here. We get svg by featch we inject into hidden div which has width/height set to 0
Then we use the getBBox() property to get the exact dimensions from that injected svg.

I am not using map.unproject in this example. To have the exact dimensions of bounds it is enough that:

const bounds = [
  [0, 0], // padding
  [width, height], // image dimensions
];

All code below:

<div id="map"></div>
<div id="svg" style="position: absolute; bottom: 0; left: 0; width: 0; height: 0;"></div>
let map = L.map("map", {
  crs: L.CRS.Simple,
  minZoom: -4,
  maxZoom: 1,
});

const url =
  "https://fractalcitta.github.io/assets/images/bhikkhu-patimokkha.svg";

async function fetchData(url) {
  try {
    const response = await fetch(url);
    const data = await response.text();
    return data;
  } catch (err) {
    console.error(err);
  }
}

fetchData(url)
  .then((svg) => {
    const map = document.getElementById("svg");
    map.insertAdjacentHTML("afterbegin", svg);
  })
  .then(() => {
    const svgElement = document.getElementById("svg");
    const { width, height } = svgElement.firstChild.getBBox();
    return { width, height };
  })
  .then(({ width, height }) => {
    const img = new Image();
    img.src = url;

    const bounds = [
      [0, 0], // padding
      [width, height], // image dimensions
    ];

    L.imageOverlay(img.src, bounds).addTo(map);

    map.fitBounds(bounds);
  });

CodePudding user response:

OK, so finally I used the code from @Grzegorz T. with a small modification. Adding a const H = 100; that play the role of an arbitrary height and then the width W is calculated using the ratio of dimensions given by the browers. (ratio are the same, dimension of SVG are differents on different browsers)

Here is the code :

const W = 100; // this allow to get the correct ratio 
               // then it dosen't depend on browser giving different dimentions.

    let map = L.map("image-map", {
        crs: L.CRS.Simple,
        minZoom: 1,
        maxZoom: 4,
    });

    function loadImage(url) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.addEventListener("load", () => resolve(img));
            img.addEventListener("error", reject);
            img.src = url;
        });
    }

    async function getImageData(url) {
        const img = await loadImage(url);
        return { img, width: img.naturalWidth, height: img.naturalHeight };
    }

    async function showOnMap(url) {
        const { img, width, height } = await getImageData(url);

        const H = W * width / height; // hopefuly height is not = 0 (mozilla ?)

        const southWest = map.unproject([0, H], map.getMaxZoom() - 4);
        const northEast = map.unproject([W, 0], map.getMaxZoom() - 4);

        const bounds = new L.LatLngBounds(southWest, northEast);
        L.imageOverlay(img.src, bounds).addTo(map);

        map.fitBounds(bounds);
    }

    showOnMap(
        "https://fractalcitta.github.io/assets/images/bhikkhu-patimokkha.svg"
    );
  • Related