|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
.area { |
|
fill: steelblue; |
|
clip-path: url(#clip); |
|
} |
|
|
|
.line { |
|
fill: none; |
|
stroke: red; |
|
stroke-width: 2px; |
|
clip-path: url(#clip) |
|
} |
|
.line_casual { |
|
fill: none; |
|
stroke: darkblue; |
|
stroke-width: 2px; |
|
clip-path: url(#clip) |
|
} |
|
.line_registered { |
|
fill: none; |
|
stroke: green; |
|
stroke-width: 2px; |
|
clip-path: url(#clip) |
|
} |
|
.line_total { |
|
fill: none; |
|
stroke: black; |
|
stroke-width: 1px; |
|
clip-path: url(#clip) |
|
} |
|
.line_temp { |
|
fill: none; |
|
stroke: orange; |
|
stroke-width: 1px; |
|
clip-path: url(#clip) |
|
} |
|
.tick line { |
|
stroke: #b5b5b5; |
|
stroke-width: 1; |
|
} |
|
.tick text { |
|
fill: #8E8883; |
|
font-size: 8pt; |
|
font-family: sans-serif; |
|
} |
|
.axis-label { |
|
fill: #635F5D; |
|
font-size: 11pt; |
|
font-family: sans-serif; |
|
} |
|
.zoom { |
|
cursor: move; |
|
fill: none; |
|
pointer-events: all; |
|
} |
|
|
|
</style> |
|
<svg width="960" height="500"></svg> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
|
|
const xValue = d => d.dteday; |
|
const xLabel = 'Date'; |
|
const yValue1 = d => d.registered; |
|
const yValue2 = d => d.casual; |
|
const yValue3 = d => d.cnt; |
|
const yValue4 = d => d.temp; |
|
const yLabel = 'Users'; |
|
const yLabelRight = 'Temperature'; |
|
|
|
var svg = d3.select("svg"), |
|
margin = {top: 20, right: 80, bottom: 110, left: 80}, |
|
margin2 = {top: 430, right: 80, bottom: 30, left: 80}, |
|
width = +svg.attr("width") - margin.left - margin.right, |
|
height = +svg.attr("height") - margin.top - margin.bottom, |
|
height2 = +svg.attr("height") - margin2.top - margin2.bottom; |
|
|
|
var parseDate = d3.timeParse("%b %Y"); |
|
|
|
var x = d3.scaleTime().range([0, width]), |
|
x2 = d3.scaleTime().range([0, width]), |
|
y = d3.scaleLinear().range([height, 0]), |
|
yRight = d3.scaleLinear().range([height, 0]), |
|
y2 = d3.scaleLinear().range([height2, 0]); |
|
|
|
var xAxis = d3.axisBottom(x), |
|
xAxis2 = d3.axisBottom(x2), |
|
yAxis = d3.axisLeft(y), |
|
yAxisRight = d3.axisRight(yRight); |
|
|
|
var brush = d3.brushX() |
|
.extent([[0, 0], [width, height2]]) |
|
.on("brush end", brushed); |
|
|
|
var zoom = d3.zoom() |
|
.scaleExtent([1, Infinity]) |
|
.translateExtent([[0, 0], [width, height]]) |
|
.extent([[0, 0], [width, height]]) |
|
.on("zoom", zoomed); |
|
|
|
var line = d3.line() |
|
.curve(d3.curveCatmullRom) |
|
.x(function(d) { return x(d.dteday); }) |
|
.y(function(d) { return y(d.cnt); }); |
|
|
|
var lineCasual = d3.line() |
|
.curve(d3.curveCatmullRom) |
|
.x(function(d) { return x(d.dteday); }) |
|
.y(function(d) { return y(d.casual); }); |
|
|
|
var lineTemp = d3.line() |
|
.curve(d3.curveCatmullRom) |
|
.x(function(d) { return x(d.dteday); }) |
|
.y(function(d) { return yRight(d.temp); }); |
|
|
|
var lineRegistered = d3.line() |
|
.curve(d3.curveCatmullRom) |
|
.x(function(d) { return x(d.dteday); }) |
|
.y(function(d) { return y(d.registered); }); |
|
|
|
var lineTotal = d3.line() |
|
.curve(d3.curveCatmullRom) |
|
.x(function(d) { return x2(d.dteday); }) |
|
.y(function(d) { return y2(d.cnt); }); |
|
|
|
|
|
svg.append("defs").append("clipPath") |
|
.attr("id", "clip") |
|
.append("rect") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var focus = svg.append("g") |
|
.attr("class", "focus") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
var context = svg.append("g") |
|
.attr("class", "context") |
|
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); |
|
|
|
|
|
const row = d => { |
|
d.dteday = new Date(d.dteday); |
|
d.season = +d.season; |
|
d.yr = +d.yr; |
|
d.mnth = +d.mnth; |
|
d.holiday = +d.holiday; |
|
d.weekday = +d.weekday; |
|
d.workingday = +d.workingday; |
|
d.weathersit = +d.weathersit; |
|
d.temp = +d.temp; |
|
d.atemp = +d.atemp; |
|
d.hum = +d.hum; |
|
d.windspeed = +d.windspeed; |
|
d.casual = +d.casual; |
|
d.registered = +d.registered; |
|
d.cnt = +d.cnt; |
|
return d; |
|
}; |
|
|
|
d3.csv("day.csv", row, function(error, data) { |
|
if (error) throw error; |
|
|
|
x.domain(d3.extent(data, function(d) { return d.dteday; })); |
|
y.domain([0, d3.max(data, function(d) { return d.cnt; })]); |
|
x2.domain(x.domain()); |
|
y2.domain(y.domain()); |
|
|
|
focus.append("path") |
|
.datum(data) |
|
.attr("class", "line line_casual") |
|
.attr("d", lineCasual); |
|
|
|
focus.append("path") |
|
.datum(data) |
|
.attr("class", "line line_registered") |
|
.attr("d", lineRegistered); |
|
|
|
focus.append("path") |
|
.datum(data) |
|
.attr("class", "line line_temp") |
|
.attr("d", lineTemp); |
|
|
|
|
|
focus.append("g") |
|
.attr("class", "axis axis--x") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(xAxis); |
|
|
|
|
|
|
|
yAxisG = focus.append("g") |
|
.attr("class", "axis axis--y") |
|
.call(yAxis); |
|
|
|
yAxisG.append('text') |
|
.attr('class', 'axis-label') |
|
.attr('x', -height / 2) |
|
.attr('y', -50) |
|
.attr('transform', `rotate(-90)`) |
|
.style('text-anchor', 'middle') |
|
.text(yLabel); |
|
|
|
yAxisRightG = focus.append("g") |
|
.attr("class", "axis axis--y") |
|
.attr("transform", "translate(" + width + ",0)") |
|
.call(yAxisRight); |
|
|
|
yAxisRightG.append('text') |
|
.attr('class', 'axis-label') |
|
.attr('x', height/2) |
|
.attr('y', -40) |
|
.attr('transform', `rotate(90)`) |
|
.style('text-anchor', 'middle') |
|
.text(yLabelRight); |
|
|
|
context.append("path") |
|
.datum(data) |
|
.attr("class", "line_total") |
|
.attr("d", lineTotal); |
|
|
|
context.append("g") |
|
.attr("class", "axis axis--x") |
|
.attr("transform", "translate(0," + height2 + ")") |
|
.call(xAxis2); |
|
|
|
context.append("g") |
|
.attr("class", "brush") |
|
.call(brush) |
|
.call(brush.move, x.range()); |
|
|
|
svg.append("rect") |
|
.attr("class", "zoom") |
|
.attr("width", width) |
|
.attr("height", height) |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") |
|
.call(zoom); |
|
}); |
|
|
|
function brushed() { |
|
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom |
|
var s = d3.event.selection || x2.range(); |
|
x.domain(s.map(x2.invert, x2)); |
|
focus.selectAll(".line_casual").attr("d", lineCasual); |
|
focus.select(".line_registered").attr("d", lineRegistered); |
|
focus.select(".line_temp").attr("d", lineTemp); |
|
focus.select(".axis--x").call(xAxis); |
|
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity |
|
.scale(width / (s[1] - s[0])) |
|
.translate(-s[0], 0)); |
|
} |
|
|
|
function zoomed() { |
|
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush |
|
var t = d3.event.transform; |
|
x.domain(t.rescaleX(x2).domain()); |
|
focus.select(".line_casual").attr("d", lineCasual); |
|
focus.select(".line_registered").attr("d", lineRegistered); |
|
focus.select(".line_temp").attr("d", lineTemp); |
|
focus.select(".axis--x").call(xAxis); |
|
context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); |
|
} |
|
|
|
|
|
|
|
</script> |