WebGL Tutorial
and more

绘制图形

撰写时间:2024-03-22

修订时间:2025-04-11

矩形

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 5, 10, 5, true, true); g.drawRect(Rect(2, 10, 2, 2)); g.drawRect(Rect(2, 4, 3, 2), 'cyan'); // border color g.fillRect(Rect(10, 8, 3, 2)); g.fillRect(Rect(10, 4, 3, 2), 'palevioletred'); // filled color g.fillRect(Rect(16, 4, 3, 2), 'yellowgreen', 'oldlace'); // filled and border color

绘制图形的方法都有draw...fill...两个版本。其中,draw...方法有默认参数color用于指定边框颜色。fill...方法有默认参数fillColor用于指定填充颜色以及默认参数bdColor用于指定边框颜色。 这些方法的代码,分别引用了geoGrpSHAPE_BORDER_COLOR属性及SHAPE_FILL_COLOR属性。geoGrp有以下通用属性:

属性名作用默认值
SHAPE_BORDER_COLOR图形边框颜色"gray"
SHAPE_STROKE_COLOR图形描边颜色"gray"
SHAPE_FILL_COLOR图形填充颜色"gray"
TEXT_STROKE_COLOR文本颜色"gray"
TEXT_FILL_COLOR文本填充颜色"gray"

这些属性值可在全局范围内修改。例如,若设置:

g.SHAPE_STROKE_COLOR = 'white';

则所有的图形描边颜色都将变为白色,从而适合在暗黑模式下使用。

圆角矩形

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); g.drawRoundRect(Rect(1, 9, 5, 3), 0.5); g.drawRoundRect(Rect(8, 9, 5, 3), [0.2, 0.5], 'cyan'); g.fillRoundRect(Rect(1, 5, 5, 3), [0.5], 'hsl(230, 35%, 35%)'); g.fillRoundRect(Rect(8, 5, 5, 3), [0.5, 0.2], 'hsl(180, 25%, 25%)', 'yellow');

因参数不多,且容易理解,故这两个方法均不设置可选的options参数,部分参数带有默认值:

undefineddrawRoundRect
  • Rectrect
  • Number | Number[]radius
  • Stringcolor = this.SHAPE_STROKE_COLOR
undefinedfillRoundRect
  • Rectrect
  • Number | Number[]radius
  • StringfillColor = this.SHAPE_FILL_COLOR
  • StringbdColor = this.SHAPE_BORDER_COLOR

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); g.drawCircle(Circle(Point(6, 6), 3)); g.fillCircle(Circle(Point(14, 6), 3), 'hsl(220, 25%, 25%)');

正多边形

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 20, 5, false); var orgPoint = Point(1, 18); var radius = 2; var horzGap = 3.5; var vertGap = 4.8; var options = { polygonColor: 'white' }; for (let i = 0; i < 6; i++, orgPoint.x += horzGap) { var sides = i + 3; g.drawRegularPolygon(Circle(orgPoint, radius), sides, options); } orgPoint.x = 1; orgPoint.y -= vertGap; options.isDrawAroundedCircle = true; for (let i = 0; i < 6; i++, orgPoint.x += horzGap) { var sides = i + 3; g.drawRegularPolygon(Circle(orgPoint, radius), sides, options); } orgPoint.x = 1; orgPoint.y -= vertGap; options.isDrawConnectedLines = true; for (let i = 0; i < 6; i++, orgPoint.x += horzGap) { var sides = i + 3; g.drawRegularPolygon(Circle(orgPoint, radius), sides, options); } orgPoint.x = 1; orgPoint.y -= vertGap; options.isDrawOrgPoint = true; for (let i = 0; i < 6; i++, orgPoint.x += horzGap) { var sides = i + 3; g.drawRegularPolygon(Circle(orgPoint, radius), sides, options); }

第一行只绘制多边形,第二行额外绘制外接圆,第三行额外绘制多边形各顶点的连线,第4行额外绘制圆心。

参数options的各个默认值如下:

