整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

使用JavaScript构建树形图

形图可视化广泛用于分层数据分析。如果你没有经验还想创建一个,那将会有些复杂。下面是一个详细教程,教你如何使用JavaScript创建交互式树形图。

宇宙中只有我们吗?我们每个人都曾在某个时候问过自己这个问题。当我们在考虑地球是否是宇宙中唯一可居住的行星时,我们可能会思考宇宙究竟有多大。让我们在树形图的帮助下看看吧!在本教程中,我们将使用树形映射出宇宙中已知的10个最大的星系。

什么是树形图?

在进入教程之前,了解一下树形图的概念。树形图是一种流行的技术,用于将分层组织、树状结构的数据可视化。它可以一目了然地展示出层次结构以及各个数据点的值,它使用了大小与相应数量成比例的嵌套矩形。

树的每个分支都是一个矩形,对于子分支,其中嵌套了较小的矩形。通过颜色和接近度显示数据,树形图可以轻松表示大量数据,同时有效利用空间,非常适合比较层次结构中的比例。

树形图类型是由Ben Shneiderman教授发明的,他在信息设计和人机交互领域作出了重大贡献。树形图被用于许多数据可视化领域,可用于分析股票市场、人口普查系统和选举统计数据,以及数据新闻、硬盘探索工具等。

浏览JS树形图

下面将使用JavaScript构建一个树形图来比较已知宇宙中排名前10的星系的大小。JS树状图在本教程结束时的样子:

创建一个基本的JS树形图

创建基于JavaScript的树状图通常需要以下四个基本步骤:

1. 创建一个HTML页面

2. 参考JavaScript文件

3. 设置数据

4. 编写一些JS树代码

如果你是 HTML、CSS 和JavaScript方面的新手,请不要担心。本文将详细介绍每一步,在学习完本教程之后,你可以尝试去做自己的JS树状图。

1. 创建一个HTML页面

首先需要创建一个基本的HTML页面。添加一个HTML块元素 (<div>),并将树形图放置其中,为其分配一个ID属性(让它成为“容器”),以便稍后在代码中引用它。

然后为 <div> 设置一些样式。将宽度和高度属性定义为 100%,边距和填充为 0。当然,你可以根据自己的喜好进行更改。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Treemap Chart</title>
    <style type="text/css">   
      html, body, #container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="container"></div>
  </body>
</html>

2. 参考JavaScript文件

接下来,需要引用所需脚本,用这些脚本创建树形图。

现在有多个JavaScript图表库可供选择。创建交互式数据可视化的基本步骤与它们中的任何一个都是差不多的。在这里,为了说明问题,我将使用AnyChart,它支持树形图并有免费版本,其源代码在GitHub上开放。

因此,要构建树形图,需要导入“核心”和“树形图”模块。在第一步创建的HTML页面的 head 部分中引用它们。从 CDN 获取它们(或下载文件)。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Treemap Chart</title>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-treemap.min.js"></script>
    <style type="text/css">   
      html, body, #container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }
  </style>
  </head>
  <body>
    <div id="container"></div>
  </body>
</html>

3.设置数据

设置数据后将把已知宇宙中最大的前10个星系的规模可视化。这些星系非常庞大,所以需要以它们的直径来衡量它们是多少光年(光年是一束光在一个地球年中传播的距离,相当于大约 6 万亿英里)。

我已经从 Largest.org 获取了星系尺度的数据。

对于图表,树结构数据根基元素是“星系”,(按星系类型)分为“椭圆”和“螺旋”作为其子元素,它们又有个别星系对象的数组作为它们自己的子元素。

每个星系对象都具有<名称 \ 尺度>键值属性。例如,{name: "IC 1101", value: 4000000} 表示规模为 4,000,000 光年的 IC 1101 星系。说实话,很难理解它有多大。

var dataSet = [
  {name: "Galaxies", children: [
    {name: "Elliptical", children: [
      {name: "IC 1101", value: 4000000},
      {name: "Hercules A", value: 1500000},
      {name: "A2261-BCG", value: 1000000},
      {name: "ESO 306-17", value: 1000000},
      {name: "ESO 444-46", value: 402200},
    ]},
    {name: "Spiral", children: [  
      {name: "Rubin's Galaxy", value: 832000},
      {name: "Comet Galaxy", value: 600000},
      {name: "Condor Galaxy", value: 522000},
      {name: "Tadpole Galaxy", value: 280000},
      {name: "Andromeda Galaxy", value: 220000} 
    ]}
  ]}
];

4. 编写一些JS树形图代码

到此只需几行JavaScript代码就可以为树形图提供动力。

1.使用anychart.onDocumentReady() 函数,加载树形图的所有JavaScript代码,确保它在网页完全加载并准备执行。

