在 JavaScript 中,我进行了 ajax/xhr d3.csv() 调用,这会触发一个冗长的 MySQL 查询(有时可能需要超过 30 秒才能运行)。然后根据数据生成 HTML 表格 ( via d3.js )。
我希望用户能够通过单击按钮将数据下载为 CSV 文件,但是
- 我不想为此在服务器上创建 tmp 文件
- 无法在服务器上再次运行查询 - 我不想让用户再等待 30 秒(也不想再次绑定(bind)数据库)
- 我想指定文件名,例如
descriptiveName-some_datetime_here.csv
- 它需要在 IE(美国公司的事物)和 Safari(公司高管的事物)中工作
将 d3 创建的 JSON 数据转换为 CSV 不是问题(我知道如何执行该部分)。
有很多类似的 SO 问题,普遍的共识似乎是:
使用数据 URI 并在 download
属性中指定文件名( Q1 、 Q2 、等)。
但遗憾的是这个属性是 not supported on IE or Safari .
最佳答案
也许有更好的方法,但这里有一种方法:提交一个具有所需文件名的表单,并将数据作为两个隐藏的表单元素。让服务器简单地返回带有为文件下载设置的适当 header 的数据。不需要tmp文件;适用于所有浏览器。
HTML:
<form id="download-form" method="post">
<input type="button" value="download CSV">
</form>
<!-- the button is right above the HTML table -->
<table>... </table>
JavaScript/D3:
var jsonData;
var filenameDateFormat = d3.time.format("%Y%m%d-%H%M%S");
// ... after loading the data, and setting jsonData to the data returned from d3.csv()
jsonData = data;
// display the form/button, which is initially hidden
d3.select("#download-form").style("display", "block");
d3.select("#download-form input[type=button]").on('click', function() {
var downloadForm = d3.select("#download-form");
// remove any existing hidden fields, because maybe the data changed
downloadForm.selectAll("input[type=hidden]").remove();
downloadForm
.each(function() {
d3.select(this).append("input")
.attr({ type: "hidden",
name: "filename",
value: CHART_NAME + "-"
+ filenameDateFormat(new Date()) + ".csv"});
d3.select(this).append("input")
.attr({ type: "hidden",
name: "data",
value: convertToCsv(jsonData) });
});
document.getElementById("download-form").submit();
});
function convertToCsv(data) {
var csvArray = ['field_name1_here,field_name2_here,...'];
data.forEach(function(d) {
csvArray.push(d.field_name1_here + ',' + d.field_name2_here + ...);
});
return csvArray.join("\n");
}
服务器(Python,使用 Bottle ):
@app.route('/download', method='POST')
def download():
if request.environ.get('HTTP_USER_AGENT').find('Chrome'):
# don't add the Content-Type, as this causes Chrome to output the following
# to the console:
# Resource interpreted as Document but transferred with MIME type text/csv
pass
else:
response.set_header('Content-Type', 'text/csv')
response.set_header('Content-Disposition',
'attachment; filename="' + request.forms.filename + '"')
return request.forms.data
虽然不太漂亮,但确实有效。
关于csv - 将 d3 生成的 HTML 表导出为 CSV(也必须在 IE 上工作),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20158236/