Commit 49435e45 authored by alain's avatar alain 🐙
Browse files
parents f7757b47 fd02f179
const { editWebpackPlugin, appendWebpackPlugin } = require('@rescripts/utilities')
const CopyWebpackPlugin = require('copy-webpack-plugin');
//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = config => {
......@@ -18,6 +19,10 @@ module.exports = config => {
config,
)
// config = appendWebpackPlugin(
// new BundleAnalyzerPlugin(),
// config,
// )
if(config.mode === 'production') {
......
export const appSettings = {
language: "nl",
panelBreakpoint: 800
}
\ No newline at end of file
import { color } from "../custom/muv/d3-color"
export const texts = {
pilotLocations: "Pilot locations",
loading: "Loading...",
lastMean: "last hourly average",
lastPeak: "peak value last hour",
mean: "mean",
peak: "peak value"
}
export const mapDefaults = {
latitude: 46.6957637170966,
longitude: 5.765113549054841,
zoom: 4.5,
pitch: 45,
bearing: 0
bounds: [
[4.5, 52.6],
[5, 52.3]
],
viewport: {
pitch: 60,
bearing: 0
}
}
export const mapLocations = [
{
name: "Amsterdam",
latitude: 52.371828,
longitude: 4.901642,
zoom: 12
},
{
name: "Barcelona",
latitude: 41.40370281706366,
longitude: 2.1432531593864312,
zoom: 12
},
{
name: "Helsinki",
latitude: 60.17226969670993,
longitude: 24.900654954799048,
zoom: 12
},
{
name: "Palermo",
latitude: 38.12088554193859,
longitude: 13.352510065410891,
zoom: 12
name: "Name",
bounds: [
[4.557490, 52.514173],
[4.694126, 52.436089]
],
sublocations: [
{
name: "Name",
bounds: [
[52.516652, 4.613219].reverse(),
[52.476220, 4.700986].reverse()
]
}
]
}
]
......@@ -62,6 +47,7 @@ export const mapItemSettings = {
sizeMax: 200,
elevationMaxMin: 120,
elevationMaxMax: 2000,
colorOffline: "#888"
}
export const lightSettings = {
......
import { addMissingHours } from "../../../src/util/data"
import { addMissingDataPoints } from "../../../src/util/data"
export default {
name: "muv",
name: "sourcename",
sides: 5,
angle: 0,
factor: 0.5,
factor: 0.5,
daysToFetch: 90,
all: async function getAll(parameter) {
all: async function(parameter) {
try {
const allResponse = await fetch(`https://data.waag.org/api/muv`)
const all = await allResponse.json()
//console.log(all)
const latestResponse = await fetch(`https://data.waag.org/api/muv/getOnlineSensors`)
const latest = await latestResponse.json()
//console.log(latest)
let offlineSensors = []
let unregisteredSensors = []
......@@ -29,10 +28,9 @@ export default {
id: sensor.id.toString(),
name: sensor.sensor_type + " " + sensor.id.toString() + " " + sensor.location,
type: sensor.sensor_type,
source: "muv",
source: "sourcename",
coordinates: [sensor.longitude, sensor.latitude].reverse(),
mean: sensorData[`${parameter}`]
//max: sensorData[`${parameter}_max`]
}
} else {
offlineSensors.push(sensor.id)
......@@ -65,15 +63,18 @@ export default {
}
},
detail: async function getDetail(station, parameter, start, end) {
stationMeta: function(station, parameter) {
const stationMeta = {
type: station.id,
name: station.name,
description: ""
}
return stationMeta
},
stationData: async function(station, parameter, start, end, granularity) {
try {
const stationInfo = {
type: station.id,
name: station.name,
description: ""
}
const response = await fetch(`https://data.waag.org/api/muv/getSensorData?sensor_id=${station.id}&start=${start}&end=${end}`)
const responseData = await response.json()
......@@ -90,7 +91,7 @@ export default {
}
})
const data = addMissingHours(conformedData)
const data = addMissingDataPoints(conformedData, granularity)
return { stationInfo, data }
} catch (error) {
......
......@@ -8,9 +8,15 @@ export const texts = {
loading: "Bezig met laden...",
loadingError: "Laden mislukt...",
loadingRetry: "Probeer opnieuw",
nodata: "Geen data...",
nodata: "geen data...",
lastMean: "laatste uurgemiddelde",
lastPeak: "piekwaarde laatste uur",
mean: "gemiddelde",
peak: "piekwaarde"
peak: "piekwaarde",
downloadData: "download data",
startDate: "startdatum",
endDate: "einddatum",
chartHeaderAddition: "(uurwaarden)",
downloadCsv: "download csv",
downloadInfo: "<small><a class='more' href='https://hollandseluchten.waag.org/data-downloaden/' target='_blank' rel='noopener noreferrer'>meer info over data downloaden en de API</a></small>",
}
This diff is collapsed.
......@@ -3,7 +3,6 @@ import { connect } from 'react-redux'
import memoize from "memoize-one";
import DeckGL from '@deck.gl/react';
import WebMercatorViewport from 'viewport-mercator-project'
import StationLayer from "./StationLayer"
import StationTooltip from "./StationTooltip"
......@@ -15,9 +14,11 @@ import IconInfo from "../Modal/IconInfo"
import { GridLayer } from '@deck.gl/aggregation-layers';
import Tooltip from "./Tooltip"
import { doOffsets } from 'util/plot';
class DeckLayers extends React.Component {
constructor(props){
......@@ -30,13 +31,10 @@ class DeckLayers extends React.Component {
renderTooltip() {
const { hover, hoverContent } = this.state || {}
const { hover, hoverContent, mousePosition } = this.state || {}
if(hover) {
const webMercatorViewport = new WebMercatorViewport(this.props.viewport)
const pixelCoords = webMercatorViewport.project(hover.coordinates)
return <Tooltip position={pixelCoords} content={hoverContent} />
return <Tooltip position={mousePosition} content={hoverContent} />
}
}
......@@ -47,24 +45,30 @@ class DeckLayers extends React.Component {
const count = {}
Object.keys(deckLayers).forEach(deckLayer => {
let previousData = []
Object.keys(deckLayers[deckLayer]).forEach(source => {
if(!count[source]) {
count[source] = { current: 0, total: 0 }
if(deckLayers[deckLayer][source].layerDefinition && deckLayers[deckLayer][source].layerDefinition.type === 'StationLayer') {
if(!count[source]) {
count[source] = { current: 0, total: 0 }
}
count[source].total++
deckLayers[deckLayer][source].data = doOffsets([...previousData, deckLayers[deckLayer][source].data])
previousData.push(deckLayers[deckLayer][source].data)
}
count[source].total++
})
})
Object.keys(deckLayers).forEach(deckLayer => {
Object.keys(deckLayers[deckLayer]).forEach(sourceName => {
const { layerDefinition, source, data } = deckLayers[deckLayer][sourceName]
count[sourceName].current++
if(!layerDefinition) return
count[sourceName].current++
switch(layerDefinition.type) {
case "StationLayer":
const unit = (layerDefinition.units ? layerDefinition.units.find(x => x.id === unitStatus[layerDefinition.id]) : null)
......@@ -91,6 +95,7 @@ class DeckLayers extends React.Component {
pickable: true,
extruded: true,
onHover: e => this.setState({
mousePosition: [e.x, e.y],
hover: e.object,
hoverContent: <StationTooltip d={e.object} label={layerDefinition.label} unit={unit.label} />
}),
......@@ -123,6 +128,7 @@ class DeckLayers extends React.Component {
getPosition: d => d.coordinates,
//getColor: d => layerDefinition.getColor(d[layerDefinition.getColorKey]),
onHover: e => this.setState({
mousePosition: [e.x, e.y],
hover: e.object,
hoverContent: <IconTooltip d={e.object} keys={layerDefinition.keysTooltip} />
}),
......
......@@ -2,7 +2,7 @@ import { CompositeLayer } from '@deck.gl/core'
import { ColumnLayer } from '@deck.gl/layers'
import { scaleLinear, scaleLog } from "d3-scale"
import { color, getColorArray } from "../util/color.js"
import { getColor, getColorArray } from "../util/color.js"
import { setMetersOffset } from "../util/plot"
......@@ -59,44 +59,35 @@ class StationLayer extends CompositeLayer {
}
return [
// // max
// new ColumnLayer({
// ...this.props,
// id: `${id}-column-layer-max`,
// data,
// radius
// diskResolution: sides,
// opacity: 1,
// lightSettings,
// getPosition: d => centroid(d.coordinates, d.offset),
// getFillColor: d => getColorArray(lightenBy(color(d.max, legend), 0.25)),
// getElevation: d => elevation(d.max, zoom),
// updateTriggers: {
// getElevation: [zoom],
// getPosition: [radius]
// }
// }),
//mean
new ColumnLayer({
...this.props,
id: `${id}-column-layer-mean`,
data,
radius,
diskResolution: sides,
opacity: 1,
opacity: 0.95,
lightSettings,
getElevation: d => getHeight(d.mean, zoom),
getPosition: d => this.getCoordinates(d, count, radius),
getFillColor: d => {
if(d.mean === null) {
return getColorArray("#ccc")
let color = getColorArray(mapItemSettings.colorOffline)
color[3] = color[3] * 0.5
return color
} else {
return getColorArray(color(d.mean, legend, (scale === 'log')))
let color = getColorArray(getColor(d.mean, legend, (scale === 'log')))
//if(d.dataAge > 3) color = changeColorLuminance(color, -0.015 * d.dataAge)
//if(d.dataAge > 4)
color[3] = color[3] * (1 - 0.1 * d.dataAge)
return color
}
},
updateTriggers: {
getElevation: [zoom],
getPosition: [radius]
getPosition: [radius, count]
}
})
]
......
......@@ -3,27 +3,29 @@ import React from 'react'
import { texts } from "../../../config/texts"
import { roundBy } from "../util/math.js"
import { moment } from "../util/time.js"
const SensorTooltip = props => {
const { d, label, unit } = props
const dataAgeText = `${ moment(d.timestamp).format("HH") }-${ moment(d.timestamp).add(1, 'hours').format("HH") }${texts.hourShort}`
return (
<div>
<h4>{d.name}</h4>
<em>{label}</em>
<table className="data"><tbody>
{ d.mean !== null &&
<tr>
<td>{ texts.lastMean }:</td>
<td><strong>{ roundBy(d.mean, 1) }{ unit }</strong></td>
</tr>
<tr>
<td>{`${texts.lastMean} (${dataAgeText}):`}</td>
<td><strong>{ roundBy(d.mean, 1) }{ unit }</strong></td>
</tr>
}
{ !!d.max &&
<tr>
<td>{ texts.lastPeak }:</td>
<td><strong>{ roundBy(d.max, 1) }{ unit }</strong></td>
</tr>
{ d.mean === null &&
<tr>
<td>{ texts.nodata }</td>
</tr>
}
</tbody></table>
</div>
......
......@@ -8,7 +8,7 @@ class MapAttributions extends React.Component {
<div className="mapboxgl-ctrl-bottom-right">
<div className="mapboxgl-ctrl mapboxgl-ctrl-attrib">
<div className="mapboxgl-ctrl-attrib-inner">
<span>v. 17/10/2019</span>
<span>v. 28/11/2019</span>
<span><a href="https://waag.org" target="_blank" rel="noopener noreferrer">waag</a></span>
<span>© <a href="http://www.openstreetmap.org/about/" target="_blank" rel="noopener noreferrer">OpenStreetMap</a></span>
</div>
......
import React from 'react'
//import { texts } from "../../../config/texts"
import Moment from "moment"
import { extendMoment } from 'moment-range'
const moment = extendMoment(Moment)
const ChartTick = (props) => {
const { width, height, x, y, fill, tickFormat } = props
const timestamp = props.payload.value
// const lines = []
// let i = 1
// if(moment(timestamp).format("HH") === "00") {
// lines.push(<tspan key={i} x={x} dy={`${i * 0.71}em`}>{ moment(timestamp).format("D MMM") }</tspan>)
// } else {
// lines.push(<tspan key={i} x={x} dy={`${i * 0.71}em`}>&nbsp;</tspan>)
// }
// if(tickFormat.length > 1) {
// i++
// lines.push(<tspan key={i} x={x} dy={`${i * 0.71}em`}>{ moment(timestamp).format("H:mm") }</tspan>)
// }
//const lines = tickFormat.map((lineFormat, i) => <tspan key={i} x={x} dy={`${(i+1) * 0.71}em`}>{ moment(timestamp).format(lineFormat) }</tspan>)
return (
<text width={width} height={height} x={x} y={y} stroke="none" fill={fill} className="recharts-text recharts-cartesian-axis-tick-value" textAnchor="middle">
<tspan x={x} dy={`${1 * 0.71}em`}>{ moment(timestamp).format(tickFormat) }</tspan>
</text>
)
}
export default ChartTick
\ No newline at end of file
......@@ -3,39 +3,53 @@ import React from 'react'
import { texts } from "../../../config/texts"
import { roundBy } from "../util/math.js"
import Moment from "moment"
import localization from "moment/locale/nl-be"
import { extendMoment } from 'moment-range'
const moment = extendMoment(Moment)
import { moment } from "../util/time.js"
const ChartTooltip = (props) => {
const { active, payload, label, unit } = props
moment().locale("nl", localization)
const { active, payload, label, unit, dataStreamsState } = props
if (active) {
let avg, max
const title = <h4>{ moment(label).format("D MMM") } { moment(label).format("HH:mm") } - { moment(label).add(1, 'hours').format("HH:mm") } { texts.hour }</h4>
let body
if(payload && payload.length > 1) {
avg = payload[1].value
max = payload[0].value[1]
} else if(payload && payload.length > 0) {
avg = payload[0].value
if(!payload) {
body = <p>{ texts.nodata }</p>
} else {
avg = "geen data"
const dataStreams = payload[0] ? payload[0].payload : {}
let rows = []
Object.keys(dataStreamsState).forEach(i => {
const headerRow = <tr key={i}><th>{ texts.dataStreams[i]}:</th><th></th></tr>
let subRows = []
Object.keys(dataStreamsState[i]).forEach(j => {
const s = dataStreamsState[i][j]
if(s.active) {
const value = dataStreams[s.key]
let text
text = Array.isArray(value) ? `${ roundBy(value[0], 1) }-${ roundBy(value[1], 1) } ${unit}` : `${roundBy(value, 1)} ${unit}`
if(!value) text = texts.nodata
subRows.push(<tr key={s.key}><td>{ texts.dataStreams[j] }:</td><td><strong>{ text }</strong></td></tr>)
}
})
if(subRows.length > 0 && Object.keys(dataStreamsState).length > 1) rows.push(headerRow)
rows = rows.concat(subRows)
})
body = <table><tbody>{ rows }</tbody></table>
}
return (
<div className="tooltip-data">
<h4>{ moment(label).format("D MMM") } { moment(label).subtract(1, 'hours').format("HH:mm") } - { moment(label).format("HH:mm") }</h4>
<table><tbody>
<tr><td>{ texts.mean }:</td><td>{ roundBy(avg, 1)}{unit}</td></tr>
{ !!max && <tr><td>{ texts.peak }:</td><td>{ roundBy(max, 1)}{unit}</td></tr> }
</tbody></table>
</div>
{ title }
{ body }
</div>
)
}
return null
......
......@@ -5,21 +5,21 @@ import { connect } from 'react-redux'
import { scaleLinear, scaleLog } from 'd3-scale'
import { getTickSettings } from "../util/plot.js"
import { ResponsiveContainer, ComposedChart, LineChart, Area, Line, XAxis, YAxis, Brush, Tooltip } from "recharts"
import ChartTooltip from "./ChartTooltip"
import ChartTick from "./ChartTick"
import IconArrowDown from "../Icons/IconArrowDown"
import { texts } from "../../../config/texts"
import { appSettings } from "../../../config/app"
import { getNowISO, getMonthsAgoHourISO } from "../util/time.js"
import Moment from "moment"
import localization from "moment/locale/nl-be"
import { extendMoment } from 'moment-range'
const moment = extendMoment(Moment)
import { moment, getNowHourISO, getDaysAgoHourISO } from "../util/time.js"
const start = getMonthsAgoHourISO(3)
const end = getNowISO()
const start = getDaysAgoHourISO(90)
const end = getNowHourISO()
class StationInfo extends React.Component {