Overlap of the X-axis domain line with the stroke of a d3 bar graph

When a bar is selected in my d3 bar chart, it should have a white border. Currently, the border is achieved using stroke, but the bottom border gets hidden under the x-axis line.

// establish container size
var margin = {top: 10, right: 10, bottom: 30, left: 30},
width = 400,
height = 300;

var data = [
{"month":"DEC","setup":{"count":26,"id":1,"label":"Set Up","year":"2016","graphType":"setup"}},
{"month":"JAN","setup":{"count":30,"id":1,"label":"Set Up","year":"2017","graphType":"setup"}},
{"month":"FEB","setup":{"count":30,"id":1,"label":"Set Up","year":"2017","graphType":"setup"}}];

var name = 'dashboard';

// define x scale
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.2);

// set x and y scales
xScale.domain(data.map(function(d) { return d.month; }));

// setup x axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.outerTickSize(0);

var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) {  
    return d.setup.count;
})])
.range([height, 0]);

var ticks = yScale.ticks(),
lastTick = ticks[ticks.length-1];    
var newLastTick = lastTick + (ticks[1] - ticks[0]);  
if (lastTick < yScale.domain()[1]){
    ticks.push(lastTick + (ticks[1] - ticks[0]));
}

// adjust domain for additional value
yScale.domain([yScale.domain()[0], newLastTick]);

// setup y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickSize(-width, 0, 0) 
.tickFormat(d3.format('d'))
.tickValues(ticks);


// create svg container
var svg = d3.select('#chart')
.append('svg')
.attr('class','d3-setup-barchart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//.on('mouseout', tip.hide);        

// add tooltip
//svg.call(tip);

// Horizontal gridline for y axis
svg.append('g')         
.attr('class', 'grid horizontal')
.call(d3.svg.axis()
      .scale(yScale)
      .orient('left')
      .tickSize(-width, 0, 0) 
      .tickFormat('')
      .tickValues(ticks)
      );

// create bars
var bars = svg.selectAll('.bar')
.data(data)
.enter()
.append('g');

bars.append('rect')
.attr('class', function(d,i) {
return 'bar';
})
.attr('id', function(d, i) {
return name+'-bar-'+i;
})
.attr('x', function(d) { return xScale(d.month); })
.attr('width', xScale.rangeBand())
.attr('y', function(d) { return yScale(d.setup.count); })
.attr('height', function(d) { return height - yScale(d.setup.count); })
.on('click', function(d, i) {
d3.select(this.nextSibling)
.classed('label-text selected', true);
d3.select(this)
.classed('bar selected', true);  
d3.select('#'+name+'-axis-text-'+i)
.classed('axis-text selected', true);
});
//.on('mouseover', tip.show)
//.on('mouseout', tip.hide);

// text at the top of the bars
bars.append('text')
.attr('class',function(d,i) {
return 'label-text';
})
.attr('x', function(d) { return xScale(d.month) + (xScale.rangeBand()/2) - 10; })
.attr('y', function(d) { return yScale(d.setup.count) + 2 ; })
.attr('transform', function() { return 'translate(10, -10)'; })
.text(function(d) { return d.setup.count; });

// draw x axis
svg.append('g')
.attr('id', name+'-x-axis')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);

// apply class & id to x-axis texts
d3.select('#'+name+'-x-axis')
.selectAll('text')
.attr('class', function(d,i) {
return 'axis-text';
})
.attr('id', function(d,i) { return name+'-axis-text-' + i; });

// draw y axis
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end');

// remove 0 from y axis
svg.select('.y')
.selectAll('.tick')
.filter(function (d) { 
return d === 0 || d % 1 !== 0;     
}).remove();

svg
.select('.horizontal')
.selectAll('.tick')
.filter(function (d) { 
return d === 0 || d % 1 !== 0;     
}).remove();

JSFiddle

Answer №1

In the realm of SVG, the rule is simple: last painted, first seen.

With that in mind, just tack on your x axis...

svg.append('g')
   .attr('id', title + '-x-axis')
   .attr('class', 'x axis')
   .attr('transform', 'translate(0,' + height + ')')
   .call(xAxis);

... Prior to creating the bars:

var bars = svg.selectAll('.bar')
    .data(information)
    .enter()
    .append('g');

Your updated fiddle can be found here: https://jsfiddle.net/abcde/

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

The overflow:hidden feature doesn't appear to be functioning as expected

I am struggling to hide the text details within a div containing text and image, organized in ul li structure. Despite applying overflow hidden to the .sbox class, the text details refuse to remain hidden and appear to be overflowing. Explore this issue o ...

What is the method for confirming the returned response string value in Vue js?

I am having trouble checking the response values of a `Vue` API request. I attempted to use `resp.data == "-1"`, but it is not yielding the desired outcome. Can someone assist me in determining how to properly check the response value in `Vue.js`? Vue.js ...

