0
votes

I'm trying to access an SVG's contentDocument (and change fill colors for specific paths, but that I don't have a problem with) via JavaScript. The SVG comes from user input. Whenever I try to access the contentDocument I get the error:

(index):41 Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLObjectElement': Blocked a frame with origin "http://localhost" from accessing a cross-origin frame.

As you can see I'm using a local server the but results are the same when accessing the file locally. Here's my code:

document.getElementById("input-image").addEventListener("load", function () {
    console.log("image loaded");
    let svgDoc = this.contentDocument;
}, false);

var src = document.getElementById("file-input");
var target = document.getElementById("input-image");
var fr = new FileReader();
fr.onload = function (e) {
    target.data = this.result;
};
src.addEventListener("change", function () {
    fr.readAsDataURL(src.files[0]);
});

And the HTML:

<object data="" type="image/svg+xml" id="input-image" width="100%" height="100%"></object>
<input id="file-input" type="file" accept=".svg" />

And here's a jsFiddle.

I know this can be fixed by actually uploading the file to the server and then accessing it locally (as in, on the server) but is there a way to get this to work without introducting server side scripting and uploads?

1
... and the code posted has been tested to work without error in IE(11) and Firefox after window load. Using both file:// and http://localhost/ access.traktor
Yes, that's why I tagged it with Google Chrome, I guess I should have mentioned that in the body and not just the title. I know it's a Chrome issue, IIRC Chrome is especially sensitive to cross frame data. The thing is, I am writing this tool for myself and I'm a Chrome user so I'd really like it to work in Chrome.ngr900

1 Answers

1
votes

A suggestion for an alternative method of loading a local svg file into the DOM is to

  1. read the file as text (let's assume it's ASCII or utf-8 encoding) after selection.
  2. write the content to an iframe object's document
  3. pick up the svgElement from within the iframe.

Concept code

This code uses an example string instead of performing step 1.

    let svgTest = function() {

    let iframe = document.createElement("iframe");
    document.body.appendChild(iframe); // insert it in the document, somewhere

    // normally read the svg as text, but here just use an example from
    // https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Getting_Started

    let result = `
        <svg version="1.1"
             baseProfile="full"
             width="300" height="200"
             xmlns="http://www.w3.org/2000/svg">
          <rect width="100%" height="100%" fill="red" />
          <circle cx="150" cy="100" r="80" fill="green" />
          <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
        </svg>
    `;

    // write it to the iframe and close the document
    let doc = iframe.contentWindow.document;
    doc.write(result)
    doc.close();

    // get the svgElement
    let svgElement = doc.getElementsByTagName("svg")[0];
    let svgRect = svgElement.getBoundingClientRect();

    // set iframe size (may need adjustment)
    doc.body.style.margin = "0";
    iframe.width = svgRect.width;
    iframe.height = svgRect.height;

    }; //end of svgTest
    svgTest();