D3.js实战:数据可视化高级技巧实例应用

简介: 本文介绍了D3.js入门,包括创建HTML文件引入库、绘制简单线图、柱状图和饼图。示例展示了数据绑定、交互性和动画效果,如柱状图的悬停效果和线图的数据平滑过渡。此外,还提及力导向图和地图可视化的实现,以及使用Enter, Update, Exit模式进行动态更新。最后提到了复杂图表和高级技巧,如使用组件库、动画、交互性和性能优化。

基础

首先,我们需要一个HTML文件来引入D3.js库,并准备一个画布来放置我们的图表。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>D3.js入门示例</title>
  <script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
  <svg width="500" height="500"></svg>
</body>
</html>
AI 代码解读

创建简单的线图

// 假设我们有以下数据
var data = [4, 8, 15, 16, 23, 42];

// 创建SVG画布
var svg = d3.select("svg"),
    margin = {
   top: 20, right: 20, bottom: 30, left: 50},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

// 创建x和y比例尺
var x = d3.scaleLinear()
    .domain(d3.extent(data, d => d))
    .range([0, width]);

var y = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([height, 0]);

// 创建x和y轴
var xAxis = d3.axisBottom(x),
    yAxis = d3.axisLeft(y);

// 添加轴
svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

svg.append("g")
    .call(yAxis);

// 绘制折线
var line = d3.line()
    .x(d => x(d))
    .y(d => y(d));

svg.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);
AI 代码解读

创建柱状图

// 假设我们有以下数据
var data = [4, 8, 15, 16, 23, 42];

// 创建SVG画布和比例尺
var svg = d3.select("svg").attr("width", 500).attr("height", 500);
var margin = {
   top: 20, right: 20, bottom: 30, left: 40};
var width = +svg.attr("width") - margin.left - margin.right;
var height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1);
var y = d3.scaleLinear().rangeRound([height, 0]);

// 数据映射到比例尺
x.domain(data.map(function(d) {
    return d; }));
y.domain([0, d3.max(data)]);

// 创建SVG g元素
var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// 添加x和y轴
g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

g.append("g")
    .call(d3.axisLeft(y));

// 绘制柱状图
g.selectAll(".bar")
    .data(data)
    .enter().append("rect")
    .attr("class", "bar")
    .attr("x", function(d) {
    return x(d); })
    .attr("y", function(d) {
    return y(d); })
    .attr("width", x.bandwidth())
    .attr("height", function(d) {
    return height - y(d); });
AI 代码解读

创建饼图

// 假设我们有以下数据
var data = [4, 8, 15, 16, 23, 42];

// 创建SVG画布和比例尺
var svg = d3.select("svg").attr("width", 500).attr("height", 500);
var radius = Math.min(svg.attr("width"), svg.attr("height")) / 2;

// 创建弧度比例尺
var arc = d3.arc().outerRadius(radius).innerRadius(0);
var pie = d3.pie().value(function(d) {
    return d; });

// 绘制饼图
var g = svg.append("g")
    .attr("transform", "translate(" + radius + "," + radius + ")");

var arcs = g.selectAll("arc")
    .data(pie(data))
    .enter().append("g")
    .attr("class", "arc");

arcs.append("path")
    .attr("d", arc)
    .attr("fill", function(d, i) {
    return d3.schemeCategory10[i]; });

arcs.append("text")
    .attr("transform", function(d) {
    return "translate(" + arc.centroid(d) + ")"; })
    .attr("dy", ".35em")
    .text(function(d) {
    return d.data; });
AI 代码解读

交互性与动画

交互性示例:添加悬停效果到柱状图

// 假设已有柱状图基础代码
// ...

// 添加悬停效果
g.selectAll(".bar")
    .on("mouseover", function(event, d) {
   
        d3.select(this)
            .transition()
            .duration(200)
            .attr("fill", "orange"); // 鼠标悬停颜色变化

        // 显示数据提示
        var tooltip = g.append("text")
            .attr("class", "tooltip")
            .attr("x", x(d) + x.bandwidth() / 2)
            .attr("y", y(d) - 10)
            .text(d);
    })
    .on("mouseout", function(event, d) {
   
        d3.select(this)
            .transition()
            .duration(200)
            .attr("fill", "steelblue"); // 恢复原始颜色

        // 移除数据提示
        g.selectAll(".tooltip").remove();
    });
AI 代码解读

动画示例:平滑过渡线图数据更新

// 假设已有线图基础代码
// ...

// 更新数据
var newData = [8, 15, 16, 23, 42, 45];

// 更新比例尺域
x.domain(d3.extent(newData));
y.domain([0, d3.max(newData)]);

// 更新轴
g.select(".axis--x").transition().duration(750).call(xAxis);
g.select(".axis--y").transition().duration(750).call(yAxis);

// 更新路径
var path = g.select(".line");
path.datum(newData).transition().duration(750).attr("d", line);
AI 代码解读

复杂图表:力导向图

力导向图展示节点和边的关系,非常适合网络、社交图谱等数据的可视化。

