1.粒子化
function Dot(X, Y, Z, R) {
this.dx = X;
this.dy = Y;
this.dz = Z;this.tx = 0;
this.ty = 0;
this.tz = 0;this.z = Z;
this.x = X;
this.y = Y;
this.r = R;this.paint = function() {
context.save();
context.beginPath();
var scale = 250 / (250 + this.z);
context.arc(canvas.width / 2 + (this.x - canvas.width / 2) * scale, canvas.height / 2 + (this.y - canvas.height / 2) * scale, this.r * scale, 0, 2 * Math.PI);
context.fillStyle = "rgba(50,50,50," + scale + ")";
context.fill();
context.restore();
}
}window.onload = function() {
canvas = document.getElementsByTagName("canvas")[0];
context = canvas.getContext(‘2d‘);var dots = getimgData(‘program‘);
dots.forEach(function(dot) {
dot.tx = Math.random() * canvas.width;
dot.ty = Math.random() * canvas.height;
dot.tz = Math.random() * 250 * 2 - 250;dot.x = dot.tx;
dot.y = dot.ty;
dot.z = dot.tz;
dot.paint();
});var moving = false;
var lastTime;
var direction = true;
function animate() {
animateRunning = true;
var thisTime = +new Date();
context.clearRect(0, 0, canvas.width, canvas.height);
dots.forEach(function(dot) {
if (direction) {
if (Math.abs(dot.dx - dot.x) < 0.1 && Math.abs(dot.dy - dot.y) < 0.1 && Math.abs(dot.dz - dot.z) < 0.1) {
if (thisTime - lastTime > 1000)
direction = false;
} else {
dot.x += (dot.dx - dot.x) * 0.1;
dot.y += (dot.dy - dot.y) * 0.1;
dot.z += (dot.dz - dot.z) * 0.1;
lastTime = +new Date();
}
} else {
if (Math.abs(dot.tx - dot.x) < 0.1 && Math.abs(dot.ty - dot.y) < 0.1 && Math.abs(dot.tz - dot.z) < 0.1) {
moving = false;
} else {
dot.x += (dot.tx - dot.x) * 0.1;
dot.y += (dot.ty - dot.y) * 0.1;
dot.z += (dot.tz - dot.z) * 0.1;
}
}
dot.paint();
});
if (moving) {
if ("requestAnimationFrame" in window) {
requestAnimationFrame(animate);
} else if ("webkitRequestAnimationFrame" in window) {
webkitRequestAnimationFrame(animate);
}
}
}document.getElementById(‘startBtn‘).onclick = function() {
if (moving)
return;
dots = getimgData(document.getElementById(‘name‘).value);
direction = true;
moving = true;
dots.forEach(function(dot) {
dot.tx = Math.random() * canvas.width;
dot.ty = Math.random() * canvas.height;
dot.tz = Math.random() * 250 * 2 - 250;dot.x = dot.tx;
dot.y = dot.ty;
dot.z = dot.tz;
dot.paint();
});
animate();
}
}
function getimgData(text) {
context.save();
context.font = "200px 微软雅黑 bold";
context.fillStyle = "rgba(255,255,255,1)";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(text, canvas.width / 2, canvas.height / 2);
context.restore();var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
context.clearRect(0, 0, canvas.width, canvas.height);var dots = [];
for (var y = 0; y < imgData.height; y += 6) {
for (var x = 0; x < imgData.width; x += 6) {
var i = (y * imgData.width + x) * 4;
if (imgData.data[i] >= 255) {
dots.push(new Dot(x - 3, y - 3, 0, 3));
}
}
}
return dots;
}
2.图片文字识别
<html>
<head>
<meta charset="UTF-8">
<title>文字识别</title>
</head>
<body>
<canvas id="canvas" width="880" height="1500"></canvas>
<script type="text/javascript">
var image = new Image();
image.src = ‘image.jpg‘;
var stanData = {};
var lineHeight = 24;
var letters = ‘0123456789abcdefghijklmnopqrstuvwxyz‘;
var context = document.getElementById(‘canvas‘).getContext(‘2d‘);
context.font = ‘16px 微软雅黑‘;
context.textBaseline = ‘top‘;image.onload = function() {
for (var i = 0; i < letters.length; i++) {
var letter = letters[i];
// 绘制白色背景,与图片背景对应
context.fillStyle = ‘#fff‘;
context.fillRect(0, 0, width, 18);
// 绘制文字,以获取字型数据
context.fillStyle = ‘#000‘;
context.fillText(letter, 0, 0);
// 获取字符绘制宽度
var width = context.measureText(letter).width;
stanData[letter] = {
width : width,
data : getBinary(context.getImageData(0, 0, width, 18).data)
};
// 清空该区域以获取下个字符字型数据
context.clearRect(0, 0, width, 18);
}
context.fillStyle = ‘#000‘;
context.fillText(‘512abcxyz‘, 0, 0);
findLetter(0, 0, ‘‘);alert(result);
};
var result = ‘‘;
function findLetter(x, y, str) {
console.log(x, y, str);
if (result != ‘‘)
return;
var queue = [];
for (var letter in stanData) {
if (y > lineHeight * 3) {
result = str;
break;
}
// 边界
var width = stanData[letter].width;
if (x + width > 440) {
continue;
}
// 获取该矩形区域下的灰度化0-1数据
var data = getBinary(context.getImageData(x, y, width, 18).data);
// 计算偏差
var deviation = 0, flag = true;
for (var i = 0; i < data.length; i++) {
if (data[i])
flag = false;
if (data[i] != stanData[letter].data[i])
deviation++;
}
if (letter == ‘0‘)
alert(deviation);
// 如果已经到了行末,重置匹配坐标
// if (flag) {
// findLetter(0, y + lineHeight, str + ‘\n‘);
// break;
// }
// 如果偏差量与宽度的比值小于3,则纳入匹配队列中
// 这里也是算法中的关键点,怎样的偏差量可以纳入匹配队列中
// 刚开始是直接用绝对偏差量判断,当偏差量小于某个值的时候则匹配成功,但调试过程中发现不妥之处
// 字符字型较小的绝对偏差量自然也小,这样l,i等较小的字型特别容易匹配成功
// 因此使用偏差量与字型宽度的比值作为判断依据较为合理
console.log(letter, deviation, deviation / width);
if (deviation / width < 3) {
queue.push({
letter : letter,
width : width,
deviation : deviation
});
}
}
// 如果匹配队列不为空
if (queue.length) {
// 对队列进行排序,同样是根据偏差量与字符宽度的比例
queue.sort(compare);
console.log(str, queue, queue.length);
for (var i = 0; i < queue.length && !result; ++i) {
var item = queue[i];
findLetter(x + item.width, y, str + item.letter);
}
} else {
return;
}
}// 两个匹配到的字符的比较方法,用于排序
function compare(letter1, letter2) {
return letter1.deviation / letter1.width - letter2.deviation / letter2.width;
}// 图像数据的灰度化及0-1化
function getBinary(data) {
var binaryData = [];
for (var i = 0; i < data.length; i += 4) {
binaryData[i / 4] = ((data[i] + data[i + 1] + data[i + 2]) / 3 < 200);
}
return binaryData;
}
</script>
</body>
</html>
3.3D云标签
<html>
<head>
<meta charset="UTF-8">
<style>
.tag {
display: block;
position: absolute;
text-decoration: none;
}
</style>
</head>
<body>
<div class="content" style="width: 800px;height: 800px;margin: 50px auto; position: relative;">
<a class="tag" href="javascript:void(0)">A</a>
<a class="tag" href="javascript:void(0)">B</a>
<a class="tag" href="javascript:void(0)">C</a>
<a class="tag" href="javascript:void(0)">D</a>
<a class="tag" href="javascript:void(0)">E</a>
<a class="tag" href="javascript:void(0)">A</a>
<a class="tag" href="javascript:void(0)">B</a>
<a class="tag" href="javascript:void(0)">C</a>
<a class="tag" href="javascript:void(0)">D</a>
<a class="tag" href="javascript:void(0)">E</a>
</div>
<script>
var tagEle = document.querySelectorAll(".tag"), paper = document.querySelector(".content");
var R = 300, fallLength = 500;
var tags = [];
var angleX = Math.PI / 500, angleY = Math.PI / 500;
var CX = paper.offsetWidth / 2, CY = paper.offsetHeight / 2, EX = paper.offsetLeft + document.body.scrollLeft + document.documentElement.scrollLeft, EY = paper.offsetTop + document.body.scrollTop + document.documentElement.scrollTop;function tag(ele, x, y, z) {
this.ele = ele;
this.x = x;
this.y = y;
this.z = z;
this.print = function() {
var scale = fallLength / (fallLength - this.z);
var alpha = (this.z + R) / (2 * R);
this.ele.style.fontSize = 80 * scale + "px";
this.ele.style.opacity = alpha + 0.5;
this.ele.style.zIndex = parseInt(scale * 100);
this.ele.style.left = this.x + CX - this.ele.offsetWidth / 2 + "px";
this.ele.style.top = this.y + CY - this.ele.offsetHeight / 2 + "px";
}
}(function() {
for (var i = 0; i < tagEle.length; i++) {
var k = (2 * (i + 1) - 1) / tagEle.length - 1;
var a = Math.acos(k);
var b = a * Math.sqrt(tagEle.length * Math.PI);var x = R * Math.sin(a) * Math.cos(b);
var y = R * Math.sin(a) * Math.sin(b);
var z = R * Math.cos(a);var t = new tag(tagEle[i], x, y, z);
tags.push(t);
t.print();
}
})();setInterval(function() {
var cosX = Math.cos(angleX);
var sinX = Math.sin(angleX);
var cosY = Math.cos(angleY);
var sinY = Math.sin(angleY);
tags.forEach(function(tag) {
tag.y = tag.y * cosX - tag.z * sinX;
tag.z = tag.z * cosX + tag.y * sinX;
tag.x = tag.x * cosY - tag.z * sinY;
tag.z = tag.z * cosY + tag.x * sinY;tag.print();
})
}, 20);paper.addEventListener("mousemove", function(event) {
var x = event.clientX - EX - CX;
var y = event.clientY - EY - CY;
angleY = x * 0.0001;
angleX = y * 0.0001;
});
</script>
</body>
</html>
小前端大能耐——Canvas与Javascript配合实现几个功能,码迷,mamicode.com