第15章 Web浏览器中的JavaScript
15.7 SVG: 可缩放矢量图形
SVG(可缩放矢量图形)是一种图像格式。其名称中的单词“矢量”表示它与指定像素值矩阵的光栅图像格式(如GIF、JPEG和PNG)有根本不同。相反,SVG“图像”是对绘制所需图形所需步骤的精确、独立于分辨率(因此“可缩放”)的描述。SVG图像通过使用XML标记语言的文本文件来描述,这与HTML非常相似。
有三种方法可以在web浏览器中使用SVG:
- 可以将.svg图像文件与常规HTML<img>标签一起使用,就像使用.png或.jpeg图像一样。
- 因为基于XML的SVG格式与HTML非常相似,所以实际上可以将SVG标签直接嵌入到HTML文档中。如果这样做,浏览器的HTML解析器允许您省略XML名称空间,并将SVG标签视为HTML标签。
- 您可以使用DOM API动态创建SVG元素以按需生成图像。
下面的小节将演示SVG的第二和第三种用法。但是,请注意,SVG有一个大而中等复杂的语法。除了简单的图形绘制原语,它还包括对任意曲线、文本和动画的支持。SVG图形甚至可以合并JavaScript脚本和CSS样式表来添加行为和表示信息。对SVG的完整描述远远超出了本书的范围。本节的目的只是向您展示如何在HTML文档中使用SVG,并使用JavaScript编写脚本。
15.7.1 HTML中的SVG
当然,SVG图像可以使用HTML<img>标签来显示。但也可以直接在HTML中嵌入SVG。如果您这样做,您甚至可以使用CSS样式表来指定字体、颜色和线宽等内容。例如,这里是一个HTML文件,它使用SVG显示模拟时钟界面:
<html>
<head>
<title>模拟时钟</title>
<style>
/* 这些CSS样式都适用于下面定义的SVG元素 */
#clock {
/* 时钟中的所有样式:*/
stroke: black; /* 黑线 */
stroke-linecap: round; /* 端部为圆形 */
fill: #ffe; /* 在米白色的背景上 */
}
#clock .face {
stroke-width: 3; } /* 钟面轮廓 */
#clock .ticks {
stroke-width: 2; } /* 小时刻度线 */
#clock .hands {
stroke-width: 3; } /* 如何画时钟指针 */
#clock .numbers {
/* 如何画数字 */
font-family: sans-serif; font-size: 10; font-weight: bold;
text-anchor: middle; stroke: none; fill: black;
}
</style>
</head>
<body>
<svg id="clock" viewBox="0 0 100 100" width="250" height="250">
<!-- width和height属性是图形的屏幕大小 -->
<!-- viewBox属性提供内部坐标系 -->
<circle class="face" cx="50" cy="50" r="45"/> <!-- 钟面 -->
<g class="ticks"> <!-- 12小时刻度 -->
<line x1='50' y1='5.000' x2='50.00' y2='10.00'/>
<line x1='72.50' y1='11.03' x2='70.00' y2='15.36'/>
<line x1='88.97' y1='27.50' x2='84.64' y2='30.00'/>
<line x1='95.00' y1='50.00' x2='90.00' y2='50.00'/>
<line x1='88.97' y1='72.50' x2='84.64' y2='70.00'/>
<line x1='72.50' y1='88.97' x2='70.00' y2='84.64'/>
<line x1='50.00' y1='95.00' x2='50.00' y2='90.00'/>
<line x1='27.50' y1='88.97' x2='30.00' y2='84.64'/>
<line x1='11.03' y1='72.50' x2='15.36' y2='70.00'/>
<line x1='5.000' y1='50.00' x2='10.00' y2='50.00'/>
<line x1='11.03' y1='27.50' x2='15.36' y2='30.00'/>
<line x1='27.50' y1='11.03' x2='30.00' y2='15.36'/>
</g>
<g class="numbers"> <!-- 给4个方向编数 -->
<text x="50" y="18">12</text><text x="85" y="53">3</text>
<text x="50" y="88">6</text><text x="15" y="53">9</text>
</g>
<g class="hands"> <!-- 指针笔直向上 -->
<line class="hourhand" x1="50" y1="50" x2="50" y2="25"/>
<line class="minutehand" x1="50" y1="50" x2="50" y2="20"/>
</g>
</svg>
<script src="clock.js"></script>
</body>
</html>
您会注意到<svg>标签的后代结点不是普通的HTML标签。<circle>、<line>和<text>标签有明显的用途,而且应该清楚这个SVG图形是如何工作的。不过,还有许多其他SVG标签,您需要参考SVG参考资料来了解更多信息。您可能还注意到样式表很奇怪。fill、stroke-width和text-anchor等样式不是普通的CSS样式属性。在这种情况下,CSS本质上是用来设置出现在文档中的SVG标签的属性。还要注意CSS font简写属性不适用于SVG标签,您必须显式地将font-family、font-size和font-weight设置为单独的样式属性。
15.7.2 编写SVG脚本
将SVG直接嵌入HTML文件(而不是仅仅使用静态<img>标签)的一个原因是,如果您这样做,那么您可以使用DOM API来操作SVG图像。假设您使用SVG在web应用程序中显示图标。您可以将SVG嵌入<template>标签(§15.6.2),然后在需要将该图标的副本插入UI时克隆模板内容。如果你想让图标在用户将鼠标指针悬停在图标上时通过改变颜色来响应用户活动,你通常可以用CSS来实现这一点。
还可以动态操作直接嵌入到HTML中的SVG图形。上一节中的钟面示例显示一个静态时钟,时针和分针朝上,显示中午或午夜的时间。但是您可能已经注意到HTML文件包含一个<script>标签。该脚本定期运行一个函数来检查时间,并通过旋转适当的度数转换时针和分针,以便时钟实际显示当前时间,如图15-5所示。
图15-5. 脚本化SVG模拟时钟
操纵时钟的代码很简单。它根据当前时间确定时针和分针的正确角度,然后使用querySelector()查找显示这些指针的SVG元素,然后在它们上设置一个transform属性,使它们围绕时钟面的中心旋转。该函数使用setTimeout()确保它每分钟运行一次:
(function updateClock() {
// 更新SVG时钟图形以显示当前时间
let now = new Date(); // 当前时间
let sec = now.getSeconds(); // 秒
let min = now.getMinutes() + sec/60; // 小数分钟
let hour = (now.getHours()