diff --git a/client/d3/bar/horizontal.js b/client/d3/bar/horizontal.js index a461260..4165473 100644 --- a/client/d3/bar/horizontal.js +++ b/client/d3/bar/horizontal.js @@ -42,7 +42,7 @@ class HorizontalBarChart extends BarChart { bbox = elem.getBBox(), middleX = bbox.x + (bbox.width / 2), middleY = bbox.y + (bbox.height / 2); - return "rotate(-30,"+middleX + "," + middleY+")" + return "rotate(-30,"+middleX + "," + middleY+")"; }); bar_chart.x_scale.domain([0, data.max]); @@ -68,7 +68,7 @@ class HorizontalBarChart extends BarChart { .attr("height", bar_chart.y_scale.rangeBand()) .attr("x", function(d) { return bar_chart.x_scale(d.cummulative); }) .attr("width", function(d) { return bar_chart.x_scale(d.value); }) - .attr("opacity", function(d) { return d.opacity; }) + .attr("opacity", function(d) { return d.opacity; }); } } diff --git a/client/d3/base.js b/client/d3/base.js index 093e65e..482ad6b 100644 --- a/client/d3/base.js +++ b/client/d3/base.js @@ -1,3 +1,5 @@ +import extend from 'extend'; + const DEFAULTS = { outer_width: 500, outer_height: 300, @@ -10,8 +12,9 @@ const DEFAULTS = { domain_attr: undefined, range_attr: undefined, titleize: function(series, datum){ - var s = datum ? datum.name : series.name, - words = s.split(' '), + var s = datum ? datum.name : series.title; + if (!s) return ''; + var words = s.split(' '), array = []; for (var i=0; i{ return n+1; })) + .rangeRoundBands([0, grid_chart.width], grid_chart.grid_padding, 0); grid_chart.x_axis = d3.svg.axis() .scale(grid_chart.x_scale) - .orient("top"); + .orient("top") + .outerTickSize(0); - // append axes - grid_chart.svg.append("g") - .attr("class", "d3-chart-domain d3-chart-axis"); - grid_chart.svg.append("g") - .attr("class", "d3-chart-range d3-chart-axis") - .attr("transform", "translate(0, " + (grid_chart.height - grid_chart.margin.top) + ")"); + // append x axis + grid_chart.svg.append("g").attr("class", "d3-chart-domain d3-chart-axis"); } afterAxes(){ var grid_chart = this; - grid_chart.day_length = grid_chart.width / 31 - grid_chart.grid_padding * 30; - if (grid_chart.parse_date_format) grid_chart.parseDate = d3.time.format(grid_chart.parse_date_format); + grid_chart.grid_unit_size = grid_chart.width / 31 - grid_chart.grid_padding * grid_chart.width / 30; + if (grid_chart.display_date_format) grid_chart.displayDate = d3.time.format(grid_chart.display_date_format); + + if (!grid_chart.toDate && grid_chart.parse_date_format){ + grid_chart.parseDate = d3.time.format(grid_chart.parse_date_format); + grid_chart.toDate = (datum)=>{ + grid_chart.parseDate(datum[grid_chart.date_attr]); + } + } else if (!grid_chart.toDate){ + grid_chart.toDate = (datum)=>{ return datum[grid_chart.date_attr] }; + } + + grid_chart.monthFormat = d3.time.format('%B %Y'); + grid_chart.toMonthString = (datum)=>{ + return grid_chart.monthFormat(grid_chart.toDate(datum)); + } } serializeData(data){ - var grid_chart = this, - serialized_data = { - series: data - }; - serialized_data.css_class = data.css_class || bar_chart.toClass ? bar_chart.toClass(data_set) : ""; - serialized_data.title = bar_chart.titleize ? bar_chart.titleize(data_set) : ""; + var grid_chart = this; + data.css_class = data.css_class || grid_chart.toClass ? grid_chart.toClass(data) : ""; - toDate = grid_chart.parseDate ? (d)=>{ return grid_chart.parseDate(d[grid_chart.date_attr]); } : (d)=>{ return d[grid_chart.date_attr] }; + grid_chart.rangeValue = grid_chart.range_attr ? function(d){ return d[grid_chart.range_attr]; } : grid_chart.rangeValue; - var min_range = grid_chart.extent[0] || 0, - max_range = grid_chart.extent[1] || 0; - serialized_data.months = []; - series.values.forEach((value)=>{ - var date = toDate(value), - date_s = grid_chart.monthFormat(value); + data.months = []; + if (data.min_range !== undefined && data.max_range !== undefined){ + data.range = {min: data.min_range, max: data.max_range}; + data.values.forEach((value)=>{ + var date = grid_chart.toDate(value), + date_s = grid_chart.monthFormat(date); + if (data.months.indexOf(date_s) < 0) data.months.push(date_s); + }); + } else { + var min_range = Infinity, + max_range = -Infinity; + data.values.forEach((value)=>{ + var date = grid_chart.toDate(value), + date_s = grid_chart.monthFormat(date), + range_value =grid_chart.rangeValue(value); + min_range = Math.min(min_range, range_value); + max_range = Math.max(max_range, range_value); + if (data.months.indexOf(date_s) < 0) data.months.push(date_s); + }); + if (grid_chart.min_range_zero) min_range = Math.min(min_range, 0); + data.range = { min: min_range, max: max_range }; + } + data.range.diff = data.range.max - data.range.min; - min_range = Math.min(0, min_range, value[grid_chart.range_attr]); - max_range = Math.max(max_range, value[grid_chart.range_attr]); - if (serialized_data.months.indexOf(date_s) < 0) serialized_data.months.push(date_s); + data.months = data.months.sort((date_s1, date_s2)=>{ + var date1 = grid_chart.monthFormat.parse(date_s1), + date2 = grid_chart.monthFormat.parse(date_s2); + return date1.getTime() - date2.getTime(); }); - serialized_data.range ={ - min: min_range, - max: max_range, - diff: max_range - min_range }; - - serialized_data.months = serialized_data.months.sort((date_s1, date_s2)=>{ - var date1 = grid_chart.monthFormat(date_s1), - date2 = grid_chart.monthFormat(date_s2); - return date1.toTime() - date2.toTime(); - }); - return serialized_data; + return data; }; drawData(data){ @@ -86,35 +106,45 @@ class CalendarGridChart extends Chart{ data = grid_chart.serializeData(data); // calibrate axes + var y_axis_height = grid_chart.grid_unit_size * (1 + grid_chart.grid_padding) * data.months.length; + grid_chart.y_scale.rangeRoundBands([0, y_axis_height], grid_chart.grid_padding, 0); grid_chart.y_scale.domain(data.months); + grid_chart.y_axis.scale(grid_chart.y_scale); + grid_chart.svg.select(".d3-chart-range") .call(grid_chart.y_axis); - grid_chart.x_scale.domain([1, 31]); grid_chart.svg.select(".d3-chart-domain").call(grid_chart.x_axis); - var grid_units = grid_chart.svg.selectAll(".d3-chart-grid-unit" + series.css_class) - .data(data.series.values); - grid_chart.applyData(data.series, grid_units.enter().append("rect")); - grid_chart.applyData(data.series, grid_units.transition()); + var grid_units = grid_chart.svg.selectAll(".d3-chart-grid-unit") + .data(data.values); + grid_chart.applyData(data, grid_units.enter().append("rect")); + grid_chart.applyData(data, grid_units.transition()); grid_units.exit().remove(); } // helper method for drawData. - applyData(series, elements){ + applyData(data, elements){ var grid_chart = this, - series_class = "d3-chart-grid-unit " + series.css_class; + series_class = "d3-chart-grid-unit " + data.css_class; elements - .attr("class", function(d){ return series_class + " " + d.css_class; }) - .attr("y", function(d) { return grid_chart.y_scale(grid_chart.monthFormat(d[grid_chart.date_attr])); }) - .attr("height", grid_chart.y_scale.rangeBand()) - .attr("x", function(d) { return d[grid_chart.date_attr].getDate(); }) - .attr("width", function(d) { return grid_chart.x_scale.rangeBand(); }) - .attr("opacity", function(d) { return grid_chart.applyOpacity(d[grid_chart.range_attr], series.range); }) + .attr("class", function(d){ return series_class; }) + .attr("y", function(d) { + var bottom = grid_chart.y_scale(grid_chart.toMonthString(d)), + middle = grid_chart.y_scale.rangeBand() / 2 - grid_chart.grid_unit_size / 2; + return bottom + middle; + }) + .attr("height", grid_chart.grid_unit_size) + .attr("x", function(d) { + return grid_chart.x_scale(grid_chart.toDate(d).getDate()); + }) + .attr("width", function(d) { return grid_chart.grid_unit_size; }) + .attr('fill', grid_chart.color) + .attr("opacity", function(d) { return grid_chart.applyOpacity(grid_chart.rangeValue(d), data.range); }); } applyOpacity(value, range){ - return (value - range.max) / range.diff; + return Math.max(0, Math.min(1, 1 - (range.max - (value - range.min)) / range.diff)); }; } diff --git a/client/d3/line/spline_stack.js b/client/d3/line/spline_stack.js index 4f2716b..0e9907c 100644 --- a/client/d3/line/spline_stack.js +++ b/client/d3/line/spline_stack.js @@ -2,7 +2,6 @@ import LineChart from './line'; const INTERPOLATION = 'cardinal'; - // inspired by https://bl.ocks.org/mbostock/3885211 class SplineStackChart extends LineChart { @@ -28,14 +27,19 @@ class SplineStackChart extends LineChart { spline_stack.defineAxes(); } + get chart_options(){ + return { + interpolation: INTERPOLATION + }; + } + serializeData(data){ var spline_stack = this, serialized_data = { range_min: -Infinity, range_max: Infinity, domain_min: -Infinity, - domain_max: Infinity - }; + domain_max: Infinity }; data.series.forEach(function(series, i){ series.css_class = series.css_class || spline_stack.toClass ? spline_stack.toClass(series) : ""; diff --git a/client/dashboard/energy/energy.js b/client/dashboard/energy/energy.js new file mode 100644 index 0000000..a43899f --- /dev/null +++ b/client/dashboard/energy/energy.js @@ -0,0 +1,110 @@ +import React from 'react'; +import energyRt from './energy.rt.js'; +import House from './../../models/house'; +import CalendarGridChart from './../../d3/grid/calendar_grid'; + +var Energy = React.createClass({ + + getInitialState: function(){ + var energy = this; + return { + view: 'graph', + graph_attr: 'production', + loading_data: true + }; + }, + + handleResize: function(e) { + this.setState({windowWidth: window.innerWidth}); + }, + + componentDidMount: function() { + // window.addEventListener('resize', this.handleResize); + var energy = this, + house = energy.props.house; + energy.graph_title = 'Daily Consumption'; + house.ensureEnergyData().then(()=>{ + energy.setState({loading_data: false}); + energy.initGraph(); + }); + }, + + componentWillReceiveProps: function(new_props){ + var energy = this; + energy.setState({loading_data: true}); + if (new_props.house !== energy.state.house){ + new_props.house.ensureEnergyData().then(()=>{ + energy.setState({loading_data: false}); + if (energy.state.view === 'graph') energy.initGraph(); + }); + } + }, + + setView: function(event){ + var energy = this, + view = event.target.dataset.value, + house = energy.props.house; + if (view !== energy.state.view){ + energy.setState({view: view}); + if (energy.state.view === 'graph') energy.initGraph(); + } + }, + + setGraphAttr: function(event){ + var energy = this, + graph_attr = event.target.dataset.value; + if (graph_attr !== energy.state.graph_attr){ + energy.graph_title = 'Daily ' + event.target.innerText; + energy.setState({ + graph_attr: graph_attr + }, function(){ + if (energy.state.view === 'graph') energy.updateGraph(); + }) + } + }, + + initGraph: function(){ + var energy = this; + if (energy.graph === undefined){ + document.getElementById('energy_graph').innerHTML = ''; + energy.graph = new CalendarGridChart({ + container: '#energy_graph', + outer_width: 800, + outer_height: 200, + date_attr: 'day', + color: '#0404B4', + toDate: (energy_datum)=>{ return energy_datum.data.day.toDate(); } + }); + jQuery('#energy_graph').tooltip({ + selector: '.d3-chart-grid-unit', + container: 'body', + title: function(){ + var energy_datum = this.__data__, + date_s = d3.time.format('%a %b %d, %Y')(energy_datum.data.day.toDate()), + range_value = `${Math.round(energy_datum.data[energy.state.graph_attr])} kWh`; + return `${date_s}: ${range_value}`; + } + }); + } + energy.updateGraph(); + }, + + updateGraph: function(){ + var energy = this, + house = energy.props.house; + energy.graph.rangeValue = (datum)=>{ return datum.data[energy.state.graph_attr]; } + energy.graph.drawData({ + title: energy.graph_title, + css_class: '', + min_range: 0, + max_range: 150, + values: house.energy_data + }); + }, + + render: function() { + return energyRt.call(this); + } +}); + +export default Energy; diff --git a/client/dashboard/energy/energy.rt b/client/dashboard/energy/energy.rt new file mode 100644 index 0000000..16e72d0 --- /dev/null +++ b/client/dashboard/energy/energy.rt @@ -0,0 +1,49 @@ +
+

Household Daily Energy

+
+ Retrieving energy data for the {this.props.house.name} household... +
+
+ + +

+
+ + +
+ + + + + + + + + + + + + + + + + +
DayConsumption (kWh)Production (kWh)
{energy_datum.day_to_s}{energy_datum.consumption_to_s}{energy_datum.production_to_s}
+
+
diff --git a/client/dashboard/energy/energy.rt.js b/client/dashboard/energy/energy.rt.js new file mode 100644 index 0000000..a999376 --- /dev/null +++ b/client/dashboard/energy/energy.rt.js @@ -0,0 +1,38 @@ +import React from 'react'; +import _ from 'lodash'; +function repeatEnergy_datum1(energy_datum, energy_datumIndex) { + return React.createElement('tr', { 'key': energy_datum.react_key }, React.createElement('td', {}), React.createElement('td', {}, energy_datum.day_to_s), React.createElement('td', {}, energy_datum.consumption_to_s), React.createElement('td', {}, energy_datum.production_to_s)); +} +export default function () { + return React.createElement('div', { 'id': 'energy_view' }, React.createElement('h2', {}, 'Household Daily Energy'), this.state.loading_data ? React.createElement('div', { 'className': 'alert alert-warning' }, '\n Retrieving energy data for the ', this.props.house.name, ' household...\n ') : null, React.createElement('div', { + 'className': 'btn-group', + 'role': 'group' + }, React.createElement('button', { + 'data-value': 'graph', + 'className': _.keys(_.pick({ active: this.state.view === 'graph' }, _.identity)).join(' ') + ' ' + 'btn btn-primary', + 'onClick': this.setView, + 'type': 'button' + }, 'Graph'), React.createElement('button', { + 'data-value': 'table', + 'className': _.keys(_.pick({ active: this.state.view === 'table' }, _.identity)).join(' ') + ' ' + 'btn btn-primary', + 'onClick': this.setView, + 'type': 'button' + }, 'Table')), React.createElement('br', {}), this.state.view === 'graph' ? React.createElement('div', { + 'className': 'btn-group', + 'role': 'group' + }, React.createElement('button', { + 'data-value': 'consumption', + 'className': _.keys(_.pick({ active: this.state.graph_attr === 'consumption' }, _.identity)).join(' ') + ' ' + 'btn btn-primary', + 'onClick': this.setGraphAttr, + 'type': 'button' + }, 'Consumption'), React.createElement('button', { + 'data-value': 'production', + 'className': _.keys(_.pick({ active: this.state.graph_attr === 'production' }, _.identity)).join(' ') + ' ' + 'btn btn-primary', + 'onClick': this.setGraphAttr, + 'type': 'button' + }, 'Production')) : null, this.state.view === 'table' ? React.createElement('table', { 'className': 'table' }, React.createElement('thead', {}, React.createElement('tr', {}, React.createElement('th', {}), React.createElement('th', {}, 'Day'), React.createElement('th', {}, 'Consumption (kWh)'), React.createElement('th', {}, 'Production (kWh)'))), React.createElement.apply(this, [ + 'tbody', + {}, + _.map(this.props.house.energy_data, repeatEnergy_datum1.bind(this)) + ])) : null, React.createElement('div', { 'id': 'energy_graph' })); +}; \ No newline at end of file diff --git a/client/dashboard/energy/energy.scss b/client/dashboard/energy/energy.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/dashboard/layout/layout.js b/client/dashboard/layout/layout.js index 5c16cf9..785331f 100644 --- a/client/dashboard/layout/layout.js +++ b/client/dashboard/layout/layout.js @@ -13,7 +13,7 @@ var Layout = React.createClass({ views: VIEWS, houses: null, house: null, - view: 'power', + view: 'energy', requesting_data: true }; }, @@ -26,8 +26,7 @@ var Layout = React.createClass({ var layout = this; // window.addEventListener('resize', this.handleResize); House.ensureHouses().then((houses)=>{ - layout.setState({houses: houses, house: houses[0]}); - layout.ensureHouseViewData(); + layout.setState({houses: houses, house: houses[0], requesting_data: false}); }); }, @@ -35,37 +34,14 @@ var Layout = React.createClass({ var layout = this, view = event.target.value; layout.view_name = event.target.innerText; - layout.setState({view: view}, function(){ - layout.ensureHouseViewData(); - }); + layout.setState({view: view}); }, setHouse: function(event){ var layout = this, house_id = event.target.value, house = layout.state.houses.find((house)=>{ return house.data.id == house_id }); - layout.setState({house: house}, function(){ - layout.ensureHouseViewData(); - }); - }, - - ensureHouseViewData: function(){ - var layout = this, - house = layout.state.house, - view = layout.state.view, - request; - layout.setState({requesting_data: true}, ()=>{ - if (view === 'power'){ - request = house.ensurePowerData(); - } else { - request = house.ensureEnergyData(); - } - request.then(()=>{ - layout.setState({requesting_data: false}, ()=>{ - console.log(layout.state.requesting_data); - }); - }); - }); + layout.setState({house: house}); }, render: function() { diff --git a/client/dashboard/layout/layout.rt b/client/dashboard/layout/layout.rt index 7424807..e9c008a 100644 --- a/client/dashboard/layout/layout.rt +++ b/client/dashboard/layout/layout.rt @@ -1,54 +1,17 @@ + +
-
Loading data...
+
Retrieving houses...

{this.state.house.name}

{this.view_name}

-
- -
-
- -
+ + - - - - - - - - - - - - - - - - - -
DayConsumption (kWh)Production (kWh)
{energy_datum.day_to_s}{energy_datum.consumption_to_s}{energy_datum.production_to_s}
- - - - - - - - - - - - - - - - - - -
TimeConsumption (W)Production (W)
{power_datum.time_to_s}{power_datum.consumption_to_s}{power_datum.production_to_s}
+ +
diff --git a/client/dashboard/layout/layout.rt.js b/client/dashboard/layout/layout.rt.js index ff597ae..6e63f8b 100644 --- a/client/dashboard/layout/layout.rt.js +++ b/client/dashboard/layout/layout.rt.js @@ -1,5 +1,7 @@ import React from 'react'; import _ from 'lodash'; +import Energy from './../energy/energy'; +import Power from './../power/power'; function repeatView1(view, viewIndex) { return React.createElement('option', { 'value': view[0], @@ -12,34 +14,20 @@ function repeatHouse2(house, houseIndex) { 'key': house.react_key }, house.data.name); } -function repeatEnergy_datum3(energy_datum, energy_datumIndex) { - return React.createElement('tr', { 'key': energy_datum.react_key }, React.createElement('td', {}), React.createElement('td', {}, energy_datum.day_to_s), React.createElement('td', {}, energy_datum.consumption_to_s), React.createElement('td', {}, energy_datum.production_to_s)); -} -function repeatPower_datum4(power_datum, power_datumIndex) { - return React.createElement('tr', { 'key': power_datum.react_key }, React.createElement('td', {}), React.createElement('td', {}, power_datum.time_to_s), React.createElement('td', {}, power_datum.consumption_to_s), React.createElement('td', {}, power_datum.production_to_s)); -} export default function () { - return React.createElement('div', { 'id': 'layout' }, this.state.requesting_data ? React.createElement('div', { 'className': 'alert alert-warning' }, 'Loading data...') : null, this.state.house ? React.createElement('h1', {}, this.state.house.name) : null, this.state.view ? React.createElement('h3', {}, this.view_name) : null, React.createElement('div', {}, React.createElement.apply(this, [ + return React.createElement('div', { 'id': 'layout' }, this.state.requesting_data ? React.createElement('div', { 'className': 'alert alert-warning' }, 'Retrieving houses...') : null, this.state.house ? React.createElement('h1', {}, this.state.house.name) : null, this.state.view ? React.createElement('h3', {}, this.view_name) : null, React.createElement.apply(this, [ 'select', { 'className': 'form-control', 'onChange': this.setView }, _.map(this.state.views, repeatView1.bind(this)) - ])), this.state.houses ? React.createElement('div', {}, React.createElement.apply(this, [ + ]), this.state.houses ? React.createElement.apply(this, [ 'select', { 'className': 'form-control', 'onChange': this.setHouse }, _.map(this.state.houses, repeatHouse2.bind(this)) - ])) : null, this.state.view === 'energy' && this.state.house ? React.createElement('table', { 'className': 'table' }, React.createElement('thead', {}, React.createElement('tr', {}, React.createElement('th', {}), React.createElement('th', {}, 'Day'), React.createElement('th', {}, 'Consumption (kWh)'), React.createElement('th', {}, 'Production (kWh)'))), React.createElement.apply(this, [ - 'tbody', - {}, - _.map(this.state.house.energy_data, repeatEnergy_datum3.bind(this)) - ])) : null, this.state.view === 'power' && this.state.house ? React.createElement('table', { 'className': 'table' }, React.createElement('thead', {}, React.createElement('tr', {}, React.createElement('th', {}), React.createElement('th', {}, 'Time'), React.createElement('th', {}, 'Consumption (W)'), React.createElement('th', {}, 'Production (W)'))), React.createElement.apply(this, [ - 'tbody', - {}, - _.map(this.state.house.power_data, repeatPower_datum4.bind(this)) - ])) : null); + ]) : null, this.state.house && this.state.view === 'energy' ? React.createElement(Energy, { 'house': this.state.house }) : null); }; \ No newline at end of file diff --git a/client/dashboard/power/power.js b/client/dashboard/power/power.js new file mode 100644 index 0000000..e69de29 diff --git a/client/dashboard/power/power.rt b/client/dashboard/power/power.rt new file mode 100644 index 0000000..8966de3 --- /dev/null +++ b/client/dashboard/power/power.rt @@ -0,0 +1,21 @@ +
+

Fifteen Minute Power Interval

+ + + + + + + + + + + + + + + + + +
TimeConsumption (W)Production (W)
{power_datum.time_to_s}{power_datum.consumption_to_s}{power_datum.production_to_s}
+
diff --git a/client/dashboard/power/power.rt.js b/client/dashboard/power/power.rt.js new file mode 100644 index 0000000..b2237e7 --- /dev/null +++ b/client/dashboard/power/power.rt.js @@ -0,0 +1,12 @@ +import React from 'react'; +import _ from 'lodash'; +function repeatPower_datum1(power_datum, power_datumIndex) { + return React.createElement('tr', { 'key': power_datum.react_key }, React.createElement('td', {}), React.createElement('td', {}, power_datum.time_to_s), React.createElement('td', {}, power_datum.consumption_to_s), React.createElement('td', {}, power_datum.production_to_s)); +} +export default function () { + return React.createElement('div', { 'id': 'power_view' }, React.createElement('h2', {}, 'Fifteen Minute Power Interval'), React.createElement('table', {}, React.createElement('thead', {}, React.createElement('tr', {}, React.createElement('th', {}), React.createElement('th', {}, 'Time'), React.createElement('th', {}, 'Consumption (W)'), React.createElement('th', {}, 'Production (W)'))), React.createElement.apply(this, [ + 'tbody', + {}, + _.map(this.state.house.power_data, repeatPower_datum1.bind(this)) + ]))); +}; \ No newline at end of file diff --git a/client/models/energy_datum.js b/client/models/energy_datum.js index 25c37d1..dbc68c6 100644 --- a/client/models/energy_datum.js +++ b/client/models/energy_datum.js @@ -38,7 +38,7 @@ class EnergyDatum { update(data){ var energy_datum = this, - house = power_datum.house; + house = energy_datum.house; if (data.day) data.day = moment.tz(data.day, house.data.timezone); extend(energy_datum.data, data); } diff --git a/client/models/house.js b/client/models/house.js index 1fe1709..8bc04c6 100644 --- a/client/models/house.js +++ b/client/models/house.js @@ -84,6 +84,7 @@ class House { if (date_range.length === 0) return house.getEnergyData({dates: [[opts.start_date, opts.end_date]]}) query_ranges = MathUtil.minusRange([opts.start_date, opts.end_date], [min_date, max_date]); + if (!query_ranges) return Promise.resolve(house.power_data); cache = ArrayUtil.selectMap(date_range, (datum_day)=>{ diff --git a/client/style.js b/client/style.js index 8fbe045..1903da4 100644 --- a/client/style.js +++ b/client/style.js @@ -6,3 +6,4 @@ require('font-awesome/css/font-awesome.min.css'); // Component Stylesheets require(__dirname + '/style.scss'); require(__dirname + '/dashboard/layout/layout.scss'); +require(__dirname + '/d3/chart.scss'); diff --git a/readme.md b/readme.md index e448f8f..cddb9d8 100644 --- a/readme.md +++ b/readme.md @@ -1,28 +1 @@ -[See necessary examples](https://drive.google.com/drive/u/0/folders/0B6Ys-9_Te2cFNktOU3VwSzA1VWs) - - -## Problems - -1. Setting type directly on field: - -```js -fields: ()=>{ - username: GraphQLString -} -``` - -threw this error: - -```sh -Unhandled rejection Error: Query.viewer field type must be Output Type but got: undefined -``` - -Must pass object: - -```js -fields: ()=>{ - username: { - type: GraphQLString - } -} -``` +# Spike