D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
interwebjill
Full window
Github gist
Combining Canvas + SVG for Retina
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <style> /* to prevent browser overscrolling */ html { overflow: hidden; } body { margin: 0; /* or else canvas alignment is off */ box-sizing: border-box; } /* for retina display */ canvas { width: 880px; height: 450px; } .chart { position: absolute; } #chart-canvas { margin: 20px 0 0 60px; z-index: 1; } #axis-svg { z-index: 2; } .area { clip-path: url(#clip); } .zoom { cursor: move; fill: none; pointer-events: all; } .PVkW { fill: #f29e2e; } .TBLkW { fill: #36aeaf; } </style> </head> <body> <canvas width="1760" height="900" id="chart-canvas" class="chart"></canvas> <svg width="960" height="500" id="axis-svg" class="chart"></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 canvas = document.querySelector("canvas"), context = canvas.getContext("2d"), canvasScale = canvas.width / width; var parseDate = d3.timeParse("%Y/%m/%d %H:%M"); var color = d3.scaleOrdinal() .domain(["PVkW", "TBLkW"]) .range(["rgba(249, 208, 87, 1.0)", "rgba(54, 174, 175, 0.6)"]); var xSVG = d3.scaleTime() .range([0, width]); var x = d3.scaleTime() .range([0, width]); var x2 = d3.scaleTime() // for zooming .range([0, width]); var ySVG = d3.scaleLinear() .range([height, 0]); var y = d3.scaleLinear() .range([height, 0]); var xAxisSVG = d3.axisBottom(xSVG); var yAxisSVG = d3.axisLeft(ySVG); var area = d3.area() .x(function(d) { return x(d.date); }) .y0(y(0)) .y1(function(d) { return y(d.kW); }) .curve(d3.curveStep) .context(context); var yGroupSVG = g.append("g") .attr("class", "y-axis"); var xGroupSVG = g.append("g") .attr("transform", "translate(0," + height + ")") .attr("class", "x-axis"); var defs = svg.append("defs"); defs.append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); d3.csv("kW.csv", type, function(error, data) { if (error) throw error; 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 len = sources.length; var xExtent = d3.extent(data, function(d) { return d.date; }); xSVG.domain(xExtent); x.domain(xExtent); x2.domain(x.domain()); ySVG.domain([ 0, d3.max(sources, function(c) { return d3.max(c.values, function(v) { return v.kW; }); }) ]); y.domain([ 0, d3.max(sources, function(c) { return d3.max(c.values, function(v) { return v.kW; }); }) ]); yGroupSVG.call(yAxisSVG); xGroupSVG.call(xAxisSVG); color.domain(sources.map(function(c) { return c.id; })); function draw() { context.save(); context.scale(canvasScale, canvasScale); context.clearRect(0, 0, width, height); // clip path context.beginPath() context.rect(0, 0, width, height); context.clip(); for (i=0; i<len; i++) { context.beginPath(); area(sources[i].values); context.fillStyle = color(sources[i].id); context.fill(); } context.restore(); } draw(); 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("fill", "none") .attr("pointer-events", "all") .call(zoom) .on("dblclick.zoom", null); function zoomed() { var t = d3.event.transform; var xz = t.rescaleX(xSVG); xGroupSVG.call(xAxisSVG.scale(xz)); x = t.rescaleX(x2); draw(); } }); 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> </body> </html>
https://d3js.org/d3.v4.min.js