WIP: Refactor code
This commit is contained in:
parent
19b91cfd0a
commit
6a3bd14343
7 changed files with 245 additions and 87 deletions
|
|
@ -122,7 +122,7 @@ const config : Config = {
|
|||
led_stahltrager: {
|
||||
name: "LED Stahlträger",
|
||||
position: [380, 300],
|
||||
icon: "white-balance-iridescent mdi-rotate-90",
|
||||
icon: "white-balance-iridescent rotate-90",
|
||||
iconColor: state => state.led_stahltraeger == "on" ? utils.rainbow : "#000000",
|
||||
ui: [
|
||||
{
|
||||
|
|
@ -150,7 +150,7 @@ const config : Config = {
|
|||
twinkle: {
|
||||
name: "Twinkle",
|
||||
position: [530, 560],
|
||||
icon: "led-off mdi-flip-v",
|
||||
icon: "led-off flip-v",
|
||||
iconColor: state => state.twinkle == "on" ? utils.rainbow : "#000000",
|
||||
ui: [
|
||||
{
|
||||
|
|
@ -399,18 +399,30 @@ const config : Config = {
|
|||
baseLayer: true,
|
||||
name: "RaumZeitLabor",
|
||||
defaultVisibility: "visible",
|
||||
opacity: 0.7
|
||||
opacity: 0.7,
|
||||
bounds: {
|
||||
topLeft: [0, 0],
|
||||
bottomRight: [1000, 700]
|
||||
}
|
||||
},
|
||||
{
|
||||
image: require("../img/layers/rzl/details.svg"),
|
||||
name: "Details",
|
||||
defaultVisibility: "visible",
|
||||
opacity: 0.4
|
||||
opacity: 0.4,
|
||||
bounds: {
|
||||
topLeft: [0, 0],
|
||||
bottomRight: [1000, 700]
|
||||
}
|
||||
},
|
||||
{
|
||||
image: require("../img/layers/rzl/labels.svg"),
|
||||
name: "Labels",
|
||||
defaultVisibility: "visible"
|
||||
defaultVisibility: "visible",
|
||||
bounds: {
|
||||
topLeft: [0, 0],
|
||||
bottomRight: [1000, 700]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
|||
63
src/components/App.js
Normal file
63
src/components/App.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// @flow
|
||||
import React from "react";
|
||||
|
||||
import MuiThemeProvider from "material-ui/styles/MuiThemeProvider";
|
||||
import createMuiTheme from "material-ui/styles/createMuiTheme";
|
||||
import withStyles from "material-ui/styles/withStyles";
|
||||
import * as Colors from "material-ui/colors";
|
||||
|
||||
import SideBar from "components/SideBar";
|
||||
import ControlMap from "components/ControlMap";
|
||||
|
||||
export type AppProps = {
|
||||
config: Config
|
||||
};
|
||||
|
||||
export type AppState = {
|
||||
selectedControl: string
|
||||
};
|
||||
|
||||
class App extends React.Component<AppProps & Classes> {
|
||||
constructor(props: AppProps & Classes) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static styles(_theme: Object) {
|
||||
return {
|
||||
drawerPaper: {
|
||||
width: 320
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get theme() {
|
||||
return createMuiTheme({
|
||||
palette: {
|
||||
primary: Colors[this.props.config.space.color]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get selectedControl(): Control {
|
||||
return this.props.config.controls[this.state.selectedControl];
|
||||
}
|
||||
|
||||
// <SpaceMapBar title={`${this.props.config.space.name} Map`} />
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<MuiThemeProvider theme={this.theme}>
|
||||
<div>
|
||||
{false && <SideBar />}
|
||||
</div>
|
||||
</MuiThemeProvider>
|
||||
<ControlMap width={1000} height={700} zoom={0}
|
||||
layers={this.props.config.layers}
|
||||
controls={this.props.config.controls}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(App.styles)(App);
|
||||
86
src/components/ControlMap.js
Normal file
86
src/components/ControlMap.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// @flow
|
||||
import React from "react";
|
||||
import { Map, ImageOverlay, Marker, LayersControl } from "react-leaflet";
|
||||
import Leaflet from "leaflet";
|
||||
|
||||
export type Point = [number, number];
|
||||
|
||||
const convertPoint = (p: Point) => [-p[1], p[0]];
|
||||
|
||||
export type ControlMapProps = {
|
||||
width: number,
|
||||
height: number,
|
||||
zoom: number,
|
||||
layers: Array<Layer>,
|
||||
controls: Controls
|
||||
};
|
||||
|
||||
export default class ControlMap extends React.Component<ControlMapProps> {
|
||||
constructor(props: SpaceMapProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
get center(): Point {
|
||||
return convertPoint([
|
||||
this.props.width / 2,
|
||||
this.props.height / 2
|
||||
]);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Map center={this.center}
|
||||
zoom={this.props.zoom}
|
||||
crs={Leaflet.CRS.Simple}>
|
||||
{this.renderMarkers()}
|
||||
{this.renderLayers()}
|
||||
</Map>
|
||||
);
|
||||
}
|
||||
|
||||
renderMarkers() {
|
||||
return Object.values(this.props.controls).map(this.renderMarker.bind(this));
|
||||
}
|
||||
|
||||
createLeafletIcon(iconRaw: string) {
|
||||
const icon = iconRaw.split(" ").map(name => "mdi-".concat(name)).join(" ");
|
||||
return Leaflet.divIcon({
|
||||
className: `mdi mdi-36px ${icon}`,
|
||||
iconSize: Leaflet.point(36, 36),
|
||||
iconAnchor: Leaflet.point(18, 18)
|
||||
});
|
||||
}
|
||||
|
||||
renderMarker(control: Control) {
|
||||
return (
|
||||
<Marker position={convertPoint(control.position)}
|
||||
key={control.name}
|
||||
icon={this.createLeafletIcon(control.icon)}
|
||||
>
|
||||
</Marker>
|
||||
);
|
||||
}
|
||||
|
||||
renderLayers() {
|
||||
return (
|
||||
<LayersControl position="topright">
|
||||
{this.props.layers.map(this.renderLayer)}
|
||||
</LayersControl>
|
||||
);
|
||||
}
|
||||
|
||||
renderLayer(layer: Layer) {
|
||||
const LayersControlType =
|
||||
layer.baseLayer ? LayersControl.BaseLayer : LayersControl.Overlay;
|
||||
return (
|
||||
<LayersControlType
|
||||
key={layer.name}
|
||||
name={layer.name}
|
||||
checked={layer.defaultVisibility === "visible"}>
|
||||
<ImageOverlay url={layer.image}
|
||||
bounds={Object.values(layer.bounds).map(convertPoint)}
|
||||
opacity={layer.opacity} />
|
||||
</LayersControlType>
|
||||
);
|
||||
}
|
||||
}
|
||||
62
src/components/SideBar.js
Normal file
62
src/components/SideBar.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// @flow
|
||||
import React from "react";
|
||||
|
||||
import withStyles from "material-ui/styles/withStyles";
|
||||
import Drawer from "material-ui/Drawer";
|
||||
import Typography from "material-ui/Typography";
|
||||
import IconButton from "material-ui/IconButton";
|
||||
import AppBar from "material-ui/AppBar";
|
||||
import Toolbar from "material-ui/Toolbar";
|
||||
import List from "material-ui/List";
|
||||
|
||||
export type SideBarProps = {
|
||||
control: Control,
|
||||
onCloseRequest: () => void
|
||||
};
|
||||
|
||||
export type SideBarState = {
|
||||
};
|
||||
|
||||
class SideBar extends React.Component<SideBarProps & Classes, SideBarState> {
|
||||
constructor(props: SideBarProps & Classes) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static styles(_theme: Object): Object {
|
||||
return {
|
||||
drawerPaper: {
|
||||
width: 320
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
close() {
|
||||
this.props.onCloseRequest();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Drawer open={true}
|
||||
anchor="right"
|
||||
onRequestClose={this.close}
|
||||
classes={{paper: this.props.classes.drawerPaper}}
|
||||
type="persistent"
|
||||
>
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<IconButton onClick={this.close}>
|
||||
<i className="mdi mdi-format-horizontal-align-right mdi-36px"></i>
|
||||
</IconButton>
|
||||
<Typography type="title">
|
||||
{this.props.control.name}
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<List id="drawer_uiComponents">
|
||||
</List>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(SideBar.styles)(SideBar);
|
||||
|
|
@ -1,24 +1,11 @@
|
|||
// @flow
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import MuiThemeProvider from "material-ui/styles/MuiThemeProvider";
|
||||
import createMuiTheme from "material-ui/styles/createMuiTheme";
|
||||
import withStyles from "material-ui/styles/withStyles";
|
||||
import Drawer from "material-ui/Drawer";
|
||||
import injectTapEventPlugin from "react-tap-event-plugin";
|
||||
import { store, Actions } from "./state";
|
||||
import connectMqtt from "./mqtt";
|
||||
import SpaceMapBar from "./appbar";
|
||||
import * as UiItems from "./UiItems.js";
|
||||
import SpaceMap from "./map.js";
|
||||
import R from "ramda";
|
||||
|
||||
import App from "components/App";
|
||||
|
||||
import Config from "./config";
|
||||
import Toolbar from "material-ui/Toolbar";
|
||||
import * as colors from "material-ui/colors";
|
||||
import Typography from "material-ui/Typography";
|
||||
import List from "material-ui/List";
|
||||
import IconButton from "material-ui/IconButton";
|
||||
import AppBar from "material-ui/AppBar";
|
||||
|
||||
import "../node_modules/mdi/css/materialdesignicons.min.css";
|
||||
import "../css/styles.css";
|
||||
|
|
@ -27,67 +14,4 @@ injectTapEventPlugin();
|
|||
|
||||
document.title = `${Config.space.name} Map`;
|
||||
|
||||
const UiItem = (state) => (props : ControlUI) =>
|
||||
UiItems[props.type](state, props);
|
||||
|
||||
const renderUi = (state: State, key: ?string) =>
|
||||
key != null && Config.controls[key] != null ?
|
||||
R.map(UiItem(state), Config.controls[key].ui) : null;
|
||||
|
||||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
primary: colors[Config.space.color]
|
||||
}
|
||||
});
|
||||
|
||||
const appStyles = withStyles((_theme) => ({
|
||||
drawerPaper: {
|
||||
width: 320
|
||||
}
|
||||
}));
|
||||
|
||||
class app extends React.Component<{state: State, classes: Object}> {
|
||||
render() {
|
||||
const state = this.props.state;
|
||||
const classes = this.props.classes;
|
||||
if (state == null) return (<div></div>);
|
||||
return (
|
||||
<div>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div>
|
||||
<SpaceMapBar title={`${Config.space.name} Map`} {...state} />
|
||||
<Drawer open={state.uiOpened != null}
|
||||
anchor="right"
|
||||
onRequestClose={() => store.dispatch({type: Actions.CHANGE_UI})}
|
||||
classes={{paper: classes.drawerPaper}}
|
||||
type="persistent"
|
||||
>
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<IconButton onClick={() => store.dispatch({type: Actions.CHANGE_UI})}>
|
||||
<i className="mdi mdi-format-horizontal-align-right mdi-36px"></i>
|
||||
</IconButton>
|
||||
<Typography type="title">
|
||||
{state.uiOpened == null ? "" : Config.controls[state.uiOpened].name}
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<List id="drawer_uiComponents">
|
||||
{renderUi(state, state.uiOpened)}
|
||||
</List>
|
||||
</Drawer>
|
||||
</div>
|
||||
</MuiThemeProvider>
|
||||
<SpaceMap width={1000} height={700} image="rzl.png" zoom={0} state={state} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const App = appStyles(app);
|
||||
|
||||
store.subscribe(() => ReactDOM.render(<App state={store.getState()} />, document.getElementById("content")));
|
||||
|
||||
store.dispatch({type:null});
|
||||
|
||||
connectMqtt(Config.space.mqtt, store);
|
||||
ReactDOM.render(<App config={Config} />, document.getElementById("content"));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
declare type Map<K,V> = { [K]: V };
|
||||
|
||||
declare type Classes = {
|
||||
classes: Map<string, string>
|
||||
};
|
||||
|
||||
declare type Topic = {
|
||||
state: string,
|
||||
command: string,
|
||||
|
|
@ -23,7 +27,7 @@ declare type ControlUI = {
|
|||
// TOGGLE optional properties
|
||||
on?: string, // on override for toggle
|
||||
off?: string, // off override for toggle
|
||||
toggled?: (internal: string, actual: any) => boolean,
|
||||
toggled?: (internal: string, actual: any, state: Map<string, any>) => boolean,
|
||||
|
||||
// DROPDOWN optional properties
|
||||
options?: Map<string,any>, //options for dropDown
|
||||
|
|
@ -70,12 +74,18 @@ declare type State = {
|
|||
visibleLayers: Array<string>
|
||||
};
|
||||
|
||||
declare type Point = [number, number];
|
||||
|
||||
declare type Layer = {
|
||||
image: string,
|
||||
name: string,
|
||||
baseLayer: boolean,
|
||||
defaultVisibility: "visible" | "hidden",
|
||||
opacity: number
|
||||
opacity: number,
|
||||
bounds: {
|
||||
topLeft: Point,
|
||||
bottomRight: Point
|
||||
}
|
||||
};
|
||||
|
||||
declare type StateAction = {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const preBuildScripts = process.env.NO_FLOW == undefined ?
|
|||
|
||||
module.exports = {
|
||||
resolve: {
|
||||
modules: [path.resolve(__dirname, "src"), "node_modules"],
|
||||
extensions: ['.js', '.jsx']
|
||||
},
|
||||
output: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue