Adding a line and text as a label to a rectangle in D3: A step-by-step guide

My current bar graph displays values for A, B, and C that fluctuate slightly in the data but follow a consistent trend, all being out of 100.

https://i.stack.imgur.com/V8AWQ.png

I'm facing issues adding lines with text to the center of each graph. Attempts at appending a path have been unsuccessful so far.

Another challenge is creating striped white lines across the entire bar while maintaining visibility underneath. The solution here doesn't alter the bars as needed. Would layering another bar with line gradient achieve this effect?

https://i.stack.imgur.com/1fgl0.png

var A = 89;
var B = 6;
var C = 5;

var A = parseInt(A);
var B = parseInt(B);
var C = parseInt(C);

var margin = {
  top: 60,
  right: 70,
  bottom: 40,
  left: 65
}


var width = '100%';
var data = [{
  "Percentage": (A + B + C),
  "Name": "A"
}, {
  "Percentage": (B + C),
  "Name": "B"
}, {
  "Percentage": C,
  "Name": "C"
}]; 
var data1 = [A, B, C];
var chart = d3.select("#ChartAreaDiv").append("svg") 
  .attr("class", "chart")
  .attr("width", width)
  .attr("height", 200 - margin.top - margin.bottom)

var x = d3.scaleLinear() 
  .domain([0, d3.max(data, function(d) {
    return d.Percentage;
  })])
  .range([0, width]);

  var x1 = d3.scaleLinear() 
    .domain([0, d3.max(data1, function(d) {
      return d.Percentage;
    })])
    .range([0, width]);

chart.selectAll("rect")
  .data(data)
  .enter().append("rect")
  .attr("width", function(d) { 
    return x(d.Percentage);
  })
  .attr("height", 30)
  .attr("rx", 4)
  .attr("ry", 4);

chart.selectAll("text") 
.data(data)
.enter().append("text")
.attr("x", function(d) { 
return x(d.Percentage);
})
.attr("y", 15) 
.attr("dx", -10) 
.attr("dy", ".42em") 
.attr("text-anchor", "middle") 
.style("font-weight", "bold")
.data(data1)
.text(String);

chart.append("path")
.data(data)
.enter().append("path")
.attr("stroke-width", 2)
.style("stroke", "grey")
.attr("x1", function(d) { 
return x(d.Percentage)/2;
})
.attr("x1", function(d) { 
return x(d.Percentage)/2;
})
.attr('y1', 30)
.attr('y2', 50);

Answer №1

Is this the solution you were looking for? Check it out here

var X = 89;
var Y = 6;
var Z = 5;

var A = parseInt(X);
var B = parseInt(Y);
var C = parseInt(Z);

var margin = {
  top: 60,
  right: 70,
  bottom: 40,
  left: 65
}

var width = '100%';
var data = [{
  "Percentage": (A + B + C),
  "Name": "X"
}, {
  "Percentage": (B + C),
  "Name": "Y"
}, {
  "Percentage": C,
  "Name": "Z"
}]; 
var dataset = [A, B, C];
var graph = d3.select("#ChartAreaDiv").append("svg") 
  .attr("class", "chart")
  .attr("width", width)
  .attr("height", 200 - margin.top - margin.bottom)

//Pattern creation
var defs = graph.append("defs")
var pattern = graph.append("pattern")
  .data(data)
  .enter()
.selectAll("pattern")
.attr('id',"hash4_4")
.attr('width',"8")
.attr('height',"8")
.attr('patternUnits',"userSpaceOnUse")
.attr('patternTransform',"rotate(-45)")
.append("rect")
.attr( 'width',"4")
.attr('height',"8")
.attr('transform',"translate(0,0)") 
.attr('fill',"black" )
.style('opacity',0.1)

