javascript - 如何在页面上将小倍数的子组放在一起?

标签 javascript html d3.js

我有一个数据集,其中有一列名为 CategoryLevel1,其中包含组的名称。我将 nest 函数应用于 Categorylevel1 并根据键生成了一系列 svg。然后我创建了代表整个数据集中项目的矩形,并在每个 svg 中重复这些矩形。我对每个 svg 应用了一个过滤器,以便只能看到具有该 svg 键的数据集项。

我的真实数据集比此处表示的玩具数据集大。上面代码的结果是一个很长的 svgs 网页——非常困惑。为了使事情更清楚,我希望根据名为 CategoryLevel2 的列对 svg 进行分组。这是我追求的效果:

enter image description here

这是我目前所拥有的:

var doc = `Manual	Name	CategoryLevel1	CategoryLevel2
DOG	"General Furry, Program and Subject Files"	Average Quantity and Planning	Edibles
TR	Senate Committee on animal Standards	Bowl and Plate Design	Edibles
TR	Published Canine	Bowl and Plate Design	Edibles
TR	Canine case files	Bowl and Plate Design	Edibles
DOG	Canine Files 	Avoiding Neck Strain	Edibles
DOG	Canine Files 	Drooling	Edibles
DOG	Canine Files 	Drooling	Edibles
DG	ADVERTISING	At home	At home
DG	PROMOTIONS	At home	At home
DG3	Publications	At home	At home
TR	Public and Information Services	At home	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
DG	DEVELOPMENT	Optimal time of day - walking	Walks and outings
DG	INCOME AND REVENUE	Optimal time of day - walking	Walks and outings
TR	Fundraising	Optimal time of day - walking	Walks and outings
TR	Fundraising	Optimal time of day - walking	Walks and outings
DG	DEVELOPMENT	Optimal time of day - walking	Walks and outings
DG	INCOME AND REVENUE	Optimal time of day - walking	Walks and outings
TR	Wishbone	Protective Measures	Walks and outings
TR	Wishbone	Protective Measures	Walks and outings
DG	Wishbone	Observant of Limps Etc	Walks and outings
DOG	Wishbone	Observant of Limps Etc	Walks and outings
TR	Wishbone	Observant of Limps Etc	Walks and outings`;

const data = d3.tsvParse(doc, function(d) {
  return {
    Manual: d.Manual,
    Name: d.Name,
    CategoryLevel1: d.CategoryLevel1,
    CategoryLevel2: d.CategoryLevel2
  };
});


var nest = d3.nest()
  .key(function(d) {
    return d.CategoryLevel1;
  })
  .entries(data);

var div = d3.select("body").append("div")
  .attr("class", "tooltip")
  .style("opacity", 0)

var height = 100,
  width = 300;

var color = d3.scaleOrdinal(["#edf8fb", "#b3cde3", "#8c96c6", "#88419d"]);

/* var svg = d3.select("body").append("svg").attr("height", "100%").attr("width", "100%");

var g = d3.select("svg").attr("height", "100%").attr("width", "100%"); */



var svgs = d3.select("body")
  .selectAll("svg")
  .data(nest)
  .enter()
  .append('svg')
  .attr("width", width)
  .attr("height", height + 20);

svgs.append("text")
  .attr('class', 'label')
  .data(nest)
  .attr('x', width / 2)
  .attr('y', height)
  .text(function(d) {
    return d.key;
  })
  .attr('text-anchor', 'middle')

svgs.selectAll("rect")
  .data(data)
  .enter().append("rect")
  .attr("class", "bar")
  .filter(function(d, i) {
    const x = d3.select(this.parentNode).datum();
    return x.key == d.CategoryLevel1 ? 1 : 0;
  })
  .attr("height", function(d) {
    return 50;
  })
  .attr("width", "5")
  .attr("x", function(d, i) {
    return i * 10;
  })
  .attr("y", 0)

  .attr("fill", function(d) {
    return color(d.Manual)
  })

  .on("mouseover", function(d, i) {
    div.transition()
      .duration(200)
      .style("opacity", .9);
    div.html(`${d.Name}`)
      .style("left", (d3.event.pageX) + "px")
      .style("top", (d3.event.pageY - 50) + "px");
  })
  .on("mouseout", function(d) {
    div.transition()
      .duration(500)
      .style("opacity", 0);
  });
.page {
  width: 90%;
  margin: auto;
}

.menu {
  height: 100px;
  background-color: #B2D6FF;
  /* Medium blue */
}

