一、D3能做什么?

D3主要应用于2D场景 svg不生效
D3.js 是一个使用动态图形进行数据可视化的JavaScript程序库

二、D3特点

一款基于JavaScript的函数库
借助HTML、SVG和CSS等实现可视化
组件强大,通过数据驱动的方式来操作DOM
svg和Canvas使用D3:
SVG:可缩放矢量图形,用于绘制可视化的图形
SVG 是使用 XML 来描述二维图形和绘图程序的语言。
Canvas 绘制的图像 都在Canvas这个画布里面,是Canvas的一部分,不能用js获取已经绘制好的图形元素。

三、选择元素与绑定数据

1.其实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’) //不需要遍历,直接对整体进行操作
2.当我们需要在当前dom中append一个子元素时,append返回的不是当前dom,而是子元素
d3.select(‘p’).append(‘span’).text(‘I am in span’) //文本添加在span复制代码
3.insert(newElement, targetElement) 返回插入的元素

p1

target

p2

复制代码
d3.select(‘body’).insert(‘p’, ‘#target’).text(‘I am new here’).style(‘color’, ‘pink’)复制代码
新的p会被插到target前面
4.remove删除元素
d3.select(‘body’).select(‘#target’).remove() //先选中然后直接remove复制代码
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})复制代码
6.选中的dom和数据一一绑定
复制代码
let dataset = [‘javascript’, ‘css’, ‘html’]d3.select(‘#list’).selectAll(‘li’).data(dataset).text((d, i) => i+ ‘ : ‘ + d)复制代码

四、svg属性

在线编辑网址: https://www.nhooo.com/run/138120.html

  1. svg坐标

SVG 坐标空间的 x = 0,y = 0 坐标位于左上角。
SVG 坐标空间的 Y 坐标从上到下增长。

  1. svg的transform属性:

transform的种类translate(平移)、skew(倾斜)、rotate(旋转)、scale(缩放)

  1. svg形状

文本text I love SVG
线条

矩形
圆形
椭圆
<svg xmlns=”http://www.w3.org/2000/svg” version=”1.1”>
style=”fill:none;stroke:black;stroke-width:3” />

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

五、实现思路

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;
});
[

](https://www.w3school.com.cn/svg/svg_rect.asp)

六、svg项目使用

  1. 安装命令 npm install d3 —save-dev
    2. 项目引入D3 import as d3 from ‘d3’ |

    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)
    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’))}
    5. 将一个’g’元素添加到SVG.g元素用于将SVG形状组合在一起 transform将svg标签放到页面中间
    let gbody = svg.append(‘g’).data([gwData.availableZone])
    6. svg的data只接受数组的数据
    .attr(‘transform’, this.lastPosition || ‘translate(‘+ widthScale +’, ‘+ heightScale +’) scale(1)’)
    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事件绑定 - 网关
}