forked from interwebjill's block: Zoomable Area SVG
Changes from the version above are noted in code comments.
xxxxxxxxxx
<style>
/* to prevent browser overscrolling */
html {
overflow: hidden;
}
/* different way of setting clipping path */
.area {
clip-path: url(#clip);
}
.PEMS {
fill: rgba(249, 208, 87, 0.8);
}
.TBLkW {
fill: rgba(54, 174, 175, 0.5);
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 60},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseDate = d3.timeParse("%Y/%m/%d %H:%M"),
formatDate = d3.timeFormat("%Y");
var x = d3.scaleTime()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(x);
var yAxis = d3.axisLeft(y);
var area = d3.area()
.curve(d3.curveStepAfter)
// added x domain, changed data value
.x(function(d) { return x(d.date); })
.y0(y(0))
.y1(function(d) { return y(d.kW); });
// var areaPath = g.append("path")
// .attr("clip-path", "url(#clip)")
// .attr("fill", "steelblue");
// group to hold the multiple paths
var dataPaths = g.append("g")
.attr("class", "dataPaths");
var yGroup = g.append("g");
var xGroup = g.append("g")
.attr("transform", "translate(0," + height + ")");
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var zoomRect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("class", "zoom-area")
.attr("fill", "none")
.attr("pointer-events", "all")
.call(zoom);
// g.append("clipPath")
// .attr("id", "clip")
// .append("rect")
// .attr("width", width)
// .attr("height", height);
// did the clip path a little differently
var defs = svg.append("defs");
defs.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// changed data source
d3.csv("kW_sample.csv", type, function(error, data) {
if (error) throw error;
// each column of data becomes a source
var sources = data.columns.slice(1).map(function(id) {
return {
id: id,
values: data.map(function(d) {
return {date: d.date, kW: d[id]};
})
};
});
var xExtent = d3.extent(data, function(d) { return d.date; });
x.domain(xExtent);
// changed to account for multiple columns of data
y.domain([
0,
d3.max(sources, function(c) { return d3.max(c.values, function(v) { return v.kW; }); })
]);
yGroup.call(yAxis);
// areaPath.datum(data);
// look in elements inspector in devtools to see how these groups are organized
var sourcedataPaths = dataPaths.selectAll("g")
.data(sources)
.enter()
.append("g")
.attr("class", "sourcedataPaths");
var dataPathsPath = sourcedataPaths.append("path")
.attr("class", function(d) { return `area ${d.id}`; })
.attr("d", function(d) { console.log(d.values); return area(d.values); });
zoomRect.call(zoom.transform, d3.zoomIdentity);
});
function zoomed() {
var xz = d3.event.transform.rescaleX(x);
xGroup.call(xAxis.scale(xz));
// areaPath.attr("d", area.x(function(d) { return xz(d.date); }));
// replaced with:
dataPaths.selectAll(".area").attr("d", area.x(function(d) { return xz(d.date); }));
dataPaths.selectAll(".area").attr("d", function(d) { return area(d.values); })
}
// rewrote for multiple data columns
function type(d, _, columns) {
d.date = parseDate(d.date);
for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +Math.round(d[c]);
return d;
}
</script>
https://d3js.org/d3.v4.min.js