Unable to create a line chart in D3.js - d3.js

I want to create a line chart using D3.js.
Here an example of line chart.
This is my code:
var margin = {top: 0, right: 0, bottom: 0, left: 0};
var svg = d3.select('#linechart')
.append('svg')
.attr('width', 600)
.attr('height', 200);
var values = createAxisLine(svg);
var x = values[0];
var y = values[1];
var width = values[2];
var height = values[3];
createChartLine(svg, x, y, width, height);
function createAxisLine(thisSvg) {
var width = thisSvg.attr('width') - margin.left - margin.right;
var height = thisSvg.attr('height') - margin.top - margin.bottom;
thisSvg = thisSvg.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
var x = d3.scaleBand()
.rangeRound([0, width])
.domain([2016, 2015, 2014, 2013, 2012, 2011, 2010]);
var y = d3.scaleLinear()
.range([height, 0])
.domain([0, 100]);
var xAxis = d3.axisBottom(x).tickSize(0, 0);
var yAxis = d3.axisLeft(y);
thisSvg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + height + ')')
.call(xAxis)
.selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em')
.attr('transform', 'rotate(-65)');
thisSvg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + margin.left + ', 0)')
.call(yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end');
return [x, y, width, height];
}
function createChartLine(thisSvg, x, y, width, height) {
thisSvg.selectAll(null)
.data(mydata)
.attr('transform', function(d) {
return 'translate(' + margin.left + ', ' + margin.top + ')';
});
var line = d3.line()
.x(function(d) {
return x(d.year);
})
.y(function(d) {
if(isNaN(d.value)) return 0;
else return y(d.value);
});
lines.append('path')
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('d', line);
}
All the code is in this plunker.
When I run the code, nothing appears, no lines or axis are showed. But data are correctly getted so I don't understand what the problem is.
I get this error:
I need help

The problem for why nothing appears is that your the code inside script.js runs before the linechart element is loaded. One of the recommendation would be to include your script.js before the close of your body tag.
<body>
<div id='linechart'></div>
<script src="script.js"></script>
</body>

Related

Double bar chart creation

