From 6ff1d4983f196ab39a43e7b1831d05607567aa63 Mon Sep 17 00:00:00 2001 From: Amir Nakhaei <6696894+amirrr@users.noreply.github.com> Date: Thu, 21 Dec 2023 04:49:20 +0100 Subject: [PATCH] few components Signed-off-by: iripiri --- src/widget/toolbox-item.js | 74 --------- src/widget/toolbox-item.jsx | 74 +++++++++ src/widget/widget-plot/plot-legend.js | 56 ------- src/widget/widget-plot/plot-legend.jsx | 62 +++++++ src/widget/widgets/{action.js => action.jsx} | 43 +++-- src/widget/widgets/{box.js => box.jsx} | 32 ++-- src/widget/widgets/button.js | 115 ------------- src/widget/widgets/button.jsx | 108 +++++++++++++ src/widget/widgets/custom-action.js | 66 -------- src/widget/widgets/custom-action.jsx | 118 ++++++++++++++ src/widget/widgets/{html.js => html.jsx} | 16 +- src/widget/widgets/icstatus.js | 79 --------- src/widget/widgets/icstatus.jsx | 71 ++++++++ src/widget/widgets/image.js | 89 ---------- src/widget/widgets/image.jsx | 78 +++++++++ src/widget/widgets/{label.js => label.jsx} | 29 ++-- src/widget/widgets/lamp.js | 86 ---------- src/widget/widgets/lamp.jsx | 72 +++++++++ src/widget/widgets/line.js | 83 ---------- src/widget/widgets/line.jsx | 70 ++++++++ src/widget/widgets/plot.js | 120 -------------- src/widget/widgets/plot.jsx | 96 +++++++++++ src/widget/widgets/slider.js | 161 ------------------- src/widget/widgets/slider.jsx | 148 +++++++++++++++++ src/widget/widgets/table.js | 136 ---------------- src/widget/widgets/table.jsx | 111 +++++++++++++ 26 files changed, 1066 insertions(+), 1127 deletions(-) delete mode 100644 src/widget/toolbox-item.js create mode 100644 src/widget/toolbox-item.jsx delete mode 100644 src/widget/widget-plot/plot-legend.js create mode 100644 src/widget/widget-plot/plot-legend.jsx rename src/widget/widgets/{action.js => action.jsx} (57%) rename src/widget/widgets/{box.js => box.jsx} (59%) delete mode 100644 src/widget/widgets/button.js create mode 100644 src/widget/widgets/button.jsx delete mode 100644 src/widget/widgets/custom-action.js create mode 100644 src/widget/widgets/custom-action.jsx rename src/widget/widgets/{html.js => html.jsx} (80%) delete mode 100644 src/widget/widgets/icstatus.js create mode 100644 src/widget/widgets/icstatus.jsx delete mode 100644 src/widget/widgets/image.js create mode 100644 src/widget/widgets/image.jsx rename src/widget/widgets/{label.js => label.jsx} (63%) delete mode 100644 src/widget/widgets/lamp.js create mode 100644 src/widget/widgets/lamp.jsx delete mode 100644 src/widget/widgets/line.js create mode 100644 src/widget/widgets/line.jsx delete mode 100644 src/widget/widgets/plot.js create mode 100644 src/widget/widgets/plot.jsx delete mode 100644 src/widget/widgets/slider.js create mode 100644 src/widget/widgets/slider.jsx delete mode 100644 src/widget/widgets/table.js create mode 100644 src/widget/widgets/table.jsx diff --git a/src/widget/toolbox-item.js b/src/widget/toolbox-item.js deleted file mode 100644 index 4c268c5..0000000 --- a/src/widget/toolbox-item.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React from 'react'; -import { DragSource } from 'react-dnd'; -import classNames from 'classnames'; -import Icon from '../common/icon'; - -const toolboxItemSource = { - beginDrag(props) { - return { - name: props.name - }; - } -}; - -function collect(connect, monitor) { - return { - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging() - } -} - -class ToolboxItem extends React.Component { - static defaultProps = { - disabled: false - }; - - render() { - var itemClass = classNames({ - 'toolbox-item': true, - 'toolbox-item-dragging': this.props.isDragging, - 'toolbox-item-disabled': this.props.disabled - }); - var dropEffect = 'copy'; - - if (this.props.disabled === false) { - return this.props.connectDragSource( -
- - {this.props.icon && } - {this.props.name} - -
- , {dropEffect}); - } - else { - return ( -
- - {this.props.icon && } - {this.props.name} - -
- ); - } - } -} - -export default DragSource('widget', toolboxItemSource, collect)(ToolboxItem); diff --git a/src/widget/toolbox-item.jsx b/src/widget/toolbox-item.jsx new file mode 100644 index 0000000..ac5e834 --- /dev/null +++ b/src/widget/toolbox-item.jsx @@ -0,0 +1,74 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from "react"; +import { DragSource } from "react-dnd"; +import classNames from "classnames"; +import Icon from "../common/icon"; + +// Drag source specification +const toolboxItemSource = { + beginDrag(props) { + return { + name: props.name, + }; + }, +}; + +// The collect function gathers props for the component related to dragging +function collect(connect, monitor) { + return { + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging(), + }; +} + +// The functional component for ToolboxItem +const ToolboxItem = ({ + connectDragSource, + isDragging, + disabled, + name, + icon, +}) => { + const itemClass = classNames({ + "toolbox-item": true, + "toolbox-item-dragging": isDragging, + "toolbox-item-disabled": disabled, + }); + + const content = ( + + {icon && } + {name} + + ); + + return disabled ? ( +
{content}
+ ) : ( + connectDragSource(
{content}
, { + dropEffect: "copy", + }) + ); +}; + +ToolboxItem.defaultProps = { + disabled: false, +}; + +export default DragSource("widget", toolboxItemSource, collect)(ToolboxItem); diff --git a/src/widget/widget-plot/plot-legend.js b/src/widget/widget-plot/plot-legend.js deleted file mode 100644 index 096c67b..0000000 --- a/src/widget/widget-plot/plot-legend.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React from 'react'; -import { scaleOrdinal} from 'd3-scale'; -import { schemeCategory10 } from 'd3-scale-chromatic' - -function Legend(props){ - - const signal = props.sig; - const hasScalingFactor = (signal.scalingFactor !== 1); - - let color = typeof props.lineColor === "undefined" ? schemeCategory10[props.index % 10] : props.lineColor; - - return ( -
  • - {signal.name} - {props.showUnit ? {signal.unit} : <> } - {hasScalingFactor ? {signal.scalingFactor} : <>} -
  • - ) -} - -class PlotLegend extends React.Component { - render() { - - return
    -
      - { this.props.lineColors !== undefined && this.props.lineColors != null ? ( - this.props.signals.map( (signal, idx) => - - )) : ( - this.props.signals.map( (signal, idx) => - - )) - } -
    -
    ; - } -} - -export default PlotLegend; diff --git a/src/widget/widget-plot/plot-legend.jsx b/src/widget/widget-plot/plot-legend.jsx new file mode 100644 index 0000000..d054e18 --- /dev/null +++ b/src/widget/widget-plot/plot-legend.jsx @@ -0,0 +1,62 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from "react"; +import { schemeCategory10 } from "d3-scale-chromatic"; + +function Legend(props) { + const { sig: signal, lineColor, index, showUnit } = props; + const hasScalingFactor = signal.scalingFactor !== 1; + const color = + typeof lineColor === "undefined" ? schemeCategory10[index % 10] : lineColor; + + return ( +
  • + {signal.name} + {showUnit && ( + + {signal.unit} + + )} + {hasScalingFactor && ( + + {signal.scalingFactor} + + )} +
  • + ); +} + +const PlotLegend = ({ signals, lineColors, showUnit }) => { + return ( +
    +
      + {signals.map((signal, idx) => ( + + ))} +
    +
    + ); +}; + +export default PlotLegend; diff --git a/src/widget/widgets/action.js b/src/widget/widgets/action.jsx similarity index 57% rename from src/widget/widgets/action.js rename to src/widget/widgets/action.jsx index 5a69d32..7b0ecb0 100644 --- a/src/widget/widgets/action.js +++ b/src/widget/widgets/action.jsx @@ -15,29 +15,28 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { Component } from 'react'; -import { Button, ButtonGroup } from 'react-bootstrap'; -import Icon from '../../common/icon'; +import React from "react"; +import { Button, ButtonGroup } from "react-bootstrap"; +import Icon from "../../common/icon"; -class WidgetAction extends Component { - constructor(props) { - super(props); +const WidgetAction = (props) => { + const onClick = (e) => { + // Put your onClick logic here + }; - this.state = { - }; - } - - onClick(e) { - - } - - render() { - return - - - - ; - } -} + return ( + + + + + + ); +}; export default WidgetAction; diff --git a/src/widget/widgets/box.js b/src/widget/widgets/box.jsx similarity index 59% rename from src/widget/widgets/box.js rename to src/widget/widgets/box.jsx index 3572267..3060610 100644 --- a/src/widget/widgets/box.js +++ b/src/widget/widgets/box.jsx @@ -15,25 +15,21 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { Component } from 'react'; +import React from "react"; +const WidgetBox = (props) => { + let colorStyle = { + borderColor: props.widget.customProperties.border_color, + backgroundColor: props.widget.customProperties.background_color, + opacity: props.widget.customProperties.background_color_opacity, + borderWidth: props.widget.customProperties.border_width + "px", + }; -class WidgetBox extends Component { - render() { - - let colorStyle = { - borderColor: this.props.widget.customProperties.border_color, - backgroundColor: this.props.widget.customProperties.background_color, - opacity: this.props.widget.customProperties.background_color_opacity, - borderWidth: this.props.widget.customProperties.border_width + 'px' - } - - return ( -
    - { } -
    - ); - } -} + return ( +
    + {} +
    + ); +}; export default WidgetBox; diff --git a/src/widget/widgets/button.js b/src/widget/widgets/button.js deleted file mode 100644 index ed6e02d..0000000 --- a/src/widget/widgets/button.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React, { Component } from 'react'; -import { Button } from 'react-bootstrap'; -import AppDispatcher from '../../common/app-dispatcher'; - -class WidgetButton extends Component { - - constructor(props) { - super(props); - - this.state = { - pressed: props.widget.customProperties.pressed - } - } - - componentDidMount() { - let widget = this.props.widget - widget.customProperties.simStartedSendValue = false - widget.customProperties.pressed = false - - AppDispatcher.dispatch({ - type: 'widgets/start-edit', - token: this.props.token, - data: widget - }); - } - - componentDidUpdate() { - // a simulaton was started, make an update - if (this.props.widget.customProperties.simStartedSendValue) { - // update widget, 'unpress' button at each simulation start - let widget = this.props.widget - widget.customProperties.simStartedSendValue = false - widget.customProperties.pressed = false - AppDispatcher.dispatch({ - type: 'widgets/start-edit', - token: this.props.token, - data: widget - }); - - // send value without changing widget - this.props.onInputChanged(widget.customProperties.off_value, '', false, false); - } - } - - static getDerivedStateFromProps(props, state){ - return { - pressed: props.widget.customProperties.pressed - } - } - - onPress(e) { - if (e.button === 0 && !this.props.widget.customProperties.toggle) { - this.valueChanged(this.props.widget.customProperties.on_value, true); - } - } - - onRelease(e) { - if (e.button === 0) { - let nextState = false; - if (this.props.widget.customProperties.toggle) { - nextState = !this.state.pressed; - } - this.valueChanged(nextState ? this.props.widget.customProperties.on_value : this.props.widget.customProperties.off_value, nextState); - } - } - - valueChanged(newValue, pressed) { - if (this.props.onInputChanged) { - this.props.onInputChanged(newValue, 'pressed', pressed, true); - } - } - - render() { - let opacity = this.props.widget.customProperties.background_color_opacity - const buttonStyle = { - backgroundColor: this.props.widget.customProperties.background_color, - borderColor: this.props.widget.customProperties.border_color, - color: this.props.widget.customProperties.font_color, - opacity: this.state.pressed ? (opacity + 1)/4 : opacity, - }; - - return ( -
    - -
    - ); - } -} - -export default WidgetButton; diff --git a/src/widget/widgets/button.jsx b/src/widget/widgets/button.jsx new file mode 100644 index 0000000..7dced13 --- /dev/null +++ b/src/widget/widgets/button.jsx @@ -0,0 +1,108 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState, useEffect } from 'react'; +import { Button } from 'react-bootstrap'; +import AppDispatcher from '../../common/app-dispatcher'; + +const WidgetButton = (props) => { + const [pressed, setPressed] = useState(props.widget.customProperties.pressed); + + useEffect(() => { + let widget = props.widget; + widget.customProperties.simStartedSendValue = false; + widget.customProperties.pressed = false; + + AppDispatcher.dispatch({ + type: 'widgets/start-edit', + token: props.token, + data: widget + }); + + // Effect cleanup + return () => { + // Clean up if needed + }; + }, [props.token, props.widget]); + + useEffect(() => { + if (props.widget.customProperties.simStartedSendValue) { + let widget = props.widget; + widget.customProperties.simStartedSendValue = false; + widget.customProperties.pressed = false; + AppDispatcher.dispatch({ + type: 'widgets/start-edit', + token: props.token, + data: widget + }); + + props.onInputChanged(widget.customProperties.off_value, '', false, false); + } + }, [props, setPressed]); + + useEffect(() => { + setPressed(props.widget.customProperties.pressed); + }, [props.widget.customProperties.pressed]); + + const onPress = (e) => { + if (e.button === 0 && !props.widget.customProperties.toggle) { + valueChanged(props.widget.customProperties.on_value, true); + } + }; + + const onRelease = (e) => { + if (e.button === 0) { + let nextState = false; + if (props.widget.customProperties.toggle) { + nextState = !pressed; + } + valueChanged(nextState ? props.widget.customProperties.on_value : props.widget.customProperties.off_value, nextState); + } + }; + + const valueChanged = (newValue, newPressed) => { + if (props.onInputChanged) { + props.onInputChanged(newValue, 'pressed', newPressed, true); + } + setPressed(newPressed); + }; + + let opacity = props.widget.customProperties.background_color_opacity; + const buttonStyle = { + backgroundColor: props.widget.customProperties.background_color, + borderColor: props.widget.customProperties.border_color, + color: props.widget.customProperties.font_color, + opacity: pressed ? (opacity + 1) / 4 : opacity, + }; + + return ( +
    + +
    + ); +}; + +export default WidgetButton; diff --git a/src/widget/widgets/custom-action.js b/src/widget/widgets/custom-action.js deleted file mode 100644 index cdd8078..0000000 --- a/src/widget/widgets/custom-action.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React, { Component } from 'react'; -import { Button } from 'react-bootstrap'; -import Icon from '../../common/icon'; -import ICStore from '../../ic/ic-store'; -import AppDispatcher from '../../common/app-dispatcher'; - -class WidgetCustomAction extends Component { - constructor(props) { - super(props); - - this.state = { - ic: null - }; - } - - static getStores() { - return [ ICStore ]; - } - - static getDerivedStateFromProps(props, state){ - if(props.widget.signalIDs.length === 0){ - return null; - } - - return{ - ic: ICStore.getState().find(s => s.id === props.icIDs[0]), - sessionToken: localStorage.getItem("token") - }; - } - - onClick() { - AppDispatcher.dispatch({ - type: 'ics/start-action', - ic: this.state.ic, - data: this.props.widget.customProperties.actions, - token: this.state.sessionToken - }); - } - - render() { - return
    - -
    ; - } -} - -export default WidgetCustomAction; diff --git a/src/widget/widgets/custom-action.jsx b/src/widget/widgets/custom-action.jsx new file mode 100644 index 0000000..1073249 --- /dev/null +++ b/src/widget/widgets/custom-action.jsx @@ -0,0 +1,118 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ +import React, { useState, useEffect } from "react"; +import { Button } from "react-bootstrap"; +import Icon from "../../common/icon"; +import ICStore from "../../ic/ic-store"; +import AppDispatcher from "../../common/app-dispatcher"; + +const WidgetCustomAction = (props) => { + const [ic, setIC] = useState(null); + const [sessionToken, setSessionToken] = useState( + localStorage.getItem("token") + ); + + useEffect(() => { + const handleStoresChanged = () => { + if (props.widget.signalIDs.length === 0) { + setIC(null); + return; + } + + const newIC = ICStore.getState().find((s) => s.id === props.icIDs[0]); + setIC(newIC); + }; + + // Subscribe to store changes + const unsubscribe = ICStore.subscribe(handleStoresChanged); + handleStoresChanged(); // Also call it to set initial state + + return () => { + unsubscribe(); // Clean up the subscription when the component is unmounted + }; + }, [props.widget.signalIDs, props.icIDs]); + + const onClick = () => { + AppDispatcher.dispatch({ + type: "ics/start-action", + ic: ic, + data: props.widget.customProperties.actions, + token: sessionToken, + }); + }; + + return ( +
    + +
    + ); +}; + +export default WidgetCustomAction; + +// import React, { Component } from 'react'; +// import { Button } from 'react-bootstrap'; +// import Icon from '../../common/icon'; +// import ICStore from '../../ic/ic-store'; +// import AppDispatcher from '../../common/app-dispatcher'; + +// class WidgetCustomAction extends Component { +// constructor(props) { +// super(props); + +// this.state = { +// ic: null +// }; +// } + +// static getStores() { +// return [ ICStore ]; +// } + +// static getDerivedStateFromProps(props, state){ +// if(props.widget.signalIDs.length === 0){ +// return null; +// } + +// return{ +// ic: ICStore.getState().find(s => s.id === props.icIDs[0]), +// sessionToken: localStorage.getItem("token") +// }; +// } + +// onClick() { +// AppDispatcher.dispatch({ +// type: 'ics/start-action', +// ic: this.state.ic, +// data: this.props.widget.customProperties.actions, +// token: this.state.sessionToken +// }); +// } + +// render() { +// return
    +// +//
    ; +// } +// } + +// export default WidgetCustomAction; diff --git a/src/widget/widgets/html.js b/src/widget/widgets/html.jsx similarity index 80% rename from src/widget/widgets/html.js rename to src/widget/widgets/html.jsx index e5c18a0..1f3774f 100644 --- a/src/widget/widgets/html.js +++ b/src/widget/widgets/html.jsx @@ -15,12 +15,16 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React from 'react'; +import React from "react"; -class WidgetHTML extends React.Component { - render() { - return
    - } -} +const WidgetHTML = (props) => { + return ( +
    + ); +}; export default WidgetHTML; diff --git a/src/widget/widgets/icstatus.js b/src/widget/widgets/icstatus.js deleted file mode 100644 index 2bb9d9b..0000000 --- a/src/widget/widgets/icstatus.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React from 'react'; -import { Badge } from 'react-bootstrap'; -import { stateLabelStyle } from "../../ic/ics"; -import AppDispatcher from '../../common/app-dispatcher'; - - -class WidgetICstatus extends React.Component { - constructor(props) { - super(props); - - this.state = { - sessionToken: localStorage.getItem("token") - }; - } - - componentDidMount() { - // Start timer for periodic refresh - this.timer = window.setInterval(() => this.refresh(), 3000); - } - - componentWillUnmount() { - window.clearInterval(this.timer); - } - - refresh() { - if (this.props.ics) { - this.props.ics.forEach(ic => { - let icID = parseInt(ic.id, 10); - AppDispatcher.dispatch({ - type: 'ics/start-load', - data: icID, - token: this.state.sessionToken, - }); - }) - } - } - - render() { - let badges = [] - let checkedICs = [] - if (this.props.widget) { - checkedICs = this.props.widget.customProperties.checkedIDs - } - if (this.props.ics && checkedICs) { - this.props.ics.forEach(ic => { - if (!checkedICs.includes(ic.id)) { - return - } - let badgeStyle = stateLabelStyle(ic.state, ic) - badges.push( - {ic.name + ": " + ic.state}) - }) - } - - return (
    {badges}
    ); - } -} - -export default WidgetICstatus; diff --git a/src/widget/widgets/icstatus.jsx b/src/widget/widgets/icstatus.jsx new file mode 100644 index 0000000..19b7dba --- /dev/null +++ b/src/widget/widgets/icstatus.jsx @@ -0,0 +1,71 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState, useEffect } from "react"; +import { Badge } from "react-bootstrap"; +import { stateLabelStyle } from "../../ic/ics"; +import AppDispatcher from "../../common/app-dispatcher"; + +const WidgetICstatus = (props) => { + const [sessionToken, setSessionToken] = useState( + localStorage.getItem("token") + ); + + useEffect(() => { + // Function to refresh data + const refresh = () => { + if (props.ics) { + props.ics.forEach((ic) => { + let icID = parseInt(ic.id, 10); + AppDispatcher.dispatch({ + type: "ics/start-load", + data: icID, + token: sessionToken, + }); + }); + } + }; + + // Start timer for periodic refresh + const timer = window.setInterval(() => refresh(), 3000); + + // Cleanup function equivalent to componentWillUnmount + return () => { + window.clearInterval(timer); + }; + }, [props.ics, sessionToken]); + + let badges = []; + let checkedICs = props.widget ? props.widget.customProperties.checkedIDs : []; + + if (props.ics && checkedICs) { + badges = props.ics + .filter((ic) => checkedICs.includes(ic.id)) + .map((ic) => { + let badgeStyle = stateLabelStyle(ic.state, ic); + return ( + + {ic.name + ": " + ic.state} + + ); + }); + } + + return
    {badges}
    ; +}; + +export default WidgetICstatus; diff --git a/src/widget/widgets/image.js b/src/widget/widgets/image.js deleted file mode 100644 index f289324..0000000 --- a/src/widget/widgets/image.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React from 'react'; - -import AppDispatcher from '../../common/app-dispatcher'; - -class WidgetImage extends React.Component { - - constructor(props) { - super(props); - - this.state = { - file: undefined, - } - } - - componentDidMount() { - // Query the image referenced by the widget - let widgetFile = this.props.widget.customProperties.file; - if (widgetFile !== -1 && this.state.file === undefined) { - AppDispatcher.dispatch({ - type: 'files/start-download', - data: widgetFile, - token: this.props.token - }); - } - } - - componentDidUpdate(prevProps: Readonly

    , prevState: Readonly, snapshot: SS) { - - if(this.props.widget.customProperties.file === -1){ - this.props.widget.customProperties.update = false; - if(this.state.file !== undefined) this.setState({ file: undefined }) - } - - let file = this.props.files.find(file => file.id === parseInt(this.props.widget.customProperties.file, 10)); - - if (file !== undefined) { - if (this.props.widget.customProperties.update) { - this.props.widget.customProperties.update = false; - AppDispatcher.dispatch({ - type: 'files/start-download', - data: file.id, - token: this.props.token - }); - this.setState({ file: file }) - } - } - - } - - imageError(e){ - console.error("Image ", this.state.file.name, "cannot be displayed."); - } - - render() { - let objectURL='' - if(this.state.file !== undefined && this.state.file.objectURL !== undefined) { - objectURL = this.state.file.objectURL - } - - return ( -

    - {objectURL !== '' ? ( - this.imageError(e)} className="full" alt={this.state.file.name} src={objectURL} onDragStart={e => e.preventDefault()} /> - ) : ( - No file selected. - )} -
    - ); - } -} - -export default WidgetImage; diff --git a/src/widget/widgets/image.jsx b/src/widget/widgets/image.jsx new file mode 100644 index 0000000..8b658d8 --- /dev/null +++ b/src/widget/widgets/image.jsx @@ -0,0 +1,78 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState, useEffect } from "react"; +import AppDispatcher from "../../common/app-dispatcher"; + +const WidgetImage = (props) => { + const [file, setFile] = useState(undefined); + + useEffect(() => { + let widgetFile = props.widget.customProperties.file; + if (widgetFile !== -1 && file === undefined) { + AppDispatcher.dispatch({ + type: "files/start-download", + data: widgetFile, + token: props.token, + }); + } + }, [file, props.token, props.widget.customProperties.file]); + + useEffect(() => { + if (props.widget.customProperties.file === -1) { + props.widget.customProperties.update = false; + if (file !== undefined) setFile(undefined); + } else { + let foundFile = props.files.find( + (f) => f.id === parseInt(props.widget.customProperties.file, 10) + ); + if (foundFile && props.widget.customProperties.update) { + props.widget.customProperties.update = false; + AppDispatcher.dispatch({ + type: "files/start-download", + data: foundFile.id, + token: props.token, + }); + setFile(foundFile); + } + } + }, [props.widget.customProperties, props.files, props.token, file]); + + const imageError = (e) => { + console.error("Image error:", e); + }; + + let objectURL = file && file.objectURL ? file.objectURL : ""; + + return ( +
    + {objectURL ? ( + {file.name} e.preventDefault()} + /> + ) : ( + No file selected. + )} +
    + ); +}; + +export default WidgetImage; diff --git a/src/widget/widgets/label.js b/src/widget/widgets/label.jsx similarity index 63% rename from src/widget/widgets/label.js rename to src/widget/widgets/label.jsx index 2a29e1f..141d1c7 100644 --- a/src/widget/widgets/label.js +++ b/src/widget/widgets/label.jsx @@ -15,23 +15,20 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { Component } from 'react'; +import React from "react"; +const WidgetLabel = (props) => { + const style = { + fontSize: props.widget.customProperties.textSize + "px", + color: props.widget.customProperties.fontColor, + opacity: props.widget.customProperties.fontColor_opacity, + }; -class WidgetLabel extends Component { - render() { - const style = { - fontSize: this.props.widget.customProperties.textSize + 'px', - color: this.props.widget.customProperties.fontColor, - opacity: this.props.widget.customProperties.fontColor_opacity, - }; - - return ( -
    -

    {this.props.widget.name}

    -
    - ); - } -} + return ( +
    +

    {props.widget.name}

    +
    + ); +}; export default WidgetLabel; diff --git a/src/widget/widgets/lamp.js b/src/widget/widgets/lamp.js deleted file mode 100644 index 43603e4..0000000 --- a/src/widget/widgets/lamp.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React, { Component } from 'react'; - - -class WidgetLamp extends Component { - constructor(props) { - super(props); - - this.state = { - value: '', - }; - } - - static getDerivedStateFromProps(props, state){ - if(props.widget.signalIDs.length === 0){ - return{ value: ''}; - } - - // get the signal with the selected signal ID - let signalID = props.widget.signalIDs[0]; - let signal = props.signals.filter(s => s.id === signalID) - - if(signal.length>0) { - // determine ID of infrastructure component related to signal[0] (there is only one signal for a lamp widget) - let icID = props.icIDs[signal[0].id]; - - // check if data available - if (props.data == null - || props.data[icID] == null - || props.data[icID].output == null - || props.data[icID].output.values == null) { - return {value: ''}; - } - - // check if value has changed - const data = props.data[icID].output.values[signal[0].index]; - if (data != null && Number(state.value) !== signal[0].scalingFactor * data[data.length - 1].y) { - return {value: signal[0].scalingFactor * data[data.length - 1].y}; - } - } - - return null; - } - - render() { - - let color; - let opacity; - - if (Number(this.state.value) > Number(this.props.widget.customProperties.threshold)){ - color = this.props.widget.customProperties.on_color; - opacity = this.props.widget.customProperties.on_color_opacity; - } - else{ - color = this.props.widget.customProperties.off_color; - opacity = this.props.widget.customProperties.off_color_opacity; - } - - let style = { - backgroundColor: color, - opacity: opacity - } - - return ( -
    - ); - } -} - -export default WidgetLamp; diff --git a/src/widget/widgets/lamp.jsx b/src/widget/widgets/lamp.jsx new file mode 100644 index 0000000..c44cdd0 --- /dev/null +++ b/src/widget/widgets/lamp.jsx @@ -0,0 +1,72 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState, useEffect } from 'react'; + +const WidgetLamp = (props) => { + const [value, setValue] = useState(''); + + useEffect(() => { + if(props.widget.signalIDs.length === 0){ + setValue(''); + return; + } + + let signalID = props.widget.signalIDs[0]; + let signal = props.signals.find(s => s.id === signalID); + + if(signal) { + let icID = props.icIDs[signal.id]; + + if (!(props.data && + props.data[icID] && + props.data[icID].output && + props.data[icID].output.values)) { + setValue(''); + return; + } + + const data = props.data[icID].output.values[signal.index]; + if(data) { + const newValue = String(signal.scalingFactor * data[data.length - 1].y); + if (value !== newValue) { + setValue(newValue); + } + } + } + }, [props.widget.signalIDs, props.signals, props.icIDs, props.data, value]); + + let color, opacity; + if (Number(value) > Number(props.widget.customProperties.threshold)) { + color = props.widget.customProperties.on_color; + opacity = props.widget.customProperties.on_color_opacity; + } else { + color = props.widget.customProperties.off_color; + opacity = props.widget.customProperties.off_color_opacity; + } + + let style = { + backgroundColor: color, + opacity: opacity + }; + + return ( +
    + ); +}; + +export default WidgetLamp; \ No newline at end of file diff --git a/src/widget/widgets/line.js b/src/widget/widgets/line.js deleted file mode 100644 index 2250907..0000000 --- a/src/widget/widgets/line.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React, { Component } from 'react'; - -class WidgetLine extends Component { - // WidgetLine is newly created when widget props are changed and saved - constructor(props) { - super(props); - this.illustrateDuringEdit = this.illustrateDuringEdit.bind(this); - - this.state = { - width: 0, - height: 0, - editing: false - } - } - - // needed to update the looks of the line in edit mode - illustrateDuringEdit(newwidth, newheight) { - this.setState({width: newwidth, height: newheight, editing: true}); - } - - render() { - let rotation = this.props.widget.customProperties.rotation; - let rad = rotation * (Math.PI / 180); - - // get the dimensions either from props (saved widget) - // or from the state (widget in edit mode) - let width = this.props.widget.width; - let height = this.props.widget.height; - - if (this.state.editing) { - width = this.state.width; - height = this.state.height; - } - - let length = width; - rotation = Math.abs(parseInt(rotation,10)); - if(rotation % 90 === 0 && (rotation/90) % 2 === 1){ - length = height; - } - - // calculate line coordinates (in percent) - const x1 = width * 0.5 - 0.5 * Math.cos(rad) * length; - const x1p = '' + Math.round(100 * x1 / width) + '%'; - - const x2 = width * 0.5 + 0.5 * Math.cos(rad) * length; - const x2p = '' + Math.round(100 * x2/width) + '%'; - - const y1 = height * 0.5 + 0.5 * Math.sin(rad) * length; - const y1p = '' + Math.round(100 * y1/height) + '%'; - - const y2 = height * 0.5 - 0.5 * Math.sin(rad) * length; - const y2p = '' + Math.round(100 * y2/height) + '%'; - - - const lineStyle = { - stroke: '' + this.props.widget.customProperties.border_color, - strokeWidth: '' + this.props.widget.customProperties.border_width + 'px' - }; - - return - - ; - } -} - -export default WidgetLine; diff --git a/src/widget/widgets/line.jsx b/src/widget/widgets/line.jsx new file mode 100644 index 0000000..d1f6648 --- /dev/null +++ b/src/widget/widgets/line.jsx @@ -0,0 +1,70 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState } from "react"; + +const WidgetLine = (props) => { + const [dimensions, setDimensions] = useState({ + width: props.widget.width || 0, + height: props.widget.height || 0, + editing: false, + }); + + const illustrateDuringEdit = (newWidth, newHeight) => { + setDimensions({ width: newWidth, height: newHeight, editing: true }); + }; + + // Assuming illustrateDuringEdit may be called from outside to update the dimensions. + // If not, you can remove this line. + props.illustrateDuringEditRef && + props.illustrateDuringEditRef(illustrateDuringEdit); + + let { rotation } = props.widget.customProperties; + let rad = rotation * (Math.PI / 180); + let length = dimensions.editing ? dimensions.width : props.widget.width; + + rotation = Math.abs(parseInt(rotation, 10)); + if (rotation % 90 === 0 && (rotation / 90) % 2 === 1) { + length = dimensions.editing ? dimensions.height : props.widget.height; + } + + // calculate line coordinates (in percent) + const x1 = length * 0.5 - 0.5 * Math.cos(rad) * length; + const x1p = `${Math.round((100 * x1) / length)}%`; + + const x2 = length * 0.5 + 0.5 * Math.cos(rad) * length; + const x2p = `${Math.round((100 * x2) / length)}%`; + + const y1 = length * 0.5 + 0.5 * Math.sin(rad) * length; + const y1p = `${Math.round((100 * y1) / length)}%`; + + const y2 = length * 0.5 - 0.5 * Math.sin(rad) * length; + const y2p = `${Math.round((100 * y2) / length)}%`; + + const lineStyle = { + stroke: props.widget.customProperties.border_color, + strokeWidth: `${props.widget.customProperties.border_width}px`, + }; + + return ( + + + + ); +}; + +export default WidgetLine; diff --git a/src/widget/widgets/plot.js b/src/widget/widgets/plot.js deleted file mode 100644 index 27041b0..0000000 --- a/src/widget/widgets/plot.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React from 'react'; - -import Plot from '../widget-plot/plot'; -import PlotLegend from '../widget-plot/plot-legend'; - -class WidgetPlot extends React.Component { - constructor(props) { - super(props); - - this.state = { - data: [], - signals: [] - }; - } - - - static getDerivedStateFromProps(props, state){ - - let intersection = [] - let data = []; - let signalID, sig; - for (signalID of props.widget.signalIDs) { - for (sig of props.signals) { - if (signalID === sig.id) { - intersection.push(sig); - - // sig is a selected signal, get data - // determine ID of infrastructure component related to signal (via config) - let icID = props.icIDs[sig.id] - - // distinguish between input and output signals - if (sig.direction === "out") { - if (props.data[icID] != null && props.data[icID].output != null && props.data[icID].output.values != null) { - if (props.data[icID].output.values[sig.index] !== undefined) { - let values = props.data[icID].output.values[sig.index]; - if(sig.scalingFactor !== 1) { - let scaledValues = JSON.parse(JSON.stringify(values)); - for (let i=0; i< scaledValues.length; i++){ - scaledValues[i].y = scaledValues[i].y * sig.scalingFactor; - } - data.push(scaledValues); - } else { - data.push(values); - } - } - } - } else if (sig.direction === "in") { - if (props.data[icID] != null && props.data[icID].input != null && props.data[icID].input.values != null) { - if (props.data[icID].input.values[sig.index] !== undefined) { - let values = props.data[icID].output.values[sig.index]; - if(sig.scalingFactor !== 1) { - let scaledValues = JSON.parse(JSON.stringify(values)); - for (let i=0; i< scaledValues.length; i++){ - scaledValues[i].y = scaledValues[i].y * sig.scalingFactor; - } - data.push(scaledValues); - } else { - data.push(values); - } - } - } - } - } // sig is selected signal - } // loop over props.signals - } // loop over selected signals - - return {signals: intersection, data: data} - - } - - //do we need this function? - scaleData(data, scaleFactor){ - // data is an array of value pairs x,y - } - - render() { - return
    -
    - -
    - -
    ; - } -} - -export default WidgetPlot; diff --git a/src/widget/widgets/plot.jsx b/src/widget/widgets/plot.jsx new file mode 100644 index 0000000..74d5a16 --- /dev/null +++ b/src/widget/widgets/plot.jsx @@ -0,0 +1,96 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState, useEffect } from "react"; +import Plot from "../widget-plot/plot"; +import PlotLegend from "../widget-plot/plot-legend"; + +const WidgetPlot = (props) => { + const [data, setData] = useState([]); + const [signals, setSignals] = useState([]); + + useEffect(() => { + const intersection = []; + const plotData = []; + let signalID, sig; + for (signalID of props.widget.signalIDs) { + for (sig of props.signals) { + if (signalID === sig.id) { + intersection.push(sig); + + // Signal is a selected signal, get data + let icID = props.icIDs[sig.id]; + let values = null; + + if ( + sig.direction === "out" && + props.data[icID]?.output?.values?.[sig.index] !== undefined + ) { + values = props.data[icID].output.values[sig.index]; + } else if ( + sig.direction === "in" && + props.data[icID]?.input?.values?.[sig.index] !== undefined + ) { + values = props.data[icID].input.values[sig.index]; + } + + if (values) { + if (sig.scalingFactor !== 1) { + values = values.map((v) => ({ + ...v, + y: v.y * sig.scalingFactor, + })); + } + plotData.push(values); + } + } + } + } + + setData(plotData); + setSignals(intersection); + }, [props.widget.signalIDs, props.signals, props.icIDs, props.data]); + + return ( +
    +
    + +
    + +
    + ); +}; + +export default WidgetPlot; diff --git a/src/widget/widgets/slider.js b/src/widget/widgets/slider.js deleted file mode 100644 index ea7be28..0000000 --- a/src/widget/widgets/slider.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React, { Component } from 'react'; -import { format } from 'd3'; -import classNames from 'classnames'; -import Slider from 'rc-slider'; -import 'rc-slider/assets/index.css'; -import AppDispatcher from '../../common/app-dispatcher'; - - -class WidgetSlider extends Component { - - static get OrientationTypes() { - return ({ - HORIZONTAL: {value: 0, name: 'Horizontal'}, - VERTICAL: {value: 1, name: 'Vertical'} - }) - } - - constructor(props) { - super(props); - - this.state = { - unit: '', - value: '', - }; - } - - componentDidMount() { - let widget = this.props.widget - widget.customProperties.simStartedSendValue = false - AppDispatcher.dispatch({ - type: 'widgets/start-edit', - token: this.props.token, - data: widget - }); - } - - componentDidUpdate() { - // a simulaton was started, make an update - if (this.props.widget.customProperties.simStartedSendValue) { - let widget = this.props.widget - widget.customProperties.simStartedSendValue = false - AppDispatcher.dispatch({ - type: 'widgets/start-edit', - token: this.props.token, - data: widget - }); - - // send value without changing widget - this.props.onInputChanged(widget.customProperties.value , '', '', false); - } - } - - static getDerivedStateFromProps(props, state){ - - let value = '' - let unit = '' - - if(props.widget.customProperties.hasOwnProperty('value') && props.widget.customProperties.value !== state.value){ - // set value to customProperties.value if this property exists and the value is different from current state - value = Number(props.widget.customProperties.value); - } else if (state.value === '') { - value = 0.0; - } - - // Update unit (assuming there is exactly one signal for this widget) - if (props.widget.signalIDs.length > 0) { - let signalID = props.widget.signalIDs[0]; - let signal = props.signals.find(sig => sig.id === signalID); - if (signal !== undefined) { - unit = signal.unit; - } - } - - if (unit !== '' && value !== ''){ - // unit and value have changed - return {unit: unit, value: value}; - } else if (unit !== ''){ - // only unit has changed - return {unit: unit} - } else if (value !== ''){ - // only value has changed - return {value: value} - } else { - // nothing has changed - return null - } - } - - valueIsChanging(newValue) { - this.props.widget.customProperties.value = newValue; - if (this.props.widget.customProperties.continous_update) - this.valueChanged(newValue, false); - - this.setState({ value: newValue }); - } - - valueChanged(newValue, isFinalChange) { - if (this.props.onInputChanged) { - this.props.onInputChanged(newValue, 'value', newValue, isFinalChange); - } - } - - render() { - - let isVertical = this.props.widget.customProperties.orientation === WidgetSlider.OrientationTypes.VERTICAL.value; - let fields = { - name: this.props.widget.name, - control: this.valueIsChanging(v) } - onAfterChange={ (v) => this.valueChanged(v, true) - }/>, - value: { format('.2f')(Number.parseFloat(this.state.value)) }, - unit: { this.state.unit } - } - - let widgetClasses = classNames({ - 'slider-widget': true, - 'full': true, - 'vertical': isVertical, - 'horizontal': !isVertical - }); - - return ( - <> -
    - { fields.name } - { fields.value } - {this.props.widget.customProperties.showUnit && fields.unit} -
    -
    - { fields.control } -
    - - ); - } -} - -export default WidgetSlider; diff --git a/src/widget/widgets/slider.jsx b/src/widget/widgets/slider.jsx new file mode 100644 index 0000000..89d33fd --- /dev/null +++ b/src/widget/widgets/slider.jsx @@ -0,0 +1,148 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { useState, useEffect } from "react"; +import { format } from "d3"; +import classNames from "classnames"; +import Slider from "rc-slider"; +import "rc-slider/assets/index.css"; +import AppDispatcher from "../../common/app-dispatcher"; + +const WidgetSlider = (props) => { + const [value, setValue] = useState(""); + const [unit, setUnit] = useState(""); + + useEffect(() => { + let widget = { ...props.widget }; + widget.customProperties.simStartedSendValue = false; + AppDispatcher.dispatch({ + type: "widgets/start-edit", + token: props.token, + data: widget, + }); + }, [props.token, props.widget]); + + useEffect(() => { + // A simulation was started, make an update + if (props.widget.customProperties.simStartedSendValue) { + let widget = { ...props.widget }; + widget.customProperties.simStartedSendValue = false; + AppDispatcher.dispatch({ + type: "widgets/start-edit", + token: props.token, + data: widget, + }); + + // Send value without changing widget + props.onInputChanged(widget.customProperties.value, "", "", false); + } + }, [props.token, props.widget, props.onInputChanged]); + + useEffect(() => { + let newValue = ""; + let newUnit = ""; + + if ( + props.widget.customProperties.hasOwnProperty("value") && + props.widget.customProperties.value !== value + ) { + newValue = Number(props.widget.customProperties.value); + } else if (value === "") { + newValue = 0.0; + } + + if (props.widget.signalIDs.length > 0) { + let signalID = props.widget.signalIDs[0]; + let signal = props.signals.find((sig) => sig.id === signalID); + if (signal !== undefined) { + newUnit = signal.unit; + } + } + + if (newUnit) { + setUnit(newUnit); + } + if (newValue !== "") { + setValue(newValue); + } + }, [props.signals, props.widget, value]); + + const valueIsChanging = (newValue) => { + props.widget.customProperties.value = newValue; + if (props.widget.customProperties.continous_update) { + valueChanged(newValue, false); + } + setValue(newValue); + }; + + const valueChanged = (newValue, isFinalChange) => { + if (props.onInputChanged) { + props.onInputChanged(newValue, "value", newValue, isFinalChange); + } + }; + + let isVertical = + props.widget.customProperties.orientation === + WidgetSlider.OrientationTypes.VERTICAL.value; + + const fields = { + name: props.widget.name, + control: ( + valueChanged(v, true)} + /> + ), + value: ( + + {format(".2f")(Number.parseFloat(value))} + + ), + unit: {unit}, + }; + + const widgetClasses = classNames({ + "slider-widget": true, + full: true, + vertical: isVertical, + horizontal: !isVertical, + }); + + return ( + <> +
    + {fields.name} + {fields.value} + {props.widget.customProperties.showUnit && fields.unit} +
    +
    {fields.control}
    + + ); +}; + +WidgetSlider.OrientationTypes = { + HORIZONTAL: { value: 0, name: "Horizontal" }, + VERTICAL: { value: 1, name: "Vertical" }, +}; + +export default WidgetSlider; diff --git a/src/widget/widgets/table.js b/src/widget/widgets/table.js deleted file mode 100644 index 7e0f8d0..0000000 --- a/src/widget/widgets/table.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * This file is part of VILLASweb. - * - * VILLASweb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * VILLASweb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with VILLASweb. If not, see . - ******************************************************************************/ - -import React, { Component } from 'react'; -import { format } from 'd3'; - -import { Table, DataColumn } from '../../common/table'; - -class WidgetTable extends Component { - constructor(props) { - super(props); - - this.state = { - rows: [], - }; - } - - static getDerivedStateFromProps(props, state){ - - let rows = []; - let signalID, sig; - for (signalID of props.widget.signalIDs) { - for (sig of props.signals) { - if (signalID === sig.id) { - // sig is a selected signal, get data - // determine ID of infrastructure component related to signal (via config) - let icID = props.icIDs[sig.id] - - // distinguish between input and output signals - if (sig.direction === "out") { - if (props.data[icID] != null && props.data[icID].output != null && props.data[icID].output.values != null) { - if (props.data[icID].output.values[sig.index] !== undefined) { - let data = props.data[icID].output.values[sig.index]; - rows.push({ - name: sig.name, - unit: sig.unit, - value: data[data.length - 1].y * sig.scalingFactor, - scalingFactor: sig.scalingFactor - }); - - } else { - // no data available - rows.push({ - name: sig.name, - unit: sig.unit, - value: NaN, - scalingFactor: sig.scalingFactor - }) - } - } - } else if (sig.direction === "in") { - if (props.data[icID] != null && props.data[icID].input != null && props.data[icID].input.values != null) { - if (props.data[icID].input.values[sig.index] !== undefined) { - let data = props.data[icID].input.values[sig.index]; - rows.push({ - name: sig.name, - unit: sig.unit, - value: data[data.length - 1].y * sig.scalingFactor, - scalingFactor: sig.scalingFactor - }); - } else { - // no data available - rows.push({ - name: sig.name, - unit: sig.unit, - value: NaN, - scalingFactor: sig.scalingFactor - }) - } - } - } - } // sig is selected signal - } // loop over props.signals - } // loop over selected signals - - return {rows: rows} - - } - - render() { - - - let showScalingFactor; - if (this.props.widget.customProperties.showScalingFactor !== undefined){ // this line ensures backwards compatibility with older versions of VILLASweb - showScalingFactor = this.props.widget.customProperties.showScalingFactor; - } else { - showScalingFactor = true; - } - - let rows = this.state.rows; - - if(rows.length === 0){ - rows.push({ - name: "no entries" - }) - } - - let columns = [ - , - , - ]; - - let nextKey = 3; - if (showScalingFactor) { - columns.push(); - nextKey++; - } - if (this.props.widget.customProperties.showUnit) { - columns.push(); - } - - return ( -
    - - { columns } -
    -
    - ); - } -} - -export default WidgetTable; diff --git a/src/widget/widgets/table.jsx b/src/widget/widgets/table.jsx new file mode 100644 index 0000000..e87fce7 --- /dev/null +++ b/src/widget/widgets/table.jsx @@ -0,0 +1,111 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ +import React, { useState, useEffect } from "react"; +import { format } from "d3"; +import { Table, DataColumn } from "../../common/table"; + +const WidgetTable = (props) => { + const [rows, setRows] = useState([]); + + useEffect(() => { + let newRows = []; + let signalID, sig; + for (signalID of props.widget.signalIDs) { + for (sig of props.signals) { + if (signalID === sig.id) { + let icID = props.icIDs[sig.id]; + + let direction = sig.direction === "out" ? "output" : "input"; + if ( + props.data[icID] && + props.data[icID][direction] && + props.data[icID][direction].values + ) { + if (props.data[icID][direction].values[sig.index] !== undefined) { + let data = props.data[icID][direction].values[sig.index]; + newRows.push({ + name: sig.name, + unit: sig.unit, + value: data[data.length - 1].y * sig.scalingFactor, + scalingFactor: sig.scalingFactor, + }); + } else { + newRows.push({ + name: sig.name, + unit: sig.unit, + value: NaN, + scalingFactor: sig.scalingFactor, + }); + } + } + } + } + } + + if (newRows.length === 0) { + newRows.push({ name: "no entries" }); + } + + setRows(newRows); + }, [props.widget.signalIDs, props.signals, props.icIDs, props.data]); + + let showScalingFactor = + props.widget.customProperties.showScalingFactor !== undefined + ? props.widget.customProperties.showScalingFactor + : true; + + let columns = [ + , + , + ]; + + let nextKey = 3; + if (showScalingFactor) { + columns.push( + + ); + nextKey++; + } + if (props.widget.customProperties.showUnit) { + columns.push(); + } + + return ( +
    + {columns}
    +
    + ); +}; + +export default WidgetTable;