Map elements in dataset to div id

[亡魂溺海] 提交于 2020-01-16 09:19:56

问题


I would like to make a webpage that looks something like the following:

More specifically, I would like my webpage to be generated based on a dataset that has four columns, titled as follows:

  • Manuals (there are four unique elements in this category, and they determine the colour of the dots)
  • Name (this category determines the words that appear on mouseover)
  • CategoryLevel1 (this category positions together rows that have the same CategoryLevel1)
  • CategoryLevel2 (this positions together CategoryLevel1 data).

Update: figured out a strategy: run nest function and create multiple svgs based on keys. Add squares representing entire dataset to svgs, then use opacity to hide the ones that are not relevant.

Problem lies in this line: .attr("opacity", function(d, i) {return d.CategoryLevel1 == nest[p].key ? 1 : 0}). Although nest[p].key works perfectly fine earlier in the code (see console.log on line 106), it seems to behave differently when in a block for creating rectangles. Does anyone know how to make it behave?

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 = 200;

    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')

    for (var p = 0; p < 9; p++) {

      nest.forEach(function(element) {

        console.log(nest[p].key);


        svgs.selectAll("rect")
          .data(data)
          .enter().append("rect")
          .attr("class", "bar")
          .attr("height", function(d) {
            return 50;
          })
          .attr("width", "5")
          .attr("x", function(d, i) {
            return i * 10;
          })
          .attr("y", 0)
          .attr("opacity", function(d, i) {
            return d.CategoryLevel1 == nest[p].key ? 1 : 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>

回答1:


Don't mess around with indices, modulo operators or things like that, as advised in the accepted other answer (in which the answerer honestly admits it's a hacky solution).

To get the datum of the parent SVG, just do:

const x = d3.select(this.parentNode).datum();

Here is your code with that change:

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")
  .attr("height", function(d) {
    return 50;
  })
  .attr("width", "5")
  .attr("x", function(d, i) {
    return i * 10;
  })
  .attr("y", 0)
  .attr("opacity", function(d, i) {
    const x = d3.select(this.parentNode).datum();
    return x.key == d.CategoryLevel1 ? 1 : 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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>



回答2:


Well I am guessing this is what you were expecting it to behave like.

Since in svgs.selectAll().data(data) part you are looping over each svg and data elements. So you are looping (data.length * svgs.length) times.

I do no not have a clean solution to your problem. But I did figure out a hacky way to solve it.

I use a global variable "index" to keep track of how many times it's looping over data and compare it with current svg element in question. I use index to deduce which is the current svg element that is being looped over.

.attr("opacity", function(d, i) {
        console.log(index)
        const x = nest[(index - i) % nest.length]
        index++;
        console.log(x.key, d.CategoryLevel1)
        return x.key == d.CategoryLevel1 ? 1:0;
})

Here's the complete fiddle - https://jsfiddle.net/q0b8u63L/4/

EDIT Ah, I guess I tried too hard to be smart with the deduction. I see what the problem with getting the remainder is. Instead you can just increment index if the loop has reached data.length - 1. Basically, compare each line with the next element in the nest when the inner loop has gone through all of the elements in data.

const x = nest[index]
index = (i == data.length - 1) ? ++index : index; 

https://jsfiddle.net/q7ocjw89/



来源:https://stackoverflow.com/questions/55154445/map-elements-in-dataset-to-div-id

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!