I want to create a bar chart like this:
There are two chart bars one below the other, the first one grows upwards while the second one grows downwards.
They have different scales and data.
This is what I created:
var doublebarSvg1 = d3.select('#doublebar')
.append('svg')
.attr('class', 'doublebarSvg1')
.attr('width', 700)
.attr('height', 400);
var doublebarSvg2 = d3.select('#doublebar')
.append('svg')
.attr('class', 'doublebarSvg2')
.attr('width', 700)
.attr('height', 400);
var margin = {top: 0, right: 0, bottom: 0, left: 50};
var width = doublebarSvg1.attr('width') - margin.left - margin.right;
var height = doublebarSvg1.attr('height') - margin.top - margin.bottom;
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.1)
.domain(years);
var y1 = d3.scaleLinear()
.rangeRound([height, 0])
.domain([0, 100]);
var y2 = d3.scaleSqrt()
.rangeRound([height, 0])
.domain([813, 0.1]); // max value 812.05 but domain is [0, 100000]
var doublebarSvgG1 = doublebarSvg1.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
var doublebarSvgG2 = doublebarSvg2.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
////////////////////////////////////////////////////////////////////////
// Tooltip.
////////////////////////////////////////////////////////////////////////
var svgTip = doublebarSvg1.append('svg').attr('id', 'tooltip');
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-5, 0])
.html(function(d) {
return '<div><span>Country:</span> <span style=\'color:white\'>' + d.country + '</span></div>' +
'<div><span>Perc:</span> <span style=\'color:white\'>' + d.perc + '%</span></div>' +
'<div><span>Rate:</span> <span style=\'color:white\'>' + d.rate + '%</span></div>';
});
svgTip.call(tip);
////////////////////////////////////////////////////////////////////////
// Draw a single double bar
////////////////////////////////////////////////////////////////////////
makeDoublebar1();
function makeDoublebar1() {
// define the axes
var xAxis = d3.axisBottom(x);
var yAxis1 = d3.axisLeft(y1);
// create x axis
doublebarSvgG1.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + height + ')')
.call(xAxis)
.selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em')
.attr('transform', 'rotate(-65)');
// create y axis
doublebarSvgG1.append('g')
.attr('class', 'y axis')
.call(yAxis1)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end');
// create bar rect
doublebarSvgG1.selectAll('.bar')
.data(testData1) //.data(covFiltered)
.enter().append('rect')
.attr('fill', 'steelblue')
.attr('class', 'bar')
.attr('x', function(d) {
return x(d.year);
})
.attr('y', function(d) {
if(isNaN(d.perc)) {
d.perc = 0;
}
return y1(d.perc);
})
.attr('width', x.bandwidth())
.attr('height', function(d) {
if(isNaN(d.perc)) {
d.perc = 0;
}
return height - y1(d.perc);
})
.on('mouseover', function(d) {
d3.select(this).attr('fill', 'darkblue');
tip.show(d);
})
.on('mouseout', function(d) {
d3.select(this).attr('fill', 'steelblue');
tip.hide(d);
});
}
////////////////////////////////////////////////////////////////////////
// Draw a single double bar
////////////////////////////////////////////////////////////////////////
makeDoublebar2();
function makeDoublebar2() {
// define the axes
var xAxis = d3.axisBottom(x);
var yAxis2 = d3.axisLeft(y2);
// create x axis
doublebarSvgG2.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, 0)')
.call(xAxis)
.selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em')
.attr('transform', 'rotate(-65)');
// create y axis
doublebarSvgG2.append('g')
.attr('class', 'y axis')
.call(yAxis2)
.append('text')
.style('text-anchor', 'end');
// create bar rect
doublebarSvgG2.selectAll('.bar')
.data(testData2)
.enter().append('rect')
.attr('fill', 'tomato')
.attr('class', 'bar')
.attr('x', function(d) { // left start point
return x(d.year);
})
.attr('y', function(d) { // top start point
if(isNaN(d.rate)) {
d.rate = 0;
}
return 0;
})
.attr('width', x.bandwidth())
.attr('height', function(d) {
if(isNaN(d.rate)) {
d.perc = 0;
}
return y2(d.rate);
})
.on('mouseover', function(d) {
d3.select(this).attr('fill', 'red');
tip.show(d);
})
.on('mouseout', function(d) {
d3.select(this).attr('fill', 'tomato');
tip.hide(d);
});
}
PLUNKER here.
There are some problem:
if I replace .axis {display: initial;} with .axis {display: none;}, all the axis disappear but I want the horizontal line between the two chart
I would like there to be only one tooltip, which when the user hovers over any bar, comes out with a tooltip that shows both perc and rate value.
And, more importantly, is this the smartest way to create a chart like that?
Regarding the axis, since you want to keep the horizontal line, just hide the ticks and the texts:
.x.axis text,.x.axis line {
opacity: 0;
}
The tooltip problem is a bit more complex. The issue is that you're binding different data arrays to each set of bars.
Because of that, the best idea is finding the desired object in each array when you hover over a given year and getting the respective properties:
var thisPerc = testData1.find(function(e){return e.year === d.year}).perc;
var thisRate = testData2.find(function(e){return e.year === d.year}).rate;
Then you use those properties for setting the tooltip's text.
Here is the updated Plunker: http://plnkr.co/edit/tfB4TpkETgzp5GF1677p?p=preview
Finally, for your last question ("And, more importantly, is this the smartest way to create a chart like that?"), the answer is no. There are a lot of things that can (and must) be changed here, but this involves a lot of refactoring and it's arguably off topic at Stack Overflow. However, this is an adequate question for Code Review. But please read their docs first for keeping your question on topic, asking there is not the same as asking here.

D3 LineChart with mouse move and show point

