Farmbot-Web-App/frontend/farm_designer/index.tsx

225 lines
8.1 KiB
TypeScript
Raw Permalink Normal View History

2017-06-29 12:54:02 -06:00
import * as React from "react";
import { connect } from "react-redux";
import { GardenMap } from "./map/garden_map";
2019-06-14 16:59:11 -06:00
import {
2020-02-28 09:35:32 -07:00
Props, State, BotOriginQuadrant, isBotOriginQuadrant,
2019-06-14 16:59:11 -06:00
} from "./interfaces";
2017-06-29 12:54:02 -06:00
import { mapStateToProps } from "./state_to_props";
import { Plants } from "./plants/plant_inventory";
2018-10-25 18:02:54 -06:00
import { GardenMapLegend } from "./map/legend/garden_map_legend";
2017-08-30 15:18:44 -06:00
import { NumericSetting, BooleanSetting } from "../session_keys";
2019-05-21 17:24:17 -06:00
import { isUndefined, last, isFinite } from "lodash";
2017-10-04 22:06:38 -06:00
import { AxisNumberProperty, BotSize } from "./map/interfaces";
2019-04-11 21:17:18 -06:00
import {
2020-04-13 13:24:38 -06:00
round, getPanelStatus, MapPanelStatus, mapPanelClassName, getMapPadding,
2019-04-11 21:17:18 -06:00
} from "./map/util";
2019-06-14 16:59:11 -06:00
import {
2020-02-28 09:35:32 -07:00
calcZoomLevel, getZoomLevelIndex, saveZoomLevelIndex,
2019-06-14 16:59:11 -06:00
} from "./map/zoom";
2019-02-04 13:54:17 -07:00
import moment from "moment";
2018-04-20 20:17:50 -06:00
import { DesignerNavTabs } from "./panel_header";
2019-04-09 23:17:03 -06:00
import {
2020-02-28 09:35:32 -07:00
setWebAppConfigValue, GetWebAppConfigValue,
2019-04-09 23:17:03 -06:00
} from "../config_storage/actions";
2018-09-13 16:00:14 -06:00
import { SavedGardenHUD } from "./saved_gardens/saved_gardens";
export const getDefaultAxisLength =
(getConfigValue: GetWebAppConfigValue): AxisNumberProperty => {
2019-05-21 17:24:17 -06:00
const mapSizeX = parseInt("" + getConfigValue(NumericSetting.map_size_x));
const mapSizeY = parseInt("" + getConfigValue(NumericSetting.map_size_y));
if (isFinite(mapSizeX) && isFinite(mapSizeY)) {
return { x: mapSizeX, y: mapSizeY };
}
2019-06-04 16:07:24 -06:00
return { x: 2900, y: 1400 };
};
2017-09-08 06:01:26 -06:00
export const getGridSize =
(getConfigValue: GetWebAppConfigValue, botSize: BotSize) => {
if (getConfigValue(BooleanSetting.dynamic_map)) {
// Render the map size according to device axis length.
return { x: round(botSize.x.value), y: round(botSize.y.value) };
}
// Use a default map size.
return getDefaultAxisLength(getConfigValue);
};
2017-10-04 22:06:38 -06:00
2017-09-08 06:22:29 -06:00
export const gridOffset: AxisNumberProperty = { x: 50, y: 50 };
2017-06-29 12:54:02 -06:00
2019-09-19 13:09:00 -06:00
export class RawFarmDesigner extends React.Component<Props, Partial<State>> {
2017-06-29 12:54:02 -06:00
initializeSetting =
2020-02-28 09:34:28 -07:00
(key: keyof State, defaultValue: boolean): boolean => {
const currentValue = this.props.getConfigValue(key);
if (isUndefined(currentValue)) {
2020-02-28 09:34:28 -07:00
this.props.dispatch(setWebAppConfigValue(key, defaultValue));
return defaultValue;
} else {
return !!currentValue;
}
2017-08-30 15:18:44 -06:00
}
2017-08-30 20:11:01 -06:00
getBotOriginQuadrant = (): BotOriginQuadrant => {
const value = this.props.getConfigValue(NumericSetting.bot_origin_quadrant);
2017-08-30 20:11:01 -06:00
return isBotOriginQuadrant(value) ? value : 2;
}
2019-12-05 13:53:31 -07:00
getState(): State {
const init = this.initializeSetting;
return {
legend_menu_open: init(BooleanSetting.legend_menu_open, false),
show_plants: init(BooleanSetting.show_plants, true),
show_points: init(BooleanSetting.show_points, true),
show_weeds: init(BooleanSetting.show_weeds, true),
2019-12-05 13:53:31 -07:00
show_spread: init(BooleanSetting.show_spread, false),
show_farmbot: init(BooleanSetting.show_farmbot, true),
show_images: init(BooleanSetting.show_images, false),
2020-02-07 16:05:16 -07:00
show_zones: init(BooleanSetting.show_zones, false),
2019-12-05 13:53:31 -07:00
show_sensor_readings: init(BooleanSetting.show_sensor_readings, false),
bot_origin_quadrant: this.getBotOriginQuadrant(),
zoom_level: calcZoomLevel(getZoomLevelIndex(this.props.getConfigValue)),
};
}
state: State = this.getState();
2017-06-29 12:54:02 -06:00
componentDidMount() {
this.updateBotOriginQuadrant(this.state.bot_origin_quadrant)();
2017-06-29 12:54:02 -06:00
this.updateZoomLevel(0)();
}
2020-02-28 09:34:28 -07:00
toggle = (key: keyof State) => () => {
const newValue = !this.state[key];
this.props.dispatch(setWebAppConfigValue(key, newValue));
this.setState({ [key]: newValue });
2017-08-30 15:18:44 -06:00
}
2017-06-29 12:54:02 -06:00
2017-08-30 15:18:44 -06:00
updateBotOriginQuadrant = (payload: BotOriginQuadrant) => () => {
this.setState({ bot_origin_quadrant: payload });
this.props.dispatch(setWebAppConfigValue(
NumericSetting.bot_origin_quadrant, payload));
2017-08-30 15:18:44 -06:00
}
2017-06-29 12:54:02 -06:00
2017-08-30 15:18:44 -06:00
updateZoomLevel = (zoomIncrement: number) => () => {
2018-08-27 13:55:06 -06:00
const newIndex = getZoomLevelIndex(this.props.getConfigValue) + zoomIncrement;
2018-01-18 19:49:39 -07:00
this.setState({ zoom_level: calcZoomLevel(newIndex) });
2018-08-27 13:55:06 -06:00
saveZoomLevelIndex(this.props.dispatch, newIndex);
2017-08-30 15:18:44 -06:00
}
2017-06-29 12:54:02 -06:00
childComponent(props: Props) {
2019-02-06 18:36:11 -07:00
return this.props.children || React.createElement(Plants, props);
2017-06-29 12:54:02 -06:00
}
2019-04-11 21:17:18 -06:00
get mapPanelClassName() { return mapPanelClassName(); }
2017-06-29 12:54:02 -06:00
render() {
2017-08-28 05:49:13 -06:00
const {
legend_menu_open,
show_plants,
show_points,
show_weeds,
show_spread,
show_farmbot,
2018-02-11 19:52:21 -07:00
show_images,
2020-02-07 16:05:16 -07:00
show_zones,
2018-10-15 17:32:23 -06:00
show_sensor_readings,
zoom_level
2017-06-29 12:54:02 -06:00
} = this.state;
2017-09-08 06:01:26 -06:00
const stopAtHome = {
x: !!this.props.botMcuParams.movement_stop_at_home_x,
y: !!this.props.botMcuParams.movement_stop_at_home_y
};
2018-02-20 17:09:40 -07:00
const newestImage = this.props.latestImages[0];
const oldestImage = last(this.props.latestImages);
const newestDate = newestImage ? newestImage.body.created_at : "";
const toOldest = oldestImage && newestDate
? Math.abs(moment(oldestImage.body.created_at)
.diff(moment(newestDate).clone(), "days"))
: 1;
const imageAgeInfo = { newestDate, toOldest };
2019-11-19 11:22:52 -07:00
const mapPadding = getMapPadding(getPanelStatus());
const padHeightOffset = mapPadding.top - mapPadding.top / zoom_level;
2017-06-29 12:54:02 -06:00
return <div className="farm-designer">
<GardenMapLegend
2019-04-11 21:17:18 -06:00
className={this.mapPanelClassName}
2017-06-29 12:54:02 -06:00
zoom={this.updateZoomLevel}
toggle={this.toggle}
legendMenuOpen={legend_menu_open}
showPlants={show_plants}
showPoints={show_points}
showWeeds={show_weeds}
showSpread={show_spread}
2018-02-11 19:52:21 -07:00
showFarmbot={show_farmbot}
2018-02-15 03:51:38 -07:00
showImages={show_images}
2020-02-07 16:05:16 -07:00
showZones={show_zones}
2018-10-15 17:32:23 -06:00
showSensorReadings={show_sensor_readings}
2019-06-07 18:26:12 -06:00
hasSensorReadings={this.props.sensorReadings.length > 0}
2018-02-15 03:51:38 -07:00
dispatch={this.props.dispatch}
2019-04-09 23:17:03 -06:00
timeSettings={this.props.timeSettings}
2018-02-20 17:09:40 -07:00
getConfigValue={this.props.getConfigValue}
2020-04-13 13:24:38 -06:00
shouldDisplay={this.props.shouldDisplay}
2018-02-20 17:09:40 -07:00
imageAgeInfo={imageAgeInfo} />
2017-06-29 12:54:02 -06:00
2019-04-11 21:17:18 -06:00
<DesignerNavTabs hidden={!(getPanelStatus() === MapPanelStatus.closed)} />
<div className={`farm-designer-panels ${this.mapPanelClassName}`}>
2017-06-29 12:54:02 -06:00
{this.childComponent(this.props)}
</div>
<div
2019-04-11 21:17:18 -06:00
className={`farm-designer-map ${this.mapPanelClassName}`}
2019-11-19 11:22:52 -07:00
style={{
transform: `scale(${zoom_level})`,
transformOrigin: `${mapPadding.left}px ${mapPadding.top}px`,
height: `calc(${100 / zoom_level}% + ${padHeightOffset}px)`
}}>
2017-06-29 12:54:02 -06:00
<GardenMap
showPoints={show_points}
showPlants={show_plants}
showWeeds={show_weeds}
showSpread={show_spread}
showFarmbot={show_farmbot}
2018-02-11 19:52:21 -07:00
showImages={show_images}
2020-02-07 16:05:16 -07:00
showZones={show_zones}
2018-10-15 17:32:23 -06:00
showSensorReadings={show_sensor_readings}
2017-06-29 12:54:02 -06:00
selectedPlant={this.props.selectedPlant}
crops={this.props.crops}
dispatch={this.props.dispatch}
designer={this.props.designer}
plants={this.props.plants}
2020-02-07 16:05:16 -07:00
genericPoints={this.props.genericPoints}
weeds={this.props.weeds}
2020-02-07 16:05:16 -07:00
allPoints={this.props.allPoints}
2017-06-29 12:54:02 -06:00
toolSlots={this.props.toolSlots}
2017-10-20 00:26:41 -06:00
botLocationData={this.props.botLocationData}
2020-04-13 13:24:38 -06:00
botSize={this.props.botSize}
2017-09-08 06:01:26 -06:00
stopAtHome={stopAtHome}
2017-08-24 22:37:24 -06:00
hoveredPlant={this.props.hoveredPlant}
zoomLvl={zoom_level}
2019-06-14 16:59:11 -06:00
botOriginQuadrant={this.getBotOriginQuadrant()}
2020-04-13 13:24:38 -06:00
gridSize={getGridSize(this.props.getConfigValue, this.props.botSize)}
2017-11-01 02:07:02 -06:00
gridOffset={gridOffset}
peripherals={this.props.peripherals}
2018-02-11 19:51:49 -07:00
eStopStatus={this.props.eStopStatus}
2018-02-11 19:52:44 -07:00
latestImages={this.props.latestImages}
2018-02-15 03:51:38 -07:00
cameraCalibrationData={this.props.cameraCalibrationData}
2018-10-15 17:32:23 -06:00
getConfigValue={this.props.getConfigValue}
sensorReadings={this.props.sensorReadings}
2019-04-09 23:17:03 -06:00
timeSettings={this.props.timeSettings}
2020-02-07 16:05:16 -07:00
sensors={this.props.sensors}
groups={this.props.groups}
2020-02-20 19:38:50 -07:00
mountedToolName={this.props.mountedToolName}
2020-02-07 16:05:16 -07:00
shouldDisplay={this.props.shouldDisplay} />
2017-06-29 12:54:02 -06:00
</div>
2018-09-13 16:00:14 -06:00
{this.props.designer.openedSavedGarden &&
<SavedGardenHUD dispatch={this.props.dispatch} />}
2017-08-02 17:59:34 -06:00
</div>;
2017-06-29 12:54:02 -06:00
}
}
2019-09-19 13:09:00 -06:00
export const FarmDesigner = connect(mapStateToProps)(RawFarmDesigner);