.sidebar {
  height: 50px;
  width: 15%;
  background-color: #F09A9D;
  float: inline-start;
  display: block;
  margin: 0.1%;
  /* Red */
}

.title {
  width: 100%;
  background-color: none;
  display: inline-block;
  float: inline-start;
  /* Yellow */
}

div.tooltip {
  position: absolute;
  text-align: center;
  width: auto;
  height: auto;
  padding: 3px;
  font: 12px sans-serif;
  border: 0px;
  border-radius: 3px;
  pointer-events: none;
  background: lightgrey;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Mapping Dog Care Manuals</title>
  <script src="https://d3js.org/d3.v4.min.js"></script>
</head>


</html>

我尝试过的:

我尝试创建表示 CategoryLevel2 的 svg,然后附加一个“innerSVG”并运行将生成 CategoryLevel1 svg 的代码。问题出在过滤器行 - 它没有访问 CategoryLevel1 的正确父级:

.filter(function(d, i) {
    const x = d3.select(this.parentNode).datum();
    return x.key == d.CategoryLevel1 ? 1 : 0;
  })

我还尝试使用“转换、翻译”功能根据 Categorylevel1 分隔矩形,但拒绝了,因为移动与 CategoryLevel1 关联的文本会很棘手。

我现在正在尝试使用一种 d3.hierarchy 布局。问题是,一旦我将 d3.stratify 应用于数据集,结果就不能用于生成一系列 svg。也就是说,当应用以下代码时,DOM 中不会显示任何内容:(仅供引用,我还用 root.descendants() 等替换了 treeData -

var treeData = d3.stratify()
  .id(function(d) { return d.CategoryLevel1; })
  .parentId(function(d) { return d.CategoryLevel2; })
  (data);

  var svgs = d3.select("chart")
    .selectAll("svg")
    .data(treeData)
    .enter()
    .append('svg')
    .attr("width", width)
    .attr("height", height + 20);

最佳答案

此处缺少一个重要信息:您没有告诉我们您希望如何分离CategoryLevel2组:在同一行?在同一栏?其他一些模式?

因此,在我的解决方案中,我将使用容器 <div>display: flex将组分隔成 3 个,一个对应 CategoryLevel2 的每个值(分别是 EdiblesAt Home Walks and outings )。

这可以通过使用 CategoryLevel2 来完成作为嵌套函数中的第一个键:

var nest = d3.nest()
  .key(function(d) {
    return d.CategoryLevel2;
  })
  .key(function(d) {
    return d.CategoryLevel1;
  })
  .entries(data);

这将创建以下数组:

[{key: "Edibles", values: Array},
 {key: "At home", values: Array},
 {key: "Walks and outings", values: Array}];

在每个values值(value),你将拥有你的原始巢穴,例如:

{
    "key": "Edibles",
    "values": [{
        "key": "Average Quantity and Planning",
        "values": [
            //etc...
        ]
    }, {
        "key": "Bowl and Plate Design",
        "values": [
            //etc..
        ]
    }, {
        "key": "Avoiding Neck Strain",
        "values": [
            //etc...
        ]
    }, {
        "key": "Drooling",
        "values": [
            //etc
        ]
    }]
}

然后使用嵌套数据附加 div:

var divs = d3.select(".container")
  .selectAll(null)
  .data(nest)
  .enter()
  .append("div")
  .attr("class", "innerdiv");

当然,不要忘记对真正的 SVG 使用内部数组:

var svgs = divs.selectAll(null)
  .data(function(d) {
    return d.values;
  })
  .enter()
  //etc...

下面是修改后的代码:

var doc = `Manual	Name	CategoryLevel1	CategoryLevel2
DOG	"General Furry, Program and Subject Files"	Average Quantity and Planning	Edibles
TR	Senate Committee on animal Standards	Bowl and Plate Design	Edibles
TR	Published Canine	Bowl and Plate Design	Edibles
TR	Canine case files	Bowl and Plate Design	Edibles
DOG	Canine Files 	Avoiding Neck Strain	Edibles
DOG	Canine Files 	Drooling	Edibles
DOG	Canine Files 	Drooling	Edibles
DG	ADVERTISING	At home	At home
DG	PROMOTIONS	At home	At home
DG3	Publications	At home	At home
TR	Public and Information Services	At home	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
TR	Petting Services	Getting special treats	At home
DG	DEVELOPMENT	Optimal time of day - walking	Walks and outings
DG	INCOME AND REVENUE	Optimal time of day - walking	Walks and outings
TR	Fundraising	Optimal time of day - walking	Walks and outings
TR	Fundraising	Optimal time of day - walking	Walks and outings
DG	DEVELOPMENT	Optimal time of day - walking	Walks and outings
DG	INCOME AND REVENUE	Optimal time of day - walking	Walks and outings
TR	Wishbone	Protective Measures	Walks and outings
TR	Wishbone	Protective Measures	Walks and outings
DG	Wishbone	Observant of Limps Etc	Walks and outings
DOG	Wishbone	Observant of Limps Etc	Walks and outings
TR	Wishbone	Observant of Limps Etc	Walks and outings`;

const data = d3.tsvParse(doc, function(d) {
  return {
    Manual: d.Manual,
    Name: d.Name,
    CategoryLevel1: d.CategoryLevel1,
    CategoryLevel2: d.CategoryLevel2
  };
});


var nest = d3.nest()
  .key(function(d) {
    return d.CategoryLevel2;
  })
  .key(function(d) {
    return d.CategoryLevel1;
  })
  .entries(data);

var div = d3.select("body").append("div")
  .attr("class", "tooltip")
  .style("opacity", 0)

var height = 80,
  width = 150;

var color = d3.scaleOrdinal(["#edf8fb", "#b3cde3", "#8c96c6", "#88419d"]);

/* var svg = d3.select("body").append("svg").attr("height", "100%").attr("width", "100%");

var g = d3.select("svg").attr("height", "100%").attr("width", "100%"); */

var divs = d3.select(".container")
  .selectAll(null)
  .data(nest)
  .enter()
  .append("div")
  .attr("class", "innerdiv");
  
divs.append("p")
  .html(function(d){
  return d.key;
  });

var svgs = divs.selectAll(null)
  .data(function(d) {
    return d.values;
  })
  .enter()
  .append('svg')
  .attr("width", width)
  .attr("height", height + 20);

svgs.append("text")
  .attr('class', 'label')
  .attr('x', width / 2)
  .attr('y', height)
  .style("font-size", "10px")
  .text(function(d) {
    return d.key;
  })
  .attr('text-anchor', 'middle')

svgs.selectAll("rect")
  .data(data)
  .enter().append("rect")
  .attr("class", "bar")
  .filter(function(d, i) {
    const x = d3.select(this.parentNode).datum();
    return x.key == d.CategoryLevel1 ? 1 : 0;
  })
  .attr("height", function(d) {
    return 50;
  })
  .attr("width", "5")
  .attr("x", function(d, i) {
    return i * 10;
  })
  .attr("y", 0)

  .attr("fill", function(d) {
    return color(d.Manual)
  })

  .on("mouseover", function(d, i) {
    div.transition()
      .duration(200)
      .style("opacity", .9);
    div.html(`${d.Name}`)
      .style("left", (d3.event.pageX) + "px")
      .style("top", (d3.event.pageY - 50) + "px");
  })
  .on("mouseout", function(d) {
    div.transition()
      .duration(500)
      .style("opacity", 0);
  });
div.tooltip {
  position: absolute;
  text-align: center;
  width: auto;
  height: auto;
  padding: 3px;
  font: 12px sans-serif;
  border: 0px;
  border-radius: 3px;
  pointer-events: none;
  background: lightgrey;
}

.container {
  display: flex;
}

.innerdiv {
 text-align: center;
 font-size: 21px;
 font-family: "Arial";
 flex: 1 1 0;
}

.innerdiv + .innerdiv {
 padding-left: 16px;
  border-left: 2px solid lightgray;
  }
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Mapping Dog Care Manuals</title>
  <script src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
  <div class="container"></div>
</body>

</html>

关于javascript - 如何在页面上将小倍数的子组放在一起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55348241/

相关文章:

javascript - 在 JavaScript 中不使用 FileSystemObject 获取文件大小

html - 几行内相同高度的行内 block 元素

javascript - 如何在强制布局 D3.js 中生成指向右侧的链接

javascript - 来自两个不同数据源的映射

javascript - 如何在javascript中获取元素的完整开始标签(不仅仅是tagName)?

html - 无法使用显示 :table 使 div 居中对齐

php - fatal error : Uncaught Error: Cannot use object of type mysqli_result as array with databases

javascript - d3 SVG Line 元素不触发 onclick 事件

javascript - D3 散点图代码中 <circle> 属性 r ="NaN"的无效值

javascript - 使用Ajax GET和POST类型调用相同的 Controller 方法