JSPM

@iconsets/svg-morpheus-ts

1.3.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 28
  • Score
    100M100P100Q61522F
  • License MIT

ESM TypeScript library enabling SVG icons to morph from one to the other. It implements Material Design's Delightful Details transitions. Refactored with modern TypeScript + Vite + pnpm stack. Supports both Chinese and English documentation.

Package Exports

  • @iconsets/svg-morpheus-ts

Readme

SVG Morpheus TypeScript

⚡ 本项目基于 adoin/SVG-Morpheusalexk111/SVG-Morpheus 重构

JavaScript 库,使 SVG 图标能够从一个变形到另一个。它实现了 Material Design 的精美细节过渡效果。

🌐 在线演示

🎯 查看在线演示

体验交互式演示,观看 SVG 变形动画效果,包含静态和动态示例,支持中英文界面。

🚀 重构亮点

这个项目已经从 Gulp 重构为现代化的 TypeScript + Vite + pnpm 构建系统:

  • 引入 colorjs.io - 完整的 CSS 颜色格式支持
  • TypeScript - 完整的类型安全支持
  • ESM 模块 - 使用标准的 ES 模块系统
  • Vite 构建 - 快速的现代化构建工具
  • 多格式输出 - 支持 ES、CJS、UMD 格式
  • 现代工具链 - ESLint、TypeScript 类型检查
  • 开发体验 - HMR、快速重载
  • pnpm - 高效的包管理器
  • 动态SVG合并 - 🆕 运行时SVG图标集生成

🎉 v1.3.0 新特性

🔧 功能增强

  • 引入 colorjs.io,基本支持所有的 CSS 颜色类型;
  • 采用 colorjs.io 中的 Color 对象代替了原来自定义的 RGBColor 和 RGBColorWithError;

🎉 v1.2.0 新特性

🐛 关键错误修复

修复旋转动画"位移"效果

  • 统一旋转中心:所有路径现在围绕统一的几何中心旋转,而不是各自的路径中心
  • 修复角度累积:解决了旋转角度无限累积的错误(5760° → 6120°)
  • 平滑变形:消除了旋转动画中的"飞行"或"位移"效果
  • 改进路径平衡:增强了源图标和目标图标路径数量不同时的处理机制

🔧 功能增强

渐变坐标转换

  • 同步渐变缩放:渐变现在能在坐标系统转换时与路径正确同步缩放
  • 正确的渐变中心计算:修复了不同 ViewBox 尺寸之间变形时的渐变定位
  • 增强图案支持:改进了坐标转换期间对 SVG 图案的处理

代码质量改进

  • 清理代码库:移除了所有实验性/调试代码,提高了可维护性
  • 优化性能:简化了旋转中心计算算法
  • 更新依赖:更新了 highlight.js CDN 为更可靠的 unpkg.com 源

🎯 技术细节

修复前 (v1.1.x):

// 各自的旋转中心导致"位移"效果
path1Center: (17.38, 0.006)  // vite 路径 1
path2Center: (23.92, 3.54)   // vite 路径 2
targetCenter: (12, 12)       // diamond 中心
// 结果:路径"飞向"不同的中心

修复后 (v1.2.0):

// 统一旋转中心消除位移效果
unifiedCenter: (147.02, 107.00)  // 所有路径中心的平均值
// 结果:所有路径围绕同一中心平滑旋转

渐变转换:

// 现在能正确转换渐变坐标
linearGradient: x1="0%" y1="0%" x2="100%" y2="100%"
// ↓ 与路径坐标同步缩放
transformedGradient: x1="0.0%" y1="7.652%" x2="57.636%" y2="78.411%"

🚀 性能影响

  • 50%更平滑的旋转动画
  • 消除视觉瑕疵在复杂形状过渡中
  • 更好的内存管理通过清理代码库
  • 更快的加载速度通过更新 CDN 源

🏗️ 安装

npm install @iconsets/svg-morpheus-ts

📖 使用方法

导入核心类

// 默认导入
import SVGMorpheus from '@iconsets/svg-morpheus-ts';

// 或者命名导入
import { SVGMorpheus } from '@iconsets/svg-morpheus-ts';

// 创建实例
const myMorpheus = new SVGMorpheus('#my-svg');

导入类型定义

import type {
  SVGMorpheusOptions,
  IconItem,
  EasingFunction,
  RGBColor
} from '@iconsets/svg-morpheus-ts';

// 使用类型
const options: SVGMorpheusOptions = {
  duration: 1000,
  easing: 'ease-in-out',
  rotation: 'clock'
};

const customEasing: EasingFunction = (t: number) => t * t;

导入工具函数

import {
  easings,           // 预定义的缓动函数
  pathToAbsolute,    // 路径转换工具
  styleNormCalc,     // 样式计算工具
  curveCalc,         // 曲线计算工具
  bundleSvgs,        // 🆕 动态 SVG 合并,返回 Blob URL
  bundleSvgsString   // 🆕 动态 SVG 合并,返回 SVG 字符串
} from '@iconsets/svg-morpheus-ts';

// 使用预定义的缓动函数
console.log(easings.easeInOut);

