SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)

一、SVG 概述

  • 官方文档:https://developer.mozilla.org/zh-CN/docs/Web/SVG
  1. SVG 全称 Scalable Vector Graphics,即可缩放矢量图形

  2. SVG 基于 XML 标记语言,用于描述二维的矢量图形

  3. 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、基础图形绘制
  1. 矩形:x, y 是左上角坐标;fill 是填充色;stroke 是描边色;stroke-width 是描边粗细
html 复制代码
<rect x="50" y="50" width="100" height="60" fill="steelblue" stroke="darkblue" stroke-width="3" />
  1. 圆形:cx, cy 是圆心坐标;r 是半径;fill 是填充色;opacity 控制透明度(0 ~ 1)
html 复制代码
<circle cx="250" cy="100" r="40" fill="coral" opacity="0.8"/>
  1. 直线:x1, y1 是起点坐标,x2, y2 是终点坐标。stroke 是线条颜色,stroke-width 是线条粗细
html 复制代码
<line x1="50" y1="200" x2="150" y2="250" stroke="green" stroke-width="5"/>
  1. 多边形:points 属性定义了一系列用空格分隔的 x,y 坐标对,它会自动连接首尾点形成封闭图形
html 复制代码
<polygon points="300,200 350,250 250,250" fill="lavender" stroke="purple" />
  1. 路径: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();
}
相关推荐
阿蒙Amon2 小时前
C#每日面试题-委托和事件的区别
java·开发语言·c#
用户47949283569152 小时前
给客户做私有化部署,我是如何优雅搞定 NPM 依赖管理的?
前端·后端·程序员
资生算法程序员_畅想家_剑魔2 小时前
Java常见技术分享-12-多线程安全-锁机制
java·开发语言
C_心欲无痕2 小时前
vue3 - markRaw标记为非响应式对象
前端·javascript·vue.js
qingyun9893 小时前
深度优先遍历:JavaScript递归查找树形数据结构中的节点标签
前端·javascript·数据结构
胡楚昊3 小时前
NSSCTF动调题包通关
开发语言·javascript·算法
2401_837088503 小时前
简要总结 HashSet 和 HashMap(Java)
java·开发语言
熬夜敲代码的小N3 小时前
Vue (Official)重磅更新!Vue Language Tools 3.2功能一览!
前端·javascript·vue.js
90后的晨仔3 小时前
用 Python 脚本一键重命名序列帧图片的名称
前端