d3.js

Looking for a better way to alter the color of axis components in d3.js v4


I want to change the colour of an axis for a simple d3.js (v4) graph. The y axis in the following image is an example of the finished product;

enter image description here

I suspect that the method I am using to achieve this a bit ugly and I believe that there should be an alternative per the description below that I do not yet understand.

The axis component is a combination of text, path and line elements which require alteration of their respective styles (stroke and fill).

At this point the only method I have found to change the colour of the components is by individually setting styles in the <style> section of the code...

.axisRed line{
  stroke: red;
}

.axisRed path{
  stroke: red;
}

.axisRed text{
  fill: red;
}

...and applying that class to the y axis when appending it later in the JavaScript;

  svg.append("g")
      .attr("class", "axisRed")
      .call(d3.axisLeft(y));

Is there a way that I can apply these styles via .style("<some style>", "<some value>") lines while appending the y axis rather than declaring in the <style> section?

An example with code is here.

I have tried trying to address the individual DOM components such as the 'domain' class, but without success. I suspect that I do not understand the hierarchy of the axis component well enough.


Solution

  • In D3 you have several options to style the elements:

    Option A: Using style tag with self-assigned class:

    <style>
    .axisRed line,
    .axisRed path {
      stroke: red;
    }
    .axisRed text
    {
      fill: red;
    }
    </style>
    
    // assign that class to the y axis
    svg.append("g")
      .attr("class", "axisRed")
      .call(d3.axisLeft(y));
    

    Option B: Using style tag with the classes auto-generated by D3:

    The axis line is a <path> element with class domain. The ticks are inside a group <g> with class tick, consisting of a <line> element for the tick line and a <text> element for the tick label:

    <style>
    path.domain,
    .tick line {
      stroke: red;
    }
    .tick text {
      fill: red;
    }
    </style>
    
    svg.append("g").call(d3.axisLeft(y));
    
    // HTML code generated by D3 (example):
    <path class="domain" stroke="currentColor" d="M-6,450.5H0.5V0.5H-6"></path>
    <g class="tick" opacity="1" transform="translate(0,414)">
      <line stroke="currentColor" x2="-6" y1="0.5" y2="0.5"></line>
      <text fill="currentColor" x="-9" y="0.5" dy=".32em">50</text>
    </g>
    

    Option C: Inline at appending time

    In D3 V3 you could do a more compact:

    svg.append("line")
       .style({
          fill: "none",
          stroke: "#f00",
          "stroke-width": "10"
        });
    

    But in D3 V4, it doesn't work anymore. So I opened an 'Issue': you can check and follow the progress here: https://github.com/d3/d3-selection/issues/82

    ** UPDATE ** In V4 you must include selection-multi:

    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>
    

    and then use: styles instead of style and attrs instead attr:

    svg.append("line")
       .styles({
          fill:"none",
          stroke:"#f00",
          "stroke-width":"10"
        })
    

    for your example:

    svg.selectAll(".domain")
       .styles({ fill:"none", stroke:"#f00",  "stroke-width":"1" });
    

    Now you got a compact way to style your elements.

    Extra: you could style and attr any element:

     var svg = d3.select("body").append("svg")
            .attrs({width:600, height:600})
            .styles({
                border:"1px",
                "border-style":"solid",
                "border-color":"#f00"})
    

    Here's the plunker