据直线的一般表示形式y=mx+b我们可以很容易得出经过两点p0(x0,y0)、p1(x1,y1)的直接方程为
稍作变换表示成函数的形式如下
显示屏幕是由如下图所示一个个微小的像素组成的,屏幕坐标是离散的,绘制一条线段实际上就是设置一系列像素的颜色来近似模拟一条直线,Bresenham方式是一种采用中点算法来实现直线绘制的方法。
这里以直线斜率在(0,1]区间的情况为例来介绍Bresenham算法的核心内容,斜率在此区间内x轴的增长要快于y轴的增长,因此我们直接遍历x0~x1之间的像素(像素坐标都是整数),关键步骤就是确定x对应的y轴像素值。
假如已经绘制了像素(x,y),下一步就是确定是绘制(x+1,y+1)还是(x+1,y),Bresenham算法采用计算直线方程的函数形式的值f(x+1, y+0.5),也就是y+1和y的中点来进行判别。
y=y0
for x=x0 to x1 do
draw(x,y)
if f(x+1, y+0.5) < 0 then
y=y + 1
其他斜率曲线的判断方法是类似的,需注意的是如果y的变化快于x的变化,需要遍历y0到y1,通过中点算法来确定x的值。另外需要特别注意的就是直接方程f(x,y)的值大于0还是小于0的判断要仔细判别,这里判断方法并不是复杂,只是比较容易混淆。
x、y象限内直线斜率可以换分为(-∞,-1]、(-1,0]、(0,1]、(1,+∞)四个区间,见下图。
最后,我们用html的canvas元素来演示Bresenham画线算法,理解了该算法的原理,代码也就顺理成章了。示例绘制了四个斜率的线段,效果如下,可以看到某些斜率下的锯齿效果还是非常明显的,后续会继续介绍如何利用抗锯齿算法来生成更平滑的直线。
注:canvas的y轴正向是向下的。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bresenham画线算法示例</title>
</head>
<body>
<canvas id="canvas" width="780" height="780"></canvas>
<script src="./bresenham.js"></script>
</body>
</html>
bresenham.js
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
function setPixel(x, y, color='rgba(255, 255, 255, 1.0)') {
ctx.fillStyle=color;
ctx.fillRect(x, y, 1, 1);
}
function drawLine(p0, p1, color='rgba(255, 255, 255, 1.0)') {
let x0, y0, x1, y1;
// 保持x1>=x0
if (p0.x > p1.x) {
[x0, y0]=[Math.round(p1.x), Math.round(p1.y)];
[x1, y1]=[Math.round(p0.x), Math.round(p0.y)];
} else {
[x0, y0]=[Math.round(p0.x), Math.round(p0.y)];
[x1, y1]=[Math.round(p1.x), Math.round(p1.y)];
}
let m=(y1-y0)/(x1-x0);
// 直线方程
let f=(x,y)=> (y0-y1)*x + (x1-x0)*y + x0*y1 - x1*y0;
// 区间(0,1]
if (m > 0 && m <=1) {
let y=y0;
for (let x=x0; x < x1; x++) {
this.setPixel(x, y, color);
if (f(x+1, y+0.5) < 0) {
y +=1;
}
}
}
// 区间(1,正无穷)
else if (m > 1) {
let x=x0;
for (let y=y0; y < y1; y++) {
this.setPixel(x, y, color);
if (f(x+0.5, y+1) > 0) {
x +=1;
}
}
}
// 区间(-1,0]
else if (m > -1 && m <=0) {
let y=y0;
for (let x=x0; x < x1; x++) {
this.setPixel(x, y, color);
if (f(x+1, y-0.5) > 0) {
y -=1;
}
}
}
// 区间(负无穷,-1]
else if (m <=-1) {
let x=x0;
for (let y=y0; y > y1; y--) {
this.setPixel(x, y, color);
if (f(x+0.5, y-1) < 0) {
x +=1;
}
}
}
}
// (1,+∞)
drawLine({x: 300, y: 590}, {x: 480, y: 190}, 'rgba(255, 0, 0, 1.0)');
// (-1,0]
drawLine({x: 300, y: 400}, {x: 480, y: 380}, 'rgba(255, 255, 0, 1.0)');
// (0,1]
drawLine({x: 300, y: 380}, {x: 480, y: 400}, 'rgba(0, 0, 255, 1.0)');
// (-∞,-1]
drawLine({x: 300, y: 190}, {x: 480, y: 590}, 'rgba(0, 255, 0, 1.0)');
[1]. 《fundamentals of computer graphics》9.1.1 line drawing, p179.
1)字体的属性
字体属性用于定义字体的类型、字号大小、加粗、斜体等方面样式。常用的字体属性如下表所示:
属 性 | 可 取 值 | 描 述 |
font | font-style、font-variant、font-weight、font-size(或 line-height)、font-family | 在一个声明中设置所有的字体属性 |
font-family | 字体名称、inherit | 设置字体类型 |
font-size | xx-small、x-small、small、medium(默认)、large、x-large、xx-large smaller、larger length、%、inherit | 设置字体大小 |
font-weight | normal(默认)、bold、bolder、lighter、inherit 100、200…900(400=normal,700=bold) | 设置字体粗细 |
font-style | normal、italic、oblique、inherit | 设置字体风格 |
例子,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
h3 {
font-size: 20px;
font-family: 隶书;
line-height: 28px;
}
span {
font: italic 16px 华文彩云;
}
</style>
</head>
<body>
<h3>Web 前端技术</h3>
<span
>在当今社会中,Web 已经成为网络信息共享和发布的主要形式。要想开发 Web 应用
系统,就必须掌握 Web 前端技术。</span
>
</body>
</html>
显示为,
(2)CSS 中链接标签可用的伪类:
CSS 中,伪类是添加到选择器的关键字,给指定元素设置一些特殊状态,我们以 : 开头。
链接有以下四个状态。这四种状态也称之为超链接的伪类。
状态 | 效果 |
a:link | 普通的、未被访问的链接。 |
a:hover | 鼠标指针位于链接的上方。 |
a:active | 链接被单击的时刻。 |
a:visited | 用户已访问的链接。 |
针对超链接的上述四种状态设置样式规则,能起到美化超链接的作用。例如,为了完成下对超链接的显示要求,编写的 CSS 样式代码如下。
状 态 | 颜 色 | 背 景 色 | 文 本 修 饰 |
未访问 | 蓝色 | 无 | 无下画线 |
鼠标移到 | 黑色 | #DDDDDD | 下画线 |
正单击 | 红色 | #AAAAAA | 删除线 |
已访问 | 绿色 | 无 | 无下画线 |
对于超链接的伪类,我们推荐的使用顺序是::link - :visited - :hover - :active。
例子,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
text-decoration: none;
}
a:link {
color: red;
}
a:visited {
color: blue;
}
a:hover {
color: green;
}
a:active {
color: yellow;
}
</style>
</head>
<body>
<a href="#">这是一个链接</a>
</body>
</html>
显示为,
为什么要按照这样的顺序来使用呢? 调整几个伪类的顺序,看看会发生什么。
我们把 a:link 放到最后,效果如下:
从图中可以发现其中的样式属性都被覆盖了。
(3)列表相关的样式属性:
属 性 | 可 取 值 | 描 述 |
list-style | list-style-type、list-style-position、list-style-image | 在一个声明中设置所有的列表属性 |
list-style-image | URL、none | 设置图像为列表项标志 |
list-style-position | inside、outside、inherit | 设置列表中列表项标志的位置 |
list-style-type | disc(默认)、circle、square、decimal 等 | 设置列表项标志的类型 |
例子,
wget https://labfile.oss.aliyuncs.com/courses/2841/list.gif
ext-decoration属性介绍#
text-decoration属性值说明表#
值作用none去掉文本修饰线underline设置下划线overline设置上划线line-through设置删除线
HTML标签自带修饰线#
u标签#
Copy<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>设置文本修饰线</title> </head> <body> <u>成功不是击败别人,而是改变自己</u> </body> </html>
*请认真填写需求信息,我们会在24小时内与您取得联系。