I'm using Two.js, I want to allow the user to import an svg file and display it on my scene.
Two.interpret() can take any dom of tag that has SVG data in it, so I've created this function to simulate tag from a file:
this.m_Two.interpretFromFile = function (two, fname) {
//Create an object and load an svg from 'fname'
var object = document.createElement("object");
//Set the id to the filename without path or extension
object.id = fname;
object.id = object.id.replace(/\\/g, '/');
object.id = object.id.substring(object.id.lastIndexOf('/')+1, object.id.lastIndexOf('.'));
console.log("Importing " + object.id);
object.data = fname; //HTML takes care of the rest
object.type = "image/svg+xml";
object.width = 64; //Import from file maybe?
object.height = 64;
object.style = "visibility:hidden;position:absolute;left:0px;top:0px;";
document.body.appendChild(object); //Add it to the body (invis) that way it loads
//When it loads, finish up
object.onload = function () {
if (!object.contentDocument || object.contentDocument.getElementsByTagName("svg").length < 1) return;
var svgObj = object.contentDocument.getElementsByTagName('svg')[0];
var ret = two.interpret(svgObj);
document.body.removeChild(object); //Remove it. Use path.clone to duplicate stuff..
return ret; //Return our new svg path
}
};
This function takes a Two instance, and a file url, and returns a two.path.
This all works fine and dandy when use the console with twoInstance.interpretFromFile (twoInstance, "images/Test.svg");
However, I am running these files locally for testing, and I certainly don't expect anyone to go into their browser's console and use the function, already knowing the file's exact path, and also know to type "file://" before that path... Yeesh
document.getElementById("dWorkSpace").ondrop = function(e) {
e.preventDefault(); //Default event loads the file itself.. KILL IT WITH FIRE.
if (!e.dataTransfer || !e.dataTransfer.items.length > 0 || !e.dataTransfer.files[0]) return;
var file = e.dataTransfer.files[0];
twoInstance.interpretFromFile(twoInstance, "file://" + file.name);
}
'file.name' only gives the file, not the path (yes, I know this is a securety thing in browsers. I've already looked at all of the other questions about that..)
So NOW, I could use a FileReader to read the svg file itself, but how do I get that data into an tag? I need it in this format at some point:
<object data="Test.svg" type="image/svg+xml"></object>
Because Two.js seems to not like 'svg' tag.. Just 'object' tag..
I am SO sorry for the enlongated question.. I'm pretty deep down this rabbit hole, as you can see. I tried to only use relevant code, but honestly the whole thing is monstrously large, and I'd hate to post it all.
You will have to create an BlobURL from your File object (which is just a direct pointer to the file on the user's disk), and then set your <object>
's data
to this BlobURL.
Here I will just use an <input>
element, but its basically the same with any Blob/File, where-ever they came (note though that IIRC you need to call getAsFile()
method from dataTransfer
's Files.
f.onchange = e =>{
var file = f.files[0];
if(file.type === 'image/svg+xml'){
var obj = document.createElement('object');
obj.data = URL.createObjectURL(file);
obj.onload = e => URL.revokeObjectURL(obj.data);
document.body.appendChild(obj);
}
};
<input type="file" id="f"/>