D3.js 使用 Promises 拉取和嵌入 DataURI 图像
D3.js pulling and embedding DataURI images with Promises
我正在构建一个依赖于大量小光栅图像的数据可视化,这些图像通过 JSON API 作为 AWS URL 提供。
这工作得相当好,直到我尝试实施我的下一步,即将数据可视化呈现为 PNG 以供下载。在 PNG 中,光栅图像已损坏。
我知道要解决这个问题,我需要将图像嵌入为数据 URL。
这是我目前得到的:
const companies_base64 = companies.map(c => {
var o = Object.assign({}, c)
o.base64 = imageToBase64(c.mimetype, c.logo)
return o
})
其中 companies
是一个对象数组。这是 imageToBase64
,Heroku 应用程序是 CORS anywhere 的克隆:
function imageToBase64(mimetype, logo) {
var url = 'https://example.herokuapp.com/' + logo
return d3.blob(url)
.then(blob => blobToBase64(blob))
.then(base64 => mimetype + base64)
.catch(error => console.error(error))
}
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.onload = () => {
let dataUrl = reader.result
let base64 = dataUrl.split(',')[1]
resolve(base64)
}
reader.onerror = () => {
reject("Error")
}
reader.readAsDataURL(blob)
})
}
这导致在 companies_base64
中的任何对象上调用 base64
时返回 Promise
,[[PromiseValue]]
当然是我所追求的。我应该如何确保它是返回的内容,以便我最终可以将它放在 <svg>
中 <image>
的 xlink:href
属性中?
我认为一旦它工作并且我可以在任何地方调用 imageToBase64
,这是我只想在用户按下 下载 时做的事情。我想我可以使用 D3 来做到这一点,迭代 <image>
s 并换出它们的 xlink:href
。还是我应该换一种方式?
我还尝试将图像作为对象获取,然后在我的 RoR 后端将它们转换为 base64,以便它们通过 Image#to_base64
方法与 JSON
打包在一起。这确实有效,但 A) 感觉很不对,B) 在初始加载时显然很慢。
感谢您的宝贵时间,我是初学者,请多多包涵。
您的 imageToBase64
函数 returns 一个承诺,而不是已解析的数据 URL。这意味着您必须等待才能将它们附加到 companies_base64
成员。您可以选择在单个 base64 字符串准备好后立即执行此操作,或者等待所有字符串:
Promise.all(companies.map(c => {
return imageToBase64(c.mimetype, c.logo)
.then(u => Object.assign({ base64: u }, c))
.then(/* change the image reference here one by one... */)
}))
.then(companies_base64 => /* ...or here, in a loop over the array */)
.catch(error => console.error(error))
我正在构建一个依赖于大量小光栅图像的数据可视化,这些图像通过 JSON API 作为 AWS URL 提供。
这工作得相当好,直到我尝试实施我的下一步,即将数据可视化呈现为 PNG 以供下载。在 PNG 中,光栅图像已损坏。
我知道要解决这个问题,我需要将图像嵌入为数据 URL。
这是我目前得到的:
const companies_base64 = companies.map(c => {
var o = Object.assign({}, c)
o.base64 = imageToBase64(c.mimetype, c.logo)
return o
})
其中 companies
是一个对象数组。这是 imageToBase64
,Heroku 应用程序是 CORS anywhere 的克隆:
function imageToBase64(mimetype, logo) {
var url = 'https://example.herokuapp.com/' + logo
return d3.blob(url)
.then(blob => blobToBase64(blob))
.then(base64 => mimetype + base64)
.catch(error => console.error(error))
}
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.onload = () => {
let dataUrl = reader.result
let base64 = dataUrl.split(',')[1]
resolve(base64)
}
reader.onerror = () => {
reject("Error")
}
reader.readAsDataURL(blob)
})
}
这导致在 companies_base64
中的任何对象上调用 base64
时返回 Promise
,[[PromiseValue]]
当然是我所追求的。我应该如何确保它是返回的内容,以便我最终可以将它放在 <svg>
中 <image>
的 xlink:href
属性中?
我认为一旦它工作并且我可以在任何地方调用 imageToBase64
,这是我只想在用户按下 下载 时做的事情。我想我可以使用 D3 来做到这一点,迭代 <image>
s 并换出它们的 xlink:href
。还是我应该换一种方式?
我还尝试将图像作为对象获取,然后在我的 RoR 后端将它们转换为 base64,以便它们通过 Image#to_base64
方法与 JSON
打包在一起。这确实有效,但 A) 感觉很不对,B) 在初始加载时显然很慢。
感谢您的宝贵时间,我是初学者,请多多包涵。
您的 imageToBase64
函数 returns 一个承诺,而不是已解析的数据 URL。这意味着您必须等待才能将它们附加到 companies_base64
成员。您可以选择在单个 base64 字符串准备好后立即执行此操作,或者等待所有字符串:
Promise.all(companies.map(c => {
return imageToBase64(c.mimetype, c.logo)
.then(u => Object.assign({ base64: u }, c))
.then(/* change the image reference here one by one... */)
}))
.then(companies_base64 => /* ...or here, in a loop over the array */)
.catch(error => console.error(error))