0

I have a img element , his src attribute is a svg url file.
I can get this img dom element, but I want to get this file content, and can't use ajax.
thanks! example:

<svg>
<rect> </rect>
</svg>

this is my code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img id="testImg" src="logo.svg" alt="">

    <script>
        const img = document.getElementById('testImg');

        console.log('img', [img]);
    </script>
</body>
</html>

This is my scene! I can't use ajax because I can't get the data of the asynchronous setting of 'ondragstart' in the 'ondrop' event.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <img id="img" draggable="true" src="logo.png" width="50px" height="50px" />

    <div
      id="div"
      style="background-color: #123; width: 400px; height: 300px;"
    ></div>
    <script>
      const img = document.getElementById('img');
      img.addEventListener('dragstart', function(e) {
        const src = e.target.src;
        console.log(src);

        axios.get(src).then(function(res) {
          console.log(res.data);
          e.dataTransfer.setData('text/plain', res.data);
        });

      });

      const div = document.getElementById('div');
      div.addEventListener('dragover', function(e) {
        e.preventDefault();
      });
      div.ondrop = function(e) {
        const data = e.dataTransfer.getData('text/plain');
        console.log(data);
      };
    </script>
  </body>
</html>
SignDawn
  • 3
  • 3
  • You can use fetch. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API – Keith Feb 21 '22 at 02:36
  • Not sure if this might help, but check it out https://stackoverflow.com/questions/2753732/how-to-access-svg-elements-with-javascript – Pietro Nadalini Feb 21 '22 at 02:51
  • "can't use ajax." why? – Kaiido Feb 21 '22 at 03:10
  • @Kaiido img has request svg content , request again is not good. And in event method 'dragstart' can't use async – SignDawn Feb 21 '22 at 06:56
  • @PietroNadalini thanks , it is a good idea , but 'object' seems unable to drag. – SignDawn Feb 21 '22 at 06:58
  • Fetching a cached resource should use the cached response. Not sure what you mean by "in event method 'dragstart' can't use async", you definitely can initiate an async call from that event. – Kaiido Feb 21 '22 at 07:02
  • @Kaiido The event handler 'ondragstart' cannot be asynchronous. If it is asynchronous, the value in ‘datatransfer’ cannot be obtained in the 'ondrop' event – SignDawn Feb 21 '22 at 07:35
  • You can very well handle the event synchronously and still initiate your async call in parallel. – Kaiido Feb 21 '22 at 07:44
  • ajax is the only way to get the content, so if you can't/won't do that the problem is unsolvable. – Robert Longson Feb 21 '22 at 07:55
  • @RobertLongson I added my scene,thanks! – SignDawn Feb 21 '22 at 08:46
  • But what is it that you would like to achieve? Should the SVG image be dragged to the new position? Or is it some other SVG image that needs to be loaded after doing the dragging? – chrwahl Feb 21 '22 at 09:43
  • After dragging, load the SVG image string for parsing and transfer it to 'ondrop' @chrwahl – SignDawn Feb 21 '22 at 10:09

2 Answers2

0

Assuming that it is the already displayed SVG image that needs to be dragged and dropped this could be an example. It is only the id of the image that is "transferred" and on the drop event the images is fetched using the src attribute.

In the callback of the fetch function I create a XML document and in this case just print out the root element in the console.

In this example I use a data URI for the images source, but this can just be replaced by your URL to your own image.

const img = document.getElementById('img');
img.addEventListener('dragstart', function(e) {
  const id = e.target.id;
  e.dataTransfer.setData('text/plain', id);
});

const div = document.getElementById('div');

div.addEventListener('dragover', function(e) {
  e.preventDefault();
});

div.addEventListener('drop', function(e) {
  e.preventDefault();
  const id = e.dataTransfer.getData('text/plain');
  
  let img = document.getElementById(id);
  
  fetch(img.src).then(res => res.text()).then(text => {
    let parser = new DOMParser();
    let svg = parser.parseFromString(text, "text/xml");
    console.log(svg.rootElement.outerHTML);
  });
  
});
<img id="img" draggable="true" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDIgMiIgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIj48Y2lyY2xlIHI9IjEiIGN4PSIxIiBjeT0iMSIgZmlsbD0icmVkIi8+PC9zdmc+" width="50px" height="50px"/>
<div id="div" style="background-color: #123; width: 400px; height: 300px;"></div>
chrwahl
  • 8,675
  • 2
  • 20
  • 30
  • I need the content string of SVG。 ‘ ’ Because I need to parse it。 – SignDawn Feb 21 '22 at 10:17
  • thanks, This is a good idea, but for business reasons, I need to get the SVG string in the 'ondragstart' event function and then process it – SignDawn Feb 22 '22 at 05:38
0

Given your project it seems like it would make a lot more sense to do it the other way around:

  • Fetch the resource
  • Read it as text
  • Load the fetched resource in the images (as a blob: URL)

This way, when you start dragging your elements around you already have their markup version:

const images = document.querySelectorAll("img[data-src]");
images.forEach( async (img) => {
  // we store the actual src in a data- attribute
  // we will only fetch it from here
  const resp = await fetch(img.getAttribute("data-src"));
  const as_blob = resp.ok && await resp.blob();
  // read as text to get the markup
  const markup = await as_blob.text();
  // create a blob: URL so we can display the image
  const url = URL.createObjectURL(as_blob);
  img.src = url;
  // once the image is loaded we can revoke the blob: URL
  // this will allow the Blob to be Garbage Collected
  img.addEventListener("load", (evt) => URL.revokeObjectURL(url), {
    once: true
  });
  img.addEventListener("dragstart", (evt) =>
    evt.dataTransfer.setData("text/plain", markup)
  );
});

const div = document.getElementById("div");
div.addEventListener("dragover", (evt) => evt.preventDefault() );

div.ondrop = (evt) => {
  const data = evt.dataTransfer.getData('text/plain');
  console.log(data);
};
<img id="img" draggable="true" data-src="https://upload.wikimedia.org/wikipedia/commons/4/4a/Commons-logo.svg" width="50px" height="50px" />

<div id="div" style="background-color: #123; width: 400px; height: 300px;"></div>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • thanks, I am doing the same at present, loading in advance, but I think there will be a better way to get SVG strings without asynchronous operation – SignDawn Feb 22 '22 at 06:48
  • No there is no (advisable) way to fetch a resource synchronously. The HTML element's fetching won't allow you to access its resource. This is the best way. Note that the asynchronicity in this case doesn't matter, it's all done before the dragstart event is attached and even before the image is rendered in the – Kaiido Feb 22 '22 at 06:50