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 来用于数据操作。

准备基础的图形绘制

准备基础的图形绘制,绘制出来几个小方块(不了解的可以往前面几篇文章翻翻)

<!DOCTYPE html>
<html lang="en">
  <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>
  <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>

导出svg图片

d3js绘制的svg导出后缀名是.svg的, 需要怎么做呢?

使用XMLSerializerserializeToString()方法返回 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导出可以看到还是蛮省劲的, 那么非.svg得格式图片该怎么导出? 可以不可以使用相同得方法呢?显然是不可以得,咱们借助canvastoDataURL进行导出。

文件类型 常见MIME 类型列表 developer.mozilla.org/zh-CN/docs/…

// 获取设备的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">
  <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>
  <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>

通过这篇文章, 相信尼对导出有了一个新得认识。

BigYe程普 React.js d3.js
私信