From 47f47a027a88ca32a919af9ae93f02904a016877 Mon Sep 17 00:00:00 2001 From: mfcss Date: Tue, 17 Sep 2019 22:40:03 +0200 Subject: [PATCH 01/13] Various changes & optimizations on db functionality --- src/browser/js/charts/DoughnutChart.js | 50 ++++++++++ src/browser/js/charts/LineChart.js | 31 +++--- src/browser/js/charts/index.js | 3 +- src/browser/js/dashboard/DashboardSection.js | 100 +++++++++++++------ src/browser/js/dashboard/actions.js | 17 +++- src/browser/less/inc/variables.less | 1 - src/sdk/aws-sdk-client.js | 5 +- src/sdk/s3explorer.js | 2 +- 8 files changed, 155 insertions(+), 54 deletions(-) create mode 100644 src/browser/js/charts/DoughnutChart.js diff --git a/src/browser/js/charts/DoughnutChart.js b/src/browser/js/charts/DoughnutChart.js new file mode 100644 index 0000000..dfefaa7 --- /dev/null +++ b/src/browser/js/charts/DoughnutChart.js @@ -0,0 +1,50 @@ +import React from "react"; +import { Doughnut } from "react-chartjs-2"; + +const DoughnutChart = (props) => { + const { + datasets, + chartColors, + aspectRatio, + chHeight + } = props; + + const time_stamp = datasets[0].label + const datasetsRestructured = []; + + // restructure the dataset to be suitable for Line/Scatter types + datasets.map(element => + element.data.map( + (e, i) => + (datasetsRestructured[i] = { + [element.label]: e, + ...datasetsRestructured[i] + }) + ) + ); + + console.log(datasets) + + console.log(datasetsRestructured) + + // borderColor: chartColors[i], + // backgroundColor: hexToRgba(chartColors[i], "0.1") + + return ( +
+ {datasets ? ( + + ) : null} +
+ ); +}; + +export default DoughnutChart; diff --git a/src/browser/js/charts/LineChart.js b/src/browser/js/charts/LineChart.js index f2d348f..007e3c8 100644 --- a/src/browser/js/charts/LineChart.js +++ b/src/browser/js/charts/LineChart.js @@ -1,27 +1,20 @@ import React from "react"; import { Line } from "react-chartjs-2"; import hexToRgba from "hex-to-rgba"; -import Moment from "moment"; -let lineChartColors = [ - "#3d85c6", - "#073763", - "#0b5394", - "#6fa8dc", - "#9fc5e8", - "#e69138", - "#ff9900", - "#f6b26b", - "#f9cb9c" -]; +const LineChart = (props) => { - -const LineChart = ({ datasets }) => { + const { + datasets, + chartColors, + aspectRatio, + chHeight + } = props; // set the header labels for use in indexing object properties const device_serialno = datasets[0].label const time_stamp = datasets[1].label - const parameter = datasets[2].label + const parameter = datasets[2].label // could be extended for multiple parameters const datasetsRestructured = []; // restructure the dataset to be suitable for Line/Scatter types @@ -46,7 +39,7 @@ const LineChart = ({ datasets }) => { let datasetsDevice = datasetsRestructured .filter(e => e[device_serialno] == deviceIds[i]) .map(e => { - const x = Moment(e[time_stamp]).format("MM/DD h:mm:ss"); + const x = e[time_stamp]; const y = e[parameter]; return { x, y }; }); @@ -54,8 +47,8 @@ const LineChart = ({ datasets }) => { datasetsAllDevices[i] = { label: deviceIds[i], data: datasetsDevice, - borderColor: lineChartColors[i], - backgroundColor: hexToRgba(lineChartColors[i], "0.1") + borderColor: chartColors[i], + backgroundColor: hexToRgba(chartColors[i], "0.1") }; } @@ -66,7 +59,9 @@ const LineChart = ({ datasets }) => { data={{ datasets: datasetsAllDevices }} + height={chHeight ? chHeight : null} options={{ + maintainAspectRatio: aspectRatio, scales: { xAxes: [ { diff --git a/src/browser/js/charts/index.js b/src/browser/js/charts/index.js index 1e721b5..040cd89 100644 --- a/src/browser/js/charts/index.js +++ b/src/browser/js/charts/index.js @@ -1,4 +1,5 @@ // We can add multiple types of charts and export all from the chart component import LineChart from "./LineChart"; +import DoughnutChart from "./DoughnutChart"; -export { LineChart }; +export { LineChart, DoughnutChart }; diff --git a/src/browser/js/dashboard/DashboardSection.js b/src/browser/js/dashboard/DashboardSection.js index c6fd080..ced8e83 100644 --- a/src/browser/js/dashboard/DashboardSection.js +++ b/src/browser/js/dashboard/DashboardSection.js @@ -2,15 +2,10 @@ import React from "react"; import { connect } from "react-redux"; import { bindActionCreators } from "redux"; import * as dashboardActions from "./actions"; -import { LineChart } from "../charts"; +import { LineChart, DoughnutChart } from "../charts"; import { defaults } from "react-chartjs-2"; -// example select statements -// "SELECT time_date, EngineSpeed FROM S3Object WHERE EngineSpeed > '0' limit 200" -// "SELECT time_date, EngineSpeed FROM S3Object WHERE device_serialno in ['7F34B296'] and time_date > '2019-04-17 21:01:25' and time_date < '2019-04-17 21:05:25' limit 800" - -// Notes: -// Schema to force that minimum one default device is included +// FIGURE OUT HOW TO CONTROL THE HEIGHT // below will later be put into the server Schema/Config: let configDashboard = { @@ -22,56 +17,80 @@ let configDashboard = { font_size: 8, legend_labels_box_width: 10, legend_labels_padding: 4, - show_lines: 0 + show_lines: 0, + chart_colors: + "#3d85c6 #073763 #0b5394 #6fa8dc #9fc5e8 #e69138 #ff9900 f6b26b #f9cb9c" }, widgets: [ { id: "widget1", title: "Engine Speed (rpm)", chart_type: "line", - data_file_name: "test.csv", + data_file_name: "line.csv", parameters: "EngineSpeed", - def_devices: "'7F34B296', 'AB22438D'", + def_devices: "7F34B296 AB22438D", def_start: "2019-04-17 21:01:25", def_end: "2019-04-17 21:09:25", limit: 800, - class_name: "col-sm-4" + class_name: "col-sm-4", + aspect_ratio: true, + height: 0 }, { id: "widget2", title: "Vehicle Speed (km/h)", chart_type: "line", - data_file_name: "test.csv", + data_file_name: "line.csv", parameters: "WheelBasedVehicleSpeed", - def_devices: "'7F34B296', 'AB22438D'", + def_devices: "7F34B296 AB22438D", def_start: "2019-04-17 21:01:25", def_end: "2019-04-17 21:09:25", limit: 800, - class_name: "col-sm-4" + class_name: "col-sm-4", + aspect_ratio: true, + height: 0 }, { id: "widget3", title: "Engine Fuel Rate", chart_type: "line", - data_file_name: "test.csv", + data_file_name: "line.csv", parameters: "EngineFuelRate", - def_devices: "'7F34B296', 'AB22438D'", + def_devices: "7F34B296 AB22438D", def_start: "2019-04-17 21:01:25", def_end: "2019-04-17 21:09:25", limit: 800, - class_name: "col-sm-4" + class_name: "col-sm-4", + aspect_ratio: true, + height: 0 + }, + { + id: "widget4", + title: "Device Status", + chart_type: "pie", + data_file_name: "pie.csv", + parameters: "type1, type2, type3, type4", + def_devices: "", + def_start: "", + def_end: "", + limit: 800, + class_name: "col-sm-6", + aspect_ratio: false, + height: 0 } ] }; // set chart defaults let chDefaults = configDashboard.chart_defaults; +let chartColors = chDefaults.chart_colors.split(" "); defaults.global.elements.line.borderWidth = chDefaults.line_border_width; defaults.global.elements.point.radius = chDefaults.point_radius; defaults.global.defaultFontSize = chDefaults.font_size; defaults.global.legend.labels.boxWidth = chDefaults.legend_labels_box_width; defaults.global.legend.labels.padding = chDefaults.legend_labels_padding; defaults.global.showLines = chDefaults.show_lines; +defaults.global.maintainAspectRatio = chDefaults.aspect_ratio; function DashboardWidget(props) { @@ -79,18 +98,36 @@ function DashboardWidget(props) {
{props.widgetTitle} - + {props.chartType == "line" ? ( + + ) : props.chartType == "pie" ? ( + + ) : null}
); } - class DashboardSection extends React.Component { constructor(props) { super(props); } + // S3 select the data componentWillMount() { this.props.prepareWidgetInputs(configDashboard); } @@ -100,15 +137,22 @@ class DashboardSection extends React.Component { return (
- {recordsArray.length != 0 ? -
{recordsArray.map((records, i) => ( - - ))}
: null} + {recordsArray.length != 0 ? ( +
+ {recordsArray.map((records, i) => ( + + ))} +
+ ) : null}
); } diff --git a/src/browser/js/dashboard/actions.js b/src/browser/js/dashboard/actions.js index 275d9aa..c6c6209 100644 --- a/src/browser/js/dashboard/actions.js +++ b/src/browser/js/dashboard/actions.js @@ -8,7 +8,22 @@ export const prepareWidgetInputs = configDashboard => { let recordsArray = _.map(configDashboard.widgets, widget => web.getWidgetQueryResult({ dataFileName: widget.data_file_name, - sqlExpression: `SELECT ${chDefaults.device_header}, ${chDefaults.timestamp_header}, ${widget.parameters} FROM S3Object WHERE ${chDefaults.device_header} in [${widget.def_devices}] and ${chDefaults.timestamp_header} > '${widget.def_start}' and ${chDefaults.timestamp_header} < '${widget.def_end}' limit ${widget.limit}` + sqlExpression: + widget.chart_type == "line" + ? `SELECT ${chDefaults.device_header}, ${ + chDefaults.timestamp_header + }, ${widget.parameters} FROM S3Object WHERE ${ + chDefaults.device_header + } in [${"'" + + widget.def_devices.replace(/ /g, "', '") + + "'"}] and ${chDefaults.timestamp_header} > '${ + widget.def_start + }' and ${chDefaults.timestamp_header} < '${widget.def_end}' limit ${ + widget.limit + }` + : widget.chart_type == "pie" + ? `SELECT ${chDefaults.device_header}, ${chDefaults.timestamp_header}, ${widget.parameters} FROM S3Object` + : null }) ); diff --git a/src/browser/less/inc/variables.less b/src/browser/less/inc/variables.less index ff00a0b..1d762d8 100644 --- a/src/browser/less/inc/variables.less +++ b/src/browser/less/inc/variables.less @@ -21,7 +21,6 @@ Frontend Customizations ----------------------------*/ - .required{ display:none !important; } diff --git a/src/sdk/aws-sdk-client.js b/src/sdk/aws-sdk-client.js index 019b807..c8e2981 100644 --- a/src/sdk/aws-sdk-client.js +++ b/src/sdk/aws-sdk-client.js @@ -20,11 +20,8 @@ class AwsSdk { if (event.Records) { result = result.concat(event.Records.Payload.toString()); } else if (event.Stats) { - console.log( - `Processed ${event.Stats.Details.BytesProcessed} bytes` - ); + } else if (event.End) { - console.log("SelectObjectContent completed"); resolve(result); } } diff --git a/src/sdk/s3explorer.js b/src/sdk/s3explorer.js index 6fdff32..d09b6b4 100644 --- a/src/sdk/s3explorer.js +++ b/src/sdk/s3explorer.js @@ -436,7 +436,6 @@ class S3Explorer { */ getWidgetQueryResult(dataFileName, sqlExpression, cb) { - console.log(sqlExpression); const params = { Bucket: this.bucketName, Key: dataFileName, @@ -476,6 +475,7 @@ class S3Explorer { dataset, records }); + return cb(null, response); }) .catch(err => { From d25c66b150fc19c2d133920080317e6b05a87afb Mon Sep 17 00:00:00 2001 From: mfcss Date: Wed, 18 Sep 2019 00:16:25 +0200 Subject: [PATCH 02/13] Added pie chart functionality --- src/browser/js/charts/BaseChart.js | 126 +++++++++++++++++++ src/browser/js/charts/DoughnutChart.js | 50 -------- src/browser/js/charts/LineChart.js | 90 ------------- src/browser/js/charts/index.js | 6 +- src/browser/js/dashboard/DashboardSection.js | 26 ++-- src/browser/js/dashboard/actions.js | 21 +--- src/sdk/s3explorer.js | 1 + 7 files changed, 143 insertions(+), 177 deletions(-) create mode 100644 src/browser/js/charts/BaseChart.js delete mode 100644 src/browser/js/charts/DoughnutChart.js delete mode 100644 src/browser/js/charts/LineChart.js diff --git a/src/browser/js/charts/BaseChart.js b/src/browser/js/charts/BaseChart.js new file mode 100644 index 0000000..d6f2968 --- /dev/null +++ b/src/browser/js/charts/BaseChart.js @@ -0,0 +1,126 @@ +import React from "react"; +import _ from "lodash"; +import { Line, Doughnut } from "react-chartjs-2"; +import hexToRgba from "hex-to-rgba"; + +const BaseChart = props => { + const { datasets, chartColors, aspectRatio, chHeight, chartType } = props; + + // set the header labels for use in indexing object properties + const device_serialno = datasets[0].label; + const time_stamp = datasets[1].label; + const parameter = datasets[2].label; // could be extended for multiple parameters + const datasetsRestructured = []; + + // set chart specific options + const lineOptions = { + maintainAspectRatio: aspectRatio, + scales: { + xAxes: [ + { + gridLines: { + display: false + }, + type: "time", + time: { + unit: "minute", + unitStepSize: 1, + displayFormats: { + second: "MM/DD h:mm:ss", + minute: "MM/DD h:mm" + } + } + } + ] + } + }; + + // restructure the dataset to be suitable for Line/Scatter types + datasets.map(element => + element.data.map( + (e, i) => + (datasetsRestructured[i] = { + [element.label]: e, + ...datasetsRestructured[i] + }) + ) + ); + + // get unique set of device IDs available in the data + const deviceIds = [ + ...new Set(datasetsRestructured.map(x => x[device_serialno])) + ]; + + // Line chart: Construct array of the data, separated by device (and add labels/colors for each) + // Pie chart: Construct arrays of parameter labels and values + + let datasetsAllDevices = []; + let datasetsDevice = []; + + + for (let i = 0; i < deviceIds.length; i++) { + let datasetsDeviceFiltered = datasetsRestructured.filter( + e => e[device_serialno] == deviceIds[i] + ); + + if (chartType == "line") { + datasetsDevice = datasetsDeviceFiltered.map(e => { + const x = e[time_stamp]; + const y = e[parameter]; + return { x, y }; + }); + + datasetsAllDevices[i] = { + label: deviceIds[i], + data: datasetsDevice, + borderColor: chartColors[i], + backgroundColor: hexToRgba(chartColors[i], "0.1") + }; + } else if (chartType == "pie") { + datasetsDevice = datasetsDeviceFiltered.map(e => { + const parameters = _.omit(e, time_stamp, device_serialno); + return { parameters }; + })[0].parameters; + + datasetsAllDevices[i] = { + label: Object.keys(datasetsDevice), + data: Object.values(datasetsDevice), + borderColor: "#ffffff", + backgroundColor: chartColors.slice(0,Object.keys(datasetsDevice).length), + hoverBackgroundColor: chartColors.slice(0,Object.keys(datasetsDevice).length) + + }; + } + } + + + return ( +
+ {datasets ? ( + chartType == "line" ? ( + + ) : chartType == "pie" ? ( + + ) : null + ) : null} +
+ ); +}; + +export default BaseChart; diff --git a/src/browser/js/charts/DoughnutChart.js b/src/browser/js/charts/DoughnutChart.js deleted file mode 100644 index dfefaa7..0000000 --- a/src/browser/js/charts/DoughnutChart.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from "react"; -import { Doughnut } from "react-chartjs-2"; - -const DoughnutChart = (props) => { - const { - datasets, - chartColors, - aspectRatio, - chHeight - } = props; - - const time_stamp = datasets[0].label - const datasetsRestructured = []; - - // restructure the dataset to be suitable for Line/Scatter types - datasets.map(element => - element.data.map( - (e, i) => - (datasetsRestructured[i] = { - [element.label]: e, - ...datasetsRestructured[i] - }) - ) - ); - - console.log(datasets) - - console.log(datasetsRestructured) - - // borderColor: chartColors[i], - // backgroundColor: hexToRgba(chartColors[i], "0.1") - - return ( -
- {datasets ? ( - - ) : null} -
- ); -}; - -export default DoughnutChart; diff --git a/src/browser/js/charts/LineChart.js b/src/browser/js/charts/LineChart.js deleted file mode 100644 index 007e3c8..0000000 --- a/src/browser/js/charts/LineChart.js +++ /dev/null @@ -1,90 +0,0 @@ -import React from "react"; -import { Line } from "react-chartjs-2"; -import hexToRgba from "hex-to-rgba"; - -const LineChart = (props) => { - - const { - datasets, - chartColors, - aspectRatio, - chHeight - } = props; - - // set the header labels for use in indexing object properties - const device_serialno = datasets[0].label - const time_stamp = datasets[1].label - const parameter = datasets[2].label // could be extended for multiple parameters - const datasetsRestructured = []; - - // restructure the dataset to be suitable for Line/Scatter types - datasets.map(element => - element.data.map( - (e, i) => - (datasetsRestructured[i] = { - [element.label]: e, - ...datasetsRestructured[i] - }) - ) - ); - - // get unique set of device IDs available in the data - const deviceIds = [ - ...new Set(datasetsRestructured.map(x => x[device_serialno])) - ]; - - // construct array of the data, separated by device (and add labels/colors for each) - let datasetsAllDevices = []; - for (let i = 0; i < deviceIds.length; i++) { - let datasetsDevice = datasetsRestructured - .filter(e => e[device_serialno] == deviceIds[i]) - .map(e => { - const x = e[time_stamp]; - const y = e[parameter]; - return { x, y }; - }); - - datasetsAllDevices[i] = { - label: deviceIds[i], - data: datasetsDevice, - borderColor: chartColors[i], - backgroundColor: hexToRgba(chartColors[i], "0.1") - }; - } - - return ( -
- {datasets ? ( - - ) : null} -
- ); -}; - -export default LineChart; diff --git a/src/browser/js/charts/index.js b/src/browser/js/charts/index.js index 040cd89..a5f7c90 100644 --- a/src/browser/js/charts/index.js +++ b/src/browser/js/charts/index.js @@ -1,5 +1,5 @@ // We can add multiple types of charts and export all from the chart component -import LineChart from "./LineChart"; -import DoughnutChart from "./DoughnutChart"; +import BaseChart from "./BaseChart"; -export { LineChart, DoughnutChart }; + +export { BaseChart}; diff --git a/src/browser/js/dashboard/DashboardSection.js b/src/browser/js/dashboard/DashboardSection.js index ced8e83..b10f350 100644 --- a/src/browser/js/dashboard/DashboardSection.js +++ b/src/browser/js/dashboard/DashboardSection.js @@ -2,7 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import { bindActionCreators } from "redux"; import * as dashboardActions from "./actions"; -import { LineChart, DoughnutChart } from "../charts"; +import { LineChart, DoughnutChart, BaseChart } from "../charts"; import { defaults } from "react-chartjs-2"; // FIGURE OUT HOW TO CONTROL THE HEIGHT @@ -19,7 +19,7 @@ let configDashboard = { legend_labels_padding: 4, show_lines: 0, chart_colors: - "#3d85c6 #073763 #0b5394 #6fa8dc #9fc5e8 #e69138 #ff9900 f6b26b #f9cb9c" + "#3d85c6 #ff9900 #073763 #0b5394 #6fa8dc #9fc5e8 #e69138 f6b26b #f9cb9c" }, widgets: [ { @@ -70,11 +70,11 @@ let configDashboard = { chart_type: "pie", data_file_name: "pie.csv", parameters: "type1, type2, type3, type4", - def_devices: "", - def_start: "", - def_end: "", + def_devices: "ALL", + def_start: "2019-04-17 18:01:25", + def_end: "2019-04-17 21:01:25", limit: 800, - class_name: "col-sm-6", + class_name: "col-sm-2", aspect_ratio: false, height: 0 } @@ -98,8 +98,8 @@ function DashboardWidget(props) {
{props.widgetTitle} - {props.chartType == "line" ? ( - - ) : props.chartType == "pie" ? ( - - ) : null}
); diff --git a/src/browser/js/dashboard/actions.js b/src/browser/js/dashboard/actions.js index c6c6209..b703ae2 100644 --- a/src/browser/js/dashboard/actions.js +++ b/src/browser/js/dashboard/actions.js @@ -8,22 +8,11 @@ export const prepareWidgetInputs = configDashboard => { let recordsArray = _.map(configDashboard.widgets, widget => web.getWidgetQueryResult({ dataFileName: widget.data_file_name, - sqlExpression: - widget.chart_type == "line" - ? `SELECT ${chDefaults.device_header}, ${ - chDefaults.timestamp_header - }, ${widget.parameters} FROM S3Object WHERE ${ - chDefaults.device_header - } in [${"'" + - widget.def_devices.replace(/ /g, "', '") + - "'"}] and ${chDefaults.timestamp_header} > '${ - widget.def_start - }' and ${chDefaults.timestamp_header} < '${widget.def_end}' limit ${ - widget.limit - }` - : widget.chart_type == "pie" - ? `SELECT ${chDefaults.device_header}, ${chDefaults.timestamp_header}, ${widget.parameters} FROM S3Object` - : null + sqlExpression: `SELECT ${chDefaults.device_header}, ${chDefaults.timestamp_header}, ${widget.parameters} FROM S3Object + WHERE ${chDefaults.device_header} in [${"'" + widget.def_devices.replace(/ /g, "', '") + "'"}] + and ${chDefaults.timestamp_header} > '${widget.def_start}' + and ${chDefaults.timestamp_header} < '${widget.def_end}' + limit ${widget.limit}` }) ); diff --git a/src/sdk/s3explorer.js b/src/sdk/s3explorer.js index d09b6b4..bde1190 100644 --- a/src/sdk/s3explorer.js +++ b/src/sdk/s3explorer.js @@ -436,6 +436,7 @@ class S3Explorer { */ getWidgetQueryResult(dataFileName, sqlExpression, cb) { + console.log(sqlExpression) const params = { Bucket: this.bucketName, Key: dataFileName, From a6587b456f6198370dc805e31be5beeaf1c2ee02 Mon Sep 17 00:00:00 2001 From: mfcss Date: Wed, 18 Sep 2019 22:28:46 +0200 Subject: [PATCH 03/13] Misc refactoring --- src/browser/js/charts/BaseChart.js | 63 ++++++++++---------- src/browser/js/dashboard/DashboardSection.js | 58 ++++++++++++------ src/sdk/s3explorer.js | 1 - 3 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/browser/js/charts/BaseChart.js b/src/browser/js/charts/BaseChart.js index d6f2968..77a458e 100644 --- a/src/browser/js/charts/BaseChart.js +++ b/src/browser/js/charts/BaseChart.js @@ -1,17 +1,16 @@ import React from "react"; import _ from "lodash"; import { Line, Doughnut } from "react-chartjs-2"; -import hexToRgba from "hex-to-rgba"; const BaseChart = props => { - const { datasets, chartColors, aspectRatio, chHeight, chartType } = props; + const { datasets, chartColors, chartColorsTransparent, aspectRatio, chHeight, chartType } = props; // set the header labels for use in indexing object properties const device_serialno = datasets[0].label; const time_stamp = datasets[1].label; const parameter = datasets[2].label; // could be extended for multiple parameters const datasetsRestructured = []; - + // set chart specific options const lineOptions = { maintainAspectRatio: aspectRatio, @@ -35,7 +34,22 @@ const BaseChart = props => { } }; - // restructure the dataset to be suitable for Line/Scatter types + const pieOptions = { + maintainAspectRatio: aspectRatio, + tooltips: { + callbacks: { + label: function(item, data) { + return ( + data.datasets[item.datasetIndex].label + + ": " + + data.datasets[item.datasetIndex].data[item.index] + ); + } + } + } + }; + + // restructure the dataset to be suitable for the chart types datasets.map(element => element.data.map( (e, i) => @@ -51,12 +65,10 @@ const BaseChart = props => { ...new Set(datasetsRestructured.map(x => x[device_serialno])) ]; - // Line chart: Construct array of the data, separated by device (and add labels/colors for each) - // Pie chart: Construct arrays of parameter labels and values - + // construct array of the data, separated by device (and add labels/colors for each) let datasetsAllDevices = []; let datasetsDevice = []; - + let pieLabels = []; for (let i = 0; i < deviceIds.length; i++) { let datasetsDeviceFiltered = datasetsRestructured.filter( @@ -69,30 +81,22 @@ const BaseChart = props => { const y = e[parameter]; return { x, y }; }); - - datasetsAllDevices[i] = { - label: deviceIds[i], - data: datasetsDevice, - borderColor: chartColors[i], - backgroundColor: hexToRgba(chartColors[i], "0.1") - }; } else if (chartType == "pie") { datasetsDevice = datasetsDeviceFiltered.map(e => { const parameters = _.omit(e, time_stamp, device_serialno); return { parameters }; - })[0].parameters; - - datasetsAllDevices[i] = { - label: Object.keys(datasetsDevice), - data: Object.values(datasetsDevice), - borderColor: "#ffffff", - backgroundColor: chartColors.slice(0,Object.keys(datasetsDevice).length), - hoverBackgroundColor: chartColors.slice(0,Object.keys(datasetsDevice).length) - - }; + })[0].parameters; // note: If multiple entries for one device, the top one is selected + pieLabels = Object.keys(datasetsDevice); } - } + datasetsAllDevices[i] = { + label: deviceIds[i], + data: chartType == "line" ? datasetsDevice : Object.values(datasetsDevice), + borderColor: chartType == "line" ? chartColors[i] : "#ffffff", + backgroundColor: chartType == "line" ? chartColorsTransparent[i] : chartColors, + hoverBorderColor: chartColorsTransparent + }; + } return (
@@ -107,15 +111,12 @@ const BaseChart = props => { /> ) : chartType == "pie" ? ( ) : null ) : null} diff --git a/src/browser/js/dashboard/DashboardSection.js b/src/browser/js/dashboard/DashboardSection.js index b10f350..fa52e25 100644 --- a/src/browser/js/dashboard/DashboardSection.js +++ b/src/browser/js/dashboard/DashboardSection.js @@ -2,13 +2,12 @@ import React from "react"; import { connect } from "react-redux"; import { bindActionCreators } from "redux"; import * as dashboardActions from "./actions"; -import { LineChart, DoughnutChart, BaseChart } from "../charts"; +import { BaseChart } from "../charts"; import { defaults } from "react-chartjs-2"; - -// FIGURE OUT HOW TO CONTROL THE HEIGHT +import hexToRgba from "hex-to-rgba"; // below will later be put into the server Schema/Config: -let configDashboard = { +let confDash = { chart_defaults: { timestamp_header: "time_stamp", device_header: "device_serialno", @@ -66,7 +65,7 @@ let configDashboard = { }, { id: "widget4", - title: "Device Status", + title: "Overall Status", chart_type: "pie", data_file_name: "pie.csv", parameters: "type1, type2, type3, type4", @@ -78,12 +77,29 @@ let configDashboard = { aspect_ratio: false, height: 0 } + , + { + id: "widget5", + title: "Device Status", + chart_type: "pie", + data_file_name: "pie-multiple-devices-dates.csv", + parameters: "type1, type2, type3, type4", + def_devices: "7F34B296 AB22438D", + def_start: "2019-04-15 18:01:25", + def_end: "2019-04-18 21:01:25", + limit: 800, + class_name: "col-sm-2", + aspect_ratio: false, + height: 0 + } ] }; // set chart defaults -let chDefaults = configDashboard.chart_defaults; +let chDefaults = confDash.chart_defaults; let chartColors = chDefaults.chart_colors.split(" "); +let chartColorsTransparent = chartColors.map(color => hexToRgba(color, "0.1")) + defaults.global.elements.line.borderWidth = chDefaults.line_border_width; defaults.global.elements.point.radius = chDefaults.point_radius; defaults.global.defaultFontSize = chDefaults.font_size; @@ -101,10 +117,10 @@ function DashboardWidget(props) {
@@ -119,7 +135,7 @@ class DashboardSection extends React.Component { // S3 select the data componentWillMount() { - this.props.prepareWidgetInputs(configDashboard); + this.props.prepareWidgetInputs(confDash); } render() { @@ -130,16 +146,20 @@ class DashboardSection extends React.Component { {recordsArray.length != 0 ? (
{recordsArray.map((records, i) => ( - +
+
+ {confDash.widgets[i].title} + +
+
))}
) : null} diff --git a/src/sdk/s3explorer.js b/src/sdk/s3explorer.js index bde1190..d09b6b4 100644 --- a/src/sdk/s3explorer.js +++ b/src/sdk/s3explorer.js @@ -436,7 +436,6 @@ class S3Explorer { */ getWidgetQueryResult(dataFileName, sqlExpression, cb) { - console.log(sqlExpression) const params = { Bucket: this.bucketName, Key: dataFileName, From 7b5127de072a556e9c34127c5b1634de22c04031 Mon Sep 17 00:00:00 2001 From: mfcss Date: Wed, 18 Sep 2019 23:08:38 +0200 Subject: [PATCH 04/13] Added bar chart --- src/browser/js/charts/BaseChart.js | 50 +++++++++++++++++--- src/browser/js/dashboard/DashboardSection.js | 19 ++++++-- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/browser/js/charts/BaseChart.js b/src/browser/js/charts/BaseChart.js index 77a458e..d9b7711 100644 --- a/src/browser/js/charts/BaseChart.js +++ b/src/browser/js/charts/BaseChart.js @@ -1,16 +1,23 @@ import React from "react"; import _ from "lodash"; -import { Line, Doughnut } from "react-chartjs-2"; +import { HorizontalBar, Line, Doughnut } from "react-chartjs-2"; const BaseChart = props => { - const { datasets, chartColors, chartColorsTransparent, aspectRatio, chHeight, chartType } = props; + const { + datasets, + chartColors, + chartColorsTransparent, + aspectRatio, + chHeight, + chartType + } = props; // set the header labels for use in indexing object properties const device_serialno = datasets[0].label; const time_stamp = datasets[1].label; const parameter = datasets[2].label; // could be extended for multiple parameters const datasetsRestructured = []; - + // set chart specific options const lineOptions = { maintainAspectRatio: aspectRatio, @@ -49,6 +56,20 @@ const BaseChart = props => { } }; + const barOptions = { + maintainAspectRatio: aspectRatio, + scales: { + yAxes: [ + { + gridLines: { display: false }, + ticks: { + beginAtZero: true + } + } + ] + } + }; + // restructure the dataset to be suitable for the chart types datasets.map(element => element.data.map( @@ -81,7 +102,7 @@ const BaseChart = props => { const y = e[parameter]; return { x, y }; }); - } else if (chartType == "pie") { + } else if (chartType == "pie" || chartType == "bar") { datasetsDevice = datasetsDeviceFiltered.map(e => { const parameters = _.omit(e, time_stamp, device_serialno); return { parameters }; @@ -91,9 +112,15 @@ const BaseChart = props => { datasetsAllDevices[i] = { label: deviceIds[i], - data: chartType == "line" ? datasetsDevice : Object.values(datasetsDevice), - borderColor: chartType == "line" ? chartColors[i] : "#ffffff", - backgroundColor: chartType == "line" ? chartColorsTransparent[i] : chartColors, + data: + chartType == "line" ? datasetsDevice : Object.values(datasetsDevice), + borderColor: chartType == "line" ? chartColors[i] : "#ffffff", + backgroundColor: + chartType == "line" + ? chartColorsTransparent[i] + : chartType == "bar" + ? chartColors[i] + : chartColors, hoverBorderColor: chartColorsTransparent }; } @@ -118,6 +145,15 @@ const BaseChart = props => { height={chHeight ? chHeight : null} options={pieOptions} /> + ) : chartType == "bar" ? ( + ) : null ) : null} diff --git a/src/browser/js/dashboard/DashboardSection.js b/src/browser/js/dashboard/DashboardSection.js index fa52e25..13c2a8e 100644 --- a/src/browser/js/dashboard/DashboardSection.js +++ b/src/browser/js/dashboard/DashboardSection.js @@ -76,13 +76,12 @@ let confDash = { class_name: "col-sm-2", aspect_ratio: false, height: 0 - } - , + }, { id: "widget5", title: "Device Status", chart_type: "pie", - data_file_name: "pie-multiple-devices-dates.csv", + data_file_name: "pie-multiple-devices.csv", parameters: "type1, type2, type3, type4", def_devices: "7F34B296 AB22438D", def_start: "2019-04-15 18:01:25", @@ -91,6 +90,20 @@ let confDash = { class_name: "col-sm-2", aspect_ratio: false, height: 0 + }, + { + id: "widget6", + title: "Device Status", + chart_type: "bar", + data_file_name: "pie-multiple-devices.csv", + parameters: "type1, type2, type3, type4", + def_devices: "7F34B296 AB22438D", + def_start: "2019-04-15 18:01:25", + def_end: "2019-04-18 21:01:25", + limit: 800, + class_name: "col-sm-6", + aspect_ratio: false, + height: 0 } ] }; From 9abca7b941bf7172fade1415d06e6794f77f323a Mon Sep 17 00:00:00 2001 From: mfcss Date: Wed, 25 Sep 2019 20:54:22 +0200 Subject: [PATCH 05/13] Misc changes to db --- package-lock.json | 93 +++++--- package.json | 2 + src/browser/index.html | 5 + src/browser/js/charts/BaseChart.js | 44 +++- src/browser/js/charts/BaseMap.js | 116 ++++++++++ src/browser/js/charts/index.js | 3 +- src/browser/js/dashboard/DashboardSection.js | 232 +++++++++++-------- src/browser/js/dashboard/actions.js | 31 ++- src/browser/less/inc/variables.less | 9 + src/sdk/s3explorer.js | 1 + 10 files changed, 394 insertions(+), 142 deletions(-) create mode 100644 src/browser/js/charts/BaseMap.js diff --git a/package-lock.json b/package-lock.json index c0491bc..a9b9cc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5941,8 +5941,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5963,14 +5962,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5985,20 +5982,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6115,8 +6109,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6128,7 +6121,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6143,7 +6135,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6151,14 +6142,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -6177,7 +6166,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6258,8 +6246,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6271,7 +6258,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6357,8 +6343,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6394,7 +6379,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6414,7 +6398,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6458,14 +6441,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -10032,6 +10013,11 @@ "invert-kv": "^2.0.0" } }, + "leaflet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.4.0.tgz", + "integrity": "sha512-x9j9tGY1+PDLN9pcWTx9/y6C5nezoTMB8BLK5jTakx+H7bPlnbCHfi9Hjg+Qt36sgDz/cb9lrSpNQXmk45Tvhw==" + }, "left-pad": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", @@ -13834,6 +13820,53 @@ "resolved": "https://registry.npmjs.org/react-jsonschema-form-pagination/-/react-jsonschema-form-pagination-0.3.12.tgz", "integrity": "sha512-1x0kqEynuX/3BkiaggnYZeBOEEsOU44eopuc3cubHV2C4i3GtERJBwxREjvyaBEDzyZe8bUsxNKWUV45BIY1SQ==" }, + "react-leaflet": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-2.4.0.tgz", + "integrity": "sha512-ex9MAz2cUAmdUucsjv180OYszdqxHIyEwzWAuMOOuxE7yUmRscxZKR5h0f+vG4shR+SekZYUBk0+gCv8apRADQ==", + "requires": { + "@babel/runtime": "^7.4.5", + "fast-deep-equal": "^2.0.1", + "hoist-non-react-statics": "^3.3.0", + "warning": "^4.0.3" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.0.tgz", + "integrity": "sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, + "react-is": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", + "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==" + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", diff --git a/package.json b/package.json index d2ea32f..922a8af 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "jsonwebtoken": "^8.3.0", "jszip": "^3.1.5", "jszip-utils": "0.0.2", + "leaflet": "^1.4.0", "list-react-files": "^0.2.0", "local-storage-fallback": "^4.1.1", "lodash": "^4.17.11", @@ -111,6 +112,7 @@ "react-json-view": "^1.19.1", "react-jsonschema-form": "1.7.0", "react-jsonschema-form-pagination": "^0.3.12", + "react-leaflet": "^2.4.0", "react-onclickout": "^2.0.8", "react-redux": "^5.0.7", "react-router-dom": "^4.3.1", diff --git a/src/browser/index.html b/src/browser/index.html index 72ee626..f48a7f2 100644 --- a/src/browser/index.html +++ b/src/browser/index.html @@ -10,6 +10,11 @@ href="data:image/png;base64,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" type="image/x-icon" /> + + +