var xScale = d3.scaleLinear() 
  .domain([0, d3.max(data, function(d) {
    return d.Percentage;
  }])
  .range([0, width]);

var xScale1 = d3.scaleLinear() 
    .domain([0, d3.max(dataset, function(d) {
      return d.Percentage;
    }])
    .range([0, width]);

var colors = ['red','green','blue']

graph.selectAll(".myrect")
  .data(data)
  .enter()
  .append("rect")
  .attr('class','myrect')
  .attr("width", function(d) { 
    return xScale(d.Percentage);
  })
  .attr("height", 30)
  .attr("rx", 4)
  .attr("ry", 4)
  .attr("fill",  function(d,i) {return colors[i]})
  .attr('id',function(d,i) {return d['Name']})
  
graph.selectAll(".myrect")
  .data(data)
  .enter()
  .append("rect")
  .attr('class','myrect')
  .attr("width", function(d) { 
    return xScale(d.Percentage);
  })
  .attr("height", 30)
  .attr("rx", 4)
  .attr("ry", 4)
  .attr('fill',"url(#hash4_4)")
  .attr('id',function(d,i) {return d['Name']})

graph.selectAll("text") 
.data(data)
.enter().append("text")
.attr("x", function(d) { 
  return xScale(d.Percentage);
})
.attr("y", 15) 
.attr("dx", -10) 
.attr("dy", ".42em") 
.attr("text-anchor", "middle") 
.style("font-weight", "bold")
.attr("fill", "white")
.data(dataset)
.text(String);

var lineText = d3.select("svg").append('g');

data.forEach(function(d,i){
  var dataIndex = i
   lineText.append('rect')
      .data([d])
      .attr("width", 1)
      .attr("height", 30)
      .attr('x',function(){
         if (dataIndex == 0){
           return $('#'+d['Name']).width()/2
         } else if (dataIndex == 1){
           return $('#'+d['Name']).width()/2+$('#'+data[2]['Name']).width()/2
         } else if(dataIndex == 2){
           return $('#'+d['Name']).width()/2
         }
       })
       .attr('y',33)
      .attr('fill', 'grey')
});

var text = d3.select("svg").append('g');
text.selectAll("text") 
.data(data)
.enter().append("text")
.attr("x", function(d,i) { 
     if (i==0){
       return $('#'+d['Name']).width()/2
     }else if(i==1){
       return $('#'+d['Name']).width()/2+$('#'+data[2]['Name']).width()/2
     }else if(i==2){
       return $('#'+d['Name']).width()/2
     }
})
.attr("y", 70) 
.attr("dy", ".42em") 
.attr("text-anchor", "middle") 
.style("font-weight", "bold")
.attr("fill", "grey")
.text(function(d,i){
  return d.Name
});

var comment = d3.select("svg").append('g');
comment
.append("text")
.attr("x", $('svg').width()/2)
.attr("y", 97) 
.attr("text-anchor", "middle") 
.style("font-weight", "bold")
.style("font-size", 12)
.attr("fill", "darkblue")
.text('"This information is too brief; Unable to provide additional details"');
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div id ="ChartAreaDiv"></div>
<script>
  </script>
</body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Even though the onSubmit attribute is set to false in the HTML form, it still submits

I've been struggling with a form that just won't stop submitting, no matter what I do. I have checked similar questions on SO, but none of the solutions seem to work for me. It's frustrating because it's such a simple task. The reason w ...

Automatically resizing images in a canvas when their resolution exceeds the canvas size in HTML5

I am currently using Html5, fabric.js, and JavaScript to upload multiple images to a canvas. However, there are instances where the uploaded image size exceeds that of the canvas. I am looking for a way to ensure that the image is set to a fixed size. v ...

Viewport height-responsive image not functioning as expected in Firefox browser

Is there a way to set an image to the 100% height of the browser window, with a small padding at the bottom, and have it centered on the page? I created an example in codepen that works well in Chrome and Safari, but not in Firefox. In Firefox, the image ...

Send properties to the makeStyles function and apply them in the CSS shorthand property of Material UI

When working with a button component, I pass props to customize its appearance: const StoreButton = ({ storeColor }) => { const borderBottom = `solid 3px ${storeColor}`; const classes = useStyles({ borderBottom }); return ( <Button varian ...

Tips for resolving import errors encountered after running npm start

I recently started using React and I am currently following a tutorial. Even though I have the exact same code as the tutorial, I'm encountering the following error. ./src/index.js Attempted import error: './components/App' does not have a ...

What is the reason for the new page rendering from the bottom of the screen in React?

Whenever I navigate between pages in my React project, the page always starts at the bottom instead of staying at the top after rendering. I am using router v5 and have been unable to find a solution specifically for this version. I have attempted differe ...

The console log is displaying 'undefined' when trying to access Node.js fs

Recently, I was engrossed in developing a Next.js blog. After completing the frontend, I shifted my focus to building the backend using Next.js. ./pages/api I created a new file: ./pages/api/blogs.js To test my backend functionalities, I generated some J ...

Troubleshooting: Issue with binding nested data property using bracket access in Vue3 v-model

Having an issue in Vue3 where I am unable to bind a nested property to v-model correctly. Check out the source code below: Template: <div id="app"> <span>{{level1.level2.level3}}</span> <br/> <span>{{level1[&ap ...

Syntax error occurs while attempting to render the return statement in a React Component

Just starting out with React and encountering a syntax issue that has me stumped. I'm working on a React Component and I thought I had the opening/closing { & }'s correct, but clearly there's something missing based on the error message it&a ...

The AJAX success callback function failed to execute in cases where the dataType was set to JSONP during Cross domain Access

type = 'math'; var ajurl = "sample.com&callback=myhandler"; var datas = "cateid=" + cateid + "&type=" + type + "&pno=" + pno + "&whos=" + whos; $.ajax({ type: "GET", url: ajurl, data: datas, contentType: "application/json; ...

Updating the div#content dynamically with Jquery without the need to refresh the page

After spending countless hours on this forum, I have yet to find a solution that perfectly fits my needs, so I will pose my question. Here is the gist of what I am attempting to accomplish: When the page loads, the default page fades in and displays. Wh ...

How can I adjust the container to fit the monitor's dimensions while still keeping the

I am currently facing an issue on my website where the main content div has a fixed height, causing it not to scale vertically on larger monitors. I attempted setting the CSS properties for the div to 'auto' in order to allow it to adjust to the ...

What is the best way to merge 60 related jquery functions into a unified function?

I designed a webpage that serves as an extensive checklist. When you click on the edit button for a checklist item, a modal window opens up. This modal window contains a radio button to indicate whether any issues were found during the check. If "Yes" is s ...

Having trouble navigating the Request and Response handling in Expressjs/Nodejs?

As I continue to delve deeper into this code, confusion seems to cloud my understanding. Here is the provided source: var express = require('express') , http = require('http') , server = express() ; var home = require('./ro ...

Tips for managing unfinished transactions through Stripe

I have successfully set up a checkout session with Stripe and included a cancel_url as per the documentation. However, I am facing an issue where the cancel_url is only triggered when the user clicks the back button provided by Stripe. What I want to achie ...

Vuetify's scrolling list feature allows for smooth navigation through a list

Check out my Vuetify code snippet that utilizes a list: <v-list> <v-list-tile v-for="user in users" :key="user.id" avatar @click="" > <v-list-tile-content> < ...

What potential problem is arising from Jest's use of "transformIgnorePatterns" and how does it impact importing scoped CSS in a React application?

Currently facing a challenge with Jest testing in my React application following the addition of transformIgnorePatterns to the Jest settings. The default settings I included in the "jest" section of the root package.json file are as follows: "transfo ...

Ways to display a specific HTML element or tag depending on the given prop in VueJs

When working with Vue.js, it's important to remember that a <template> can only have one root element. But what should be done if you need to render different html elements based on a prop? For instance, let's say we have a <heading> ...

Modify the AJAX data in Datatables without directly modifying the elements

I am currently working with a Datatable that is being populated through AJAX, and everything is going smoothly. However, I am looking for a way to include some shortcuts to send requests to the server. The issue lies in how I can modify the data being sent ...

Choose an XPath formula that will target every single element, text node, and comment node in the original sequence

How can we write an XPath expression that selects all elements, text nodes, and comment nodes in the order they appear in the document? The code below selects all elements but not text nodes and comment nodes: let result = document.evaluate('//*&apo ...