本篇文章主要说下如何实现使用d3js绘制的svg怎么导出成各个类型的图片呢?.png、.svg、.jpg...
前端一般做导出都是利用blob和createObjectURL创建一个url,然后放在一个a标签里面进行导出的。
code
function onDownload(data, type, name) {
const blob = new Blob([data], { type }); // 返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。
const url = window.URL.createObjectURL(blob); //创建一个url
const link = document.createElement('a'); //创建一个a标签
link.href = url; // 把url 赋值给a标签的href
link.style.display = 'none'; // 不显示a
link.setAttribute('download', name);
document.body.appendChild(link);
link.click(); // 触发a标签的点击事件
URL.revokeObjectURL(url); // 清除Url
document.body.removeChild(link);
};
Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
准备基础的图形绘制,绘制出来几个小方块(不了解的可以往前面几篇文章翻翻) 效果图:
code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#container {
width: 500px;
margin: 50px auto 0;
}
</style>
</head>
<body>
<div id="container">
</div>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const width = 500;
const height = 500;
const svg = d3.select('#container')
.append('svg')
.attr('width', width)
.attr('height', width);
const container = svg.append('g');
const data = [
{ id: 1, fill: 'black', x: 10, y: 10 },
{ id: 2, fill: 'black', x: 50, y: 50 },
{ id: 3, fill: 'black', x: 100, y: 70 },
{ id: 4, fill: 'black', x: 20, y: 100 }
];
draw(); // 绘制
function draw() {
const update = container.selectAll('rect')
.data(data, d => d.id);
//修改层
update.attr('x', (d, idx) => d.x)
.attr('y', (d, idx) => d.y)
.attr('fill', (d) => d.fill)
//渲染层
const enter = update.enter();
//删除层
const exit = update.exit();
enter.append('rect')
.attr('width', 20)
.attr('height', 20)
.attr('id', d => d.id)
.attr('x', (d, idx) => d.x)
.attr('y', (d, idx) => d.y)
.attr('fill', (d) => d.fill)
.attr('stroke', 'blue')
.attr('strokeWidth', 1)
exit.remove()
}
</script>
用d3js绘制的svg导出后缀名是.svg的, 需要怎么做呢?
使用XMLSerializer的serializeToString()
方法返回 DOM 子树序列化后的字符串。 用法示例(MDN):
//这里新建了一个 XMLSerializer 对象实例,然后将待序列化的 Document 对象实例传入返回等价 XML 的 serializeToString() (en-US) 方法。
var s = new XMLSerializer();
var d = document;
var str = s.serializeToString(d);
saveXML(str);
咱们也只需要把svg放进serializeToString
是不是就行了呢? 代码如下:
function onDownload(data, type, name) {
const blob = new Blob([data], { type }); // 返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。
const url = window.URL.createObjectURL(blob); //创建一个url
const link = document.createElement('a'); //创建一个a标签
link.href = url; // 把url 赋值给a标签的href
link.style.display = 'none';
link.setAttribute('download', name);
document.body.appendChild(link);
link.click(); // 触发a标签的点击事件
URL.revokeObjectURL(url); // 清除Url
document.body.removeChild(link);
};
function onSaveSvg() { // 保存svg
const svg = document.querySelector('svg');
const source = new XMLSerializer().serializeToString(svg); //将整个SVG document 对象序列化为一个 XML 字符串。
onDownload(source, 'text/xml', 'test.svg'); // 下载
}
效果图如下:
解释下为啥type类型会传text/xml
SVG 是使用 XML 来描述二维图形和绘图程序的语言。
.svg导出可以看到还是蛮省劲的, 那么非.svg得格式图片该怎么导出? 可以不可以使用相同得方法呢?显然是不可以得,咱们借助canvas得toDataURL进行导出。
文件类型 常见MIME 类型列表 developer.mozilla.org/zh-CN/docs/…
效果图:
code
// 获取设备的devicePixelRatio
function getPixelRatio(context) {
const backingStore = context.backingStorePixelRatio
|| context.webkitBackingStorePixelRatio
|| context.mozBackingStorePixelRatio
|| context.msBackingStorePixelRatio
|| context.oBackingStorePixelRatio
|| context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
}
function onSavePng() { // 保存png
const svgDom = document.querySelector('svg');
const format = 'png'
const svgString = new XMLSerializer().serializeToString(svgDom);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const ratio = getPixelRatio(ctx); // 获取设备的devicePixelRatio
const w = window.innerWidth; // 获取设备的显示屏幕宽高
const h = window.innerHeight; // 图片加载完this.height才大于0.
const ratioW = canvas.width || w * ratio; // 计算屏幕的高清图片的宽高,同时设置画板的像素
const ratioH = canvas.height || h * ratio;
const domURL = this.URL || this.webkitURL || this;
const img = new Image(ratioW, ratioH);
const svg = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
const url = domURL.createObjectURL(svg);
img.src = url;
img.onload = function on() {
ctx.drawImage(img, 0, 0);
const png = canvas.toDataURL(`image/${format}`);
domURL.revokeObjectURL(png);
const a = document.createElement('a');
a.setAttribute('download', `test.${format}`);
a.setAttribute('href', png);
a.style.display = 'none';
document.body.appendChild(a);
a.click();
a.remove();
};
}
包含导出svg、png、jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#container {
width: 500px;
margin: 50px auto 0;
}
</style>
</head>
<body>
<div id="container">
<button onclick="onSaveSvg()"> 保存svg图片 </button>
<button onclick="onSaveImage('png')"> 保存png图片 </button>
<button onclick="onSaveImage('jpg')"> 保存jpg图片 </button>
</div>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const width = 500;
const height = 500;
const svg = d3.select('#container')
.append('svg')
.attr('width', width)
.attr('height', width);
const container = svg.append('g');
const data = [
{ id: 1, fill: 'black', x: 10, y: 10 },
{ id: 2, fill: 'black', x: 50, y: 50 },
{ id: 3, fill: 'black', x: 100, y: 70 },
{ id: 4, fill: 'black', x: 20, y: 100 }
];
draw(); // 绘制
function draw() {
const update = container.selectAll('rect')
.data(data, d => d.id);
//修改层
update.attr('x', (d, idx) => d.x)
.attr('y', (d, idx) => d.y)
.attr('fill', (d) => d.fill)
//渲染层
const enter = update.enter();
//删除层
const exit = update.exit();
enter.append('rect')
.attr('width', 20)
.attr('height', 20)
.attr('id', d => d.id)
.attr('x', (d, idx) => d.x)
.attr('y', (d, idx) => d.y)
.attr('fill', (d) => d.fill)
.attr('stroke', 'blue')
.attr('strokeWidth', 1)
exit.remove()
}
function onDownload(data, type, name) {
const blob = new Blob([data], { type }); // 返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。
const url = window.URL.createObjectURL(blob); //创建一个url
const link = document.createElement('a'); //创建一个a标签
link.href = url; // 把url 赋值给a标签的href
link.style.display = 'none';
link.setAttribute('download', name);
document.body.appendChild(link);
link.click(); // 触发a标签的点击事件
URL.revokeObjectURL(url); // 清除Url
document.body.removeChild(link);
};
function onSaveSvg() { // 保存svg
const svg = document.querySelector('svg');
const source = new XMLSerializer().serializeToString(svg); //将整个SVG document 对象序列化为一个 XML 字符串。
onDownload(source, 'text/xml', 'test.svg'); // 下载
}
// 获取设备的devicePixelRatio
function getPixelRatio(context) {
const backingStore = context.backingStorePixelRatio
|| context.webkitBackingStorePixelRatio
|| context.mozBackingStorePixelRatio
|| context.msBackingStorePixelRatio
|| context.oBackingStorePixelRatio
|| context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
}
function onSaveImage(format) { // 保存png
const svgDom = document.querySelector('svg');
const svgString = new XMLSerializer().serializeToString(svgDom);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const ratio = getPixelRatio(ctx); // 获取设备的devicePixelRatio
const w = window.innerWidth; // 获取设备的显示屏幕宽高
const h = window.innerHeight; // 图片加载完this.height才大于0.
const ratioW = canvas.width || w * ratio; // 计算屏幕的高清图片的宽高,同时设置画板的像素
const ratioH = canvas.height || h * ratio;
const domURL = this.URL || this.webkitURL || this;
const img = new Image(ratioW, ratioH);
const svg = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
const url = domURL.createObjectURL(svg);
img.src = url;
img.onload = function on() {
ctx.drawImage(img, 0, 0);
const png = canvas.toDataURL(`image/${format}`);
domURL.revokeObjectURL(png);
const a = document.createElement('a');
a.setAttribute('download', `test.${format}`);
a.setAttribute('href', png);
a.style.display = 'none';
document.body.appendChild(a);
a.click();
a.remove();
};
}
</script>
通过这篇文章, 相信尼对导出有了一个新得认识。
阅读量:830
点赞量:0
收藏量:0