D3js library from csv to json input - javascript

I am a beginner in JS and D3. Doing reseach for my project I found this library which gives the type of plot needed for our project written in d3js. The input is cvs, but the setup requires using json. To migrate the code I have used d3.json, but the app only loads one data element. Any ideas what's going wrong?
input json (snippet)
[
{"date":"2017-09-03 19:49:51","volume":"3070.33","price":"0.0314009","average":"0.0314009"},
{"date":"2017-09-03 19:59:47","volume":"3061.02","price":"0.0313057","average":"0.0313057"},
{"date":"2017-09-03 20:09:46","volume":"3062.63","price":"0.0313221","average":"0.0313221"},
{"date":"2017-09-03 20:19:54","volume":"3049.41","price":"0.0311875","average":"0.0311875"}
]
Code
/* global d3, _ */
(function() {
var margin = {top: 30, right: 20, bottom: 100, left: 50},
margin2 = {top: 210, right: 20, bottom: 20, left: 50},
width = 764 - margin.left - margin.right,
height = 283 - margin.top - margin.bottom,
height2 = 283 - margin2.top - margin2.bottom;
var parseDate = d3.time.format('%d/%m/%Y %H:%M').parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
legendFormat = d3.time.format('%b %d, %Y %H:%M');
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y1 = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]),
y3 = d3.scale.linear().range([60, 0]);
var xAxis = d3.svg.axis().scale(x).orient('bottom'),
xAxis2 = d3.svg.axis().scale(x2).orient('bottom'),
yAxis = d3.svg.axis().scale(y).orient('left');
var priceLine = d3.svg.line()
.interpolate('monotone')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
var avgLine = d3.svg.line()
.interpolate('monotone')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.average); });
var area2 = d3.svg.area()
.interpolate('monotone')
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var svg = d3.select('body').append('svg')
.attr('class', 'chart')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom + 60);
svg.append('defs').append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', width)
.attr('height', height);
var make_y_axis = function () {
return d3.svg.axis()
.scale(y)
.orient('left')
.ticks(3);
};
var focus = svg.append('g')
.attr('class', 'focus')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var barsGroup = svg.append('g')
.attr('class', 'volume')
.attr('clip-path', 'url(#clip)')
.attr('transform', 'translate(' + margin.left + ',' + (margin.top + 60 + 20) + ')');
var context = svg.append('g')
.attr('class', 'context')
.attr('transform', 'translate(' + margin2.left + ',' + (margin2.top + 60) + ')');
var legend = svg.append('g')
.attr('class', 'chart__legend')
.attr('width', width)
.attr('height', 30)
.attr('transform', 'translate(' + margin2.left + ', 10)');
legend.append('text')
.attr('class', 'chart__symbol')
.text('Renos : RNS')
var rangeSelection = legend
.append('g')
.attr('class', 'chart__range-selection')
.attr('transform', 'translate(110, 0)');
d3.json('http://rns.ud.vg/datastockstyle.php', function(err, data) {
data.forEach( function(d) {
date = parseDate(d.date);
price = +d.price;
average = +d.average;
volume = +d.volume;
});
var brush = d3.svg.brush()
.x(x2)
.on('brush', brushed);
var xRange = d3.extent(data.map(function(d) { return d.date; }));
x.domain(xRange);
y.domain(d3.extent(data.map(function(d) { return d.price; })));
y3.domain(d3.extent(data.map(function(d) { return d.price; })));
x2.domain(x.domain());
y2.domain(y.domain());
var min = d3.min(data.map(function(d) { return d.price; }));
var max = d3.max(data.map(function(d) { return d.price; }));
var range = legend.append('text')
.text(legendFormat(new Date(xRange[0])) + ' - ' + legendFormat(new Date(xRange[1])))
.style('text-anchor', 'end')
.attr('transform', 'translate(' + width + ', 0)');
focus.append('g')
.attr('class', 'y chart__grid')
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(''));
var averageChart = focus.append('path')
.datum(data)
.attr('class', 'chart__line chart__average--focus line')
.attr('d', avgLine);
var priceChart = focus.append('path')
.datum(data)
.attr('class', 'chart__line chart__price--focus line')
.attr('d', priceLine);
focus.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0 ,' + height + ')')
.call(xAxis);
focus.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(12, 0)')
.call(yAxis);
var focusGraph = barsGroup.selectAll('rect')
.data(data)
.enter().append('rect')
.attr('class', 'chart__bars')
.attr('x', function(d, i) { return x(d.date); })
.attr('y', function(d) { return 155 - y3(d.price); })
.attr('width', 1)
.attr('height', function(d) { return y3(d.price); });
var helper = focus.append('g')
.attr('class', 'chart__helper')
.style('text-anchor', 'end')
.attr('transform', 'translate(' + width + ', 0)');
var helperText = helper.append('text')
var priceTooltip = focus.append('g')
.attr('class', 'chart__tooltip--price')
.append('circle')
.style('display', 'none')
.attr('r', 2.5);
var averageTooltip = focus.append('g')
.attr('class', 'chart__tooltip--average')
.append('circle')
.style('display', 'none')
.attr('r', 2.5);
var mouseArea = svg.append('g')
.attr('class', 'chart__mouse')
.append('rect')
.attr('class', 'chart__overlay')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.on('mouseover', function() {
helper.style('display', null);
priceTooltip.style('display', null);
averageTooltip.style('display', null);
})
.on('mouseout', function() {
helper.style('display', 'none');
priceTooltip.style('display', 'none');
averageTooltip.style('display', 'none');
})
.on('mousemove', mousemove);
context.append('path')
.datum(data)
.attr('class', 'chart__area area')
.attr('d', area2);
context.append('g')
.attr('class', 'x axis chart__axis--context')
.attr('y', 0)
.attr('transform', 'translate(0,' + (height2 - 22) + ')')
.call(xAxis2);
context.append('g')
.attr('class', 'x brush')
.call(brush)
.selectAll('rect')
.attr('y', -6)
.attr('height', height2 + 7);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]);
var i = bisectDate(data, x0, 1);
var d0 = data[i - 1];
var d1 = data[i];
var d = x0 - d0.date > d1.date - x0 ? d1 : d0;
helperText.text(legendFormat(new Date(d.date)) + ' - Price: ' + d.price + ' Avg: ' + d.average);
priceTooltip.attr('transform', 'translate(' + x(d.date) + ',' + y(d.price) + ')');
averageTooltip.attr('transform', 'translate(' + x(d.date) + ',' + y(d.average) + ')');
}
function brushed() {
var ext = brush.extent();
if (!brush.empty()) {
x.domain(brush.empty() ? x2.domain() : brush.extent());
y.domain([
d3.min(data.map(function(d) { return (d.date >= ext[0] && d.date <= ext[1]) ? d.price : max; })),
d3.max(data.map(function(d) { return (d.date >= ext[0] && d.date <= ext[1]) ? d.price : min; }))
]);
range.text(legendFormat(new Date(ext[0])) + ' - ' + legendFormat(new Date(ext[1])))
focusGraph.attr('x', function(d, i) { return x(d.date); });
var days = Math.ceil((ext[1] - ext[0]) / (24 * 3600 * 1000))
focusGraph.attr('width', (40 > days) ? (40 - days) * 5 / 6 : 5)
}
priceChart.attr('d', priceLine);
averageChart.attr('d', avgLine);
focus.select('.x.axis').call(xAxis);
focus.select('.y.axis').call(yAxis);
}
var dateRange = ['1h', '1d', '1w', '1m', '3m', '6m', '1y']
for (var i = 0, l = dateRange.length; i < l; i ++) {
var v = dateRange[i];
rangeSelection
.append('text')
.attr('class', 'chart__range-selection')
.text(v)
.attr('transform', 'translate(' + (18 * i) + ', 0)')
.on('click', function(d) { focusOnRange(this.textContent); });
}
function focusOnRange(range) {
var today = new Date(data[data.length - 1].date)
var ext = new Date(data[data.length - 1].date)
if (range === '1m')
ext.setMonth(ext.getMonth() - 1)
if (range === '1w')
ext.setDate(ext.getDate() - 7)
if (range === '1d')
ext.setDate(ext.getDate() - 1)
if (range === '1h')
ext.setTime(ext.getTime() - 60*60*1000)
if (range === '3m')
ext.setMonth(ext.getMonth() - 3)
if (range === '6m')
ext.setMonth(ext.getMonth() - 6)
if (range === '1y')
ext.setFullYear(ext.getFullYear() - 1)
brush.extent([ext, today])
brushed()
document.getElementById("demo").innerHTML =ext;
context.select('g.x.brush').call(brush.extent([ext, today]))
}
})// end Data
}());