<script>
  anychart.onDocumentReady(function () {
    // JS树映射代码会写到这里
  });
</script>

2.然后,从第3步开始在树形图中添加我们想要可视化的数据。

<script>
 
  anychart.onDocumentReady(function () {
 
    var dataSet = [
      {name: "Galaxies", children: [
        {name: "Elliptical", children: [
          {name: "IC 1101", value: 4000000},
          {name: "Hercules A", value: 1500000},
          {name: "A2261-BCG", value: 1000000},
          {name: "ESO 306-17", value: 1000000},
          {name: "ESO 444-46", value: 402200},
        ]},
        {name: "Spiral", children: [  
          {name: "Rubin's Galaxy", value: 832000},
          {name: "Comet Galaxy", value: 600000},
          {name: "Condor Galaxy", value: 522000},
          {name: "Tadpole Galaxy", value: 280000},
          {name: "Andromeda Galaxy", value: 220000} 
        ]}
      ]}
    ];
 
  });
 
</script>

3.添加以下代码将数据转换到图上。

var chart = anychart.treeMap(dataSet, "as-tree");

4.添加一个标题,将图表放入之前定义的 <div> 容器中,并使用 draw 命令显示它。

chart.title("The 10 Largest Galaxies in the Known Universe");
chart.container("container");
chart.draw();

现在JS树形图基本上已经准备好了:

加载树形图时,只会显示两个图块,“椭圆”和“螺旋”。然后可以单击它们,展开其各自的子星系,这就是所谓的下钻操作。

为什么会只有两块?因为默认情况下,最大深度值设置为1。这意味着一次只能看到其父级的一个级别。较低的级别是隐藏的。在第一层,将“星系”分为“椭圆”和“螺旋”,所以只能看到这一层。

显示所有星系图块只需要使用maxDepth()函数更改最大深度值。

chart.maxDepth(2);

效果如下:

在这张图表中,可以看到星系是如何根据层次结构进行分组的,还可以单击顶部的“椭圆”或“螺旋”标题来放大其子星系。

完整代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Treemap Chart</title>
    <script data-fr-src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script data-fr-src="https://cdn.anychart.com/releases/8.11.0/js/anychart-treemap.min.js"></script>
    <style type="text/css">   
      html, body, #container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="container"></div>
 
    <script>
 
      anychart.onDocumentReady(function () {
 
        // 创建数据
        var dataSet = [
          {name: "Galaxies", children: [
            {name: "Elliptical", children: [
              {name: "IC 1101", value: 4000000},
              {name: "Hercules A", value: 1500000},
              {name: "A2261-BCG", value: 1000000},
              {name: "ESO 306-17", value: 1000000},
              {name: "ESO 444-46", value: 402200},
            ]},
            {name: "Spiral", children: [  
              {name: "Rubin's Galaxy", value: 832000},
              {name: "Comet Galaxy", value: 600000},
              {name: "Condor Galaxy", value: 522000},
              {name: "Tadpole Galaxy", value: 280000},
              {name: "Andromeda Galaxy", value: 220000} 
            ]}
          ]}
        ];
        
        // 创建树形图并设置数据
        var chart = anychart.treeMap(dataSet, "as-tree");
 
        // 设置图表标题
        chart.title("The 10 Largest Galaxies in the Known Universe");
 
        // 设置图表的容器id
        chart.container("container");
 
        // 开始绘制图表
        chart.draw();
 
      });
 
    </script>
  </body>
</html>

现在,你可以一目了然地看到10个最大星系的规模并进行比较。下面展示如何自定义JavaScript树形图。

自定义JS树形图

A. 改变颜色

改变任何图表的外观和感觉有一种简单方法就是更改颜色。

chart.normal().fill('#B46FC2');
chart.hovered().fill('#44008B', 0.8);
chart.selected().fill('#0A0068', 0.8);
chart.selected().hatchFill("forward-diagonal", '#282147', 2, 20);

添加了fill()和hashFill()方法来更改树形图的颜色。

B. 应用线性色标

在树形图中,除了大小,图块的颜色也有助于突出显示比例。可以借助线性色标根据相应的数据维度自动为图块着色。

创建一个线性色标,为其提供两个值,一个为最低范围值,另一个为最高值,最后启用颜色范围。

var customColorScale = anychart.scales.linearColor();
customColorScale.colors(['#37B8F7', '#ffcc00']);
chart.colorScale(customColorScale);
chart.colorRange().enabled(true);
chart.colorRange().length('90%');

实现这些需要修改上一节中的代码。

C. 格式化标签和工具提示

可以使用HTML来格式化标签。为此,需要为标签启用 HTML。然后,你就可以不受限制地使用HTML对它们进行格式化。

可以把标签格式化为<span>HTML元素,并对其进行样式设计,以增加字体大小和改变颜色。

