简体   繁体   中英

d3.js : Applying styles to individual lines

Was trying out the draggable network and wanted to be able to use different colours for different links. When I commented out the lines

/*var link = svg.append("g")
    .attr("class", "link") 
    .selectAll("line");*/

and replaced it with var link = svg.append("g");
so that I could try adding links one by one, with if-else conditions where I could apply a different line style to each line. But when I tried applying just a single style uniformly to all lines itself, the lines didn't show up on the screen. Firebug also didn't show any error.

  link = link.data(graph.links).enter().append("line")
      .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; })
      .attr("class", "link");

I had added the .attr("class", "link"); section, thinking that it'd apply the style to the lines. But it didn't. Could you help with the right way to append attributes selectively?

This is the entire code:

<!DOCTYPE html>
<meta charset="utf-8">

<svg id="mySvg" width="20" height="20">
  <defs id="mdef">
        <pattern id="image" x="0" y="0" height="20" width="20">
          <image x="0" y="0" width="20" height="20" xlink:href="url.png"></image>
        </pattern>
  </defs>
  <defs>
  <pattern id="tile-ww" patternUnits="userSpaceOnUse" width="25" height="25">
  <image xlink:href="url.png" x="15" y="15" width="15" height="15"></image></pattern>
  </defs>
</svg>

<style>

.node {
  stroke: green;
  stroke-width: 1px;
  opacity: 0.8;
  fill: url(#image);  
}

.node .selected {
  stroke: red;
}

.link {
  stroke: orange;
  stroke-width: 3;
  stroke-dasharray: 20,10,5,5,5,10;
  opacity: 0.5;
}

.dotted {border: 1px dotted #ff0000; border-style: none none dotted; color: #fff; background-color: #fff; }

.brush .extent {
  fill-opacity: .1;
  stroke: #fff;
  shape-rendering: crispEdges;
}

</style>
<body>
<script src="d3/d3.v3.js"></script>

<script>

var width = 960, height = 500, shiftKey;

var svg = d3.select("body")
    .attr("tabindex", 1)
    .on("keydown.brush", keydown)
    .on("keyup.brush", keyup)
    .each(function() { this.focus(); })
    .append("svg")
    .attr("width", width)
    .attr("height", height);

/*var link = svg.append("g")
    .attr("class", "link") 
    .selectAll("line");*/
var link = svg.append("g");

var brush = svg.append("g")
    .datum(function() { return {selected: false, previouslySelected: false}; })
    .attr("class", "brush");

var node = svg.append("g")
    .attr("class", "node")
    .selectAll("circle");

//Add the SVG Text Element to the svgContainer
text = svg.append('text').text('This is some information about whatever')
                        .attr('x', 50)
                        .attr('y', 200)
                        .attr('fill', 'black');

//you can delete this circle
svg.append("circle")
         .attr("class", "logo")
         .attr("cx", 225)
         .attr("cy", 225)
         .attr("r", 20)
         .style("fill", "transparent")       
         .style("stroke", "black")     
         .style("stroke-width", 0.25)
         .on("mouseover", function(){ 
               d3.select(this)
                   .style("fill", "url(#image)");
         })
          .on("mouseout", function(){ 
               d3.select(this)
                   .style("fill", "transparent");
         });

//get the json file with either error messages or the entire data as "graph" object
d3.json("graph.json", function(error, graph) {

  //"links" is a property in "graph", and contains some data in it. Iterate through all of them
  graph.links.forEach(function(d) //iterate through each data object in link
  {
    d.source = graph.nodes[d.source];//we got nodes too, with graph so access its data
    d.target = graph.nodes[d.target];
    d.linkStatus = d.status;
    console.log(d.source);
  });


  link = link.data(graph.links).enter().append("line")
      .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; })
      .attr("class", "link");

  brush.call(d3.svg.brush()
        .x(d3.scale.identity().domain([0, width]))
        .y(d3.scale.identity().domain([0, height]))
        .on("brushstart", function(d) {
          node.each(function(d) { d.previouslySelected = shiftKey && d.selected; });
        })
        .on("brush", function() {
          var extent = d3.event.target.extent();
          node.classed("selected", function(d) {
            return d.selected = d.previouslySelected ^
                (extent[0][0] <= d.x && d.x < extent[1][0]
                && extent[0][1] <= d.y && d.y < extent[1][1]);
          });
        })
        .on("brushend", function() {
          d3.event.target.clear();
          d3.select(this).call(d3.event.target);
        }));

  node = node.data(graph.nodes).enter().append("circle")
      .attr("r", 10)//radius
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .on("mousedown", function(d) {
        if (!d.selected) { // Don't deselect on shift-drag.
          if (!shiftKey) node.classed("selected", function(p) { return p.selected = d === p; });
          else d3.select(this).classed("selected", d.selected = true);
        }
      })
      .on("mouseup", function(d) {
        if (d.selected && shiftKey) d3.select(this).classed("selected", d.selected = false);
      })
      .call(d3.behavior.drag()
        .on("drag", function(d) { nudge(d3.event.dx, d3.event.dy); }));
});

function nudge(dx, dy) 
{
  node.filter(function(d) { return d.selected; })
      .attr("cx", function(d) { return d.x += dx; })
      .attr("cy", function(d) { return d.y += dy; })

  link.filter(function(d) { return d.source.selected; })
      .attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; });

  link.filter(function(d) { return d.target.selected; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; });

  d3.event.preventDefault();
}

function keydown() 
{
  if (!d3.event.metaKey) switch (d3.event.keyCode) {
    case 38: nudge( 0, -1); break; // UP
    case 40: nudge( 0, +1); break; // DOWN
    case 37: nudge(-1,  0); break; // LEFT
    case 39: nudge(+1,  0); break; // RIGHT
  }
  shiftKey = d3.event.shiftKey || d3.event.metaKey;
}

function keyup() 
{
  shiftKey = d3.event.shiftKey || d3.event.metaKey;
}

</script>

You don't need any if-else conditions, or extensive modifications of the existing code. The way things like line color are set in D3 is through the .style() command:

link.style("stroke", ...);

The argument doesn't have to be a fixed value, but can be a function. This function is then evaluated for each element in the selection (the lines in this case), allowing you to give them different colours. If, for example, you wanted to give different colours based on the x position of the source, you would do the following.

var color = d3.scale.category20();
link.style("stroke", function(d) { return color(d.source.x); });

You can use anything that's part of the data bound to the element ( d ) to determine what color you want, or indeed anything else. To eg set a different color for each line based on the index, you would do this.

link.style("stroke", function(d, i) { return color(i); });

To make your links visible

Do this

var link = svg.append("g")
             .selectAll("line");

Instead of

var link = svg.append("g");

Now you can see all your links in orange color.

To apply styles to individual lines

Add class names using conditions like this.

link.data(graph.links).enter()
     .append("line")
     .attr("class",function(d){     
          return (d.source.x>400 && d.source.y<300)?'link-b':'link-r';
     });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM