0

I want to select a triangle in my SVG file loaded with <object> and change its properties but I can't do that.

<object id="pyth1" data="pyth1.svg" type="image/svg+xml"></object>
<script>
document.getElementById("pyth1").addEventListener("load", function() {
  var doc = this.getSVGDocument();
  var triangle = doc.querySelector("triangle"); // suppose our image contains a <rect>
  triangle.setAttribute("fill", "green");
});
</script>

The pyth1.svg is a SVG file located in the same folder of the HTML file.

<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="136.15602mm" height="136.41513mm" viewBox="0 0 136.15602 136.41513" version="1.1" id="pythpf1" sodipodi:docname="pyth1.svg" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)">
  <sodipodi:namedview id="namedview7" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:document-units="mm" showgrid="false" inkscape:zoom="1.0074671" inkscape:cx="421.35373" inkscape:cy="146.40677" inkscape:window-width="1920" inkscape:window-height="1001" inkscape:window-x="-9" inkscape:window-y="-9" inkscape:window-maximized="1" inkscape:current-layer="layer1" lock-margins="true" fit-margin-top="10" fit-margin-left="10" fit-margin-right="10" fit-margin-bottom="10"/>
  <defs id="defs2">
    <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 168.5 : 1" inkscape:vp_y="0 : 1000.0001 : 0" inkscape:vp_z="210.00001 : 168.5 : 1" inkscape:persp3d-origin="105.00001 : 119 : 1" id="perspective2244"/>
  </defs>
  <g inkscape:label="Calque 1" inkscape:groupmode="layer" id="layer1" transform="translate(-36.921986,-80.292432)">
    <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="sqA" width="36.859184" height="36.859184" x="125.68764" y="91.080582"/>
    <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="sqB" width="78.265648" height="78.265648" x="47.421986" y="127.93977"/>
    <path style="fill:#8888ff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" d="M 125.68763,91.080581 47.421985,127.93977 h 78.265645 z" id="triangle"/>
    <path style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 47.708953,127.65162 125.9746,90.792432 H 47.708953 Z" id="triangleC"/>
    <path style="fill:#ccccff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" d="m 162.2915,206.205 -36.60367,-78.38547 l -0.25532,78.26523 z" id="triangleABB"/>
    <path style="fill:#ccccff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" d="M 125.68782,127.81952 162.2915,206.205 v 0 l 0.25531,-78.26524 z" id="triangleABA"/>
  </g>
</svg>

The answers for questions suggest contentDocument and getSVGDocument(), but I'm getting null. Even though they are in the same folder, it seems that the SVG file is treated as a foreign origin content, so that contentDocument returns null. For the second method, it seems that getSVGDocument() is deprecated, but firstElementChild doesn't bring me anywhere further.

How can I select a node in a SVG loaded with <object> with JavaScript?

can't SVG elt from JS can't SVG elt from JS2

  • @mplungjan I would like to add animation to the triangle later. That's a geometric proof for the Pythagoras Theorem. – GNUSupporter 8964民主女神 地下教會 Mar 22 '22 at 13:50
  • But why load it using `object` ? – mplungjan Mar 22 '22 at 13:50
  • If you just include the SVG in the page, you can do https://jsfiddle.net/mplungjan/1092stom/ – mplungjan Mar 22 '22 at 13:53
  • @mplungjan the linked question doesn't seem to answer my question, beccause in my HTML code I did try to add a listener for the `load` event. I would like to add more contents aside from the SVG file, that's why I'm choosing ``. – GNUSupporter 8964民主女神 地下教會 Mar 22 '22 at 13:55
  • I expected it to be a dupe of https://stackoverflow.com/questions/11434916/javascript-accessing-inner-dom-of-svg - I have reopened. – mplungjan Mar 22 '22 at 14:00
  • Why would adding more content mean you could not inline the SVG? – mplungjan Mar 22 '22 at 14:01
  • @mplungjan The adopted answer in your linked question was posted ten years ago, and a recent comment claiming that it doesn't work has received three upvotes. The alternate answer requires setting up a server, but it's seems too much for me. I'm drawing using Inkscape, and it would be inconvenient to copy and paste the source code into HTML. I would like to include multiple SVG files (to illustrate different alternate geometric proofs, and how to adapt them into other situations). Having multiple inline SVG elements in one single HTML file would make the editing difficult. – GNUSupporter 8964民主女神 地下教會 Mar 22 '22 at 14:08
  • Ah, no server... Then trickier. You can load them using script – mplungjan Mar 22 '22 at 14:10