chart.labels().useHtml(true);
chart.labels().format(
  "<span style='font-size: 24px; color: #00076f'>{%name}</span><br>{%value}"
);

正如你在上面的代码片段中看到的,还使用了{%name}和{%value}标记,用来更改树形图标签和工具提示的文本。这样,在创建可视化时将为每个星系输出名称和比例值。

此外,使用format()方法来定制工具提示的文本。一个内容丰富的工具提示有助于更好地理解数据。

chart.tooltip().format(
    "Scale: {%value} light-years"
);

D. 按升序排列图块

默认情况下,树形图图块按降序排列。可以看到星系是从高到低排列的,规模最大的IC 1101星系是左起第一个。

如果需要升序排列,那么添加:

chart.sort("asc");

下面是一个完整 样例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Treemap Chart</title>
    <script data-fr-src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script data-fr-src="https://cdn.anychart.com/releases/8.11.0/js/anychart-treemap.min.js"></script>
    <style type="text/css">   
      html, body, #container {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="container"></div>
 
    <script>
 
      anychart.onDocumentReady(function () {
 
        // create the data
        var dataSet = [
          {name: "Galaxies", children: [
            {name: "Elliptical", children: [
              {name: "IC 1101", value: 4000000},
              {name: "Hercules A", value: 1500000},
              {name: "A2261-BCG", value: 1000000},
              {name: "ESO 306-17", value: 1000000},
              {name: "ESO 444-46", value: 402200},
            ]},
            {name: "Spiral", children: [  
              {name: "Rubin's Galaxy", value: 832000},
              {name: "Comet Galaxy", value: 600000},
              {name: "Condor Galaxy", value: 522000},
              {name: "Tadpole Galaxy", value: 280000},
              {name: "Andromeda Galaxy", value: 220000} 
            ]}
          ]}
        ];

        // create the treemap chart and set the data
        var chart = anychart.treeMap(dataSet, "as-tree");
 
        // set the chart title
        chart.title("The 10 Largest Galaxies in the Known Universe");

        // set a custom color scale
        var customColorScale = anychart.scales.linearColor();
        customColorScale.colors(['#37B8F7', '#ffcc00']);
        chart.colorScale(customColorScale);
        chart.colorRange().enabled(true);
        chart.colorRange().length('90%');

        // format the labels
        chart.labels().useHtml(true);
        chart.labels().format(
          "<span style='font-size: 24px; color: #00076f'>{%name}</span><br>{%value}"
        );
  
        // format the tooltips
        chart.tooltip().format(
          "Scale: {%value} light years"
        );

        // sort in ascending order
        chart.sort("asc");
 
        // set the container id for the chart
        chart.container("container");
 
        // initiate drawing the chart
        chart.draw();
 
      });
 
    </script>
  </body>
</html>

结论

恭喜现在已经学会了轻松地创建出色的交互式JavaScript树形图!请参阅树形图文档 , 以 便 了解它还可以做些什么,或者使用不同的图表库。

一节聊到正则表达式的简单应用,不足之处欢迎留言交流。

Javascript正则表达式示例之基本概念

今天,我们来看一下,如何使用正则表达式,匹配HTML标签及相关信息。

为什么要加上相关信息呢?

因为,如果您想写一个HTML语法树解析库的时候,可能会用到。


下面内容用到的语法

|:表示或者,要么前面,要么后面

(?<=我前面出现的内容)要匹配的内容:只匹配前面出现的字符之后的内容。

可视图

要匹配的内容(?=我前面出现的内容):只匹配后面出现的字符之前的内容。

可视图

分组捕获:一对完整的小括号(),表示一个组。

\数字:你要使用那一个分组捕获到的内容。

.*?:在正则表达式中,. 表示匹配任意字符,* 表示匹配 0 到任意次的前一个字符,? 表示非贪婪匹配,即尽可能匹配最少的字符。因此,.*? 表示匹配任意字符零次或多次,但尽可能匹配最少的字符。这个表达式通常用于匹配一个字符串中的所有内容,但是避免贪婪匹配导致的匹配错误。

^: 表示匹配开始

[要匹配的字符]:只匹配括号中的字符。

比如[0-9]、[a-z]、[A-Z]、[0-9a-zA-Z]、[0-9abc]等等。

[^要匹配的字符]:[]中加^表示匹配不是“要匹配的字符”。


1、匹配所有HTML标签,并清空。实现innerText类似的功能。

<body><div id="left">left</div><div id="right">right</div></body>
const text = document.body.innerText;
text = text.replace(/\n/g, '');
console.log(text);
//输出: leftright

假设没有innerText的功能呢?实现这个功能,使用正则表达式无疑是最方便的。

var text = document.body.innerHTML.replace(/<[^>]+>/g,'');
text = text.replace(/\n/g, '');
console.log(text);
//输出: leftright

