xxxxxxxxxx
<html lang="en">
<head>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600|Open+Sans+Condensed:300' rel='stylesheet' type='text/css'>
<title></title>
<meta name="description" content="">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="../lib/globalStyle.css" />
<style type="text/css">
.background0 {
background: #dadada;
}
.background1 {
background: #7BCAE2;
}
#triangleEnd {
fill: black;
}
#triangleStart {
fill: black;
}
.x.axis path {
display: none;
}
/* Full width */
.btn-form-fullwidth {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
font-family: 'Open Sans',Arial,sans-serif;
-webkit-font-smoothing: antialiased;
font-weight: 600;
font-size: 16px;
margin-bottom: 32px;
width: 100%;
}
.form-group-fullwidth {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
cursor: pointer;
height: 40px;
box-sizing: border-box;
text-align: center;
width: 100%;
}
.form-group-fullwidth:last-child {
border-right: solid 1px #A6A8AB;
}
.label-primary-fullwidth {
padding: 8px 16px;
cursor: pointer;
color: #333;
background: #F9F9F9;
border-top: solid 1px #A6A8AB;
border-left: solid 1px #A6A8AB;
border-bottom: solid 1px #A6A8AB;
width: 100%;
}
.label-primary-fullwidth:hover {
background: #003C57;
color: #fff;
border-color: #003C57;
width: 100%;
}
.radio-primary-fullwidth:checked + .label-primary-fullwidth {
background: #206095;
color: #fff;
border-color: #206095;
cursor: default;
width: 100%;
}
.radio-primary-fullwidth {
display: none;
}
</style>
</head>
<body>
<div id="buttons">
<form class="btn-form btn-form-fullwidth" role="radiogroup">
<div class="form-group form-group-fullwidth" role="radio" tabindex="0">
<input id="button-1" class="radio-primary radio-primary-fullwidth" type="radio" name="button" value="1" aria-checked="true" checked>
<label class="label-primary label-primary-fullwidth" for="button-1">Females</label>
</div>
<div class="form-group form-group-fullwidth" role="radio" tabindex="2">
<input id="button-2" class="radio-primary radio-primary-fullwidth" type="radio" name="button" value="2" aria-checked="false">
<label class="label-primary label-primary-fullwidth" for="button-2">Males</label>
</div>
<div class="form-group form-group-fullwidth" role="radio" tabindex="3">
<input id="button-3" class="radio-primary radio-primary-fullwidth" type="radio" name="button" value="3" aria-checked="false">
<label class="label-primary label-primary-fullwidth" for="button-3">Both</label>
</div>
</form>
</div>
<div id="graphic">
<img src="fallback.png" alt="[Chart]" />
</div>
<div id="keypoints">
<p></p>
</div>
<div class="footer">
</div>
<script src="https://cdn.ons.gov.uk/vendor/d3/4.2.7/d3.min.js" type="text/javascript"></script>
<script src="modernizr.svg.min.js" type="text/javascript"></script>
<script src="pym.js" type="text/javascript"></script>
<script>
var graphic = d3.select('#graphic');
var keypoints = d3.select('#keypoints');
var footer = d3.select(".footer");
var pymChild = null;
function drawGraphic() {
var graphic_data = data1;
var prev_data = data3;
var threshold_md = 788;
var threshold_sm = dvc.optional.mobileBreakpoint; // 510
//set variables for chart dimensions dependent on width of #graphic
if (parseInt(graphic.style("width")) < threshold_sm) {
var ball = 4;
var margin = {
top: dvc.optional.margin_sm[0],
right: dvc.optional.margin_sm[1],
bottom: dvc.optional.margin_sm[2],
left: dvc.optional.margin_sm[3]
};
var chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
var height = Math.ceil((chart_width * dvc.optional.aspectRatio_sm[1]) / dvc.optional.aspectRatio_sm[0]) - margin.top - margin.bottom;
} else if (parseInt(graphic.style("width")) < threshold_md) {
var ball = 4;
var margin = {
top: dvc.optional.margin_md[0],
right: dvc.optional.margin_md[1],
bottom: dvc.optional.margin_md[2],
left: dvc.optional.margin_md[3]
};
var chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
var height = Math.ceil((chart_width * dvc.optional.aspectRatio_md[1]) / dvc.optional.aspectRatio_md[0]) - margin.top - margin.bottom;
} else {
var ball = 5;
var margin = {
top: dvc.optional.margin_lg[0],
right: dvc.optional.margin_lg[1],
bottom: dvc.optional.margin_lg[2],
left: dvc.optional.margin_lg[3]
}
var chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
var height = Math.ceil((chart_width * dvc.optional.aspectRatio_lg[1]) / dvc.optional.aspectRatio_lg[0]) - margin.top - margin.bottom;
}
// clear out existing graphics
graphic.selectAll("*").remove();
keypoints.selectAll("*").remove();
footer.selectAll("*").remove();
var x = d3.scaleLinear()
.range([0, chart_width]);
var y = d3.scalePoint()
.range([0, height], .3);
//.rangeRoundBands([0, height]); // .1
y.domain(graphic_data.map(function(d) {
return d.name;
}));
var yAxis = d3.axisLeft(y)
var xAxis = d3.axisBottom(x);
//specify number or ticks on x axis
if (parseInt(graphic.style("width")) <= threshold_sm) {
xAxis.ticks(dvc.optional.x_num_ticks_sm_md_lg[0])
} else if (parseInt(graphic.style("width")) <= threshold_md) {
xAxis.ticks(dvc.optional.x_num_ticks_sm_md_lg[1])
} else {
xAxis.ticks(dvc.optional.x_num_ticks_sm_md_lg[2])
}
var lines = graphic_data.map(function(d, i) { //console.log(d + " " +i);
return {
// lines.x: csv.column_headings
'name': d.name, // might not need since we mapped it in y.domain earlier
'mymin': +d.imin, // + changes string to numeric.
'mymax': +d.imax,
'mymedian': +d.median,
'prev_mymin':0,
'prev_mymax':0
};
});
var memax = d3.max(lines, function(d) {
return d.mymax;
});
//console.log("memax: "+memax);
var memin = d3.min(lines, function(d) {
return d.mymin;
});
//x domain calculations : zero to intelligent max choice, or intelligent min and max choice, or interval chosen manually
if (dvc.essential.xAxisScale == "auto_zero_max") {
var xDomain = [0, Math.ceil(d3.max(lines, function(d) {
return d.mymax;
}))];
} else if (dvc.essential.xAxisScale == "auto_min_max") {
var xDomain = [Math.floor(d3.min(lines, function(d) {
return d.mymin;
})),
Math.ceil(d3.max(lines, function(d) {
return d.mymax;
}))
];
/*var yDomain = [ Math.floor(d3.min(dvc.yData)/dvc.essential.yAxisScaleDivisor)*dvc.essential.yAxisScaleDivisor , Math.ceil(d3.max(dvc.yData)/dvc.essential.yAxisScaleDivisor)*dvc.essential.yAxisScaleDivisor ];*/
} else {
var xDomain = dvc.essential.xAxisScale;
var yDomain = dvc.essential.yAxisScale;
}
x.domain(xDomain);
// sort these hardwired numbers maybe through the dimensions above
var legend = d3.select('#graphic').append('svg')
.attr("width", chart_width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom + 30)
.append("g")
.attr("id", "legend")
//create svg for chart
var svg = d3.select('svg')
.attr("id", "chart")
.style("background-color", "#fff")
.attr("width", chart_width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom + 80)
.append("g")
.attr("transform", "translate(" + margin.left + "," + (margin.top + 40) + ")")
svg.append("rect")
.attr("class", "svgRect")
.style("fill", "#fff")
.attr("width", chart_width)
.attr("height", height);
svg.append('g')
.attr('class', 'x axis')
.attr("transform", "translate(0, " + height + ")")
.call(xAxis.tickSize(-height, 0))
.selectAll("line")
.style("stroke", "#E5E6E7");
svg.select(".x.axis")
.append("text")
.attr('class', 'x-label')
.attr("y", 35)
.attr("x", chart_width)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(dvc.essential.xAxisLabel[0]);
d3.select(".y.axis")
.selectAll(".ticks")
.attr("class", function(d, i) {
return "tick" + i
})
//move the x number down a bit
d3.selectAll(".tick").select("text").attr("transform", "translate(0,15)")
//create y axis, if x axis doesn't start at 0 drop x axis accordingly
svg.append('g')
.attr('class', 'y axis')
.attr('transform', function(d) {
if (xDomain[0] != 0) {
return 'translate(' + (-30) + ',0)'
} else {
return 'translate(' + 0 + ', 0)'
}
})
d3.select('.y')
.selectAll('.tick')
.attr('class', function(d, i) {
return 'tick' + d;
})
d3.select('.tick5')
.style('font-weight', 'bold')
d3.select(".y.axis").selectAll("line").remove();
svg.append("text")
.attr('class', 'unit')
.attr('transform', "translate(" + -margin.left + "," + eval(-margin.top) + ")") // + (lineNo+1)*20 or -10
.attr("font-size", "12px")
.attr("fill", "#666")
.text(dvc.essential.yAxisLabel);
var paths = svg.append("defs")
svg.append("defs").append("marker")
.attr("id", "triangleStart")
.attr("viewBox", "0 0 20 20")
.attr("refX", 0)
.attr("refY", 5)
.attr("markerUnits", "strokeWidth")
.attr("markerWidth", 20)
.attr("markerHeight", 20)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 5 L 10 10 L 10 0 z")
.style("fill", '#414042');
svg.append("defs").append("marker")
.attr("id", "triangleEnd")
.attr("viewBox", "0 0 20 20")
.attr("refX", 10)
.attr("refY", 5)
.attr("markerUnits", "strokeWidth")
.attr("markerWidth", 20)
.attr("markerHeight", 20)
.attr("orient", "auto")
.append("path")
.attr("d", "M 10 5 L 0 0 L 0 10 z")
.style("fill", "#414042");
lines = graphic_data.map(function(d, i) { //console.log(d + " " +i);
return {
// lines.x: csv.column_headings
'name': d.name, // might not need since we mapped it in y.domain earlier
'mymin': +d.imin, // + changes string to numeric.
'mymax': +d.imax,
'mymedian': +d.median,
'prev_name': prev_data[i].name,
'prev_mymin':+prev_data[i].imin,
'prev_mymax':+prev_data[i].imax
};
});
connect_line = svg.selectAll('.line')
.data(lines) // ["value"]
connect_line
.enter()
.append('line')
.attr('class', function(d, i) {
return 'line tiefighter '+d.name.replace(/\s+/g, '')
})
.style("stroke", "#dadada")
.attr('y1', function(d, i) {
return y(d.prev_name);
})
.attr('y2', function(d) {
return y(d.prev_name);
})
.attr('x1', function(d, i) {
return x(d.prev_mymin);
}) //d.mymin
.attr('x2', function(d) {
return x(d.prev_mymax);
})
d3.select('.England')
.style('stroke', dvc.essential.stroke_average_line)
// svg.selectAll('.tiefighter')//.append("svg")
var dots_min = svg.selectAll('.circlemin')
.data(lines)
var dots_max = svg.selectAll('.circlemax')
.data(lines)
dots_min
.enter()
.append('circle')
.attr('class', function(d, i) {
return 'circlemin circlemin' + i +' circlemin'+d.name.replace(/\s+/g, '')
})
.attr("fill", dvc.essential.colour_palette[0])
// .attr('cy', height)
// .attr('cx', 0)
.attr('cx', function(d, i) {
return x(d.mymin);
})
.attr('cy', function(d, i) {
return y(d.name);
})
.attr('r', ball)
d3.select('.circleminEngland')
.style('fill', dvc.essential.colour_average)
if (dvc.essential.minmaxonly == "true") {
dots_max
.enter()
.append('circle')
.attr('class', function(d, i) {
return 'circlemax circlemax' + i +' circlemax'+d.name.replace(/\s+/g, '')
})
.attr("fill", dvc.essential.colour_palette[1])
.attr('cx', function(d, i) {
return x(d.mymax);
})
.attr('cy', function(d, i) {
return y(d.name);
})
.attr('r', ball)
} else {
svg.append('g').selectAll('.circle')
.data(lines)
.enter()
.append('circle')
.attr('class', "circlemax")
.attr("fill", dvc.essential.colour_palette[0])
.attr('cx', function(d, i) {
return x(d.mymax);
})
.attr('cy', function(d, i) {
return y(d.name);
})
.attr('r', ball);
}
d3.selectAll("input[name='button']")
.on('click', function() {
d3.select('.x-label')
.text(dvc.essential.xAxisLabel[+this.value-1]);
d3.selectAll('.annotext')
.style('display','none')
d3.selectAll('.annorect')
.style('display','none')
d3.select('.annotext'+[+this.value-1])
.style('display', 'block')
d3.select('.annorect'+[+this.value-1])
.style('display', 'block')
// var prev_data = graphic_data;
if(+this.value === 1) {
graphic_data = data1
} else if(+this.value === 2) {
graphic_data = data2
} else if (+this.value === 3){
graphic_data = data3
}
tieFight(graphic_data)//, prev_data);
})
tieFight(graphic_data)
function tieFight(graphic_data){//, prev_data) {
var t = d3.transition()
.duration(1000)
.ease(d3.easeQuadOut)
// console.log(graphic_data)
lines = graphic_data.map(function(d, i) { //console.log(d + " " +i);
return {
'name': d.name, // might not need since we mapped it in y.domain earlier
'mymin': +d.imin, // + changes string to numeric.
'mymax': +d.imax,
};
});
newlines={}
lines.map(function(d,i){
newlines[d.name]={"min":+d.mymin,"max":+d.mymax}
})
lines.sort(function(a,b) {
return d3.descending(a.mymax, b.mymax)
})
var memax = d3.max(lines, function(d) {
return d.mymax;
});
//console.log("memax: "+memax);
var memin = d3.min(lines, function(d) {
return d.mymin;
});
y.domain(lines.map(function(d) {
return d.name;
}));
svg.select('.y.axis')
.transition(t)
.call(yAxis);
d3.select('.y')
.selectAll('.tick')
.attr('class', function(d, i) {console.log(d)
return 'tick tick-' + d.replace(/\s+/g, '')
})
d3.select('.tick-England')
.style('font-weight', 'bold')
for(i=0;i<lines.length;i++){
d3.select("."+lines[i].name.replace(/\s+/g, ''))
.transition(t)
.attr('y1', function(d) {
return y(lines[i].name);
})
.attr('y2', function(d) {
return y(lines[i].name);
})
.attr('x1', function(d) { //console.log("x1 "+i+" "+x(d.mymin));
return x(lines[i].mymin);
}) //d.mymin
.attr('x2', function(d) {
return x(lines[i].mymax)
})
d3.select(".circlemin"+lines[i].name.replace(/\s+/g, ''))
.transition(t)
.attr('cx', function(d) {
return x(lines[i].mymin);
})
.attr('cy', function(d) {
return y(lines[i].name);
})
.attr('r', ball)
d3.select(".circlemax"+lines[i].name.replace(/\s+/g, ''))
.transition(t)
.attr('cx', function(d) {
return x(lines[i].mymax);
})
.attr('cy', function(d) {
return y(lines[i].name);
})
.attr('r', ball)
}
y.domain(lines.map(function(d) {
return d.name;
}));
svg.selectAll('.tiefighter')
svg.select('.x.axis')
.transition(t)
.call(xAxis);
//if not only drawing two dots, draw the median dot.
if (dvc.essential.minmaxonly == "true") {} else {
columnH = d3.keys(graphic_data[0]).filter(function(key) {
return key;
});
if (columnH[3] == "median") {
svg.append('g').selectAll('.med')
.data(lines)
.enter()
.append('circle')
.attr("class", "circlemed")
.attr("fill", dvc.essential.colour_palette[1])
.attr('cx', function(d, i) {
return x(d.mymedian);
})
.attr('cy', function(d, i) {
return y(d.name);
})
.attr('r', ball * 1.5);
}
} //end of tiefighter
}
//create centre line if required
if (dvc.optional.centre_line == true) {
svg.append("line")
.attr("id", "centreline")
.attr('y1', 0)
.attr('y2', height)
.attr('x1', x(dvc.optional.centre_line_value))
.attr('x2', x(dvc.optional.centre_line_value));
} else {}
writeAnnotation();
function writeAnnotation() {
if (parseInt(graphic.style("width")) < threshold_sm) {
dvc.essential.annotationBullet.forEach(function(d, i) {
d3.select("#keypoints").append("svg")
.attr("width", "20px")
.attr("height", "20px")
.attr("class", "circles")
.append("circle")
.attr("class", "annocirc" + (i))
.attr("r", "2")
.attr('cy', "12px")
.attr("cx", "10px");
d3.select("#keypoints").append("p").text(dvc.essential.annotationBullet[i]);
}) // end foreach
} else {
dvc.essential.annotationChart.forEach(function(d, i) {
// draw annotation text based on content of var annotationArray ...
svg.append("text")
.text(dvc.essential.annotationChart[i])
.attr("class", "annotext annotext" + i)
.attr("text-anchor", dvc.essential.annotationAlign[i])
.attr('y', y(dvc.essential.annotationXY[i][1]))
.attr('x', x(dvc.essential.annotationXY[i][0]));
d3.selectAll(".annotext" + (i))
.each(insertLinebreaks)
.each(createBackRect);
function insertLinebreaks() {
var str = this;
var el1 = dvc.essential.annotationChart[i];
var el = el1.data;
var words = el1.split(' ');
d3.select(this /*str*/ ).text('');
for (var j = 0; j < words.length; j++) {
var tspan = d3.select(this).append('tspan').text(words[j]);
if (j > 0)
tspan.attr('x', x(dvc.essential.annotationXY[i][0])).attr('dy', '22');
}
d3.selectAll('.annotext')
.style('display','none')
d3.selectAll('.annorect')
.style('display','none')
d3.select('.annotext0')
.style('display', 'block')
d3.select('.annorect0')
.style('display', 'block')
};
function createBackRect() {
var BBox = this.getBBox()
svg.insert("rect", ".annotext" + (i))
.attr('class', 'annorect annorect'+i)
.attr("width", BBox.width)
.attr("height", BBox.height)
.attr("x", BBox.x)
.attr("y", BBox.y)
.attr("fill", "white")
.attr("opacity", 0.4);
}; // end function createBackRect()
}); // end foreach
} // end else ...
// If you have labels rather than years then you can split the lines using a double space (in the CSV file).
function insertLinebreaksLabels() {
var str = this.textContent;
var words = str.split(' ');
d3.select(this /*str*/ ).text('');
for (var j = 0; j < words.length; j++) {
var tspan = d3.select(this).append('tspan').text(words[j]);
if (j > 0)
tspan
.attr('x', -10)
.attr('dy', '1em');
}
};
d3.selectAll(".y text").each(insertLinebreaksLabels)
} // end function writeAnnotation()
createLegend();
function createLegend() {
var prevX = 0;
var prevY = 0;
lineNo = 0;
var lineNoOld = 0;
dvc.essential.legendLabels.forEach(function(d, i) {
// draw legend text based on content of var legendLabels ...
var_group = d3.select("#legend").append("g")
if (dvc.essential.legendStyle != "circle") {
var_group.append("rect")
.attr("class", "rect" + i)
.attr("fill", dvc.essential.colour_palette[i])
.attr("x", 0)
.attr("y", 0)
.attr("width", function(d) {
if (dvc.essential.legendStyle == "rect") {
return 15;
} else {
return 20;
}
})
.attr("height", function(d) {
if (dvc.essential.legendStyle == "rect") {
return 15;
} else {
return 3;
}
})
} else {
var_group.append("circle")
.attr("class", "legendcirclesmove circ" + i)
.attr("fill", dvc.essential.colour_palette[i])
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 5);
}
var_group.append("text")
.text(dvc.essential.legendLabels[i])
.attr("class", "legend" + i)
.attr("text-anchor", "start")
.style("font-size", "12px")
.style("fill", "#666")
.attr('y', 15)
.attr('x', 0);
d3.selectAll(".legend" + (i))
.each(calcPosition);
function calcPosition() {
var BBox = this.getBBox()
//prevY =BBox.width
d3.select(".legend" + (i))
.attr("y", function(d) {
if ((prevX + BBox.width + 50) > parseInt(graphic.style("width"))) {
lineNoOld = lineNo;
lineNo = lineNo + 1;
prevX = 0;
}
return eval((lineNo * 20) + 20);
})
.attr("x", function(d) {
return prevX + 25;
})
if (dvc.essential.legendStyle != "rect") {
d3.select(".circ" + (i))
.attr("cy", function(d) {
if ((prevX + BBox.width + 50) > parseInt(graphic.style("width"))) {
lineNoOld = lineNo;
lineNo = lineNo + 1;
prevX = 0;
}
if (dvc.essential.legendStyle == "circle") {
return eval((lineNo * 20) + 5);
} else {
return eval((lineNo * 20) + 12);
}
})
.attr("cx", function(d) {
return prevX;
})
prevX = prevX + BBox.width + 50
d3.selectAll(".legendcirclesmove").attr("transform", "translate(10,10)");
d3.selectAll(".circ1").attr("transform", "translate(10,10)");
} else {
d3.select(".rect" + (i))
.attr("y", function(d) {
if ((prevX + BBox.width + 50) > parseInt(graphic.style("width"))) {
lineNoOld = lineNo;
lineNo = lineNo + 1;
prevX = 0;
}
if (dvc.essential.legendStyle == "rect") {
return eval((lineNo * 20) + 5);
} else {
return eval((lineNo * 20) + 12);
}
})
.attr("x", function(d) {
return prevX;
})
prevX = prevX + BBox.width + 50
}
}; // end function calcPosition()
}); // end foreach
} // end function createLegend()
// css fix
d3.selectAll("path").attr("fill", "none");
d3.selectAll("text").attr("font-family", "'Open Sans', sans-serif");
d3.selectAll(".x text").attr("font-size", "12px").attr("fill", "#666");
d3.selectAll(".y text").attr("font-size", "12px").attr("fill", "#666");
d3.selectAll(".y line")
.attr("stroke", "#CCC")
.attr("stroke-width", "1px")
.style("shape-rendering", "crispEdges");
//create link to source
d3.select(".footer").append("p")
.text("Source: ")
.append("a")
.attr("href", dvc.essential.sourceURL)
.attr("target", "_blank")
.html(dvc.essential.sourceText);
//use pym to calculate chart dimensions
if (pymChild) {
pymChild.sendHeight();
}
}
//check whether browser can cope with svg
if (Modernizr.svg) {
//load config
d3.json("config.json", function(error, config) {
dvc = config;
d3.queue()
.defer(d3.csv, dvc.essential.graphic_data_url[0])
.defer(d3.csv, dvc.essential.graphic_data_url[1])
.defer(d3.csv, dvc.essential.graphic_data_url[2])
.await(function(error, data_csv1, data_csv2, data_csv3) {
//load chart data
data1 = data_csv1;
data2 = data_csv2;
data3 = data_csv3;
// console.log(data)
//use pym to create iframed chart dependent on specified variables
pymChild = new pym.Child({
renderCallback: drawGraphic
});
});
function init() {
//load chart data
graphic_data = file1;
//use pym to create iframed chart dependent on specified variables
pymChild = new pym.Child({
renderCallback: drawGraphic
});
}
})
} else {
//use pym to create iframe containing fallback image (which is set as default)
pymChild = new pym.Child();
if (pymChild) {
pymChild.sendHeight();
}
}
</script>
</body>
</html>
https://cdn.ons.gov.uk/vendor/d3/4.2.7/d3.min.js