Skip to content

SVG 工具

概述

本文档介绍了一组用于处理 SVG(可缩放矢量图形)的实用工具函数。这些函数主要用于 SVG 转换、样式操作等场景,可以帮助开发者在前端应用中灵活处理 SVG 图像。

函数详解

1. SVG 转 PNG - convertSvgToPng

将 SVG 元素转换为 PNG 格式的 base64 数据 URL。

函数签名

typescript
async function convertSvgToPng(svg: HTMLElement, scale: number = 2): Promise<string>

参数

  • svg: SVG 元素,可以是 SVGSVGElement 或包含 SVG 的 HTML 元素
  • scale: 可选参数,输出图像的缩放比例,默认值为 2

返回值

返回一个 Promise,解析为 PNG 格式的 base64 数据 URL 字符串。

工作原理

  1. 检查并获取 SVG 内容
  2. 创建 Canvas 元素并获取 2D 上下文
  3. 将 SVG 字符串转换为 base64 格式的 data URL
  4. 创建 Image 对象并加载 SVG 数据
  5. 设置 Canvas 大小,考虑缩放比例和设备像素比
  6. 设置白色背景并将 SVG 绘制到 Canvas
  7. 将 Canvas 内容转换为 PNG 格式的 data URL

使用示例

javascript
import { convertSvgToPng } from '@pt/utils/modules/svg';

// 示例 1: 转换页面中的 SVG 元素
const svgElement = document.querySelector('svg');
try {
  const pngDataUrl = await convertSvgToPng(svgElement);
  
  // 创建下载链接
  const link = document.createElement('a');
  link.href = pngDataUrl;
  link.download = 'image.png';
  link.click();
} catch (error) {
  console.error('SVG 转换失败:', error);
}

// 示例 2: 使用自定义缩放比例
const svgContainer = document.getElementById('chart-container');
const highResPng = await convertSvgToPng(svgContainer, 4); // 4倍缩放

2. 移除 SVG 样式 - removeSvgStyle

从 SVG 字符串中移除 SVG 标签上的 style 属性。

函数签名

typescript
function removeSvgStyle(svgString: string): string

参数

  • svgString: 包含 SVG 标记的字符串

返回值

返回移除 style 属性后的 SVG 字符串。

工作原理

使用正则表达式找到 SVG 标签中的 style 属性并将其移除。

使用示例

javascript
import { removeSvgStyle } from '@pt/utils/modules/svg';

// 原始 SVG 字符串
const originalSvg = '<svg width="100" height="100" style="background-color: blue;">';

// 移除样式
const cleanedSvg = removeSvgStyle(originalSvg);
console.log(cleanedSvg); // 输出: '<svg width="100" height="100">'

3. 替换 SVG 样式 - replaceSvgStyles

替换 SVG 字符串中的所有 style 属性值。

函数签名

typescript
function replaceSvgStyles(svgContent: string, newStyle: string): string

参数

  • svgContent: 包含 SVG 标记的字符串
  • newStyle: 新的样式字符串,将替换现有的 style 属性值

返回值

返回替换样式后的 SVG 字符串。

工作原理

使用正则表达式找到所有 style 属性并替换其值为指定的新样式。

使用示例

javascript
import { replaceSvgStyles } from '@pt/utils/modules/svg';

// 原始 SVG 字符串
const originalSvg = '<svg width="100" height="100" style="background-color: blue;"><rect style="fill: red;"></rect></svg>';

// 替换所有样式
const newSvg = replaceSvgStyles(originalSvg, "background-color: white; border: 1px solid gray;");
console.log(newSvg);
// 输出: '<svg width="100" height="100" style="background-color: white; border: 1px solid gray;"><rect style="background-color: white; border: 1px solid gray;"></rect></svg>'

实际应用场景

场景一:导出 SVG 图表为图片

javascript
import { convertSvgToPng } from '@pt/utils/modules/svg';

// 假设您使用了 D3.js 或 Chart.js 创建了一个 SVG 图表
const chartSvg = document.getElementById('chart');

// 添加导出按钮
const exportButton = document.getElementById('export-button');
exportButton.addEventListener('click', async () => {
  try {
    // 转换为高分辨率 PNG
    const pngUrl = await convertSvgToPng(chartSvg, 3);
    
    // 创建下载链接
    const link = document.createElement('a');
    link.href = pngUrl;
    link.download = 'chart-export.png';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  } catch (error) {
    console.error('导出失败:', error);
    alert('图表导出失败,请重试!');
  }
});

场景二:动态主题切换

javascript
import { replaceSvgStyles } from '@pt/utils/modules/svg';

// 主题样式映射
const themeStyles = {
  light: 'background-color: white; color: black;',
  dark: 'background-color: #333; color: white;',
  blue: 'background-color: #e6f7ff; color: #0066cc;'
};

// 主题切换函数
function changeTheme(themeName) {
  // 获取所有 SVG 元素
  const svgElements = document.querySelectorAll('svg');
  
  svgElements.forEach(svg => {
    // 获取原始 SVG 内容
    const svgString = svg.outerHTML;
    
    // 替换样式
    const newSvgString = replaceSvgStyles(svgString, themeStyles[themeName]);
    
    // 更新 SVG 内容
    svg.outerHTML = newSvgString;
  });
}

// 使用示例
document.getElementById('theme-selector').addEventListener('change', (e) => {
  changeTheme(e.target.value);
});

场景三:创建干净的 SVG 以便应用自定义样式

javascript
import { removeSvgStyle } from '@pt/utils/modules/svg';

// 从外部来源获取 SVG
async function fetchAndCleanSvg(url) {
  try {
    const response = await fetch(url);
    const svgText = await response.text();
    
    // 移除原始样式
    const cleanSvg = removeSvgStyle(svgText);
    
    // 将干净的 SVG 插入到页面
    document.getElementById('svg-container').innerHTML = cleanSvg;
    
    // 现在可以通过 CSS 应用自定义样式
  } catch (error) {
    console.error('获取或处理 SVG 失败:', error);
  }
}

// 使用示例
fetchAndCleanSvg('/assets/icons/chart.svg');

注意事项

  1. 浏览器兼容性

    • 这些函数使用了现代 DOM API 和 Canvas API,支持大多数现代浏览器
    • 在 IE11 等旧浏览器中可能需要使用 polyfill
  2. SVG 复杂性

    • 复杂的 SVG(包含滤镜、动画等)在转换为 PNG 时可能会出现渲染差异
    • 外部引用的资源(如外部 CSS 或图像)可能不会正确转换
  3. 安全考虑

    • 处理用户提供的 SVG 时应注意 XSS 安全风险
    • SVG 可以包含 JavaScript 代码,应避免直接加载不可信的 SVG
  4. 性能

    • 大尺寸或复杂的 SVG 转换为 PNG 可能会占用较多内存和处理时间
    • 使用合理的缩放比例,避免生成过大的图像
  5. 依赖项

    • convertSvgToPng 函数依赖 js-base64 库进行 base64 编码

兼容性特别处理

convertSvgToPng 函数中包含了几个特别的兼容性处理:

  1. 修复自闭合标签:将 <br> 替换为 <br/>
  2. 修复 img 标签:确保所有 img 标签都是正确的自闭合格式
  3. 添加 XML 声明:确保 SVG 内容有正确的 XML 声明
  4. 考虑设备像素比:适应高 DPI 显示器

这些处理使得该函数在各种环境下都能可靠工作。

Released under the MIT License.