I created a lineChart by d3(4.12.2). And I want to add mouse move event. It's not work for me. This is my code jsfiddle.
Thanks your help.
$(document).ready(function () {
function lineChart(elementId, xMax, yMax, xMin, yMin, x, y, dataset) {
var margin = {
top: 60,
right: 40,
bottom: 120,
left: 60
};
var w = 700;
var h = 300;
var width = w + margin.left + margin.right;
var height = h + margin.top + margin.bottom;
var xScale = d3.scaleTime()
.domain([xMin, xMax])
.range([0, w]);
var yScale = d3.scaleLinear().domain([yMin, yMax]).range([h, 0]);
var line = d3.line()
.x(function (d) {
return xScale(d[x]);
})
.y(function (d) {
return yScale(d[y]);
});
var svg = d3.select(`#${elementId}`).append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "transparent")
.on('mousemove', identifyMouse);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + h + ')')
.call(d3.axisBottom(xScale)
.tickFormat(d3.timeFormat('%Y-%m-%d %H:%M:%S')))
.selectAll('text')
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr('transform', 'rotate(-65)');
svg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(0,0)')
.call(d3.axisLeft(yScale));
svg.append('path').datum(dataset).attr('fill', 'none')
.attr('stroke', 'DodgerBlue')
.attr('stroke-width', 1)
.attr('d', line);
var bisectDate = d3.bisector(function (d) {
return d[x];
}).left;
var circle = svg.append('circle')
.style("fill", "black")
.style("stroke", "blue")
.attr('r', 5);
function identifyMouse() {
console.log(dataset.length);
var x0 = xScale.invert(d3.mouse(this)[0]);
console.log('old', x0);
x0 = new Date(`'${x0}'`).getTime();
console.log('new', x0);
var i = bisectDate(dataset, x0);
console.log(i);
var smaller = dataset[i - 1];
console.log('smaller', smaller);
var larger = dataset[i];
console.log('larger', larger);
var d = x0 - smaller[x] > larger[x] - x0 ? larger : smaller;
circle.attr("transform", "translate(" + xScale(d[x]) + "," + yScale(d[y]) + ")");
}
}
});
Instead of
var bisectDate = d3.bisector(function(d){ return d[x]; }).right;
it should have been
var bisectDate = d3.bisector(function(a, b){ return a[x] - b; }).right;
Then for bisect, to work its assumed that the dataset is sorted.
so sort the data like this before passing to bisect function:
dataset.sort(function(a, b){
return a[x]-b[x];
});
Finally, for getting the bisected data do:
var i = bisectDate(dataset, x0.getTime()); //sincex0is date object.
working code here
EDIT
How do you know to use a[x] - b
In this line below.
var i = bisectDate(dataset, x0.getTime())
here x0 is a date object.
So in the function:
d3.bisector(function(a, b){ return a[x] - b; }).right;
so a[x] is your unixtime which is tie stamp and b as mentioned is also time stamp.
So here in bisector function we subtracting both time stamps to find the closest point.

Using d3-tip on line graph without defined points

