Browse Source

Cloud coverage chart with lots of realignment

master
Nathan Bergey 5 years ago
parent
commit
db718e185f
  1. 58
      src/data.js
  2. 16
      src/index.js
  3. 60
      src/render.js
  4. 8
      src/style.sass

58
src/data.js

@ -1,50 +1,72 @@
var d3 = require('d3')
export function readxml(xmldoc) {
let forcast = xmldoc.childNodes[0]
let data = forcast.children[1]
const forcast = xmldoc.childNodes[0]
const data = forcast.children[1]
// Time
let times = data.getElementsByTagName('time-layout')[0]
var startTimes = []
const times = data.getElementsByTagName('time-layout')[0]
let startTimes = []
for (let time of times.getElementsByTagName('start-valid-time')) {
let date = new Date(time.textContent)
const date = new Date(time.textContent)
startTimes.push(date)
}
var endTimes = []
let endTimes = []
for (let time of times.getElementsByTagName('end-valid-time')) {
let date = new Date(time.textContent)
const date = new Date(time.textContent)
endTimes.push(date)
}
// Temperature
var temperatures = []
let temperatures = []
for (let temp_type of data.getElementsByTagName('temperature')) {
if (temp_type.attributes.type.nodeValue === 'hourly') {
for (let temp of temp_type.getElementsByTagName('value')) {
let degC = (parseFloat(temp.textContent) - 32) * (5.0/9.0)
const degC = (parseFloat(temp.textContent) - 32) * (5.0/9.0)
temperatures.push(degC)
}
}
}
// Cloud Cover
let cloudCover = []
const clouds = data.getElementsByTagName('cloud-amount')[0]
for (let cloud of clouds.getElementsByTagName('value')) {
cloudCover.push(parseFloat(cloud.textContent))
}
// Map
let nElements = startTimes.length
var forcastData = []
const nElements = startTimes.length
let forcastData = []
let cloudData = []
cloudData.push({
date: startTimes[0],
coverage: 0
})
for (var i = 0; i < nElements; i++) {
let midtimeScale = d3.scaleTime()
const midtimeScale = d3.scaleTime()
.domain([0, 1])
.range([startTimes[i], endTimes[i]])
let midpointTime = midtimeScale(0.5)
const midpointTime = midtimeScale(0.5)
forcastData.push({
'date': midpointTime,
'temp': temperatures[i]
date: midpointTime,
temp: temperatures[i]
})
cloudData.push({
date: midpointTime,
coverage: cloudCover[i]
})
}
cloudData.push({
date: endTimes[endTimes.length - 1],
coverage: 0
})
return {
'startTimes': startTimes,
'endTimes': endTimes,
'temperature': forcastData
startTimes: startTimes,
endTimes: endTimes,
temperature: forcastData,
clouds: cloudData
}
}

16
src/index.js

