// Based on: //https://github.com/benalexkeen/d3-flask-blog-post/blob/master/templates/index.html // And: https://bl.ocks.org/mbostock/35964711079355050ff1 function preprocessData(data) { var n = 0; cleanData = []; run = []; for (i=0; i 0) cleanData.push(run); run = []; continue; } run.push({"X": n++, "Y": d}); } cleanData.push(run); return cleanData; } function scaleAndAxis(data, width, height) { // xScale is the active scale used for zooming, xScaleOrig is used as // the original scale that is never changed. var xScale = d3.scaleLinear().range([0, width]); var xScaleOrig = d3.scaleLinear().range([0, width]); var yScale = d3.scaleLinear().range([height, 0]); // create the axes var xAxis = d3.axisBottom(xScale); var yAxis = d3.axisLeft(yScale); // turn off ticks on the y axis. We don't want annotators to be // influenced by whether a change is big in the absolute sense. yAxis.ticks(0); var xmin = Math.min(...data.map(function(run) { return Math.min(...run.map(it => it.X)); })) var xmax = Math.max(...data.map(function(run) { return Math.max(...run.map(it => it.X)); })) var ymin = Math.min(...data.map(function(run) { return Math.min(...run.map(it => it.Y)); })) var ymax = Math.max(...data.map(function(run) { return Math.max(...run.map(it => it.Y)); })) var xExtent = [xmin, xmax]; var yExtent = [ymin, ymax]; // compute the domains for the axes //var xExtent = d3.extent(data, function(d) { return d.X; }); var xRange = xExtent[1] - xExtent[0]; var xDomainMin = xExtent[0] - xRange * 0.02; var xDomainMax = xExtent[1] + xRange * 0.02; //var yExtent = d3.extent(data, function(d) { return d.Y; }); var yRange = yExtent[1] - yExtent[0]; var yDomainMin = yExtent[0] - yRange * 0.05; var yDomainMax = yExtent[1] + yRange * 0.05; // set the axis domains xScale.domain([xDomainMin, xDomainMax]); xScaleOrig.domain([xDomainMin, xDomainMax]); yScale.domain([yDomainMin, yDomainMax]); return [xAxis, yAxis, xScale, xScaleOrig, yScale, yDomainMin, yDomainMax]; } function noZoom() { d3.event.preventDefault(); } function baseChart( selector, data, clickFunction, annotations, annotationFunction, divWidth, divHeight ) { /* Note: * It may be tempting to scale the width/height of the div to be * proportional to the size of the window. However this may cause some * users with wide screens to perceive changes in the time series * differently than others because the horizontal axis is more * stretched out. It is therefore better to keep the size of the graph * the same for all users. */ if (divWidth === null || typeof divWidth === 'undefined') divWidth = 1000; if (divHeight === null || typeof divHeight === 'undefined') divHeight = 480; // preprocess the data data = preprocessData(data); var svg = d3.select(selector) .on("touchstart", noZoom) .on("touchmove", noZoom) .append("svg") .attr("width", divWidth) .attr("height", divHeight) .attr("viewBox", "0 0 " + divWidth + " " + divHeight); var margin = {top: 20, right: 20, bottom: 50, left: 50}; var width = +svg.attr("width") - margin.left - margin.right; var height = +svg.attr("height") - margin.top - margin.bottom; var [xAxis, yAxis, xScale, xScaleOrig, yScale, yDomainMin, yDomainMax] = scaleAndAxis( data, width, height); var lineObjects = []; for (let r=0; r