aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/static/annotate.css27
-rw-r--r--app/templates/annotate/index.html361
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 %}