Browse Source

New Chart abstraction and set up for solar chart

master
Nathan Bergey 6 years ago
parent
commit
754b33a23e
  1. 5
      src/index.js
  2. 241
      src/render.js

5
src/index.js

@ -1,6 +1,6 @@
var d3 = require('d3') var d3 = require('d3')
import {readxml} from './data.js' import {readxml} from './data.js'
import {render} from './render.js'
import {render_astronomy, render_temperature} from './render.js'
let canvas = d3.select('svg') let canvas = d3.select('svg')
@ -8,5 +8,6 @@ let canvas = d3.select('svg')
const url = '/forcast.xml' const url = '/forcast.xml'
d3.xml(url).then(function(xmldoc) { d3.xml(url).then(function(xmldoc) {
let data = readxml(xmldoc) let data = readxml(xmldoc)
render(canvas, data)
render_astronomy(canvas, 100, 25, data)
render_temperature(canvas, 600, 100, data)
}) })

241
src/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()
} }
Loading…
Cancel
Save