使用Canvas基于手势可以使树秋千
用Canvas制作能够依据手势摆动的树
依据工作的须要。制作一个摆动的树做为页面的背景。为了添加页面的交互性,我又为背景中的树添加了鼠标(触控)事件,使他可以依据鼠标(触控)做出对应的动作,当手指做上下或者左右滑动的时候树会跟着摆动。先看看终于效果。
Step1.完毕HTML页面。新建一个Tree类
完毕HTML页面后新建一个Tree类用来记录树的各个属性。当中x,y
为树根部的坐标值。branchLen,branchWidth
各自是树枝的长度与宽度,depth
为树枝的层数。canvas
用来接页面中的canvas元素(默认是ID为canvas的元素)。
function Tree(x,y,branchLen,branchWidth,depth,canvas){
this.canvas = canvas || document.getElementById('canvas');
this.ctx = this.canvas.getContext('2d');
this.x = x||0;
this.y = y||0;
this.branchLen = branchLen||0;
this.branchWidth = branchWidth||0;
var depth = depth || 5;
}
Step2.加入drawRoot方法,用来绘制树干
首先在drawRoot中画第一个枝干。
drawRoot的參数意义同上。而且在Tree类的构造函数中执行drawRoot并把Tree接受到的參数传入。最后new一个Tree类,使树根位于屏幕的底部正中心。树枝长100px,树枝宽度为8px,树枝层数为8层(临时用不上)。
var atree = new Tree(canvas.width/2-4,canvas.height,100,8,8,canvas);
在drawRoot中我们须要用lineTo()
画出树枝。树枝的起始的坐标值(x,y)
已经给出,结束的坐标值(toX,toY)
须要进行计算。第一个画的是树干,因为树干垂直于地面所以结束坐标toX
等于初始坐标x
,而结束坐标toY
等于初始y
减去树干长度branchLen
(注意坐标的0,0点在canvas的左上角)。var
toX = x;var toY = y-branchLen;
function Tree(x,y,branchLen,branchWidth,depth,canvas){
this.canvas = canvas || document.getElementById('canvas');
this.ctx = this.canvas.getContext('2d');
this.x = x||0;
this.y = y||0;
this.branchLen = branchLen||0;
this.branchWidth = branchWidth||0;
var depth = depth || 5;
this.drawRoot(this.x,this.y,this.branchLen,this.branchWidth);
}
Tree.prototype.drawRoot = function(x,y,branchLen,branchWidth){
var toX = x;
var toY = y-branchLen;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
}
var atree = new Tree(canvas.width/2-4,canvas.height,100,8,8,canvas);
执行代码:
Step3.加入drawBranch方法,用来绘制树枝
drawBranch相同是依据初始与结束坐标画出一条直线代表树枝。
与树干不同的是树枝不再是垂直与地面而是与树干保持一定的角度。并且树枝的初始值是树干的结束点(toX,toY)
。所以在drawBranch中我们增加新參数angle
用来表示树枝与树干的垂直夹角α,这样就能够依据α算出toX与toY。请看图。
这样我们在画完树干后再分别画两个不同角度的树枝。一个是30°
一个-30°
。并将传给树枝的宽度branchWidth减小一个像素。使其与树干粗细不同。
Tree.prototype.drawRoot = function(x,y,branchLen,branchWidth){
var toX = x;
var toY = y-branchLen;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
this.drawBranch(toX,toY,branchLen,branchWidth-1,30);
this.drawBranch(toX,toY,branchLen,branchWidth-1,-30);
}
Tree.prototype.drawBranch = function(x,y,branchLen,branchWidth,angle){
var angle = angle || 0;
var radian = (90-angle)*(Math.PI/180);
var toX = x+Math.cos(radian)*branchLen;
var toY = y-Math.sin(radian)*branchLen;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
}
执行代码:
Step4.改动drawBranch函数,反复画树枝
在drawBranch函数的最后再次调用两次drawBranch
this.drawBranch(toX,toY,branchLen,branchWidth-1,angle+30);
this.drawBranch(toX,toY,branchLen,branchWidth-1,angle-30);
使其调用自己完毕递归,注意这里传入的角度是在之前的角度的基础上在添加或者降低30度。
为了使递归停下来我们须要一个停止条件,就是之前一直没实用到的depth
參数。我们在每次画下一层之前使其减1表示已经完毕了一层树枝的绘制,直至depth减小到0表示绘制全然部的层数。
function Tree(x,y,branchLen,branchWidth,depth,canvas){
this.canvas = canvas || document.getElementById('canvas');
this.ctx = this.canvas.getContext('2d');
this.x = x||0;
this.y = y||0;
this.branchLen = branchLen||0;
this.branchWidth = branchWidth||0;
var depth = depth || 5;
this.drawRoot(this.x,this.y,this.branchLen,this.branchWidth,depth);
}
Tree.prototype.drawRoot = function(x,y,branchLen,branchWidth,depth){
var toX = x;
var toY = y-branchLen;
var depth = depth||5;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
depth--;
if(depth>0){
this.drawBranch(toX,toY,branchLen,branchWidth-1,30,depth);
this.drawBranch(toX,toY,branchLen,branchWidth-1,-30,depth);
}
}
Tree.prototype.drawBranch = function(x,y,branchLen,branchWidth,angle,depth){
var angle = angle || 0;
var radian = (90-angle)*(Math.PI/180);
var toX = x+Math.cos(radian)*branchLen;
var toY = y-Math.sin(radian)*branchLen;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
depth--;
if(depth>0){
this.drawBranch(toX,toY,branchLen,branchWidth-1,angle+30,depth);
this.drawBranch(toX,toY,branchLen,branchWidth-1,angle-30,depth);
}
}
执行代码:
因为树之间角度过大,并且全部树枝长度都相等,看起来并不像一棵树。所以我们须要在Tree的构造函数中增加几个參数用来调整树的姿态。
function Tree(x,y,branchLen,branchWidth,depth,canvas){
......
this.branchLenFactor = 0.8;
this.rootLenFactor = 1.2;
this.branchAngle = 20;
......
}
branchLenFactor:画每一层树枝的时候乘在branchLen上面,用来控制树枝长度。
rootLenFactor:画树根的时候乘在branchLen上面,用来控制树根长度。branchAngle: 用来控制树枝之间的角度。
Tree.prototype.drawRoot = function(x,y,branchLen,branchWidth,depth){
var toX = x;
var toY = y-branchLen*this.rootLenFactor;
var depth = depth||5;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
depth--;
if(depth>0){
this.drawBranch(toX,toY,branchLen*this.branchLenFactor,branchWidth-1,this.branchAngle,depth);
this.drawBranch(toX,toY,branchLen*this.branchLenFactor,branchWidth-1,-this.branchAngle,depth);
}
}
Tree.prototype.drawBranch = function(x,y,branchLen,branchWidth,angle,depth){
var angle = angle || 0;
var radian = (90-angle)*(Math.PI/180);
var toX = x+Math.cos(radian)*branchLen;
var toY = y-Math.sin(radian)*branchLen;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
depth--;
if(depth>0){
this.drawBranch(toX,toY,branchLen*this.branchLenFactor,branchWidth-1,angle+this.branchAngle,depth);
this.drawBranch(toX,toY,branchLen*this.branchLenFactor,branchWidth-1,angle-this.branchAngle,depth);
}
}
执行代码:
Step5.使树枝晃动起来
为了使树枝有摇晃的效果。我们仅仅须要改变树枝之间的角度branchAngle就能够了。我须要在Tree的构造函数中添加三个新属性:oBranchAngle
用来记录初始角度。branchAngleFactor
用来控制角度随时间变化的变化量;swingAngle
:随时间添加用来记录摇动的角度。
同一时候改动下drawRoot函数使其不用接受參数。调用更加方便。
function Tree(x,y,branchLen,branchWidth,depth,canvas){
......
this.branchAngle = 20;
this.oBranchAngle = this.branchAngle;
this.branchAngleFactor = 5;
this.swingAngle = 0;
......
this.drawRoot();
} Tree.prototype.drawRoot = function(){
var x = this.x,y=this.y,branchLen = this.branchLen,depth = this.depth,branchWidth = this.branchWidth;
var toX = x;
var toY = y-branchLen*this.rootLenFactor;
var depth = depth||5;
this.ctx.save();
this.ctx.strokeStyle="rgba(37, 141, 194, 0.93)";
this.ctx.beginPath();
this.ctx.lineCap = "butt";
this.ctx.lineJoin="round";
this.ctx.lineWidth = this.branchWidth;
this.ctx.moveTo(x,y);
this.ctx.lineTo(toX,toY);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.restore();
depth--;
if(depth>0){
this.drawBranch(toX,toY,branchLen*this.branchLenFactor,branchWidth-1,this.branchAngle,depth);
this.drawBranch(toX,toY,branchLen*this.branchLenFactor,branchWidth-1,-this.branchAngle,depth);
}
}
添加循环函数,在循环函数中重绘整个树。而且每次重绘都要改动branchAngle值,使大树摇动起来。atree.swingAngle++;
使摇动角度随时间变化。这里使用Math.sin(atree.swingAngle*(Math.PI/180))
能够获得一个-1至1之间的连续变化值。atree.branchAngle = Math.sin(atree.swingAngle*(Math.PI/180))*atree.branchAngleFactor+atree.oBranchAngle;
乘以系数并加在原角度上。
function loop(time){
ctx.clearRect(0,0,canvas.width,canvas.height);
atree.branchAngle = Math.sin(atree.swingAngle*(Math.PI/180))*atree.branchAngleFactor+atree.oBranchAngle;
atree.drawRoot()
requestAnimFrame(loop);
}
loop(0);
执行代码:
Step6.加入手势
这里为了省事仅仅加入了touch事件,mouse事件与touch事件的处理方法大体一致。
首先为Tree新加一个属性swingSwitch = true
用来表示大树是否摆动。当手指触控到屏幕的时候摆动停止,离开屏幕的时候摆动继续。
加入strengthX
,strengthY
两个属性;分别表示树在x轴与y轴因受到的力而移动的距离。
加入strengthXFactor
,strengthYFactor
;分别用来表示再一次滑动中x轴与y轴移动的最大距离。
function Tree(x,y,branchLen,branchWidth,depth,canvas){
......
this.swingSwitch = true;
......
this.strengthX = 0;
this.strengthY = 0;
......
}
//记录触控開始时的信息
var touchStart = {x:0,y:0,strengthX:0,strengthY:0};
document.addEventListener('touchstart',function(e){
//让树停止摆动
atree.swingSwitch = false;
touchStart.x = e.touches[0].clientX;
touchStart.y = e.touches[0].clientY;
//记录触控開始时,原strength的值
touchStart.strengthX = atree.strengthX;
touchStart.strengthY = atree.strengthY;
});
document.addEventListener('touchmove',function(e){
//阻止浏览器默认动作
e.preventDefault();
//(touchStart.x-e.touches[0].clientX)/canvas.width能够依据滑动距离获得一个0-1的值
atree.strengthX = touchStart.strengthX-(touchStart.x-e.touches[0].clientX)/canvas.width*atree.strengthXFactor;
atree.strengthY = touchStart.strengthY-(touchStart.y-e.touches[0].clientY)/canvas.height*atree.strengthYFactor;
});
document.addEventListener('touchend',function(e){
//恢复摆动
atree.swingSwitch = true;
});
改动drawBranch将strength的变化加入到角度与toX,toY的计算中,详情见凝视。
Tree.prototype.drawBranch = function(x,y,branchLen,branchWidth,angle,depth){ var angle = angle || 0;
//用strengthX乘以(depth/this.depth)使得树枝末梢对角度的变化不敏感
angle += this.strengthX*(depth/this.depth)/this.strengthXFactor*this.branchAngle;
var radian = (90-angle)*(Math.PI/180);
//用strengthX乘以(1-depth/this.depth)使得树枝末梢对角度的变化敏感
var toX = x+Math.cos(radian)*branchLen+this.strengthX*(1-depth/this.depth);
var toY = y-Math.sin(radian)*branchLen+this.strengthY*(1-depth/this.depth);
......
}
在动画循环中加入恢复代码,使strengthX,strengthY恢复为0。并添加swingSwitch的推断。
function loop(time){
......
//当swingSwitch开启时開始摆动
if(atree.swingSwitch){
//将strength恢复到0
if(atree.strengthX >0){
atree.strengthX -= 1;
}
if(atree.strengthX <0){
atree.strengthX += 1;
}
if(atree.strengthY >0){
atree.strengthY -= 1;
}
if(atree.strengthY <0){
atree.strengthY += 1;
}
atree.swingAngle++;
atree.branchAngle = Math.sin(atree.swingAngle*(Math.PI/180))*atree.branchAngleFactor+atree.oBranchAngle;
}
......
}
loop(0);
执行代码:
Step7.加入缓动效果
Step6中的恢复strengthX,strengthY的代码过于简单,动画匀速恢复到0,显得过于突兀。比較真实的情况应该是由快变慢的恢复,所以我们要为恢复代码加上缓动。首先在Tree中加入recoverStartTime = 0
用来记录恢复開始的时间。在手指离开屏幕的时候(touchend)将其赋为0,同一时候用oStrengthX
,oStrengthY
记录下来strengthX与strengthY的目标值。
function Tree(x,y,branchLen,branchWidth,depth,canvas){
......
this.recoverStartTime = 0;
......
}
function loop(time){
......
if(atree.swingSwitch){
if(atree.strengthX > 0){
if(atree.recoverStartTime == 0){
atree.recoverStartTime = time;
}
var t = time-atree.recoverStartTime;
//五次方的缓动
atree.strengthX = Math.max(atree.oStrengthX-atree.oStrengthX*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
if(atree.strengthX < 0){
if(atree.recoverStartTime == 0){
atree.recoverStartTime = time;
}
var t = time-atree.recoverStartTime;
//五次方的缓动
atree.strengthX = Math.min(atree.oStrengthX-atree.oStrengthX*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
if(atree.strengthY > 0){
if(atree.recoverStartTime == 0){
atree.recoverStartTime = time;
}
var t = time-atree.recoverStartTime;
//五次方的缓动
atree.strengthY = Math.max(atree.oStrengthY-atree.oStrengthY*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
if(atree.strengthY < 0){
if(atree.recoverStartTime == 0){
atree.recoverStartTime = time;
}
var t = time-atree.recoverStartTime;
//五次方的缓动
atree.strengthY = Math.min(atree.oStrengthY-atree.oStrengthY*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
}
......
}
document.addEventListener('touchend',function(e){
atree.recoverStartTime = 0;
atree.oStrengthX = atree.strengthX;
atree.oStrengthY = atree.strengthY;
......
});
执行代码:
Step7.使树干摇动并移至屏幕左边
改动drawRoot使树干也能够晃动,并改动var atree = new Tree(10,canvas.height,100,8,8,canvas);
使其移至左边。
Tree.prototype.drawRoot = function(){
......
//添加strength
var angle = 0;
angle += this.strengthX/this.strengthXFactor*this.branchAngle;
var radian = (90-angle)*(Math.PI/180);
var toX = x+Math.cos(radian)*branchLen*this.rootLenFactor;
var toY = y-Math.sin(radian)*branchLen*this.rootLenFactor;
......
}
var atree = new Tree(10,canvas.height,100,8,8,canvas);
执行代码:
Step8.
将动画循环中处理角度的部分加入到Tree的swing()中。
Tree.prototype.swing = function(time){
this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
if(this.swingSwitch){
if(this.strengthX > 0){
if(this.recoverStartTime == 0){
this.recoverStartTime = time;
}
var t = time-this.recoverStartTime;
this.strengthX = Math.max(this.oStrengthX-this.oStrengthX*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
if(this.strengthX < 0){
if(this.recoverStartTime == 0){
this.recoverStartTime = time;
}
var t = time-this.recoverStartTime;
this.strengthX = Math.min(this.oStrengthX-this.oStrengthX*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
if(this.strengthY > 0){
if(this.recoverStartTime == 0){
this.recoverStartTime = time;
}
var t = time-this.recoverStartTime;
this.strengthY = Math.max(this.oStrengthY-this.oStrengthY*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
if(this.strengthY < 0){
if(this.recoverStartTime == 0){
this.recoverStartTime = time;
}
var t = time-this.recoverStartTime;
this.strengthY = Math.min(this.oStrengthY-this.oStrengthY*((t=t/2000-1)*t*t*t*t + 1)+0,0);
}
this.swingAngle++;
this.branchAngle = Math.sin(this.swingAngle*(Math.PI/180))*this.branchAngleFactor+this.oBranchAngle;
}
this.drawRoot();
}
var atree = new Tree(10,canvas.height,100,8,8,canvas);
function loop(time){
atree.swing(time);
requestAnimFrame(loop);
}
loop(0);
执行代码:
如有问题或者建议请微博@UED天机。
我会及时回复
也能够收藏天机的官网,http://ued.sexy/ 经常更新了最新的教程。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
使用Canvas基于手势可以使树秋千的更多相关文章
- 游戏AI(三)—行为树优化之基于事件的行为树
上一篇我们讲到了关于行为树的内存优化,这一篇我们将讲述行为树的另一种优化方法--基于事件的行为树. 问题 在之前的行为树中,我们每帧都要从根节点开始遍历行为树,而目的仅仅是为了得到最近激活的节点,既然 ...
- 手把手教学~基于element封装tree树状下拉框
在日常项目开发中,树状下拉框的需求还是比较常见的,但是element并没有这种组件以供使用.在这里,小编就基于element如何封装一个树状下拉框做个详细的介绍. 通过这篇文章,你可以了解学习到一个树 ...
- 中文分词系列(二) 基于双数组Tire树的AC自动机
秉着能偷懒就偷懒的精神,关于AC自动机本来不想看的,但是HanLp的源码中用户自定义词典的识别是用的AC自动机实现的.唉-没办法,还是看看吧 AC自动机理论 Aho Corasick自动机,简称AC自 ...
- POJ 2763 /// 基于边权的树链剖分
题目大意: 给定n个结点,有n-1条无向边,给定每条边的边权 两种操作,第一种:求任意两点之间路径的权值和,第二种:修改树上一点的权值. 因为是一棵树,可以直接把 u点和v点间(假设u为父节点,v为子 ...
- 基于easyUI实现组织结构树图形
一. 准备工作 1. 点击此下载相关文件 2. 进入 js 文件夹,解压缩 jquery-easyui-1.5.rar 到当前文件夹 二. 在浏览器中运行 organize.html 文件,即可看到效 ...
- 基于cookie实现zTree树刷新后,展开状态不变
1.除了引用jQuery和zTree的JS外,引用cookie的JS: <script type="text/javascript" src="~/Scripts/ ...
- HTML5 Canvas简简单单实现手机九宫格手势密码解锁
原文:HTML5 Canvas简简单单实现手机九宫格手势密码解锁 早上花了一个半小时写了一个基于HTML Canvas的手势解锁,主要是为了好玩,可能以后会用到. 思路:根据配置计算出九个点的位置,存 ...
- 毕达哥拉斯树(pythagorasTree)原理解析及canvas动画实现
以前就看到了这个东西,由于太忙了最近才有时间来实现这个; 该文章适合有一定 canvas 基础的人阅读; 首先说说他的原理: The construction of the Pythagoras tr ...
- 手势识别(一)--手势基本概念和ChaLearn Gesture Challenge
以下转自: http://blog.csdn.net/qq1175421841/article/details/50312565 像点击(clicks)是GUI平台的核心,轻点(taps)是触摸平台的 ...
随机推荐
- RH133读书笔记(7)-Lab 7 Advanced Filesystem Mangement
Lab 7 Advanced Filesystem Mangement Goal: Develop skills and knowlege related to Software RAID, LVM, ...
- zepto.js 源码注释备份
/* Zepto v1.0-1-ga3cab6c - polyfill zepto detect event ajax form fx - zeptojs.com/license */ ;(funct ...
- 跑openstack命令错误【You must provide a username via either -...】
openstack设置环境,openstack该服务已经启动.当运行openstack当一个命令,如nova service list例如,下面的错误信息 You must provide a use ...
- VB.NET之错误异常处理
相对于VB而言,VB.NET中引入了很多特色.当中最吸引我的就是引入了结构化异常处理. 尽管VB.NET仍然支持OnError Goto类型的异常处理,可是这样做并非非常好.相比而言,结构化异常处理更 ...
- NSIS:使用PassDialog插件实现密码安装(卸载)功能
原文 NSIS:使用PassDialog插件实现密码安装(卸载)功能 有时,出于特殊的需求,我们要给安装或卸载程序加一个密码,只有输入了正确的密码才可以继续.比如: 下面我们使用插件来实现安装密码: ...
- Intelli idea 常用快捷键汇总
To navigate to the implementation(s) of an abstract method, position the caret at its usage or its n ...
- ubuntu13.10 下一个 g++和gcc 4.8不兼容的问题不能被安装
前gcc这是4.8.x.导致g++不能用.因此,要 网上找了很多办法,在安装过程中或这些以下问题的出现: 1. Unable to exec g++.real: 没有那个文件或文件夹 2. 下列软件包 ...
- git fetch, merge, pull, push需要注意的地方(转)
在git操作中,我们经常会用到fetch, merge, pull和push等命令,以下是一些我们需要注意的地方. 给大家准备了参考资料: 1. Whatʼs a Fast Forward Merge ...
- 创建线程的两种方式:继承Thread类和实现Runnable接口
第一种方式:继承Thread类 步骤:1.定义类继承Thread 2.覆写Threa类的run方法. 自定义代码放在run方法中,让线程运行 3.调用线程的star方法, 该线程有两个作用:启动线程, ...
- Log4j 2.0在具体解释发展先进的使用—SocketAppender远程输出(五岁以下儿童)
Log4j2的Appenders充分考虑输出日志事件.包装和过滤可以被转发,它包含的主要输出到本地文件.输出到远程主机, 文件包.注射.而且,根据该日志文件的时间点.自己主动文件大小的储存条件. 例如 ...