(JavaScript) 从文件或 FileReader 对象导入外部 <object> svg
(JavaScript) Import external <object> svg from File or FileReader Object
我正在使用 Two.js,我想允许用户导入一个 svg 文件并将其显示在我的场景中。
Two.interpret() 可以获取任何 dom 包含 SVG 数据的标签,所以我创建了这个函数来模拟文件中的标签:
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,并且 returns 一个 two.path。
当使用控制台时,这一切工作正常,花花公子
twoInstance.interpretFromFile (twoInstance, "images/Test.svg");
但是,我 运行 这些文件在本地进行测试,我当然不指望任何人进入他们的浏览器控制台并使用该功能,已经知道文件的确切路径,也知道在该路径之前键入 "file://"... 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' 只给出文件,不给出路径(是的,我知道这在浏览器中是安全的。我已经看过所有其他关于它的问题..)
所以现在,我可以使用 FileReader 来读取 svg 文件本身,但是我如何将该数据放入标签中呢?我有时需要这种格式:
<object data="Test.svg" type="image/svg+xml"></object>
因为 Two.js 似乎不喜欢 'svg' 标签..只是 'object' 标签..
对于这个冗长的问题,我深表歉意。如您所见,我已经陷入了这个兔子洞的深处。我试图只使用相关代码,但老实说,整个事情大得惊人,我不想 post 全部。
您必须从您的 File 对象(它只是指向用户磁盘上文件的直接指针)创建一个 BlobURL,然后将您的 <object>
的 data
设置为此BlobURL。
在这里我将只使用一个 <input>
元素,但它与任何 Blob/File 基本相同,无论它们来自哪里(请注意,尽管 IIRC 你需要调用 getAsFile()
dataTransfer
的文件中的方法。
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"/>
多么快速的回答.. @guest271314(如果我以后能弄明白,我会link这个)。
这对我有用:
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文件到页面上试试看。
这是我上传 svg 图像并附加到 div 的方法,使用 atob 将 base64 字符串转换为 svg 字符串:var svg = atob(event.target.result.replace(/data:image\/svg\+xml;base64,/, ''));
我在 angular 应用程序中使用它。我为谁分忧
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>
如果要将外部 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);
我正在使用 Two.js,我想允许用户导入一个 svg 文件并将其显示在我的场景中。
Two.interpret() 可以获取任何 dom 包含 SVG 数据的标签,所以我创建了这个函数来模拟文件中的标签:
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,并且 returns 一个 two.path。
当使用控制台时,这一切工作正常,花花公子 twoInstance.interpretFromFile (twoInstance, "images/Test.svg");
但是,我 运行 这些文件在本地进行测试,我当然不指望任何人进入他们的浏览器控制台并使用该功能,已经知道文件的确切路径,也知道在该路径之前键入 "file://"... 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' 只给出文件,不给出路径(是的,我知道这在浏览器中是安全的。我已经看过所有其他关于它的问题..)
所以现在,我可以使用 FileReader 来读取 svg 文件本身,但是我如何将该数据放入标签中呢?我有时需要这种格式:
<object data="Test.svg" type="image/svg+xml"></object>
因为 Two.js 似乎不喜欢 'svg' 标签..只是 'object' 标签..
对于这个冗长的问题,我深表歉意。如您所见,我已经陷入了这个兔子洞的深处。我试图只使用相关代码,但老实说,整个事情大得惊人,我不想 post 全部。
您必须从您的 File 对象(它只是指向用户磁盘上文件的直接指针)创建一个 BlobURL,然后将您的 <object>
的 data
设置为此BlobURL。
在这里我将只使用一个 <input>
元素,但它与任何 Blob/File 基本相同,无论它们来自哪里(请注意,尽管 IIRC 你需要调用 getAsFile()
dataTransfer
的文件中的方法。
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"/>
多么快速的回答.. @guest271314(如果我以后能弄明白,我会link这个)。
这对我有用:
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文件到页面上试试看。
这是我上传 svg 图像并附加到 div 的方法,使用 atob 将 base64 字符串转换为 svg 字符串:var svg = atob(event.target.result.replace(/data:image\/svg\+xml;base64,/, ''));
我在 angular 应用程序中使用它。我为谁分忧
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>
如果要将外部 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);