⭐前言
大家好,我是yma16,本文分享webgl canvas系列——animation基本旋转、平移、缩放。
该系列往期文章
web canvas系列——快速入门上手绘制二维空间点、线、面
webgl canvas系列——快速加背景、抠图、加水印并下载图片
⭐canvas绘制图片
💖状态保存和恢复
方法 | 作用 |
save() | 保存画布 (canvas) 的所有状态。 |
restore() | save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。 |
💖移动、旋转、缩放、变形
方法 | 作用 |
translate(x, y) | x *是左右偏移量,y 是上下偏移量 |
scale(x, y) | scale方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。默认值为 1,为实际大小 |
transform(a, b, c, d, e, f) | 将当前的变形矩阵乘上一个基于自身参数的矩阵 |
a c e b d f 0 0 1 (transform)
ab0cd0ef1������001
\tag{transform}ab0cd0ef1(transform)
💖移动绘制一个渐变的box
使用translate移动
js代码快如下
function draw() { var ctx = document.getElementById("canvas").getContext("2d"); const width=150 const height=150 for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { ctx.save(); ctx.fillStyle = "rgb(" + 51 * i + ", " + (255 - 51 * i) + ", 255)"; ctx.translate(10+ j * (width+1), 10 + i * (height+1)); ctx.fillRect(0, 0, width, height); ctx.restore(); } } }
效果
💖旋转
先移动原点再旋转
旋转一个正方形
function draw() { const ctx = document.getElementById("canvas").getContext("2d"); const xRectX=100 const yRextY=100 const width=100 const height=100 ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; ctx.beginPath(); ctx.arc(xRectX, yRextY, 10, 0, Math.PI * 2, true); // 旋转中心 ctx.fill(); ctx.restore(); // ctx.save(); const translateX=xRectX+width/2 const translateY=yRextY-height/4 // left rectangles, rotate from canvas origin // blue rect ctx.fillStyle = "#0095DD"; ctx.fillRect(xRectX, yRextY, width, height); ctx.fillStyle = "rgba(255, 0, 200, 0.5)"; ctx.beginPath(); ctx.arc(translateX, translateY, 10, 0, Math.PI * 2, true); // 旋转中心 ctx.fill(); ctx.translate(translateX, translateY); // translate back ctx.rotate((Math.PI / 180) * 45); // red rect ctx.fillStyle = "rgba(255,0,0,.2)"; ctx.fillRect(0, 0, width, height); ctx.restore(); }
蓝色的圆点移动到红色的点之后再旋转45°
移动中心 再旋转
function draw() { const ctx = document.getElementById("canvas").getContext("2d"); const xRectX = 100 const yRextY = 100 const width = 100 const height = 100 ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; ctx.beginPath(); ctx.arc(xRectX, yRextY, 10, 0, Math.PI * 2, true); // 旋转中心 ctx.fill(); ctx.restore(); // ctx.save(); // x = x + 0.5 * width // y = y + 0.5 * height const translateX = xRectX + width / 2 const translateY = yRextY + height / 2 // left rectangles, rotate from canvas origin // blue rect ctx.fillStyle = "#0095DD"; ctx.fillRect(xRectX, yRextY, width, height); ctx.translate(translateX, translateY); ctx.rotate((Math.PI / 180) * 45); ctx.translate(-translateX, -translateY); // ctx.translate(translateX, translateY); // translate back // red rect ctx.fillStyle = "rgba(255,0,0,.2)"; ctx.fillRect(xRectX, xRectX, width, height); ctx.fillStyle = "rgba(255, 0, 200, 0.5)"; ctx.beginPath(); ctx.arc(translateX, translateY, 10, 0, Math.PI * 2, true); // 旋转中心 ctx.fill(); }
效果(红点为旋转中心)
💖缩放
缩放文字
function draw() { var ctx = document.getElementById("canvas").getContext("2d"); // mirror horizontally ctx.scale(2, 2); ctx.font = "48px serif"; ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; ctx.fillText("csdn yma16", 0, 120); }
⭐模拟冒泡排序过程
冒泡排序(Bubble Sort)
是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
vue3页面简单使用canvas模拟冒泡排序的效果
<script lang="js" setup> import { reactive, onMounted } from 'vue'; const state = reactive({ value: '[100,20,69,16,55,33]', title: '冒泡排序可视化', visualSortArray: [ ] }) function bubbleSort(arr) { // 冒泡排序算法,对数组进行排序,同时记录每一步操作,保存在一个数组中 function sort() { // virtualArr 用来存放 每一个步内容的数组 const virtualArr = [arr.slice()]; console.log('virtualArr', virtualArr) const max = arr.length; for (let i = 0; i < max; i++) { let done = true; for (let j = 0; j < max - i; j++) { if (arr[j] > arr[j + 1]) { let temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; done = false; virtualArr.push(arr.slice()); } }; if (done) { break; }; } return virtualArr; } // 绘画,调用一次就画出一步的图像 function darw(arr, count) { const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); // 最大高度 400 let maxHeight = canvas.height; // 每个长方形的宽度 let width = 20; // 每个长方形之间的间隔 let space = 100; const total = arr.reduce((p, c) => p + c, 0) // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 设置字体 ctx.font = "18px serif"; // 在页面上,画出一步的内容 for (let i = 0; i < arr.length; i++) { ctx.fillStyle = '#61C5FE'; const x= i * (width + space) const y= maxHeight - arr[i] const height=Math.round((arr[i] / total)*100 + 100) ctx.fillRect(x, y, width, height); console.log('x',x) console.log('y',y) console.log('width',width) console.log('height',height) ctx.fillStyle = '#240be4'; // 标题文字 ctx.fillText(arr[i], x, y); ctx.restore(); } ctx.fillText(`第${count}趟排序`, 200, 100); ctx.fillStyle = "rgba(0, 66, 200, 0.5)"; ctx.beginPath(); ctx.lineTo(0, 400); ctx.lineTo(800, 400); ctx.stroke() } // 动画 function animation() { // 调用sort 方法,返回包括每一步内容的数组 var virtualArr = sort(); var interval = 500; // 遍历得到的数组,每隔500ms,调用darw 方法,画出一步内容 virtualArr.forEach((item, index) => { setTimeout(() => darw(item, index + 1), index * interval); }); state.visualSortArray = virtualArr } animation(); } const sortBtn = () => { const arr = state.value.replace('[', '').replace(']', '').split(',').map(n => +n) console.log('arr', arr) bubbleSort(arr); } onMounted(()=>{ sortBtn() }) </script> <template> <div> <div style="display:flex;"> <a-card :title="state.title" style="min-width: 800px"> <div class="input-box"> <div> <a-input v-model:value="state.value" placeholder="请输入数组" clearable></a-input> </div> <div style="margin-left:50px"><a-button type="primary" @click="sortBtn">开始排序</a-button></div> </div> <div class="container-sort"> <div style="text-align: right;margin-right: 20px;"> <div v-for="(item, index) in state.visualSortArray" :key="index"> <div> 第 {{ index + 1 }} 躺排序: {{ item.toString() }} </div> </div> </div> <canvas id="myCanvas" width="800" height="400"> </canvas> </div> </a-card> </div> </div> </template> <style lang="less"> .input-box { display: flex; margin-bottom: 10px; } .container-sort { height: 800px; border: 1px solid #dcdcdc; } .box { margin: 10px; .bar { width: 10px; background: #1677ff; border-radius: 2px; } .num { font-size: 18px; } } </style>
效果
inscode代码块
⭐结束
本文分享到这结束,如有错误或者不足之处欢迎指出!