D3中的each() 以及svg defs元素 clipPath的使用
each() 方法允许我们定制对选择集中DOM元素的处理行为:
selection . each ( func )
参数 func 是调用者定义的函数,在d3中被称为 访问器/accessor 。 d3将对选择集中的 每一个 DOM对象, 依次 调用该访问器函数。
在调用 访问器 函数时,d3会将 this 指向当前要处理的 DOM对象 , 并传入两个参数:
datum : 当前DOM对象对应的数据
index :当前DOM对象在集合中的序号
可以认为 访问器 是d3流水线中每个处理环节 用户逻辑 的封装接口,d3通过这个接口, 实现了 流水线框架 和 用户处理逻辑 的 解耦 :
const d3Elements = d3Svg.selectAll('#dangan-elements').data(['elements']); //图片部分
d3Elements.enter().append('g').attr('id', 'dangan-elements');
// svg选中所有class为 elementName 的依次进行处理
var clipBox = d3Elements.selectAll('.'+elementName).data(data).enter()
.append('g')
.classed(elementName, true)
.classed(d => ({'dangan-click': d.click}))
.attr('clip-path', (d,i) => `url(#${unique+clipName+i})`)
.each(function(d) {
console.log(d);
}
SVG defs元素
SVG的<defs>元素用于预定义一个元素使其能够在SVG图像中重复使用。例如你可以将一些图形制作为一个组,并用<defs>元素来定义它,然后你就可以在SVG图像中将它当做简单图形来重复使用。
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<g>
<rect x="100" y="100" width="100" height="100" />
<circle cx="100" cy="100" r="100" />
</g>
</defs>
</svg>
在<defs>元素中定义的图形不会直接显示在SVG图像上。要显示它们需要使用<use>元素来引入它们。如下面的代码所示:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<g id="shape">
<rect x="50" y="50" width="50" height="50" />
<circle cx="50" cy="50" r="50" />
</g>
</defs>
<use xlink:href="#shape" x="50" y="50" />
<use xlink:href="#shape" x="200" y="50" />
</svg>
要引用<g>元素,必须在<g>元素上设置一个ID,通过ID来引用它。<use>元素通过xlink:href属性来引入<g>元素。注意在ID前面要添加一个#。
在<use>元素中,通过x和y属性来指定重用图形的显示位置。注意在<g>元素中的图形的定位点都是0,0,在使用<use>元素来引用它的时候,它的定位点被转换为<use>元素x和y属性指定的位置。
哪些元素可以被定义为defs中的元素呢?
任何图形元素,如:rect,line g symbol
1.SVG中的clip-path
SVG中,有个名叫<clipPath>的元素,其专门用来定义剪裁路径的。举个简单例子:
<defs><!-- 定义 -->
<clipPath id="clipPath"><!-- 定义剪裁路径 -->
<rect x="0" y="0" width="80" height="80" /><!-- 路径详细 -->
</clipPath>
</defs>
上面的<clipPath>定义了一个80*80的矩形剪裁路径。OK,假设现在SVG中有个圆,SVG代码如下:
<circle cx="60" cy="60" r="50" fill="#34538b" />
按照我们浅显的认识,应该会出现一个填充某种颜色的圆。
SVG一个普通的圆
但是,如果此时该圆同时设置了clip-path属性,且值指向的就是上面定义的剪裁路径#clipPath呢?
<circle cx="60" cy="60" r="50" fill="#34538b" clip-path="url(#clipPath)" />
则,十五的圆被剪裁成了银杏叶:
跟<g>, <symbol>等元素类似,<clipPath>元素里面除了rect元素, 还可以是circle, ellipse, line, polyline, polygon, ...等等,甚至是text文本。
<svg> <defs> <clipPath id="clipPath"> <text x="10" y="50" style="font-size: 20px;">一步之遥</text> </clipPath> </defs> <g style="clip-path: url(#clipPath);"> <circle cx="60" cy="60" r="50" fill="#34538b" /> <rect x="0" y="0" width="60" height="90" style="fill:#cd0000;"/> </g> </svg>
2. enter().append("rect").append("rect")
添加的第二个rect 是在第一个的基础里添加的
相当于 <rect>
<rect></rect>
</rect>
例 <p>Hello World 1</p>
<p>Hello World 2</p>
var width = 300; //画布的宽度 var height = 300; //画布的高度 var svg = d3.select("body") //选择文档中的body元素 .append("svg") //添加一个svg元素 .attr("width", width) //设定宽度 .attr("height", height); //设定高度 var dataset = [ 250 , 210 , 170 , 130 , 190 ]; var rectHeight = 25; //每个矩形所占的像素高度(包括空白) svg.selectAll("rect") .data(dataset) .enter() .append("rect") .attr("x",20) .attr("y",function(d,i){ return i * rectHeight; }) .attr("width",function(d){ return d; }) .attr("height",rectHeight-2) .attr("fill","steelblue") .append("rect") .attr("x",20) .attr("y",function(d,i){ return i * rectHeight; });