// 假设我们有节点和边的数据
var nodes = [{
   id: "A"}, {
   id: "B"}, {
   id: "C"}];
var links = [{
   source: nodes[0], target: nodes[1]}, {
   source: nodes[1], target: nodes[2]}];

// 创建SVG画布
var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

// 创建力模拟
var simulation = d3.forceSimulation(nodes)
    .force("link", d3.forceLink(links).id(function(d) {
    return d.id; }))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));

// 创建链接和节点
var link = svg.append("g")
    .attr("stroke", "#999")
    .attr("stroke-opacity", 0.6)
  .selectAll("line")
  .data(links)
  .join("line")
    .attr("stroke-width", 2);

var node = svg.append("g")
    .attr("stroke", "#fff")
    .attr("stroke-width", 1.5)
  .selectAll("circle")
  .data(nodes)
  .join("circle")
    .attr("r", 5)
    .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended));

node.append("title")
    .text(function(d) {
    return d.id; });

simulation.on("tick", ticked);

function ticked() {
   
  link
      .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; });

  node
      .attr("cx", function(d) {
    return d.x; })
      .attr("cy", function(d) {
    return d.y; });
}

// 拖拽事件处理函数
function dragstarted(event, d) {
   
  if (!event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(event, d) {
   
  d.fx = event.x;
  d.fy = event.y;
}

function dragended(event, d) {
   
  if (!event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}
AI 代码解读

地图可视化

D3.js可以与地理数据格式如GeoJSON配合,创建互动式地图。这包括国家、州、城市边界等。

基本步骤:

  • 加载地图数据:使用D3的d3.json或d3.geoJson加载GeoJSON数据。
  • 创建比例尺:定义地理投影和比例尺,如Mercator或Albers USA。
  • 绑定数据并绘制:将GeoJSON数据绑定到SVG路径元素,并应用投影。
  • 添加交互:如悬停效果、点击事件等。
d3.json("world.geojson").then(function(geoData) {
   
  var svg = d3.select("svg"),
      projection = d3.geoMercator().scale(130).translate([400, 250]),
      path = d3.geoPath().projection(projection);

  svg.selectAll("path")
    .data(geoData.features)
    .enter().append("path")
    .attr("d", path)
    .attr("fill", "#ccc")
    .attr("stroke", "#fff");
});
AI 代码解读

数据绑定与动态更新

基本步骤:

  • 初始化数据绑定:使用data()方法绑定数据到DOM元素。
  • Enter, Update, Exit模式:处理新数据、更新现有数据及移除无用数据。
  • 动态更新:监听数据变化,重新执行绑定和渲染流程。
var svg = d3.select("svg"),
    data = [4, 8, 15, 16, 23, 42];

// 初始化柱状图
var bars = svg.selectAll("rect").data(data);

bars.enter().append("rect")
    .attr("x", function(d, i) {
    return i * 50; })
    .attr("y", function(d) {
    return 300 - d; })
    .attr("width", 40)
    .attr("height", function(d) {
    return d; });

// 动态更新
setInterval(function() {
   
  data = data.map(function(d) {
    return Math.max(0, Math.random() * 50); });

  bars.data(data)
    .transition()
    .duration(500)
    .attr("y", function(d) {
    return 300 - d; })
    .attr("height", function(d) {
    return d; });
}, 2000);
AI 代码解读

复杂图表与高级技巧

高级技巧:

  • 使用D3的组件库:像D3fc这样的库提供了高级图表组件,简化复杂图表的创建。
  • 动画与过渡:利用transition()方法创建流畅的动画效果。
  • 交互性:增加点击、悬停事件,使用brush和zoom功能增强用户体验。
  • 性能优化:合理使用selectAll(), data(), enter(), exit()减少DOM操作,使用requestAnimationFrame()优化动画性能。

2500G计算机入门到高级架构师开发资料超级大礼包免费送!

目录
打赏
0
0
0
0
38
分享
相关文章
【Java进阶】JavaScript电灯开关实例:从理论到实践
这个例子展示了JavaScript的基本功能,包括操作HTML元素,监听事件,以及改变元素的样式。通过学习和理解这个例子,你可以了解到JavaScript在网页中的应用,以及如何使用JavaScript来创建交互式的网页。
28 13
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver:原理与实战案例
MutationObserver 是一个非常强大的 API,提供了一种高效、灵活的方式来监听和响应 DOM 变化。它解决了传统 DOM 事件监听器的诸多局限性,通过异步、批量的方式处理 DOM 变化,大大提高了性能和效率。在实际开发中,合理使用 MutationObserver 可以帮助我们更好地控制 DOM 操作,提高代码的健壮性和可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver:原理与实战案例
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
一些有用的javascript实例分析(二)
原文:一些有用的javascript实例分析(二) 1 5 求出数组中所有数字的和 2 window.onload = function () 3 { 4 var oBtn = document.
968 0
一些有用的javascript实例分析(一)
原文:一些有用的javascript实例分析(一)      本文以http://fgm.cc/learn/链接的实例索引为基础,可参见其实际效果。分析和整理了一些有用的javascript实例,相信对一些初学者有一定的帮助。
815 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等