const { orgPointRadius = 0.2, polygonColor = this.SHAPE_STROKE_COLOR, aroundedCircleColor = this.SHAPE_BORDER_COLOR, connectedLinesColor = this.SHAPE_BORDER_COLOR, orgPointFillColor = this.SHAPE_FILL_COLOR, orgPointBdColor = this.SHAPE_BORDER_COLOR, isDrawPolygon = true, isDrawAroundedCircle = false, isDrawConnectedLines = false, isDrawOrgPoint = false } = options ??= {};

通过上面的参数配置,我们很容易绘制出一个五角形:

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 20, 5, true, true); var orgPoint = Point(10, 11); var radius = 5; var options = { isDrawPolygon: false, isDrawConnectedLines: true, connectedLinesColor: 'yellow' }; g.drawRegularPolygon(Circle(orgPoint, radius), 5, options);

黄金矩形

达芬奇的众多秘密就藏在黄金矩形中。

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); g.drawGoldenRect(Point(2, 8), 5, 5, false); g.drawGoldenRect(Point(10, 8), 8, 12, true, 'orange');

原型:

undefineddrawGoldenRect
  • Pointpoint
  • Numberwidth
  • NumberarcNums
  • BooleanisDrawGrid
  • Stringcolor = this.SHAPE_BORDER_COLOR

黄金矩形的特色是,每条弧线都在一个正方形内绘制,而整个矩形的短边与长边之比为黄金分割率0.618geoGrp为此定义了常量:

const GOLDEN_RATE = (Math.sqrt(5) - 1) / 2; pc.log(GOLDEN_RATE);

从上面绘图结果可看出,肉眼可清晰地分辨出7个正方形内的弧线,再多就看不清了。

箭头

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); g.drawLineWithArrow(Point(4, 4), Point(10, 8), 20, 0.5, 'yellow'); g.drawPathWithArrow('M 2 2 h 4 v 5 h 2 v -3 h 5', 20, 0.5, 'cyan'); g.drawArcWithArrow(Circle(Point(15, 5), 3), 0, 90, true, 20, 0.5, 'orange');

夹角圆弧

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); let srcPt = Point(4, 2); let dstPt1 = Point(10, 8); let dstPt2 = Point(13, 2); let r = 1.5; g.drawArcInIntersectAngle(srcPt, dstPt1, dstPt2, r, 'cyan'); g.drawLineWithArrow(srcPt, dstPt1, 20, 0.5, 'silver'); g.drawLineWithArrow(srcPt, dstPt2, 20, 0.5, 'silver'); let ptRadius = 0.2; g.fillCircle(Circle(srcPt, ptRadius), 'forestgreen');

括号

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); g.drawLengthBrace(Point(4, 4), 6, { oriantation: 'down', lineColor: 'yellow' }); g.drawLengthBrace(Point(10, 8), 3, { oriantation: 'up', lineColor: 'cyan' });

两圆之间的连线

g.setupCoordinate('up', g.getLeftBottomCorner(), 20, 10, 10, 5, true, true); var circle1 = Circle(Point(2, 6), 1); var circle2 = Circle(Point(8, 3), 1.3); g.drawArrowBetweenCircles(circle1, circle2, 20, 0.5, 'orange'); var circle3 = Circle(Point(15, 3), 1); var circle4 = Circle(Point(18, 9), 1.3); g.drawArrowBetweenCircles(circle3, circle4, 20, 0.5, 'orange'); g.fillCircle(circle4, '#496D79');

drawArrowBetweenCircles的价值在于确定两个不重合的圆弧上的连接点。该方法只负责画出两圆的外弧及其两圆之间的箭头连线。上图共有2种这种图形。右边一组使用单独的代码对其中一个圆进行了填充。

这种积木式API的设计理念,目的在于解耦。它只关心最核心的部分。至于所连接的两个圆如何变化,像右边的图例所示,用户反倒有更充分的自由空间。

当然,如果像上面右边图像应用场合较多,则可将其封装为一个方法,但为应对不同的场合,其参数必然较为复杂,这种API就显得呆板而笨重了。

色轮

g.setupCoordinate('up', g.getCenterPoint(), 20, 10, 10, 5, false); g.drawColorWheel(Point(0, 0), 8, 4, 144, false);

外圆半径为8,内圆半径为4,色块数量为144个,不绘制色块之间的边界线。

参考资源

  1. Safari HTML5 Canvas Guide
  2. HTML5 Canvas Element