I am working on a d3js horizontal chart - the designers are specific in having the labels this way.
I've built the following - but would like to model it more on older code that had animation properties.
//current chart
https://codepen.io/anon/pen/ZmJzXZ
//static vertical chart http://jsfiddle.net/pg886/201/
//animated vertical chart http://jsfiddle.net/Qh9X5/12073/
-- d3js code
var data = [{
"name": "Apples",
"value": 20,
},
{
"name": "Bananas",
"value": 12,
},
{
"name": "Grapes",
"value": 19,
},
{
"name": "Lemons",
"value": 5,
},
{
"name": "Limes",
"value": 16,
},
{
"name": "Oranges",
"value": 26,
},
{
"name": "Pears",
"value": 30,
}];
//sort bars based on value
data = data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
})
//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 60
};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#graphic").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 + ")");
var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);
var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .3)
.domain(data.map(function (d) {
return d.name;
}));
//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("right");
var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")
.attr("class", "bars")
//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
});
//add a value label to the right of each bar
bars.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 + 4;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.value) + 3;
})
.text(function (d) {
return d.value;
});
var labels =
bars.append("text")
.attr("class", "labels")
.attr("y", function (d) {
return y(d.name) + y.rangeBand() / 2 - 30;
})
.attr("x", 0)
.text(function (d) {
return d.name;
});
I had a similar chart that I've made a few modifications to that might fill your requierments, so I'll be basing my answer of my own code.
I'll just go through the most relevant part of the question and you can just have a look at the code and hopefully figure out how it works yourself.
The inital animation works exactly the same way as in the third link you posted:
.transition().duration(speed)
.delay((_, i) => delay * i)
we set a delay so that each bar appear one at a time.
I've also set it up so that you can change the data using the d3js update pattern.
var bar = svg.selectAll(".bar")
.data(data, d => d.name)
bar.exit().remove();
bar.enter().insert("g", ".y-axis").append("rect")
.attr("class", "bar")
.attr("fill", "#ccc")
.attr("x", x(0))
.attr("y", d => y(d.name))
.attr("height", y.bandwidth())
.merge(bar)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("y", d => y(d.name))
.attr("width", d => x(d.value) - x(0));
Since you didn't specify how you want to update the new data it's just a year filter for now.
Here's all the code:
var init = [
{"year": "2017", "name": "Apples", "value": 20},
{"year": "2017", "name": "Bananas","value": 12},
{"year": "2017", "name": "Grapes", "value": 19},
{"year": "2017", "name": "Lemons", "value": 5},
{"year": "2017", "name": "Limes", "value": 16},
{"year": "2017", "name": "Oranges", "value": 26},
{"year": "2017", "name": "Pears","value": 30},
{"year": "2018", "name": "Apples", "value": 10},
{"year": "2018", "name": "Bananas","value": 42},
{"year": "2018", "name": "Grapes", "value": 69},
{"year": "2018", "name": "Lemons", "value": 15},
{"year": "2018", "name": "Limes", "value": 26},
{"year": "2018", "name": "Oranges", "value": 36},
{"year": "2018", "name": "Pears","value": 20}
];
chart(init)
function chart(result) {
var format = d3.format(",.0f")
var years = [...new Set(result.map(d => d.year))]
var fruit = [...new Set(result.map(d => d.name))]
var options = d3.select("#year").selectAll("option")
.data(years)
.enter().append("option")
.text(d => d)
var svg = d3.select("#graphic"),
margin = {top: 25, bottom: 10, left: 50, right: 45},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleLinear()
.range([margin.left, width - margin.right])
var y = d3.scaleBand()
.range([margin.top, height - margin.bottom])
.padding(0.1)
.paddingOuter(0.5)
.paddingInner(0.5)
var xAxis = svg.append("g")
.attr("class", "x-axis")
.attr("transform", `translate(0,${margin.top})`)
var yAxis = svg.append("g")
.attr("class", "y-axis")
.attr("transform", `translate(${margin.left},0)`)
update(d3.select("#year").property("value"), 750, 250)
function update(input, speed, delay) {
var data = result.filter(f => f.year == input)
var sum = d3.sum(data, d => d.value)
x.domain([0, d3.max(data, d => d.value)]).nice()
svg.selectAll(".x-axis").transition().duration(speed)
.call(d3.axisTop(x).tickSizeOuter(0));
data.sort((a, b) => b.value - a.value)
y.domain(data.map(d => d.name))
svg.selectAll(".y-axis").transition().duration(speed)
.call(d3.axisLeft(y));
yAxis.selectAll("text").remove()
yAxis.selectAll("line").remove()
var bar = svg.selectAll(".bar")
.data(data, d => d.name)
bar.exit().remove();
bar.enter().insert("g", ".y-axis").append("rect")
.attr("class", "bar")
.attr("fill", "#ccc")
.attr("x", x(0))
.attr("y", d => y(d.name))
.attr("height", y.bandwidth())
.merge(bar)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("y", d => y(d.name))
.attr("width", d => x(d.value) - x(0));
var value = svg.selectAll(".value")
.data(data, d => d.name)
value.exit().remove();
value.enter().append("text")
.attr("class", "value")
.attr("opacity", 0)
.attr("dy", 4)
.attr("y", d => y(d.name) + y.bandwidth() / 2)
.merge(value)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("opacity", 1)
.attr("y", d => y(d.name) + y.bandwidth() / 2)
.attr("x", d => x(d.value) + 5)
.text(d => format((d.value / sum) * 100) + " %")
var name = svg.selectAll(".name")
.data(data, d => d.name)
name.exit().remove();
name.enter().append("text")
.attr("class", "name")
.attr("opacity", 0)
.attr("dy", -5)
.attr("y", d => y(d.name))
.merge(name)
.transition().duration(speed)
.delay((_, i) => delay * i)
.attr("opacity", 1)
.attr("y", d => y(d.name))
.attr("x", d => x(0) + 5)
.text(d => d.name)
}
var select = d3.select("#year")
.style("border-radius", "5px")
.on("change", function() {
update(this.value, 750, 0)
})
}
body {
margin: auto;
width: 650px;
font: 12px arial;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="graphic" width="600" height="380"></svg><br>
Choose year:
<select id="year"></select>
I display a d3.area(). To show the highest value, I draw a horizontal line with d3.line() at the maximum value of the dataset. This value is calculated using:
var max_out = d3.max(data, function(d){ return +d.out; });
To brush through the graph, I use the setup as in this example:
As soon as the area is brushed, I would also like to move the "maximum line" up and down reflecting the new domain instead of using the whole dataset.
Any pointers?
Let's have a line function definition, in the first time only defining the x attribute:
var line = d3.line()
.x(function(d) { return x(d.date); });
Right after you append your area in the main view, add another path, which will be used to draw your horizontal line above the corresponding area:
focus.append("path")
.attr("class", "line");
Notice that I'm giving it a line class for styling.
We're also gonna draw the line, at first simply using the function you are currently using to determine the peak of your data:
.attr("d", line.y(function () {
return y(max);
}));
... and feed our line generator the right data :):
.datum(data)
To summarize, here's what we got on initialization:
// There's your main view's data area
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
// There's your 'peak' horizontal line
var max = d3.max(data, function(d){ return d.price; });
focus.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line.y(function () {
return y(max);
}));
In the functions that trigger a re-drawing of your elements, you simply have to update the d attribute of your path.line element.
We're gonna simply do the following:
Filter out data points that aren't within the updated domain of your x-axis
Evaluate the maximum value of that sub-set (using the method you described)
Let D3 generate the new value for the d attribute and set it.
That translates into the following:
var lo = x.domain()[0],
hi = x.domain()[1];
var max = d3.max(data.filter(function (d) {
return d.date.getTime() >= lo && d.date.getTime() <= hi;
}), function(d){ return d.price; });
focus.select(".line").attr("d", line.y(function () {
return y(max);
}));
See an example in action in the snippet below or on JSFiddle.
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 110, left: 40},
margin2 = {top: 180, right: 20, bottom: 30, left: 40},
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 x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
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 area = d3.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var area2 = d3.area()
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var line = d3.line()
.x(function(d) { return x(d.date); });
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 + ")");
var data;
(function (_data) {
data = _data;
data.forEach(function (d) {
d.date = new Date(d.date);
});
data = (function uniqBy(a, key) {
var seen = {};
return a.filter(function(item) {
var k = key(item);
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
});
})(data, function (d) {return d.date;});
data.sort(function(a,b) {
return new Date(a.date).getTime() - new Date(b.date).getTime();
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.price; })]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
var max = d3.max(data, function(d){ return d.price; });
focus.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line.y(function () {
return y(max);
}));
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
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);
})([{"date":"1999-12-31T23:00:00.000Z","price":1394.46},{"date":"2000-01-31T23:00:00.000Z","price":1366.42},{"date":"2000-02-29T23:00:00.000Z","price":1498.58},{"date":"2000-03-31T22:00:00.000Z","price":1452.43},{"date":"2000-04-30T22:00:00.000Z","price":1420.6},{"date":"2000-05-31T22:00:00.000Z","price":1454.6},{"date":"2000-06-30T22:00:00.000Z","price":1430.83},{"date":"2000-07-31T22:00:00.000Z","price":1517.68},{"date":"2000-08-31T22:00:00.000Z","price":1436.51},{"date":"2000-09-30T22:00:00.000Z","price":1429.4},{"date":"2000-10-31T23:00:00.000Z","price":1314.95},{"date":"2000-11-30T23:00:00.000Z","price":1320.28},{"date":"2000-12-31T23:00:00.000Z","price":1366.01},{"date":"2001-01-31T23:00:00.000Z","price":1239.94},{"date":"2001-02-28T23:00:00.000Z","price":1160.33},{"date":"2001-03-31T22:00:00.000Z","price":1249.46},{"date":"2001-04-30T22:00:00.000Z","price":1255.82},{"date":"2001-05-31T22:00:00.000Z","price":1224.38},{"date":"2001-06-30T22:00:00.000Z","price":1211.23},{"date":"2001-07-31T22:00:00.000Z","price":1133.58},{"date":"2001-08-31T22:00:00.000Z","price":1040.94},{"date":"2001-09-30T22:00:00.000Z","price":1059.78},{"date":"2001-10-31T23:00:00.000Z","price":1139.45},{"date":"2001-11-30T23:00:00.000Z","price":1148.08},{"date":"2001-12-31T23:00:00.000Z","price":1130.2},{"date":"2002-01-31T23:00:00.000Z","price":1106.73},{"date":"2002-02-28T23:00:00.000Z","price":1147.39},{"date":"2002-03-31T22:00:00.000Z","price":1076.92},{"date":"2002-04-30T22:00:00.000Z","price":1067.14},{"date":"2002-05-31T22:00:00.000Z","price":989.82},{"date":"2002-06-30T22:00:00.000Z","price":911.62},{"date":"2002-07-31T22:00:00.000Z","price":916.07},{"date":"2002-08-31T22:00:00.000Z","price":815.28},{"date":"2002-09-30T22:00:00.000Z","price":885.76},{"date":"2002-10-31T23:00:00.000Z","price":936.31},{"date":"2002-11-30T23:00:00.000Z","price":879.82},{"date":"2002-12-31T23:00:00.000Z","price":855.7},{"date":"2003-01-31T23:00:00.000Z","price":841.15},{"date":"2003-02-28T23:00:00.000Z","price":848.18},{"date":"2003-03-31T22:00:00.000Z","price":916.92},{"date":"2003-04-30T22:00:00.000Z","price":963.59},{"date":"2003-05-31T22:00:00.000Z","price":974.5},{"date":"2003-06-30T22:00:00.000Z","price":990.31},{"date":"2003-07-31T22:00:00.000Z","price":1008.01},{"date":"2003-08-31T22:00:00.000Z","price":995.97},{"date":"2003-09-30T22:00:00.000Z","price":1050.71},{"date":"2003-10-31T23:00:00.000Z","price":1058.2},{"date":"2003-11-30T23:00:00.000Z","price":1111.92},{"date":"2003-12-31T23:00:00.000Z","price":1131.13},{"date":"2004-01-31T23:00:00.000Z","price":1144.94},{"date":"2004-02-29T23:00:00.000Z","price":1126.21},{"date":"2004-03-31T22:00:00.000Z","price":1107.3},{"date":"2004-04-30T22:00:00.000Z","price":1120.68},{"date":"2004-05-31T22:00:00.000Z","price":1140.84},{"date":"2004-06-30T22:00:00.000Z","price":1101.72},{"date":"2004-07-31T22:00:00.000Z","price":1104.24},{"date":"2004-08-31T22:00:00.000Z","price":1114.58},{"date":"2004-09-30T22:00:00.000Z","price":1130.2},{"date":"2004-10-31T23:00:00.000Z","price":1173.82},{"date":"2004-11-30T23:00:00.000Z","price":1211.92},{"date":"2004-12-31T23:00:00.000Z","price":1181.27},{"date":"2005-01-31T23:00:00.000Z","price":1203.6},{"date":"2005-02-28T23:00:00.000Z","price":1180.59},{"date":"2005-03-31T22:00:00.000Z","price":1156.85},{"date":"2005-04-30T22:00:00.000Z","price":1191.5},{"date":"2005-05-31T22:00:00.000Z","price":1191.33},{"date":"2005-06-30T22:00:00.000Z","price":1234.18},{"date":"2005-07-31T22:00:00.000Z","price":1220.33},{"date":"2005-08-31T22:00:00.000Z","price":1228.81},{"date":"2005-09-30T22:00:00.000Z","price":1207.01},{"date":"2005-10-31T23:00:00.000Z","price":1249.48},{"date":"2005-11-30T23:00:00.000Z","price":1248.29},{"date":"2005-12-31T23:00:00.000Z","price":1280.08},{"date":"2006-01-31T23:00:00.000Z","price":1280.66},{"date":"2006-02-28T23:00:00.000Z","price":1294.87},{"date":"2006-03-31T22:00:00.000Z","price":1310.61},{"date":"2006-04-30T22:00:00.000Z","price":1270.09},{"date":"2006-05-31T22:00:00.000Z","price":1270.2},{"date":"2006-06-30T22:00:00.000Z","price":1276.66},{"date":"2006-07-31T22:00:00.000Z","price":1303.82},{"date":"2006-08-31T22:00:00.000Z","price":1335.85},{"date":"2006-09-30T22:00:00.000Z","price":1377.94},{"date":"2006-10-31T23:00:00.000Z","price":1400.63},{"date":"2006-11-30T23:00:00.000Z","price":1418.3},{"date":"2006-12-31T23:00:00.000Z","price":1438.24},{"date":"2007-01-31T23:00:00.000Z","price":1406.82},{"date":"2007-02-28T23:00:00.000Z","price":1420.86},{"date":"2007-03-31T22:00:00.000Z","price":1482.37},{"date":"2007-04-30T22:00:00.000Z","price":1530.62},{"date":"2007-05-31T22:00:00.000Z","price":1503.35},{"date":"2007-06-30T22:00:00.000Z","price":1455.27},{"date":"2007-07-31T22:00:00.000Z","price":1473.99},{"date":"2007-08-31T22:00:00.000Z","price":1526.75},{"date":"2007-09-30T22:00:00.000Z","price":1549.38},{"date":"2007-10-31T23:00:00.000Z","price":1481.14},{"date":"2007-11-30T23:00:00.000Z","price":1468.36},{"date":"2007-12-31T23:00:00.000Z","price":1378.55},{"date":"2008-01-31T23:00:00.000Z","price":1330.63},{"date":"2008-02-29T23:00:00.000Z","price":1322.7},{"date":"2008-03-31T22:00:00.000Z","price":1385.59},{"date":"2008-04-30T22:00:00.000Z","price":1400.38},{"date":"2008-05-31T22:00:00.000Z","price":1280},{"date":"2008-06-30T22:00:00.000Z","price":1267.38},{"date":"2008-07-31T22:00:00.000Z","price":1282.83},{"date":"2008-08-31T22:00:00.000Z","price":1166.36},{"date":"2008-09-30T22:00:00.000Z","price":968.75},{"date":"2008-10-31T23:00:00.000Z","price":896.24},{"date":"2008-11-30T23:00:00.000Z","price":903.25},{"date":"2008-12-31T23:00:00.000Z","price":825.88},{"date":"2009-01-31T23:00:00.000Z","price":735.09},{"date":"2009-02-28T23:00:00.000Z","price":797.87},{"date":"2009-03-31T22:00:00.000Z","price":872.81},{"date":"2009-04-30T22:00:00.000Z","price":919.14},{"date":"2009-05-31T22:00:00.000Z","price":919.32},{"date":"2009-06-30T22:00:00.000Z","price":987.48},{"date":"2009-07-31T22:00:00.000Z","price":1020.62},{"date":"2009-08-31T22:00:00.000Z","price":1057.08},{"date":"2009-09-30T22:00:00.000Z","price":1036.19},{"date":"2009-10-31T23:00:00.000Z","price":1095.63},{"date":"2009-11-30T23:00:00.000Z","price":1115.1},{"date":"2009-12-31T23:00:00.000Z","price":1073.87},{"date":"2010-01-31T23:00:00.000Z","price":1104.49},{"date":"2010-02-28T23:00:00.000Z","price":1140.45 }]);
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.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
var lo = x.domain()[0],
hi = x.domain()[1];
var max = d3.max(data.filter(function (d) {
return d.date.getTime() >= lo && d.date.getTime() <= hi;
}), function(d){ return d.price; });
focus.select(".line").attr("d", line.y(function () {
return y(max);
}));
}
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(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
var lo = x.domain()[0],
hi = x.domain()[1];
var max = d3.max(data.filter(function (d) {
return d.date.getTime() >= lo && d.date.getTime() <= hi;
}), function(d){ return d.price; });
focus.select(".line").attr("d", line.y(function () {
return y(max);
}));
}
function type(d) {
d.date = parseDate(d.date);
d.price = +d.price;
return d;
}
.area {
fill: steelblue;
clip-path: url(#clip);
}
.line {
stroke: red;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="250"></svg>
Something like this:
focus.append("line")
.attr("class", "peak")
.style("stroke", "orange")
.attr("stroke-width", 3);
function setPeak(){
var maxY = {
x: null,
y: -1e100
};
data.forEach(function(d){
if (d.date >= x.domain()[0] &&
d.date <= x.domain()[1] &&
d.price > maxY.y){
maxY.y = d.price;
maxY.x = d.date;
}
});
d3.select(".peak")
.attr("x1", x(maxY.x))
.attr("x2", x(maxY.x))
.attr("y1", 0)
.attr("y2", height);
}
setPeak();
Running code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.area {
fill: steelblue;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
</style>
<svg width="400" height="300"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 110,
left: 40
},
margin2 = {
top: 230,
right: 20,
bottom: 30,
left: 40
},
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 x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
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 area = d3.area()
.curve(d3.curveMonotoneX)
.x(function(d) {
return x(d.date);
})
.y0(height)
.y1(function(d) {
return y(d.price);
});
var area2 = d3.area()
.curve(d3.curveMonotoneX)
.x(function(d) {
return x2(d.date);
})
.y0(height2)
.y1(function(d) {
return y2(d.price);
});
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 + ")");
//d3.csv("data.csv", type, function(error, data) {
// if (error) throw error;
var data = [{
"date": "1999-12-31T23:00:00.000Z",
"price": 1394.46
}, {
"date": "2000-01-31T23:00:00.000Z",
"price": 1366.42
}, {
"date": "2000-02-29T23:00:00.000Z",
"price": 1498.58
}, {
"date": "2000-03-31T22:00:00.000Z",
"price": 1452.43
}, {
"date": "2000-04-30T22:00:00.000Z",
"price": 1420.6
}, {
"date": "2000-05-31T22:00:00.000Z",
"price": 1454.6
}, {
"date": "2000-06-30T22:00:00.000Z",
"price": 1430.83
}, {
"date": "2000-07-31T22:00:00.000Z",
"price": 1517.68
}, {
"date": "2000-08-31T22:00:00.000Z",
"price": 1436.51
}, {
"date": "2000-09-30T22:00:00.000Z",
"price": 1429.4
}, {
"date": "2000-10-31T23:00:00.000Z",
"price": 1314.95
}, {
"date": "2000-11-30T23:00:00.000Z",
"price": 1320.28
}, {
"date": "2000-12-31T23:00:00.000Z",
"price": 1366.01
}, {
"date": "2001-01-31T23:00:00.000Z",
"price": 1239.94
}, {
"date": "2001-02-28T23:00:00.000Z",
"price": 1160.33
}, {
"date": "2001-03-31T22:00:00.000Z",
"price": 1249.46
}, {
"date": "2001-04-30T22:00:00.000Z",
"price": 1255.82
}, {
"date": "2001-05-31T22:00:00.000Z",
"price": 1224.38
}, {
"date": "2001-06-30T22:00:00.000Z",
"price": 1211.23
}, {
"date": "2001-07-31T22:00:00.000Z",
"price": 1133.58
}, {
"date": "2001-08-31T22:00:00.000Z",
"price": 1040.94
}, {
"date": "2001-09-30T22:00:00.000Z",
"price": 1059.78
}, {
"date": "2001-10-31T23:00:00.000Z",
"price": 1139.45
}, {
"date": "2001-11-30T23:00:00.000Z",
"price": 1148.08
}, {
"date": "2001-12-31T23:00:00.000Z",
"price": 1130.2
}, {
"date": "2002-01-31T23:00:00.000Z",
"price": 1106.73
}, {
"date": "2002-02-28T23:00:00.000Z",
"price": 1147.39
}, {
"date": "2002-03-31T22:00:00.000Z",
"price": 1076.92
}, {
"date": "2002-04-30T22:00:00.000Z",
"price": 1067.14
}, {
"date": "2002-05-31T22:00:00.000Z",
"price": 989.82
}, {
"date": "2002-06-30T22:00:00.000Z",
"price": 911.62
}, {
"date": "2002-07-31T22:00:00.000Z",
"price": 916.07
}, {
"date": "2002-08-31T22:00:00.000Z",
"price": 815.28
}, {
"date": "2002-09-30T22:00:00.000Z",
"price": 885.76
}, {
"date": "2002-10-31T23:00:00.000Z",
"price": 936.31
}, {
"date": "2002-11-30T23:00:00.000Z",
"price": 879.82
}, {
"date": "2002-12-31T23:00:00.000Z",
"price": 855.7
}, {
"date": "2003-01-31T23:00:00.000Z",
"price": 841.15
}, {
"date": "2003-02-28T23:00:00.000Z",
"price": 848.18
}, {
"date": "2003-03-31T22:00:00.000Z",
"price": 916.92
}, {
"date": "2003-04-30T22:00:00.000Z",
"price": 963.59
}, {
"date": "2003-05-31T22:00:00.000Z",
"price": 974.5
}, {
"date": "2003-06-30T22:00:00.000Z",
"price": 990.31
}, {
"date": "2003-07-31T22:00:00.000Z",
"price": 1008.01
}, {
"date": "2003-08-31T22:00:00.000Z",
"price": 995.97
}, {
"date": "2003-09-30T22:00:00.000Z",
"price": 1050.71
}, {
"date": "2003-10-31T23:00:00.000Z",
"price": 1058.2
}, {
"date": "2003-11-30T23:00:00.000Z",
"price": 1111.92
}, {
"date": "2003-12-31T23:00:00.000Z",
"price": 1131.13
}, {
"date": "2004-01-31T23:00:00.000Z",
"price": 1144.94
}, {
"date": "2004-02-29T23:00:00.000Z",
"price": 1126.21
}, {
"date": "2004-03-31T22:00:00.000Z",
"price": 1107.3
}, {
"date": "2004-04-30T22:00:00.000Z",
"price": 1120.68
}, {
"date": "2004-05-31T22:00:00.000Z",
"price": 1140.84
}, {
"date": "2004-06-30T22:00:00.000Z",
"price": 1101.72
}, {
"date": "2004-07-31T22:00:00.000Z",
"price": 1104.24
}, {
"date": "2004-08-31T22:00:00.000Z",
"price": 1114.58
}, {
"date": "2004-09-30T22:00:00.000Z",
"price": 1130.2
}, {
"date": "2004-10-31T23:00:00.000Z",
"price": 1173.82
}, {
"date": "2004-11-30T23:00:00.000Z",
"price": 1211.92
}, {
"date": "2004-12-31T23:00:00.000Z",
"price": 1181.27
}, {
"date": "2005-01-31T23:00:00.000Z",
"price": 1203.6
}, {
"date": "2005-02-28T23:00:00.000Z",
"price": 1180.59
}, {
"date": "2005-03-31T22:00:00.000Z",
"price": 1156.85
}, {
"date": "2005-04-30T22:00:00.000Z",
"price": 1191.5
}, {
"date": "2005-05-31T22:00:00.000Z",
"price": 1191.33
}, {
"date": "2005-06-30T22:00:00.000Z",
"price": 1234.18
}, {
"date": "2005-07-31T22:00:00.000Z",
"price": 1220.33
}, {
"date": "2005-08-31T22:00:00.000Z",
"price": 1228.81
}, {
"date": "2005-09-30T22:00:00.000Z",
"price": 1207.01
}, {
"date": "2005-10-31T23:00:00.000Z",
"price": 1249.48
}, {
"date": "2005-11-30T23:00:00.000Z",
"price": 1248.29
}, {
"date": "2005-12-31T23:00:00.000Z",
"price": 1280.08
}, {
"date": "2006-01-31T23:00:00.000Z",
"price": 1280.66
}, {
"date": "2006-02-28T23:00:00.000Z",
"price": 1294.87
}, {
"date": "2006-03-31T22:00:00.000Z",
"price": 1310.61
}, {
"date": "2006-04-30T22:00:00.000Z",
"price": 1270.09
}, {
"date": "2006-05-31T22:00:00.000Z",
"price": 1270.2
}, {
"date": "2006-06-30T22:00:00.000Z",
"price": 1276.66
}, {
"date": "2006-07-31T22:00:00.000Z",
"price": 1303.82
}, {
"date": "2006-08-31T22:00:00.000Z",
"price": 1335.85
}, {
"date": "2006-09-30T22:00:00.000Z",
"price": 1377.94
}, {
"date": "2006-10-31T23:00:00.000Z",
"price": 1400.63
}, {
"date": "2006-11-30T23:00:00.000Z",
"price": 1418.3
}, {
"date": "2006-12-31T23:00:00.000Z",
"price": 1438.24
}, {
"date": "2007-01-31T23:00:00.000Z",
"price": 1406.82
}, {
"date": "2007-02-28T23:00:00.000Z",
"price": 1420.86
}, {
"date": "2007-03-31T22:00:00.000Z",
"price": 1482.37
}, {
"date": "2007-04-30T22:00:00.000Z",
"price": 1530.62
}, {
"date": "2007-05-31T22:00:00.000Z",
"price": 1503.35
}, {
"date": "2007-06-30T22:00:00.000Z",
"price": 1455.27
}, {
"date": "2007-07-31T22:00:00.000Z",
"price": 1473.99
}, {
"date": "2007-08-31T22:00:00.000Z",
"price": 1526.75
}, {
"date": "2007-09-30T22:00:00.000Z",
"price": 1549.38
}, {
"date": "2007-10-31T23:00:00.000Z",
"price": 1481.14
}, {
"date": "2007-11-30T23:00:00.000Z",
"price": 1468.36
}, {
"date": "2007-12-31T23:00:00.000Z",
"price": 1378.55
}, {
"date": "2008-01-31T23:00:00.000Z",
"price": 1330.63
}, {
"date": "2008-02-29T23:00:00.000Z",
"price": 1322.7
}, {
"date": "2008-03-31T22:00:00.000Z",
"price": 1385.59
}, {
"date": "2008-04-30T22:00:00.000Z",
"price": 1400.38
}, {
"date": "2008-05-31T22:00:00.000Z",
"price": 1280
}, {
"date": "2008-06-30T22:00:00.000Z",
"price": 1267.38
}, {
"date": "2008-07-31T22:00:00.000Z",
"price": 1282.83
}, {
"date": "2008-08-31T22:00:00.000Z",
"price": 1166.36
}, {
"date": "2008-09-30T22:00:00.000Z",
"price": 968.75
}, {
"date": "2008-10-31T23:00:00.000Z",
"price": 896.24
}, {
"date": "2008-11-30T23:00:00.000Z",
"price": 903.25
}, {
"date": "2008-12-31T23:00:00.000Z",
"price": 825.88
}, {
"date": "2009-01-31T23:00:00.000Z",
"price": 735.09
}, {
"date": "2009-02-28T23:00:00.000Z",
"price": 797.87
}, {
"date": "2009-03-31T22:00:00.000Z",
"price": 872.81
}, {
"date": "2009-04-30T22:00:00.000Z",
"price": 919.14
}, {
"date": "2009-05-31T22:00:00.000Z",
"price": 919.32
}, {
"date": "2009-06-30T22:00:00.000Z",
"price": 987.48
}, {
"date": "2009-07-31T22:00:00.000Z",
"price": 1020.62
}, {
"date": "2009-08-31T22:00:00.000Z",
"price": 1057.08
}, {
"date": "2009-09-30T22:00:00.000Z",
"price": 1036.19
}, {
"date": "2009-10-31T23:00:00.000Z",
"price": 1095.63
}, {
"date": "2009-11-30T23:00:00.000Z",
"price": 1115.1
}, {
"date": "2009-12-31T23:00:00.000Z",
"price": 1073.87
}, {
"date": "2010-01-31T23:00:00.000Z",
"price": 1104.49
}, {
"date": "2010-02-28T23:00:00.000Z",
"price": 1140.45
}];
data = data.map(type);
console.log(data)
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.price;
})]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
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);
focus.append("line")
.attr("class", "peak")
.style("stroke", "orange")
.attr("stroke-width", 3);
//});
function setPeak(){
var maxY = {
x: null,
y: -1e100
};
data.forEach(function(d){
if (d.date >= x.domain()[0] &&
d.date <= x.domain()[1] &&
d.price > maxY.y){
maxY.y = d.price;
maxY.x = d.date;
}
});
d3.select(".peak")
.attr("x1", x(maxY.x))
.attr("x2", x(maxY.x))
.attr("y1", 0)
.attr("y2", height);
}
setPeak();
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.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
setPeak();
}
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(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function type(d) {
d.date = new Date(d.date);
d.price = +d.price;
return d;
}
</script>