The data contains hyphens not forward slashes.
Your date parsing should not be
var parseDate = d3.time.format('%d/%m/%Y %H:%M').parse,
it should be,
var parseDate = d3.time.format('%d-%m-%Y %H:%M').parse,
Also, what is y0? I don't see y0 in your scales.
.y0(height2)
I don't know what's wrong with your code, but others will be able to help easier with this,
jsFiddle

Related

my data is undefined in my d3.js data viz

I'm trying to build a line graph that when the user hovers over a part of the chart, a callout appears with the date, country and incidents data points. however currently all my data points show up as 'undefined'. does anyone know what's going on here?
here is my code.
function circleHover(chosen) {
if (modus == "incidents") {
d3.select("#callOut")
.style("top", "570px")
.style("left", "30px");
d3.select("#divCountry").html('Country: ' + chosen.country);
d3.select("#divDate").html('Date: ' + chosen.date);
d3.select("#divIncidents").html('Incidents: ' + chosen.incidents);
d3.select("#callOut")
.style("visibility","visible");
}
if (modus == "fatalities") {
d3.select("#callOut2")
.style("top", "570px")
.style("left", "30px");
d3.select("#divCountry2").html('Country: ' + chosen.country);
d3.select("#divDate2").html('Date: ' + chosen.date);
d3.select("#divFatalities2").html('Fatalities: ' + chosen.fatalities);
d3.select("#callOut2")
.style("visibility","visible");
}
if (modus == "injuries") {
d3.select("#callOut3")
.style("top", "570px")
.style("left", "30px");
d3.select("#divCountry3").html('Country: ' + chosen.country);
d3.select("#divDate3").html('Date: ' + chosen.date);
d3.select("#divInjuries3").html('Injuries: ' + chosen.injuries);
d3.select("#callOut3")
.style("visibility","visible");
}
};
function showOne(d) {
var margin = {top: 80, right: 80, bottom: 80, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#svg").append("svg")
.attr("width", width)
.attr("height", height);
var incidentsData = svg.append("g");
incidentsData.selectAll(".incidentsData")
.data(incidentData)
.enter()
.append('incidentsData')
.attr('class', 'incidentsData');
var fatalitiesData = svg.append("g");
fatalitiesData.selectAll(".fatalitiesData")
.data(fatalityData)
.enter()
.append('fatalitiesData')
.attr('class', 'fatalitiesData');
var injuriesData = svg.append("g");
injuriesData.selectAll(".injuriesData")
.data(injuryData)
.enter()
.append('injuriesData')
.attr('class', 'injuriesData');
var chosen = d;
var setOpacity = 0;
if (modus == "incidents") {
circleHover(chosen);
setOpacity = 0.1;
incidentsData.selectAll(".incidentsData")
.filter(function (d) { return eval("d.country") != eval("chosen.country");})
.style("fill-opacity", setOpacity);
}
if (modus == "fatalities") {
circleHover(chosen);
setOpacity = 0.1;
fatalitiesData.selectAll(".fatalitiesData")
.filter(function (d) { return eval("d.country") != eval("chosen.country");})
.style("fill-opacity", setOpacity);
}
if (modus == "injuries") {
circleHover(chosen);
setOpacity = 0.1;
injuriesData.selectAll(".injuriesData")
.filter(function (d) { return eval("d.country") != eval("chosen.country");})
.style("fill-opacity", setOpacity);
}
};
function showAll() {
var margin = {top: 80, right: 80, bottom: 80, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#svg").append("svg")
.attr("width", width)
.attr("height", height);
var incidentsData = svg.append("g");
incidentsData.selectAll(".incidentsData")
.data(incidentData)
.enter()
.append('incidentsData')
.attr('class', 'incidentsData');
var fatalitiesData = svg.append("g");
fatalitiesData.selectAll(".fatalitiesData")
.data(fatalityData)
.enter()
.append('fatalitiesData')
.attr('class', 'fatalitiesData');
var injuriesData = svg.append("g");
injuriesData.selectAll(".injuriesData")
.data(injuryData)
.enter()
.append('injuriesData')
.attr('class', 'injuriesData');
if (modus == "incidents") {
incidentsData.selectAll(".incidentsData")
.style("fill-opacity", 0.5);
d3.select("#callOut").style("visibility","hidden");
}
if (modus == "fatalities") {
fatalitiesData.selectAll(".fatalitiesData")
.style("fill-opacity", 0.5);
d3.select("#callOut2").style("visibility","hidden");
}
if (modus == "injuries") {
injuriesData.selectAll(".injuriesData")
.style("fill-opacity", 0.5);
d3.select("#callOut3").style("visibility","hidden");
}
};
//totalIncidents
function totalIncidentsLineGraph() {
modus = "incidents";
var margin = {top: 80, right: 80, bottom: 80, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#svg").append("svg")
.attr("width", width)
.attr("height", height);
var incidentsData = svg.append("g");
incidentsData.selectAll(".incidentsData")
.data(incidentData)
.enter()
.append('incidentsData')
.attr('class', 'incidentsData');
//.on("mouseover", showOne)
//.on("mouseout", showAll);
//.attr('id', function (d) { return "id_2010_" + d.rank_pop; })
//var parse = d3.time.format("%b %Y").parse;
var parse = d3.time.format("%Y").parse;
// Scales and axes. Note the inverted domain for the y-scale: bigger is up!
var x = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
xAxis = d3.svg.axis().scale(x).tickSize(-height).tickSubdivide(true),
yAxis = d3.svg.axis().scale(y).ticks(4).orient("right");
// An area generator, for the light fill.
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.incidents); });
// A line generator, for the dark stroke.
var line = d3.svg.line()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.incidents); });
// Parse dates and numbers. We assume israel are sorted by date.
function type(d) {
d.country = d.country;
d.date = parse(d.date);
d.incidents = +d.incidents
return d;
};
var data = d3.csv("static/data/israel/incidents_linechart.csv", type, function(error, data) {
console.log(data);
var israel = data.filter(function(d) {
return d.country == "Israel";
});
var unitedStates = data.filter(function(d) {
return d.country == "United States";
});
var iran = data.filter(function(d) {
return d.country == "Iran";
});
var saudiArabia = data.filter(function(d) {
return d.country == "Saudi Arabia";
});
var turkey = data.filter(function(d) {
return d.country == "Turkey";
});
var egypt = data.filter(function(d) {
return d.country == "Egypt";
});
var syria = data.filter(function(d) {
return d.country == "Syria";
});
var lebanon = data.filter(function(d) {
return d.country == "Lebanon";
});
var jordan = data.filter(function(d) {
return d.country == "Jordan";
});
var palestine = data.filter(function(d) {
return d.country == "Palestine";
});
x.domain([unitedStates[0].date, unitedStates[unitedStates.length - 1].date]);
y.domain([0, d3.max(egypt, function(d) { return d.incidents; })]).nice();
//x.domain([israel[0].date, israel[israel.length - 1].date]);
//y.domain([0, d3.max(israel, function(d) { return d.incidents; })]).nice();
// Add an SVG element with the desired dimensions and margin.
var svg = d3.select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
// Add the clip path.
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the y-axis.
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ",0)")
.call(yAxis);
var colors = d3.scale.category10();
svg.selectAll('.line')
.data([israel, unitedStates, iran, saudiArabia, turkey, egypt, syria, lebanon, jordan, palestine]) /// can add however many i want here
.enter()
.append('path')
.attr('class', 'line')
.style('stroke', function(d) {
return colors(Math.random() * 50);
})
.attr('clip-path', 'url(#clip)')
.attr('d', function(d) {
return line(d);
})
.on("mouseover", showOne)
.on("mouseout", showAll);
/* Add 'curtain' rectangle to hide entire graph */
var curtain = svg.append('rect')
.attr('x', -1 * width)
.attr('y', -1 * height)
.attr('height', height)
.attr('width', width)
.attr('class', 'curtain')
.attr('transform', 'rotate(180)')
.style('fill', '#ffffff')
/* Optionally add a guideline */
var guideline = svg.append('line')
.attr('stroke', '#333')
.attr('stroke-width', 0)
.attr('class', 'guide')
.attr('x1', 1)
.attr('y1', 1)
.attr('x2', 1)
.attr('y2', height)
/* Create a shared transition for anything we're animating */
var t = svg.transition()
.delay(750)
.duration(6000)
.ease('linear')
.each('end', function() {
d3.select('line.guide')
.transition()
.style('opacity', 0)
.remove()
});
t.select('rect.curtain')
.attr('width', 0);
t.select('line.guide')
.attr('transform', 'translate(' + width + ', 0)')
d3.select("#show_guideline").on("change", function(e) {
guideline.attr('stroke-width', this.checked ? 1 : 0);
curtain.attr("opacity", this.checked ? 0.75 : 1);
})
});
};
here is a snippet of my data:
any help owuld be immensely appreciated.

