Sample for:
Y axis label word wrap/ Label centered on the scale / Horizontal bar with different color(data) / Date x axis / Grid lines
license: mit |
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta charset="utf-8" /> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<title></title> | |
<link href="stylesheets/charts.css" rel="stylesheet" /> | |
<style> | |
svg { | |
width: 100%; | |
height: 100%; | |
position: center; | |
} | |
.passBar { | |
fill: #a6f3a6; | |
} | |
.failBar { | |
fill: #f8cbcb; | |
} | |
.grid line { | |
stroke: white; | |
stroke-width: 2px; | |
} | |
.xAxis { | |
font-size: 15px; | |
shape-rendering: crispEdges; | |
} | |
.yAxis { | |
font-size: 15px; | |
shape-rendering: crispEdges; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var tempArray2 = [{date: "2017/3/11", ratio: 1}, {date: "2017/3/12", ratio: 0.5}, {date: "2017/3/13", ratio: 0.3}, {date: "2017/3/14", ratio: 0}, {date: "2017/3/15", ratio: 0.8}]; | |
var margin = {top: 20, right: 20, bottom: 40, left: 80}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
barHeight = 40; | |
labelWidth = 0; | |
tempArray2.sort(function (a, b) { | |
return new Date(a.date) - new Date(b.date); | |
}) | |
dateRange = Math.round((new Date(tempArray2[tempArray2.length - 1].date) - new Date(tempArray2[0].date))/1000/3600/24); | |
svg = d3.select('body') | |
.append("svg") | |
.attr("style", "width: 960px\; height: 500px\;"); | |
var x = d3.scaleUtc().range([0, width]) | |
.domain([toUTCDate(tempArray2[0].date), calculateDays(toUTCDate(tempArray2[tempArray2.length - 1].date), 1)]); | |
var y = d3.scaleBand() | |
.range([height, 0]) | |
.padding(0.1) | |
.domain(["Domain for testinginginging", "Another domain used for testing", "Horizontal bar"]); | |
passBar = svg.selectAll(".passBar") | |
.data(tempArray2) | |
.enter(); | |
passBar.append("rect") | |
.attr("class", "passBar") | |
.attr("height", barHeight) | |
.attr("width", function(d){ | |
return x(calculateDays(toUTCDate(d.date), d.ratio)) - x(toUTCDate(d.date)); | |
}) | |
.attr("y", y("Horizontal bar") + (y.bandwidth() - barHeight)/2) | |
.attr("transform", function(d){ | |
return "translate(" + (margin.left + x(toUTCDate(d.date))) + ", 0)"; | |
}); | |
failBar = svg.selectAll(".failBar") | |
.data(tempArray2) | |
.enter(); | |
failBar.append("rect") | |
.attr("class", "failBar") | |
.attr("height", barHeight) | |
.attr("width", function(d){ | |
return x(calculateDays(toUTCDate(d.date), 1 - d.ratio)) - x(toUTCDate(d.date)); | |
}) | |
.attr("y", y("Horizontal bar") + (y.bandwidth() - barHeight)/2) | |
.attr("transform", function(d){ | |
return "translate(" + (margin.left + x(toUTCDate(d.date)) + x(calculateDays(toUTCDate(d.date), d.ratio)) - x(toUTCDate(d.date))) + ", 0)"; | |
}); | |
//add grid lines | |
svg.append("g") | |
.attr("class", "grid") | |
.attr("transform", "translate(" + margin.left + "," + height + ")") | |
.call(make_x_gridlines(dateRange) | |
.tickSize(-height) | |
.tickFormat("") | |
) | |
// always draw axis at last | |
svg.append("g") | |
.attr("transform", "translate(" + margin.left + "," + height + ")") | |
.attr("class", "xAxis") | |
.call(d3.axisBottom(x).ticks(dateRange).tickFormat(d3.utcFormat("%m-%d"))) | |
.selectAll("text") | |
.style("text-anchor", "middle"); | |
svg.append("g") | |
.attr("transform", "translate(" + margin.left + ", 0)") | |
.attr("class", "yAxis") | |
.call(d3.axisLeft(y)) | |
.selectAll("text") | |
.attr("class", "cateName") | |
.style("text-anchor", "start") | |
.call(wrapText, margin.left - 13); | |
function calculateDays(date, number) { | |
date.setUTCHours(Math.round(number*24 - number*24%1)); | |
date.setUTCMinutes(Math.round(number*24%1*60)); | |
return date; | |
} | |
function make_x_gridlines(tickTime) { | |
return d3.axisBottom(x).ticks(tickTime); | |
} | |
function toUTCDate(input) { | |
var tempDate = new Date(input); | |
return new Date(Date.UTC(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())); | |
} | |
function wrapText(text, width) { | |
text.each(function() { | |
var text = d3.select(this), | |
textContent = text.text(), | |
tempWord = addBreakSpace(textContent).split(/\s+/), | |
x = text.attr('x'), | |
y = text.attr('y'), | |
dy = parseFloat(text.attr('dy') || 0), | |
tspan = text.text(null).append('tspan').attr('x', x).attr('y', y).attr('dy', dy + 'em'); | |
for (var i = 0; i < tempWord.length; i++) { | |
tempWord[i] = calHyphen(tempWord[i]); | |
} | |
textContent = tempWord.join(" "); | |
var words = textContent.split(/\s+/).reverse(), | |
word, | |
line = [], | |
lineNumber = 0, | |
lineHeight = 1.1, // ems | |
spanContent, | |
breakChars = ['/', '&', '-']; | |
while (word = words.pop()) { | |
line.push(word); | |
tspan.text(line.join(' ')); | |
if (tspan.node().getComputedTextLength() > width) { | |
line.pop(); | |
spanContent = line.join(' '); | |
breakChars.forEach(function(char) { | |
// Remove spaces trailing breakChars that were added above | |
spanContent = spanContent.replace(char + ' ', char); | |
}); | |
tspan.text(spanContent); | |
line = [word]; | |
tspan = text.append('tspan').attr('x', x).attr('y', y).attr('dy', ++lineNumber * lineHeight + dy + 'em').text(word); | |
} | |
} | |
var emToPxRatio = parseInt(window.getComputedStyle(text._groups[0][0]).fontSize.slice(0,-2)); | |
text.attr("transform", "translate(-" + (margin.left - 13) + ", -" + lineNumber/2 * lineHeight * emToPxRatio + ")"); | |
function calHyphen(word) { | |
tspan.text(word); | |
if (tspan.node().getComputedTextLength() > width) { | |
var chars = word.split(''); | |
var asword = ""; | |
for (var i = 0; i < chars.length; i++) { | |
asword += chars[i]; | |
tspan.text(asword); | |
if (tspan.node().getComputedTextLength() > width) { | |
if (chars[i - 1] !== "-") { | |
word = word.slice(0, i - 1) + "- " + calHyphen(word.slice(i - 1)); | |
} | |
i = chars.length; | |
} | |
} | |
} | |
return word; | |
} | |
}); | |
function addBreakSpace(inputString) { | |
var breakChars = ['/', '&', '-'] | |
breakChars.forEach(function(char) { | |
// Add a space after each break char for the function to use to determine line breaks | |
inputString = inputString.replace(char, char + ' '); | |
}); | |
return inputString; | |
} | |
} | |
</script> | |
</body> | |
</html> |
how to fix: Uncaught TypeError: Cannot read property '0' of undefined
in this line: var emToPxRatio = parseInt(window.getComputedStyle(text._groups[0][0]).fontSize.slice(0,-2));
or how to understand this row?