@ -1,6 +1,6 @@
var d3 = require('d3')
import {readxml} from './data.js'
import {render_calendar, render_nights, render_astronomy, render_temperature} from './render.js'
import {render_calendar, render_nights, render_astronomy, render_temperature, render_clouds} from './render.js'
const canvas = d3.select('svg')
@ -24,10 +24,16 @@ const render = function (data) {
const width = canvas.node().getBoundingClientRect().width
const height = canvas.node().getBoundingClientRect().height
render_calendar(canvas, width, 20, 0, data)
render_nights(canvas, width, height - 20, 20, data)
render_astronomy(canvas, width, 70, 20, data)
render_temperature(canvas, width, 350, 70, data)
const calHeight = 20
const astroHeight = 50
const tempHeight = 300
const cloudHeight = height - (calHeight +tempHeight + astroHeight)
render_calendar(canvas, width, calHeight, 0, data)
render_nights(canvas, width, height - calHeight, calHeight, data)
render_astronomy(canvas, width, astroHeight, calHeight, data)
render_temperature(canvas, width, tempHeight, calHeight + astroHeight, data)
render_clouds(canvas, width, cloudHeight, calHeight + astroHeight + tempHeight, data)
}
d3.xml(url).then(function(xmldoc) {

60
src/render.js

@ -14,9 +14,12 @@ class Chart {
this.margin = margin
this.data = data
this.top = offset + margin.top
this.bottom = offset + height - margin.bottom
this.yRange = d3.scaleLinear()
.domain(yrange)
.range([height - margin.bottom, offset])
.range([this.bottom, this.top])
this.xRange = d3.scaleTime()
.domain([data.beginTime, data.endTime])
.range([margin.left, width - margin.right])
@ -24,24 +27,24 @@ class Chart {
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)
.attr('x1', this.margin.left).attr('y1', this.top)
.attr('x2', this.margin.left).attr('y2', this.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)
.attr('x1', this.margin.left).attr('y1', this.top)
.attr('x2', this.width - this.margin.right).attr('y2', this.top)
}
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)
.attr('x1', this.margin.left).attr('y1', this.bottom)
.attr('x2', this.width - this.margin.right).attr('y2', this.bottom)
}
draw_yAxisTitle(title) {
const middle = (this.offset + this.height - this.margin.bottom) / 2.0
const middle = (this.top - this.bottom) / 2.0
const x = 15
this.canvas.append('text').attr('class', 'axis-title')
.attr('text-anchor', 'middle').attr('dominant-baseline', 'middle')
@ -63,11 +66,11 @@ class Chart {
set_xAxisTic(value, label, anchor) {
const x = this.xRange(value)
this.canvas.append('line').attr('class', 'axis')
.attr('x1', x).attr('y1', this.height - this.margin.bottom)
.attr('x2', x).attr('y2', this.height - this.margin.bottom + 2)
.attr('x1', x).attr('y1', this.bottom)
.attr('x2', x).attr('y2', this.bottom + 2)
this.canvas.append('text').attr('class', 'axis-label')
.attr('text-anchor', anchor).attr('dominant-baseline', 'hanging')
.attr('x', x).attr('y', this.height - this.margin.bottom + 1)
.attr('x', x).attr('y', this.bottom + 1)
.text(label)
}
@ -209,7 +212,7 @@ export function render_astronomy(canvas, width, height, offset, data) {
const x = chart.xRange(data.beginTime)
const box_width = chart.xRange(data.endTime) - x
canvas.append('rect').attr('class', 'blank')
.attr('x', x).attr('y', height - margin.bottom)
.attr('x', x).attr('y', offset + height - margin.bottom)
.attr('width', box_width)
.attr('height', margin.bottom)
@ -282,7 +285,7 @@ export function render_temperature(canvas, width, height, offset, data) {
const margin = {
top: 0,
left: leftMargin,
bottom: 12,
bottom: 5,
right: 0
}
const yrange = [-15, 45]
@ -316,3 +319,34 @@ export function render_temperature(canvas, width, height, offset, data) {
//chart.draw_xAxisLineTop()
chart.draw_xAxisLineBottom()
}
export function render_clouds(canvas, width, height, offset, data) {
const margin = {
top: 0,
left: leftMargin,
bottom: 10,
right: 0
}
const yrange = [0, 100]
const chart = new Chart(canvas, width, height, offset, margin, data, yrange)
const line = d3.line()
.x(function(d) { return chart.xRange(d.date) })
.y(function(d) { return chart.yRange(d.coverage) })
.curve(d3.curveBasis)
//chart.draw_xAxisLineTop()
chart.set_yAxisTic( 0, '0%')
chart.set_yAxisTic( 50, '50%')
chart.draw_xGrid( 50, 'guide')
chart.set_yAxisTic(100, '100%')
chart.draw_xGrid( 100, 'guide')
canvas.append('path')
.data([data.clouds])
.attr('class', 'clouds')
.attr('d', line)
chart.draw_xAxisLineBottom()
}

8
src/style.sass

@ -45,9 +45,6 @@ h1.title
path, line
fill: none
line
shape-rendering: crispEdges
#calendar .axis
stroke: #bbb
stroke-width: 1px
@ -74,6 +71,11 @@ path.moon
stroke: #999
stroke-width: 1px
path.clouds
opacity: 0.7
stroke: #bbb
fill: #ddd
line.now
stroke: #f5f
stroke-width: 1px

Loading…
Cancel
Save