So I've gone and implemented something similar to this using that as a tutorial. However, where it reaches the point about a tooltip I want to do something slightly different, I really want to use d3-tip. So I've spent a bunch of time learning how to use d3-tip but it seems that everywhere I look people are defining elements and then attaching mouseover and mouseout events to them in order to make the tooltip appear. I don't believe I can do that because I'm using the previous method of drawing a circle over the line based on where my mouse is on the graph. So I'm wondering what I can do to get d3-tip to work with this implementation, or if it's even possible?
The following is my code:
var margin = {
top: 20,
left: 50,
right: 50,
bottom: 50
},
width = $element.innerWidth() - margin.left - margin.right,
height = 0.2 * width;
var parseTime = d3.timeParse('%m/%d/%Y');
data.forEach(function(d) {
d.date = parseTime(d.date);
d.price = +d.price;
});
data.sort(function(a, b) {
return d3.ascending(a.date, b.date);
});
var formatDate = d3.timeFormat('%b %-d / %Y');
var bisectDate = d3.bisector(function(d) { return d.date; }).left;
var x = d3.scaleTime()
.domain(d3.extent(data, function(d, i) {
return d.date;
}))
.range([0, width]);
var y = d3.scaleLinear()
.domain(d3.extent(data, function(d, i) {
return d.price;
}))
.range([height, 0]);
var xAxis = d3.axisBottom(x)
.tickSizeOuter(0);
var yAxis = d3.axisLeft(y)
.ticks(5)
.tickSizeOuter(0);
var area = d3.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return 'Closing: ' + d.price +
'<br />' +
'Date: ' + formatDate(d.date);
});
var svg = d3.select('#priceChart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.call(tip);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.call(yAxis);
var areaSvg = svg.append('g');
areaSvg.append('path')
.attr('class', 'area')
.attr('d', area(data))
.style('opacity', 0.3);
var lineSvg = svg.append('g');
lineSvg.append('path')
.attr('class', 'line')
.attr('d', line(data));
var focus = svg.append('g')
.style('display', 'none');
focus.append('line')
.attr('class', 'x dash')
.attr('y1', 0)
.attr('y2', height);
focus.append('line')
.attr('class', 'y dash')
.attr('x1', width)
.attr('x2', width);
focus.append('circle')
.attr('class', 'y circle')
.attr('r', 5);
svg.append('rect')
.attr('width', width)
.attr('height', height)
.style('fill', 'none')
.style('pointer-events', 'all')
.on('mouseover', function() { focus.style('display', null); })
.on('mouseout', function() { focus.style('display', 'none'); })
.on('mousemove', mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.select('circle.y')
.attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')');
focus.select('.x')
.attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')')
.attr('y2', height - y(d.price));
focus.select('.y')
.attr('transform', 'translate(' + width * -1 + ',' + y(d.price) + ')')
.attr('x2', width + width);
}
Also, I've got this jsFiddle here that shows all my current work. I've got everything in place and it all works great, minus actually showing the tooltip.
I changed your fiddle a bit so that the tooltip is shown and the text is updated accordingly:
.on('mouseover', function(d) {
focus.style('display', null);
if(d!=undefined){
tip.show(d);// give the tip the data it needs to show
}
})
.on('mouseout', function() {
focus.style('display', 'none');
tip.hide();
})
I also changed mousemove function to update the tip
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.select('circle.y')
.attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')');
focus.select('.x')
.attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')')
.attr('y2', height - y(d.price));
focus.select('.y')
.attr('transform', 'translate(' + width * -1 + ',' + y(d.price) + ')')
.attr('x2', width + width);
// we need to update the offset so that the tip shows correctly
tip.offset([y(d.price) - 20, x(d.date) - (width/2)] ) // [top, left]
tip.show(d);
}
Also updated the css:
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 15px;
width: 1%;
line-height: 4;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
pointer-events: none;
left: 45%;
}
https://jsfiddle.net/mkaran/5t3ycyxs/1/
There could be a better way though.Hope this helps! Good luck!

d3js v4 can't remove old data chart after update

