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

时间:2019-03-26 00:29:10

标签: 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);

1 个答案:

答案 0 :(得分:3)

这里缺少重要信息:您没有告诉我们如何要分离CategoryLevel2组:在同一行中?在同一列中?还有其他模式吗?

因此,在我的解决方案中,我将使用带有<div>的容器display: flex将3个中的组分开,每个CategoryLevel2的值(它们是EdiblesAt Home Walks and outings)。

只需使用CategoryLevel2作为Nest函数中的第一个键即可完成

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值中,您将拥有原始的嵌套,例如:

{
    "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>