HTML5系列(5)-- SVG 集成详解
前端技术探索系列:HTML5 SVG 集成详解 🎨
开篇寄语 👋
前端开发者们,
在前五篇文章中,我们探讨了 HTML5 的多个特性。今天,让我们深入了解 SVG 的魅力,看看如何创建可缩放的矢量图形。
一、SVG 基础入门 ✨
1. SVG 语法基础
<!-- 内联 SVG -->
<svg width="200" height="200" viewBox="0 0 200 200"><!-- 基础图形 --><circle cx="100" cy="100" r="50" fill="blue" /><rect x="50" y="50" width="100" height="100" fill="red" opacity="0.5" /><path d="M10 10 H 90 V 90 H 10 Z" fill="none" stroke="black" />
</svg>
2. 基础图形绘制
<svg width="400" height="400"><!-- 矩形 --><rectx="10" y="10"width="100" height="50"fill="blue"stroke="black"stroke-width="2"rx="10" ry="10"/><!-- 圆形 --><circlecx="200" cy="50"r="40"fill="red"stroke="darkred"stroke-width="2"/><!-- 椭圆 --><ellipsecx="300" cy="50"rx="60" ry="30"fill="green"/><!-- 线条 --><linex1="10" y1="100"x2="100" y2="150"stroke="purple"stroke-width="2"/><!-- 多边形 --><polygonpoints="200,100 250,150 150,150"fill="orange"/>
</svg>
3. 复用与组织
<!-- 定义可重用元素 -->
<svg><defs><!-- 渐变定义 --><linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" style="stop-color:rgb(255,255,0);" /><stop offset="100%" style="stop-color:rgb(255,0,0);" /></linearGradient><!-- 符号定义 --><symbol id="star" viewBox="0 0 32 32"><path d="M16 0 L20 12 L32 12 L22 20 L26 32 L16 24 L6 32 L10 20 L0 12 L12 12 Z" /></symbol></defs><!-- 使用定义的元素 --><rect width="200" height="100" fill="url(#gradient)" /><use href="#star" x="50" y="50" width="32" height="32" fill="gold" />
</svg>
二、SVG 动画技术 🎬
1. SMIL 动画
<svg width="300" height="300"><circle cx="150" cy="150" r="50" fill="blue"><!-- 位置动画 --><animateTransformattributeName="transform"type="translate"values="0,0; 50,0; 0,0"dur="2s"repeatCount="indefinite"/><!-- 颜色动画 --><animateattributeName="fill"values="blue;red;blue"dur="3s"repeatCount="indefinite"/><!-- 路径动画 --><animateMotionpath="M 0 0 H 100 V 100 H 0 Z"dur="4s"repeatCount="indefinite"/></circle>
</svg>
2. CSS 动画
<style>
.rotating-star {animation: rotate 3s linear infinite;transform-origin: center;
}@keyframes rotate {from { transform: rotate(0deg); }to { transform: rotate(360deg); }
}.pulsing-circle {animation: pulse 2s ease-in-out infinite;
}@keyframes pulse {0% { transform: scale(1); }50% { transform: scale(1.2); }100% { transform: scale(1); }
}
</style><svg width="200" height="200"><use href="#star" class="rotating-star" x="50" y="50" width="100" height="100" /><circle class="pulsing-circle" cx="100" cy="100" r="50" fill="purple" />
</svg>
3. JavaScript 动画
class SVGAnimator {constructor(element) {this.element = element;this.animations = new Map();}// 添加动画animate(properties, duration, easing = 'linear') {const startTime = performance.now();const initialValues = {};// 获取初始值for (const prop in properties) {initialValues[prop] = parseFloat(this.element.getAttribute(prop));}const animation = {startTime,duration,initialValues,targetValues: properties,easing};this.animations.set(animation, true);this.startAnimation();}// 动画循环startAnimation() {if (this.animationFrame) return;const animate = (currentTime) => {let hasRunning = false;this.animations.forEach((isRunning, animation) => {if (!isRunning) return;const elapsed = currentTime - animation.startTime;const progress = Math.min(elapsed / animation.duration, 1);if (progress < 1) {hasRunning = true;this.updateProperties(animation, progress);} else {this.animations.delete(animation);}});if (hasRunning) {this.animationFrame = requestAnimationFrame(animate);} else {this.animationFrame = null;}};this.animationFrame = requestAnimationFrame(animate);}// 更新属性updateProperties(animation, progress) {for (const prop in animation.targetValues) {const initial = animation.initialValues[prop];const target = animation.targetValues[prop];const current = initial + (target - initial) * progress;this.element.setAttribute(prop, current);}}
}
三、SVG 交互实现 🖱️
1. 事件处理
class SVGInteraction {constructor(svg) {this.svg = svg;this.elements = new Map();this.setupEvents();}setupEvents() {this.svg.addEventListener('click', this.handleClick.bind(this));this.svg.addEventListener('mousemove', this.handleMouseMove.bind(this));}// 获取 SVG 坐标getSVGPoint(event) {const point = this.svg.createSVGPoint();point.x = event.clientX;point.y = event.clientY;return point.matrixTransform(this.svg.getScreenCTM().inverse());}// 添加可交互元素addInteractiveElement(element, handlers) {this.elements.set(element, handlers);element.addEventListener('mouseenter', () => {if (handlers.hover) {handlers.hover(element, true);}});element.addEventListener('mouseleave', () => {if (handlers.hover) {handlers.hover(element, false);}});}handleClick(event) {const point = this.getSVGPoint(event);this.elements.forEach((handlers, element) => {if (this.isPointInElement(point, element) && handlers.click) {handlers.click(element);}});}handleMouseMove(event) {const point = this.getSVGPoint(event);this.elements.forEach((handlers, element) => {if (this.isPointInElement(point, element) && handlers.move) {handlers.move(element, point);}});}isPointInElement(point, element) {const bbox = element.getBBox();return (point.x >= bbox.x &&point.x <= bbox.x + bbox.width &&point.y >= bbox.y &&point.y <= bbox.y + bbox.height);}
}
2. 滤镜效果
<svg width="400" height="400"><defs><!-- 高斯模糊 --><filter id="blur"><feGaussianBlur stdDeviation="2" /></filter><!-- 阴影效果 --><filter id="shadow"><feDropShadow dx="2" dy="2" stdDeviation="2" /></filter><!-- 发光效果 --><filter id="glow"><feGaussianBlur stdDeviation="2" result="coloredBlur" /><feMerge><feMergeNode in="coloredBlur" /><feMergeNode in="SourceGraphic" /></feMerge></filter></defs><!-- 使用滤镜 --><circle cx="100" cy="100" r="50" fill="purple" filter="url(#glow)" />
</svg>
四、实践项目:动态 LOGO 生成器 🎯
class LogoGenerator {constructor(container) {this.container = container;this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');this.setup();}setup() {this.svg.setAttribute('width', '300');this.svg.setAttribute('height', '300');this.container.appendChild(this.svg);// 定义滤镜和渐变this.defineFilters();this.defineGradients();}defineFilters() {const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');// 添加发光效果const glowFilter = `<filter id="logo-glow"><feGaussianBlur stdDeviation="2" result="blur" /><feFlood flood-color="rgba(0,0,255,0.3)" result="color" /><feComposite in="color" in2="blur" operator="in" /><feMerge><feMergeNode /><feMergeNode in="SourceGraphic" /></feMerge></filter>`;defs.innerHTML = glowFilter;this.svg.appendChild(defs);}defineGradients() {const defs = this.svg.querySelector('defs');// 添加渐变const gradient = `<linearGradient id="logo-gradient" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" style="stop-color:#4CAF50" /><stop offset="100%" style="stop-color:#2196F3" /></linearGradient>`;defs.innerHTML += gradient;}// 生成 LogogenerateLogo(text, options = {}) {const {fontSize = 48,fontFamily = 'Arial',color = 'url(#logo-gradient)',useGlow = true} = options;// 清空现有内容while (this.svg.lastChild) {this.svg.removeChild(this.svg.lastChild);}// 重新添加 defsthis.defineFilters();this.defineGradients();// 创建文本元素const textElement = document.createElementNS('http://www.w3.org/2000/svg', 'text');textElement.textContent = text;textElement.setAttribute('x', '150');textElement.setAttribute('y', '150');textElement.setAttribute('text-anchor', 'middle');textElement.setAttribute('dominant-baseline', 'middle');textElement.setAttribute('font-size', fontSize);textElement.setAttribute('font-family', fontFamily);textElement.setAttribute('fill', color);if (useGlow) {textElement.setAttribute('filter', 'url(#logo-glow)');}// 添加动画const animation = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');animation.setAttribute('attributeName', 'transform');animation.setAttribute('type', 'scale');animation.setAttribute('values', '1;1.1;1');animation.setAttribute('dur', '2s');animation.setAttribute('repeatCount', 'indefinite');textElement.appendChild(animation);this.svg.appendChild(textElement);return this;}// 导出 SVGexport() {const serializer = new XMLSerializer();return serializer.serializeToString(this.svg);}// 导出 PNGasync exportPNG() {return new Promise((resolve, reject) => {const image = new Image();image.onload = () => {const canvas = document.createElement('canvas');canvas.width = 300;canvas.height = 300;const ctx = canvas.getContext('2d');ctx.drawImage(image, 0, 0);resolve(canvas.toDataURL('image/png'));};image.onerror = reject;const svgBlob = new Blob([this.export()], { type: 'image/svg+xml' });image.src = URL.createObjectURL(svgBlob);});}
}// 使用示例
const logoGen = new LogoGenerator(document.getElementById('logo-container'));
logoGen.generateLogo('LOGO', {fontSize: 64,useGlow: true
});
性能优化建议 🚀
-
SVG 优化
- 使用
<use>复用元素 - 压缩 SVG 代码
- 避免不必要的精度
- 使用
-
动画优化
- 使用 CSS 动画代替 SMIL
- 使用
transform代替位置属性 - 避免频繁的 DOM 操作
-
交互优化
- 使用事件委托
- 优化碰撞检测
- 使用
requestAnimationFrame
浏览器兼容性 🌐
| 特性 | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| 基础 SVG | ✅ | ✅ | ✅ | ✅ |
| SMIL | ✅ | ✅ | ✅ | ✅ |
| CSS 动画 | ✅ | ✅ | ✅ | ✅ |
| 滤镜 | ✅ | ✅ | ✅ | ✅ |
实用工具推荐 🛠️
-
SVG 编辑器
- Inkscape
- Adobe Illustrator
- Figma
-
SVG 优化工具
- SVGO
- SVG OMG
- SVG Optimizer
-
JavaScript 库
- Snap.svg
- SVG.js
- GreenSock
总结 🎯
SVG 为我们提供了强大的矢量图形能力:
- 可缩放性 📏
- 动画效果 🎬
- 交互能力 🖱️
- 滤镜效果 🎨
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻
相关文章:
HTML5系列(5)-- SVG 集成详解
前端技术探索系列:HTML5 SVG 集成详解 🎨 开篇寄语 👋 前端开发者们, 在前五篇文章中,我们探讨了 HTML5 的多个特性。今天,让我们深入了解 SVG 的魅力,看看如何创建可缩放的矢量图形。 一、…...
深度学习常见数据集处理方法
1、数据集格式转换(json转txt) import json import os 任务:实例分割,labelme的json文件, 转txt文件 Ultralytics YOLO format <class-index> <x1> <y1> <x2> <y2> ... <xn> <yn> # 类…...
1180 - 【入门】数字出现次数
题目描述 有50个数(0-19),求这50个数中相同数字出现的最多次数为几次? 输入 50个数字 输出 1个数字(即相同数字出现的最多次数) 样例 输入 复制 1 10 2 0 15 8 12 7 0 3 15 0 15 18 16 7 17 16 9 …...
C++20: 像Python一样split字符串
概要 Python 的字符串天生支持 split( ) 操作,支持单个字符或字符串作为分隔符。 C 在这方面显得很笨拙,但是在 C20 下经过一番尝试,还是能够提供类似的简洁调用。 Python 代码 s 0,11,336,23,370nums s.split(,) for n in nums:print(n…...
Unity3D UI 嵌套滚动视图
Unity3D 解决 UI 嵌套滚动视图滑动问题。 嵌套滚动视图 滑动问题 在游戏开发中,我们常常会遇到一种情况,在一个滚动视图列表中,每个 item 还包含了一个内嵌的滚动视图。 这样,当我们在滑动外层的滚动视图时,如果点…...
你还没有将 Siri 接入GPT对话功能吗?
由于各种原因,国内ios用户目前无缘自带 AI 功能,但是这并不代表国内 ios 无法接入 AI 功能,接下来手把手带你为iPhone siri 接入 gpt 对话功能。 siri 接入 chatGPT 暂时还无法下载 ChatGPT app,或者没有账号的读者可以直接跳到…...
_C#_串口助手_字符串拼接缺失问题(未知原理)
最近使用WPF开发串口助手时,遇到一个很奇怪的问题,无论是主线程、异步还是多线程,当串口接收速度达到0.016s一次以上,就会发生字符串缺失问题并且很卡。而0.016s就一切如常,仿佛0.015s与0.016s是天堑之隔。 同一份代码…...
浅析大数据时代下的网络安全
一、大数据时代下网络安全的现状 在全球化进程不断深入发展的情况下,互联网行业发展速度也更加迅猛,人们对网络信息的需求量不断增加,所以目前已经进入了大数据时代。 随着计算机技术的不断发展,我国互联网网络规模、网民数量、…...
Mysql数据库基础篇笔记
目录 sql语句 DDL——数据库定义语言(定义库,表,字段) 数据库操作: 表操作: DML 增删改语句 DQL 语法编写顺序: 条件查询 DCL 用户管理: 权限管理: 函数 常见字符串内置函…...
rabbitmq原理及命令
目录 一、RabbitMQ原理1、交换机(Exchange)fanoutdirecttopicheaders(很少用到) 2、队列Queue3、Virtual Hosts4、基础对象 二、RabbitMQ的一些基本操作:1、用户管理2、用户角色3、vhost4、开启web管理接口5、批量删除队列 一、Ra…...
React进阶面试题(四)
React 的 reconciliation(协调)算法 Reconciliation是React的diff算法,用于比较更新前后的虚拟DOM树差异,从而使用最小的代价将原始DOM按照新的状态、属性进行更新。其目的是找出两棵树的差异,原生方式直接比较复杂度…...
24/12/1 算法笔记<强化学习> 创建Maze交互
我们今天制作一个栅格的游戏。 我们直接上代码教学。 1.载入库和查找相应的函数版本 import numpy as np import time import sysif sys.version_info.major 2:import Tkinter as tk else:import tkinter as tk 2.设置长宽和单元格大小 UNIT 40 MAZE_H 4 MAZE_W 4 3.初始…...
Linux驱动开发(10):I2C子系统–mpu6050驱动实验
本章我们以板载MPU6050为例讲解i2c驱动程序的编写,本章主要分为五部分内容。 第一部分,i2c基本知识,回忆i2c物理总线和基本通信协议。 第二部分,linux下的i2c驱动框架。 第三部分,i2c总线驱动代码拆解。 第四部分&a…...
《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》
《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》 一、引言二、K-5S 电化学传感器模组概述(一)产品简介(二)产品特点(三)产品适用场景 三、电化学传感器原理及优点(一…...
如何将多个JS文件打包成一个JS文件?
文章目录 前言SDK 打包安装 webpack创建 webpack.config.js编译命令行遇到的坑点前言 上一篇已经记录了如何开发一个小游戏聚合SDK,既然是SDK,最终都是给外部人员使用的。调研了一下市面上的前端SDK,最终都是编译成一个 js 文件。我猜理由大概是 js 文件之间的调用都是需要…...
100个python经典面试题详解(新版)
应老粉要求,每晚加餐一个最新面试题 包括Python面试中常见的问题,涵盖列表、元组、字符串插值、比较操作符、装饰器、类与对象、函数调用方式、数据结构操作、序列化、数据处理函数等多个方面。 旨在帮助数据科学家和软件工程师准备面试或提升Python技能。 7、Python面试题…...
C#初阶概念理解
梳理了一些本人在学习C#时的一些生疏点,同时也加深自己的印象。 堆&栈 堆用来存储程序运行时产生的变量,当程序结束时释放; 栈用来存储程序运行时,调用方法产生的临时变量,方法运行完成后就会释放…...
node.js基础学习-url模块-url地址处理(二)
前言 前面我们创建了一个HTTP服务器,如果只是简单的http://localhost:3000/about这种链接我们是可以处理的,但是实际运用中一般链接都会带参数,这样的话如果我们只是简单的判断链接来分配数据,就会报404找不到链接。为了解决这个问…...
算法与数据结构(1)
一:数据结构概论 数据结构分为初阶数据结构(主要由C语言实现)和高阶数据结构(由C实现) 初阶数据结构当中,我们会学到顺序表、链表、栈和队列、二叉树、常见排序算法等内容。 高阶数据结构当中࿰…...
FTP介绍与配置
前言: FTP是用来传送文件的协议。使用FTP实现远程文件传输的同时,还可以保证数据传输的可靠性和高效性。 介绍 FTP的应用 在企业网络中部署一台FTP服务器,将网络设备配置为FTP客户端,则可以使用FTP来备份或更新VRP文件和配置文件…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