How to print content of tooltip on different lines in D3

Below is the code for horizontal stacked Bar Chart. When I hover on any bar, it shows me content of the element all in single line. I want to add line break to separate each parameter of the data. I tried looking for this type of question and found something with 'tspan' but that is not working in my code. Please have a look.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="lit" uri="/WEB-INF/......" %>
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" media="all" type="text/css" href="<c:url value="/styl........."/>" />
</head>
<body>
<script src="//d3js.org/d3.v3.js"></script>
<script>
var i = 0;
var margins = {
top: 12,
left: 48,
right: 24,
bottom: 24
},
legendPanel = {
width: 180
},
width = 1500 - margins.left - margins.right - legendPanel.width,
height = 900 - margins.top - margins.bottom,
dataset = ${JSONData},
series = dataset.map(function (d) {
return d.name;
}),
dataset = dataset.map(function (d) {
return d.data.map(function (o) {
return {
name: d.name,
y: +o.count,
x: o.time
};
});
}),
stack = d3.layout.stack();
stack(dataset);
var dataset = dataset.map(function (group) {
return group.map(function (d) {
return {
name: d.name,
x: d.y,
y: d.x,
x0: d.y0
};
});
}),
svg = d3.select('body')
.append('svg')
.attr('width', width + margins.left + margins.right + legendPanel.width)
.attr('height', height + margins.top + margins.bottom)
.append('g')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
xMax = d3.max(dataset, function (group) {
return d3.max(group, function (d) {
return d.x + d.x0;
});
}),
xScale = d3.scale.linear()
.domain([0, xMax])
.range([0, width]),
months = dataset[0].map(function (d) {
return d.y;
}),
_ = console.log(months),
yScale = d3.scale.ordinal()
.domain(months)
.rangeRoundBands([0, height], .1),
xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom'),
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left'),
colours = d3.scale.category10(),
groups = svg.selectAll('g')
.data(dataset)
.enter()
.append('g')
.style('fill', function (d, i) {
return colours(i);
}),
rects = groups.selectAll('rect')
.data(function (d) {
return d;
})
.enter()
.append('rect')
.attr('x', function (d) {
return xScale(d.x0);
})
.attr('y', function (d, i) {
return yScale(d.y);
})
.attr('height', function (d) {
return yScale.rangeBand();
})
.attr('width', function (d) {
return xScale(d.x);
})
.on('mouseover', function (d) {
var xPos = parseFloat(d3.select(this).attr('x')) / 2 + width/2;
var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() / 2;
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.text("Count: " + d.x + "Time: " + d.y + "String1"+
"\nString2");
//.text(d.x+","+d.y+","+d.name);
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function () {
d3.select('#tooltip').classed('hidden', true);
})
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'axis')
.call(yAxis);
svg.append('rect')
.attr('fill', 'yellow')
.attr('width', 160)
.attr('height', 30 * dataset.length)
.attr('x', width + margins.left)
.attr('y', 0);
series.forEach(function (s, i) {
svg.append('text')
.attr('fill', 'black')
.attr('x', width + margins.left + 8)
.attr('y', i * 24 + 24)
.text(s);
svg.append('rect')
.attr('fill', colours(i))
.attr('width', 60)
.attr('height', 20)
.attr('x', width + margins.left + 90)
.attr('y', i * 24 + 6);
});
</script>
<div id="tooltip" class="hidden">
<p><span id="value">100</span>
</p>
</div>
</body>
</html>
Your "tooltip" is just an HTML span; so all you need to do is use .html and a <br> for the line break:
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.html("Count: " + d.x + "Time: " + d.y + " String1" + "<br>String2");
If you had been creating an svg text element, then you'd need to append multiple tspan elements to it.
Full code:
<html>
<head>
</head>
<body>
<script src="//d3js.org/d3.v3.js"></script>
<script>
var i = 0;
var margins = {
top: 12,
left: 48,
right: 24,
bottom: 24
},
legendPanel = {
width: 180
},
width = 1500 - margins.left - margins.right - legendPanel.width,
height = 900 - margins.top - margins.bottom,
dataset = [{data:[{
count: Math.random(),
time: "One"
},{
count: Math.random(),
time: "Two"
},{
count: Math.random(),
time: "Three"
}]}];
series = dataset.map(function(d) {
return d.name;
}),
dataset = dataset.map(function(d) {
return d.data.map(function(o) {
return {
name: d.name,
y: +o.count,
x: o.time
};
});
}),
stack = d3.layout.stack();
stack(dataset);
var dataset = dataset.map(function(group) {
return group.map(function(d) {
return {
name: d.name,
x: d.y,
y: d.x,
x0: d.y0
};
});
}),
svg = d3.select('body')
.append('svg')
.attr('width', width + margins.left + margins.right + legendPanel.width)
.attr('height', height + margins.top + margins.bottom)
.append('g')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
xMax = d3.max(dataset, function(group) {
return d3.max(group, function(d) {
return d.x + d.x0;
});
}),
xScale = d3.scale.linear()
.domain([0, xMax])
.range([0, width]),
months = dataset[0].map(function(d) {
return d.y;
}),
_ = console.log(months),
yScale = d3.scale.ordinal()
.domain(months)
.rangeRoundBands([0, height], .1),
xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom'),
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left'),
colours = d3.scale.category10(),
groups = svg.selectAll('g')
.data(dataset)
.enter()
.append('g')
.style('fill', function(d, i) {
return colours(i);
}),
rects = groups.selectAll('rect')
.data(function(d) {
return d;
})
.enter()
.append('rect')
.attr('x', function(d) {
return xScale(d.x0);
})
.attr('y', function(d, i) {
return yScale(d.y);
})
.attr('height', function(d) {
return yScale.rangeBand();
})
.attr('width', function(d) {
return xScale(d.x);
})
.on('mouseover', function(d) {
var xPos = parseFloat(d3.select(this).attr('x')) / 2 + width / 2;
var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() / 2;
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.html("Count: " + d.x + "Time: " + d.y + " String1" + "<br>String2");
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function() {
d3.select('#tooltip').classed('hidden', true);
})
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g')
.attr('class', 'axis')
.call(yAxis);
svg.append('rect')
.attr('fill', 'yellow')
.attr('width', 160)
.attr('height', 30 * dataset.length)
.attr('x', width + margins.left)
.attr('y', 0);
series.forEach(function(s, i) {
svg.append('text')
.attr('fill', 'black')
.attr('x', width + margins.left + 8)
.attr('y', i * 24 + 24)
.text(s);
svg.append('rect')
.attr('fill', colours(i))
.attr('width', 60)
.attr('height', 20)
.attr('x', width + margins.left + 90)
.attr('y', i * 24 + 6);
});
</script>
<div id="tooltip" class="hidden">
<p>
<span id="value">100</span>
</p>
</div>
</body>
</html>

D3js zoom/drag not working any more in my code (+code sample)

Code
In this file http://tc51.net/w/at/stackoverflow.com/20150604.1/20150604.1.zip
You will find all .htm, .js, .css, .csv files of:
The example I started with
My current work in progess.
The problem
Since I did some refactoring required for further developments, the chart drag/zoom feature is not working anymore. No apparent JavaScript error in debugger, and it seems to have to do with 3Djs inner zoom functions so I have no clue what I did wrong. Can you help me find out? Thank you.
(I tried to create two JSFiddles as well but they don't work at all, I have no idea why: Start example:
https://jsfiddle.net/TTTT/erndok36/2 Current work in progress: https://jsfiddle.net/TTTT/mfudwy0q
)
And here is some code:
//Start example: http://mbostock.github.io/d3/talk/20111018/area-gradient.html
function parseDate(unix_timestamp){return new Date(unix_timestamp*1000);}
var svg, m, w, h, x, y, xAxis, yAxis, area, line, gradient, margin, varData,
//parseDate = d3.time.format('%Y-%m-%d').parse,
format = d3.time.format('%Y')
function CreateSvg()
{
margin = {top: 79, right: 80, bottom: 160, left: 79};
//m = [79, 80, 160, 79];
w = 1280 - margin.right - margin.left;
h = 800 - margin.top - margin.bottom;
//Scales. Note the inverted domain for the y-scale: bigger is up!
x = d3.time.scale().range([0, w]);
y = d3.scale.linear().range([h, 0]);
xAxis = d3.svg.axis().scale(x).orient('bottom').tickPadding(6).tickFormat(d3.time.format('%Y/%m/%d %H:%M:%S')).ticks(30); //.tickSize(-h, 0)
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(w).tickPadding(6);
area = d3.svg.area()
.interpolate('step-after')
.x(function(d) { return x(d.date); })
.y0(y(0))
.y1(function(d) { return y(d.value); });
line = d3.svg.line()
.interpolate('step-after')
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
svg = d3.select('#ChartContainer').append('svg:svg')
.attr('width', w + margin.right + margin.left)
.attr('height', h + margin.top + margin.bottom)
.append('svg:g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
gradient = svg.append('svg:defs').append('svg:linearGradient')
.attr('id', 'gradient')
.attr('x2', '0%')
.attr('y2', '100%');
gradient.append('svg:stop')
.attr('offset', '40%')
.attr('stop-color', '#f00')
.attr('stop-opacity', .5);
gradient.append('svg:stop')
.attr('offset', '100%')
.attr('stop-color', '#0f0')
.attr('stop-opacity', 1);
svg.append('svg:clipPath')
.attr('id', 'clip')
.append('svg:rect')
.attr('x', x(0))
.attr('y', y(1))
.attr('width', x(1) - x(0))
.attr('height', y(0) - y(1));
svg.append('svg:g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + w + ',0)');
svg.append('svg:path')
.attr('class', 'area')
.attr('clip-path', 'url(#clip)')
.style('fill', 'url(#gradient)');
svg.append('svg:g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + h + ')');
svg.append('svg:path')
.attr('class', 'line')
.attr('clip-path', 'url(#clip)');
svg.append('svg:rect')
.attr('class', 'pane')
.attr('width', w)
.attr('height', h)
.call(d3.behavior.zoom().on('zoom', zoom));
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 0-margin.left)
.attr('x', 0-(h/2))
.attr('dy', '1em')
.style('text-anchor', 'middle')
.text('Noise (dB)');
svg.append('text')
.attr('y', w/2)
.attr('x', h)
.attr('dx', '1em')
.style('text-anchor', 'middle')
.text('Time');
}
function CreateData()
{
//.csv() function is async!
d3.csv('data-noise-example.csv', function(data)
{
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
//Adds two random data. ''Getting started experimentation code.'
//data.reverse();
data.push({date:parseDate(1433160989), value:Math.random() * 180});
data.push({date:parseDate(1433160990), value:Math.random() * 180});
data.push({date:parseDate(1433160991), value:179});
data.push({date:parseDate(1433160992), value:1});
//data.reverse();
varData = data;
ReDraw(varData);
});
}
function ReDrawTest()
{
varData.push({date:parseDate(1433160993), value:Math.random() * 180});
varData.push({date:parseDate(1433160994), value:Math.random() * 180});
ReDraw(varData);
}
function FirstDraw()
{
CreateData();
//ReDraw(varData);
}
function ReDraw(data)
{
y.domain([0, 180]);
x.domain([parseDate(1433160660), parseDate(1433160780)]);
//Bind the data to our path elements
svg.select('path.area').data([data]);
svg.select('path.line').data([data]);
var t = svg.select('g.x.axis').call(xAxis).selectAll('text')
.style('text-anchor', 'end')
.attr('dx', '-.8em')
.attr('dy', '.15em');
t.attr('transform', 'translate(-2,0)').attr('transform', 'rotate(-90)');
svg.select('g.y.axis').call(yAxis);
svg.select('path.area').attr('d', area);
svg.select('path.line').attr('d', line); //.on('click', clickPath).on('mouseover', onMouseOverPath);
//d3.select('#footer span').text('U.S. Commercial Flights, ' + x.domain().map(format).join('-'));
}
/*function clickPath(e){
console.log('onclickPath', this);
//console.log('onclickPath', this.attr("d"));
var coordinates = d3.mouse(this);
console.log(coordinates[0],coordinates[1]);
}
function findData(x,y)
{
var relY = Math.abs(height-y)/height;
var valY = relY*(chartMaxY-chartMinY);
return [valY,''];
}
function onMouseOverPath(e){
var coordinates = d3.mouse(this);
var x = coordinates[0];
var y = coordinates[1];
var coordValue = 'Coord.: x:' + x + ',y:' + y;
$('#coordValue').text(coordValue);
//Probably not the cleanest way, but that way gives result ...
//console.log(svg.select('title'));
//console.log(coordinates[0] + ',' +coordinates[1]);
var retrievedData = findData(x,y);
var noiseValue = 'Noise: '+ retrievedData[0]+','+retrievedData[1];
$('#noiseValue').text(noiseValue);
svg.append('svg:title').text(noiseValue + "\r\n" + coordValue);
svg.select('title').text(noiseValue + "\r\n" + coordValue);
}
function onMouseOutPath(){alert('mouseOutPath');}
function click() {alert('onclick');}
function onMouseOver(){alert('mouseOver');}
function onMouseOut(){alert('mouseOut');}*/
function zoom() {
d3.event.transform(x); //TODO d3.behavior.zoom should support extents
ReDraw(varData);
}
$(document).ready(function() {
CreateSvg();
FirstDraw();
});
Solution found:
Moving
y.domain([0, 180]);
x.domain([parseDate(1433160660), parseDate(1433160780)]);
to
function FirstDraw(){...}
(I thought I had tested it already ...)

D3js Angular Directive Lots of Repeating Code on Re-Rendering

I'm a little new to using D3, and trying to create a scatter-plot. I seem to have lots of repeating code due for window resize, and rendering on data updates. I'm not sure if it's the nature of D3 and updating data or if I'm overlooking a pretty obvious update pattern.
The directive seems lengthy, but only because I have similar code repeated in updateWindow() (for browser resize), render (for the initial rendering and inserting SVG elements, and update (for updating the element attributes when the data changes). Here is my directive, currently:
app.directive('scatterPlot', function ($window, inputService, dataHandler) {
return {
restrict: 'E',
scope: {
input: '=',
display: '='
},
link: function (scope, element, array) {
var container = angular.element(document.querySelector('section.output'))[0];
var filterCount = 0;
var data = undefined;
// ********** ********** ************ //
// ********* ************ *********** //
// ******** ************** ********** //
// ******* **************** ********* //
// ******* WATCH AND RENDER ********* //
scope.$on('inputChange', function(event, isDeleted, isEmpty, isComplete, id, value) {
// CHECK FOR MATCHES //
console.log('event: ', event);
console.log('isDeleted: ', isDeleted, ', isEmpty: ', isEmpty, ', isComplete: ', isComplete, ', id: ', id, ', value: ', value);
if (isDeleted) {
filterCount -= 1;
console.log('filterCount: ', filterCount);
} else {
if (filterCount == 0) {
dataHandler.matchQuery(id, value).then(function(matches) {
data = matches;
filterCount += 1;
return render(matches);
});
} else {
dataHandler.matchQuery(id, value, data).then(function(matches) {
data = matches;
filterCount += 1;
if (filterCount > 0) {
return update(data);
}
});
}
}
});
var formatAsMillions = d3.format('$' + "s");
var formatAsYears = function(d) { return Math.floor(d/365) + ' Years'; };
function update(data) {
var el = element[0];
var margin = {
top: container.clientHeight / 12,
right: container.clientWidth / 7,
bottom: container.clientHeight / 5,
left: container.clientWidth / 11
};
var w = (container.clientWidth - margin.left - margin.right) * 0.9;
var h = (container.clientHeight - margin.top - margin.bottom) * 0.9;
var input = data;
var xScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ctc"]; })])
.range([0, w])
.nice();
var yScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ttc"]; })])
.range([h, 0])
.nice();
var rScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["effective"]; })])
.range([2, 10]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(5)
.tickFormat(formatAsMillions);
var max= xScale.domain()[1];
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.ticks(8)
.tickFormat(formatAsYears)
.tickFormat(function (days) {
if (max < 50) {
return d3.format("2.1f")(days) + " d";
}
else if (max >= 50 && max < 100) {
return d3.format("2.1f")(days/7) + " w";
}
else if (max >= 100 && max < 500) {
return d3.format("2.1f")(days/(365/12)) + " m";
}
else if (max >= 500){
return d3.format("2.1f")(days/365) + " y";
}
});
// *********** //
// SVG ELEMENT //
var svg = d3.select('svg')
.attr('class', 'scatter')
.attr('width', w + margin.left + margin.right)
.attr('height', h + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// add X axis
d3.select('.xAxis')
.data(input)
.remove()
.exit()
svg.append('g')
.attr('class', 'xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis);
// add Y axis
d3.select('.yAxis')
.data(input)
.remove()
.exit()
svg.append('g')
.attr('class', 'yAxis')
.call(yAxis);
// DATA JOIN
// Join new data with old elements, if any.
var circle = d3.selectAll('circle')
.data(input, function(d) {return d.id;})
.remove()
.exit();
// UPDATE
// Update old elements as needed.
circle.attr('class', 'update')
.transition()
.duration(300)
.attr('cx', function(d) { return xScale(d["ctc"]); })
.attr('cy', function(d) { return yScale(d["ttc"]); })
.attr('r', function(d) { return rScale(d["effective"]); });
}
function render(matches) {
console.log(matches.length);
// ********** ********** ************ //
// ********* ************ *********** //
// ******** ************** ********** //
// ******** **************** ******** //
// ******** BASIC ATTRIBUTES ******** //
var input = matches;
var el = element[0];
var effectiveScale = d3.scale.linear()
.domain([1, d3.max(input, function(d) {return d["effective"]; }) ])
.range(["#35ca98", "#029765", "#006432", "#001700"]);
var margin = {
top: container.clientHeight / 12,
right: container.clientWidth / 7,
bottom: container.clientHeight / 5,
left: container.clientWidth / 11
};
var w = (container.clientWidth - margin.left - margin.right) * 0.9;
var h = (container.clientHeight - margin.top - margin.bottom) * 0.9;
var xScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ctc"]; })])
.range([0, w])
.nice();
var yScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ttc"]; })])
.range([h, 0])
.nice();
var rScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["effective"]; })])
.range([2, 15]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(5)
.tickFormat(formatAsMillions);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.ticks(8)
.tickFormat(formatAsYears);
// *********** //
// SVG ELEMENT //
var svg = d3.select(el)
.append('svg')
.attr('class', 'scatter')
.attr('width', w + margin.left + margin.right)
.attr('height', h + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// add X axis
svg.append('g')
.attr('class', 'xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis);
// add Y axis
svg.append('g')
.attr('class', 'yAxis')
.call(yAxis);
//Create the tooltip label
var tooltip = d3.select('body')
.append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('z-index', '10')
.style('visibility', 'hidden')
// add circles in group
var circles = svg.append('g')
.attr('class','circles')
.attr('clip-path','url(#chart-area)');
// add individual circles
var circle = circles.selectAll('circle')
.data(input, function(d) {return d.id;})
.enter()
.append('circle')
.attr('class', 'circle')
.attr('cx', function(d) { return xScale(d["ctc"]); })
.attr('cy', function(d) { return yScale(d["ttc"]); })
.attr('r', function(d) { return rScale(d["effective"]); })
.attr('fill', function(d, i) { return effectiveScale(d["effective"])})
.on('mouseover', function(d) {
tooltip.style('visibility', 'visible');
return tooltip.text(d["technology"]);
})
.on("mousemove", function(){ return tooltip.style("top",
(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");})
// NEW SCOPE VALUE ON CLICK //
.on('click', function(d) {
scope.display = d;
console.log(d);
scope.$apply();
return d;
});
// append clip path
svg.append('clipPath')
.attr('id','chart-area')
.append('rect')
.attr('class', 'rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', w)
.attr('height', h);
// add text
svg.selectAll('text')
.data(input, function(d) {return d.id;})
.enter()
.append('text')
.attr('class', 'label')
.attr('clip-path','url(#chart-area)')
.attr('x', function(d) { return xScale(d["ctc"]); })
.attr('y', function(d) { return yScale(d["ttc"]) - rScale(d["effective"]) - 9; })
//.text(function(d) { return d["technology"]; });
// ********** ********** ************ //
// ********* ************ *********** //
// ******** ************** ********** //
// ******** ************** ********** //
// ******** UPDATE WINDOW *********** //
angular.element($window).bind('resize', function() {
updateWindow();
});
function updateWindow() {
var w = container.clientWidth - margin.left - margin.right;
var h = (container.clientHeight - margin.top - margin.bottom) * 0.9;
var xScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ctc"]; })])
.range([0, w])
.nice();
var yScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ttc"]; })])
.range([h, 0])
.nice();
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(5)
.tickFormat(formatAsMillions);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.ticks(8)
.tickFormat(formatAsYears);
// add X axis
d3.select('.xAxis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis);
// add Y axis
d3.select('.yAxis')
.call(yAxis);
/// adjust svg element width/height
d3.select('.scatter')
.attr('width', w + margin.left + margin.right)
.attr('height', h + margin.top + margin.bottom)
.select('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.attr('width', w + margin.left + margin.right)
.attr('height', h + margin.top + margin.bottom);
// adjust circle location
d3.select('.circles')
.attr('clip-path','url(#chart-area)')
.selectAll('circle')
.attr('cx', function(d) { return xScale(d["ctc"]); })
.attr('cy', function(d) { return yScale(d["ttc"]); })
.attr('r', function(d) { return rScale(d["effective"]); });
// adjust clip path
d3.select('.rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', w)
.attr('height', h);
}
};
}
};
});
Is there a common update pattern for reusing some of the same declarations here?

set the gridline at the back of gantt when redraw in d3

i know this maybe super duper simple to you guyz but this is the last piece of my project and i am done so i already want to finish this. here is my problem when i first load my gantt chart i draw first the axis and the gridlines before the chart it self so it appears as i desire that the gridlines is the background of my chart but when i redraw my chart there is the problem exist the gantt draw first before the gridlines so the output is the gridlines is covering the gantt chart which looks so bad. i will post my codes so you can check it. I can't pin point where i put first the gridlines. I think i need and extra eye here..........
d3.gantt = function() {
var FIT_TIME_DOMAIN_MODE = "fit";
var FIXED_TIME_DOMAIN_MODE = "fixed";
var margin = {
top : 50,
right : 40,
bottom : 20,
left : 120
};
var timeDomainStart = d3.time.day.offset(new Date(),-3);
var timeDomainEnd = d3.time.hour.offset(new Date(),+3);
var timeDomainMode = FIT_TIME_DOMAIN_MODE;// fixed or fit
var taskTypes = [];
var height = 500 - margin.top - margin.bottom-5;
var width = 1200 - margin.right - margin.left-5;
var tickFormat = "%H:%M";
var keyFunction = function(d) {
return d.startDate + d.taskName + d.endDate;
};
var rectTransform = function(d) {
return "translate(" + x(d.startDate) + "," + y(d.taskName) + ")";
};
var x = d3.time.scale().domain([ timeDomainStart, timeDomainEnd ]).range([ 0, width ]).clamp(true);
var y = d3.scale.ordinal().domain(taskTypes).rangeRoundBands([ 0, height - margin.top - margin.bottom ], .1);
var xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(d3.time.format(tickFormat)).tickSubdivide(true).tickSize(8).tickPadding(8);
var yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0);
var initTimeDomain = function(tasks) {
if (timeDomainMode === FIT_TIME_DOMAIN_MODE) {
if (tasks === undefined || tasks.length < 1) {
timeDomainStart = d3.time.day.offset(new Date(), -3);
timeDomainEnd = d3.time.hour.offset(new Date(), +3);
return;
}
tasks.sort(function(a, b) {
return a.endDate - b.endDate;
});
timeDomainEnd = tasks[tasks.length - 1].endDate;
tasks.sort(function(a, b) {
return a.startDate - b.startDate;
});
timeDomainStart = tasks[0].startDate;
}
};
var xAxisGrid = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height + margin.top + margin.bottom, 0, 0)
.tickFormat("");
var initAxis = function() {
x = d3.time.scale().domain([ timeDomainStart, timeDomainEnd ]).range([ 0, width ]).clamp(true);
y = d3.scale.ordinal().domain(taskTypes).rangeRoundBands([ 0, height - margin.top - margin.bottom ], .1);
xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(d3.time.format(tickFormat)).tickSubdivide(true)
.tickSize(8).tickPadding(8);
yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0);
xAxisGrid = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height + margin.top + margin.bottom, 0, 0)
.tickFormat("");
};
/////////////////////////////////
//Creating the chart
////////////////////////////
function gantt(tasks) {
initTimeDomain(tasks);
initAxis();
var dateFormat = d3.time.format("%Y-%m-%d");
var svg = d3.select("#gantt_chart")
.append("svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "gantt-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", (height + margin.top + margin.bottom) / tasks[tasks.length - 1].endDate)
.attr("transform", "translate(" + margin.left + ", " + margin.top + ")");
var div = d3.select("body").append("div")
.attr("class","tooltip")
.style("opacity",0);
//this is the x-axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")")
.transition()
.call(xAxis)
.selectAll("text")
.style("text-anchor","end")
.attr("dx", 35)
.attr("dy", 5);
//.attr("dx", "-.8em")
//.attr("dy", -10)
//.attr("transform", function(d){return "rotate(-90)"});
//this is the y-axis
svg.append("g").attr("class", "y axis").transition().call(yAxis);
// title of the gantt
svg.append("g")
.append("text")
.attr("x", 300)
.attr("y", -30)
.attr("class","title")
.style("font-size",20)
.text("MINI-PM SCHEDULER GANTT CHART");
// y title
svg.append("g")
.append("text")
.attr("transform", "rotate(-90)")
.attr("dx", -220)
.attr("dy", -100)
.style("font-size",16)
.text("HANDLER ID");
//this is the legend part
var colors = [["RUNNING", "#669900"],["WARNING", "#ffbb33"],["DOWN", "#FF0000"]];
var legend = svg.append("g")
.attr("class", "legend");
var circle = legend.selectAll('circle')
.data(colors)
.enter()
.append("circle")
.attr("cx", function (d, i) {
return (i * 80)+(width/2)-125;
})
.attr("cy", 405)
.attr("r", 5)
.style("fill", function (d) {
return d[1];
});
var legendText = legend.selectAll('text')
.data(colors)
.enter()
.append("text")
.attr("x", function (d, i) {
return (i * 80)+(width/2)-115;
})
.attr("y", 410)
.text(function (d) {
return d[0];
});
// Add X Axis grid lines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")")
.call(xAxisGrid);
//this is the actual gantt
svg.selectAll(".chart")
.data(tasks, keyFunction).enter()
.append("rect")
.attr("rx", 0)
.attr("ry", 0)
.attr("class", function(d){
if(d.status > 75)
{
return "bar-failed";
}
else if (d.status >= 55 && d.status <= 75){
return "bar-killed";
}
else{
return "bar-running";
}
})
.attr("y", 0)
.attr("transform", rectTransform)
.attr("height", function(d) { return y.rangeBand(); })
.attr("width", function(d) {
return (x(d.endDate) - x(d.startDate));
})
.on("mouseover", function(d){
div.transition()
.duration(200)
.style("opacity", .9);
div.html("HandlerID: " + d.taskName + "<br>" + "startDate: " + dateFormat(d.startDate) + "<br/>" + "endDate: " + dateFormat(d.endDate) + "<br/>" + "% Insertions: " + d3.round(d.status,2) + "%")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout",function(d){
div.transition()
.duration(500)
.style("opacity", 0);
});
/*
svg.append("g")
.append("text")
.attr("x", width / 2)
.attr("y", 380)
.style("font-size",12)
.text("PERIOD"); */
return gantt;
};
gantt.redraw = function(tasks) {
initTimeDomain(tasks);
initAxis();
var dateFormat = d3.time.format("%Y-%m-%d");
var div = d3.select("body").append("div")
.attr("class","tooltip")
.style("opacity",0);
var svg = d3.select("#gantt_chart");
var ganttChartGroup = svg.select(".gantt-chart");
var rect = ganttChartGroup.selectAll("rect").data(tasks, keyFunction);
rect.enter()
.insert("rect",":first-child")
.attr("rx", 0)
.attr("ry", 0)
.attr("class", function(d){
if(d.status > 75)
{
return "bar-failed";
}
else if (d.status >= 55 && d.status <= 75){
return "bar-killed";
}
else{
return "bar-running";
}
})
.transition()
.attr("y", 0)
.attr("transform", rectTransform)
.attr("height", function(d) { return y.rangeBand(); })
.attr("width", function(d) {
return (x(d.endDate) - x(d.startDate));
});
rect.transition()
.attr("transform", rectTransform)
.attr("height", function(d) { return y.rangeBand(); })
.attr("width", function(d) {
return (x(d.endDate) - x(d.startDate));
});
rect.exit().remove();
rect
.on("mouseover", function(d){
div.transition()
.duration(200)
.style("opacity", .9);
div.html("HandlerID: " + d.taskName + "<br>" + "startDate: " + dateFormat(d.startDate) + "<br/>" + "endDate: " + dateFormat(d.endDate) + "<br/>" + "% Insertions: " + d3.round(d.status,2) + "%")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout",function(d){
div.transition()
.duration(500)
.style("opacity", 0);
});
svg.select(".grid").transition().call(xAxisGrid);
svg.select(".x").transition().call(xAxis);
svg.select(".y").transition().call(yAxis);
return gantt;
}; // end of redraw
gantt.margin = function(value) {
if (!arguments.length)
return margin;
margin = value;
return gantt;
};
gantt.timeDomain = function(value) {
if (!arguments.length)
return [ timeDomainStart, timeDomainEnd ];
timeDomainStart = +value[0], timeDomainEnd = +value[1];
return gantt;
};
/**
* #param {string}
* vale The value can be "fit" - the domain fits the data or
* "fixed" - fixed domain.
*/
gantt.timeDomainMode = function(value) {
if (!arguments.length)
return timeDomainMode;
timeDomainMode = value;
return gantt;
};
gantt.taskTypes = function(value) {
if (!arguments.length)
return taskTypes;
taskTypes = value;
return gantt;
};
gantt.taskStatus = function(value) {
if (!arguments.length)
return taskStatus;
taskStatus = value;
return gantt;
};
gantt.width = function(value) {
if (!arguments.length)
return width;
width = +value;
return gantt;
};
gantt.height = function(value) {
if (!arguments.length)
return height;
height = +value;
return gantt;
};
gantt.tickFormat = function(value) {
if (!arguments.length)
return tickFormat;
tickFormat = value;
return gantt;
};
return gantt;
};

Categories

Resources