Заполните тег объекта кодом SVG с помощью javascript

У меня есть доступный код svg в виде текста в переменной в javascript. Мне нужно установить его как изображение в теге объекта (не SVG или IMG). Это возможно?

Это обсуждалось в разделе Создать тег объекта SVG с кэшированным кодом SVG. без ответа.


person Nillus    schedule 12.11.2017    source источник


Ответы (1)


Есть несколько способов сделать это, но не все они позволят вам получить доступ к объекту contentDocument...

Самый простой — преобразовать SVG-разметку в data-URI.

Но тогда браузеры будут рассматривать этот документ как кросс-оригинальный ресурс и запретят вам доступ к нему через js.

// an svg string
const svgStr = `<svg width="120" height="120" viewBox="0 0 120 120"
    xmlns="http://www.w3.org/2000/svg">

  <rect x="10" y="10" width="100" height="100"/>
</svg>`;
// as dataURI
const dataURI = 'data:image/svg+xml;charset=utf8, '+ encodeURIComponent(svgStr);
obj.data = dataURI;

// do some checks after it has loaded
obj.onload = e => {
  console.log('loaded');
  try{  
    console.log(obj.contentDocument.documentElement.nodeName);
    }
  catch(err){
    console.log('but cant access the document...');
    console.error(err);
  }
};
<object id="obj"></object>

Один из способов обойти это в большинстве браузеров — использовать blobURI, который должен быть отмечен источником документа, что позволяет нам получить доступ к документу. Но IE не устанавливает это происхождение в blobURI... Таким образом, этот браузер также не позволит вам получить доступ к contentDocument.

Фрагмент ниже будет действовать как IE во всех браузерах, поскольку iframes StackSnippets имеют нулевое происхождение:

// an svg string
const svgStr = `<svg width="120" height="120" viewBox="0 0 120 120"
    xmlns="http://www.w3.org/2000/svg">

  <rect x="10" y="10" width="100" height="100"/>
</svg>`;

// as blobURI
const blob = new Blob([svgStr], {type:'image/svg+xml'})
const blobURI = URL.createObjectURL(blob);
obj.data = blobURI;

// do some checks after it has loaded
obj.onload = e => {
  console.log('loaded');
  try{  
    console.log(obj.contentDocument.documentElement.nodeName);
    }
  catch(err){
    console.log('but cant access the document...');
    console.error(err);
  }
};
<object id="obj"></object>

Но эта скрипта будет работать во всех браузерах, кроме IE.

Таким образом, один из способов, который должен работать и в IE, — это использовать пустой HTML-документ, обслуживаемый из того же источника, к которому мы добавим svg после его загрузки.

// first load an same-origin document (not sure if about:blank works in IE...)
obj.data = 'empty.html';

// once it has loaded
obj.onload = e => {
  // parse our svgString to a DOM element
  const svgDoc = new DOMParser().parseFromString(svgStr, 'image/svg+xml');
  const objDoc = obj.contentDocument;
  // ask the object's document to adopt the svg node
  const toAppend = objDoc.adoptNode(svgDoc.documentElement);
  // now we can append it and it will display
  objDoc.documentElement.appendChild(toAppend);
};

Как скрипка.

person Kaiido    schedule 12.11.2017
comment
С empty.html я трачу HTTP-запрос на сервер, и его нельзя кэшировать, поскольку он является источником данных для элемента объекта. - person Nillus; 12.11.2017
comment
@Nillus да, вы бы сделали http-запрос ... к файлу размером 28 байт (все, что нужно, это <!DOCTYPE html><html></html>). - person Kaiido; 12.11.2017