Nathan Bergey
6 years ago
2 changed files with 155 additions and 91 deletions
-
5src/index.js
-
241src/render.js
@ -1,110 +1,173 @@ |
|||||
var d3 = require('d3') |
var d3 = require('d3') |
||||
|
|
||||
|
|
||||
export function render(canvas, data) { |
|
||||
const xWidth = canvas.node().getBoundingClientRect().width |
|
||||
const yHeight = canvas.node().getBoundingClientRect().height |
|
||||
const xMargin = 50 |
|
||||
const yMargin = 25 |
|
||||
const nElements = data.startTimes.length |
|
||||
|
|
||||
const beginTime = new Date( |
|
||||
data.startTimes[0].getFullYear(), |
|
||||
data.startTimes[0].getMonth(), |
|
||||
data.startTimes[0].getDate(), |
|
||||
0,0,0 |
|
||||
) |
|
||||
|
|
||||
const xRange = d3.scaleTime() |
|
||||
.domain([beginTime, data.endTimes[nElements - 1]]) |
|
||||
.range([xMargin, xWidth]) |
|
||||
const yRange = d3.scaleLinear() |
|
||||
.domain([-15, 45]) |
|
||||
.range([yHeight - yMargin, 0]) |
|
||||
|
|
||||
const xLine = function (location, style) { |
|
||||
canvas.append('line') |
|
||||
.attr('class', style) |
|
||||
.attr('x1', xMargin) |
|
||||
.attr('x2', xWidth) |
|
||||
.attr('y1', yRange(location)) |
|
||||
.attr('y2', yRange(location)) |
|
||||
|
class Chart { |
||||
|
constructor(canvas, height, width, margin, offset, data, yrange) { |
||||
|
this.canvas = canvas |
||||
|
this.height = height |
||||
|
this.width = width |
||||
|
this.margin = margin |
||||
|
this.offset = offset |
||||
|
this.data = data |
||||
|
|
||||
|
this.beginTime = new Date( |
||||
|
data.startTimes[0].getFullYear(), |
||||
|
data.startTimes[0].getMonth(), |
||||
|
data.startTimes[0].getDate(), |
||||
|
0,0,0 |
||||
|
) |
||||
|
this.endTime = data.endTimes[data.endTimes.length - 1] |
||||
|
this.yRange = d3.scaleLinear() |
||||
|
.domain(yrange) |
||||
|
.range([this.height - this.margin.bottom, offset]) |
||||
|
this.xRange = d3.scaleTime() |
||||
|
.domain([this.beginTime, this.endTime]) |
||||
|
.range([margin.left, width]) |
||||
|
} |
||||
|
|
||||
|
draw_yAxisLine() { |
||||
|
this.canvas.append('line').attr('class', 'axis') |
||||
|
.attr('x1', this.margin.left).attr('y1', this.offset) |
||||
|
.attr('x2', this.margin.left).attr('y2', this.height - this.margin.bottom) |
||||
|
} |
||||
|
|
||||
|
draw_xAxisLineTop() { |
||||
|
this.canvas.append('line').attr('class', 'axis') |
||||
|
.attr('x1', this.margin.left).attr('y1', this.offset) |
||||
|
.attr('x2', this.width).attr('y2', this.offset) |
||||
|
} |
||||
|
|
||||
|
draw_xAxisLineBottom() { |
||||
|
this.canvas.append('line').attr('class', 'axis') |
||||
|
.attr('x1', this.margin.left).attr('y1', this.height - this.margin.bottom) |
||||
|
.attr('x2', this.width).attr('y2', this.height - this.margin.bottom) |
||||
|
} |
||||
|
|
||||
|
draw_yAxisTitle(title) { |
||||
|
const middle = (this.offset + this.height - this.margin.bottom) / 2.0 |
||||
|
const x = 15 |
||||
|
this.canvas.append('text').attr('class', 'axis-title') |
||||
|
.attr('text-anchor', 'middle').attr('dominant-baseline', 'middle') |
||||
|
.attr('transform', 'rotate(-90,' + x + ',' + middle + ')') |
||||
|
.attr('x', x).attr('y', middle) |
||||
|
.text(title) |
||||
|
} |
||||
|
|
||||
|
set_yAxisTic(value, label) { |
||||
|
this.canvas.append('line').attr('class', 'axis') |
||||
|
.attr('x1', this.margin.left - 4).attr('y1', this.yRange(value)) |
||||
|
.attr('x2', this.margin.left).attr('y2', this.yRange(value)) |
||||
|
this.canvas.append('text').attr('class', 'axis-label') |
||||
|
.attr('text-anchor', 'end').attr('dominant-baseline', 'middle') |
||||
|
.attr('x', this.margin.left - 6).attr('y', this.yRange(value)) |
||||
|
.text(label) |
||||
} |
} |
||||
const yLine = function (date, style) { |
|
||||
canvas.append('line') |
|
||||
.attr('class', style) |
|
||||
.attr('x1', xRange(date)) |
|
||||
.attr('x2', xRange(date)) |
|
||||
.attr('y1', 0) |
|
||||
.attr('y2', yHeight - yMargin) |
|
||||
|
|
||||
|
set_xAxisTic(value, label) { |
||||
|
this.canvas.append('text').attr('class', 'axis-label') |
||||
|
.attr('text-anchor', 'middle').attr('dominant-baseline', 'alphabetic') |
||||
|
.attr('x', this.xRange(value)).attr('y', this.offset - 5) |
||||
|
.text(label) |
||||
} |
} |
||||
const xAxisLabel = function (date) { |
|
||||
canvas.append('text') |
|
||||
.attr('class', 'axis-label') |
|
||||
.attr('text-anchor', 'middle') |
|
||||
.attr('dominant-baseline', 'alphabetic') |
|
||||
.attr('x', xRange(date)) |
|
||||
.attr('y', yHeight - yMargin + 12) |
|
||||
.text(date.toLocaleDateString('en-US', {weekday: 'long'})) |
|
||||
|
|
||||
|
draw_yGrid(value, style) { |
||||
|
this.canvas.append('line').attr('class', style) |
||||
|
.attr('x1', this.xRange(value)).attr('y1', this.offset) |
||||
|
.attr('x2', this.xRange(value)).attr('y2', this.height - this.margin.bottom) |
||||
} |
} |
||||
const yAxisLabel = function (value) { |
|
||||
canvas.append('text') |
|
||||
.attr('class', 'axis-label') |
|
||||
.attr('text-anchor', 'end') |
|
||||
.attr('dominant-baseline', 'middle') |
|
||||
.attr('x', xMargin - 5) |
|
||||
.attr('y', yRange(value)) |
|
||||
.text(value + ' °C') |
|
||||
|
|
||||
|
draw_xGrid(value, style) { |
||||
|
this.canvas.append('line').attr('class', style) |
||||
|
.attr('x1', this.margin.left).attr('y1', this.yRange(value)) |
||||
|
.attr('x2', this.width).attr('y2', this.yRange(value)) |
||||
} |
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Sun and moon chart |
||||
|
*/ |
||||
|
export function render_astronomy(canvas, height, offset, data) { |
||||
|
const fullWidth = canvas.node().getBoundingClientRect().width |
||||
|
const margins = { |
||||
|
'left': 75, |
||||
|
'bottom': 10 |
||||
|
} |
||||
|
const yrange = [0, 75] |
||||
|
const chart = new Chart(canvas, height, fullWidth, margins, offset, data, yrange) |
||||
|
|
||||
|
chart.draw_yAxisTitle('Altitude') |
||||
|
chart.set_yAxisTic( 0, '0°') |
||||
|
chart.set_yAxisTic(45, '45°') |
||||
|
chart.set_yAxisTic(75, '75°') |
||||
|
|
||||
|
const year = chart.beginTime.getFullYear() |
||||
|
const month = chart.beginTime.getMonth() |
||||
|
|
||||
|
for (var day = chart.beginTime.getDate(); day <= chart.endTime.getDate(); day++) { |
||||
|
const noon = new Date(year, month, day, 12, 0, 0) |
||||
|
chart.set_xAxisTic(noon, noon.toLocaleDateString('en-US', {weekday: 'long'})) |
||||
|
chart.draw_yGrid(noon, 'noon') |
||||
|
|
||||
|
// Don't draw the first midnight line because that's also our yAxis line
|
||||
|
if (day != chart.beginTime.getDate()) { |
||||
|
const midnight = new Date(year, month, day, 0, 0, 0) |
||||
|
chart.draw_yGrid(midnight, 'midnight') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
chart.draw_yAxisLine() |
||||
|
chart.draw_xAxisLineTop() |
||||
|
chart.draw_xAxisLineBottom() |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function render_temperature(canvas, height, offset, data) { |
||||
|
const fullWidth = canvas.node().getBoundingClientRect().width |
||||
|
const margins = { |
||||
|
'left': 75, |
||||
|
'bottom': 10 |
||||
|
} |
||||
|
const yrange = [-15, 45] |
||||
|
const chart = new Chart(canvas, height, fullWidth, margins, offset, data, yrange) |
||||
|
|
||||
const line = d3.line() |
const line = d3.line() |
||||
.x(function(d) { return xRange(d.date) }) |
|
||||
.y(function(d) { return yRange(d.temp) }) |
|
||||
|
.x(function(d) { return chart.xRange(d.date) }) |
||||
|
.y(function(d) { return chart.yRange(d.temp) }) |
||||
.curve(d3.curveBasis) |
.curve(d3.curveBasis) |
||||
|
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||
// Paint
|
|
||||
|
chart.draw_yAxisTitle('Temperature') |
||||
|
chart.set_yAxisTic(-10, '-10 °C') |
||||
|
chart.draw_xGrid( -10, 'guide') |
||||
|
chart.set_yAxisTic( 0, '0 °C') |
||||
|
chart.draw_xGrid( 0, 'zero') |
||||
|
chart.set_yAxisTic( 12, '12 °C') |
||||
|
chart.draw_xGrid( 12, 'guide') |
||||
|
chart.set_yAxisTic( 22, '22 °C') |
||||
|
chart.draw_xGrid( 22, 'guide') |
||||
|
chart.set_yAxisTic( 30, '30 °C') |
||||
|
chart.draw_xGrid( 30, 'hot') |
||||
|
chart.set_yAxisTic( 40, '40 °C') |
||||
|
chart.draw_xGrid( 40, 'guide') |
||||
|
|
||||
yLine(Date.now(), 'now') |
|
||||
for (let time of data.startTimes) { |
|
||||
if (time.getHours() === 0) { |
|
||||
yLine(time, 'midnight') |
|
||||
} |
|
||||
if (time.getHours() === 12) { |
|
||||
yLine(time, 'noon') |
|
||||
xAxisLabel(time) |
|
||||
|
const year = chart.beginTime.getFullYear() |
||||
|
const month = chart.beginTime.getMonth() |
||||
|
for (var day = chart.beginTime.getDate(); day <= chart.endTime.getDate(); day++) { |
||||
|
const noon = new Date(year, month, day, 12, 0, 0) |
||||
|
chart.draw_yGrid(noon, 'noon') |
||||
|
// Don't draw the first midnight line because that's also our yAxis line
|
||||
|
if (day != chart.beginTime.getDate()) { |
||||
|
const midnight = new Date(year, month, day, 0, 0, 0) |
||||
|
chart.draw_yGrid(midnight, 'midnight') |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
xLine(-10, 'guide') |
|
||||
xLine( 0, 'zero') |
|
||||
xLine( 12, 'guide') |
|
||||
xLine( 22, 'guide') |
|
||||
xLine( 30, 'hot') |
|
||||
xLine( 40, 'guide') |
|
||||
yAxisLabel(-10) |
|
||||
yAxisLabel(0) |
|
||||
yAxisLabel(12) |
|
||||
yAxisLabel(22) |
|
||||
yAxisLabel(30) |
|
||||
yAxisLabel(40) |
|
||||
|
|
||||
canvas.append('path') |
canvas.append('path') |
||||
.data([data.temperature]) |
.data([data.temperature]) |
||||
.attr('class', 'data') |
.attr('class', 'data') |
||||
.attr('d', line) |
.attr('d', line) |
||||
|
|
||||
// Axis Lines
|
|
||||
canvas.append('line') |
|
||||
.attr('class', 'axis') |
|
||||
.attr('x1', xMargin) |
|
||||
.attr('x2', xMargin) |
|
||||
.attr('y1', 0) |
|
||||
.attr('y2', yHeight - yMargin) |
|
||||
canvas.append('line') |
|
||||
.attr('class', 'axis') |
|
||||
.attr('x1', xMargin) |
|
||||
.attr('x2', xWidth) |
|
||||
.attr('y1', yHeight - yMargin) |
|
||||
.attr('y2', yHeight - yMargin) |
|
||||
|
chart.draw_yAxisLine() |
||||
|
chart.draw_xAxisLineTop() |
||||
|
chart.draw_xAxisLineBottom() |
||||
} |
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue