Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add filled sections to SVG circles using d3.js

I am generating some SVG circles using d3.js. I'm able to generate them, but I can't figure how to divide them into 4 equal sections and color fill each section. I'm using version 4 of d3.js.

Here is a snippet of my javascript from my fiddle:

var nodes = [

  {"type":'family',"id":'f1',"name":'', "image":""},
  {"type":'person',"id":'p1',"name":'fred flintstone',"age": 39, "relationship": "father","sex":' '},
  {"type":'person',"id":'p2',"name":'wilma flintstone',"age": 36, "relationship": "mother","sex":'m'},
  {"type":'person',"id":'p3',"name":'pebbles flintstone',"age": 4 , "relationship": "daughter","sex":'mf'},
  {"type":'person',"id":'p4',"name":'dino',"age": 8 ,"relationship": "pet","sex":'m'},


  {"type":'family',"id":'f3',"name":'', "image":""},
  {"type":'person',"id":'p5',"name":'barney rubble',"age": 43, "relationship": "father","sex":'m'},
  {"type":'person',"id":'p6',"name":'betty rubble',"age": 41, "relationship": "mother","sex":'f'},
  {"type":'person',"id":'p7',"name":'bam bam rubble',"age": 4, "relationship": "son","sex":'m'},


]

//more code in my fiddle

  my.width = function(value) {
    if (!arguments.length) return width;
    width = value;
    return my;
  };

  my.nodes = function(value) {
    if (!arguments.length) return nodes;
    nodes = value;
    return my;
  };

  my.links = function(value) {
    if (!arguments.length) return links;
    links = value;
    return my;
  };

  my.height = function(value) {
    if (!arguments.length) return height;
    height = value;
    return my;
  };

  return my;
}

Thanks much in advance.

https://jsfiddle.net/pqk8y3mb/

like image 812
user1647160 Avatar asked Jun 29 '19 05:06

user1647160


1 Answers

I would recommend manually drawing the arcs with SVG's path.

First, here is a working example with the additions: https://jsfiddle.net/mztafs0w/


Explanation:

SVG Path has commands such as M for Move, A for Arc, L for draw Line to:

  • Capital letters are absolute pixel movements
  • Lowercase letters are relative pixel movements

To make a filled pie slice using SVG path, you must perform these actions:

How to draw an arc image source


Let's say your radius is 40 and you want a slice for the top-right quadrant. The entire command for this would be:

  • Move X(0) Y(-40) -- move to top
  • Arc X-Radius(40) Y-Radius(40) XRot(0) >180deg?(0) Sweep(1) X(40) Y(0) -- arc to right
  • Line X(0) Y(0) -- return to center

Compressed into svg path format, this appears as:

M 0 -40 A 40 40 0 0 1 40 0 L 0 0 (minimally, M0,-40A40,40,0,0,1,40,0L0,0)

Performing this 4 times to get all 4 quadrants is simple enough, and replacing radius with ${r} allows the size to be easily adjusted.

The final code added to your JS fiddle:

var slices=[];
  slices[0] = node.append("path")
  .attr("d", function(d) {
    let r = d.type == "family" ? family_radius + 5 : 40;
    return `M 0 -${r} A ${r} ${r} 0 0 1 ${r} 0 L 0 0`; } )
  .attr("fill", "coral");
slices[1] = node.append("path")
    .attr("d", function(d) {
    let r = d.type == "family" ? family_radius + 5 : 40;
    return `M ${r} 0 A ${r} ${r} 0 0 1 0 ${r} L 0 0`; } )
  .attr("fill", "royalblue");
slices[2] = node.append("path")
  .attr("d", function(d) {
    let r = d.type == "family" ? family_radius + 5 : 40;
    return `M 0 ${r} A ${r} ${r} 0 0 1 -${r} 0 L 0 0`; } )
  .attr("fill", "olivedrab");
slices[3] = node.append("path")
  .attr("d", function(d) {
    let r = d.type == "family" ? family_radius + 5 : 40;
    return `M -${r} 0 A ${r} ${r} 0 0 1 0 -${r} L 0 0`; } )
  .attr("fill", "goldenrod");

I recommend you remove the non-working describeArc section and make the code more DRY. You may perform more calculations to have the circle slices break at places other than 0/90/180/270. Let me know if you need help with any of those, or you may check the image source for more tips.

I also changed the family_radius to family_radius + 5 so you can see the arcs being drawn underneath the white fill of those smaller circles. If this is not desirable you may either remove the white fill on these circles (line 165 if(d.type == "family"){return "white"}) or simply not draw these slices at all for those circles.

like image 171
Daryll Avatar answered Nov 14 '22 21:11

Daryll