一、SVG 概述
- 官方文档:
https://developer.mozilla.org/zh-CN/docs/Web/SVG
-
SVG 全称 Scalable Vector Graphics,即可缩放矢量图形
-
SVG 基于 XML 标记语言,用于描述二维的矢量图形
-
SVG 格式提供的是矢量图,这意味着它的图像能够被无限放大而不失真或降低质量,并且可以方便地修改内容,无需图形编辑器
二、SVG 基本使用
1、准备阶段
- 准备一个宽 400 像素、高 300 像素的灰色边框的空白 SVG 画布
html
<svg id="mySvg" width="400" height="300" xmlns="http://www.w3.org/2000/svg">
...
</svg>
css
svg {
border: 1px solid #ccc;
}
2、基础图形绘制
- 矩形:x, y 是左上角坐标;fill 是填充色;stroke 是描边色;stroke-width 是描边粗细
html
<rect x="50" y="50" width="100" height="60" fill="steelblue" stroke="darkblue" stroke-width="3" />
- 圆形:cx, cy 是圆心坐标;r 是半径;fill 是填充色;opacity 控制透明度(0 ~ 1)
html
<circle cx="250" cy="100" r="40" fill="coral" opacity="0.8"/>
- 直线:x1, y1 是起点坐标,x2, y2 是终点坐标。stroke 是线条颜色,stroke-width 是线条粗细
html
<line x1="50" y1="200" x2="150" y2="250" stroke="green" stroke-width="5"/>
- 多边形:points 属性定义了一系列用空格分隔的 x,y 坐标对,它会自动连接首尾点形成封闭图形
html
<polygon points="300,200 350,250 250,250" fill="lavender" stroke="purple" />
- 路径:d 属性包含绘制命令,上例中,M(移动到)、L(画线到)、Z(闭合路径)
html
<path d="M 100,150 L 200,150 L 150,100 Z" fill="lightyellow" stroke="orange" />
三、SVG 使用 CSS
- SVG 的 fill、stroke、opacity 等属性可以使用 CSS控制,这有助于统一风格与交互效果
html
<svg id="mySvg" width="400" height="300" xmlns="http://www.w3.org/2000/svg">
<rect class="shape" x="50" y="50" width="100" height="60" />
<circle class="shape" cx="250" cy="100" r="40" />
</svg>
css
svg {
border: 1px solid #ccc;
}
.shape {
stroke-width: 2;
stroke-opacity: 0.7;
stroke: blue;
fill: gray;
transition: fill 0.3s ease;
}
.shape:hover {
fill: gold;
}
四、SVG 使用 JavaScript
html
<svg id="mySvg" width="400" height="300" xmlns="http://www.w3.org/2000/svg">
<rect id="myRect" class="shape" x="50" y="50" width="100" height="60" />
</svg>
css
svg {
border: 1px solid #ccc;
}
.shape {
stroke-width: 3;
stroke-opacity: 0.7;
stroke: blue;
}
js
const mySvg = document.getElementById("mySvg");
const myRect = document.getElementById("myRect");
// 生成一个随机颜色,改变矩形的填充色
myRect.addEventListener("click", function () {
const randomColor = "#" + Math.floor(Math.random() * 16777215).toString(16);
console.log(randomColor);
this.setAttribute("fill", randomColor);
});
// 在 SVG 内部点击时添加圆形
mySvg.addEventListener("click", function (event) {
const point = mySvg.createSVGPoint();
point.x = event.clientX;
point.y = event.clientY;
const svgPoint = point.matrixTransform(mySvg.getScreenCTM().inverse());
const newCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
newCircle.setAttribute("cx", svgPoint.x);
newCircle.setAttribute("cy", svgPoint.y);
newCircle.setAttribute("r", "15");
newCircle.setAttribute("fill", "lightcoral");
newCircle.classList.add("shape");
mySvg.appendChild(newCircle);
});
五、SVG 实例实操(房屋绘制)
html
<svg width="400" height="400" viewBox="0 0 400 400">
<!-- 房屋主体 -->
<rect class="house-body" x="100" y="200" width="200" height="150" rx="5" />
<!-- 屋顶 -->
<polygon class="roof" points="70,200 330,200 200,100" />
<!-- 烟囱 -->
<rect class="chimney" x="260" y="120" width="30" height="60" />
<rect class="chimney" x="255" y="115" width="40" height="10" />
<!-- 烟囱烟 -->
<path d="M275,90 Q280,70 290,65 Q300,60 310,55" fill="none" stroke="#aaa" stroke-width="3" stroke-linecap="round" />
<path d="M280,80 Q285,60 295,55 Q305,50 315,45" fill="none" stroke="#aaa" stroke-width="3" stroke-linecap="round" />
<!-- 窗户 -->
<rect class="window" x="120" y="220" width="40" height="40" rx="3" />
<rect class="window" x="240" y="220" width="40" height="40" rx="3" />
<!-- 窗户十字架 -->
<line x1="140" y1="220" x2="140" y2="260" stroke="#3366cc" stroke-width="1" />
<line x1="120" y1="240" x2="160" y2="240" stroke="#3366cc" stroke-width="1" />
<line x1="260" y1="220" x2="260" y2="260" stroke="#3366cc" stroke-width="1" />
<line x1="240" y1="240" x2="280" y2="240" stroke="#3366cc" stroke-width="1" />
<!-- 门 -->
<rect class="door" x="180" y="280" width="40" height="70" rx="3" />
<!-- 门把手 -->
<circle cx="210" cy="315" r="3" fill="gold" />
<!-- 台阶 -->
<rect x="170" y="350" width="60" height="10" fill="#888" rx="2" />
<!-- 文字 -->
<text x="200" y="390" text-anchor="middle" font-size="14" fill="#666">SVG 房屋绘制</text>
</svg>
<div style="text-align: center; margin: 20px">
<button onclick="addSun()">添加太阳</button>
<button onclick="changeColor()">改变颜色</button>
<button onclick="reset()">重置</button>
</div>
css
svg {
border: 1px solid #ddd;
background-color: #f8f9fa;
display: block;
margin: 20px auto;
}
.house-body {
fill: #ffcc99;
stroke: #cc9966;
stroke-width: 2;
}
.roof {
fill: #cc3333;
stroke: #993333;
stroke-width: 2;
}
.window {
fill: #99ccff;
stroke: #3366cc;
stroke-width: 1;
}
.window:hover {
fill: #66aaff;
}
.door {
fill: #996633;
stroke: #663300;
stroke-width: 2;
}
.door:hover {
fill: #cc9966;
}
.chimney {
fill: #cccccc;
stroke: #999999;
stroke-width: 2;
}
js
function addSun() {
const svg = document.querySelector("svg");
const sun = document.createElementNS("http://www.w3.org/2000/svg", "circle");
sun.setAttribute("cx", "350");
sun.setAttribute("cy", "50");
sun.setAttribute("r", "30");
sun.setAttribute("fill", "gold");
sun.setAttribute("opacity", "0.8");
svg.appendChild(sun);
// 阳光光线
for (let i = 0; i < 12; i++) {
const ray = document.createElementNS("http://www.w3.org/2000/svg", "line");
const angle = (i * 30 * Math.PI) / 180;
const x1 = 350 + Math.cos(angle) * 30;
const y1 = 50 + Math.sin(angle) * 30;
const x2 = 350 + Math.cos(angle) * 45;
const y2 = 50 + Math.sin(angle) * 45;
ray.setAttribute("x1", x1);
ray.setAttribute("y1", y1);
ray.setAttribute("x2", x2);
ray.setAttribute("y2", y2);
ray.setAttribute("stroke", "gold");
ray.setAttribute("stroke-width", "3");
svg.appendChild(ray);
}
}
function changeColor() {
const colors = ["#ff9999", "#99ff99", "#9999ff", "#ffff99", "#ff99ff"];
const houseBody = document.querySelector(".house-body");
const randomColor = colors[Math.floor(Math.random() * colors.length)];
houseBody.style.fill = randomColor;
}
function reset() {
location.reload();
}