canvas製作馬賽克&飛鳥動畫&小球拖拽動畫
一、瞭解單像素操作
1、在canvas中的像素操作
到目前爲止,我們尚未深入瞭解Canvas畫布真實像素的原理,事實上,
你可以直接通過ImageData對象操縱像素數據,直接讀取或將數據數組寫入該對象中
2、得到場景像素數據
getImageData():
獲得一個包含畫布場景像素數據的ImageData對像,它代表了畫布區域的對象數據
ctx.getImageData(sx, sy, sw, sh)
sx:將要被提取的圖像數據矩形區域的左上角 x 座標。
sy:將要被提取的圖像數據矩形區域的左上角 y 座標。
sw:將要被提取的圖像數據矩形區域的寬度。
sh:將要被提取的圖像數據矩形區域的高度。
3、ImageData對象
ImageData
對象中存儲着canvas對象真實的像素數據,它包含以下幾個只讀屬性:
width:
圖片寬度,單位是像素
height:
圖片高度,單位是像素
data:Uint8ClampedArray
類型的一維數組,
包含着RGBA格式的整型數據,範圍在0至255之間(包括255)
R:0 --> 255
(黑色到白色)
G:0 --> 255
(黑色到白色)
B:0 --> 255
(黑色到白色)
A:0 --> 255
(透明到不透明)
4、在場景中寫入像素數據
putImageData()
方法去對場景進行像素數據的寫入。
putImageData(myImageData, dx, dy)
dx
和dy
參數表示你希望在場景內左上角繪製的像素數據所得到的設備座標
5、創建一個ImageData對象
ctx.createImageData(width, height);
width : ImageData 新對象的寬度。
height: ImageData 新對象的高度。
默認創建出來的是透明的
二、canvas使用圖片
1、在canvas中插入圖片(需要image對象)
1.
canvas操作圖片時,必須要等圖片加載完才能操作
2.drawImage(image, x, y, width, height)
其中image
是image
或者canvas
對象,x 和 y
是其在目標 canvas 裏的起始座標。
這個方法多了2個參數:width 和 height,
這兩個參數用來控制 當像canvas畫入時應該縮放的大小
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
body {
background: pink;
}
#test {
background: gray;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<canvas id="test" width="300" height="300">
<span>您的瀏覽器不支持畫布元素 請您換成萌萌的谷歌</span>
</canvas>
</body>
<script type="text/javascript">
window.onload = function() {
var canvas = document.querySelector("#test");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
var img = new Image(); //加載圖片
img.src = "tg.png";
img.onload = function() {
draw(); //加載成功之後
}
function draw() {
ctx.drawImage(img, 0, 0, img.width, img.height)
}
}
}
2、在canvas中設置背景(需要image對象)
1.createPattern(image, repetition)
image:圖像源
epetition:
"repeat"
"repeat-x"
"repeat-y"
"no-repeat"
一般情況下,我們都會將createPattern返回的對象作爲fillstyle的值
漸變
canvas漸變(線性漸變)
createLinearGradient(x1, y1, x2, y2)
表示漸變的起點 (x1,y1) 與終點 (x2,y2)
gradient.addColorStop(position, color)
gradient :createLinearGradient
的返回值
addColorStop
方法接受 2 個參數,
position 參數必須是一個 0.0 與 1.0 之間的數值,表示漸變中顏色所在的相對位置。
例如,0.5 表示顏色會出現在正中間。
color 參數必須是一個有效的 CSS 顏色值(如 #FFF, rgba(0,0,0,1),等等)
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
body {
background: pink;
}
#test {
background: gray;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<canvas id="test" width="300" height="300">
<span>您的瀏覽器不支持畫布元素 請您換成萌萌的谷歌</span>
</canvas>
</body>
<script type="text/javascript">
window.onload = function() {
var canvas = document.querySelector("#test");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
/*var img = new Image();
img.src="tg.png";
img.οnlοad=function(){
draw();
}*/
// function draw(){
var gradient = ctx.createLinearGradient(0, 0, 300, 300);
gradient.addColorStop(0, "red");
gradient.addColorStop(0.5, "yellow");
gradient.addColorStop(0.7, "pink");
gradient.addColorStop(1, "green");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 300, 300);
// }
}
}
</script>
canvas漸變(徑向漸變)
createRadialGradient(x1, y1, r1, x2, y2, r2)
前三個參數則定義另一個以(x1,y1) 爲原點,半徑爲 r1 的圓,
後三個參數則定義另一個以 (x2,y2) 爲原點,半徑爲 r2 的圓。
<style type="text/css">
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
body{
background: pink;
}
#test{
background: gray;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<canvas id="test" width="300" height="300">
<span>您的瀏覽器不支持畫布元素 請您換成萌萌的谷歌</span>
</canvas>
</body>
<script type="text/javascript">
window.onload=function(){
var canvas = document.querySelector("#test");
if(canvas.getContext){
var ctx = canvas.getContext("2d");
/*var img = new Image();
img.src="tg.png";
img.οnlοad=function(){
draw();
}*/
// function draw(){
var gradient = ctx.createRadialGradient(150, 150, 50, 150, 150, 100)
gradient.addColorStop(0,"red");
gradient.addColorStop(0.5,"yellow");
gradient.addColorStop(0.7,"pink");
gradient.addColorStop(1,"green");
ctx.fillStyle=gradient;
ctx.fillRect(0,0,300,300);
// }
}
}
</script>
三、飛鳥動畫
效果圖
完整代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
body{
background: pink;
}
#test{
background: white;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<canvas id="test" width="300" height="300">
<span>您的瀏覽器不支持畫布元素 請您換成萌萌的谷歌</span>
</canvas>
</body>
<script type="text/javascript">
window.onload=function(){
var canvas = document.querySelector("#test");
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
if(canvas.getContext){
var ctx = canvas.getContext("2d");
var flag = 0;
var value=0;
setInterval(function(){
ctx.clearRect(0,0,canvas.width,canvas.height)
value+=10;
flag++;
if(flag==9){
flag=1;
}
var img = new Image();
img.src="img/q_r"+(flag)+".jpg";
img.onload=function(){
draw(this);
}
},100)
function draw(img){
ctx.drawImage(img,value,0)
}
}
}
</script>
</html>
四、操作單個像素(行與列)
示例一
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
body{
background: pink;
}
#test{
background: gray;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<canvas id="test" width="300" height="300">
<span>您的瀏覽器不支持畫布元素 請您換成萌萌的谷歌</span>
</canvas>
</body>
<script type="text/javascript">
window.onload=function(){
var canvas = document.querySelector("#test");
if(canvas.getContext){
var ctx = canvas.getContext("2d");
// ctx.fillStyle="rgba(255, 192, 203,1)";
// ctx.fillRect(0,0,100,100);
//100*100 10000個像素點
/*imageData
width:橫向上像素點的個數
height:縱向上像素點的個數
data:數組
每一個像素點的rgba信息
*/
//默認創建出來 rgba(0,0,0,0)
var imageData = ctx.createImageData(100,100);
for(var i=0;i<imageData.data.length;i++){
imageData.data[4*i+3]=255;
}
ctx.putImageData(imageData,100,100)
}
}
</script>
</html>
效果圖
示例二
HTML&CSS
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
body {
background: pink;
}
#test {
background: gray;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
</head>
<body>
<canvas id="test" width="400" height="300">
<span>您的瀏覽器不支持畫布元素 請您換成萌萌的谷歌</span>
</canvas>
</body>
獲取某個點的像素
求出該點像素的座標關係
function getPxInfo(imgdata, x, y) {
var color = [];
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
//(x,y) x*w+y
//r
color[0] = data[(y * w + x) * 4];
//g
color[1] = data[(y * w + x) * 4 + 1];
//b
color[2] = data[(y * w + x) * 4 + 2];
//a
color[3] = data[(y * w + x) * 4 + 3];
return color;
}
設置某個點的像素
function setPxInfo(imgdata, x, y, color) {
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
//(x,y) x*w+y x:多少列 y:多少行
//r
data[(y * w + x) * 4] = color[0];
//g
data[(y * w + x) * 4 + 1] = color[1];
//b
data[(y * w + x) * 4 + 2] = color[2];
//a
data[(y * w + x) * 4 + 3] = color[3];
}
完整JavaScript代碼
<script type="text/javascript">
window.onload = function() {
var canvas = document.querySelector("#test");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "pink";
ctx.beginPath();
ctx.fillRect(50, 50, 100, 100);
ctx.restore();
var imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height);
/*var color = getPxInfo(imgdata,49,49);
console.log(color);*/
for (var i = 0; i < imgdata.width; i++) {
setPxInfo(imgdata, 30, i, [0, 0, 0, 255]);
}
ctx.putImageData(imgdata, 0, 0);
}
// console.log(imgdata);
let color = getPxInfo(imgdata, 49, 49);
console.log(color);
for (var i = 0; i < imgdata.width; i++) {
setPxInfo(imgdata, i, 50, [0, 0, 0, 255]);
}
ctx.putImageData(imgdata, 0, 0);
function getPxInfo(imgdata, x, y) {
var color = [];
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
//(x,y) x*w+y
//r
color[0] = data[(y * w + x) * 4];
//g
color[1] = data[(y * w + x) * 4 + 1];
//b
color[2] = data[(y * w + x) * 4 + 2];
//a
color[3] = data[(y * w + x) * 4 + 3];
return color;
}
function setPxInfo(imgdata, x, y, color) {
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
//(x,y) x*w+y x:多少列 y:多少行
//r
data[(y * w + x) * 4] = color[0];
//g
data[(y * w + x) * 4 + 1] = color[1];
//b
data[(y * w + x) * 4 + 2] = color[2];
//a
data[(y * w + x) * 4 + 3] = color[3];
}
}
</script>
效果圖
平行X軸
for (var i = 0; i < imgdata.width; i++) {
setPxInfo(imgdata, 30, i, [0, 0, 0, 255]);
}
平行y軸
for (var i = 0; i < imgdata.width; i++) {
setPxInfo(imgdata, i, 50, [0, 0, 0, 255]);
}
五、馬賽克
HTML&CSS
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
#msk {
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
/*background: gray;*/
}
</style>
</head>
<body>
<canvas id="msk"></canvas>
</body>
選取馬賽克矩形
- 選取一個馬賽克矩形(
可以通過size調節模糊程度
) - 從馬賽克矩形中隨機抽出一個像素點的信息(rgba)
- 將整個馬賽克矩形中的像素點信息統一調成隨機抽出的那個
function draw() {
ctx.drawImage(img, 0, 0);
var oldImgdata = ctx.getImageData(0, 0, img.width, img.height);
var newImgdata = ctx.createImageData(img.width, img.height);
//馬賽克
/*
1.選取一個馬賽克矩形
2.從馬賽克矩形中隨機抽出一個像素點的信息(rgba)
3.將整個馬賽克矩形中的像素點信息統一調成隨機抽出的那個
*/
//選取一個馬賽克矩形
var size = 5;
for (var i = 0; i < oldImgdata.width / size; i++) {
for (var j = 0; j < oldImgdata.height / size; j++) {
//(i,j) 每一個馬賽克矩形的座標
//(0,0): (0,0) (4,4);[0,4] //(1,0): (5,0) (9,4)
//(0,1): (0,5) (4,9) //(1,1): (5,5) (9,9)
//Math.random() [0,1)
//Math.random()*size [0,5)
//Math.floor(Math.random()*size) [0,4]
//從馬賽克矩形中隨機抽出一個像素點的信息(rgba)
var color = getPxInfo(oldImgdata, i * size + Math.floor(Math.random() * size), j * size + Math.floor(Math.random() * size));
//將整個馬賽克矩形中的像素點信息統一調成隨機抽出的那個
for (var a = 0; a < size; a++) {
for (var b = 0; b < size; b++) {
setPxInfo(newImgdata, i * size + a, j * size + b, color)
}
}
}
}
單像素操作
function getPxInfo(imgdata, x, y) {
var color = [];
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
color[0] = data[(y * w + x) * 4];
color[1] = data[(y * w + x) * 4 + 1];
color[2] = data[(y * w + x) * 4 + 2];
color[3] = data[(y * w + x) * 4 + 3];
return color;
}
function setPxInfo(imgdata, x, y, color) {
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
data[(y * w + x) * 4] = color[0];
data[(y * w + x) * 4 + 1] = color[1];
data[(y * w + x) * 4 + 2] = color[2];
data[(y * w + x) * 4 + 3] = color[3];
}
完整代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
#msk {
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
/*background: gray;*/
}
</style>
</head>
<body>
<canvas id="msk"></canvas>
</body>
<script type="text/javascript">
var oc = document.querySelector("#msk");
if (oc.getContext) {
var ctx = oc.getContext("2d");
var img = new Image();
img.src = "2.png";
img.onload = function() {
oc.width = img.width * 2;
oc.height = img.height * 2;
draw();
}
function draw() {
ctx.drawImage(img, 0, 0);
var oldImgdata = ctx.getImageData(0, 0, img.width, img.height);
var newImgdata = ctx.createImageData(img.width, img.height);
//馬賽克
/*
1.選取一個馬賽克矩形
2.從馬賽克矩形中隨機抽出一個像素點的信息(rgba)
3.將整個馬賽克矩形中的像素點信息統一調成隨機抽出的那個
*/
//選取一個馬賽克矩形
var size = 5;
for (var i = 0; i < oldImgdata.width / size; i++) {
for (var j = 0; j < oldImgdata.height / size; j++) {
//(i,j) 每一個馬賽克矩形的座標
//(0,0): (0,0) (4,4);[0,4] //(1,0): (5,0) (9,4)
//(0,1): (0,5) (4,9) //(1,1): (5,5) (9,9)
//從馬賽克矩形中隨機抽出一個像素點的信息(rgba)
var color = getPxInfo(oldImgdata, i * size + Math.floor(Math.random() * size), j * size + Math.floor(Math.random() * size));
//將整個馬賽克矩形中的像素點信息統一調成隨機抽出的那個
for (var a = 0; a < size; a++) {
for (var b = 0; b < size; b++) {
setPxInfo(newImgdata, i * size + a, j * size + b, color)
}
}
}
}
ctx.putImageData(newImgdata, img.width, 0);
}
function getPxInfo(imgdata, x, y) {
var color = [];
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
color[0] = data[(y * w + x) * 4];
color[1] = data[(y * w + x) * 4 + 1];
color[2] = data[(y * w + x) * 4 + 2];
color[3] = data[(y * w + x) * 4 + 3];
return color;
}
function setPxInfo(imgdata, x, y, color) {
var data = imgdata.data;
var w = imgdata.width;
var h = imgdata.height;
data[(y * w + x) * 4] = color[0];
data[(y * w + x) * 4 + 1] = color[1];
data[(y * w + x) * 4 + 2] = color[2];
data[(y * w + x) * 4 + 3] = color[3];
}
}
</script>
</html>
效果圖
六、小球動畫
1、角度與弧度的js表達式:
radians=(Math.PI/180)*degrees。
2、canvas繪製圓形
arc(x, y, radius, startAngle, endAngle, anticlockwise)
畫一個以(x,y)爲圓心的以radius爲半徑的圓弧(圓),從startAngle開始到endAngle
結束,
按照anticlockwise給定的方向(默認爲順時針)來生成。
ture:逆時針 false:順時針
x,y
爲繪製圓弧所在圓上的圓心座標
radius爲半徑
startAngle以及endAngle
參數用弧度定義了開始以及結束的弧度。這些都是以x軸爲基準
參數anticlockwis
爲一個布爾值
。爲true時,是逆時針方向,否則順時針方向。
3、arcTo
arcTo(x1, y1, x2, y2, radius)
根據給定的控制點和半徑畫一段圓弧
肯定會從(x1 y1)
但不一定經過(x2 y2);(x2 y2)
只是控制一個方向
4、實現小球拖拽與自動移動動畫
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
#canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background-color: rgb(255, 235, 205);
}
</style>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</body>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var raf;
var running = false;
console.log(canvas.offsetHeight, canvas.offsetLeft);
var ball = {
x: 100,
y: 100,
vx: 5,
vy: 1,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function clear() {
ctx.fillStyle = 'rgba(255, 235, 205,0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function draw() {
clear();
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener('mousemove', function(e) {
if (!running) {
clear();
ball.x = e.clientX - canvas.offsetLeft;
ball.y = e.clientY - canvas.offsetTop;
// console.log(e.clientX, e.clientY);
ball.draw();
}
});
canvas.addEventListener('click', function(e) {
if (!running) {
raf = window.requestAnimationFrame(draw);
running = true;
}
});
canvas.addEventListener('mouseout', function(e) {
window.cancelAnimationFrame(raf);
running = false;
});
ball.draw();
</script>
</html>
七、後記
喜歡的話可以關注我哦,相互交流學習。