I've modified nice AlainRo’s Block for my needs (unfortunately can't link to it, because have not enough reputation), and I can't remove old data chart after entering new data. There is my codepen. In another example I've added merge(), and the chart is well aligned but the old one is still visible and text values are missed.
I spent a lot of time on it, and I run out of ideas.
There's code
barData = [
{ index: _.uniqueId(), value: _.random(1, 20) },
{ index: _.uniqueId(), value: _.random(1, 20) },
{ index: _.uniqueId(), value: _.random(1, 20) }
];
var margin = {top: 20, right: 20, bottom: 50, left: 70},
width = 400 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
delim = 4;
var scale = d3.scaleLinear()
.domain([0, 21])
.rangeRound([height, 0]);
var x = d3.scaleLinear()
.domain([0, barData.length])
.rangeRound([0, width]);
var y = d3.scaleLinear()
.domain([0, 21])
.rangeRound([height, 0]);
var svg = d3.select('#chart')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append('g')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.call(d3.axisLeft(y));
function draw() {
x.domain([0, barData.length]);
var brush = d3.brushY()
.extent(function (d, i) {
return [[x(i)+ delim/2, 0],
[x(i) + x(1) - delim/2, height]];})
.on("brush", brushmove);
var svgbrush = svg.selectAll('.brush')
.data(barData)
.enter()
.append('g')
.attr('class', 'brush')
.append('g')
.call(brush)
.call(brush.move, function (d){return [d.value, 0].map(scale);});
svgbrush
.append('text')
.attr('y', function (d){return scale(d.value) + 25;})
.attr('x', function (d, i){return x(i) + x(0.5);})
.attr('dx', '-.60em')
.attr('dy', -5)
.style('fill', 'white')
.text(function (d) {return d3.format('.2')(d.value);});
svgbrush
.exit()
.append('g')
.attr('class', 'brush')
.remove();
function brushmove() {
if (!d3.event.sourceEvent) return; // Only transition after input.
if (!d3.event.selection) return; // Ignore empty selections.
if (d3.event.sourceEvent.type === "brush") return;
var d0 = d3.event.selection.map(scale.invert);
var d = d3.select(this).select('.selection');;
var d1 =[d0[0], 0];
d.datum().value = d0[0]; // Change the value of the original data
d3.select(this).call(d3.event.target.move, d1.map(scale));
svgbrush
.selectAll('text')
.attr('y', function (d){return scale(d.value) + 25;})
.text(function (d) {return d3.format('.2')(d.value);});
}
}
draw();
function upadateChartData() {
var newBarsToAdd = document.getElementById('charBarsCount').value;
var newBarData = function() {
return { index: _.uniqueId(), value: _.random(1, 20) }
};
newBarData = _.times(newBarsToAdd, newBarData);
barData = _.concat(barData, newBarData)
draw();
};
Is it also possible to remove cross pointer and leave only resize, when I'm dragging top bar border?
You're appending g elements twice. This:
svgbrush.enter()
.append('g')
.attr('class', 'brush')
.merge(svgbrush)
.append('g')
.call(brush)
.call(brush.move, function (d){return [d.value, 0].map(scale);});
Should be:
svgbrush.enter()
.append('g')
.attr('class', 'brush')
.merge(svgbrush)
.call(brush)
.call(brush.move, function (d){return [d.value, 0].map(scale);});
Here is your updated Pen: http://codepen.io/anon/pen/VmavyX
PS: I also made other changes, declaring some new variables, just to organize your enter and update selections and solving the texts problem.

Not able to display line in D3 bar/line chart