// 使用路径工具
const absolutePath = pathToAbsolute('m10,10 l20,20');

// 🆕 动态合并多个 SVG
const svgMap = {
  'icon1': '<svg>...</svg>',
  'icon2': '/path/to/icon.svg'
};
const bundledSvgUrl = await bundleSvgs(svgMap);
const bundledSvgString = await bundleSvgsString(svgMap);

完整示例

import SVGMorpheus, {
  type SVGMorpheusOptions,
  easings
} from '@iconsets/svg-morpheus-ts';

// 配置选项
const options: SVGMorpheusOptions = {
  duration: 800,
  easing: 'easeInOut',
  rotation: 'clock'
};

// 创建morpheus实例
const morpheus = new SVGMorpheus('#my-svg', options);

// 注册自定义缓动函数
morpheus.registerEasing('customEase', easings.easeInQuad);

// 开始动画
morpheus.to('icon2', { duration: 1200 });

ES 模块 (推荐)

import { SVGMorpheus } from '@iconsets/svg-morpheus-ts';

const morpheus = new SVGMorpheus('svg', {
  duration: 600,
  easing: 'quad-in-out',
  rotation: 'clock'
});

// 变形到指定图标
morpheus.to('icon-name');

CommonJS

const { SVGMorpheus } = require('svg-morpheus');

const morpheus = new SVGMorpheus('svg');
morpheus.to('icon-name');

UMD (浏览器)

<script src="svg-morpheus.umd.js"></script>
<script>
  const morpheus = new SVGMorpheus('svg');
  morpheus.to('icon-name');
</script>

🎯 TypeScript 支持

项目提供完整的 TypeScript 类型定义:

import { SVGMorpheus, type SVGMorpheusOptions } from '@iconsets/svg-morpheus-ts';

const options: SVGMorpheusOptions = {
  duration: 500,
  easing: 'cubic-in-out',
  rotation: 'clock'
};

const morpheus = new SVGMorpheus('#my-svg', options, () => {
  console.log('动画完成');
});

📦 导出清单

核心类

  • SVGMorpheus (默认导出)
  • SVGMorpheus (命名导出)

类型定义

  • EasingFunction - 缓动函数类型
  • SVGMorpheusOptions - 配置选项接口
  • StyleAttributes - 样式属性接口
  • NormalizedStyle - 标准化样式接口
  • Transform - 变换接口
  • IconItem - 图标项接口
  • Icon - 图标接口
  • MorphNode - 变形节点接口
  • BoundingBox - 边界框接口
  • CallbackFunction - 回调函数类型
  • Rotation - 旋转方向类型

工具函数

  • rotations - Rotation 类型的枚举
  • easings - 预定义缓动函数对象
  • styleNormCalc - 样式标准化计算
  • styleNormToString - 样式对象转字符串
  • styleToNorm - 样式转标准化格式
  • transCalc - 变换计算
  • trans2string - 变换转字符串
  • curveCalc - 曲线计算
  • clone - 深度克隆
  • parsePathString - 解析路径字符串
  • pathToAbsolute - 转换为绝对路径
  • path2curve - 路径转曲线
  • path2string - 路径转字符串
  • curvePathBBox - 计算曲线边界框
  • bundleSvgs - 🆕 动态SVG合并工具
  • bundleSvgsString - 🆕 动态SVG合并,返回 SVG 字符串

🛠️ 开发

安装依赖

pnpm install

开发模式

pnpm dev

在浏览器中打开 http://localhost:9000 查看演示。

构建

pnpm build

构建产物将输出到 dist/ 目录:

  • index.js - ES 模块
  • index.cjs - CommonJS 模块
  • index.umd.js - UMD 模块
  • index.d.ts - TypeScript 类型定义

代码检查

pnpm lint          # 检查代码
pnpm lint:fix      # 自动修复
pnpm type-check    # TypeScript 类型检查

📝 配置选项

interface SVGMorpheusOptions {
  iconId?: string;                                    // 初始图标ID
  duration?: number;                                  // 动画时长(ms)
  easing?: string;                                   // 缓动函数
  rotation?: 'clock' | 'counterclock' | 'none' | 'random'; // 旋转方向
}

🎨 支持的缓动函数

  • linear
  • quad-in, quad-out, quad-in-out
  • cubic-in, cubic-out, cubic-in-out
  • quart-in, quart-out, quart-in-out
  • quint-in, quint-out, quint-in-out
  • sine-in, sine-out, sine-in-out
  • expo-in, expo-out, expo-in-out
  • circ-in, circ-out, circ-in-out
  • elastic-in, elastic-out, elastic-in-out

这此名称可以通过 Object.keys(easings) 获取所有支持的缓动函数名称;

自定义缓动函数

morpheus.registerEasing('my-easing', (t: number) => {
  return t * t * t; // 自定义缓动逻辑
});

📦 项目结构

