xxxxxxxxxx
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.0px;
}
.dot {
fill: white;
stroke: steelblue;
stroke-width: 0.5px;
}
.area {
fill: lightsteelblue;
stroke: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 150px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
/* pointer-events: none; This line needs to be removed */
}
</style>
<body>
<!-- load the d3.js library -->
<script type="text/javascript" src="https://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="moment.js"></script>
<script type="text/javascript" src="moment-timezone.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d %X").parse; //27-May-12 16:00:00. This is used for D3JS parsing
var formatTime = d3.time.format("%Y-%m-%d %X");// Format tooltip date / time
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.defined(function (d) { return d; }) // This is important to define to identify nulls and break the line.
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Define the area for min/max
var valuearea = d3.svg.area()
.defined(function (d) { return d; }) // This is important to define to identify nulls and break the line.
.x(function(d) { return x(d.date); })
.y1(function(d) { return y(d.max); })
.y0(function(d) { return y(d.min); });
// Define 'div' for tooltips
var div = d3.select("body")
.append("div") // declare the tooltip div
.attr("class", "tooltip")
.style("opacity", 0);
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.csv("datatips.csv", function(error, data) {
data.forEach(function(d) {
d.dateUTC = parseDate(moment.utc(d.date).format("YYYY-MM-DD HH:mm:ss")); // using moment to get proper UTC time and formatting for D3
d.date = parseDate(moment.tz(moment.utc(d.date).clone(), "America/Chicago").format("YYYY-MM-DD HH:mm:ss"));// Converting UTC time to US/Chicago time and formatting for D3 parseDate
d.close = +d.close;
d.min = +d.min;
d.max = +d.max;
});
var dateRange = d3.extent(data, function(d) { return d.date; });
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.max; })]);
var startDate = moment(dateRange[0]);
var endDate = moment(dateRange[1]);
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Define a function that finds all possible date time values given the selected date time range and aggregate type. If timezone is already taken care of (ideally, it should be taken care before here), we can eliminate it here.
function allDatesFun(startDate, endDate, timezone, aggType){
// I did not handle time series aggregate types. we need to know the sample rate for time series (for example 4 hz or 0.25 secs). This information needs parsing separately.
var allDates = [];
var intervalVal = Math.round(aggType.substr(0,aggType.length-1));
var intervalType = aggType.substr(-1).toLowerCase();
do {
allDates.push({dateT: parseDate(moment.tz(moment(startDate._d), timezone).format("YYYY-MM-DD HH:mm:ss"))});
startDate = startDate.clone().add(intervalVal, intervalType);
}
while (startDate <= endDate);
return allDates;
}
var allDates = allDatesFun(startDate, endDate, "America/Chicago", "1H");
function join(dataTable, allTable, dataTableKey, allTableKey, select) {
var l = dataTable.length,
m = allTable.length,
lookupIndex = [],
output = [];
for (var i = 0; i < l; i++) { // loop through l items
var row = dataTable[i];
lookupIndex[row[dataTableKey]] = row; // create an index for lookup table
}
for (var j = 0; j < m; j++) { // loop through m items
var y = allTable[j];
var x = lookupIndex[y[allTableKey]]; // get corresponding row from lookupTable
output.push(select(y, x)); // select only the columns you need
}
return output;
}
// here we are identifying gaps and marking the object null corresponding to missing data
data = join(data, allDates, "date", "dateT", function(allDateObject, dataObject) {
return (dataObject !== undefined)? dataObject: null;
});
// Add the valuearea path.
svg.append("path")
.attr("class", "area")
.attr("d", valuearea(data));
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// draw the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.filter(function(d) { return (d !== null) })
.attr("class", "dot")
.attr("r", 2)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); })
// Tooltip stuff after this
.on("mouseover", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(
'<a href= "'+d.link+'" target="_blank">' + //with a link
formatTime(d.date) +
"</a>" +
"<br/>" + d.close)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
});
});
</script>
</body>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js