(JavaScript)从File或FileReader Object导入外部<object> svg

时间:2017-06-05 06:18:51

标签: javascript html svg import external

我使用Two.js,我想允许用户导入svg文件并在我的场景中显示它。

Two.interpret()可以获取其中包含SVG数据的任何标签dom,因此我创建了此函数来模拟文件中的标记:

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
        }
    };

此函数采用Two实例和文件url,并返回two.path。

使用控制台时,这一切都很好用 twoInstance.interpretFromFile(twoInstance,&#34; images / Test.svg&#34;);

但是,我在本地运行这些文件进行测试,我当然不希望任何人进入他们的浏览器控制台并使用该功能,已经知道该文件的确切路径,并且还知道键入&#34; file://&#34;在那条路之前...... 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);
    }

&#39; file.name&#39;只提供文件,而不是路径(是的,我知道这在浏览器中是安全的。我已经查看了所有其他有关此问题的问题......)

现在,我可以使用FileReader来读取svg文件本身,但是如何将这些数据转换为标签呢?我在某种程度上需要这种格式:

            <object data="Test.svg" type="image/svg+xml"></object>

因为Two.js似乎不喜欢&#39; svg&#39;标签..只是&#39;对象&#39;标签..

我很抱歉这个长期存在的问题......正如你所看到的,我在这个兔子洞的深处。我试图只使用相关的代码,但说实话,整个事情都非常庞大,我讨厌发布它。

4 个答案:

答案 0 :(得分:2)

这是我上传svg图像并附加到div的方法,使用atob将base64字符串转换为svg字符串:var svg = atob(event.target.result.replace(/data:image\/svg\+xml;base64,/, ''));

我在有角度的应用中使用它。我与谁分享关注点。

handleFileInput(file: FileList) {
    this.fileToUpload = file.item(0);
    var xlinkNS = "http://www.w3.org/1999/xlink";
    //Show image preview
    let reader = new FileReader();
    reader.onload = (event: any) => {

      var svg = atob(event.target.result.replace(/data:image\/svg\+xml;base64,/, ''));
      console.log(svg);

      var element = document.createElement("div");
      element.id = "svg";
      document.getElementsByClassName('svg-container')[0].innerHTML = '';
      document.getElementsByClassName('svg-container')[0].appendChild(element); 
      var newSvg = document.getElementById('svg');
      newSvg.outerHTML = svg;

    }
    reader.readAsDataURL(this.fileToUpload);
  }

HTML

<div class="svg-container">
        <div id="svg"></div>
    </div>
    <div class="image-upload">
        <label (click)='inputClick(Image)'>
            <img src="image/upload.png" />
        </label>

        <input #Image type="file" (change)="handleFileInput($event.target.files)"/>
        <button type="submit" class="btn-large btn-submit" [disabled]="Image.value=='' || !imageForm.valid"><i class="material-icons">save</i></button>
    </div>

答案 1 :(得分:1)

快速回答.. @ guest271314(如果我以后能搞清楚的话,我会链接这个。)

这对我有用:

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];

    var reader = new FileReader(); //Make a reader

    reader.onloadend = function (evt) { //When the file is actually loaded
        Application.m_Two.interpretFromFile(Application.m_Two, reader.result);
    }
    reader.readAsDataURL(file);
}

更改的位是FileReader对象,我使用readAsDataUrl之类的 guest271314在第一条评论中谈到了。你能说出我是新人吗?的xD

演示:http://jonathancrowder.com/AnimatorProject/Application.html - 将SVG文件拖到页面上进行试用。

答案 2 :(得分:1)

如果要将外部svg文件包括在内嵌SVG中,则可以使用FileReader.readAsText()函数以文本字符串的形式获取SVG的内容。

参考:https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText

const reader = new FileReader();
reader.addEventListener("load", (event) => {
    console.log(event.target.result);
});
reader.readAsText(file);

或者,如果要将其嵌入为Object或Img,则可以使用FileReader.readAsDataURL()来获取SVG作为已编码的数据字符串,请参阅本文。 https://web.dev/read-files/ 及其代码示例: https://glitch.com/~read-image-file

const reader = new FileReader();
reader.addEventListener('load', event => {
    document.getElementById('output').src = event.target.result;
});
reader.readAsDataURL(file);

答案 3 :(得分:0)

您必须从File对象创建一个BlobURL(它只是指向用户磁盘上文件的直接指针),然后设置<object>&#39; s {{ 1}}到这个BlobURL。

这里我将使用一个data元素,但它与任何Blob / File基本相同,无论它们来自哪里(请注意,虽然IIRC需要从{{<input>方法调用getAsFile() 1}}&#39; s文件。

&#13;
&#13;
dataTransfer
&#13;
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);
    }
  };
      
&#13;
&#13;
&#13;