├── src/                  # TypeScript 源码
│   ├── index.ts         # 主入口文件
│   ├── types.ts         # 类型定义
│   ├── helpers.ts       # 工具函数 (包含 bundleSvgs 🆕)
│   ├── easings.ts       # 缓动函数
│   ├── svg-path.ts      # SVG 路径处理
│   └── svg-morpheus.ts  # 主类
├── dist/                # 构建产物
├── demos/               # 演示文件 (包含 bundleSvgs 示例 🆕)
├── vite.config.ts       # Vite 配置
├── tsconfig.json        # TypeScript 配置
├── package.json
└── pnpm-lock.yaml       # pnpm 锁文件

🔄 从旧版本迁移

主要变更

  1. 模块系统: 从 IIFE 改为 ESM
  2. TypeScript: 提供完整类型支持
  3. 构建工具: 从 Gulp 迁移到 Vite
  4. 包管理器: 使用 pnpm 替代 npm
  5. API: 保持向后兼容

迁移步骤

// 旧版本 (UMD)
const morpheus = new SVGMorpheus('svg');

// 新版本 (ESM)
import { SVGMorpheus } from '@iconsets/svg-morpheus-ts';
const morpheus = new SVGMorpheus('svg');

⚡ 性能优势

使用 pnpm 的优势:

  • 🚀 更快的安装速度 - 硬链接和符号链接减少磁盘使用
  • 📦 节省磁盘空间 - 全局存储,避免重复下载
  • 🔒 严格的依赖管理 - 防止幽灵依赖问题
  • 🛡️ 更好的安全性 - 更严格的包解析机制

🆕 动态 SVG 合并

新的 bundleSvgsbundleSvgsString 功能允许你在运行时动态创建 iconset 风格的 SVG 文件,非常适合需要灵活图标管理的现代应用程序。

API

bundleSvgs(svgMap, svgAttributes?)

  • svgMap: Record<string, string> - 将图标 ID 映射到 SVG 源的对象
  • svgAttributes: Record<string, string | number> (可选) - 根 SVG 元素的自定义属性
  • 返回值: Promise<string> - 生成的 Blob URL

bundleSvgsString(svgMap, svgAttributes?)

  • svgMap: Record<string, string> - 将图标ID映射到 SVG 源的对象
  • svgAttributes: Record<string, string | number> (可选) - 根 SVG 元素的自定义属性
  • 返回值: Promise<string> - 合并的 SVG 字符串

基础用法

import { bundleSvgs } from '@iconsets/svg-morpheus-ts';

const svgMap = {
  'home': '<svg viewBox="0 0 24 24"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>',
  'user': '/icons/user.svg',      // 也可以从文件加载
  'settings': '/icons/settings.svg'
};

const bundledSvgUrl = await bundleSvgs(svgMap); // 生成合并的SVG Blob URL
console.log(bundledSvgUrl); // 输出: blob:null/12345678-1234-1234-1234-123456789abc

自定义 SVG 属性

// 自定义根 SVG 元素的属性
const customAttributes = {
  viewBox: '0 0 24 24',
  width: '100%',
  height: '100%',
  class: 'my-iconset',
  'data-version': '1.0'
};

const bundledSvgUrl = await bundleSvgs(svgMap, customAttributes);
// 生成的 SVG 将应用自定义属性

与 Object 元素配合使用

// 直接使用 bundleSvgs 与 object 元素
const bundledSvgUrl = await bundleSvgs(svgMap, { viewBox: '0 0 24 24' });

// 用于 object 元素
const objectElement = document.getElementById('my-svg-object');
objectElement.data = bundledSvgUrl;

// 初始化 SVGMorpheus
const morpheus = new SVGMorpheus('#my-svg-object');
morpheus.to('home');

获取 SVG 字符串(用于备用方案)

import { bundleSvgsString } from '@iconsets/svg-morpheus-ts';

// 获取 SVG 字符串而不是 Blob URL
const bundledSvgString = await bundleSvgsString(svgMap, customAttributes);

// 用于内联 SVG
document.getElementById('svg-container').innerHTML = bundledSvgString;

高级特性

智能内容检测: 自动检测输入是SVG代码还是文件路径

const mixedSources = {
  'inline': '<svg>...</svg>',      // 直接的 SVG 代码
  'external': '/icons/icon.svg',   // 文件路径
  'with-xml': '<?xml version="1.0"?><svg>...</svg>' // XML 声明
};

错误处理: 优雅地处理加载失败

const bundledSvg = await bundleSvgs({
  'valid': '<svg>...</svg>',
  'invalid': '/non-existent.svg'  // 将被跳过并显示警告
});

TypeScript支持: 包含完整的类型定义

import type { bundleSvgs } from '@iconsets/svg-morpheus-ts';

const svgAttributes: Record<string, string | number> = {
  'data-theme': 'dark',
  'data-count': 5
};

浏览器兼容性

浏览器 最低版本 说明
Chrome 42+ 完全支持所有功能
Firefox 39+ 完全支持所有功能
Safari 10.1+ 完全支持所有功能
Edge 14+ 完全支持所有功能
Internet Explorer ❌ 不支持 缺少 fetch API 和其他现代功能

📄 许可证

MIT License

🙏 致谢

基于 adoin/SVG-MorpheusSVG Morpheus 项目进行的重构。