onChange("formula", e.target.value)} />
+
+ );
+};
+
+Formula.propTypes = {
+ data: PropTypes.object,
+ onChange: PropTypes.func
+};
+
+export default Formula;
diff --git a/web/client/components/widgets/builder/wizard/common/WPSWidgetOptions.jsx b/web/client/components/widgets/builder/wizard/common/WPSWidgetOptions.jsx
index cbd8ca4eba..015e455035 100644
--- a/web/client/components/widgets/builder/wizard/common/WPSWidgetOptions.jsx
+++ b/web/client/components/widgets/builder/wizard/common/WPSWidgetOptions.jsx
@@ -8,8 +8,12 @@
import React, {useEffect, useState} from 'react';
import { head, get} from 'lodash';
import { Row, Col, Form, FormGroup, FormControl, ControlLabel, Glyphicon, OverlayTrigger, Tooltip } from 'react-bootstrap';
-import Message from '../../../../I18N/Message';
+import PropTypes from 'prop-types';
import Select from 'react-select';
+import classNames from 'classnames';
+import uuid from 'uuid';
+
+import Message from '../../../../I18N/Message';
import ColorRamp from '../../../../styleeditor/ColorRamp';
import { generateRandomHexColor } from '../../../../../utils/ColorUtils';
import Button from '../../../../misc/Button';
@@ -17,10 +21,9 @@ import ConfirmModal from '../../../../../components/resources/modals/ConfirmModa
import StepHeader from '../../../../misc/wizard/StepHeader';
import SwitchButton from '../../../../misc/switch/SwitchButton';
import ChartAdvancedOptions from './ChartAdvancedOptions';
+import CounterAdvancedOptions from './CounterAdvancedOptions';
import ColorClassModal from '../chart/ColorClassModal';
import { defaultColorGenerator } from '../../../../charts/WidgetChart';
-import classNames from 'classnames';
-import uuid from 'uuid';
const DEFAULT_CUSTOM_COLOR_OPTIONS = {
base: 190,
@@ -101,7 +104,7 @@ const formatAutoColorOptions = (classification, attributeType) => (
))
);
-export default ({
+const WPSWidgetOptions = ({
hasAggregateProcess,
data = { options: {}, autoColorOptions: {} },
onChange = () => { },
@@ -116,7 +119,8 @@ export default ({
},
aggregationOptions = [],
sampleChart,
- layer }) => {
+ layer
+}) => {
const [showModal, setShowModal] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
@@ -346,12 +350,34 @@ export default ({
: null}
{formOptions.advancedOptions && data.widgetType === "chart" && (data.type === "bar" || data.type === "line")
- ?
+ ?
+ : null}
+ {formOptions.advancedOptions && data.widgetType === "counter"
+ ?
: null}
-
);
};
+
+WPSWidgetOptions.propTypes = {
+ aggregationOptions: PropTypes.array,
+ data: PropTypes.object,
+ formOptions: PropTypes.object,
+ hasAggregateProcess: PropTypes.bool,
+ layer: PropTypes.object,
+ onChange: PropTypes.func,
+ options: PropTypes.array,
+ sampleChart: PropTypes.node,
+ showTitle: PropTypes.bool
+};
+export default WPSWidgetOptions;
diff --git a/web/client/components/widgets/widget/CounterView.jsx b/web/client/components/widgets/widget/CounterView.jsx
index ad30dd2dc4..200aab4147 100644
--- a/web/client/components/widgets/widget/CounterView.jsx
+++ b/web/client/components/widgets/widget/CounterView.jsx
@@ -6,46 +6,107 @@
* LICENSE file in the root directory of this source tree.
*/
+import { compose } from 'recompose';
+import { get } from 'lodash';
+import { Textfit } from 'react-textfit';
+import PropTypes from 'prop-types';
+import {format} from 'd3-format';
+import React from 'react';
import loadingStateFactory from '../../misc/enhancers/loadingState';
-
-const loadingState = loadingStateFactory();
import errorChartState from '../enhancers/errorChartState';
import emptyChartState from '../enhancers/emptyChartState';
-import FormatNumber from '../../I18N/Number';
-import { compose } from 'recompose';
-import { get } from 'lodash';
-import { Textfit } from 'react-textfit';
-const Counter = ({ value = "", uom = "", ...props } = {}) => (
- {uom}
-);
+
+import { parseExpression } from '../../../utils/ExpressionUtils';
+
+const loadingState = loadingStateFactory();
+const processFormula = (v, formula = "") => {
+ const value = v;
+ try {
+ return parseExpression(formula, {value});
+ } catch {
+ // if error (e.g. null values), return the value itself
+ return v;
+ }
+};
+const Counter = ({
+ value = "",
+ uom = "",
+ formula = "",
+ counterOpts = {
+ tickPrefix: "",
+ tickSuffix: ""
+ },
+ ...props
+} = {}) =>{
+ let val = value;
+ if (formula) {
+ val = processFormula(value, formula);
+ }
+ if (counterOpts?.format) {
+ try {
+ const formatter = format(counterOpts.format);
+ val = formatter(val);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ return (
+
+ {counterOpts?.tickPrefix ? counterOpts.tickPrefix : null}
+
+
+ {val}
+
+
+ {counterOpts?.tickSuffix || uom}
+
+ );
+};
const enhanceCounter = compose(
loadingState,
errorChartState,
emptyChartState
);
-import React from 'react';
-export default enhanceCounter(({ series = [], data = [], options = {}, style = {
- width: "100%",
- height: "100%",
- transform: "translate(-50%, -50%)",
- position: "absolute",
- display: "inline",
- padding: "1%",
- top: "50%",
- left: "50%"
-}} ) => {
+const CounterView = enhanceCounter(({
+ series = [],
+ data = [],
+ options = {},
+ style = {
+ width: "100%",
+ height: "100%",
+ transform: "translate(-50%, -50%)",
+ position: "absolute",
+ display: "inline",
+ padding: "1%",
+ top: "50%",
+ left: "50%"
+ },
+ counterOpts,
+ formula
+}) => {
const renderCounter = ({ dataKey } = {}, i) => ();
return ({series.map(renderCounter)}
);
});
+
+Counter.propTypes = {
+ uom: PropTypes.string,
+ value: PropTypes.string,
+ formula: PropTypes.string,
+ counterOpts: PropTypes.object
+};
+export default CounterView;
diff --git a/web/client/plugins/widgetbuilder/CounterBuilder.jsx b/web/client/plugins/widgetbuilder/CounterBuilder.jsx
index eec10ba5a8..62acc82c29 100644
--- a/web/client/plugins/widgetbuilder/CounterBuilder.jsx
+++ b/web/client/plugins/widgetbuilder/CounterBuilder.jsx
@@ -89,8 +89,9 @@ export default chooseLayerEnhancer(({ enabled, onClose = () => { }, exitButton,
>
{enabled ? : null}
));