一、D3能做什么?
- D3主要应用于2D场景 svg不生效
D3.js 是一个使用动态图形进行数据可视化的JavaScript程序库
二、D3特点
一款基于JavaScript的函数;借助HTML、SVG和CSS等实现可视化;组件强大,通过数据驱动的方式来操作DOM;
svg和Canvas对比:SVG:可缩放矢量图形,用于绘制可视化的图形
- SVG 是使用 XML 来描述二维图形和绘图程序的语言。
- Canvas 绘制的图像 都在Canvas这个画布里面,是Canvas的一部分,不能用js获取已经绘制好的图形元素。
三、选择元素与绑定数据
1.直接操作dom-d3选中元素和jQuery很像
d3主要通过select , selectAll实现选择元素,参照原生js的querySelector querySelectorAll;
d3是支持连缀操作的,当你选中元素后可以直接去更改它们; ``` const dataset = [12, 31, 22]; d3.select(‘body’).data(dataset).enter().append(‘h2’).text(‘New Title’) // data()方法接收数组作为参数,并运行三次后面的代码,每次对应数组中的一个对象。 d3.select(‘body’).selectAll(‘h2’).data(dataset).enter().append(‘h2’).text(‘New Title’) // select()这个标签元素,可用链式向标签里添加html节点append(),在往节点添加文本text() d3.select(‘p’).style(‘background’, ‘yellow’) d3.selectAll(‘p’).style(‘background’, ‘yellow’) // 不需要遍历,直接对整体进行操作
<a name="w6XUB"></a>
#### 2.当我们需要在当前[dom](https://so.csdn.net/so/search?q=dom&spm=1001.2101.3001.7020)中append一个子元素时,append返回的不是当前dom,而是子元素
d3.select(‘p’).append(‘span’).text(‘I am in span’) //文本添加在span复制代码
<a name="JuRam"></a>
#### 3.insert(newElement, targetElement) 返回插入的元素
p1
target
p2
// 讲新的p插到target前面 d3.select(‘body’).insert(‘p’, ‘#target’).text(‘I am new here’).style(‘color’, ‘pink’)
<a name="E4zhP"></a>
#### 4.remove删除元素
d3.select(‘body’).select(‘#target’).remove() //先选中然后直接remove
<a name="lPKng"></a>
#### 5.一些常用的修改dom样式,属性和内容的api
attr,style,text 看名字其实就知道,attr常用来修改svg节点的属性, 这用attr做个案例
d3.selectAll('p').text((d, i) => {
if (i === 2) {
d3.select(this).attr('class', 'new') //this为html
} return d
})
<a name="vybgc"></a>
#### 6.选中的dom和数据一一绑定
let dataset = [‘javascript’, ‘css’, ‘html’] d3.select(‘#list’).selectAll(‘li’).data(dataset).text((d, i) => i + ‘ : ‘ + d)
<a name="VGq5s"></a>
## 四、svg属性
在线编辑网址: [https://www.nhooo.com/run/138120.html](https://www.nhooo.com/run/138120.html)
<a name="zhhuV"></a>
### 1.svg坐标
SVG 坐标空间的 x = 0,y = 0 坐标位于左上角。<br />SVG 坐标空间的 Y 坐标从上到下增长。
<a name="Hs82P"></a>
### 2.svg的transform属性:
transform的种类translate(平移)、skew(倾斜)、rotate(旋转)、scale(缩放)
<a name="SyE9O"></a>
### 3.svg形状
// 折线
// 文本
<a name="uTydK"></a>
#### 4.svg事件
鼠标事件
- click:鼠标单机某元素(mousedown+mouseup)
- mouseover:光标放在某元素上
- mouseout:光标从某元素上移出来
- mousemove:鼠标被移动
- mousedown:鼠标被按下
- mouseup:鼠标按钮被松开
- 双击:没有 click+延迟判定来模拟(还不会)
键盘事件
- keydown:按下任意键触发
- keypress:按下字符键触发
- keyup:释放键触发
触屏
- touchstart:触摸点放在触摸屏上时
- touchmove:触摸点移动
- touchend:触摸点拿开
svg其他属性,详见:[https://www.w3school.com.cn/svg/svg_rect.asp](https://www.w3school.com.cn/svg/svg_rect.asp)
<a name="PMQay"></a>
## 五、实现思路
- svg是操作dom元素, 在生命周期mounted/created里面操作dom,通过jquery操作dom的方式,给元素添加属性,用svg显示形状,在svg区域中创建图形。
- svg 支持多种图形,比如矩形和圆形,并用它们来显示数据。例如,在条形图中一个矩形(rect )svg 图形可以创建一个组。
- svg 的rect有四个属性。x和y坐标指定图形放在svg区域的位置,height和width指定图形大小。
- rect元素和div有一些不同,rect必须添加在svg元素内,而不能直接添加在body内。同时,你需要告诉 D3 将rect放在svg区域的哪个位置。
// 添加中心区域背景底色 g.append(“rect”) .attr(“x”, -8) .attr(“y”, -5) .attr(‘width’, 155) .attr(‘height’, 137) .attr(“fill”, ‘rgba(32, 64, 132, 0.3)’) // 添加文字 g.append(“text”) .attr(“x”, 0) .attr(“y”,122) .attr(“font-size”, 14) .attr(“fill”, ‘#E0FFF9’) .text(function(data) { return data.center; });
<a name="szxCK"></a>
## 六、svg项目使用
<a name="V5asX"></a>
#### 1. 安装命令
npm install d3 —save-dev
<a name="hIoiS"></a>
#### 2.项目引入D3
import * as d3 from ‘d3’ |
<a name="DpGTR"></a>
#### 3.绘制矩形方阵, 按照标准分辨率1440*900的尺寸,设置设置svg的宽高
let width = 1300, height = 780, gwWidth = 40, gwHeight = 40, clientWidth = document.documentElement.clientWidth, clientHeight = document.documentElement.clientHeight, widthScale = ((clientWidth - width) / 2), heightScale = ((clientHeight - height) / 2), div = d3.select(‘#chart’), svg = div.append(‘svg’) .attr(“id”,”mainSvg”) .attr(‘width’, clientWidth) .attr(‘height’, clientHeight)
<a name="rcio7"></a>
#### 4. 基于中心缩放方法
function zoomed() { let _t = d3.event.transform gbody.attr(‘transform’, ‘translate(‘+ (widthScale + _t.x) +’, ‘+ (heightScale + _t.y) +’) scale(‘+_t.k+’)’) localStorage.setItem(“key”, $(‘#mainSvg’).find(‘g’).attr(‘transform’))}
<a name="olaCe"></a>
#### 5.将一个'g'元素添加到SVG.g元素用于将SVG形状组合在一起 transform将svg标签放到页面中间
let gbody = svg.append(‘g’).data([gwData.availableZone])
<a name="W11X7"></a>
#### 6.svg的data只接受数组的数据
.attr(‘transform’, this.lastPosition || ‘translate(‘+ widthScale +’, ‘+ heightScale +’) scale(1)’)
<a name="jIxbg"></a>
#### 7.绘制线条
// 绘制线条-集群之间的调用情况 function drawLine(drawData){ for(var x = 0; x < drawData.length; x++){ let _item = drawData[x]; let dx = 0, x1=_item.x1,y1=_item.y1,x2=_item.x2,y2=_item.y2; let dy = Math.round(Math.abs( ( ( y2 - y1 ) / ( x2 - x1 ) ) * dx )); // 绝对值随机数 //向右上弯曲 let cpx = Math.round(( x1 + x2 ) / 2 + dx); let cpy = Math.round(( x1 + x2 ) / 2 - dy); var path = d3.path(); path.moveTo(x1,y1); path.quadraticCurveTo(cpx,cpy,x2,y2); drawData[x].path = path.toString(); } drawData.forEach(item => { let _item = item; gbody.append(‘path’) // 添加路径 .attr(‘d’, item.path) .attr(‘JSON’,JSON.stringify(item)) .attr(‘fill’,’none’) .attr(‘stroke-opacity’,’0.5’) // 透明度 .attr(‘stroke’, getStrokeState(_item.state)) .attr(‘marker-start’,’’) // 开始箭头 .attr(‘marker-end’,’url(#markerArrow)’) // 结束箭头 .on(“click”, lineClick) // click事件绑定 - 集群关系线条 }) }
// 根据数据绘制中心的数据 gbody.selectAll(‘g.centers’) .data(gwData.centers) //实例相关信息 将借口返回的数据渲染到页面上 .enter() .append(‘g’) .attr(‘transform’, function(d, i) { return’translate(‘+ 166 (i % 8)+’,’+ 148 (parseInt(i/8)+1)+’)’; }) // 一排八个 .attr(“key”, function(d,i){ return d.center }) .each(function(d, i) { drawCenter(d3.select(this), d, i); }); //调取方法 循环数组渲染
```
function drawCenter(g, data, index) {
// 添加文字
g.append("text")
.attr("x", 0)
.attr("y",122)
.attr("font-size", 14)
.text(function(data) {
return data.center;
});
// 绘制图片
g.selectAll('image')
.data(function(data) {
return data.clusters;
})
.enter()
.append('image')
.attr('xlink:href', function(d, i) {
return getClustersState(d.state);
})
.attr('x', function(d, i) {
return24 * (i % 6); // 取余
})
.attr('y', function(d, i){
return24 * (parseInt(i/6)); // 取整
})
.attr("state", function(d,i){
return d.state // 记录集群状态值
})
.attr("key", function(d){
let _cx = ((this.x.baseVal.value +
this.parentNode.transform.animVal[0].matrix.e) + 6),
_cy = ((this.y.baseVal.value +
this.parentNode.transform.animVal[0].matrix.f) + 10);
allNodes.push({
type:'center',
key:d.cluster,
cx: _cx,
cy: _cy,
})
return d.cluster
})
.attr("cx", function(d,i){
return ((this.x.baseVal.value +
this.parentNode.transform.animVal[0].matrix.e) + 9) // 计算元素x轴位置信息
})
.attr("cy", function(d,i){
return ((this.y.baseVal.value +
this.parentNode.transform.animVal[0].matrix.f) + 6)// 计算元素y轴位置信息
})
.attr('width', 18)
.attr('height', 18)
.on("click", clustersClick) // 点击事件绑定 - 网关
.on("mouseover", clustersMouseover) // mouseover事件绑定 - 网关
.on("mouseout",clustersMouseout) // mouseout事件绑定 - 网关
}