Jest test failing due to issues with a stateful React component containing an asynchronous function

I'm currently going through a Jest testing tutorial on Pluralsight that can be found here. Even though I have written the code exactly like the author, my test is not passing for some reason. Link to my Pull request on the author's repo: https:/ ...

What is the method to determine the duration of a video using the FileReader function to access the video file?

My current challenge involves uploading a video to a server and reading it on the client end using `readAsBinaryString()` from FileReader. However, I am facing an issue when trying to determine the duration of this video file. If I attempt to read the fi ...

Troubleshooting EasyTabs: Localhost Issue with Ajax Tab Configurations

I've implemented EasyTabs for organizing my tabs on a webpage. I decided to use ajax-tabs functionality in order to fetch content from other pages when users click on the navigation menu buttons. However, I've encountered an issue where the conte ...

Error: Null value does not have a property for 'categories' to be read

When I check my back-end terminal, it shows that I am getting null and a TypeError: Cannot read property 'categories' of null. What could be missing in my code? Additionally, when I log null on the console with my controllers, what might I be ove ...

Why does Vue keep-alive fail to function properly when there is a nested div?

What causes the interruption of keep-alive functionality by this particular div? <keep-alive> <div> <suspense> <component :is="Component"> </suspense> </div> </keep-alive> Placing the ...

Vue's datepicker displays the date value as '1969'

I recently integrated the Vue datepicker component by following the guide provided at: https://github.com/ReproNim/reproschema-ui/blob/master/src/components/Inputs/YearInput/YearInput.vue After answering the component, if I navigate away from the page and ...

Determine the selected option in the dropdown menu upon loading the page and when clicked

I am working on capturing the value of a drop-down list whenever it is changed or when the page loads. The aim is to display different div elements based on the selected option in the report field - either State or Year. Any assistance with this would be ...

Conceal and reveal modal by leveraging the power of redux

Is there a way to toggle the visibility of a modal using an axios post method? I keep encountering the error message, 'Cannot read property 'hide' of undefined.' Any suggestions on how to fix this issue? // Function to hide the modal ...

Invoke Angular scope function from index.html using href

I have a user controller that contains a logout function. I am trying to figure out how to call this logout function using a hyperlink in my index.html file. Just to clarify, I am currently using yeoman as well. The hyperlink is located within the navigati ...

Guide to sending and receiving JSON data using XAMPP PHP

Currently, my XAMPP 7.1.10-0 server is up and running with the following index.php file: <?php if(isset($_POST["username"])) { echo $_POST; header("Location:getbooks.php"); exit; } else { echo file_get_conten ...

Is there a different alternative to @JavascriptInterface in Android WebView?

I understand how to invoke a Java method within JavaScript code using the @JavascriptInterface annotation. However, I am facing an issue when trying to determine which JS method should be called from Android. Currently, I am triggering an Android Dialog ...

Oops! Vue.js is throwing a compile error involving unused variables and undefined variables

I'm currently working on developing a new Vue.js component, but I'm encountering an error when launching the application. The specific error message is displayed below: https://i.sstatic.net/0MQxl.png <template> <div class="hello" ...

Decoding entities in a jQuery AJAX form

I am working on a jQuery AJAX form to add, edit, and delete usernames in a MySQL database. When I retrieve data with special characters from the database, I want to populate the modal edit form with entity-decoded characters. This means that characters lik ...

Implementing personalized font styles in HTML on a WordPress platform

I recently followed a tutorial on how to upload custom fonts to my WordPress website, which you can find at the link below. I completed all the necessary steps, such as uploading to the ftp, modifying the header.php file to include the font stylesheet, and ...

Ways to dynamically retrieve the height of elements loaded within an Ionic dialog

I am working on a modal dialog template that includes a GoogleMap. My goal is to have the GoogleMap take up all available space below a header and sub-header within the template. The height of the header and sub-header are defined using mediaqueries in th ...

Perform a task if a checkbox is marked or unmarked

Currently, I am working on an HTML form that includes a checkbox asking users if they have a phone number. I am facing an issue where I want to implement two actions: 1. If the user checks the checkbox, a new input element should appear on the same page ...

Remove the JSON object from the screen in an asynchronous manner

I am currently working on developing a single-page application that retrieves information from a JSON file, displays it on the screen, and performs various actions. At this point, all the information is being properly displayed on the screen: http://jsfid ...

Will "Access-Control-Allow-Origin" provide protection if someone directs their domain to my server?

It seems I may have misinterpreted the full implementation of CORS on my server. Looking at this screenshot of a request made through Chrome. https://i.sstatic.net/9F1tE.png We can observe that we are accessing the site shakh.photography, where the requ ...