0

I am trying to develop a website consisting of a geographic map using svg, with data derived from OpenStreetMap. Since it will be large and will be accepting transformations (zooming and moving), only a part of it will visible on the screen. So, for performance issues, probably it will be necessary to find a way to asynchronously load parts of it. Is there a way to do this? (e.g., like CATiledLayer of iOS)

How do websites like Google Maps do this?

ckc
  • 345
  • 4
  • 12
  • 1
    Just like with tiling images, the SVG would need to be broken up ahead of time. – Ouroborus Oct 26 '21 at 07:55
  • @Ouroborus Yes, it would need to be split in parts (tiles), but how is the asynchronous loading of the parts realized? – ckc Oct 26 '21 at 07:59
  • 1
    Google maps uses lots of individual images that are carefully placed next to each other. It isn't one large image. SVG is similar to the DOM in that you can load individual parts of it and just insert them, but bear in mind that this will cause a repaint each time you do this due to the fact SVG gets converted to a raster image before it is rendered. I would follow the Google pattern of individual images that are carefully positioned in a large container to avoid this, those images can of course be SVGs if you wish! – GrahamTheDev Oct 26 '21 at 08:12
  • @GrahamRitchie I can split the map in small parts (images of SVGs), but I don't know how to load each time only the ones that are currently visible. In iOS, this is achieved using CATiledLayer. Is there somethiing similar in web programming? – ckc Oct 26 '21 at 08:20
  • 1
    Set them at a specific size (say 200px by 200px) and create a container for each image at that size. Then look at [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) as this will let you know when the image is in a position where it should be visible. I would then just switch the `src` on the image when it is in the viewport (or your outer container if it isn't full screen) as the simplest solution. – GrahamTheDev Oct 26 '21 at 08:22
  • @GrahamRitchie thank you, I will try your approach – ckc Oct 26 '21 at 12:24

1 Answers1

0

You have to use the svg inline and not as an image reference. This way you will be able to manipulate the image parts as a DOM elements with javascript.

// adding a black circle after 1 sec
setTimeout(() => {
  var svgNS = "http://www.w3.org/2000/svg"
  var myImage = document.createElementNS(svgNS,"image")
  myImage.setAttributeNS(null,"x",20)
  myImage.setAttributeNS(null,"y",20) 
  myImage.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href","https://picsum.photos/200/200")
  document.getElementById("mySVG").appendChild(myImage)
}, 1000)
<!-- existing svg image -->
<svg id="mySVG">
  <circle fill="red" cx="20" cy="20" r="20" />
  
</svg>

In the above example an image is being added to an existing svg. Thanks for Alex Moanga and Daveman for the js snippets.

gazdagergo
  • 6,187
  • 1
  • 31
  • 45
  • gazdagergo Thank you for your answer. It is not relevent though, since the question is how to load only the images/SVGs that are currently visible (due to scrolling or zooming) – ckc Oct 26 '21 at 08:32
  • ah ok, you mean the map tile images right? – gazdagergo Oct 26 '21 at 08:47
  • Yes, only the ones that are currently visible must be loaded – ckc Oct 26 '21 at 08:51
  • 1
    OK, I think this still can work with images. The setTimeout simulates the async call. You need to detect which image should be loaded using intersection api maybe. I've changed my example to image. – gazdagergo Oct 26 '21 at 09:04