diff options
| author | Gertjan van den Burg <gertjanvandenburg@gmail.com> | 2019-03-25 19:36:38 +0000 |
|---|---|---|
| committer | Gertjan van den Burg <gertjanvandenburg@gmail.com> | 2019-03-25 19:40:20 +0000 |
| commit | 46224ce156a9a2782a21172c39c40968db7f89e0 (patch) | |
| tree | 2ac7ec52d115e0748641c304e11432029f9c891e /app | |
| parent | Add assignment template (diff) | |
| download | AnnotateChange-46224ce156a9a2782a21172c39c40968db7f89e0.tar.gz AnnotateChange-46224ce156a9a2782a21172c39c40968db7f89e0.zip | |
first working version of pan + zoom + click
Diffstat (limited to 'app')
| -rw-r--r-- | app/static/annotate.css | 27 | ||||
| -rw-r--r-- | app/templates/annotate/index.html | 361 |
2 files changed, 125 insertions, 263 deletions
diff --git a/app/static/annotate.css b/app/static/annotate.css index d6e30fc..0ee40f6 100644 --- a/app/static/annotate.css +++ b/app/static/annotate.css @@ -3,25 +3,6 @@ text-align: center; } -/* -path { - stroke-width: 2; - fill: none; -} - -.axis path, .axis line { - fill: none; - stroke: grey; - stroke-width: 1; - shape-rendering: crispEdges; -} - -#changepoint-table { - margin: 0 auto; -} - -*/ - .line { fill: none; stroke: blue; @@ -33,8 +14,8 @@ circle { fill: blue; } -.zoom { - cursor: move; - fill: none; - pointer-events: fill; +rect { + fill: white; + opacity: 0; } + diff --git a/app/templates/annotate/index.html b/app/templates/annotate/index.html index b605dc3..1805d95 100644 --- a/app/templates/annotate/index.html +++ b/app/templates/annotate/index.html @@ -24,204 +24,139 @@ {# Based on: https://github.com/benalexkeen/d3-flask-blog-post/blob/master/templates/index.html #} +{# And: https://bl.ocks.org/mbostock/35964711079355050ff1 #} <script src="http://d3js.org/d3.v5.min.js"></script> <script> - var graphData = {{ data.chart_data | safe }}; +var data = {{ data.chart_data | safe }}; +var n = 0; +data.forEach(function(d) { + d.X = n++; + d.Y = d.value; +}); + +var divWidth = 1000; +var divHeight = 480; + +var svg = d3.select("#graph") + .on("touchstart", nozoom) + .on("touchmove", nozoom) + .append("svg") + .attr("width", divWidth) + .attr("height", divHeight); + +var margin = {top: 20, right: 20, bottom: 100, left: 100}; +var width = +svg.attr("width") - margin.left - margin.right; +var height = +svg.attr("height") - margin.top - margin.bottom; -/**** Starting the alternative in this block: - https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172 - **/ -var svg = d3.select("#graph").append("svg").attr("width", 960).attr("height", 500), - margin = {top: 20, right: 20, bottom: 110, left: 40}, - margin2 = {top: 430, 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 zoom = d3.zoom() + .scaleExtent([1, 10]) + .translateExtent([[0, 0], [width, height]]) + .extent([[0, 0], [width, height]]) + .on("zoom", zoomed); -var x = d3.scaleLinear().range([0, width]), - y = d3.scaleLinear().range([height, 0]), - x2 = d3.scaleLinear().range([0, width]); +var x = d3.scaleLinear().range([0, width]); +var x2 = d3.scaleLinear().range([0, width]); +var y = d3.scaleLinear().range([height, 0]); -var xAxis = d3.axisBottom(x), - yAxis = d3.axisLeft(y); +var xAxis = d3.axisBottom(x); +var yAxis = d3.axisLeft(y); -var zoom = d3.zoom() - .scaleExtent([1, 10]) - .translateExtent([[0, 0], [width, height]]) - .extent([[0, 0], [width, height]]) - .on("zoom", zoomed); +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 line = d3.line() - .x(function(d) { return x(d.X); }) - .y(function(d) { return y(d.Y); }); +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; + +x.domain([xDomainMin, xDomainMax]); +y.domain([yDomainMin, yDomainMax]); +x2.domain(x.domain()); -// used for clipping the path outside the graph svg.append("defs").append("clipPath") - .attr("id", "clip") - .append("rect") - .attr("width", width) - .attr("height", height); + .attr("id", "clip") + .append("rect") + .attr("width", width - 30) + .attr("height", height) + .attr("transform", "translate(" + 30 + ",0)"); + +svg.append("g") + .attr("class", "axis axis--y") + .attr("transform", "translate(" + 30 + ",0)") + .call(yAxis); + +svg.append("g") + .attr("class", "axis axis--x") + .attr("transform", "translate(0," + height + ")") + .call(xAxis); + +svg.append("text") + .attr("text-anchor", "middle") + .attr("class", "axis-label") + .attr("transform", "translate(" + (width - 20) + "," + (height + 50) + ")") + .text("Time"); -var focus = svg.append("g") - .attr("class", "focus") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); +var line = d3.line() + .x(function(d) { return x(d.X); }) + .y(function(d) { return y(d.Y); }); + +var g = svg.append("g") + .call(zoom); + +g.append("rect") + .attr("width", width) + .attr("height", height); + +var view = g.append("g") + .attr("class", "view"); + +view.append("path") + .datum(data) + .attr("class", "line") + .attr("d", line); + +var points = view.selectAll("circle") + .data(data) + .enter().append("circle") + .attr("cx", function(d) { return x(d.X); }) + .attr("cy", function(d) { return y(d.Y); }) + .attr("data_X", function(d) { return d.X; }) + .attr("data_Y", function(d) { return d.Y; }) + .attr("r", 5) + .on("click", clicked); 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()); - // redraw - focus.select(".line").attr("d", line); - points.data(graphData) - .attr("cx", function(d) { return x(d.X) }) - .attr("cy", function(d) { return y(d.Y) }); - // update axis - focus.select(".axis--x").call(xAxis); + t = d3.event.transform; + x.domain(t.rescaleX(x2).domain()); + svg.select(".line").attr("d", line); + points.data(data) + .attr("cx", function(d) { return x(d.X); }) + .attr("cy", function(d) { return y(d.Y); }); + svg.select(".axis--x").call(xAxis); } -function draw(data) { - var n = 0; - data.forEach(function(d) { - d.X = n++; - d.Y = d.value; - }); - - var yExtent = d3.extent(data, function(d) { return d.Y; }), - yRange = yExtent[1] - yExtent[0]; - - x.domain(d3.extent(data, function(d) { return d.X; })); - y.domain([yExtent[0] - (yRange * 0.05), yExtent[1] + (yRange * - 0.05)]); - x2.domain(x.domain()); - - focus.append("path") - .datum(data) - .attr("class", "line") - .attr("d", line); - - 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); - - var points = focus.append("g") - .selectAll("dot") - .data(data) - .enter() - .append("circle") - .attr("cx", function(d) { return x(d.X); } ) - .attr("cy", function(d) { return y(d.Y); } ) - .attr("data_X", function(d) { return d.X; } ) - .attr("data_Y", function(d) { return d.Y; } ) - .attr("r", 4) - .attr("fill", "blue") - .on("click", function(d, i) { - // this function handles changepoint marking - var elem = d3.select(d); - if (elem.classed("changepoint")) { - elem.style("fill", "blue"); - elem.classed("changepoint", false); - } else { - elem.style("fill", "red"); - elem.classed("changepoint", true); - } - // updateTable(); - }); - - var layer = svg.append("rect") - .attr("class", "zoom") - .attr("width", width) - .attr("height", height) - .attr("transform", "translate(" + margin.left + "," + margin.top + ")") - .call(zoom); - - return(points); -}; - -var points = draw(graphData); - - - - - - - -/***** END ALTERNATIVE **/ - - -/* - // Set the dimension of the svg - var margin = {top: 30, right: 50, bottom: 30, left: 50}; - var svgWidth = 800; - var svgHeight = 400; - var graphWidth = svgWidth - margin.left - margin.right; - var graphHeight = svgHeight - margin.top - margin.bottom; - - var xAxisScale = d3.scaleLinear().range([0, graphWidth]); - var yAxisScale = d3.scaleLinear().range([graphHeight, 0]); - - var xAxis = d3.axisBottom(xAxisScale).ticks(5); - var yAxis = d3.axisLeft(yAxisScale).ticks(5); - - var line = d3.line() - .x(function(d) { return xAxisScale(d.X); }) - .y(function(d) { return yAxisScale(d.Y); }); - - var svg = d3.select("#graph") - .append("svg") - .attr("width", svgWidth) - .attr("height", svgHeight) - - var zoom = d3.zoom() - .scaleExtent([1, 5]) - .on("zoom", zoomFunction); - - var innerSpace = svg - .append("g") - .attr("class", "inner_space") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - -// Add the X Axis - var gX = innerSpace.append("g") - .attr("class", "axis axis--x") - .attr("transform", "translate(0," + graphHeight + ")") - .call(xAxis); - -// Add the Y Axis - var gY = innerSpace.append("g") - .attr("class", "axis axis--y") - .call(yAxis); - - var view = innerSpace.append("rect") - .attr("class", "zoom") - .attr("width", graphWidth) - .attr("height", graphHeight) - .call(zoom) - - function zoomFunction() { - - var e = d3.event, - tx = Math.min(0, Math.max(e.transform.x, graphWidth - - graphWidth * e.scale)), - ty = Math.min(0, Math.max(e.transform.y, graphHeight - - graphHeight * e.scale)); - zoom.translateBy([tx, ty]); - - theline.attr("transform", [ - "translate(" + [tx, ty] + ")", - "scale(" + e.scale + ")" - ].join(" ")); +function clicked(d, i) { + if (d3.event.defaultPrevented) return; // zoomed + + // this function handles changepoint marking + var elem = d3.select(this); + if (elem.classed("changepoint")) { + elem.style("fill", "blue"); + elem.classed("changepoint", false); + } else { + elem.style("fill", "red"); + elem.classed("changepoint", true); + } + updateTable(); +} - } +function nozoom() { + d3.event.preventDefault(); +} - function updateTable() { +function updateTable() { var changepoints = document.getElementsByClassName("changepoint"); var myTableDiv = document.getElementById("changepoint-table"); @@ -238,7 +173,7 @@ var points = draw(graphData); heading[1] = "X"; heading[2] = "Y"; - // TABLE COLUMNS + // TABLE COLUMNS var thead = document.createElement('THEAD'); thead.className = "thead-dark"; table.appendChild(thead); @@ -250,7 +185,7 @@ var points = draw(graphData); } var body = document.createElement("TBODY"); -//TABLE ROWS + //TABLE ROWS for (i = 0; i < changepoints.length; i++) { cp = changepoints[i]; @@ -277,61 +212,7 @@ var points = draw(graphData); } table.appendChild(body); myTableDiv.appendChild(table); - } - - function draw(data) { - var n = 0; - data.forEach(function(d) { - d.X = n++; - d.Y = d.value; - }); - - xAxisScale.domain(d3.extent(data, function(d) { return d.X; })); - yAxisScale.domain([ - d3.min(data, function(d) { - return Math.min(d.Y) - }), - d3.max(data, function(d) { - return Math.max(d.Y) - })]); - - // the line - var theline = innerSpace.append("path") - .style("stroke", "blue") - .style("fill", "none") - .attr("class", "line") - .attr("d", line(data)); - -// the points - var thepoints = innerSpace.append("g") - .selectAll("dot") - .data(data) - .enter() - .append("circle") - .attr("cx", function(d) { return xAxisScale(d.X) } ) - .attr("cy", function(d) { return yAxisScale(d.Y) } ) - .attr("data_X", function(d) { return d.X } ) - .attr("data_Y", function(d) { return d.Y } ) - .attr("r", 4) - .attr("fill", "blue") - .on("click", function(d, i) { - // this function handles changepoint marking - var elem = d3.select(this); - if (elem.classed("changepoint")) { - elem.style("fill", "blue"); - elem.classed("changepoint", false); - } else { - elem.style("fill", "red"); - elem.classed("changepoint", true); - } - updateTable(); - }); - return [theline, thepoints]; - }; - - var out = draw(graphData); - var theline = out[0] - var thepoints = out[1]; - */ +} + </script> {% endblock %} |
