First sketch of layers
This commit is contained in:
parent
d1dd22eb5d
commit
412d95f07a
8 changed files with 62 additions and 13 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
[ignore]
|
[ignore]
|
||||||
|
.*node_modules/react-event-listener/.*
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
src/
|
src/
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,24 @@ import AppBar from "material-ui/AppBar";
|
||||||
import CircularProgress from "material-ui/CircularProgress";
|
import CircularProgress from "material-ui/CircularProgress";
|
||||||
import MapIcon from "material-ui/svg-icons/maps/map";
|
import MapIcon from "material-ui/svg-icons/maps/map";
|
||||||
import PhonelinkOffIcon from "material-ui/svg-icons/hardware/phonelink-off";
|
import PhonelinkOffIcon from "material-ui/svg-icons/hardware/phonelink-off";
|
||||||
|
import LayersIcon from "material-ui/svg-icons/maps/layers";
|
||||||
import IconMenu from "material-ui/IconMenu";
|
import IconMenu from "material-ui/IconMenu";
|
||||||
import IconButton from "material-ui/IconButton";
|
import IconButton from "material-ui/IconButton";
|
||||||
import MenuItem from "material-ui/MenuItem";
|
import MenuItem from "material-ui/MenuItem";
|
||||||
import { orange400, grey50 } from "material-ui/styles/colors";
|
import { orange400, grey50 } from "material-ui/styles/colors";
|
||||||
|
|
||||||
|
const TopBarLayerSelector = (props: Object) => (
|
||||||
|
<IconMenu
|
||||||
|
iconButtonElement={
|
||||||
|
<IconButton style={{width: 48, height: 48, padding: 0}}
|
||||||
|
iconStyle={{width: 48, height: 48}}>
|
||||||
|
<LayersIcon color={grey50} />
|
||||||
|
</IconButton>}
|
||||||
|
style={{width:48, height:48}}>
|
||||||
|
<MenuItem primaryText="Layer1" />
|
||||||
|
</IconMenu>
|
||||||
|
)
|
||||||
|
|
||||||
const TopBarIndicatorMenu = (props: Object) => (
|
const TopBarIndicatorMenu = (props: Object) => (
|
||||||
<IconMenu
|
<IconMenu
|
||||||
iconButtonElement={
|
iconButtonElement={
|
||||||
|
|
@ -37,6 +50,7 @@ const TopBar = (props: Object) => (
|
||||||
<AppBar title={props.title}
|
<AppBar title={props.title}
|
||||||
style={{background:orange400}}
|
style={{background:orange400}}
|
||||||
iconElementLeft={<TopBarIndicator {...props} />}
|
iconElementLeft={<TopBarIndicator {...props} />}
|
||||||
|
iconElementRight={<TopBarLayerSelector {...props} />}
|
||||||
className="nav"
|
className="nav"
|
||||||
/>);
|
/>);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,24 @@ const config : Config = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
image: "img/layers/rzl/rooms.png",
|
||||||
|
forceVisibility: "on",
|
||||||
|
name: "RaumZeitLabor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "img/layers/rzl/details.png",
|
||||||
|
forceVisibility: "on",
|
||||||
|
name: "Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "img/layers/rzl/labels.png",
|
||||||
|
forceVisibility: "on",
|
||||||
|
name: "Labels"
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,7 @@ return (
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
</MuiThemeProvider>
|
</MuiThemeProvider>
|
||||||
<SpaceMap width={640} height={640} image="rzl.svg" zoom={0.1}
|
<SpaceMap width={950} height={640} image="rzl.png" zoom={0.1} state={state} />
|
||||||
store={store} state={state} />
|
|
||||||
</div>
|
</div>
|
||||||
);}
|
);}
|
||||||
|
|
||||||
|
|
|
||||||
19
src/map.js
19
src/map.js
|
|
@ -6,6 +6,7 @@ import R from "ramda";
|
||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
import { Actions } from "./state";
|
import { Actions } from "./state";
|
||||||
import { keyOf } from "./util";
|
import { keyOf } from "./util";
|
||||||
|
import { store } from "./state";
|
||||||
|
|
||||||
import ActionInfo from 'material-ui/svg-icons/action/info';
|
import ActionInfo from 'material-ui/svg-icons/action/info';
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
|
|
@ -34,18 +35,26 @@ const Markers = (props) => R.values(R.mapObjIndexed((el,key) => (
|
||||||
iconSize: Leaflet.point(32,32)
|
iconSize: Leaflet.point(32,32)
|
||||||
})}>
|
})}>
|
||||||
<Popup
|
<Popup
|
||||||
onOpen={() => props.store.dispatch({type: Actions.CHANGE_UI, payload: key})}
|
onOpen={() => store.dispatch({type: Actions.CHANGE_UI, payload: key})}
|
||||||
onClose={() => props.store.dispatch({type: Actions.CHANGE_UI})}>
|
onClose={() => store.dispatch({type: Actions.CHANGE_UI})}>
|
||||||
<span>{el.name}</span>
|
<span>{el.name}</span>
|
||||||
</Popup>
|
</Popup>
|
||||||
</Marker>
|
</Marker>
|
||||||
), R.propOr({}, "controls", Config)));
|
), R.propOr({}, "controls", Config)));
|
||||||
|
|
||||||
const SpaceMap = (props: Object) => (
|
const Layer = (layer: Layer, bounds: Array<Array<number>>) => (
|
||||||
|
<ImageOverlay url={layer.image} bounds={bounds} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const visibleLayers = (state: State) => R.filter(
|
||||||
|
x => (x.forceVisibility == null && R.contains(state.visibleLayers, x.image))
|
||||||
|
|| x.forceVisibility == "on", Config.layers)
|
||||||
|
|
||||||
|
const SpaceMap = (props: { state: State, width: number, height: number,
|
||||||
|
zoom: number, image: string}) => (
|
||||||
<Map center={c([props.width / 2, props.height / 2])} zoom={props.zoom}
|
<Map center={c([props.width / 2, props.height / 2])} zoom={props.zoom}
|
||||||
crs={Leaflet.CRS.Simple}>
|
crs={Leaflet.CRS.Simple}>
|
||||||
<ImageOverlay url={props.image}
|
{R.map(x => Layer(x, [c([0,0]), c([props.width, props.height])]), visibleLayers(props.state))}
|
||||||
bounds={[c([0,0]), c([props.width, props.height])]} />
|
|
||||||
{Markers(props)}
|
{Markers(props)}
|
||||||
</Map>
|
</Map>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ const initState : State = {
|
||||||
topic => { return {
|
topic => { return {
|
||||||
internal: keyOf(topic.values, topic.defaultValue),
|
internal: keyOf(topic.values, topic.defaultValue),
|
||||||
actual: topic.defaultValue
|
actual: topic.defaultValue
|
||||||
}}, Config.topics)
|
}}, Config.topics),
|
||||||
|
visibleLayers: []
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMessage = (state: State, action: StateAction) => {
|
const onMessage = (state: State, action: StateAction) => {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ declare type Controls = Map<string,Control>;
|
||||||
|
|
||||||
declare type Config = {
|
declare type Config = {
|
||||||
topics: Topics,
|
topics: Topics,
|
||||||
controls: Controls
|
controls: Controls,
|
||||||
|
layers: Array<Layer>
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type State = {
|
declare type State = {
|
||||||
|
|
@ -53,10 +54,17 @@ declare type State = {
|
||||||
// topic, for example given by:
|
// topic, for example given by:
|
||||||
// values: { off: "OFF", on: "ON" }
|
// values: { off: "OFF", on: "ON" }
|
||||||
// and actual is the value of that or whatever is given by mqtt.
|
// and actual is the value of that or whatever is given by mqtt.
|
||||||
values: Map<string, { internal: ?string, actual: any }>
|
values: Map<string, { internal: ?string, actual: any }>,
|
||||||
|
visibleLayers: Array<string>
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type Layer = {
|
||||||
|
image: string,
|
||||||
|
name: string,
|
||||||
|
forceVisibility?: "on"|"off"
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type StateAction = {
|
declare type StateAction = {
|
||||||
type: "DISCONNECT" | "CONNECT" | "MESSAGE" | "UI_POPUP",
|
type: "DISCONNECT" | "CONNECT" | "MESSAGE" | "UI_POPUP",
|
||||||
payload?: any
|
payload?: any
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ module.exports = {
|
||||||
extensions: ['.js', '.jsx']
|
extensions: ['.js', '.jsx']
|
||||||
},
|
},
|
||||||
entry: [
|
entry: [
|
||||||
path.resolve(__dirname, 'src/index.js')
|
path.resolve(__dirname, 'src/index.jsx')
|
||||||
],
|
],
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue