canvas:理解canvas / 基础使用 / 实用demo

一、理解Canvas

Canvas是一个HTML5元素,用于在Web页面上绘制2D或3D图形。它允许使用JavaScript在网页上创建和操作图形。Canvas的主要功能是绘图,但也可以用来实现其他功能,如动画和交互式游戏。

使用Canvas,可以创建各种形状、路径、文本和图像。可以使用JavaScript绘制直线、矩形、圆形、弧形等基本形状。通过使用path API,可以创建复杂的形状和路径。同时,还可以在Canvas上添加图像,通过缩放、旋转、移动等操作进行处理。

Canvas还可以用于创建动画效果。可以使用JavaScript逐帧地修改和更新Canvas元素,从而创建动画效果。可以使用setTimeout()或requestAnimationFrame()函数来控制动画的帧速率和时间。

除了绘图和动画,Canvas还可以用来实现交互式游戏。可以使用Canvas元素检测鼠标、键盘等用户输入,根据用户的输入进行相应操作,从而实现游戏的交互性。

总之,Canvas是一个强大的HTML5工具,可以用于创建各种图形和动画效果,并实现交互式网页应用程序。

二、项目介绍

本文项目 vue3 + ts

三、Canvas的使用方法

Canvas是HTML5新增的一个标签,用于绘制图形,动画等。这里简单介绍一下Canvas的使用方法。

3.1、创建Canvas元素

在HTML中使用<canvas>标签创建Canvas元素,需要指定Canvas的宽度和高度,例如:

<canvas id="myCanvas" width="400" height="400"></canvas>

3.2、获取Canvas上下文

在JavaScript中,需要使用Canvas元素的getContext()方法获取Canvas的上下文对象,通过上下文对象可以对Canvas进行绘制,例如:

import { onMounted } from "vue";

// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
})

四、绘制基本图形

4.1、绘制一条直线

<template>
  <div class="contmian">
    <canvas id="myCanvas" width="400" height="400"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
  // 绘制一条直线
  ctx.beginPath();
  ctx.moveTo(0, 0); //起点
  ctx.lineTo(200, 200); //终点
  ctx.stroke(); //绘制线条
})

</script>
<style scoped lang="less">
</style>

4.2、绘制一个矩形

<template>
  <div class="contmian">
    <canvas id="myCanvas" width="400" height="400"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
  // 绘制一个矩形
  ctx.beginPath();
  ctx.rect(50, 50, 100, 100); //x轴坐标,y轴坐标,宽度,高度
  ctx.fill(); //填充矩形
})

</script>
<style scoped lang="less">
</style>

4.3、绘制一个圆形

<template>
  <div class="contmian">
    <canvas id="myCanvas" width="400" height="400"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
  // 绘制一个圆形
  ctx.beginPath();
  ctx.arc(200, 200, 100, 0, 2*Math.PI); //中心点x轴坐标,中心点y轴坐标,半径,起始角度,终止角度
  ctx.stroke(); //绘制圆形
})

</script>
<style scoped lang="less">
</style>

 

4.4、绘制图像

通过Canvas的上下文对象,还可以绘制图像,例如:

<template>
  <div class="contmian">
    <canvas id="myCanvas" width="400" height="400"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
  // 绘制图像
  var img = new Image();
  img.src = "../../../public/docker.png";
  img.onload = function() {
    ctx.drawImage(img, 50, 50, 200, 200); //绘制图像,x轴坐标,y轴坐标,宽度,高度
  }
})

</script>
<style scoped lang="less">
</style>

4.5、绘制动画

通过setInterval()方法可以实现Canvas上的动画效果,例如:

<template>
  <div class="contmian">
    <canvas id="myCanvas" width="400" height="400"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
  // 绘制动画
  var x = 0;
  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height); //清除画布
    ctx.beginPath();
    ctx.rect(x, 50, 50, 50); //绘制矩形
    ctx.fill();
    x++;
    console.log(x)
    if(x > 400){
      clearInterval(timer)
    }
  }
  const timer = setInterval(draw, 10); //每10毫秒调用一次draw()函数
})

</script>
<style scoped lang="less">
</style>

以上是Canvas的基本使用方法,还有很多其他功能可以通过Canvas实现,需要进一步学习和掌握。

五、canvas  Demo

5.1、canvas实现流星雨

<template>
  <div class="contmian">
    <canvas id="myCanvas" width="400" height="400"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
onMounted(()=>{
  let canvas: any = document.getElementById("myCanvas");
  let ctx = canvas.getContext("2d");
  // 设置canvas宽度和高度
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  // 定义流星雨粒子对象
  function Particle (x, y, vx, vy, size, color) {
    this.x = x;
    this.y = y;
    this.vx = vx;
    this.vy = vy;
    this.size = size;
    this.color = color;
  }

  // 定义流星雨数组
  let particles = [];

  // 创建流星雨粒子函数
  const createParticle = () => {
    let x = Math.random() * canvas.width; // 随机横坐标
    let y = Math.random() * canvas.height; // 随机纵坐标
    let vx = -(Math.random() * 2 + 3); // x方向速度
    let vy = Math.random() * 2 + 2; // y方向速度
    let size = Math.random() * 3 + 1; // 大小
    let color = "#ff0000"; // 颜色
    particles.push(new Particle(x, y, vx, vy, size, color));
  }

  // 绘制流星雨
  const draw = () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空canvas
    for (let i = 0; i < particles.length; i++) {
      let p = particles[i];
      ctx.beginPath();
      ctx.fillStyle = p.color;
      ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2, false);
      ctx.fill();
      p.x += p.vx;
      p.y += p.vy;
      if (p.x < -p.size || p.y > canvas.height + p.size) {
        // 如果粒子出了画布则删除
        particles.splice(i, 1);
        i--;
      }
    }
    requestAnimationFrame(draw);
  }

  // 创建流星雨粒子
  setInterval(createParticle, 50);

  // 开始绘制流星雨
  draw();
})

</script>
<style scoped lang="less">
</style>

通过以上代码可以实现一个简单的canvas流星雨。如果需要更加复杂的效果可以调整粒子的属性值或添加其他动画效果。

5.2、canvas实现修改图片色调、饱和度、亮度

<template>
  <div class="contmian">
    <h1>Canvas修改图片色调、饱和度、亮度</h1>
    <p>请选择图片文件:</p>
    <input type="file" accept="image/*" @change="loadImage">
    <h2>修改颜色</h2>
    <p>
      <label for="hue">色调:</label>
      <input type="range" id="hue" min="0" max="360" value="0" @change="updateColor()">
    </p>
    <p>
      <label for="saturation">饱和度:</label>
      <input type="range" id="saturation" min="0" max="2" step="0.01" value="1" @change="updateColor()">
    </p>
    <p>
      <label for="lightness">亮度:</label>
      <input type="range" id="lightness" min="0" max="2" step="0.01" value="1" @change="updateColor()">
    </p>
    <canvas id="canvas"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
let ctx:any = {}
let canvas:any = {}
onMounted(()=>{
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");
})

let img:any;

const loadImage = (e: any) => {
  console.log('35', e)
  let reader = new FileReader();
    reader.onload = function(event: any) {
      img = new Image();
      img.onload = function() {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
      };
      img.src = event.target.result;
    };
    reader.readAsDataURL(e.target.files[0]);
  }

  const updateColor = () => {
    let hue = document.getElementById('hue').value;
    let saturation = document.getElementById('saturation').value;
    let lightness = document.getElementById('lightness').value;

    let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    let data = imageData.data;

    for (let i = 0; i < data.length; i += 4) {
      let hsl = rgbToHsl(data[i], data[i+1], data[i+2]);

      hsl[0] = (hsl[0] + hue) % 360;
      hsl[1] = hsl[1] * saturation;
      hsl[2] = hsl[2] * lightness;

      let rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);

      data[i] = rgb[0];
      data[i+1] = rgb[1];
      data[i+2] = rgb[2];
    }

    ctx.putImageData(imageData, 0, 0);
  }

  // RGB转HSL
  const rgbToHsl = (r: any, g: any, b: any) => {
    r /= 255, g /= 255, b /= 255;
    let max = Math.max(r, g, b), min = Math.min(r, g, b);
    let h: any, s: any, l = (max + min) / 2;
    if(max == min){
      h = s = 0;
    }else{
      let d = max - min;
      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
      switch(max){
        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
        case g: h = (b - r) / d + 2; break;
        case b: h = (r - g) / d + 4; break;
      }
      h /= 6;
    }
    return [h * 360, s, l];
  }

  // HSL转RGB
  const hslToRgb = (h:any, s:any, l: any) => {
    let r:any, g:any, b:any;
    if(s == 0){
      r = g = b = l;
    }else{
      function hue2rgb(p:any, q:any, t:any){
        if(t < 0) t += 1;
        if(t > 1) t -= 1;
        if(t < 1/6) return p + (q - p) * 6 * t;
        if(t < 1/2) return q;
        if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
        return p;
      }
      let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
      let p = 2 * l - q;
      r = hue2rgb(p, q, h + 1/3);
      g = hue2rgb(p, q, h);
      b = hue2rgb(p, q, h - 1/3);
    }
    return [r * 255, g * 255, b * 255];
  }

</script>
<style scoped lang="less">
</style>

在这个示例中,使用<input>元素选择图像文件,并在加载图像时绘制在canvas上。使用三个<input>元素来控制色调、饱和度和亮度。在更新颜色值时,使用getImageData()方法获取图像的像素数据。遍历像素数据并将每个像素的RGB颜色值转换为HSL值,并根据选择的色调、饱和度和亮度值进行修改。然后将修改后的像素数据使用putImageData()方法重新绘制到canvas上。 请注意,这个示例的性能可能受到图像大小和计算复杂度的影响。如果需要处理大型图像或者进行更复杂的颜色修改,请考虑使用WebGL或其他高性能图形库。

5.3、canvas实现通过点击事件修改图片中点中区域元素内容颜色为指定颜色

以下是一个使用HTML canvas实现通过点击事件修改图片中点中区域元素内容颜色为指定颜色的示例代码。

<template>
  <div class="contmian">
    <h1>Canvas通过点击事件修改图片中点中区域元素内容颜色</h1>
    <p>请选择图片文件:</p>
    <input type="file" accept="image/*" @change="loadImage">
    <h2>修改颜色</h2>
    <p>
      <label for="color">颜色:</label>
      <input type="color" id="color" value="#ff0000">
    </p>
    <canvas id="canvas"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
let ctx:any = {}
let canvas:any = {}
let color:any = {}
onMounted(()=>{
  canvas = document.getElementById("canvas");
	canvas.addEventListener('click', updateColor);
  ctx = canvas.getContext("2d");
  color = document.getElementById('color').value;
})

let img:any;

    const loadImage = (e: any) => {
			var reader = new FileReader();
			reader.onload = function(event) {
				img = new Image();
				img.onload = function() {
					canvas.width = img.width;
					canvas.height = img.height;
					ctx.drawImage(img, 0, 0);
				};
				img.src = event.target.result;
			};
			reader.readAsDataURL(e.target.files[0]);
		}

		const updateColor = (e) => {
			var x = e.offsetX;
			var y = e.offsetY;

			var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
			var data = imageData.data;
			var index = (x + y * imageData.width) * 4;

			data[index] = parseInt(color.substr(1, 2), 16);
			data[index + 1] = parseInt(color.substr(3, 2), 16);
			data[index + 2] = parseInt(color.substr(5, 2), 16);

			ctx.putImageData(imageData, 0, 0);
		}


</script>
<style scoped lang="less">
canvas {
  border: 1px solid black;
}
</style>

在这个示例中,使用&lt;input>元素选择图像文件,并在加载图像时绘制在canvas上。使用&lt;input>元素选择要更改元素的颜色。 使用addEventListener()方法在canvas上添加点击事件监听器。在事件处理程序中,获取鼠标点击位置的x和y坐标,并使用getImageData()方法获取图像的像素数据。计算要更改的像素的索引,并将其颜色更改为所选颜色。使用putImageData()方法重新绘制修改后的图像数据。 请注意,此示例仅在单击canvas上的图像时更改指定像素的颜色。您可以根据需要修改更改颜色的逻辑和条件。

5.4、canvas实现刮刮乐

以下是一个使用HTML canvas实现刮刮乐效果的示例代码。

<template>
  <div class="contmian">
    <h1>Canvas实现刮刮乐效果</h1>
	<p>刮奖面板:</p>
    <canvas id="canvas"></canvas>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
// 获取Canvas上下文
let ctx:any = {}
let canvas:any = {}
let isDrawing = false;
let img:any;
onMounted(()=>{
  	canvas = document.getElementById("canvas");
  	canvas.addEventListener('mousedown', startDrawing);
	canvas.addEventListener('mousemove', draw);
	canvas.addEventListener('mouseup', stopDrawing);
	canvas.addEventListener('mouseleave', stopDrawing);
  	ctx = canvas.getContext("2d");
	init();
})

		const init = () => {
			canvas.width = 400;
			canvas.height = 200;

			ctx.fillStyle = '#ddd';
			ctx.fillRect(0, 0, canvas.width, canvas.height);

			ctx.font = 'bold 30px Arial';
			ctx.fillStyle = '#f00';
			ctx.fillText('刮一刮', 120, 100);

			img = new Image();
			img.onload = function() {
				ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
			};
			img.src = 'image.jpg';
		}

		const startDrawing = () => {
			isDrawing = true;
		}

		const stopDrawing = () => {
			isDrawing = false;
		}

		const draw = (e) => {
			if (!isDrawing) return;

			var x = e.offsetX;
			var y = e.offsetY;

			ctx.globalCompositeOperation = 'destination-out';
			ctx.beginPath();
			ctx.arc(x, y, 20, 0, Math.PI * 2, false);
			ctx.fill();
		}

</script>
<style scoped lang="less">
canvas {
  border: 1px solid black;
}
</style>

在这个示例中,使用&lt;canvas>元素创建刮刮乐面板并绘制了一个图像。当鼠标在canvas上按下时,设置isDrawing变量为true。当鼠标移动时,如果isDrawingtrue,则使用globalCompositeOperation属性将画笔设置为destination-out模式,这样每次涂抹时都会将像素颜色变成透明颜色。在鼠标弹起或离开canvas时,设置isDrawingfalse,停止绘制涂层。

此示例中,使用了一个灰色矩形覆盖图像,但是您可以使用任何其他的遮罩层,或者在涂抹时使用自己的颜色。

5.5、canvas玩转图片

用canvas玩转图片【渡一教育】_哔哩哔哩_bilibili

六、html 转 canvas

HTML如何转化为canvas教程_htmltocanvas-CSDN博客

七、过程记录

7.1、Caught error TypeError: Cannot read properties of null (reading 'getContext')

注意获取Canvas上下文的生命周期,在onMounted里边即可

import { onMounted } from "vue";

7.2、html 转 canvas

HTML转Canvas的原理如下

1. 首先,将HTML中的DOM元素(如div、p、img等)转换为Canvas上的元素。

2. 然后,将CSS样式应用到Canvas上的元素。这意味着,需要将HTML中的样式计算出来,并将其应用到Canvas上。

3. 接下来,需要将HTML中的所有内容都绘制到Canvas上。这可以通过在Canvas上使用绘图API(如绘制文本、图像、路径等)来完成。

4. 最后,需要将Canvas上的内容转换为图像或数据,以便将其保存或上传至服务器等操作。

总体来说,HTML转Canvas的过程可以分为三个主要阶段:解析HTML和CSS、将内容绘制到Canvas上、将Canvas内容转换为图像或数据。

demo待完成

7.3、canvas.getContext都有哪些值集

let canvas: any = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");

canvas.getContext方法有一个参数,表示上下文类型,常见的有以下类型:
"2d":获取二维绘图上下文对象。
"webgl" 或 "experimental-webgl":获取 WebGL 绘图上下文对象。
"webgl2":获取 WebGL2 绘图上下文对象。
"bitmaprenderer":获取位图渲染器上下文对象,用于生成位图并使用 ImageBitmap 对象呈现。

7.3、webgl 是基于 canvas 吗

 WebGL是基于HTML5中的canvas元素的。WebGL使用OpenGL ES 2.0规范来编写3D图形。WebGL的API允许JavaScript在canvas元素上绘制各种类型的3D图像,并使用GPU加速。所以,可以说WebGL是基于canvas,但它使用了更高级的图形处理技术来实现复杂的3D图像。

7.4、canvas可以使用display: none吗

浏览器可以。使用display: none可以让canvas元素隐藏,不显示在页面上。但是需要注意的是,当canvas元素被隐藏后,其上绘制的图形仍然会存在,只是不可见。

小程序可以使用 display: none 吗 ,测试无效果。

可以使用position: fixed; left: 5000px; top: 5000px;

这样就实现了隐藏canvas元素的目的,并且不赞用空间。已测试。

微信小程序Canvas隐藏问题处理_51CTO博客_微信小程序canvas层级问题

小程序canvas 可以用visibility: hidden? | 微信开放社区

八、欢迎交流指正

九、参考链接

Canvas详解-CSDN博客

Canvas 基础使用_canvas 字体_19岁的墨先生的博客-CSDN博客

HTML 画布 | 菜鸟教程

学习 HTML5 Canvas 这一篇文章就够了 | 菜鸟教程

HTML5 Canvas | 菜鸟教程

Canvas 教程 - Web API 接口参考 | MDN

canvas基础简单易懂教程(完结,多图)_canvas教程-CSDN博客

canvas详细入门教程(1W字 吐血分享)_canvas教程-CSDN博客

解决canvas清晰度的问题【渡一教育】_哔哩哔哩_bilibili

canvas动画【渡一教育】_哔哩哔哩_bilibili

文字也能很酷炫【渡一教育】_哔哩哔哩_bilibili

用canvas玩转图片【渡一教育】_哔哩哔哩_bilibili

猜你喜欢

转载自blog.csdn.net/snowball_li/article/details/133758093
今日推荐