I'm trying to create a combination bar and line graph. The bar is the primary y axis representing data.total and the line is the secondary y axis representing data.percent.
Disclaimer:I'm very new to javascript and D3.
I've been clunking away for hours trying to figure out why the chart won't render the line series. Some of this code was based upon other example templates I found online so there may be something in there that isn't kosher with my modifications and I completely missed it.
Thanks for the help in advance!!!
Here's what I have:
<!DOCTYPE HTML>
<HTML>
<HEAD>
<STYLE>`enter code here`
svg{ padding-left: 100 px}
path {
stroke: Black;
stroke-width: 1;
fill: none;
}
.chartTitle{
color: #002b80;
font-size: 32pt;
font-weight: bold;
text-align: left;
padding-left: 20px;
}
</STYLE>
</HEAD>
<BODY>
<div class="chartTitle">Estimate of "Everything is Awesome"</div>
<SCRIPT SRC = 'd3.min.js'></SCRIPT>
<SCRIPT>
var data = [
{'date': '4/1/2015', 'total':500, 'percent':0.535},
{'date': '5/1/2015', 'total': 650, 'percent': 0.593},
{'date': '6/1/2015', 'total': 700, 'percent': 0.687},
{'date': '7/1/2015', 'total': 750, 'percent': 0.734},
{'date': '8/1/2015', 'total': 800, 'percent': 0.988},
{'date': '9/1/2015', 'total': 850, 'percent': 0.99},
{'date': '10/1/2015', 'total': 900, 'percent': 1.0}
];
var margin = {top: 70, right: 70, bottom: 70, left:60},
width = 600,
height = 500;
var toolTip = d3.select('body').append('div')
.style('position', 'absolute')
.style('background', 'white')
.style('opacity', .9)
.style('padding', '0 20px')
.style('border-radius', '25px')
.style('border', ' 2px solid dodgerblue')
// X and Y Axis
var xScale = d3.time.scale()
.domain([new Date(data[0].date), d3.time.month.offset(new Date(data[data.length - 1].date), 0)])
.rangeRound([0, width - margin.left - margin.right ]);
var y1Scale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.total;})])
.range([height - margin.top - margin.bottom, 0]);
var y2Scale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.percent;})])
.range([height - margin.top - margin.bottom, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(d3.time.month, 1)
.tickFormat(d3.time.format('%b -%y'))
.tickSize(1)
.tickPadding(8);
var y1Axis = d3.svg.axis()
.scale(y1Scale)
.orient('left')
.tickPadding(8)
.tickSize(1);
var y2Axis = d3.svg.axis()
.scale(y2Scale)
.orient('right')
.tickPadding(8)
.tickSize(1);
var lineData = d3.svg.line()
.x(function(d) { return xScale(d.date); })
.y(function(d) { return -1 * y2Scale(d.percent); });
//Chart Body
var svg = d3.select('body').append('svg')
.attr('class', 'chart')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
//Chart Body Creation
svg.selectAll('.chart')
.data(data)
.enter().append('rect')
.style('fill', 'dodgerblue')
.attr('class', 'bar')
.attr('x', function(d) { return xScale(new Date(d.date)); })
.attr('y', function(d) { return height - margin.top - margin.bottom - (height - margin.top - margin.bottom - y1Scale(d.total)) })
.attr('width', 20)
.attr('height', function(d) { return height - margin.top - margin.bottom - y1Scale(d.total) })
// Roll over SFX
.on('mouseover', function (d) {
toolTip.transition()
.style('opacity', .9)
toolTip.html(d.total)
.style('left', (d3.event.pageX - 40) + 'px')
.style('top', (d3.event.pageY - 30) + 'px')
d3.select(this)
.style('opacity', 0.5)
})
.on('mouseout', function (d) {
toolTip.transition()
.delay(100)
.duration(600)
.style('opacity', 0)
.style('pointer-events', 'none')
d3.select(this)
.style('opacity', 1)
});
//lDraw Line
svg.append("path")
.attr("d", lineData(data))
.style('stroke', 'DarkOrange');
//Draw the X Axis
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + (height - margin.top - margin.bottom) + ')')
.call(xAxis);
//Draw the Y1 Axis
svg.append('g')
.attr('class', 'y axis')
.call(y1Axis);
//Draw the Y2 Axis
svg.append('g')
.attr('class', 'y axis')
.attr("transform", "translate(" + (height ) + " ,0)")
.call(y2Axis);
</SCRIPT>
</BODY>
</HTML>
Problem 1:
You have date in this format {'date': '10/1/2015', 'total': 900, 'percent': 1.0} in your JSON, you will need to convert it into date object.
var format = d3.time.format("%d/%m/%Y");
data.forEach(function(d){
d.date = format.parse(d.date);
});
For various date format parsing refer
Problem2:
You are defining the domain incorrectly
var xScale = d3.time.scale()
.domain([new Date(data[0].date), d3.time.month.offset(new Date(data[data.length - 1].date), 0)])
.rangeRound([0, width - margin.left - margin.right ]);
Domain should be min/max of the date.
var xScale = d3.time.scale()
.domain([d3.min(data, function(d){return d.date}), d3.max(data, function(d){return d.date})])
.rangeRound([0, width - margin.left - margin.right]);
Reason for why is line not drawing up
var lineData = d3.svg.line()
.x(function(d) { return xScale(d.date); })//this date is not in the correct format so d3 does not know what to do and so gives NaN.
.y(function(d) { return -1 * y2Scale(d.percent); });
Now Problem 1 will fix this issue since we have converted the data into date.
Working example here
Hope this helps!

Resources