1 Answers1

0

So instead of the object tag, you can load the SVG using script

Since you do not have a server you need .js files instead of just svg files

window.addEventListener("DOMContentLoaded", function() {
  const div = document.getElementById("svgContainer");
  const svg1 = document.createElement("script")
  svg1.addEventListener("load",function() {
    document.querySelector("head").appendChild(svg1)
  })
  //svg1.src = "svgs/svg1.svg";
  div.innerHTML = svg; // remove this
  
  // here we can play
  document.querySelector("#svgContainer path").setAttribute('style', 'fill: green');
})

/* example external svg script:
  
  document.getElementById("svgContainer").innerHTML = `<svg......>..........</svg>`;

*/
<div id="svgContainer"></div>

<!-- ignore this - it is just to show example -->
<script>
const svg = `<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="136.15602mm" height="136.41513mm" viewBox="0 0 136.15602 136.41513" version="1.1" id="pythpf1" sodipodi:docname="pyth1.svg" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)">
  <sodipodi:namedview id="namedview7" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:document-units="mm" showgrid="false" inkscape:zoom="1.0074671" inkscape:cx="421.35373" inkscape:cy="146.40677" inkscape:window-width="1920" inkscape:window-height="1001" inkscape:window-x="-9" inkscape:window-y="-9" inkscape:window-maximized="1" inkscape:current-layer="layer1" lock-margins="true" fit-margin-top="10" fit-margin-left="10" fit-margin-right="10" fit-margin-bottom="10"/>
  <defs id="defs2">
    <inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 168.5 : 1" inkscape:vp_y="0 : 1000.0001 : 0" inkscape:vp_z="210.00001 : 168.5 : 1" inkscape:persp3d-origin="105.00001 : 119 : 1" id="perspective2244"/>
  </defs>
  <g inkscape:label="Calque 1" inkscape:groupmode="layer" id="layer1" transform="translate(-36.921986,-80.292432)">
    <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="sqA" width="36.859184" height="36.859184" x="125.68764" y="91.080582"/>
    <rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="sqB" width="78.265648" height="78.265648" x="47.421986" y="127.93977"/>
    <path style="fill:#8888ff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" d="M 125.68763,91.080581 47.421985,127.93977 h 78.265645 z" id="triangle"/>
    <path style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 47.708953,127.65162 125.9746,90.792432 H 47.708953 Z" id="triangleC"/>
    <path style="fill:#ccccff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" d="m 162.2915,206.205 -36.60367,-78.38547 l -0.25532,78.26523 z" id="triangleABB"/>
    <path style="fill:#ccccff;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" d="M 125.68782,127.81952 162.2915,206.205 v 0 l 0.25531,-78.26524 z" id="triangleABA"/>
  </g>
</svg>`
</script>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • thank you for answer excuse me i'm having a voice chat on discord. lemme view this in a few hours. – GNUSupporter 8964民主女神 地下教會 Mar 22 '22 at 14:23
  • sorry for late response i returned to this problem after preparing other learning materials on Geogebra.org for high schools students who are gonna take their public exams in a month. in your solution `svg1` is a `script`, but you're setting `svg1.src = 'svg/svg1.svg'`, so when I try this in my web browser's dev tool I got "Refused to execute script from 'file:///C:/Users/xxxx/Pictures/pyth1.svg' because its MIME type ('image/svg+xml') is not executable." – GNUSupporter 8964民主女神 地下教會 Mar 29 '22 at 17:58
  • I’ll take a look tomorrow – mplungjan Mar 29 '22 at 18:34