D3.js 以圆做点绘制力图(一)

news/2024/11/17 3:05:52/

SVG是什么?

如何在SVG上绘制一个圆?

如何在SVG上绘制一条线?

力图的基本属性有哪些?

这些问题将由本文来一一解答。

在代码方面,我们沿用上文的网页框架,把body里面的js替换成现在的js即可。


SVG

  SVG,可缩放的矢量图,我们以后所绘制 的数据展示图大都是在SVG这个大容器内完成的,它相当于画布。创建SVG,就是有利于导出、保存绘制好的图形。

  简单的SVG标签格式 <svg width="500" height="50"></svg>,在SVG标签中可以嵌入很多可见元素,包括 rect、circle、ellipse、line、text和path。

  下面,我们在body中创建一个js标签,在里面创建一个svg对象,代码如下:

<span style="font-size:14px;">var w = 500;
var h = 500;
var svg = d3.select("body").append("svg").attr("width", w)          //设置宽度.attr("height", h);        //设置高度</span>
 
绘制圆

在svg内添加circle元素,先介绍下circle的基本属性:cx 圆心x坐标  cy圆心y坐标   r半径

接下来,绘制五个半径依次增大的圆,并将它们的圆心放到同一条y轴上,代码如下

<span style="font-size:14px;"> var dataset = [ 5, 10, 15, 20, 25 ];var circles = svg.selectAll("circle").data(dataset)        .enter().append("circle");  circles.attr("cx", function(d, i) {//圆心坐标从左向右依次递增,注意:i表示引入数据在数组的下标,如:d=5,i=0return (i * 50) + 25;}).attr("cy", h/2) //将圆心放到svg高度中间.attr("r", function(d) {//半径return d;})</span>

紧接着设置各圆的属性

<span style="font-size:14px;">    .attr("fill", "yellow")         //给各圆填充黄色.attr("stroke", "orange")       //给各圆边涂成橘黄.attr("stroke-width", function(d) { //按比例设置边的厚度return d/2;
}); 
</span>

至此,SVG上的圆就绘制完成了见下图


绘制线

在svg绘制一条线,首先要定义它的两个端点,起点和终点 (x1,y1)和(x2,y2)

线的基本属性包括:

  • x1 属性在 x 轴定义线条的开始
  • y1 属性在 y 轴定义线条的开始
  • x2 属性在 x 轴定义线条的结束
  • y2 属性在 y 轴定义线条的结束

<span style="font-size:14px;">var line = svg.append('line').attr('x1',100)   .attr('y1',100).attr('x2',200).attr('y2',200).attr('style','stroke:rgb(99,99,99);stroke-width:2'); //描边宽度</span>
显示效果图如下:



用力图简介

  有点有线,那么有关联的点用线相连,再设置下点之间的电荷排斥力,让没关联的点保持距离, 那么力图的雏形就形成了。

  力学图( Force ),也有被翻译做力导向图等。这种图很有意思,先从初始数据开始,看下面代码:

