接着上一节的内容,本次学习主要介绍SVG组合式应用以及js交互式应用!
1、组合式应用
绘制两棵带有投影效果的树!
<svg width="400" height="600"> <defs> <pattern id="grap" patternUnits="userSpaceOnUse" x="0" y="0" width="100" height="67" viewBox="0 0 102 76"> <image x="0" y="0" width="102" height="76" xlink:href="http://pic27.nipic.com/20130324/9148618_153134223000_2.jpg"></image> </pattern> <linearGradient id="TrunkGrad"> <stop offset="0%" stop-color="#663300"></stop> <stop offset="40%" stop-color="#996600"></stop> <stop offset="100%" stop-color="#552200"></stop> </linearGradient> <rect x="-5" y="-50" width="10" height="50" id="Trunk"></rect> <path d="M-25,-50L-10,-80L-20,-80L-5,-110L-15,-110L0,-140L15,-110L5,-110L20,-80L10,-80L25,-50Z" fill="#f00" id="can"> </path> <linearGradient id="shadow" x=0 y=0 x2=0 y2=100%> <stop offset="0%" stop-color="#000" stop-opacity=".5"></stop> <stop offset="20%" stop-color="#996600" stop-opacity="0"></stop> </linearGradient> <g id="tree"> <use xlink:href="#Trunk" fill="url(#TrunkGrad)"/> <use xlink:href="#Trunk" fill="url(#shadow)"/> <use xlink:href="#can" fill="none" stroke="#663300" stroke-linejoin="round" stroke-width="4px" /> <use xlink:href="#can" fill="#339900" stroke="none"/> </g> <g id="treeShadow"> <use xlink:href="#Trunk" fill="#000"/> <use xlink:href="#can" fill="#000" stroke="none"/> </g> </defs> <text y=60 x=200 font-family="Arial" font-size="60px" fill="#996600" text-anchor="middle">tree</text> <text y=90 x=200 font-family="Arial" font-size="20px" fill="#996600" text-anchor="middle" id="treeCounter"></text> <text y=550 x=20 font-family="Arial" font-size="20px" fill="#996600" text-anchor="left"> <tspan>点击一颗树或树的影子</tspan> <tspan>并移除掉它。。。</tspan> </text> <g transform="translate(-10,350)" stroke-width="20" stroke="url(#grap)" stroke-linejoin="round"> <path d="M0,0Q170,-50 260,-190Q310,-250 410,-250" fill="none"> </path> </g> <!--skewX() x轴方向向右扭曲25像素--> <use xlink:href="#treeShadow" transform="translate(130,250) scale(1,.6) skewX(-25)" opacity="0.4" /> <use xlink:href="#tree" transform="translate(130,250)" /> <use xlink:href="#treeShadow" transform="translate(260,500) scale(2,1.2) skewX(-25)" opacity="0.4" /> <use xlink:href="#tree" transform="translate(260,500) scale(2)" /> </svg>
说明:
scale(1,.6) :缩放 x轴缩放1倍,y轴缩放0.6倍
skewX(-25) :扭曲 x轴水平方向扭曲-25像素
<text y=550 x=20 font-family="Arial" font-size="20px" fill="#996600" text-anchor="left"> <tspan>点击一颗树或树的影子</tspan> <tspan>并移除掉它。。。</tspan> </text>
这里的tspan 类似于我们在页面中添加span标签,用于分割汉字
<linearGradient id="shadow" x=0 y=0 x2=0 y2=100%> <stop offset="0%" stop-color="#000" stop-opacity=".5"></stop> <stop offset="20%" stop-color="#996600" stop-opacity="0"></stop> </linearGradient>
stop-opacity=".5" :渐变的透明度设置
上诉代码运行结果如图:
2、SVG交互式应用
我们希望自己可以点击按钮的时候生成一颗随机的树,位置控制在svg画板中,而且点击生成的树还可以移除掉它!
新树的尺寸控制在50% - 150% 之间进行随机缩放!
首先我们创建一个添加树的函数:
/* document.createElementNS() 创建带有命名空间的的<use>元素 setAttributeNS() 方法创建或改变具有命名空间的属性。 语法: elementNode.setAttributeNS(name,value) */ document.getElementById('btn').onclick = function(){ var x = Math.floor(Math.random()*400);//随机数x var y = Math.floor(Math.random()*600);//随机数y var scale = Math.random()+0.5;//生成随机缩放的比例 var translate = 'translate('+x+','+y+')'; var tree = document.createElementNS('http://www.w3.org/2000/svg','use'); var treeSd = document.createElementNS('http://www.w3.org/2000/svg','use'); treeSd.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href','#treeShadow'); treeSd.setAttribute('transform',translate + ' scale('+ scale +','+ scale*0.6 +') skewX(-25)'); treeSd.setAttribute('opacity',0.4); document.querySelector('svg').appendChild(treeSd);//添加到svg中 tree.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href','#tree'); tree.setAttribute('transform',translate + ' scale('+ scale +')'); document.querySelector('svg').appendChild(tree);//添加到svg中 updateTrees(); }
接着我们创建一个更新树的数量的函数,以及给每棵树添加自己的移除的方法
function updateTrees(){ //查找所有的use元素 var list = document.querySelectorAll('use'); var treeCount = 0; for(var i=0;i<list.length;i++){ //如果是树或者树的阴影 if(list[i].getAttribute('xlink:href') == '#tree' || list[i].getAttribute('xlink:href') == '#treeShadow'){ treeCount++; //点击树或者阴影移除自己 list[i].onclick = removeTree; } } //更新数量 var counter = document.getElementById('treeCon'); counter.innerHTML = parseInt(treeCount/2) + 'trees in the svg'; }
创建树的移除的函数
function removeTree(e){ //e.target 被点击的目标对象 var e = e.target; /* e.correspondingUserElement 意思大概是当使用的元素有嵌套的时候使用最外层的元素作为目标对象 具体说明可参考地址: https://msdn.microsoft.com/en-us/library/ff971929(v=vs.85).aspx */ if(e.correspondingUserElement){ e = e.correspondingUserElement; } e.parentNode.removeChild(e); updateTrees(); }
完整的例子如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>svg 交互测试</title> </head> <style> svg{border:1px solid #000;} use:nth-of-type(even):hover{ opacity:0.9; cursor:crosshair;/*十字线光标*/ } use:nth-of-type(odd):hover{ opacity:0.5; cursor:crosshair;/*十字线光标*/ } </style> <body> <div > <button type="button" id="btn">点击按钮生成树</button> </div> <svg width="400" height="600"> <defs> <pattern id="grap" patternUnits="userSpaceOnUse" x="0" y="0" width="100" height="67" viewBox="0 0 102 76"> <image x="0" y="0" width="102" height="76" xlink:href="http://pic27.nipic.com/20130324/9148618_153134223000_2.jpg"></image> </pattern> <linearGradient id="TrunkGrad"> <stop offset="0%" stop-color="#663300"></stop> <stop offset="40%" stop-color="#996600"></stop> <stop offset="100%" stop-color="#552200"></stop> </linearGradient> <rect x="-5" y="-50" width="10" height="50" id="Trunk"></rect> <path d="M-25,-50L-10,-80L-20,-80L-5,-110L-15,-110L0,-140L15,-110L5,-110L20,-80L10,-80L25,-50Z" fill="#f00" id="can"> </path> <linearGradient id="shadow" x=0 y=0 x2=0 y2=100%> <stop offset="0%" stop-color="#000" stop-opacity=".5"></stop> <stop offset="20%" stop-color="#996600" stop-opacity="0"></stop> </linearGradient> <g id="tree"> <use xlink:href="#Trunk" fill="url(#TrunkGrad)"/> <use xlink:href="#Trunk" fill="url(#shadow)"/> <use xlink:href="#can" fill="none" stroke="#663300" stroke-linejoin="round" stroke-width="4px" /> <use xlink:href="#can" fill="#339900" stroke="none"/> </g> <g id="treeShadow"> <use xlink:href="#Trunk" fill="#000"/> <use xlink:href="#can" fill="#000" stroke="none"/> </g> </defs> <text y=60 x=200 font-family="Arial" font-size="60px" fill="#996600" text-anchor="middle">tree</text> <text y=90 x=200 font-family="Arial" font-size="20px" fill="#996600" text-anchor="middle" id="treeCounter"></text> <text y=550 x=20 font-family="Arial" font-size="20px" fill="#996600" text-anchor="left"> <tspan>点击一颗树或树的影子</tspan> <tspan>并移除掉它。。。</tspan> </text> <g transform="translate(-10,350)" stroke-width="20" stroke="url(#grap)" stroke-linejoin="round"> <path d="M0,0Q170,-50 260,-190Q310,-250 410,-250" fill="none"> </path> </g> <!--skewX() x轴方向向右扭曲25像素--> <use xlink:href="#treeShadow" transform="translate(130,250) scale(1,.6) skewX(-25)" opacity="0.4" /> <use xlink:href="#tree" transform="translate(130,250)" /> <use xlink:href="#treeShadow" transform="translate(260,500) scale(2,1.2) skewX(-25)" opacity="0.4" /> <use xlink:href="#tree" transform="translate(260,500) scale(2)" /> </svg> <p id="treeCon"></p> </body> <script> /* document.createElementNS() 创建带有命名空间的的<use>元素 setAttributeNS() 方法创建或改变具有命名空间的属性。 语法: elementNode.setAttributeNS(name,value) */ document.getElementById('btn').onclick = function(){ var x = Math.floor(Math.random()*400);//随机数x var y = Math.floor(Math.random()*600);//随机数y var scale = Math.random()+0.5;//生成随机缩放的比例 var translate = 'translate('+x+','+y+')'; var tree = document.createElementNS('http://www.w3.org/2000/svg','use'); var treeSd = document.createElementNS('http://www.w3.org/2000/svg','use'); treeSd.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href','#treeShadow'); treeSd.setAttribute('transform',translate + ' scale('+ scale +','+ scale*0.6 +') skewX(-25)'); treeSd.setAttribute('opacity',0.4); document.querySelector('svg').appendChild(treeSd);//添加到svg中 tree.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href','#tree'); tree.setAttribute('transform',translate + ' scale('+ scale +')'); document.querySelector('svg').appendChild(tree);//添加到svg中 updateTrees(); } function updateTrees(){ //查找所有的use元素 var list = document.querySelectorAll('use'); var treeCount = 0; for(var i=0;i<list.length;i++){ //如果是树或者树的阴影 if(list[i].getAttribute('xlink:href') == '#tree' || list[i].getAttribute('xlink:href') == '#treeShadow'){ treeCount++; //点击树或者阴影移除自己 list[i].onclick = removeTree; } } //更新数量 var counter = document.getElementById('treeCon'); counter.innerHTML = parseInt(treeCount/2) + 'trees in the svg'; } function removeTree(e){ //e.target 被点击的目标对象 var e = e.target; /* e.correspondingUserElement 意思大概是当使用的元素有嵌套的时候使用最外层的元素作为目标对象 具体说明可参考地址: https://msdn.microsoft.com/en-us/library/ff971929(v=vs.85).aspx */ if(e.correspondingUserElement){ e = e.correspondingUserElement; } e.parentNode.removeChild(e); updateTrees(); } </script>
说明:
use:nth-of-type(even):hover{ opacity:0.9; cursor:crosshair;/*十字线光标*/ } use:nth-of-type(odd):hover{ opacity:0.5; cursor:crosshair;/*十字线光标*/ }
这里是css3 新的选择方法
use:nth-of-type(even):选择奇数的use元素
use:nth-of-type(odd):选择偶数的use元素
当点击按钮的时候可以生成同样带有的投影效果的树,位置不一,大小不一!
鼠标移动到树或者影子的上面的时候出现十字光标,点击可以移除树或者影子
例子中我们看到,svg是可以通过dom操作元素,并添加事件处理函数的!这点比canvas在事件处理方面更灵活!
SVG的介绍大概先介绍这些,具体详细的API可以参考下面的地址:
https://developer.mozilla.org/zh-CN/docs/Web/SVG