二维码

图形开发学院(GraphAnywhere.com)

第八章 图形样式

1. 填充和描边

  在图形系统实战—基础篇中,我们已经学习了绘制几何图形时,可以通过渲染上下文对象的strokeStylefillStyle两个属性指定几何图形边框效果和填充效果,而且这两个属性均可设置颜色、渐变、图案三种渲染效果。本文将进一步讲解这三种渲染效果的更多技术。

1.1 颜色

  在图形开发中,色彩的运用是非常重要的,它能直接影响到图形的美观度和用户体验。 WEB网页 和 Canvas图形均采用 HTML颜色 作为颜色应用的基础。

  HTML颜色 由红色、绿色、蓝色混合而成,其颜色值由一个十六进制符号来定义,这个符号由红色、绿色和蓝色的值组成(RGB)。各颜色的最小值是0(十六进制:#00)。最大值是255(十六进制:#FF)。三种颜色 红,绿,蓝的组合从0到255,一共可表达1600万种不同颜色(256 x 256 x 256)。

  除了颜色值之外,HTML颜色 还可通过 透明度 描述元素的可见程度,可以用来实现层次感、透视效果等。具体来说透明度是通过RGBA颜色模式中的 Alpha 值来控制的。

  在使用 HTML 颜色时可采用HEX、RGB、RGBA、HSL和HSLA等几种格式。

十六进制格式 (Hex格式)

十六进制颜色格式为:#RRGGBB

  • 十六进制颜色值必须带有前导“#”字符。
  • 其中RR(红色)、GG(绿色)和 BB(蓝色)是介于 00 和 FF 之间的十六进制整数,用于指定颜色的强度。例如,#FF0000显示为红色,因为红色被设置为其最高值(FF),而其他两个(绿色和蓝色)被设置为00。#00FF00显示为绿色,因为绿色被设置为其最高值(FF),而其他两个(红色和蓝色)被设置为00。
  • 要显示黑色,所有颜色参数设置为00,如下所示:#000000。
  • 要显示白色,所有颜色参数设置为FF,如下所示:#FFFFFF。
透明度

  在十六进制表示法中,颜色的透明度由两位十六进制数表示,取值范围为00到FF。其中,00表示完全透明,FF表示完全不透明。例如,#FF0000表示红色不透明,#FF000080表示红色半透明。

  可通过正则表达式判断是否为一个有效的十六进制颜色值,其代码如下:

1
2
3
4
5
6
7
function isValidateHex(color) {
if (color.startsWith('#')) {
// 首字符为#,颜色值必须为3/4/6/8个字符
let pattern = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;
return pattern.test(color);
}
}

RGB格式

RGB颜色格式为:rgb(red, green, blue)

  • 各个参数(红色、绿色和蓝色)定义的颜色强度值在0到255之间。例如rgb(255,0,0)显示为红色,因为红色被设置为其最高值(255),而其他两个(绿色和蓝色)被设置为0。rgb(0,255,0)显示为绿色,因为绿色被设置为其最高值(255),而其他两个(红色和蓝色)被设置为0。
  • 若要显示黑色,所有颜色参数设置为0,如下所示:rgb(0,0,0)。
  • 若要显示白色,所有颜色参数设置为255,如下所示:rgb(255,255,255)。
透明度

  对应于RGB颜色格式,包含透明度的格式为:rgba(red, green, blue, alpha)

  rgba颜色值是具有Alpha通道的rgb颜色值的扩展,alpha通道指定颜色的不透明度。alpha 值为从0到1的十进制数,其中0表示完全透明,1表示完全不透明。例如,rgba(255, 0, 0, 1)表示红色不透明,rgba(255, 0, 0, 0.5)表示红色半透明。

  可通过正则表达式判断是否为一个有效的RGB颜色值,其代码如下:

1
2
3
4
5
6
function isValidateRGB(color) {
if (color.toLowerCase().startsWith('rgb')) {
let pattern = /^rgba?\(\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*(?:\s*,\s*((?:\d*\.?\d+)?)\s*)?\)$/i;
return pattern.test(color);
}
}

内置颜色名称

  HTML支持140个颜色名,这其中包括了HTML4就开始支持的16个颜色名。注意这些关键字虽然不区分大小写,但此处为了可读性以混合的大小写列出。下表列出这140个颜色:

英文颜色名 中文颜色名 RGB值 十六进制值 颜色展示
Black 黑色 rgb(0,0,0) #000000
Navy 深蓝色 rgb(0,0,128) #000080
DarkBlue 深蓝色、暗蓝色 rgb(0,0,139) #00008B
MediumBlue 间蓝色、中蓝色 rgb(0,0,205) #0000CD
Blue 蓝色 rgb(0,0,255) #0000FF
DarkGreen 暗绿色、青绿色 rgb(0,100,0) #006400
Green 绿色 rgb(0,128,0) #008000
Teal 水鸭色、青色 rgb(0,128,128) #008080
DarkCyan 暗青色、深青色 rgb(0,139,139) #008B8B
DeepSkyBlue 深天蓝色 rgb(0,191,255) #00BFFF
DarkTurquoise 暗宝石绿色 rgb(0,206,209) #00CED1
MediumSpringGreen 中春绿色、间嫩绿色 rgb(0,250, 154) #00FA9A
Lime 酸橙色 rgb(0,255,00) #00FF00
SpringGreen 嫩绿色、春绿色 rgb(0,255,127) #00FF7F
Aqua 浅绿色、青色 rgb(0,255,255) #00FFFF
Cyan 青色、浅绿色 rgb(0,255,255) #00FFFF
MidnightBlue 中灰蓝色 rgb(25,25,112) #191970
DodgerBlue 闪蓝色 rgb(30,144,255) #1E90FF
LightSeaGreen 亮海蓝色、亮海绿色 rgb(32,178,170) #20B2AA
ForestGreen 森林绿色 rgb(34,139,34) #228B22
SeaGreen 海绿色、海藻色 rgb(46,139,87) #2E8B57
DarkSlateGray 暗瓦灰色 rgb(47,79,79) #2F4F4F
LimeGreen 橙绿色 rgb(50,205,50) #32CD32
MediumSeaGreen 中海蓝色、间海绿色 rgb(60,179,113) #3CB371
Turquoise 青绿色、绿松石色 rgb(64,224,208) #40E0D0
RoyalBlue 皇家蓝色、宝蓝色 rgb(65,105,225) #4169E1
SteelBlue 钢蓝色、钢铁蓝色 rgb(70,130,180) #4682B4
DarkSlateBlue 暗灰蓝色、深灰蓝色 rgb(72,61,139) #483D8B
MediumTurquoise 中绿宝石色、暗粉蓝色 rgb(72,209,204) #48D1CC
Indigo 靛蓝色、靛蓝色 rgb(75,0,130) #4B0082
DarkOliveGreen 暗橄榄绿色、深橄榄绿色 rgb(85,107,47) #556B2F
CadetBlue 军蓝色 rgb(95,158,160) #5F9EA0
CornflowerBlue 菊蓝色、矢车菊蓝色 rgb(100,149,237) #6495ED
MediumAquaMarine 间绿色、中绿色 rgb(102,205,170) #66CDAA
DimGray 暗灰色 rgb(105,105,105) #696969
SlateBlue 石蓝色、石板蓝色、岩蓝色、石青色 rgb(106,90,205) #6A5ACD
OliveDrab 深绿褐色 rgb(107,142,35) #6B8E23
SlateGray 灰石色 rgb(112,128,144) #708090
LightSlateGray 亮蓝灰色 rgb(119,136,153) #778899
MediumSlateBlue 中暗蓝色 rgb(123,104,238) #7B68EE
LawnGreen 草绿色 rgb(124,252,0) #7CFC00
Chartreuse 黄绿色 rgb(127,255,0) #7FFF00
Aquamarine 碧绿色 rgb(127,255,212) #7FFFD4
Maroon 栗色 rgb(128,0,0) #800000
Purple 紫色 rgb(128,0,128) #800080
Olive 橄榄色 rgb(128,128,0) #808000
Gray 灰色 rgb(128,128,128) #808080
SkyBlue 天蓝色 rgb(135,206,235) #87CEEB
LightSkyBlue 亮天蓝色 rgb(135,206,250) #87CEFA
BlueViolet 紫罗兰色 rgb(138,43,226) #8A2BE2
DarkRed 暗红色 rgb(139,0,0) #8B0000
DarkMagenta 暗洋红色 rgb(139,0,139) #8B008B
SaddleBrown 重褐色 rgb(139,69,19) #8B4513
DarkSeaGreen 暗海蓝色 rgb(143,188,143) #8FBC8F
LightGreen 亮绿色 rgb(144,238,144) #90EE90
MediumPurple 中紫色 rgb(147,112,219) #9370DB
DarkViolet 暗紫罗兰色 rgb(148,0,211) #9400D3
PaleGreen 苍绿色 rgb(152,251,152) #98FB98
DarkOrchid 暗紫色 rgb(153,50,204) #9932CC
YellowGreen 黄绿色 rgb(154,205,50) #9ACD32
Sienna 赭色 rgb(160,80,45) #A0522D
Brown 褐色 rgb(165,42,42) #A52A2A
DarkGray 暗灰色 rgb(169,169,169) #A9A9A9
LightBlue 亮蓝色 rgb(173,216,230) #ADD8E6
GreenYellow 黄绿色 rgb(173,255,47) #ADFF2F
PaleTurquoise 苍宝石绿色 rgb(175,239,239) #AFEEEE
LightSteelBlue 亮钢蓝色 rgb(176,196,222) #B0C4DE
PowderBlue 粉蓝色 rgb(176,224,230) #B0E0E6
FireBrick 火砖色 rgb(178,34,34) #B22222
DarkGoldenRod 暗金黄色 rgb(184,134,11) #B8860B
MediumOrchid 中粉紫色 rgb(186,85,211) #BA55D3
RosyBrown 褐玫瑰色 rgb(188,143,143) #BC8F8F
DarkKhaki 暗黄褐色 rgb(189,183,107) #BDB76B
Silver 银色 rgb(192,192,192) #C0C0C0
MediumVioletRed 中紫罗兰色 rgb(199,21,133) #C71585
IndianRed 印第安红 rgb(205,92,92) #CD5C5C
Peru 秘鲁色 rgb(205,133,63) #CD853F
Chocolate 巧克力色 rgb(210,105,30) #D2691E
Tan 茶色 rgb(210,180,140) #D2B48C
LightGray 亮灰色 rgb(211,211,211) #D3D3D3
Thistle 蓟色 rgb(216,191,216) #D8BFD8
Orchid 淡紫色 rgb(218,112,214) #DA70D6
GoldenRod 金麒麟色 rgb(218,165,32) #DAA520
PaleVioletRed 苍紫罗兰色 rgb(219,112,147) #DB7093
Crimson 暗深红色 rgb(220,20,60) #DC143C
Gainsboro 淡灰色 rgb(220,220,220) #DCDCDC
Plum 洋李色 rgb(221,160,221) #DDA0DD
BurlyWood 实木色 rgb(222,184,135) #DEB887
LightCyan 亮青色 rgb(224,255,255) #E0FFFF
Lavender 淡紫色 rgb(230,230,250) #E6E6FA
DarkSalmon 暗肉色 rgb(233,198,122) #E9967A
Violet 紫罗兰色 rgb(238,130,170) #EE82AA
PaleGoldenRod 苍麒麟色 rgb(238,232,170) #EEE8AA
LightCoral 亮珊瑚色 rgb(240,128,128) #F08080
Khaki 黄褐色 rgb(240,230,141) #F0E68C
AliceBlue 艾利斯蓝色 rgb(240,248,255) #F0F8FF
HoneyDew 蜜色 rgb(240,255,240) #F0FFF0
Azure 天蓝色 rgb(240,255,255) #F0FFFF
SandyBrown 沙褐色 rgb(244,164,96) #F4A460
Wheat 浅黄色 rgb(245,222,179) #F5DEB3
Beige 米色 rgb(245,245,220) #F5F5DC
WhiteSmoke 烟白色 rgb(245,245,245) #F5F5F5
MintCream 薄荷色 rgb(245,255,250) #F5FFFA
GhostWhite 幽灵白色 rgb(250,250,255) #FAFAFF
Salmon 鲜肉色 rgb(250,128,114) #FA8072
AntiqueWhite 古董白色 rgb(250,235,215) #FAEBD7
Linen 亚麻色 rgb(250,240,230) #FAF0E6
LightGoldenRodYellow 亮金黄色 rgb(250,250,210) #FAFAD2
OldLace 老花色 rgb(253,254,86) #FDFE56
Red 红色 rgb(255,0,0) #FF0000
Fuchsia 紫红色、红紫色 rgb(255,0,255) #FF00FF
Magenta 红紫色、紫红色 rgb(255,0,255) #FF00FF
DeepPink 深粉红色 rgb(255,20,147) #FF1493
OrangeRed 红橙色 rgb(255,69,0) #FF4500
Tomato 西红柿色、番茄色 rgb(255,99,71) #FF6347
HotPink 热粉红色 rgb(255,105,180) #FF69B4
Coral 珊瑚色 rgb(255,127,80) #FF7F50
DarkOrange 暗桔黄色 rgb(255,140,0) #FF8C00
LightSalmon 亮肉色 rgb(255,160,122) #FFA07A
Orange 橙色、橘色 rgb(255,165,0) #FFA500
LightPink 亮粉红色 rgb(255,182,193) #FFB6C1
Pink 粉色、粉红色 rgb(255,192,203) #FFC0CB
Gold 金色 rgb(255,215,0) #FFD700
PeachPuff 桃色 rgb(255,218,185) #FFDAB9
NavajoWhite 纳瓦白色 rgb(255,222,173) #FFDEAD
Moccasin 鹿皮色 rgb(255,228,181) #FFE4B5
Bisque 桔黄色 rgb(255,228,196) #FFE4C4
MistyRose 浅玫瑰色 rgb(255,228,225) #FFE4E1
BlanchedAlmond 白杏色 rgb(255,235,205) #FFEBCD
PapayaWhip 番木色 rgb(255,239,213) #FFEFD5
LavenderBlush 淡紫色 rgb(255,240,245) #FFF0F5
SeaShell 海贝色 rgb(255,245,238) #FFF5EE
Cornsilk 米绸色 rgb(255,248,220) #FFF8DC
LemonChiffon 柠檬色、柠檬绸色 rgb(255,250,205) #FFFACD
FloralWhite 花白色 rgb(255,250,240) #FFFAF0
Snow 雪白色 rgb(255,250,250) #FFFAFA
Yellow 黄色 rgb(255,255,0) #FFFF00
LightYellow 亮黄色 rgb(255,255,224) #FFFFE0
Ivory 象牙色、象牙白色 rgb(255,255,240) #FFFFF0
White 白色 rgb(255,255,255) #FFFFFF

HSL(色相、饱和度、亮度)

HSL代表hue(色调)、saturation(饱和度)和lightness(亮度)。

  • 色相指图像的相对明暗程度,也称之为色调,是色轮上从0到360的度数。0(或360)为红色,120为绿色,240为蓝色
  • 饱和度可以描述为色彩的鲜艳程度。它是一个从0%到100%的百分比值。
    • 100%是全彩,没有灰色阴影。
    • 50%是50%的灰色,但你仍然可以看到颜色。
    • 0%为完全灰色;你再也看不到颜色了。
  • 亮度指色彩的明暗差异,可以描述为你想给颜色多少光,其中0%表示没有光(暗),50%表示50%光(既不暗也不亮),100%表示全光。

其格式为:hsl(hue, saturation, lightness),如下所示:

1
2
3
{"color":"hsl(0, 100%, 50%)"}
{"color":"hsl(120, 100%, 50%)"}
{"color":"hsl(240, 100%, 50%)"}

注意:Edge、Chrome、Firefox、Safari、Opera 10+和IE9+支持HSL颜色值。

透明度

  HSLA颜色值是HSL颜色值的扩展,具有Alpha通道,用于指定颜色的不透明度。alpha参数是介于0.0(完全透明)和1.0(完全不透明)之间的数字:

  其格式为:hsla(hue, saturation, lightness, alpha),如下所示:

1
2
3
4
{"color":"hsla(0, 100%, 50%, 0.2)"}
{"color":"hsla(0, 100%, 50%, 0.4)"}
{"color":"hsla(0, 100%, 50%, 0.6)"}
{"color":"hsla(0, 100%, 50%, 0.8)"}

以下代码可判断是否为一个有效的颜色值:

1
2
3
4
5
6
function isValidateHSL(color) {
if (color.toLowerCase().startsWith('hsl')) {
let pattern = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/i;
return pattern.test(color);
}
}

ColorUtil工具类

  AnyGraph 提供了一个通用的Color工具类,提供了将上述各种颜色格式转换为Color类型格式的功能,也提供了将 Color类型格式转换为上述各种颜色格式的功能,还提供了生成随机色,生成色带等功能,其方面名称如下表所示:

名称 说明
toRgb() 转换为rgb()字符串颜色值
toHex() 转换为16进制字符串颜色值
toHSL() 转换为HSL颜色对象
toHSV() 转换为HSV颜色对象
toHSB() 转换为HSB颜色对象
static fromHex(hex) 将16进制颜色字符串 转换为Color对象
static fromString(str) 将字符串颜色转换为Color对象
static fromHSL (hslColor) 将HSL的字符串颜色转换为Color对象
static isValidColor(color) 判断一个颜色值是否合法
static random() 生成随机色
static band(color, count) 生成色带

  下面这些代码展示了 Color 类中的类型转换功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

console.info(Color.fromString("#FFF").toString());
// return: rgb(255,255,255)

console.info(Color.fromString("#FFFFFFDF").toString());
// return: rgba(255,255,255,0.87)

let red = Color.fromString("red")
console.info(red.toHSL());
// return: {H: 0, S: 1, L: 1}

console.info(red.toHSB());
// return: {h: 0, s: 1, b: 1}

console.info(red.toHSV());
// return: {h: 0, s: 1, v: 255}

console.info(red.toHex());
// return: #ff0000

console.info(red.toRgb());
// return: rgb(255,0,0)

  Color 类中包含了一个静态方法 band(color, count),该方法可生成指定颜色的色带值。下图为生成的 deeppink 色带。

运行效果

1.2 渐变效果

  在 图形系统开发实战课程-基础篇 第五章 渲染效果 中我们详细讲解了 Canvas 所提供渐变效果功能。渐变风格包括 “线性渐变”和“径向渐变”两种不同的风格, 这里我们简单回顾一下。

线性渐变

  线性渐变是一种颜色过渡方式,它以一条直线(水平或垂直)为轴线,从起点到终点颜色进行顺序渐变。渲染上下文对象提供了建立线性渐变的方法,其定义如下:

1
CanvasGradient ctx.createLinearGradient(x0, y0, x1, y1);
参数 说明
x0 起点的 x 轴坐标
y0 起点的 y 轴坐标
x1 终点的 x 轴坐标
y1 终点的 y 轴坐标

  该方法的返回值是一个CanvasGradient对象,将该对象直接赋值给 ctx.fillStyle 属性 或 ctx.strokeStyle 属性,即可在图形中实现渐变效果。该对象还包含了一个方法,用于添加一个由偏移值和颜色值指定的 断点 到渐变对象中,API如下:

1
void gradient.addColorStop(offset, color);
参数 说明
offset 偏移位置,0到1之间的值
color 颜色值

径向渐变

  径向渐变是指从起点到终点颜色从内到外进行圆形渐变(从中间向外拉)。渲染上下文对象提供了建立径向渐变的方法,其定义如下:

1
CanvasGradient ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
参数 说明
x0 开始圆形的 x 轴坐标
y0 开始圆形的 y 轴坐标
r0 开始圆形的半径
x1 结束圆形的 x 轴坐标
y1 结束圆形的 y 轴坐标
r1 结束圆形的半径

  该方法的返回值是一个CanvasGradient对象,该对象包含了方法addColorStop()与线性渐变的该方法完全一样。

AnyGraph 中的实现

  从上面这两类渐变的API中可以看出,创建渐变对象时需指定渐变位置。这对于静态图形而言没什么问题,而对于具体图形交互(平移和缩放) 功能的动态图形而言,位置信息是会随着图形的平移和缩放而发生改变的,因此我们不能在创建图形对象的时候就创建渐变对象,而应该是在渲染的时候创建渐变对象,且在图形对象平移或缩放的过程中,同步计算渐变对象的位置信息。

  为此 AnyGraph 设计了渐变对象类 Gradient。我们通过一个具体样例来说明 Gradient的设计,运行效果图如下:

运行效果

  这是一个展示矩形线性渐变的示例,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

let colorSet = ["red", "orange", "gold", "green", "black", "blue"];
let width = 180;
let height = 120;

for (let x = 40; x < 800; x += width + 20) {
for (let y = 40; y < 400; y += height + 20) {
let color = colorSet[MathUtil.getRandomNum(0, colorSet.length - 1)];
let colorBand = Color.band(color, 10);

// 渐变对象
let gradient = new Gradient({
"type": "linear",
"coords": { "x1": x, "y1": y, "x2": x + width, "y2": y },
"colorStops": [{
"offset": "0.1",
"color": colorBand[2]
}, {
"offset": "0.95",
"color": colorBand[6]
}]
});

layer.getSource().add(new Rect({
x, y, width, height, "style": { "fillColor": gradient, "fillStyle": 1, "color": "none" }
}));
}
}

  通过代码不难发现,在创建 Rect 矩形对象之前创建了 Gradient渐变对象,该对象的坐标与矩形对象一致,通过type属性指定为线性渐变,通过 colorStops 属性为渐变对象设定了 断点 。在创建 Rect 矩形对象时,通过该对象的style属性的fillColor 属性将该渐变对象赋值到了矩形对象中。

  这样就完成了为矩形对象指定渐变效果,在渲染 Rect 对象时,将会在执行 toPixel() 方法时同步为 Gradient 渐变对象计算像素坐标,在执行 draw() 方法时通过渲染上下文对象的createLinearGradient()createRadialGradient() API 实现渐变效果。

  渐变效果在图形系统中有着广泛的应用。

  • 色彩过渡:实现色彩之间的平滑过渡,使图像或画面的色彩更加自然和协调;
  • 质感模拟:模拟出各种自然或非自然的质感,为设计作品增加更多的层次和细节;
  • 视觉引导:引导用户的视觉焦点将用户的注意力引向特定的区域或元素等方面;
  • 动态效果:渐变效果也可以用于实现动态的视觉效果。例如,在制作动画或动态背景时,可以使用渐变效果来创造出更加自然和流畅的运动轨迹。

  下面这张图是使用 AnyGraph 装载两个SVG文件,并使用渐变效果渲染图形,实现模拟真实世界的光照效果。

运行效果

1.3 填充图案/纹理

  渲染上下文对象提供了创建图案/纹理对象的方法createPattern(),其定义如下:

1
CanvasPattern ctx.createPattern(image, repetition);
参数 说明
image 填充图案源
repetition 重复方式
  • 填充图案源可以是位图、也可以是的画布对象
  • 重复方式包括:
    • “repeat” :水平和垂直方向均重复
    • “repeat-x” :仅水平方向重复
    • “repeat-y” :仅垂直方向重复
    • “no-repeat” :不重复
      默认值是:repeat

  绘制几何图形时,通过渲染上下文对象的strokeStylefillStyle两个属性指定几何图形边框效果和填充效果,而且这两个属性除了可以 使用颜色渐变对象 外,还可以指定为 图案/纹理对象

AnyGraph 中的实现

  和渐变的实现方式类似,AnyGraph 提供了Pattern类,可直接将该对象赋值给图形对象 style 属性的 fillColor 属性或 color 属性。

  下面这个示例,使用图案/纹理对象填充了文字,其运行效果和源代码分别如下:

运行效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// graph对象
let graph = new Graph({
"target": "graphWrapper"
});

// 新建绘图图层
let layer = graph.addLayer();
let image = new ImageObject("./images/bg_06.jpg", function(){
let pattern = new Pattern({ "type": "image", "image": image });
layer.getSource().add(new Text({
"text": "图形开发",
"x": graph.getSize().width / 2,
"y": graph.getSize().height / 2,
"style": { "lineWidth": 4, "fillStyle": 0, "fillColor": pattern, "fontSize": 200, "fontName": "黑体", "textAlign": "center", "textBaseline": "middle" }
}));
});

2. 透明度

  Canvas 渲染上下文对象提供了通过颜色值设置图形对象的透明度和为画布指定透明度两种方式设置颜色的透明度。

2.1 通过颜色值设置透明度

  在本章的1.1颜色部分介绍了 HTML颜色 ,常见的设置颜色的方式有:

  • 十六进制格式
  • RGB格式
  • 内置颜色名称
  • HSL格式

  除了内置颜色名称不能指定透明度外,其他三种方式均可以指定透明度。下面这个示例将绘制一个透明度为60%的红色矩形。

1
2
3
4
5
// 开始绘制路径
ctx.beginPath();
ctx.rect(50, 40, 200, 100);
ctx.fillStyle = "rgba(255,0,0,0.6)"; // Alpha:0.6
ctx.fill();

2.2 通过 globalAlpha 设置透明度

  Canvas渲染上下文对象提供了 globalAlpha属性, 该属性为在 canvas 绘图时设置图形和图像透明度的属性。

  下面这个示例在fill() 之前设置了 ctx.globalAlpha = 0.6;,其绘制的结果与上面那个示例运行的结果完全一样。

1
2
3
4
5
6
7
8
// 开始绘制路径
ctx.save();
ctx.beginPath();
ctx.rect(50, 40, 200, 100);
ctx.fillStyle = "rgb(255,0,0)";
ctx.globalAlpha = 0.6; // Alpha:0.6
ctx.fill();
ctx.restore();

  globalAlpha 属性同样也是可以通过 ctx.save()和ctx.restore()保存与恢复的。关于状态保存方面的内容请参见:图形系统开发实战-基础篇:第六章:画布操作

  globalAlpha 数值的范围从 0.0(完全透明)到 1.0(完全不透明)。该属性不仅仅可以指定绘制图形的透明度,也可以指定绘制图像的透明度。下图是设置了 ctx.globalAlpha = 0.4 的运行效果。

运行效果

2.3 AnyGraph中的实现

  AnyGraph 中除了可以支持通过图形对象样式指定颜色透明度和globalAlpha透明度之外,还可以设置图层的透明度。

颜色透明度

  采用颜色透明度绘制图像比较简单,仅需在指定图形对象颜色的时候赋予颜色透明值即可。

globalAlpha 透明度

  globalAlpha 透明度也是通过对象的style 属性中指定的,其属性名为 opacity

1
2
3
4
5
6
7
8
9
10
// 绘制图像
let image = new Image({
"x": 50,
"y": 50,
"width": 500,
"height": 450,
"style": { "opacity": 0.4 },
"src": "./images/ma.png"
});
layer.getSource().add(image);

图层透明度

  本课程 第二章:图形管理类 中我们讲述过的图形渲染思路是:各个图层分别对应独立的Canvas画布,在画布中渲染各自图层中的数据,最后按图层顺序将各图层合并为完整的图形。

  在这个思路的之上,图层透明度的实现就很简单了。在将各图层合并为完整的图形的时候,采用的是 ctx.drawImage() 方式,按照刚刚讲述的 globalAlpha 用法, 在执行 ctx.drawImage() 设置 globalAlpha 透明值,即可实现图层的透明控制。

  Layer图层类提供了 setOpacity(opacity)getOpacity() 两个方法可设置和获取图层透明度,opacity 的取值范围仍旧是 0 ~ 1。下面这个示例演示图层透明度的功能。运行效果如下:

运行效果

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script type="module">
import { Graph, VectorSource, Layer, SvgFormat, debug } from "../../../src/index.js";

let layer1 = new Layer({
"name": "篮球",
"source": new VectorSource({
"dataType": "xml",
"fileUrl": "./images/basketball1.svg",
"format": new SvgFormat()
})
});
let layer2 = new Layer({
"name": "足球",
"source": new VectorSource({
"dataType": "xml",
"fileUrl": "./images/football2.svg",
"format": new SvgFormat()
})
});

// graph对象
let graph = new Graph({
"target": "graphWrapper",
"layers": [layer1, layer2],
});

// 图层1透明度控制
let slideBar1 = document.getElementById("slideBar1");
slideBar1.addEventListener("change", function (e) {
layer1.setOpacity(this.value / 100);
graph.render();
})

// 图层2透明度控制
let slideBar2 = document.getElementById("slideBar2");
slideBar2.addEventListener("change", function (e) {
layer2.setOpacity(this.value / 100);
graph.render();
})
</script>

3. 阴影

Canvas 渲染上下文对象提供了以下几个和阴影效果有关的属性。

属性 说明
shadowBlur 描述模糊效果程度的,float 类型的值。
shadowColor 可以转换成 CSS 值的DOMString 字符串。
shadowOffsetX 阴影水平偏移距离的 float 类型的值。默认值是 0。
shadowOffsetY 阴影垂直偏移距离的 float 类型的值。默认值是 0。

  关于这部分内容的讲解请参见:图形系统开发实战-基础篇:第五章:渲染效果

3.1 AnyGraph中的实现

  图形对象 Geometry 类的 Sytle 对象中包含了与Canvas 渲染上下文对象阴影属性对应的属性,如下表所示:

参数 说明
shadowBlur 模糊效果程度
shadowColor 模糊颜色
shadowOffsetX 阴影水平偏移距离
shadowOffsetY 阴影垂直偏移距离

下面这个示例演示为图形对象设置阴影效果。运行效果如下:

运行效果

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let colorSet = ["red", "orange", "gold", "green", "black", "blue"];
let radius = 60;
for (let x = 100; x < 800; x += radius * 2.5) {
for (let y = 100; y < 500; y += radius * 2.5) {
let color = colorSet[MathUtil.getRandomNum(0, colorSet.length - 1)];
let colorBand = Color.band(color, 10);

// 渐变对象
let gradient = new Gradient({
"type": "radial",
"coords": { "x1": x + radius / 2, "y1": y + radius / 2, "r1": 0, "x2": x, "y2": y, "r2": radius },
"colorStops": [{
"offset": "0.1",
"color": colorBand[2],
}, {
"offset": "0.95",
"color": colorBand[7]
}]
});
// 圆
layer.getSource().add(new Circle({
x, y, radius,
"style": {
"fillColor": gradient,
"fillStyle": 1,
"color": "none",
"shadowOffsetX": MathUtil.getRandomNum(3, 8),
"shadowOffsetY": MathUtil.getRandomNum(2, 5),
"shadowBlur": 30,
"shadowColor": colorBand[8]
}
}));
}
}


  “图形系统实战开发-进阶篇 第八章 图形样式” 的内容讲解到这里就结束了,如果觉得对你有帮助有收获,可以关注我们的官方账号,持续关注更多精彩内容。


本文为“图形开发学院”(graphanywhere.com)网站原创文章,遵循CC BY-NC-ND 4.0版权协议,商业转载请联系作者获得授权,非商业转载请附上原文出处链接及本声明。