{"nodes":[{"name":"Myriel","group":3,"QQ":"635511111"},{"name":"Napoleon","group":1,"QQ":"635511112"},{"name":"Mlle.Baptistine","group":1,"QQ":"635511113"},{"name":"Mme.Magloire","group":1,"QQ":"635511114"},{"name":"CountessdeLo","group":1,"QQ":"635511115"},{"name":"Geborand","group":1,"QQ":"635511116"},{"name":"Champtercier","group":1,"QQ":"635511117"},{"name":"Cravatte","group":1,"QQ":"635512111"},{"name":"Count","group":1,"QQ":"635513111"},{"name":"OldMan","group":1,"QQ":"635514111"},{"name":"Labarre","group":2,"QQ":"635515111"},{"name":"Valjean","group":2,"QQ":"635516111"},{"name":"Marguerite","group":3,"QQ":"635531111"},{"name":"Mme.deR","group":2,"QQ":"635511311"},{"name":"Isabeau","group":2,"QQ":"635511211"},{"name":"Gervais","group":2,"QQ":"635514111"},{"name":"Tholomyes","group":3,"QQ":"635571111"},{"name":"Listolier","group":3,"QQ":"635581111"},{"name":"Fameuil","group":3,"QQ":"635511011"},{"name":"Blacheville","group":3,"QQ":"635211111"},{"name":"Favourite","group":3,"QQ":"635510111"},{"name":"Dahlia","group":3,"QQ":"635511121"}],"links":[{"source":1,"target":0,"value":1},{"source":2,"target":0,"value":8},{"source":3,"target":0,"value":10},{"source":3,"target":2,"value":6},{"source":4,"target":0,"value":1},{"source":5,"target":0,"value":1},{"source":6,"target":0,"value":1},{"source":7,"target":0,"value":1},{"source":8,"target":0,"value":2},{"source":9,"target":0,"value":1},{"source":11,"target":1,"value":1},{"source":11,"target":3,"value":3},{"source":11,"target":2,"value":3},{"source":11,"target":0,"value":5},{"source":12,"target":2,"value":1},{"source":13,"target":2,"value":1},{"source":14,"target":2,"value":1},{"source":15,"target":2,"value":1},{"source":17,"target":3,"value":4},{"source":18,"target":3,"value":4},{"source":18,"target":3,"value":4},{"source":19,"target":3,"value":4},{"source":19,"target":2,"value":4},{"source":19,"target":3,"value":4},{"source":20,"target":4,"value":3},{"source":20,"target":1,"value":3},{"source":20,"target":2,"value":3},{"source":20,"target":3,"value":4},{"source":21,"target":16,"value":3},{"source":21,"target":17,"value":3},{"source":21,"target":18,"value":3},{"source":21,"target":19,"value":3},{"source":21,"target":20,"value":5}]
}

这些数据包含两部分,点(nodes)和边(links),source 和target的数值代表nodes数组该数值下标对应的元素。

注意的一点,不管nodes元素有多少属性,source和target都暂时指向人名,如source 1 target0 表示napoleon和myriel连接

细细一看就会发现,这些点只是些人员的属性而已,光靠这些是无法知道每个点该画到哪儿。

  所以就需要先了解一下D3 画力图的一些专有方法了 。下面为大家罗列一些必要的方法和解释:

  为了使用方便先将上面的json数据,赋值给 dataset,放到js里

(以后这些数据都会保存在相应格式的文件中,由d3加载,加载方法在 D3总体展示篇已略有介绍) 

var force = d3.layout.force()  //转换数据的方法,将点转换为坐标格式
.nodes(<span style="font-size:14px;">dataset.</span>nodes)          //传入点
.links(dataset.links)          //传入边
.size([w, h])                  //设置图形宽高
.start();                      //开始转换

以上代码是 用力图最基础的布局方法。

这些基本布局并不能满足所有数据集,我们还要在这基础上添加一些layout的自定义方法,

 比如设置节点间连线的长度、节点间互斥力大小。完善之后的代码显示如下:

var force = d3.layout.force()
.nodes(dataset.nodes)
.links(dataset.edges)
.size([w, h])
.linkDistance([50]) // 节点连线长度
.charge([-100]) //    排斥力
.start();
至此,力图基本初始化布局完成

 接下来创建连线

var edges = svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);

这里的连线颜色和宽度都可以编写函数随意设定,例如同类人员设为同色,重要人员连线加粗等

然后为每个节点创建圆,方便浏览

var nodes = svg.selectAll("circle")
.data(dataset.nodes)
.enter()
.append("circle")
.attr("r", 10)
.style("fill", function(d, i) {
return colors(i);
})
.call(force.drag);    //增加拖动效果,拉动节点
 最后,我们就要打点,将点线绘制到画布上

