小前端大能耐——Canvas与Javascript配合实现几个功能

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

时间: 2025-01-04 06:03:04

小前端大能耐——Canvas与Javascript配合实现几个功能的相关文章

网站前端_JavaScript-项目经验.纯JavaScript实现客户端的分页功能?

项目简介: 说明: 此项目属于医院电子病例系统,由于历史原因,整个系统后台基于Java开发,前端使用Html+CSS+原生JavaScript,项目功能模块要求必须纯JS实现,而此次的任务是为住院病例页面编写一个客户端分页功能. 实现思路: 1. 基于客户端分页的前提是数据已经加载完毕,所以此功能模块必须等待数据加载完毕后再加载 2. 基于客户端分页的首页只需要显示24个患者信息即可 3. 上一页/当前页/下一页功能类似,基于当前页面传递同样的参数(页码, 限制患者数),所以自然而然想到了递归,

微信小程序,前端大梦想(一)

小程序框架MINA简介 微信公众平台"小程序"具有不是APP胜似APP的效果,是一种不需要下载安装即可使用的应用,它实现了应用"触手可及"的梦想,用户扫一扫或者搜一下即可打开应用.也体现了"用完即走"的理念,用户不用关心是否安装太多应用的问题.应用将无处不在,随时可用,但又无需安装卸载. 去年9月22日,微信公众平台向外发出200个"小程序"内测邀请函.该"小程序"即去年年初腾讯曾对外介绍的微信"

前端大神总结的学习方法【引用】

下面是一些前端大师的学习方法,目前我正在学习,希望对大家有用! 转载出处: https://github.com/qiu-deqing/FE-learning FE-learning 必备基础技能 基本开发工具 学习方法和学习目标 入门之路 继续提高 一些个人经历 LingyuCoder的学习经历 工具 技能 语言基础 进阶 项目 未来 其他 入门书 一些不错的网站 历程 MrRaindrop的学习经历 缘起 项目,下一个项目 收集癖和知识管理 跟对神 读书 前端的定位 最后 结合个人经历总结的

15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)

15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经验的凝练和总结,能更大限度的优化代码以及对已有代码的合理重构.作为一名合格的前端工程师,学习设计模式是对自己工作经验的另一种方式的总结和反思,也是开发高质量,高可维护性,可扩展性代码的重要手段. 我们所熟知的金典的几大框架,比如jquery, react, vue内部也大量应用了设计模式, 比如观察

前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型

前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的影响,单单是自己的念想受到了一定得局限,想法不能够像平地而起的高楼大厦建成一样.可是那大楼也是有烂尾的呀,我觉得最重要的还是外在环境与个人观念的先决条件,决定了拖延症的症状的好坏,有那么一些人,它也有拖延症,但是它在拖的中间,想的更多,看的更远.事情在做的时候更加有条不紊,这拖延症这样看来,它也是好

web前端大神整理:CSS 布局经典问题

本文来自前端大神的整理,主要对 CSS 布局中常见的经典问题进行简单说明,并提供相关解决方案的参考链接,涉及到三栏式布局,负 margin,清除浮动,居中布局,响应式设计,Flexbox 布局,等等. CSS 基础知识 下面几个入门教程不错: 幕课网 – HTML+CSS基础课程:偏基础,可以在线练习和预览 MDN – CSS入门教程: MDN 的官方文档 学习 CSS 布局:排版和配色特别舒服,简短但不深入,适合概览入门 CSS 定位问题 主要就是经典的绝对定位,相对定位问题. 10个文档学布

android FakeWindow的小应用大用途

在windowmanager里面有一个FakeWindow,细致一看也就是一个透明的应用覆盖到屏幕的最前端,这样有什么优点呢?首先我们还是从应用的需求来看这个问题.在android系统里无论是手机还是平板,状态栏一般都是在的,导航栏在有些设备里面是没有的,由于android须要的那些HOME\BACK\MENU\SERCACH可能已经做在触摸屏上,或者是其它一些低成本的触摸小按键上或者硬按键上,可是也有非常多机器是没有这些的,那么就须要一个导航栏了,这样前期背景就清楚了. 有了导航栏跟状态栏,好

五个小例子教你搞懂 JavaScript 作用域问题

众所周知,JavaScript 的作用域和其他传统语言(类C)差别比较大,掌握并熟练运用JavaScript 的作用域知识,不仅有利于我们阅读理解别人的代码,也有助于我们编写自己的可靠代码. 下面笔者将使用五个小例子来给大家分析下 JavaScript 的作用域要注意的问题. 感谢 例子的来源 (这5个例子我做错了2个 [嘿嘿,尽情鄙视吧],笔者就是要 死磕自己,奉献大家!) 先给出五个例子: 每个例子旁边都会给出答案的链接,如果你全部都正确了,你可以忽略这篇短文,并深深的鄙视下笔者. 例一:

【小命令大作用】第三篇 ls 命令 - 查看目录或文件

ls命令查看目录或文件 [语法] ls [选项] (路径) [常用选项] -l    长文本查看文件=windows的右键属性 -d    查看目录 PS:一般配合-l使用 -a    查看目录下所有文件(包括隐藏文件) -i    显示索引号(inode) -F    给文件加标识 -t    以文件修改时间排序 -r    倒序排列 -k    以K为单位显示大小 [实例] 查看/etc/最近修改的文件并以长格式显示 [[email protected] ~]# ls -lrt /etc/