Skip to content

Commit

Permalink
canvas绘制 transform
Browse files Browse the repository at this point in the history
  • Loading branch information
lefex committed Oct 17, 2021
1 parent 63877b7 commit d230aa2
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 127 deletions.
4 changes: 2 additions & 2 deletions learn-canvas/1-create-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*/

import {initCanvas} from './share';
import {GridSize} from './constant';

function syDraw() {
const drawReact = (ctx: CanvasRenderingContext2D) => {
ctx.fillStyle = 'blue';
ctx.fillRect(40, 40, 120, 80);
ctx.fillRect(GridSize, GridSize, GridSize * 2, 80);
}

let ctx = initCanvas();
Expand Down
187 changes: 187 additions & 0 deletions learn-canvas/17-transform2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/**
* @author 素燕(我有个公众号:素燕)
* @description transform 的理解
* scale, rotate, translate (move), and skew the context
* https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-settransform-dev
*/

import { initCanvas, SYAxisPos } from './share';
import { GridSize, TextColor } from './constant';

function syRunDemo() {
const drawSkew = (ctx: CanvasRenderingContext2D) => {
ctx.save();
ctx.strokeStyle = '#1c4587';
// ctx.translate(origin.x, origin.y);
ctx.setTransform(4, .1, .1, 2, 1, 2);
let width = 120;
let height = 80;
// ctx.strokeRect(-width - 40, -height - 40, width, height);
ctx.fillRect(40, 40, width, height);
ctx.restore();
}

const move = (ctx: CanvasRenderingContext2D, x: number, y: number) => {
ctx.save();

const drawArrow = (dash: number[]) => {
ctx.beginPath();
ctx.lineJoin = 'round';
ctx.setLineDash(dash);
ctx.moveTo(0, 0);
ctx.lineTo(GridSize * 3, GridSize * 3);
ctx.lineTo(3 * GridSize - GridSize * 0.5, 3*GridSize);
ctx.moveTo(GridSize * 3, GridSize * 3);
ctx.lineTo(3 * GridSize, 3*GridSize - GridSize * 0.5);
ctx.stroke();
ctx.closePath();
}

drawArrow([8]);

ctx.fillStyle = TextColor;
ctx.font = '30px Times';
ctx.fillText('Translate 位置移动', GridSize * 3, GridSize);

/**
* 平移,相当于修改 e、f 的值,初始矩阵
* | a c e |
* | b d f |
* | 0 0 1 |
* x' = ax + cy + e
* y' = bx + dy + f
*
* | 1 0 0 |
* | 0 1 0 |
* | 0 0 1 |
*
* | 1 0 40 |
* | 0 1 20 |
* | 0 0 1 |
*
* x' = 1*x + 0*y + 40 = x + 40
* y' = 0*x + 1*y + 20 = y + 20
*
*/
ctx.transform(1, 0, 0, 1, x, y);
drawArrow([0]);

ctx.restore();
}

const scale = (ctx: CanvasRenderingContext2D, x: number, y: number) => {
ctx.save();
ctx.fillStyle = TextColor;
ctx.font = '30px Times';
ctx.fillText('Scale 缩放', -GridSize * 3, GridSize);

ctx.restore();
ctx.save();
ctx.globalAlpha = 0.2;
ctx.fillRect(-GridSize*6, GridSize, GridSize*3, GridSize*2);

/**
* 平移,相当于修改 e、f 的值,初始矩阵
* | a c e |
* | b d f |
* | 0 0 1 |
* x' = ax + cy + e
* y' = bx + dy + f
*
* 初始矩阵:
* | 1 0 0 |
* | 0 1 0 |
* | 0 0 1 |
*
* 缩放后的矩阵
* | 4 0 0 |
* | 0 2 0 |
* | 0 0 1 |
*
* x' = 4*x + 0*y + 0 = 4x
* y' = 0*x + 2*y + 0 = 2y
*
*/
ctx.transform(x, 0, 0, y, 0, 0);
// 等价于 scale
// ctx.scale(x, y)
ctx.globalAlpha = 1;
// x,y,width,height 均按照缩放比例进行缩放
/**
* x = x * scaleX
* y = y * scaleY
* width = width * scaleX
* height = height * scaleY
*/
ctx.fillRect(-GridSize*6, GridSize, GridSize*3, GridSize*2);

ctx.restore();
}

const rotate = (ctx: CanvasRenderingContext2D, angle: number) => {
ctx.save();
ctx.fillStyle = TextColor;
ctx.font = '30px Times';
ctx.fillText('Rotate旋转', GridSize * 3, -0.5*GridSize);

ctx.restore();
ctx.save();

ctx.save();

const drawArrow = (dash: number[]) => {
ctx.beginPath();
ctx.lineJoin = 'round';
ctx.strokeStyle = '#32C5FF'
ctx.setLineDash(dash);
ctx.moveTo(0, 0);
ctx.lineTo(GridSize * 3, -GridSize * 3);
ctx.lineTo(3 * GridSize - GridSize * 0.5, -3*GridSize);
ctx.moveTo(GridSize * 3, -GridSize * 3);
ctx.lineTo(3 * GridSize, -3*GridSize + GridSize * 0.5);
ctx.stroke();
ctx.closePath();
}

drawArrow([8]);

/**
* 平移,相当于修改 e、f 的值,初始矩阵
* | a c e |
* | b d f |
* | 0 0 1 |
* x' = ax + cy + e
* y' = bx + dy + f
*
* 初始矩阵:
* | 1 0 0 |
* | 0 1 0 |
* | 0 0 1 |
*
* 缩放后的矩阵
* | cosθ -sinθ 0 |
* | sinθ cosθ 0 |
* | 0 0 1 |
*
* x' = cos45*x + -sin45*y + 0 = cos45*x - sin45*y
* y' = sin45*x + cos45*y + 0 = sin45*x + cos45*y
*
*/
ctx.transform(Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0, 0);
drawArrow([0]);

ctx.restore();
}

// 1. 创建 canvas
let ctx = initCanvas(SYAxisPos.Center);

move(ctx, GridSize*2, GridSize);
scale(ctx, 0.5, 2);
rotate(ctx, 0.4);

// drawSkew(ctx);

}

syRunDemo();
11 changes: 5 additions & 6 deletions learn-canvas/2-shape-rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,27 @@
*/

import {initCanvas} from './share';
import {GridSize} from './constant';

function syRunDrawRectDemo() {
const drawReact = (ctx: CanvasRenderingContext2D) => {
ctx.fillStyle = '#555';
ctx.fillRect(40, 40, 80, 80);
ctx.fillRect(GridSize * 8, GridSize, GridSize * 2, GridSize * 2);
}

const strokeReact = (ctx: CanvasRenderingContext2D) => {
ctx.strokeStyle = '#555';
ctx.strokeRect(200, 40, 120, 80);
ctx.strokeRect(GridSize * 8, GridSize * 4, GridSize * 2, GridSize);
}

const clearReact = (ctx: CanvasRenderingContext2D) => {
ctx.clearRect(120, 200, 80, 80);
ctx.clearRect(GridSize * 9, GridSize * 1, GridSize * 1, GridSize * 1);
}

const drawColorPannel = (ctx: CanvasRenderingContext2D) => {
for (let i = 0; i < 6; i++){
for (let j = 0; j < 6; j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25, i*25, 25, 25);
ctx.fillRect(GridSize + j*GridSize, GridSize + i*GridSize, GridSize, GridSize);
}
}
}
Expand Down
98 changes: 46 additions & 52 deletions learn-canvas/3-shape-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,28 @@
*/

import { initCanvas } from './share';
import {GridSize} from './constant';

function syRunDrawPathDemo() {
// 绘制一根线
const drawLine = (ctx: CanvasRenderingContext2D) => {
// 不调用 beginPath 会有意想不到的结果
ctx.beginPath();
// 移动移动到某个位置,可以作为绘图的起点,或者绘制之间不连接的 path
// 线宽
ctx.lineWidth = 30;
// 线顶点的样式 'butt', 'round', 'square'
// butt 默认样式,不会导致线变长
// round 圆头,会导致两顶点处的线变长 lineWidth/2
// square 方头,会导致两顶点处线变长 lineWidth/2
ctx.lineCap = 'round';

// 在画线的过程中需要注意最终线被画到了那个区域
ctx.moveTo(80, 120);
// lineTo 画一条直线
ctx.lineTo(320, 120);
ctx.stroke();
}
// 绘制一根线
const drawLine = (ctx: CanvasRenderingContext2D) => {
// 不调用 beginPath 会有意想不到的结果
ctx.beginPath();
// 移动移动到某个位置,可以作为绘图的起点,或者绘制之间不连接的 path
// 线宽
ctx.lineWidth = 20;
// 线顶点的样式 'butt', 'round', 'square'
// butt 默认样式,不会导致线变长
// round 圆头,会导致两顶点处的线变长 lineWidth/2
// square 方头,会导致两顶点处线变长 lineWidth/2
ctx.lineCap = 'round';

// 在画线的过程中需要注意最终线被画到了那个区域
ctx.moveTo(GridSize * 2, GridSize * 2);
// lineTo 画一条直线
ctx.lineTo(GridSize * 5, GridSize * 5);
ctx.stroke();
}

const drawLineJoinStyle = (ctx: CanvasRenderingContext2D) => {
ctx.beginPath();
Expand All @@ -42,7 +43,6 @@ const drawLine = (ctx: CanvasRenderingContext2D) => {
// ctx.lineJoin = 'round';

let dashs = ctx.getLineDash();
console.log('dashs = ', dashs);
ctx.setLineDash([20]);

ctx.stroke();
Expand All @@ -68,45 +68,39 @@ const drawLine = (ctx: CanvasRenderingContext2D) => {
ctx.fill();
}

const drawArcs = (ctx: CanvasRenderingContext2D) => {
// arc(x, y, radius, startAngle, endAngle, counterclockwise)
ctx.beginPath();
// false 顺时针 true 逆时针
// 弧度和角度
// 弧度是角的度量单位
// 弧长等于半径的弧,其所对的圆心角为一弧度
// 弧度表示:弧长与半径长相等所对应的角度
// 圆的弧长为 2πr,一个圆的弧度为 2πr / r = 2π,π为圆周率,约为 3.14 2π = 2*3.14=6.28
// 1π 为 180度,1度 = π / 180, 1弧度 = 180 / π

// 起点为 3 点钟方向
// 画一弧度
// ctx.arc(80, 160, 40, 0, 1, false); // Outer circle
// 画 90 度
// ctx.arc(80, 160, 40, 0, Math.PI / 180 * 90);
ctx.arc(80, 160, 40, 0, Math.PI / 180 * 360, false);

// 如何才能让起点为 12 点钟方向
// ctx.arc(80, 160, 40, Math.PI / 180 * 270, Math.PI / 180 * 180, false);
const drawArcs = (ctx: CanvasRenderingContext2D) => {
// arc(x, y, radius, startAngle, endAngle, counterclockwise)
ctx.beginPath();
// false 顺时针 true 逆时针
// 弧度和角度
// 弧度是角的度量单位
// 弧长等于半径的弧,其所对的圆心角为一弧度
// 弧度表示:弧长与半径长相等所对应的角度
// 圆的弧长为 2πr,一个圆的弧度为 2πr / r = 2π,π为圆周率,约为 3.14 2π = 2*3.14=6.28
// 1π 为 180度,1度 = π / 180, 1弧度 = 180 / π

// 起点为 3 点钟方向
// 画一弧度
// ctx.arc(80, 160, 40, 0, 1, false); // Outer circle
// 画 90 度
// ctx.arc(80, 160, 40, 0, Math.PI / 180 * 90);
ctx.arc(80, 160, 40, 0, Math.PI / 180 * 360, false);

// 如何才能让起点为 12 点钟方向
// ctx.arc(80, 160, 40, Math.PI / 180 * 270, Math.PI / 180 * 180, false);

ctx.stroke();
}
ctx.stroke();
}

// 1. 创建 canvas
let ctx = initCanvas();

// 初始化画布的一些属性
// 设置线的颜色
ctx.strokeStyle = 'red';
ctx.fillStyle = '#222';
ctx.lineWidth = 4;

// 在画布中画一个矩形区域
// drawLine(ctx);
// drawRect(ctx);
// drawTriangle(ctx);
drawLine(ctx);
drawRect(ctx);
drawTriangle(ctx);
drawArcs(ctx);
// drawLineJoinStyle(ctx);
drawLineJoinStyle(ctx);
}

syRunDrawPathDemo();
6 changes: 5 additions & 1 deletion learn-canvas/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@

export const BgColor = '#222';
export const TextColor = '#fff';
export const LineColor = '';
export const ContentColor = '#C741B1';
export const StrokeColor = '#FEFF06';
export const GridLineColor = '#42A0B8';
export const AxisLineColor = '#fff';
export const GridSize = 80;
3 changes: 2 additions & 1 deletion learn-canvas/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@
<!-- <script src="./12-transform-scale.ts" type="module"></script> -->
<!-- <script src="./13-transform-rotate.ts" type="module"></script> -->
<!-- <script src="./14-translate.ts" type="module"></script> -->
<script src="./15-transform.ts" type="module"></script>
<!-- <script src="./15-transform.ts" type="module"></script> -->
<!-- <script src="./16-sin-cos-tan.ts" type="module"></script> -->
<script src="./17-transform2.ts" type="module"></script>

</body>
</html>
Loading

0 comments on commit d230aa2

Please sign in to comment.