1.SVG 指的是可伸缩矢量图形(Scalable Vector Graphics),用来定义用于网络的基于矢量的图形,使用 XML 格式定义图形。SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失,是万维网联盟的标准。
2.SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体。 2003 年一月,SVG 1.1 被确立为 W3C 标准。与其他图像格式相比,使用 SVG 的优势有以下几点:
3.SVG文件,用.svg后缀来保存:
<?xml version="1.0" standalone="no"?>
// standalone="no"意味着SVG文档会引用一个外部文件——这里是DTD文件
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
//该DTD位于W3C,含有所有允许的SVG元素。
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
//根元素,width 和 height 属性可设置此 SVG 文档的宽度和高度,version定义所使用的SVG版本,xmlns定义SVG命名空间
<circle cx="200" cy="100" r="50" stroke="red" stroke-width="2" fill="green"/>
</svg>
4.SVG引用方式
方式一:用img引入SVG文件
<img src="1svg.svg"/>
方式二:用样式将SVG做背景
<div style="height:200px; width:200px; background:url(1svg.svg) no-repeat"></div>
方式三:用框架将SVG引入
<iframe src="1svg.svg"></iframe>
方式四:在html页面中书写svg(HTML5技术,命名空间必须有)
<div id="div1">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<circle cx="100" cy="100" r="40" fill="red" />
</svg>
</div>
img在你设置边框的时候,边框是和模型的一部分,设置边框后,盒子的宽度会增加2倍的边框宽。
svg在设置边框时,图形的大小只会增加边框宽度的一半。也就是说设置了边框宽度为10px,但事实上5px的边框向外扩张,5px的边框向内容区扩展。
5.SVG绘制的设置,可以用属性或css样式设置:
1.SVG图形绘制语法:
<circle cx="" cy="" r="" fill="" />
//cx和cy默认值为0
<ellipse cx="" cy="" rx="" ry="" fill="" />
//rx和ry的值相等时即是圆形
rect(圆角矩形)——属性参数:width(宽度)、height(高度)、x(左上角X轴坐标)、y(左上角Y轴坐标)、rx(圆角X轴半径)、ry(圆角Y轴半径,省略时为半径为rx的正圆圆角)
<rect x="" y="" width="" height="" rx="" ry="" stroke="" stroke-width="" /> //注意:边框的宽度同时向内外延伸
line(画线,线是边框不能用fill填充色)——属性参数:x1(起点X轴坐标)、y1(起点Y轴坐标)、x2(终点X轴坐标)、y2(终点Y轴坐标)
<line x1="" y1="" x2="" y2="" stroke="" stroke-width="" />
//stroke默认白色
polyline(折线)——属性参数:points(折点设置)、必须设置fill='transparent’去掉填充
<polyline points="" fill="transparent" stroke="" />
//points的值为坐标对,如:10,10 10,50 50,50 50,100 100,100 100,150
polygon(多边形)——属性参数:同上,不去掉填充
<polyline points="" fill="red"/>
text(文字)——属性参数:x(文字X轴坐标)、y(文字Y轴坐标)、font-size(字体大小)、font-family(文字样式)、text-anchor(对齐点,坐标在文字middle/start/end哪个位置)
<text x="" y="" text-anchor="" fill="" >文字内容</text>
//文字用填充色
image(图片)——属性参数:x(图片X轴坐标)、y(图片Y轴坐标)、width(图片宽)、height(图片高)、xlink:href(图片地址)
<image x="" y="" width="" height="" xlink:href=""/>
//这里图片不会变形,会按照width和height最小比例进行缩放
path(路径,单标签):path是SVG基本形状中最强大的一个,它能创建包括其他基本形状在内的所有形状。如矩形、圆形、椭圆、折线形、多边形,以及贝塞尔曲线、2次曲线等曲线。用属性d来定义路径点,它是一个命令+参数的序列。命令包括:
<path d="M50 50 L150 150 L50 150" fill="red"/>
//大写的命令代表绝对位置(参照左上0,0点的位置),填充时无需设置Z闭合
<path d="M50 150 h100 v-50 Z" stroke="red" stroke-width="2" fill="transparent"/>
//小写的命令代表相对位置(相对于上个点增加或减少多少)
过于复杂的图往往是通过图像转换成path代码的:转换网址
1.之前我们学习了css的滤镜,通过filter的值修改元素的效果,SVG也可以设置滤镜,不但可以在SVG中使用,部分甚至可以配合css的filter在HTML中使用。SVG中的滤镜在filter元素中定义,filter元素具有必需的id属性,用于标识滤镜,然后指向要使用的滤镜。SVG的滤镜有很多,用一些常用的举例说明。
2.feGaussianBlur:用于创建模糊效果
<filter id="f1" x="0" y="0">
//定义滤镜,获得f1标识,在SVG的filter属性或元素css的filter样式中使用
<feGaussianBlur in="SourceGraphic" stdDeviation="15" />
//in属性决定创建效果;stdDeviation决定了模糊量
</filter>
<rect width="90" height="90" stroke="green" stroke-width="3" fill="yellow" filter="url(#f1)" />
3.eOffset:用于创建阴影效果,拍摄SVG图形(图像或元素)并将其在xy平面中偏移,再用feBlend叠加到原图中,如果需要模糊阴影则将feGaussianBlur也设置上,用feColorMatrix将影子的颜色向黑色变化
<filter id="f1" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceGraphic" dx="20" dy="20" />
//dx和dy,x轴和y轴偏移距离,将in的值改成SourceAlpha可以变成黑色影子(无论图形什么颜色),如果设置feColorMatrix可以让颜色向接近黑色变化
<feColorMatrix result="matrixOut" in="offOut" type="matrix" values="0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0" />
<feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="10" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
<rect width="90" height="90" stroke="green" stroke-width="3" fill="yellow" filter="url(#f1)" />
1.linearGradient:用于定义线性渐变,用stop定义线性渐变的颜色点。线性渐变可以定义为水平,垂直或角度渐变:当y1和y2相等且x1和x2不同时,将创建水平渐变;当x1和x2相等且y1和y2不同时,将创建垂直渐变;当x1和x2不同且y1和y2不同时,将创建角度渐变。
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
// x1,x2,y1,y2 属性定义渐变的开始和结束位置
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
//offset为该颜色点在开始到结束的位置
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
//style的stop-color和stop-opacity用于设置颜色和透明度
</linearGradient>
<ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" />
<text fill="#ffffff" font-size="45" font-family="Verdana" x="150" y="86">SVG</text>
2.radialGradient:用于定义径向渐变,用stop定义线性渐变的颜色点。cx,cy为最外层中心(决定形状,一般为50%,50%即中心点),fx,fy为最内层中心(渐变中心点,要设置在图形内)
<radialGradient id="grad1" cx="50%" cy="50%" r="50%" fx="50%" fy="90%">
<stop offset="0%" style="stop-color:red;stop-opacity:1" />
//offset的值决定了梯度,0%即最内层
<stop offset="50%" style="stop-color:green;stop-opacity:0.5" />
<stop offset="100%" style="stop-color:blue;stop-opacity:1" />
//100%即最外层
</radialGradient>
<ellipse cx="200" cy="70" rx="85" ry="55" fill="yellow" />
<text fill="url(#grad1)" font-size="55" font-family="Verdana" x="140" y="90" >SVG</text>
1.SVG变形与css3的变形相似,只不过是写在SVG标记的transform属性上,但是相对于SVG根元素的0,0点,且不能加单位。
<rect x="0" y="0" width="100" height="100" transform="translate(30,40)" />
rotate:旋转
<rect x="-50" y="-50" width="100" height="100" transform="translate(100 100) rotate(45)" />
//为了让其以中心点旋转,我们需要把0,0点设置在其中心点上,然后位移到需要的位置,再旋转
skewX()和skewY():斜切
<rect x="0" y="0" width="100" height="100" transform="skewX(30) skewY(30)" />
scale:缩放和翻转
<rect x="0" y="0" width="100" height="100" transform="translate(100 100) scale(-0.5)" />
//负值也是翻转,但是由于中心点在0,0点,一样需要设置中心点防止位移
2.g(分组标签):是一个容器标签,用来组合元素,这样可以同时控制一组元素,比如执行变形的时候:
<g style="cursor:pointer" transform="translate(100 100) rotate(45) scale(-1,1)">
<circle cx="0" cy="0" r="40" fill="yellow" stroke="red" stroke-width="3" />
<text x="0" y="8" font-size="20" text-anchor="middle"> 新卓越</text>
</g>
1.SVG元素不同于HTML的元素,没有办法用定位或边距来改变位置,但可以使用css3的animation样式来执行动画,除此以外SVG还提供了animate标记来设置动画,注意这是需要将SVG编辑设置成双标记,将animate变成它的子元素
2.animate的重要属性:
attributeName——需要动画的属性名称;
from/to——属性的初始值/终止值;values——动画每个设置点,两个值时与from和to的写法效果一致;
dur——动画时长;repeatCount——重复次数,默认一次,indefinite为无限循环
<rect width="100" height="100" x="10" y="10">
<animate attributeName="x" values="10;150;10" dur="4s" repeatCount="indefinite"/>
//values设置3个值且最后一个值等于第一个值比较适合循环
</rect>
<rect width="100" height="100" x="10" y="120">
<animate attributeName="width" from="100" to="240" dur="4s" repeatCount="3"/>
</rect>
3.如果想让元素的更多属性具有动画效果,只要添加更多的animate元素到该元素内部即可。
<rect width="100" height="100" x="10" y="10" fill="red">
<animate attributeName="rx" values="0;25;0" dur="4s" repeatCount="indefinite" />
<animate attributeName="fill" values="red;blue;green;red" dur="4s" repeatCount="indefinite" />
</rect>
1.当我们的动画需要做旋转之类的效果时,animate标记明显满足不了,这时就是animateTransform登场的时候了。
2.animateTransform的重要属性:
3.将animateTransform设置在要执行变形动画的标记里:
<rect x="50" y="50" width="30" height="40" fill="blue" stroke="black" stroke-width="1" transform="rotation">
<animateTransform attributeName="transform" begin="0s" dur="5s" type="rotate" from="0 65 70" to="360 65 70" repeatCount="indefinite" />
//form和to的第二个第三个值起始就是旋转的中心点
</rect>
4.如果想让文字标记也有动画效果,可以用g标记将所有想执行动画的标记包装起来
<g>
<rect x="50" y="50" width="30" height="40" fill="blue" stroke="black" stroke-width="1" transform="rotation"/>
<text x="50" y="70" text-anchor="center" fill="white">文字</text>
<animateTransform attributeName="transform" begin="0s" dur="5s" type="rotate" from="0 65 70" to="360 65 70" repeatCount="indefinite" />
</g>
1.如果我们希望元素按照我们设计的路线执行动画就要用到animateMotion标记了,路径类似path的方式定义
2.animateMotion的重要属性:
3.用animateMotion设置动画,为了方便看我们将对应的路径一起画了出来:
<path d="M 250,80 H 50 Q 30,80 30,50 Q 30,20 50,20 H 250 Q 280,20,280,50 Q 280,80,250,80ZM 250,80 H 50 Q 30,80 30,50 Q 30,20 50,20 H 250 Q 280,20,280,50 Q 280,80,250,80Z" stroke="red" fill="transparent"/>
<rect x="0" y="0" width="20" height="20" fill="blue" stroke="black" stroke-width="1">
<animateMotion path="M 250,80 H 50 Q 30,80 30,50 Q 30,20 50,20 H 250 Q 280,20,280,50 Q 280,80,250,80Z" dur="3s" repeatCount="indefinite" rotate="auto">
</rect>
4.甚至我们可以用mpath直接把某个path图形当成路径
<path id="path1" d="M100,250 C 100,50 400,50 400,250" fill="none" stroke="blue" stroke-width="2"/>
<path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z" fill="yellow" stroke="red" stroke-width="7.06">
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto">
<mpath xlink:href="#path1"/>
</animateMotion>
</path>
<div style="width:500px;height:500px">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
</svg>
</div>
<script>
var oSVG=document.getElementsByTagName('svg')[0];
var oCircle=createSVG('circle',{
"cx":"120",
"cy":"120",
"r":"50",
"fill":"blue"
});
oCircle.onclick=function(){
console.log('yes');
}
oSVG.appendChild(oCircle);
function createSVG(tagName,option){
var sXmls="http://www.w3.org/2000/svg";
var obj=document.createElementNS(sXmls,tagName);
for(var attr in option){
obj.setAttribute(attr,option[attr]);
}
return obj;
}
</script>
//绘制六边形
<div class="div1">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<path d="M100 30 L140 60 L140 100 L100 130 L60 100 L60 60 Z" stroke="black" stroke-width="3px" fill="transparent"></path>
</svg>
</div>
//屏幕解锁静态效果
<div class="div1">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<circle cx="40" cy="40" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="120" cy="40" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="200" cy="40" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="40" cy="120" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="120" cy="120" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="200" cy="120" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="40" cy="200" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="120" cy="200" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
<circle cx="200" cy="200" r="25" fill="transparent" stroke="black" stroke-width="4px"/>
</svg>
</div>
//靶子效果
<div class="div1">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<g transform="translate(160 160)">
<circle cx="0" cy="0" r="140" fill="red"/>
<circle cx="0" cy="0" r="120" fill="#fee4d3"/>
<circle cx="0" cy="0" r="100" fill="red"/>
<circle cx="0" cy="0" r="80" fill="#fee4d3"/>
<circle cx="0" cy="0" r="60" fill="red"/>
<circle cx="0" cy="0" r="40" fill="#fee4d3"/>
<circle cx="0" cy="0" r="20" fill="red"/>
//方式一
<path d="M0 -160 L0 160 Z" stroke="black" stroke-width="2" fill="transparent"></path>
<path d="M-160 0 L160 0 Z" stroke="black" stroke-width="2" fill="transparent"></path>
//方式二
<!-- <line x1="0" y1="-180" x2="0" y2="180" stroke="black" stroke-width="2" />
<line x1="-180" y1="0" x2="180" y2="0" stroke="black" stroke-width="2" /> -->
</g>
</svg>
</div>
1.canvas是 HTML5 提供的一种新标签,它本身并不具备绘画能力,只是一个画布,一个容器。绘图能力是基于html5的getContext(“2d”)返回的CanvasRenderingContext2D对象(3d需要用到webgl)来完成的。
2.什么时候会用到canvas
3.与SVG的区别
4.创建一个canvas标记,看起来和img标签差不多,只是它只有两个可选的属性 width、heigth 属性,没有 src、alt 属性。不设置widht、height属性时,则默认 width为300、height为150,单位都是px。
也可以使用css属性来设置宽高,但是如宽高属性和初始比例不一致,他会出现缩放。
除非确实需要缩放,否则建议永远不要使用css属性来设置canvas的宽高。
<canvas id="c1" width="400" height="400"></canvas>
//设置绘图环境
var oC = document.getElementById('c1'); //获得画布
var oCG = oC.getContext('2d'); //注意:2d小写
canvas元素起点为左上角(0,0),x 向右增大,y 向下增大。所有元素的位置都相对于原点来定位。绘制canvas需要在2d对象上绘制路径(不会画出来),然后调用描边或填充才会画出来
oCG.fillStyle = color;
//设置填充颜色
oCG.strokeStyle = color;
//设置描边颜色
oCG.lineCap = "round";
//端点样式:butt(方形,默认)、round(圆角)、square(多出宽的一半)
oCG.lineJoin = "round";
//边界连接点样式:miter(直角,默认)、round(圆角)、bevel(斜角)
oCG.moveTo(x,y);
//移动画笔到x,y点
oCG.lineTo(x,y);
//绘制直线路径(从画笔上一个的位置绘制到x,y点)
oCG.beginPath();
//开始绘制新路径(以区分与之前的路径)
oCG.closePath();
//闭合该次绘制的最后位置和初始位置
oCG.stroke();
//描边,以线的方式画出绘制的路径
oCG.fill();
//填充,将闭合的路径内填充颜色
注意:
oCG.lineWidth="1"的线的宽度和oCG.lineWidth="2"的线的宽度相同,但是前者的线浅后者的线宽。这是因为:oCG.lineWidth=“1”;oCG.lineTo(20,20);oCG.stroke();的时候就会从(20,20)处向左延伸0.5px并且向右延伸0.5px按理说线的左右像素为19.5px和20.5px但是由于像素点为1px的整数所以实际上会将(20,20)处向左拉伸1px并且向右拉伸1px此时颜色变浅。左右像素为19px和21px,线宽为2px。
oCG.lineWidth="2"则是正常结果。
oCG.beginPath()是指从这里开始重新绘制另外一个路径,不会再重绘前面的路径,而OCG.closePath()则是指闭合路径。两个方法看上去是反义词,事实上只是两个不同的用途并非相反用途。
//绘制矩形:x,y是矩形左上角坐标,width和height是尺寸
oCG.rect(x, y, width, height);
oCG.strokeRect(x, y, width, height);
//直接用描边画出来
oCG.fillRect(x, y, width, height);
//直接用填充画出来
oCG.clearRect(x, y, width, height);
//清除该矩形内的绘制的内容,相当于橡皮擦
//绘制圆弧:圆心到最右边点是 0 度,顺时针方向弧度增大,弧度和角度的转换公式:rad = deg*Math.PI/180
oCG.arc(x, y, r, sAngle, eAngel, anticlockwise);
//x,y是圆心坐标,r是半径,sAngle是起始弧度,eAngel是结束弧度,注意是弧度,anticlockwise是否是逆时针(true 是逆时针,false:顺时针)
oCG.arcTo(x1, y1, x2, y2, r);
//用起始点到x1,y1和x1,y1到x2,y2作为切线,用r作为半径画弧
绘制文字,填充字体用fillStyle设置fillText绘制;描边字体用strokeStyle设置strokeText绘制:
oCG.font = "18px bold 黑体";
// 设置字体
oCG.fillStyle = "#ff0";
// 设置颜色
oCG.textAlign = "center";
// 设置水平对齐方式
oCG.textBaseline = "middle";
// 设置垂直对齐方式
oCG.fillText("要写的文字", 100, 100);
// 绘制文字(参数:内容,指定位置x,y坐标)
textAlign:start(默认): 文本在指定的位置开始;end: 文本在指定的位置结束;center: 文本的中心被放置在指定的位置;left: 文本左对齐;right: 文本右对齐。
textBaseline:alphabetic(默认):文本基线是字母基线;top:文本基线是四线格的顶端;hanging:文本基线是悬挂基线;middle:文本基线是四线格的正中;ideographic:文本基线是表意字基线;bottom:文本基线是四线格的底端。
绘制图片:该方法也可以绘制视频或另一个画布,将图片对象换成视频/画布对象即可
var img = new Image(); //如图片未在dom中需先创建img对象
img.src = '图片路径';
img.onload = function (){ //图片加载成功后绘制图片
oCG.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
}
img是绘制的图片对象,sx,sy,swidth,sheight是原图切片,如果不设置就是用整张图片绘制,x和y是距离0,0点的距离,width和height是绘制大小(如果缺省就是等于原图大小)
//举个例子
oCG.drawImage(img,300,100,550,220,50,50,400,120);
//从原图(300,100)位置开始,截取宽550高220的尺寸。在canvas里(50,50)开始绘制图,大小为400*120
设置背景图:同图片一样,不在dom中的图需要先加载
var img = new Image();
img.src = '图片路径';
img.onload = function (){ //图片加载成功后绘制背景图
oCG.fillStyle = oCG.createPattern(this,'repeat');
//用图片来绘制填充图像,平铺方式(repeat、repeat-x、repeat-y、no-repeat)
oCG.fillRect(0,0,300,300); //设置完成后可以用此填充图来绘制任何形状
}
配置状态的保存和恢复(save和restore):是绘制复杂图形时必不可少的操作,类似js的函数作用域,在一个save和restore范围内的设置只对其内部生效:
oCG.save(); // 保存默认状态
oCG.fillStyle = 'red'
oCG.fillRect(15, 15, 120, 120);
oCG.save(); // 再次保存当前状态
oCG.fillStyle = '#FFF'
oCG.fillRect(30, 30, 90, 90);
oCG.restore(); // 重新加载之前的颜色状态,退出这次的save()操作
oCG.fillRect(45, 45, 60, 60);
oCG.restore(); // 加载默认颜色配置,退出这次的save()操作
oCG.fillRect(60, 60, 30, 30); // 使用加载的配置绘制一个矩形
1.和css一样,画布变形也是将要绘制的图形缩放、位移和旋转,但是画布变形的是整个画布,一旦设置所有后续绘制的新元素都被影响。让变形只对需要变形的绘制起效,就要用到save和restore方法。
oCG.translate(x, y); //x轴和y轴的偏移值
oCG.scale(x, y); //x轴和y轴的缩放因子
oCG.rotate(angle); //正值为顺时针,参数值为弧度
2.我们画多个图形时,肯定会出现重叠的情况,默认是后绘制的会覆盖原绘制的,我们可以通过设置合成(globalCompositeOperation)的值改变合成后的样子
oCG.globalCompositeOperation = type;
type的值:source-over(默认,新图覆盖原图)、source-in(仅显示重叠部分的新图)、source-out(仅显示未重叠部分的新图)、source-atop(显示重叠部分的新图和所有原图)、destination-over(原图覆盖新图)、destination-in(仅显示重叠部分的原图)、destination-out(仅显示未重叠部分的原图)、destination-atop(显示重叠部分的原图和所有新图)、lighter(同默认,重叠部分颜色叠加)、darken(同默认,重叠部分高亮)、lighten(同默认,重叠部分变暗)、xor(同默认,重叠部分透明)、copy(仅保留新图)
小例子
//绘制一个正方形
<canvas width="500" height="500"></canvas>
<script>
var oC=document.getElementsByTagName('canvas')[0];
var oCG=oC.getContext('2d');
oCG.fillRect(100,100,150,150);
</script>
//绘制一个旋转45度的正方形
<canvas width="500" height="500"></canvas>
<script>
var oC=document.getElementsByTagName('canvas')[0];
var oCG=oC.getContext('2d');
oCG.translate(175,175);
//将画布的原点移动到(175,175)的位置也就是原本正方形的中心点
oCG.rotate(45*Math.PI/180);
//将所作图形按照原点顺时针旋转45度
oCG.fillRect(-75,-75,150,150);
//既然原本的(175,175)充当了画布原点,那么原本的正方形的左上角点(100,100)就变成了(-75,-75)
</script>
//要求:绘制一个红色小方块,不断旋转的同时由小变大再由大变小
<canvas width="500" height="500"></canvas>
<script>
var oC=document.getElementsByTagName('canvas')[0];
var oCG=oC.getContext('2d');
var scal=1;
var rota=1;
var flag=true;
//var change=0.01;
//oCG.globalCompositeOperation = "copy";
//有了这句可以代替oCG.clearRect()
setInterval(function(){
oCG.clearRect(0,0,oC.width,oC.height);
oCG.save();
oCG.translate(250,250);
//方法一
if(scal<2&&flag){
scal+=0.01;
}else{
scal-=0.01;
flag=false;
if(scal<=0.1){
scal+=0.01;
flag=true;
}
}
//方法二
// if(scal>2){
// change=-0.01;
//}else if(scal<=0){
// change=0.01;
//}
//scal+=change;
oCG.scale(scal,scal);
oCG.rotate((rota++)*Math.PI/180);
oCG.fillStyle="#f40";
oCG.fillRect(-75,-75,150,150);
oCG.restore();
},17)
</script>
1.我们可以将绘制好的canvas生成图片或保存下来,需要将生成的base64放在img的src属性或a的href属性中
2.toDataURL:把 canvas 绘制的内容输出成base64内容,参数为图片格式(image/png、image/jpeg)
方法一
<canvas width="500" height="500"></canvas>
<a href="">aa</a>
<script>
var oC=document.getElementsByTagName('canvas')[0];
var oCG=oC.getContext('2d');
oCG.fillStyle="red";
oCG.arc(150,150,100,0,360);
oCG.fill();
var oA = document.querySelector("a");
oA.href = oC.toDataURL("image/png");
oA.download = "p.png"; //download为下载图片的名字
</script>
方式二
<canvas width="500" height="500"></canvas>
<img src="" />
<script>
var oC=document.getElementsByTagName('canvas')[0];
var img = document.querySelector("img");
var oCG=oC.getContext('2d');
oCG.fillStyle="red";
oCG.arc(150,150,100,0,360);
oCG.fill();
img.src = oC.toDataURL("image/png"); //注意toDataURL是画布方法,不是2d绘图环境的方法
</script>
3.配合html2canvas.js库,我们设置可以将一个html的部分转换成canvas,然后再生成图片或者下载
<style>
table,td{
border: 1px #000 solid;
background-color: orange;
}
td{
width: 120px;
height: 60px;
}
</style>
<table cellspacing="0">
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<a href="">aa</a>
</tbody>
</table>
<script src="../canvastoimg.js"></script>
<script>
var oTable=document.getElementsByTagName('table')[0];
var oA=document.getElementsByTagName('a')[0];
new html2canvas(oTable).then(canvas=>{
let oImg=new Image();
oImg.src=canvas.toDataURL('image/png');
document.body.appendChild(oImg);
oA.href=canvas.toDataURL('image/png');
oA.download="my.png";
})
</script>
1.canvas的动画并不是绘制的图形动起来了,而是通过不停的绘制清空来实现动画的。
2.实现动画帧的步骤:
3.下面我们就画出了一帧,接着使用计时器重复上面过程:如setInterval()/setTimeout()/requestAnimationFrame()等方法,setTimeout()和requestAnimationFrame()需要递归,接着让每一帧画面都出现一些变化就实现了动画效果,如:
var x = 0,y = 0;
var timer = setInterval(function (){
oCG.clearRect(0,0,oC.offsetWidth,oC.offsetHeight);
oCG.fillRect(x++,y++,100,100);
if(x>oC.offsetWidth-100){
clearInterval(timer);
}
},50)
电子时钟效果
几个注意点:
对于时来说:(走一圈360度24小时)
1小时时针走30度
对于分针来说1小时走了360度走了60分钟,对于时针来说1小时走了30度也走了60分钟,那么走1分钟时针走了(30/60)度。
对于分来说:(走一圈360度60分钟)
分针走了一分钟秒针就走了60秒。60分钟为一整圈,那么1分钟就走了6度。也就是说60秒走了6度。进而可以得出1分钟是6度;1秒钟是0.1度。
对于秒针来说1分钟走了360度走了60秒,对于分针来说1分钟走了6度也走了60秒,那么走1秒分针走了(6/60)度。
那么每分钟时针的角度(Hours30+Minutes/2-90)而不是(Hours30+Minutes/2)的原因是按照钟表来说将12点方向看成0度位置,可以写成(Hours30+Minutes/2);但是由于canvas画布12点方向是-90度,因此实际的计算公式为(Hours30+Minutes/2-90)。
oCG.arc(200,200,50,(Hours*30+Minutes/2-90)Math.PI/180,(Hours30+Minutes/2-90)*Math.PI/180,false);这种开始角度和终止角度绘制出来的图形是一个有偏向角度的直线。
//电子时钟效果
<canvas width="400" height="400" class="myCanvas"></canvas>
<script>
var oC=document.getElementsByClassName('myCanvas')[0];
var oCG=oC.getContext('2d');
oCG.strokeStyle="black";
var Hours=0;
var Minutes=0;
var Seconds=0;
for(var i=0;i<60;++i){
oCG.beginPath();
oCG.moveTo(200,200);
oCG.arc(200,200,150,(i*6)*Math.PI/180,((i+1)*6)*Math.PI/180,false);
oCG.stroke();
}
oCG.beginPath();
oCG.fillStyle="white";
oCG.arc(200,200,140,0,360*Math.PI/180,false);
oCG.fill();
oCG.strokeStyle="orange";
for(var i=0;i<12;++i){
oCG.beginPath();
oCG.moveTo(200,200);
oCG.arc(200,200,150,(i*30)*Math.PI/180,(i*30)*Math.PI/180,false);
oCG.stroke();
}
oCG.beginPath();
oCG.fillStyle="white";
oCG.arc(200,200,130,0,360*Math.PI/180,false);
//少写oCG.fill()就会有一些不同之处
oCG.fill();
oCG.beginPath();
oCG.fillStyle="black";
oCG.arc(200,200,5,0,360*Math.PI/180,false);
oCG.fill();
setInterval(function(){
init();
},1000);
function init(){
oCG.clearRect(100,100,200,200);
//不加这里的oCG.beginPath()会出现问题。
oCG.beginPath();
oCG.fillStyle="black";
oCG.arc(200,200,5,0,360*Math.PI/180,false);
oCG.fill();
var time=new Date();
Hours=time.getHours();
Minutes=time.getMinutes();
Seconds=time.getSeconds();
//下面的这三个oCG.beginPath()也很重要。如果不写可能会出现时针中有一根红色的细线,分针中也有根红色的细线。
oCG.beginPath();
oCG.strokeStyle="gray";
oCG.lineWidth="5";
oCG.moveTo(200,200);
oCG.arc(200,200,50,(Hours*30+Minutes/2-90)*Math.PI/180,(Hours*30+Minutes/2-90)*Math.PI/180,false);
oCG.stroke();
oCG.beginPath();
oCG.strokeStyle="black";
oCG.lineWidth="3";
oCG.moveTo(200,200);
oCG.arc(200,200,80,(Minutes*6+Seconds/10-90)*Math.PI/180,(Minutes*6+Seconds/10-90)*Math.PI/180,false);
oCG.stroke();
oCG.beginPath();
oCG.strokeStyle="#f40";
oCG.lineWidth="2";
oCG.moveTo(200,200);
oCG.arc(200,200,100,(Seconds*6-90)*Math.PI/180,(Seconds*6-90)*Math.PI/180,false);
oCG.stroke();
}
init();
</script>
//绘制视频
<video src="./Intermission-Walk-in_512kb.mp4" id="video" controls></video>
<canvas class="myCanvas"></canvas>
<script>
var oC=document.getElementsByClassName('myCanvas')[0];
var oCG=oC.getContext('2d');
var video=document.getElementsByTagName('video')[0];
//必须是window.onload,此外video.onloadedmetadata也是可以的
window.onload = function (){ //图片加载成功后绘制图片
oC.width=video.videoWidth;
oC.height=video.videoHeight;
setInterval(function(){
oCG.clearRect(0,0,oC.offsetWidth,oC.offsetHeight);
oCG.drawImage(video,0,0);
},16.67);
}
</script>
//自制画笔功能
<canvas width="400" height="300" class="myCanvas"></canvas>
<br/>
<input type="text" placeholder="请输入画笔的宽度" value="3"/>
<span>画笔的颜色:</span><input type="color" />
<script>
var oC=document.getElementsByClassName('myCanvas')[0];
var oCG = oC.getContext('2d');
var oWidth=document.getElementsByTagName('input')[0];
var oColor=document.getElementsByTagName('input')[1];
oCG.lineWidth=oWidth.value;
oCG.strokeStyle=oColor.value;
oC.onmousedown=function(e){
oCG.beginPath();
oCG.moveTo(e.pageX-oC.offsetLeft,e.pageY-oC.offsetTop);
document.onmousemove=function(ev){
oCG.lineTo(ev.pageX-oC.offsetLeft,ev.pageY-oC.offsetTop);
oCG.stroke();
}
document.onmouseup=function(){
oCG.closePath();
document.onmouseup=document.onmousemove=null;
}
}
oWidth.onchange=function(){
oCG.lineWidth=oWidth.value;
}
oColor.onchange=function(){
oCG.strokeStyle=oColor.value;
}
</script>
1.js有jQuery库,canvas如果不做封装写起来也是很麻烦,且不能像对象一样操作。jCanvas就是一个基于jQuery的免费且开源的 HTML5的Canvas API。它能让你用原生的Canvas API来实现,并可以做更多的事情。你也可以将原生的Canvas API方法和jCanvas一起使用,draw()方法就可以这样使用。你还可以用自己的方法结合 extend()函数来扩展jCanvas的功能。
2.jCanvas需要依赖 jQuery才能正常工作,所以还要确保引入了 jQuery文件:
<script src="js/jquery.min.js"></script>
<script src="js/jcanvas.js"></script>
drawRect()方法
$("canvas").drawRect({
fillStyle: 'steelblue', //设置填充色
strokeStyle: 'blue', //设置边框色
strokeWidth: 4, //设置边框宽
x: 150, //设置基点x轴位置
y: 100, //设置基点y轴位置
fromCenter: false, //基点是否为中心点(false为矩形左上角)
width: 200, //设置矩形宽
height: 100 //设置矩形高
});
drawArc() 方法
$("canvas").drawArc({
fillStyle: 'steelblue',
strokeStyle: 'blue',
strokeWidth: 4,
x: 300, y: 100, //设置圆心x/y轴位置
radius: 50, //设置半径
ccw:true, //是否逆时针(false默认值为顺时针)
start: 0, end: 200 //设置起点/终点角度(0为12点位置)
});
由于绘制对象是jQ对象,因此可以像jQ一样进行链式操作,绘制一个笑脸:
$("canvas").drawArc({ // draw the face
fillStyle: 'yellow',
strokeStyle: '#333',
strokeWidth: 4,
x: 300,
y: 100,
radius: 80
}).drawArc({ // draw the left eye
fillStyle: '#333',
strokeStyle: '#333',
x: 265,
y: 85,
radius: 5
}).drawArc({ // draw the right eye
fillStyle: '#333',
strokeStyle: '#333',
x: 335,
y: 85,
radius: 5
}).drawArc({ // draw the smile
strokeStyle: '#333',
strokeWidth: 4,
x: 300, y: 120,
radius: 30,
start: 110,
end: 250
});
drawLine()
$("canvas").drawLine({
strokeStyle: 'steelblue',
strokeWidth: 10,
rounded: true, //设置边界连接点是否为圆角
closed: true, //设置是否闭合路径
x1: 100, y1: 28, //设置第一个点坐标......
x2: 50, y2: 200,
x3: 300, y3: 200,
x4: 200, y4: 109
});
drawText()
$("canvas").drawText({
text: 'Canvas is fun', //文字内容
fontFamily: 'cursive', //字体
fontSize: 40, //字体大小
x: 290, y: 150,
fillStyle: 'lightblue',
strokeStyle: 'blue',
strokeWidth: 1
});
drawPath()方法。你可以用画线条和曲线同样的方式画箭头,但你必须提供一些箭头专有的属性
$("canvas").drawPath({
strokeStyle: '#000',
strokeWidth: 4,
x: 10,
y: 10,
//以(10,10)为canvas画布的原点
p1: { //当type="line"时其实就相当于绘制线条
type: 'line', //路径类型(常用的line-线、arc-圆弧、quadratic-二次曲线、vector-矢量)
x1: 100, y1: 100, x2: 200, y2: 100
},
});
//绘制箭头
$("canvas").drawPath({
strokeStyle: '#000',
strokeWidth: 4,
x: 10,
y: 10,
p1: { //第二部分
type: 'line',
startArrow: false, //是否有一个箭头画在路径的开始点。
endArrow: true, //是否有一个箭头画在路径的结束点
arrowRadius: 25, //箭头的每个尖端的长度
arrowAngle: 90, //箭头两个尖端的夹角
x1: 100,
y1: 100,
x2: 290,
y2: 100
},
p2: { //第三部分
type: 'line',
startArrow: false,
endArrow: true,
arrowRadius: 25,
arrowAngle: 90,
x1: 100,
y1: 100,
x2: 100,
y2: 250
}
});
drawImage()方法
$('canvas').drawImage({
source: $('#fish')[0], //绘制DOM已经存在的图片,或用'imgs/cat.jpg'绘制未加载的图片
x: 50,
y: 50,
fromCenter: false,
width: 100,
height: 100, //图片大小
shadowColor: '#222', //阴影颜色
shadowBlur: 3, //模糊距离
rotate: 40, //旋转角度
load (){ //未加载的图片可以设置
//加载图片后的代码,
}
});
该方法本来就是在图片加载成功之后才绘制的。
addLayer()方法或layer属性,向画布添加了一个图层。
$('canvas').drawRect({
layer: true, //创建一个图层后绘制图形
name: 'myBox', //用来检索图层、删除图层或变动图层
fillStyle: '#585',
x: 100,
y: 100,
width: 100,
height: 50
});
1.可以在任何jCanvas图层上绑定任意数量的jCanvas事件。jCanvas支持鼠标事件和触摸事件事件会和 图层API结合使用。
2.支持事件的方法:drawRect()、drawArc()、drawEllipse()、drawLine()、drawQuadratic()、drawBezier()、drawVector()、drawGraph()、drawPolygon()、、drawImage()、drawText()
3.支持的事件:click、dblclick、mousedown、mouseup、mousemove、mouseover、mouseout、dragstart、drag、dragstop、touchstart、touchend、touchmove
4.配合animateLayer执行动画效果
$('canvas').drawRect({
layer: true,
//绘制图层
fillStyle: '#6c0',
x: 100,
y: 100,
width: 100,
height: 80,
click (layer) {
//layer为图层对象
$(this).animateLayer(layer,{
rotate : layer.rotate+144
},400)
}, //参数:执行动画的图层对象、变化样式和动画时间
animatestart (layer){},
//动画开始时,要运行的代码
animate (layer, fx){},
//动画相关属性的动画fx(prop属性为执行动画的样式、start为初始值、now为当前值、end为结束值)的每个帧上运行这些代码
animateend (layer){}
//动画结束时,要运行的代码
});
1.利用属性draggable设置为true可以把一个图层变成可拖曳。
$('canvas').drawArc({
layer: true,
draggable: true,
fillStyle: '#36c',
x: 150,
y: 150,
radius: 50
}).drawRect({
layer: true,
draggable: true,
fillStyle: '#6c1',
x: 100,
y: 100,
width: 100,
height: 100
});
2.拖曳事件:通过定义dragstart、drag、dragstop和dragcancel为各种拖曳事件提供回调函数。
$('canvas').drawArc({
layer: true,
draggable: true,
fillStyle: '#36c',
x: 150,
y: 150,
radius: 50,
groups: ['shapes'],
//设置图层组,设置该值的图层即为同一组
dragGroups: ['shapes'],
//拖曳编组,当图层被拖曳时,同一编组中所有其它图层都会被拖动。
dragstart (layer) { },
// 在拖曳开始时要运行的代码
drag (layer) { },
// 当正在拖曳时要运行的代码
dragstop (layer) { },
// 在停止拖曳时要运行的代码
dragcancel (layer) { }
// 在把一个图层拖出画布时要运行的代码(拖拽过程中鼠标离开画布)
}).drawRect({
layer: true,
draggable: true,
fillStyle: '#6c1',
x: 100,
y: 100,
width: 100, h
eight: 100,
groups: ['shapes'],
dragGroups: ['shapes'] //设置与上面相同的组和拖拽编组
});
//制作一个不断有不同颜色的圆圈有不透明变为透明的效果
<canvas width="500" height="500"></canvas>
<script src="../jquery.js"></script>
<script src="./jcanvas.js"></script>
<script>
var index=0;
setInterval(function(){
index++;
$('canvas').drawArc({
layer:true,
name:'circle'+index, fillStyle:`rgb(${Math.random()*255},${Math.random()*255},${Math.random()*255})`,
x: Math.random()*$('canvas')[0].offsetWidth,
y: Math.random()*$('canvas')[0].offsetHeight,
radius: 5,
ccw:true,
start: 0,
end:360,
anmateend(layer){
$('canvas').removeLayer(layer.name);
}
}).animateLayer('circle'+index,{
opacity:0,
radius:50
},900)
},90)
</script>
数据可视化的目的是借助图形化清晰有效的传达与沟通信息,把数据从数字转换成图形,更好的揭示数据规律。ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。
<script src="echarts.min.js"></script>
<div class="box"></div>
//设置容器(必须有大小)
var myChart = echarts.init(document.querySelector(".box"));
//得到echarts实例对象
var option = {
//指定配置项和数据
//配置code
};
myChart.setOption(option);
//将配置项赋予echarts实例对象
option配置对象中包含很多需要配置的属性:
1.首先在官网查找我们需要的类似实例,将其引入到HTML页面中,并根据需求定制图标。由于每个实例都需要初始化echarts实例对象和设置,因此需要用到立即执行函数来防止变量污染。
2.定制图表效果:根据我们的需要修改图表内容和样式,找到该实例的设置内容,按照配置属性修改(更详细的设置请查看官网的配置项手册)
3.图表自适应浏览器大小
window.onresize = function (){
myChart.resize();
}
chart.js和Echarts(百度)的区别
//做一个学习前端的Echarts图
<style>
.box{
width: 600px;
height: 500px;
}
</style>
<div class="box"></div>
<script src="https://cdn.bootcss.com/echarts/3.6.2/echarts.min.js"></script>
<script>
var myChart = echarts.init(document.querySelector(".box"));
var option={
title: {
text: '前端学习组成',
subtext: '纵使风吹',
left: 'center',
bottom:'0%'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left',
},
series: [
{
name: '组成部分',
type: 'pie',
radius: '60%',
data: [
{value: 0.1, name: 'HTML和CSS'},
{value: 0.1, name: 'HTML5和CSS3'},
{value: 0.3, name: 'JavaScript'},
{value: 0.02, name: 'webpack'},
{value: 0.02, name: 'Git'},
{value: 0.05, name: 'ES6'},
{value: 0.03, name: 'JQuery'},
{value: 0.03, name: '移动端'},
{value: 0.15, name: 'React'},
{value: 0.1, name: 'VUE'},
{value: 0.1, name: '项目实战'},
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
myChart.setOption(option);
</script>
如图所示: