SVG(Scalable Vector Graphics)是一种基于XML的矢量图形格式,可以无损缩放且支持交互和动画。本章将介绍SVG的基本概念和使用方法。
const svgOverview = {
definition: 'SVG是一种用于描述二维矢量图形的XML标记语言',
features: [
'矢量图形,无损缩放',
'基于XML,可读性好',
'支持CSS样式',
'支持JavaScript交互',
'支持动画',
'文件体积小'
],
comparison: {
SVG: {
type: '矢量',
scaling: '无损',
editing: '可编程修改',
use: '图标、图表、简单图形'
},
Canvas: {
type: '位图',
scaling: '有损',
editing: '需要重绘',
use: '游戏、图像处理、复杂动画'
}
}
};
<img src="image.svg" alt="SVG图像">
<object type="image/svg+xml" data="image.svg"></object>
<embed type="image/svg+xml" src="image.svg">
<div style="background-image: url('image.svg')"></div>
<svg width="200" height="200">
<circle cx="100" cy="100" r="50" fill="red"/>
</svg>
<svg width="300" height="200">
<rect x="10" y="10" width="100" height="80" fill="blue"/>
<rect x="130" y="10" width="100" height="80"
fill="green" stroke="black" stroke-width="3"/>
<rect x="10" y="110" width="100" height="80" rx="10" ry="10" fill="purple"/>
<rect x="130" y="110" width="100" height="80" rx="40" fill="orange"/>
</svg>
<svg width="300" height="200">
<circle cx="80" cy="100" r="60" fill="red"/>
<circle cx="220" cy="100" r="60" fill="blue"
stroke="black" stroke-width="5"/>
<ellipse cx="80" cy="100" rx="70" ry="40" fill="green"/>
<ellipse cx="220" cy="100" rx="40" ry="70" fill="purple"/>
</svg>
<svg width="300" height="200">
<line x1="10" y1="10" x2="290" y2="190"
stroke="black" stroke-width="2"/>
<polyline points="10,190 50,150 90,170 130,130 170,150 210,110 250,130 290,90"
fill="none" stroke="blue" stroke-width="2"/>
<polygon points="150,10 280,90 230,190 70,190 20,90"
fill="lime" stroke="green" stroke-width="2"/>
</svg>
<svg width="400" height="300">
<path d="M 10 10 L 100 10 L 100 100 Z" fill="red"/>
<path d="M 150 10 L 250 10 L 200 100 Z" fill="blue"/>
<path d="M 10 150 Q 100 50 200 150" fill="none" stroke="green" stroke-width="2"/>
<path d="M 220 150 C 220 50 350 50 350 150" fill="none" stroke="purple" stroke-width="2"/>
<path d="M 10 250 A 50 50 0 1 1 100 250" fill="none" stroke="orange" stroke-width="2"/>
</svg>
const pathCommands = {
M: { name: 'moveto', description: '移动到指定点' },
L: { name: 'lineto', description: '画线到指定点' },
H: { name: 'horizontal lineto', description: '水平线' },
V: { name: 'vertical lineto', description: '垂直线' },
C: { name: 'curveto', description: '三次贝塞尔曲线' },
S: { name: 'smooth curveto', description: '平滑三次贝塞尔曲线' },
Q: { name: 'quadratic Bézier curve', description: '二次贝塞尔曲线' },
T: { name: 'smooth quadratic Bézier curveto', description: '平滑二次贝塞尔曲线' },
A: { name: 'elliptical Arc', description: '椭圆弧' },
Z: { name: 'closepath', description: '闭合路径' }
};
<svg width="400" height="300">
<rect x="10" y="10" width="100" height="80"
fill="red" stroke="black" stroke-width="3"/>
<rect x="130" y="10" width="100" height="80"
fill="rgb(0, 128, 255)" stroke="#333" stroke-width="2"/>
<rect x="250" y="10" width="100" height="80"
fill="rgba(255, 0, 0, 0.5)" stroke="hsl(120, 100%, 50%)" stroke-width="4"/>
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:red"/>
<stop offset="100%" style="stop-color:blue"/>
</linearGradient>
</defs>
<rect x="10" y="110" width="100" height="80" fill="url(#grad1)"/>
<defs>
<radialGradient id="grad2" cx="50%" cy="50%" r="50%">
<stop offset="0%" style="stop-color:yellow"/>
<stop offset="100%" style="stop-color:red"/>
</radialGradient>
</defs>
<rect x="130" y="110" width="100" height="80" fill="url(#grad2)"/>
<rect x="250" y="110" width="100" height="80"
fill="none" stroke="black" stroke-width="10"
stroke-dasharray="10,5"/>
<rect x="10" y="210" width="100" height="80"
fill="purple" stroke="black" stroke-width="5"
stroke-linecap="round" stroke-linejoin="round"/>
<rect x="130" y="210" width="100" height="80"
fill="purple" opacity="0.5"/>
</svg>
<style>
.my-rect {
fill: blue;
stroke: black;
stroke-width: 2;
transition: fill 0.3s ease;
}
.my-rect:hover {
fill: red;
}
.my-circle {
fill: green;
filter: drop-shadow(3px 3px 2px rgba(0,0,0,0.3));
}
</style>
<svg width="300" height="200">
<rect class="my-rect" x="10" y="10" width="100" height="80"/>
<circle class="my-circle" cx="200" cy="100" r="50"/>
</svg>
<svg width="400" height="300">
<text x="50" y="50" font-family="Arial" font-size="24" fill="black">
东巴文 SVG教程
</text>
<text x="50" y="100" font-family="Arial" font-size="20" fill="blue"
text-anchor="middle">
居中文本
</text>
<text x="50" y="150" font-family="Arial" font-size="16" fill="green"
font-weight="bold" font-style="italic">
粗斜体文本
</text>
<text x="50" y="200">
<tspan fill="red">红色</tspan>
<tspan fill="blue">蓝色</tspan>
<tspan fill="green">绿色</tspan>
</text>
<defs>
<path id="textPath" d="M 50 250 Q 200 200 350 250"/>
</defs>
<text font-size="16">
<textPath href="#textPath">
沿路径排列的文本内容
</textPath>
</text>
</svg>
<svg width="400" height="300">
<rect x="10" y="10" width="50" height="50" fill="red"/>
<rect x="10" y="10" width="50" height="50" fill="blue"
transform="translate(100, 0)"/>
<rect x="10" y="10" width="50" height="50" fill="green"
transform="rotate(45, 35, 35) translate(200, 0)"/>
<rect x="10" y="10" width="50" height="50" fill="purple"
transform="scale(1.5) translate(200, 100)"/>
<rect x="10" y="10" width="50" height="50" fill="orange"
transform="skewX(20) translate(0, 150)"/>
<rect x="10" y="10" width="50" height="50" fill="cyan"
transform="matrix(1, 0.5, 0.5, 1, 200, 150)"/>
</svg>
<svg width="400" height="300">
<circle cx="50" cy="150" r="30" fill="red">
<animate attributeName="cx" from="50" to="350"
dur="2s" repeatCount="indefinite"/>
</circle>
<circle cx="200" cy="50" r="20" fill="blue">
<animate attributeName="cy" from="50" to="250"
dur="2s" repeatCount="indefinite"/>
<animate attributeName="r" values="20;40;20"
dur="2s" repeatCount="indefinite"/>
</circle>
<rect x="100" y="100" width="50" height="50" fill="green">
<animateTransform attributeName="transform" type="rotate"
from="0 125 125" to="360 125 125"
dur="3s" repeatCount="indefinite"/>
</rect>
<path d="M 10 250 L 100 250" stroke="purple" stroke-width="3">
<animate attributeName="d"
values="M 10 250 L 100 250;M 10 250 L 200 250;M 10 250 L 100 250"
dur="2s" repeatCount="indefinite"/>
</path>
</svg>
<style>
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.2); }
}
.rotating {
animation: rotate 3s linear infinite;
transform-origin: center;
}
.pulsing {
animation: pulse 1s ease-in-out infinite;
}
</style>
<svg width="400" height="300">
<rect class="rotating" x="75" y="75" width="50" height="50" fill="blue"/>
<circle class="pulsing" cx="250" cy="100" r="30" fill="red"/>
</svg>
const svg = document.querySelector('svg');
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', 50);
circle.setAttribute('cy', 150);
circle.setAttribute('r', 30);
circle.setAttribute('fill', 'blue');
svg.appendChild(circle);
let x = 50;
let direction = 1;
function animate() {
x += direction * 2;
if (x > 350 || x < 50) {
direction *= -1;
}
circle.setAttribute('cx', x);
requestAnimationFrame(animate);
}
animate();
function createSVGElement(tag, attributes) {
const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
for (const [key, value] of Object.entries(attributes)) {
element.setAttribute(key, value);
}
return element;
}
const rect = createSVGElement('rect', {
x: 100,
y: 100,
width: 50,
height: 50,
fill: 'green'
});
svg.appendChild(rect);
<svg width="400" height="300">
<rect id="myRect" x="50" y="50" width="100" height="80" fill="blue"/>
<circle id="myCircle" cx="250" cy="100" r="40" fill="red"/>
<path id="myPath" d="M 100 200 L 150 150 L 200 200 Z" fill="green"/>
</svg>
<script>
const rect = document.getElementById('myRect');
rect.addEventListener('click', function() {
this.setAttribute('fill', this.getAttribute('fill') === 'blue' ? 'red' : 'blue');
});
rect.addEventListener('mouseenter', function() {
this.style.cursor = 'pointer';
});
rect.addEventListener('mouseleave', function() {
this.style.cursor = 'default';
});
const circle = document.getElementById('myCircle');
circle.addEventListener('mousedown', function(e) {
const startX = e.clientX;
const startY = e.clientY;
const startCx = parseFloat(this.getAttribute('cx'));
const startCy = parseFloat(this.getAttribute('cy'));
const moveHandler = (e) => {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
this.setAttribute('cx', startCx + dx);
this.setAttribute('cy', startCy + dy);
};
const upHandler = () => {
document.removeEventListener('mousemove', moveHandler);
document.removeEventListener('mouseup', upHandler);
};
document.addEventListener('mousemove', moveHandler);
document.addEventListener('mouseup', upHandler);
});
</script>
<svg width="400" height="300">
<defs>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
</filter>
<filter id="shadow">
<feDropShadow dx="5" dy="5" stdDeviation="3" flood-color="black"/>
</filter>
<filter id="glow">
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<filter id="grayscale">
<feColorMatrix type="matrix"
values="0.33 0.33 0.33 0 0
0.33 0.33 0.33 0 0
0.33 0.33 0.33 0 0
0 0 0 1 0"/>
</filter>
<clipPath id="clipCircle">
<circle cx="100" cy="100" r="50"/>
</clipPath>
<mask id="maskGradient">
<rect x="0" y="0" width="200" height="200" fill="url(#grad1)"/>
</mask>
</defs>
<rect x="10" y="10" width="80" height="80" fill="red" filter="url(#blur)"/>
<rect x="110" y="10" width="80" height="80" fill="blue" filter="url(#shadow)"/>
<rect x="210" y="10" width="80" height="80" fill="green" filter="url(#glow)"/>
<image href="photo.jpg" x="10" y="110" width="100" height="100" filter="url(#grayscale)"/>
<rect x="120" y="110" width="100" height="100" fill="purple" clip-path="url(#clipCircle)"/>
</svg>
🎨 SVG使用建议
- 图标系统:使用SVG sprite或symbol创建图标系统
- 优化文件:使用SVGO等工具优化SVG文件
- 可访问性:添加title和desc元素提高可访问性
- 性能:复杂SVG考虑使用CSS will-change优化
📐 坐标系统
SVG坐标系统:
- 原点在左上角
- X轴向右为正
- Y轴向下为正
- 使用viewBox实现响应式缩放
下一章将探讨 [Web Audio API](file:///e:/db-w.cn/md_data/javascript/76_Web Audio API.md),学习如何在Web应用中处理音频。