WIP: Refactor code

This commit is contained in:
uwap 2017-11-07 06:02:01 +01:00
parent 19b91cfd0a
commit 6a3bd14343
7 changed files with 245 additions and 87 deletions

View file

@ -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
View 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);

View 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
View 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);

View file

@ -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"));

View file

@ -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 = {

View file

@ -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: {