可视化 | 【d3】桑基图

文章目录

  • d3
  • 桑基图应用
    • html
    • css
    • js

d3

d3.js是一个用于创建数据可视化的JavaScript库,它提供了丰富的API和工具来操作文档对象模型(DOM),使得创建可交互的、动态的数据可视化变得更加容易。

  1. 选择元素:使用d3.select()函数可以选择一个元素,使用d3.selectAll()函数可以选择多个元素。选择函数可以接收CSS选择器、DOM元素或函数作为参数。

    var svg = d3.select("#chart"); // 选择id为"chart"的元素
    var circles = d3.selectAll("circle"); // 选择所有的circle元素
    
  2. 绑定数据:使用.data()函数可以将数据绑定到选择的元素上。数据可以是数组、对象或函数的返回值。

    var data = [1, 2, 3, 4, 5];
    var circles = svg.selectAll("circle")
        .data(data);
    
  3. 创建元素:使用.enter()函数可以创建新的元素,这些元素对应于未绑定数据的选择集。可以使用.append().insert()等方法来创建元素。

    var circles = svg.selectAll("circle")
        .data(data)
        .enter()
        .append("circle");
    
  4. 设置元素属性:使用.attr()函数可以设置元素的属性,可以传入属性名和对应的值,也可以传入一个函数来动态计算属性值。

    	circles.attr("cx", function(d, i) {
    	    return i * 50; // 根据索引动态设置x坐标
    	})
    	.attr("cy", 50)
    	.attr("r", 20);
    
  5. 设置元素样式:使用.style()函数可以设置元素的样式,可以传入属性名和对应的值,也可以传入一个函数来动态计算样式值。

    circles.style("fill", "blue")
        .style("opacity", 0.5);
    
  6. 缓动过渡:使用.transition()可以为元素添加过渡效果,可以设置过渡时间、缓动函数等。

    circles.transition()
        .duration(1000)
        .attr("cx", function(d, i) {
            return i * 100;
        });
    
  7. 事件处理:可以使用.on()函数为元素绑定事件处理函数,可以处理鼠标事件(如click、mouseover等)和其他事件(如transitionend等)。

    circles.on("click", function(d) {
        console.log("Clicked:", d);
    });
    

桑基图应用

html

  • 放两个div,一个放图,一个用于悬浮框。
    <div id="chart">div>
    <div id="tooltip">div>
    

css

  • #tooltip: 定义了一个绝对定位的工具提示框样式,包括居中对齐、背景颜色、文本颜色和字体样式,以及圆角边框。pointer-events: none; 禁用了鼠标事件,确保工具提示不会干扰用户操作。
  • svg: 设置了SVG元素的全局字体、显示为块级元素以及水平居中。
  • .node rect: 定义了节点(node)矩形的样式,包括移动光标时显示为移动样式、填充不透明度以及形状呈现方式。
  • .node text: 设置了节点文本的样式,包括禁用指针事件、设置不透明度以及字体样式。
  • .link: 设置了链接(link)的样式,包括不填充任何颜色、设置描边颜色以及描边不透明度。
  • .link:hover: 当鼠标悬停在链接上时,修改了描边的不透明度,以增强交互体验。
    body{
       background: url(./assects/images/background.jpg) center;
    }
    #tooltip {
        position: absolute;
        text-align: center;
        width: auto;
        height: auto;
        padding: 2px;
        background: #13393E;
        color: #F2CCA6;
        font-size: 14px;
        font-family: KaiTi, serif;
        border: 0px;
        border-radius: 8px;
        pointer-events: none;
    }
    svg {
        font: 10px sans-serif;
        display: block;
        margin:0 auto;
    }
    .node rect {
        cursor: move;
        fill-opacity: .9;
        shape-rendering: crispEdges;
    }
    .node text {
        pointer-events: none;
        opacity: .5;
        font-weight: bold;
        font-family: KaiTi, serif;
    }
    .link {
        fill: none;
        stroke: #000;
        stroke-opacity: .06;
    
    }
    .link:hover {
        stroke-opacity: .18;
    }
    

js

  • 引入js外部库:d3.js本地下载

    <script src="./assects/js/d3/d3.v3.min.js"></script>
    <!-- D3.js的作者之一Mike Bostock提供的Sankey图相关的Javascript库 -->
    <script src="https://bost.ocks.org/mike/sankey/sankey.js"></script>
    

以下是自定义部分⭐️


  • 数据定义:定义节点nodes和链接links。links里的起始按索引设置。
    var json = {
     "nodes": [
            {
                "name": "洛阳"
            },
            {
                "name": "陇西"
            }
            ...
        ],
        "links": [
            {
                "source": 0,
                "target": 55,
                "value": 99
            },
            {
                "source": 1,
                "target": 56,
                "value": 47
            }
            ...   
        ]
     };
    
  • 基础设定
    // 定义边距、宽度和高度
    var margin = {top: 3, right: 1, bottom: 3, left: 1}, // 定义边距的对象
       width = window.innerWidth * 0.5 - margin.left - margin.right, // 计算宽度
       height = window.innerHeight * 0.95 - margin.top - margin.bottom; // 计算高度
    
    // 格式化和颜色比例尺
    var formatNumber = d3.format(",.0f"), // 格式化数字的函数
       format = function(d) { return formatNumber(d); }, // 定义格式化函数
       color = d3.scale.category20(); // 创建颜色比例尺
    
    // 创建一个SVG元素并将其附加到图表div中
    var svg = d3.select("#chart").append("svg") // 选择图表元素,并添加SVG元素
       .attr("width", width + margin.left + margin.right) // 设置SVG宽度
       .attr("height", height + margin.top + margin.bottom) // 设置SVG高度
    .append("g") // 添加一个分组元素
       .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // 设置图表的偏移量
    
  • 初始化Sankey图布局
    // 初始化Sankey图布局
    var sankey = d3.sankey() // 创建Sankey布局
        .nodeWidth(30) // 设置节点宽度
        .nodePadding(5) // 设置节点间距
        .size([width, height]); // 设置布局大小
    
    var path = sankey.link(); // 为链接定义路径生成器
    
    // 在Sankey图中设置节点、链接和布局
    sankey
        .nodes(json.nodes) // 设置节点数据
        .links(json.links) // 设置链接数据
        .layout(32); // 执行布局计算
    
  • 链接links绑定
    // 创建链接并绑定数据
    var link = svg.append("g").selectAll(".link") // 创建链接的选择集
        .data(json.links) // 绑定数据
    .enter().append("path") // 进入更新
        .attr("class", "link") // 添加class
        .attr("d", path) // 设置路径
        .style("stroke-width", function(d) { return Math.max(1, d.dy); }) // 设置描边宽度
        .sort(function(a, b) { return b.dy - a.dy; }); // 根据数据大小排序
    
  • 节点nodes设置
    // 创建节点并绑定数据
    var node = svg.append("g").selectAll(".node") // 创建节点的选择集
         .data(json.nodes) // 绑定数据
     .enter().append("g") // 进入更新
         .attr("class", "node") // 添加class
         .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) // 设置节点位置
         .call(d3.behavior.drag() // 添加拖动行为
             .origin(function(d) { return d; }) // 定义起始位置
             .on("dragstart", function() { this.parentNode.appendChild(this); }) // 开始拖动时将节点置于顶层
             .on("drag", dragmove)); // 拖动时的处理函数
    
     // 节点颜色数组
     var colorArray = ["#00577f", "#439083", "#aa5723", /* ... */ ]; // 节点颜色数组
    
     // 为节点创建矩形
     node.append("rect") // 添加矩形元素
         .attr("height", function(d) { return d.dy; }) // 设置高度
         .attr("width", sankey.nodeWidth()) // 设置宽度
         .style("fill", function(d, i) { return colorArray[i % colorArray.length]; }) // 设置填充颜色
         .style("stroke", function(d, i) { return d3.rgb(colorArray[i % colorArray.length]).darker(0); }) // 设置描边颜色
         .append("title"); // 添加标题元素
    
     // 为节点添加标签
     node.append("text") // 添加文本元素
         .attr("x", -6) // 设置x坐标
         .attr("y", function(d) { return d.dy / 2; }) // 设置y坐标
         .attr("dy", ".35em") // 设置dy属性
         .attr("text-anchor", "end") // 设置文本锚点
         .attr("transform", null) // 重置变换
         .text(function(d) { return d.name; }) // 设置文本内容
         .filter(function(d) { return d.x < width / 2; }) // 过滤条件
         .attr("x", 6 + sankey.nodeWidth()) // 设置x坐标
         .attr("text-anchor", "start"); // 设置文本锚点
    
  • 悬浮框动作触发设置
    // 当鼠标悬停在节点上时显示悬浮框
    node.on("mouseover", function(d) {
            d3.select("#tooltip")
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 28) + "px")
                .style("opacity", 0.9)
                .html(d.name + ": " + format(d.value));
        });
    
    // 鼠标移出节点的时候隐藏自定义悬浮框
    node.on("mouseout", function(d) {
        d3.select("#tooltip").style("opacity", 0);
    });
    
    // 在鼠标悬浮在链接上的时候显示自定义悬浮框
    link.on("mouseover", function(d) {
        d3.select("#tooltip")
            .style("left", (d3.event.pageX) + "px")
            .style("top", (d3.event.pageY - 28) + "px")
            .style("opacity", 0.9)
            .html(d.source.name + " → " + d.target.name + ": " + format(d.value));
    });
    
    // 鼠标移出链接的时候隐藏自定义悬浮框
    link.on("mouseout", function(d) {
        d3.select("#tooltip").style("opacity", 0);
    });
    
  • 节点拖动功能实现
    // 通过拖动行为移动节点
    function dragmove(d) {
         d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
         sankey.relayout();
         link.attr("d", path);
    }
    

你可能感兴趣的:(#,数据可视化技术,大数据与数据分析,#,小案例,前端,d3.js)