匹配结果

可视图


是的,这个正则表达式的意思是,查找<>并且包含他们之间不为>的一段字符串。

到这里,您以为就结束了吗?您在网上搜索匹配HTML标签,可能也会得到这么一个结果(例如:<[^>]+>、<.*?>、等等),但实际上这只是开始,我们本着只要是程序就可能有bug的原则,所以我们来看下面一个例子。

const strHtml = '<span data-code=">">>是大于符号。</span>';
const strRes = strHtml.replace(/<[^>]+>/g, '');
console.log(strRes);
// ">>是大于符号。

[可怜]bug出现了,怎么办?别着急,请看下一个知识点。


2、匹配HTML标签属性,是写一个HTML语法树要经历的事情。


2.1、首先,我们先解决第一点最后的bug。

const strHtml = '<span data-code=">">>是大于符号。</span>';
// 一个小改动即可。
const strRes = strHtml.replace(/<("[^"]*"|[^>])+>/g, '');
console.log(strRes);
// >是大于符号。

可视图

完美[打脸] ,还没结束……

const strHtml = "<span data-code='>'>>是大于符号。</span>";
const strRes = strHtml.replace(/<("[^"]*"|[^>])+>/g, '');
console.log(strRes);
// '>>是大于符号。

甲:这不是我写的HTML不标准,是你的解析库兼容性不好,浏览器都可以识别,你为什么不可以?

已:……。

const strHtml = `<i code="<"><小于符号。</i><i code='>'>>大于符号。</i>`;
// 继续改造
const strRes = strHtml.replace(/<((["'])+.*?\2|[^>])+>/g, '');
console.log(strRes);
// <小于符号。>大于符号。

匹配结果

可视图

是的,利用正则表达式分组捕获的语法,实现了上面的需求。


2.2 现在,我们来看看,如何找到某个标签的所有属性。

const strHtml = `
<input type='text' disabled value="" class="txt txt-md" v-on:click="save('button')" />
`;

上面的例子中,有多种情况,我们首先来整理出来。

属性1:type='text'

/[\w]+=(["'])+.*?/

属性2:disabled

/[\w]+/

属性3:value=""

/[\w]+=(["'])+.*?/

属性4:class="txt txt-md"

/[\w]+=(["'])+.*?/

属性5:v-on:click="save('button')"

/[\w:]+=(["'])+.*?/

其他情况:欢迎讨论。

把所有情况连起来之后。

const strHtml = `<input type='text' disabled value="" class="txt txt-md" v-on:click="save('button')" />`;
const tagAttrs = strHtml.match(/(?<=\s)[\w:-]+(=(["']).*?\2)*/g) || [];
console.log(tagAttrs);
//  ["type='text'", 'disabled', 'value=""', 'class="txt txt-md"', `v-on:click="save('button')"`]

匹配结果

可视图

人人为我,我为人人,欢迎您的浏览,我们一起加油吧。

通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素。

HTML DOM (文档对象模型)

当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。

HTML DOM 模型被构造为对象的树:

HTML DOM 树

通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML。

  • JavaScript 能够改变页面中的所有 HTML 元素

  • JavaScript 能够改变页面中的所有 HTML 属性

  • JavaScript 能够改变页面中的所有 CSS 样式

  • JavaScript 能够对页面中的所有事件做出反应

查找 HTML 元素

通常,通过 JavaScript,您需要操作 HTML 元素。

为了做到这件事情,您必须首先找到该元素。有三种方法来做这件事:

  • 通过 id 找到 HTML 元素

  • 通过标签名找到 HTML 元素

  • 通过类名找到 HTML 元素

通过 id 查找 HTML 元素

在 DOM 中查找 HTML 元素的最简单的方法,是通过使用元素的 id。

本例查找 id="intro" 元素:

实例

var x=document.getElementById("intro");

如果找到该元素,则该方法将以对象(在 x 中)的形式返回该元素。

如果未找到该元素,则 x 将包含 null。

通过标签名查找 HTML 元素

本例查找 id="main" 的元素,然后查找 id="main" 元素中的所有 <p> 元素:

实例

var x=document.getElementById("main");

var y=x.getElementsByTagName("p");

通过类名找到 HTML 元素

本例通过 getElementsByClassName 函数来查找 class="intro" 的元素:

实例

var x=document.getElementsByClassName("intro");

HTML DOM 后篇

我会接着介绍:

  • 如何改变 HTML 元素的内容 (innerHTML)

  • 如何改变 HTML 元素的样式 (CSS)

  • 如何对 HTML DOM 事件对出反应

  • 如何添加或删除 HTML 元素

如您还有不明白的可以在下面与我留言或是与我探讨QQ群308855039,我们一起飞!