![0640477cf5484611f9ba1f5880c5b81e.png](https://img-blog.csdnimg.cn/img_convert/0640477cf5484611f9ba1f5880c5b81e.png)
案例一:JS根据用户照片和姓名生成海报
需求描述
用户点击按钮进行照片上传
照片上传完成后,将照片进行裁剪,并和海报背景、姓名等组合得到海报
将生成的海报上传
效果大概如下:
海报背景:
![f5f03e3ae73685fbfa8f66c8c1145c3f.png](https://img-blog.csdnimg.cn/img_convert/f5f03e3ae73685fbfa8f66c8c1145c3f.png)
成品:
![565b111912cce2cf5163c0262a668b14.png](https://img-blog.csdnimg.cn/img_convert/565b111912cce2cf5163c0262a668b14.png)
实现过程
1、初始化 canvas
canvas#poster-canvas(width='960' height='1280')
function initCanvas() { canvasCtx = document.getElementById("poster-canvas").getContext('2d');}
2、绘制海报背景
海报背景为预先提供的一张照片,将其设置到一个隐藏的 img 标签里面,
并且预留一个 canvas 元素用于绘制海报:
img.poster-background(src='/assets/xxx/poster-background.jpeg')
页面加载完成后,将海报背景绘制到 canvas 内:
$('img.poster-background').on('load', function () {
var backgroundImg = $('img.poster-background')[0];
canvasCtx.drawImage(backgroundImg, 0, 0, 960, 1280);
renderName();
});
海报背景绘制完成之后,需要将用户姓名绘制到特定位置。由于用户姓名长度不一,因此需要进行计算确定字体大小:
function renderName() {
var name = $('input[name="chName"]').val();
var fontSize;
if (name.length < 3) {
fontSize = 100;
} else {
fontSize = parseInt(320 / name.length);
}
canvasCtx.font = "bold " + fontSize + "px Courier New";
canvasCtx.fillStyle = "#de071b";
canvasCtx.fillText(name, 20, 1066);
}
3、上传照片
使用 file 类型的 input 元素,因为页面上表现为点击按钮,因此使用经典的将 input 元素透明化并覆盖按钮的方法:
a.upload-btn input#photo(type='file' name='photo' accept='image/jpeg, image/png')
| 上传自己的照片生成专属海报
.upload-btn input {
position: absolute;
left: 0;
top: 0;
opacity: 0;
width: 100%;
height: 68px;
cursor: pointer;
}
然后监听 input 元素的 change 事件,然后使用 FormData API 构造表单数据,使用 ajax 进行异步上传,照片上传完成之后。得到一个地址,将这个地址设置到页面上预留的一个 img 标签里面:
$('#photo').on('change', function (e) {
var file = e.target.files[0];
var type = file.type;
if (type !== 'image/jpeg' && type !== 'image/png') {
window.toastr.error('请上传 jpg 或 png 格式的图片');
} else {
var formData = new FormData();
formData.append('avatar', file);
$.ajax({
type: 'POST',
url: '/upload_url',
data: formData,
contentType: false,
processData: false,
success: function(result) {
var avatarUrl = result.data.url;
$('img.avatar').attr('src', avatarUrl);
},
error: function(err) {
}
});
}
});
4、绘制照片
海报中放置照片的区域为正方形,但是用户上传的照片却不一定,因此需要对照片进行裁剪,裁剪的原则为取照片中间部分。然后将裁剪参数传进 canvas 的 drawImage 方法,进行绘制:
$('img.avatar').on('load', function () {
var avatarImg = $('img.avatar')[0];
var originWidth = avatarImg.width;
var originHeight = avatarImg.height;
var newWidth, cutStartX, cutStartY;
if (originWidth < originHeight) {
newWidth = originWidth;
cutStartX = 0;
cutStartY = (originHeight - originWidth) / 2;
} else if (originWidth > originHeight) {
newWidth = originHeight;
cutStartX = (originWidth - originHeight) / 2;
cutStartY = 0;
} else {
newWidth = originWidth;
cutStartX = 0;
cutStartY = 0;
}
canvasCtx.drawImage(avatarImg, cutStartX, cutStartY,newWidth, newWidth, 0, 0, 960, 960); uploadPoster();
});
前面绘制海报背景和这里绘制照片,调用的是同一个方法,只不过后者多传进去了裁剪参数。但是需要注意的是,裁剪参数是在绘制位置之前传进去的,而不是简单的补在后面:
canvasCtx.drawImage(backgroundImg, 0, 0, 960, 1280);
canvasCtx.drawImage(avatarImg, cutStartX, cutStartY, newWidth, newWidth, 0, 0, 960, 960);
5、上传海报
依然使用 FormData API,因此需要先用 canvas 构造一个 Blob 对象。
新版本的 Chrome 和 Firefox 支持 canvas 的 toBlob 方法,可以直接使用:document.getElementById("poster-canvas").toBlob(function (blob) {});其它浏览器里,可以先用 toDataURL方法得到 base64 格式的图片数据,再转为 Blob:
var blob = dataURLtoBlob(document.getElementById("poster-canvas").toDataURL());function dataURLtoBlob(dataurl) {
if (dataurl.indexOf('base64') < 0) {
dataurl = 'data:image/jpeg;base64,' + dataurl;
}
var arr = dataurl.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while (n --) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type: mime});
}
然后进行上传,步骤和前面上传照片一致:
var formData = new FormData();
formData.append('poster', blob);
$.ajax({
type: 'POST',
url: '/upload_poster_url',
data: formdata,
contentType: false,
processData: false,
success: function(result) {
},
error: function(err) {
}
});
案例二:JS实现简易刻度时钟
如图所示,利用JS实现简易的刻度时钟;
原理如下:利用60等份的li进行布局,li两两之间的间隔为6deg,把基点定在圆心上,使得li圆形分布。然后另外设置三条针线的样式的位置,基点同样定在圆心上,然后秒针每秒动6deg,分针每秒动1/60deg,时针每秒动1/3600deg。
布局代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css" id="sty">
*{
margin: 0;
padding: 0;
list-style: none;
}
#wrap{
width: 200px;
height: 200px;
border: 1px solid #000;
border-radius: 50%;
margin: 20px auto;
position: relative;
}
#wrap ul{
position: relative;
}
#wrap ul li{
width: 2px;
height: 6px;
background: #000;
position: absolute;
left: 99px;
top: 0;
-moz-transform-origin: center 100px;
}
#wrap ul li:nth-child(5n){
height: 10px;
}
#con{
width: 10px;
height: 10px;
background: #000;
border-radius: 50%;
position: absolute;
left: 95px;
top: 95px;
}
#hour{
width: 5px;
height: 70px;
background: red;
border-radius: 50%;
position: absolute;
left: 98px;
top: 35px;
-moz-transform-origin: center 65px;
}
#min{
width: 3px;
height: 85px;
background: #000;
border-radius: 50%;
position: absolute;
left: 98.5px;
top: 20px;
-moz-transform-origin: center 80px;
}
#sec{
width: 2px;
height: 100px;
background: gray;
border-radius: 50%;
position: absolute;
left: 98.5px;
top: 20px;
-moz-transform-origin: center 80px;
}
</style>
</head>
<body>
<div id="wrap">
<ul id="list">
</ul>
<div id="hour"></div>
<div id="min"></div>
<div id="sec"></div>
<div id="con"></div>
</div>
</body>
</html>
布局代码里需要注意的是:每隔四个刻度就有一个刻度比较长,所以我们在设置样式的时候要特别注意加上:#wrap ul li:nth-child(5n){height: 10px;}。第5n个的长度变长。
JS代码中主要搞清楚三针之间的度数关系就好做了,代码如下:
<script type="text/javascript">
window.οnlοad=function(){
var oWrap=document.getElementById('wrap');
var oList=document.getElementById('list');
var oSty=document.getElementById('sty');
var tump='';
for(var i=0;i<60;i++){
var aLi=document.createElement('li');
oList.appendChild(aLi); tump+='#wrap ul li:nth-child('+(i+1)+'){transform: rotate('+(i+1)*6+'deg);}'; oSty.innerHTML+=tump;
}
var oSec=document.getElementById('sec');
var oMin=document.getElementById('min');
var oHour=document.getElementById('hour');
function time(){
var date=new Date();
var s=date.getSeconds();
var m=date.getMinutes()+(s/60);
var h=date.getHours()+(m/60);
oSec.style.transform='rotate('+s*6+'deg)';
oMin.style.transform='rotate('+m*6+'deg)';
oHour.style.transform='rotate('+h*30+'deg)';
}
time();
setInterval(time,1000);
}
</script>
案例三:JS实现的自动打字效果
本文实例讲述了JS实现的自动打字效果。分享给大家供大家参考,具体如下:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>js typing</title>
</head>
<body>
<div id='divTyping'></div>
<script>
var str = 'js 实现的 打字效果,感觉蛮有趣的。';
var i = 0;
function typing(){
var divTyping = document.getElementById('divTyping');
if (i <= str.length) {
divTyping.innerHTML = str.slice(0, i++) + '_';
setTimeout('typing()', 200);//递归调用
}
else{
divTyping.innerHTML = str;//结束打字,移除 _ 光标
}
}
typing();
</script>
</body>
</html>