|
<!DOCTYPE html> |
|
<html lang="en"> |
|
|
|
<head> |
|
<meta charset="utf-8"> |
|
<title>DTS</title> |
|
|
|
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script> |
|
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script> |
|
<script src="https://code.jquery.com/jquery-2.2.4.min.js" type="text/javascript"></script> |
|
|
|
<style type="text/css"> |
|
body { |
|
color: #444; |
|
font: 10px sans-serif; |
|
} |
|
|
|
svg { |
|
font: 10px sans-serif; |
|
} |
|
|
|
text { |
|
fill: #444; |
|
} |
|
|
|
.points circle { |
|
stroke: #000; |
|
stroke-width: 1px; |
|
} |
|
|
|
.boundary { |
|
stroke: none; |
|
fill: rgba(0, 0, 0, 0); |
|
} |
|
|
|
.point:hover circle { |
|
stroke: red; |
|
stroke-width: 3px; |
|
} |
|
|
|
rect.key { |
|
stroke-width: 0px; |
|
opacity: 0.4; |
|
} |
|
|
|
path.line { |
|
fill: none; |
|
stroke: black; |
|
stroke-width: 3px; |
|
} |
|
|
|
line.grid { |
|
fill: none; |
|
shape-rendering: crispEdges; |
|
stroke: white; |
|
stroke-width: 1px; |
|
} |
|
|
|
line.threshold { |
|
fill: none; |
|
shape-rendering: crispEdges; |
|
stroke: darkred; |
|
stroke-width: 2px; |
|
} |
|
|
|
line.cursor { |
|
stroke: grey; |
|
stroke-width: 1px; |
|
stroke-dasharray: 2, 2; |
|
} |
|
|
|
.clabel rect { |
|
stroke: red; |
|
fill: white; |
|
} |
|
|
|
.clabel text { |
|
text-anchor: middle; |
|
font-size: 9px; |
|
} |
|
|
|
.caption { |
|
text-anchor: middle; |
|
} |
|
|
|
.axis path, |
|
.axis line { |
|
fill: none; |
|
stroke: #000; |
|
shape-rendering: crispEdges; |
|
} |
|
|
|
.points text { |
|
margin-left: -5px; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<div class="container"> |
|
<div id="plot"></div> |
|
</div> |
|
<script type="text/javascript"> |
|
var margin = { top: 10, right: 10, bottom: 40, left: 40 }, |
|
width = 880, |
|
height = 300, |
|
distance = 100, |
|
min = -40, |
|
max = 100, |
|
threshold = 65; |
|
|
|
var voronoi = d3.voronoi() |
|
.extent([[-1, -1], [width + 1, height + 1]]); |
|
|
|
var color = d3.scaleLinear() |
|
.domain([min, 15, max]) |
|
.range(["#4575b4", "#ffffbf", "#a50026"]) |
|
.interpolate(d3.interpolateHcl); |
|
|
|
var x = d3.scaleLinear().domain([0, distance]).range([0, width]), |
|
y = d3.scaleLinear().domain([min, max]).range([height, 0]); |
|
|
|
var xAxis = d3.axisBottom().scale(x), |
|
yAxis = d3.axisLeft().scale(y); |
|
|
|
var val = d3.randomNormal(30, 10), |
|
delta = d3.randomNormal(0, 0.5), |
|
data = d3.range(distance).map(function (x) { return [x, val()]; }), |
|
xValue = function (d) { return x(d[0]); }, |
|
yValue = function (d) { return y(d[1]); }, |
|
textValue = function (d) { return d[1].toFixed(2); }; |
|
|
|
|
|
var line = line = d3.line() |
|
.x(xValue) |
|
.y(yValue); |
|
|
|
var svg = d3.select("#plot").append("svg") |
|
.attrs({ |
|
"width": width + margin.left + margin.right, |
|
"height": height + margin.top + margin.bottom |
|
}); |
|
|
|
var plot = svg.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
plot.selectAll(".key") |
|
.data(pair(y.ticks(40))) |
|
.enter().append("rect") |
|
.attrs({ |
|
"class": "key", |
|
"width": width, |
|
"x": 0, |
|
"y": function (d) { return y(d[1]); }, |
|
"height": function (d) { return y(d[0]) - y(d[1]); }, |
|
"fill": function (d) { return color((d[0] + d[1]) / 2); } |
|
}); |
|
|
|
plot.selectAll("line.hgrid") |
|
.data(y.ticks(10)) |
|
.enter().append("line") |
|
.attrs({ |
|
"class": "hgrid grid", |
|
"x1": 0, |
|
"x2": width, |
|
"y1": function (d) { return y(d); }, |
|
"y2": function (d) { return y(d); } |
|
}); |
|
|
|
plot.selectAll("line.vgrid") |
|
.data(x.ticks(20)) |
|
.enter().append("line") |
|
.attrs({ |
|
"class": "vgrid grid", |
|
"y1": 0, |
|
"y2": height, |
|
"x1": function (d) { return x(d); }, |
|
"x2": function (d) { return x(d); } |
|
}); |
|
|
|
plot.append("line") |
|
.attrs({ |
|
"class": "threshold", |
|
"x1": 0, |
|
"x2": width, |
|
"y1": y(threshold), |
|
"y2": y(threshold) |
|
}); |
|
|
|
plot.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(0," + (height) + ")") |
|
.call(xAxis) |
|
.append("text") |
|
.text("Distance (Km)") |
|
.attrs({ |
|
"class": "caption", |
|
"x": width / 2, |
|
"y": 35 |
|
}); |
|
|
|
plot.append("g") |
|
.attr("class", "y axis") |
|
.call(yAxis) |
|
.append("text") |
|
.text("Temperature \u00B0C") |
|
.attrs({ |
|
"transform": "rotate(90)", |
|
"class": "caption", |
|
"x": height / 2, |
|
"y": 35 |
|
}); |
|
|
|
var graph = plot.append("path") |
|
.attr("class", "line") |
|
.datum(data) |
|
.attr("d", line); |
|
|
|
var vlabel = svg.append("g") |
|
.attrs({ |
|
"class": "clabel vlable", |
|
"transform": "translate(10," + height / 2 + ")" |
|
}) |
|
.style("display", "none"); |
|
|
|
vlabel.append("rect") |
|
.attrs({ |
|
"rx": 5, |
|
"ry": 5, |
|
"width": 30, |
|
"height": 20 |
|
}); |
|
|
|
vlabel.append("text") |
|
.attrs({ |
|
"x": 15, |
|
"y": 15 |
|
}); |
|
|
|
var hlabel = svg.append("g") |
|
.attrs({ |
|
"class": "clabel hlable", |
|
"transform": "translate(" + width / 2 + "," + (height + margin.top) + ")" |
|
}) |
|
.style("display", "none"); |
|
|
|
hlabel.append("rect") |
|
.attrs({ |
|
"rx": 5, |
|
"ry": 5, |
|
"width": 30, |
|
"height": 20 |
|
}); |
|
|
|
hlabel.append("text") |
|
.attrs({ |
|
"x": 15, |
|
"y": 15 |
|
}); |
|
|
|
plot.append("line") |
|
.attrs({ |
|
"class": "cursor vcursor", |
|
"y1": 0, |
|
"y2": height, |
|
}) |
|
.style("display", "none"); |
|
|
|
plot.append("line") |
|
.attrs({ |
|
"class": "cursor hcursor", |
|
"x1": 0, |
|
"x2": width, |
|
}) |
|
.style("display", "none"); |
|
var points = plot.append("g") |
|
.attr("class", "points"); |
|
|
|
update(); |
|
|
|
setInterval(update, 1000); |
|
|
|
plot.on("mousemove", function () { |
|
selectPoint(); |
|
}); |
|
|
|
plot.on("mouseleave", function () { |
|
plot.selectAll(".cursor") |
|
.style("display", "none"); |
|
svg.selectAll(".clabel") |
|
.style("display", "none"); |
|
}); |
|
|
|
function pair(array) { |
|
return array.slice(1).map(function (b, i) { |
|
return [array[i], b]; |
|
}); |
|
} |
|
|
|
function update() { |
|
var deltaT = d3.range(distance).map(function (x) { return [x, delta()]; }); |
|
data = data.map(function (x, i) { return [x[0], Math.min(max, Math.max(min, x[1] + deltaT[i][1]))]; }); |
|
var p = data.map(function (d) { return [x(d[0]), y(d[1])] }); |
|
|
|
var cells = voronoi.polygons(p); |
|
|
|
graph.datum(data) |
|
.transition().duration(500) |
|
.attr("d", line); |
|
|
|
var circles = points.selectAll("g.point") |
|
.data(data); |
|
|
|
var point = circles.enter() |
|
.append("g") |
|
.attr("class", "point"); |
|
|
|
point.append("circle") |
|
.attr("r", 5); |
|
|
|
point.append("path") |
|
.attr("class", "boundary"); |
|
|
|
circles.select("circle") |
|
.transition().duration(500) |
|
.attr("cx", xValue) |
|
.attr("cy", yValue) |
|
.attr("fill", function (d) { return color(d[1]) }); |
|
|
|
circles.select("path") |
|
.attr("d", function (d, i) { return "M" + cells[i].join("L") + "Z"; }); |
|
|
|
circles.exit().remove(); |
|
|
|
selectPoint(); |
|
} |
|
|
|
function selectPoint() { |
|
var k = points.select(".point:hover circle"); |
|
|
|
if (k.size() > 0) { |
|
var h = points.select(".point:hover").data()[0]; |
|
var t = [k.attr("cx"), k.attr("cy")]; |
|
|
|
hlabel.attr("transform", "translate(" + (t[0] + 25) + "," + (height + margin.top) + ")") |
|
.style("display", t[0] > 0 ? null : "none") |
|
.select("text") |
|
.text(h[0].toFixed(2)); |
|
|
|
plot.select(".vcursor") |
|
.attrs({ |
|
"x1": t[0], |
|
"x2": t[0] |
|
}) |
|
.style("display", t[0] > 0 ? null : "none"); |
|
|
|
vlabel.attr("transform", "translate(10," + t[1] + ")") |
|
.style("display", t[1] > 0 ? null : "none") |
|
.select("text") |
|
.text(h[1].toFixed(2)); |
|
|
|
plot.select(".hcursor") |
|
.attrs({ |
|
"y1": t[1], |
|
"y2": t[1] |
|
}) |
|
.style("display", t[1] > 0 ? null : "none"); |
|
} |
|
} |
|
</script> |
|
</body> |