force.on("tick", function() {
edges.attr("x1", function(d) { return d.source.x; }).attr("y1", function(d) { return d.source.y; }).attr("x2", function(d) { return d.target.x; }).attr("y2", function(d) { return d.target.y; });nodes.attr("cx", function(d) { return d.x; }).attr("cy", function(d) { return d.y; });
});
这样,每次打点,取得线和点的坐标,在更新到画布上。那么这些坐标哪儿来的?就是layout初始化转换传入的点线数据后,

 为他们模拟一些坐标信息。你可以在浏览器控制台输入dataset查看各点线坐标信息

  好了,最简单的用力图就这样完成了,后文会继续在此基础上讲解如何为个点设置图标、如何实现不同分组的群成员聚类缩放、如何显示成员信息、如何将圆替换为矩形块放置属性联系方式等,敬请期待!





http://www.ppmy.cn/news/580900.html

相关文章

机器学习强基计划9-2:图解字典学习KSVD算法(附Python实战)

目录 0 写在前面1 字典学习2 问题形式化3 KSVD算法4 Python实现 0 写在前面 机器学习强基计划聚焦深度和广度&#xff0c;加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理&#xff1b;“广”在分析多个机器学习模型&#xff1a;决策树、支持向量机、…

年轻人存款难题:挑战与可能

近日&#xff0c;有一项调查结果显示&#xff0c;大约五分之一的年轻人的存款不超过一万元。并且&#xff0c;存款达到十万元似乎成为一个“坎”&#xff0c;因为超过这个金额的存款已经超过了53.7%的人。这个令人关注的数据引发了广泛的讨论&#xff0c;让我们深入探讨一下年轻…

MySQL数据库——主从复制

目录 前言一、读写分离概述1. 什么是读写分离&#xff1f;2. 为什么要读写分离呢&#xff1f;3. 什么时候要读写分离&#xff1f;4. 主从复制与读写分离5. mysq支持的复制类型6. 主从复制的工作过程7. MySQL主从复制延迟 二、主从复制配置方法 前言 在实际的生产环境中&#x…

【TWS API使用教程2】---如何使用 TWS API在ubuntu和windows上分别设置contract、获取contract详细信息、设置order、下单、获取持仓信息、获取账户信息

这个是接下来几篇文章的汇总,先提供代码,大家尝试运行之后,没有问题了,再详细了解下,这些代码究竟有什么意义。 在测试的过程中,发现同样的代码,在ubuntu上和在windows上表现是不一样的 具体就是在windows上,基本上每两秒都会断联一次,导致运行的过程中,需要经常重新…

百款 TWS蓝牙耳机 蓝牙天线拆机分析与仿真

上一篇&#xff1a;贴片陶瓷天线原理 与 HFSS模型建立和仿真分析总结 &#xff08;原创文章&#xff0c;转载请与作者联系&#xff09; 0.前言 TWS是英文True Wireless Stereo的缩写&#xff0c;即真正无线立体声的意思&#xff0c;TWS技术同样也是基于蓝牙芯片技术的发展。 …

TWS耳机及相关蓝牙协议

TWS - True Wireless Stereo&#xff0c;即真正无线立体声 优势&#xff1a;真无线结构&#xff1b; 劣势&#xff1a;关键是蓝牙的传输方案不稳定&#xff1a; 1、传输稳定性差&#xff0c;容易受到外界干扰&#xff1b; 2、主副耳机信号不同步&#xff1b; 3、音质差&#x…

BES2500SDK TWS组队逻辑及触发机制详述

芯片上电初始化 跑到app_init&#xff08;再apps.cpp文件里面&#xff09; 代码断如下&#xff1a; int app_init(void) { int nRet 0; struct nvrecord_env_t *nvrecord_env; #ifdef POWER_ON_ENTER_TWS_PAIRING_ENABLED bool need_check_key false; #else …

【TWS API 使用教程8】一个基于TWS API的简单的程序化策略

使用前面的TWS API写成的simpleClient做了一个简单的策略,供大家参考。不要用于实盘,大概率会亏损。 TWS API相关的教程 【TWS API使用教程1】—如何在自己创建的client和TWS之间创建一个连接,并请求当前的时间 【TWS API使用教程2】—如何使用 TWS API在ubuntu和windows上…