请帮忙看看 html5 canvas 如何做到文字旋转?我的代码出不来旋转。。
首先:save是保存当前状态,restore是返回上一次保存的状态。
你画出"文字1",后旋转,后返回(相当于没有旋转),最后才画"文字2",所以两次文字都不旋转。
其次:rotate()的参数不是角度制,而是弧度制(MahtPI相当于180度)。
所以要旋转30角度必须这样写crotate(MathPI/6);
再次:旋转之后的方向都发生了改变。
就是说如果你先在x=200,y=200的地方画了东西,然后旋转30度,然后在x=200,y=200的地方画了另一个东西,这两个东西将不在同一个地方。(可以想象画画得人绕着坐标原点旋转了30度,而画布位置没变)
最后:附上能看见效果的代码。
<!DOCTYPE HTML>
<html>
<head><title>canvas</title><meta charset="utf-8" /></head>
<body>
<canvas id="canvas" width="600"height="400" style="border:1px solid black">
<p>Your browserdoes not support the canvas element!</p>
</canvas>
<script type="text/javascript">
var canvas =documentgetElementById("canvas");
var c =canvasgetContext("2d");
cfillStyle = '#000000';
cfont = 'bold 16px verdana';
cfillText("文字1",200,30);
csave();
crotate(MathPI/6);
cfillText("文字2",200,30);
crestore();
</script>
</body>
</html>
2、创建图表
为了创建图表,我们要实例化一个Chart对象。为了完成前面的步骤,首先需要需要传入一个绘制图表的2d context。
1
<canvas id="myChart" width="400" height="400"></canvas>
1
2
3
//Get the context of the canvas element we want to select
var ctx = documentgetElementById("myChart")getContext("2d");
var myNewChart = new Chart(ctx)PolarArea(data);
当我们完成了在指定的canvas上实例化Chart对象之后,Chartjs会自动针对retina屏幕做缩放。
Chart对象设置完成后,我们就可以继续创建Chartjs中提供的具体类型的图表了
使用jQuery chart 绘制柱状图(Bar chart)
代码如下:
<canvas width="300" height="100" id="myCanvas" stylle="width:300px;height:100px;"></canvas><script type="text/javascript">
var canvas=documentgetElementById('myCanvas');
var ctx=canvasgetContext('2d');
var yinliang=70;
var zongyinliang=100;
var per;
var x0=15;
var y0=50;
var w=200;
var h=10;
var circle={
x:0,
y:0,
r:10
}
var op;
refresh();//手动刷新一次
canvasaddEventListener("mousedown",mouseDownHandler);
/
鼠标按下
@param e
/
function mouseDownHandler(e){
var o=getCanvasPos(canvas,e);
op=o;
//consolelog(o)
var distance=Mathsqrt((ox-circlex)(ox-circlex)+(oy-circley)(oy-circley));
//consolelog(distance)
if(distance<circler){
consolelog("在圆上按下鼠标,开始拖动");
windowaddEventListener("mousemove",mouseMoveHandler);
windowaddEventListener("mouseup",mouseUpHandler);
windowaddEventListener("onmouseout",mouseUpHandler);
}
}
/
鼠标移动。
拖动,更新音量。
@param e
/
function mouseMoveHandler(e){
//consolelog("mousemove");
var o=getCanvasPos(canvas,e);
var dx=ox-opx;
per=(circlex+dx-x0)/w;
if(per<0)per=0;
if(per>1)per=1;
circlex=x0+perw;
yinliang=perzongyinliang;
refresh();
op=o;
}
/
鼠标弹起,或者浏览器窗口失去焦点。
取消拖动。
@param e
/
function mouseUpHandler(e){
//consolelog("mouseup");
windowremoveEventListener("mousemove",mouseMoveHandler);
windowremoveEventListener("mouseup",mouseUpHandler);
windowremoveEventListener("onmouseout",mouseUpHandler);
}
/
获取鼠标在canvas上的坐标。
参考:http://blogcsdnnet/u010484625/article/details/46047695
@param canvas
@param e
@return {x:0,y:0}
/
function getCanvasPos(canvas,e) {
var rect = canvasgetBoundingClientRect();
return {
x: eclientX - rectleft (canvaswidth / rectwidth),
y: eclientY - recttop (canvasheight / rectheight)
};
}
/
刷新显示。
/
function refresh(){
//清空画布
ctxfillStyle='#ffffff';
ctxfillRect(0,0,300,200);
ctxsave();
//画底槽
ctxlineCap="round";
ctxstrokeStyle="#E5E5E5";
ctxlineWidth=h;
ctxbeginPath();
ctxmoveTo(x0,y0);
ctxlineTo(x0+w,y0);
ctxstroke();
//根据音量计算圆的位置
per=yinliang/zongyinliang;
if(per<0)per=0;
if(per>1)per=1;
circlex=x0+perw;
circley=y0;
//画音量条
ctxstrokeStyle="#BABABA";
ctxbeginPath();
ctxmoveTo(x0,y0);
ctxlineTo(x0+wper,y0);
ctxstroke();
//画圆
ctxfillStyle="#1B8ECC";
ctxarc(circlex,circley,circler,0,2MathPI);
ctxfill();
//画文字
ctxfillStyle="#000000";
ctxfont="14px Microsoft YaHei";
ctxfillText("音量:"+parseInt(yinliang),x0+w+15,y0+5);
ctxrestore();
}
</script>
photoshop魔棒抠出的图怎么直接保存?
1、打开PhotoShop,点击“文件”,再点击“打开”,将你要抠的原打开。
2、然后,点击左侧工具栏内的“魔棒工具”,注意在选区上设置为添加到选取,然后不断单击你要抠的局部,这里就是点击那个中的铅笔,直到闪烁的蚂蚁线把整个兔子包围,如图所示
3、在上方菜单栏中选择“文件”,“新建”,新建一个透明的图层;
4、将刚才的兔子,按住上方合并框,将它单独拉出来,向新建的透明图层拖过去。这样就完成了素材的整个抠图过程。
5、点击菜单栏中的“文件”,点击“存储为”,将进行保存。注意,要将格式设置为“png格式”
求教如何把下面网站的canvas里面的弄下来!就是那些兔子之类的!不知道你想要的是哪张,直接下载的是没有动画效果的。
兔子拉血怎么办你确定是拉血么是血尿么
什么样的尿算正常尿,红尿是怎么回事,尿钙是什么样的,有什么危险,我们该怎么办。。。。
嗯,如果你是新人,可能对这些还有些困惑,没关系,我收集了一些各种尿的,咱们一起来辩一辩,如果你发现有叙述不够准确的地方,千万要告诉我,我在来做修改
下面的只是个参考,具体情况还要根据你兔兔实际情况及医院检查为准
正常兔兔的尿液多为微黄、**、咖啡色、白色,不浓稠、无浑浊、无沉淀物、无残留物,见下图
偶尔也会见到橘红色、铁锈红、砖红色这种颜色深的红尿,有的是在排出体外被氧化后变成的,有的是直接排出的。
这类颜色的尿多与兔兔所吃进去的食物、个体差异、温度变化、体内缺水或服用某种药物等都有关,通常都能在短时间内恢复正常,只要兔兔精神正常、吃喝正常,你就不用太担心,这也算的上是正常尿。
出现上面这些多色的红尿,你注意观察就行,让兔兔多喝水,检查一下所吃的食物有没有更改过,可以做一下食物调整,看尿的颜色有没有恢复原状。如持续性的红尿,而且兔兔精神也跟以前不同,有条件的可以收集些尿样去医院做下化验。
真正的血尿是鲜红的,多发生在成兔、老年兔身上。
泌尿系统感染(肾、尿路、膀胱)、泌尿系统结石(肾、尿路、膀胱)、子宫病变(母兔)都有可能造成血尿的发生,若出现这样的血尿,一定要在第一时间去医院做检查治疗。
血尿外观看有时候与正常尿液一样,肉眼看不出,有时候会一抹浅浅的血混在尿液中,捎带有血腥味,一般比较粘稠,用卫生纸蘸会比较明显,收集化验的尿样需没污染。
此文章与均转自兔子吧后花园
h5中的canvas有非常强大的绘图功能
1渲染上下文
canvas起初是空白的。为了展示,首先脚本要找到渲染上下文,然后在它的上面绘制。<canvas>元素有一个叫做getcontext()的方法,这个方法是用来渲染上下文和它的绘画功能,getContext只有一个参数,上下文的格式。对于2D图像而言,你可以使用CanvasRenderingContext2D
绘制矩形
canvas提供了三种方法绘制矩形
fillRect(s,y,width,height)
绘制一个填充的矩形
strokeRect(x,y,width,height)
绘制一个矩形的边框
clearRect(x,y,width,height)
清除指定矩形区域,让清除部分完全透明
绘制路径
图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的集合。一个路径,甚至一个子路径,都是闭合的。使用绘制路径绘制图形需要一些额外的步骤。
1首先,你需要创建路径起始点。
2然后你使用画图命令去画出路径。
3之后你把路径封闭。
4一旦路径生成,你就能通过描边或填充路径区域来渲染图形。
以下是所要用到的函数:
beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径
closePath()
闭合路径之后图形绘制命令又重新指向到上下文中
stroke()
通过线条来绘制图形轮廓
fill()
通过填充路径的内容区域生成实心的图形
移动笔触
一个非常有用的函数,而这个函数实际上兵不能画出任何东西,也是上面所描述的路径列表的一部分,这个函数就是moveTo()。或者你可以想象以下在纸上作业,一直钢笔或者铅笔的笔尖从一个点到另一个点的移动过程。
moveTo(x,y)
将笔触移动到指定的坐标x以及y上。
线
绘制直线,需要用到的方法lineTo(0
lineTo(x,y)
绘制一条从当前位置到指定x以及y位置的直线。
该方法有两个参数:x以及y,代表坐标系中直线结束的点。开始点和之前的绘制路径有关,之前路径的结束点就是接下来的开始点。开始点也可以通过moveTo()函数改变。
注意:路径使用填充(filled)时,路径自动闭合,使用描边(stroked)则不会闭合路径。如果没有添加闭合路径closePath()到描述三角形函数中,则只绘制了两条线段,并不是一个完整的三角形。
圆弧
绘制圆弧或者圆,我们使用arc()方法。当然也可以使用arcTo(),不过这个的实现并不是那么的可靠,所以我们这里不做介绍。
arc(x,y,radius,startAngle,endAngle,anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
arcTo(x1,y1,x2,y2,radius)
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
该方法有五个参数:x,y为绘制圆弧所在圆上的圆心坐标。radius为半径。startAngle以及endAngle参数用弧度定义了开始以及结束的弧度。这些都是以x轴为基准。参考anticlockwise为一个布尔值。为true时,是逆时针方向,否则顺时针方向。
贝塞尔以及二次贝塞尔
一般用来绘制复杂有规律的图形。
quadraticCurveTo(cp1x,cp1y,x,y)
绘制二次贝塞尔曲线,x,y为结束点,cp1x,cp1y为控制点。
bezierCurveTo(cp1x,cp1y,cp2x,cp2Y,x,y)
绘制三次贝塞尔曲线,x,y为结束点,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二。
矩形
同样也有rect(0方法,将一个矩形路径增加到当前路径上。
rect(x,y,width,height)
绘制一个左上角坐标为(x,y),高度为width以及height的矩形。
当该方法执行的时候,moveTo(0方法自动设置坐标参数(0,0)。也就是说,当前笔触自动重置为默认坐标。
Path2D对象
为了简化代码和提高性能,Path2D对象已可以在较新版本的浏览器中使用,用来缓存或记录绘画命令,这样你将能快速的回顾路径。
Path2D()
所有的路径方法比如moveTo,rext,arc或quadraticCurveTo()等,如我们前面见过的,都可以在Path2D中使用。
Path2D API中添加了addPath作为将path结合起来的方法。当你想要从几个元素中来创建对象时,这将会很实用。
比如:
Path2DaddPath(path,[,trnasform])
添加一条路径到当前路径(可能添加了一个变换矩形)。
使用SVG paths
新的Path2D API有另一个强大的特点,就是使用SVG path data来初始化canvas上的路径。这将使你获取路径时可以以SVG或canvas的方式来重用它们。
如 var p=new Path2D("M10 10 h 80 v 80 h -80 Z");
这条路径将先移动到点(M10 10)然后再水平移动80个单位(h,80),然后下移80个单位(v,80),接着左移80个单位(h-80),再回到起点处(z)。
色彩 Colors
如果我们想给图形上色,有两个重要的属性可以做到:
fillStyle =color
设置图形的填充颜色
strokeStyle=color
设置图形轮廓的颜色
color可以是表示CSS颜色值的字符串,渐变对象或者团对象。在默认情况下,线条和填充颜色都是黑色(CSS 颜色值 #000000)。
注意:一旦您设置了strokeStyle或者fillStyle的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置fillStyle或strokeStyle的值。
透明度
除了可以绘制实色图形,我们还可以用canvas来绘制半透明的图形。通过设置globalAlpha属性或者使用一个半透明颜色作为轮廓或填充的样式。这个属性值影响到canvas里所有图形的透明度,有效值的范围是00(完全透明)到10(完全不透明),默认是10
rgba()示例
该例是画矩形。这里我们可以看出,rgba()可以分别设置轮廓和填充样式,因而具有更好的操作性和使用弹性。
function draw() {
var ctx = documentgetElementById('canvas')getContext('2d');
// Draw background
ctxfillStyle = 'rgb(255,221,0)';
ctxfillRect(0,0,150,375);
ctxfillStyle = 'rgb(102,204,0)';
ctxfillRect(0,375,150,375);
ctxfillStyle = 'rgb(0,153,255)';
ctxfillRect(0,75,150,375);
ctxfillStyle = 'rgb(255,51,0)';
ctxfillRect(0,1125,150,375);
// Draw semi transparent rectangles
for (var i=0;i<10;i++){
ctxfillStyle = 'rgba(255,255,255,'+(i+1)/10+')';
for (var j=0;j<4;j++){
ctxfillRect(5+i14,5+j375,14,275)
}
}}
线性Line Styles
可以通过一系列属性来设置线的样式
lineWidth=value
lineCap=type
lineJoin=type
miterLimit=value
lineWidth属性的例子
这个属性设置当前绘线的粗细。属性值必须为正数。默认值是10。
线宽是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半。因为画布的坐标并不和像素直接对应,当需要获得精确的水平或垂直线的时候要特别注意。
如果你想要绘制一条从 (3,1) 到 (3,5),宽度是 10 的线条,你会得到像第二幅图一样的结果。实际填充区域(深蓝色部分)仅仅延伸至路径两旁各一半像素。而这半个像素又会以近似的方式进行渲染,这意味着那些像素只是部分着色,结果就是以实际笔触颜色一半色调的颜色来填充整个区域(浅蓝和深蓝的部分)。这就是上例中为何宽度为 10 的线并不准确的原因。
要解决这个问题,你必须对路径施以更加精确的控制。已知粗 10 的线条会在路径两边各延伸半像素,那么像第三幅图那样绘制从 (35,1) 到 (35,5) 的线条,其边缘正好落在像素边界,填充出来就是准确的宽为 10 的线条。
对于那些宽度为偶数的线条,每一边的像素数都是整数,那么你想要其路径是落在像素点之间 (如那从 (3,1) 到 (3,5)) 而不是在像素点的中间。同样,注意到那个例子的垂直线条,其 Y 坐标刚好落在网格线上,如果不是的话,端点上同样会出现半渲染的像素点。
虽然开始处理可缩放的 2D 图形时会有点小痛苦,但是及早注意到像素网格与路径位置之间的关系,可以确保图形在经过缩放或者其它任何变形后都可以保持看上去蛮好:线宽为 10 的垂线在放大 2 倍后,会变成清晰的线宽为 20,并且出现在它应该出现的位置上。
lineCap属性
属性lineCap的值决定了线段端点显示的样子。它可以为下面的三种的其中之一:butt,round,square。默认是butt。
lineJoin属性
lineJoin的属性值直接决定了图形中两线段连接处所显示的样子。它可以是这三种之一:round,bevel和miter默认是miter。
miterLimit 属性的演示例子
As you've seen in the previous example, when joining two lines with themiter option, the outside edges of the two joining lines are extended up to the point where they meet For lines which are at large angles with each other, this point is not far from the inside connection point However, when the angles between each line decreases, the distance (miter length) between these points increases exponentially
就如上一个例子所见的应用 miter 的效果,线段的外侧边缘会延伸交汇于一点上。线段直接夹角比较大的,交点不会太远,但当夹角减少时,交点距离会呈指数级增大。
The miterLimit property determines how far the outside connection point can be placed from the inside connection point If two lines exceed this value, a bevel join will be drawn
miterLimit 属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,连接效果会变成了 bevel。
I've made a little demo in which you can set miterLimit dynamically and see how this effects the shapes on the canvas The blue lines show where the start and endpoints for each of the lines in the zig-zag pattern are
我做了一个演示页面,你可以动手改变 miterLimit 的值,观察其影响效果。蓝色辅助线显示锯齿折线段的起点与终点所在的位置。
渐变Gradients
我们可以用线性或者径向的渐变来填充或者描边
用下面的方法新建canvasGadient对象,并且赋给图形的fillStyle或strokeStyle属性。
createLinearGradient(x1,y1,x2,y2) 方法接受4个参数,标书渐变的起点(x1,y1)与终点(x2,y2)。
createRadiaGradient(x1,y1,r1,x2,y2,r2)方法接受6个参数,前三个定义一个以(x1,y1)为原点,半径为r1的圆,后三个参数则定义另一个以(x2,y2)为原点,半径为r2的圆。
创建出canvasStop对象后,我们就可以用addColorStop方法给它上色了。
addColorStop(position,color)
addcolorStop方法接受两个参数,position参数必须是一个00与10之间的数值,表示渐变中颜色所在的相对位置。例如,05表示颜色会出现在正中间。color参数必须是一个有效的CSS颜色值(如#FFF,rgba(0,0,0,1)等等)。
图案 Patterns
实现图案的效果,有一个更加简单的方法:createPattern。
createPattern(image,type)
Image可以是一个Image对象的引用,或者另一个canvas对象。Type必须是下面的字符串之一:repeat,repeat-x,repeat-y,no-repeat。
注意:用canvas对象作为Image参数在Firefox 15(Gecko 18)中是无效的。
图案的应用于渐变类似,创建出一个pattern之后,赋给fillStyle或strokeSty le属性即可。
与drawImage有点不同,你需要确认image对象已经装载完毕,否则图案可能效果不对的。
对于Firefox浏览器,目前只支持属性repeat,如果赋其他值,什么效果都没有的。
阴影Shadows
shadowOffsetX=float
shadowOffsetY=float
shadowBlur=float
shadowColor=color
shadowOffsetX和shadowOffsetY用来设定阴影在X和Y轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,他们默认都是0。
shadowBlur用于设定阴影的模糊成都,其数值并不跟像素挂钩,也不受变换矩阵的影响,默认为0。
shadowColor是标准的CSS颜色值,用于设定阴影颜色效果,默认是全透明的黑色。
Canvas 填充规则EDIT
When using fill (or clip and isPointinPath) you can optionally provide a fill rule algorithm by which to determine if a point is inside or outside a path and thus if it gets filled or not This is useful when a path intersects itself or is nested
当我们用到fill(或者clip和isPointinPath)你可以选择一个填充规则,该填充规则根据某处在路径的外面或者里面来决定该处是否被填充,这对于自己与自己路径相交或者路径被嵌套的时候是有用的。
Two values are possible:
"nonzero": The non-zero winding rule, which is the default rule
"evenodd": The even-odd winding rule
两个可能的值:
"nonzero": non-zero
winding rule, 默认值
"evenodd": even-odd
winding rule
In this example we are using the evenodd rule
这个例子,我们用填充规则evenodd
function draw() {var ctx = documentgetElementById('canvas')getContext('2d');
ctxbeginPath();
ctxarc(50, 50, 30, 0, MathPI2, true);
ctxarc(50, 50, 15, 0, MathPI2, true);
ctxfill("evenodd");
}
Screenshot
Live sample
待续。。。
阅读全文
你的意思是用canvas2D绘制是吧
实际上,拿canvas2D绘制,只是把image渲染到 canvas(画布上)而实际的事件,就不能像标签那么处理,应该对canvas的事件做处理
实现逻辑是这样:
1,添加事件监听,比如说,鼠标按下 做什么,滑动 做什么,弹起做什么一般鼠标事件都是判断弹起的位置
2,判断有效坐标,在事件中判断坐标位置是否在位置,也就是在canvas的位置
ex:
//some code
canvaswidth=400;
canvasheight=400;
var context2d = canvasgetContext("2d");
var img =new Image();
imgsrc="xxx/xxxpng";
imgonload=function(){
context2ddrawImage(img,X,Y,WIDTH,HEIGTH);
//X=0,Y=0,W=50,H=50
canvasaddEventListener("mouseup", keyUp, false);
}
function keyUp(evt){
Event_UpX = evtoffsetX;
Event_UpY = evtoffsetY;
if(Event_UpX>=绘制坐标X&&Event_UpX<=宽度){
if(Event_UpY>=绘制坐标Y&&Event_UpY<=高度){
//do something
}
}
}
本篇文章主要介绍HTML如何利用canvas实现弹幕功能,感兴趣的朋友参考下,希望对大家有所帮助。
简介
最近在做大作业的时候需要做一个弹幕播放器。借鉴了一下别人的源码自己重新实现了一个,演示如下
主要的功能有
发送弹幕
设置弹幕的颜色,速度和类型
显示弹幕
已知缺陷:
不能全屏
canvas没有做自适应
没有自定义播放器控件
没有根据播放时间显示相应的弹幕
弹幕不能实现悬停
已知的缺陷以后会进行改进。网上能找到的弹幕播放器的源码一般只做了滚动的弹幕而没有做静止的弹幕,这里我特意加上了静止弹幕的实现。
Canvas绘制文字以及文字滚动效果
整个播放器的核心就是绘制文字以及做文字滚动的动画,canvas中对于文字并没有很好的动画支持,只能通过自己实现,实现的思路就是不断的清屏然后重写文字,当清屏重写的频率达到24fps的时候就是流畅的动画了。
先在HTML文件中添加视频video标签和画布canvas标签
<p id="barrageplayer">
<canvas id="cv_video" width="900px" height="450px"></canvas>
<video id="v_video" src="testMP4" controls type="video/mp4"></video>
</p>把canvas标签的位置样式设置为position:absolute然后视频和画布就重叠在一起,看起来就是一个弹幕播放器了。然后为画布添加弹幕相关的内容,首先获取画布的相关信息和设置画布的字体大小和字体样式
var c=documentgetElementById("cv_video");
//获取画布大小
var c_height=cheight;
var c_width=cwidth;
//获取画布
ctx=cgetContext("2d");
//设置字体样式
ctxfont="25px DengXian";
画布信息已经获取和设置,巧妇难为无米之炊,接着我们就要构造弹幕对象,使用的构造模式是动态原型模式
//弹幕对象
function Barrage(content,color,type,speed){
thiscontent=content;
thiscolor=color;
thistype=type;
thisspeed=speed;
if(thistype=="default"){
thisheight=parseInt(Mathrandom()c_height)+10;
}else if (thistype=="static top"){
thisheight=parseInt((c_height/2)-Mathrandom()c_height/2)+10;
}else if (thistype=="static bottom"){
thisheight=parseInt((c_height/2)+Mathrandom()c_height/2)+10;
}
if(typeof thismove!="function"){
Barrageprototypemove=function(){
if(thistype=="default"){
thisleft=thisleft-thisspeed;
}
}
}
}构造的弹幕对象初始化了各种参数,包括内容,颜色,运动类型和速度,定义了move()方法来控制弹幕的缓动,每出发一次move()方法向左滚动一个单位speed的像素。
弹幕对象构造完成之后就进入到主题,动画的制作,直接上代码
//循环擦写画布实现动画效果
setInterval(function(){
ctxclearRect(0,0,c_width,c_height);
ctxsave();
for(var i=0;i<msgslength;i++){
if(msgs[i]!=null){
if(msgs[i]type=="default"){
handleDefault(msgs[i]);
}else{
handleStatic(msgs[i]);
}
}
}
},20)每20ms执行一次擦写,ctxclearRect(0,0,c_width,c_height);是将整张当前的画布清除,然后使用ctxsave()将当前的画布保存,接着遍历弹幕列表(msgs是弹幕列表,当每发送一条弹幕都会将该弹幕实例添加到列表中),然后按照默认样式的弹幕还是静止样式的弹幕分别处理。如果是默认样式的弹幕将会按照以下的方法处理
//处理默认弹幕样式
function handleDefault(barrage){
if(barrageleft==undefined||barrageleft==null){
barrageleft=cwidth;
}else{
if(barrageleft<-200){
barrage=null;
}else{
barragemove()
ctxfillStyle=barragecolor;
ctxfillText(barragecontent,barrageleft,barrageheight)
ctxrestore();
}
}
}首先如果弹幕实例没有设置left属性则将画布的宽度赋予它,如果弹幕实例已经退出画布则将其置null以节省内存,否则的话就调用弹幕实例的move()方法改变left属性的值,然后设置文字的颜色,一级写入新的文字,恢复画布。这样就完成了一帧动画。
对于静止弹幕的实现方法如下
//处理静止弹幕样式
function handleStatic(barrage){
ctxmoveTo(c_width/2,barrageheight);
ctxtextAlign="center";
ctxfillStyle=barragecolor;
ctxfillText(barragecontent,c_width/2,barrageheight);
if(barrageleft==undefined||barrageleft==null){
barrageleft=cwidth;
}else{
if(barrageleft<-200){
ctxfillText("",c_width/2,barrageheight);
barrage=null;
//ctxrestore();
ctxclearRect(0,0,c_width,c_height);
}else{
barrageleft=barrageleft-6;
}
}
}首先将画布的基点移动到画布的中心,需要注意的是这时候相对与生成了一张新的画布,原来画布的clearRect()方法已经不适用与这张画布了。然后再设置文字对齐为居中对齐,设置文字样式,填充文字。因为弹幕是静止的所以不需要进行缓动,但是静止弹幕也是会消失的,需要设置一个标志位来使他定时消失。在这里为了不占用额外的属性,我们直接使用left属性作为标志位,同样进行left属性的递减,但不把递减反映到画布中,当left达到阈值,则使用ctxclearRect()方法将弹幕清除。这样就实现了静止弹幕的处理。
其他关于颜色,样式的设置有一定基础的人应该是很容易掌握的在这里就不多介绍了,自己看可运行代码部分理解一下就好。
总结
这个项目主要是使用了canvas进行文字绘制以及实现文字的缓动动画,主要用到的方法有
canvasDomgetContext()
canvassave()/canvasrestore()
canvasclearRect()
canvasmoveTo()原来我对与save()和restore()是不能理解的,现在我算是有一点理解了,当你更改了画布状态,现在的画布就已经不是原来的画布,所以在修改画布状态之前先把画布状态保存,切换画布状态,完成工作之后,恢复为原来的画布状态继续工作。像我处理静态弹幕的时候,把画布的基点改变了,那么原来画布的清除方法就不再适用于当前画布,只有在当前画布中自己使用另外的清除方法。然后再恢复到原来的画布。
可运行代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=10">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style type="text/css">
pickp{
width: 30px;
height: 30px;
cursor: pointer;
border: 2px solid gray;
display: inline-block;
}
#white{
background: white;
}
#red{
background:#ff6666;
}
#yellow{
background:#ffff00;
}
#blue{
background:#333399;
}
#green{
background:#339933;
}
#cv_video{
position: absolute;
z-index: 1;
}
#barrageplayer{
position: relative;
display: block;
width: 900px;
height: 500px;
}
#v_video{
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
</style>
<body>
<p id="barrageplayer">
<canvas id="cv_video" width="900px" height="450px"></canvas>
<video id="v_video" src="testMP4" controls type="video/mp4"></video>
</p>
<p id="barrageinput">
<p>
<input type="text" id="smsg" placeholder="请输入弹幕内容"/>
<button id="send"> 发送</button>
</p>
<p id="colorpick">
<p class="pickp" id="white"></p>
<p class="pickp" id="red"></p>
<p class="pickp" id="yellow"></p>
<p class="pickp" id="blue"></p>
<p class="pickp" id="green"></p>
</p>
<p id="typepick">
<input type="radio" name="type" value="default">默认
<input type="radio" name="type" value="static top">静止顶部
<input type="radio" name="type" value="static bottom">静止底部
</p>
<p id="speedpick">
<input type="radio" name="speed" value="1">1X
<input type="radio" name="speed" value="2">2X
<input type="radio" name="speed" value="3">3X
</p>
<p id="stylepick"></p>
</p>
<script>
var c=documentgetElementById("cv_video");
var typeDom=documentgetElementsByName("type");
var speedDom=documentgetElementsByName("speed");
var colorpick=documentgetElementById("colorpick");
var smsg=documentgetElementById("smsg");
var color="#white";
var speed=1;
var type="default";
var msgs=[];
//获取画布大小
var c_height=cheight;
var c_width=cwidth;
//获取画布
ctx=cgetContext("2d");
ctxfont="25px DengXian";
//处理颜色选择
colorpickaddEventListener('click',function(event){
switch(eventtargetid){
case "white":
color="white";
break;
case "red":
color="#ff6666";
break;
case "yellow":
color="#ffff00";
break;
case "green":
color="#339933";
break;
case "blue":
color="#333399";
break;
}
})
//处理发送弹幕
documentgetElementById("send")onclick=function(){
var text=smsgvalue;
for(var i=0;i<typeDomlength;i++){
if(typeDom[i]checked){
type=typeDom[i]value;
break;
}
}
for(var i=0;i<speedDomlength;i++){
if(speedDom[i]checked){
speed=2parseInt(speedDom[i]value);
break;
}
}
var tempBarrage=new Barrage(text,color,type,speed);
msgspush(tempBarrage);
}
//
//弹幕功能部分代码
//
//弹幕对象
function Barrage(content,color,type,speed){
thiscontent=content;
thiscolor=color;
thistype=type;
thisspeed=speed;
if(thistype=="default"){
thisheight=parseInt(Mathrandom()c_height)+10;
}else if (thistype=="static top"){
thisheight=parseInt((c_height/2)-Mathrandom()c_height/2)+10;
}else if (thistype=="static bottom"){
thisheight=parseInt((c_height/2)+Mathrandom()c_height/2)+10;
}
if(typeof thismove!="function"){
Barrageprototypemove=function(){
if(thistype=="default"){
thisleft=thisleft-thisspeed;
}
}
}
}
//循环擦写画布实现动画效果
setInterval(function(){
ctxclearRect(0,0,c_width,c_height);
ctxsave();
for(var i=0;i<msgslength;i++){
if(msgs[i]!=null){
if(msgs[i]type=="default"){
handleDefault(msgs[i]);
}else{
handleStatic(msgs[i]);
}
}
}
},20)
//处理默认弹幕样式
function handleDefault(barrage){
if(barrageleft==undefined||barrageleft==null){
barrageleft=cwidth;
}else{
if(barrageleft<-200){
barrage=null;
}else{
barragemove()
ctxfillStyle=barragecolor;
ctxfillText(barragecontent,barrageleft,barrageheight)
ctxrestore();
}
}
}
//处理静止弹幕样式
function handleStatic(barrage){
ctxmoveTo(c_width/2,barrageheight);
ctxtextAlign="center";
ctxfillStyle=barr
Overlay,即覆盖,就将他理解成一块透明的画布,将它铺在地图上,可以进行的操作主要有两项:绘制(标记)和处理触摸事件。
建立一个覆盖我们需要做的步骤如下 :
1创建一个继承自Overlay的新类,这个类我们需要复写draw方法和onTap方法。(即新建一张画布)
代码示例:
public class MyOverlay extends Overlay{
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
// TODO Auto-generated method stub
superdraw(canvas, mapView, shadow);
}
@Override
public boolean onTap(GeoPoint p, MapView mapView) {
// TODO Auto-generated method stub
return superonTap(p, mapView);
}
}
这里简要说明一下,draw方法在使用时,需要使用传进来的geopoint,即实际的经纬度位置,将它转换成投影(Projection)。之后根据这个投影位置在进行绘制。
2在MapView上添加(删除)新覆盖。(即把生成的画布贴在地图上)
(1)添加
private void display(){
List<Overlay> overlays=mvgetOverlays();
MyOverlay myoverlay=new MyOverlay();
overlaysadd(myoverlay);
}
首先,获取Overlays列表,接着新建MyOverlay 实例对象,最后将该对象添加到列表中。这样,在onCreate()中调用display()函数,就将会显示MyOverlay覆盖中所绘制的内容,同时也会对点击动作做出相应的回应。
(2)删除
删除所有覆盖:
overlaysclear();
删除指定覆盖:
overlaysremove(int i);//删除第i个覆盖,i的取值是0到overlayssize()-1。
3详解draw方法和onTap方法
(1) draw(Canvas canvas, MapView mapView, boolean shadow){}
canvas:就是所要绘制其上的画布。这里要啰嗦一下Canvas 类。Canvas类就是表示一块画布,你可以在上面画你想画的东西。它提供一些方法,使得我们可以绘制各种形状,颜色的图形。具体的使用方法我会在今后介绍。
mapView:所需标记的地图图层。这个参数的一个重要作用就是MapViewgetProjection()这个方法,它完成从物理经纬度到屏幕投影坐标的转换,继而在相应坐标点上进行绘制。
shadow:当该值为true,则需绘制阴影图层,若为false,则只需绘制本来的内容即可。
(2)onTap(GeoPoint p, MapView mapView){}
该方法响应点击事件
p:被点击的点。
mapView:产生点击事件的地图图层。
请帮忙看看 html5 canvas 如何做到文字旋转?我的代码出不来旋转。。
本文2023-09-30 04:53:18发表“资讯”栏目。
本文链接:https://www.lezaizhuan.com/article/139496.html