summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/components/topologies/map/layers
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/topologies/map/layers')
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js55
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js41
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js53
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js61
4 files changed, 210 insertions, 0 deletions
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js
new file mode 100644
index 00000000..2b1060c0
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js
@@ -0,0 +1,55 @@
+import PropTypes from 'prop-types'
+import React, { useMemo, useState } from 'react'
+import { Layer } from 'react-konva/lib/ReactKonva'
+import HoverTile from '../elements/HoverTile'
+import { TILE_SIZE_IN_PIXELS } from '../MapConstants'
+import { useEffectRef } from '../../../../util/effect-ref'
+
+function HoverLayerComponent({ isEnabled, isValid, onClick, children }) {
+ const [[mouseWorldX, mouseWorldY], setPos] = useState([0, 0])
+
+ const layerRef = useEffectRef((layer) => {
+ if (!layer) {
+ return
+ }
+
+ const stage = layer.getStage()
+
+ // Transform used to convert mouse coordinates to world coordinates
+ const transform = stage.getAbsoluteTransform().copy()
+ transform.invert()
+
+ stage.on('mousemove.hover', () => {
+ const { x, y } = transform.point(stage.getPointerPosition())
+ setPos([x, y])
+ })
+ return () => stage.off('mousemove.hover')
+ })
+
+ const gridX = Math.floor(mouseWorldX / TILE_SIZE_IN_PIXELS)
+ const gridY = Math.floor(mouseWorldY / TILE_SIZE_IN_PIXELS)
+ const valid = useMemo(() => isEnabled && isValid(gridX, gridY), [isEnabled, isValid, gridX, gridY])
+
+ if (!isEnabled) {
+ return <Layer />
+ }
+
+ const x = gridX * TILE_SIZE_IN_PIXELS
+ const y = gridY * TILE_SIZE_IN_PIXELS
+
+ return (
+ <Layer opacity={0.6} ref={layerRef}>
+ <HoverTile x={x} y={y} isValid={valid} onClick={() => (valid ? onClick(gridX, gridY) : undefined)} />
+ {children ? React.cloneElement(children, { x, y, scale: 1 }) : undefined}
+ </Layer>
+ )
+}
+
+HoverLayerComponent.propTypes = {
+ isEnabled: PropTypes.bool.isRequired,
+ isValid: PropTypes.func.isRequired,
+ onClick: PropTypes.func.isRequired,
+ children: PropTypes.node,
+}
+
+export default HoverLayerComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js
new file mode 100644
index 00000000..c902532b
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { Group, Layer } from 'react-konva'
+import Backdrop from '../elements/Backdrop'
+import TopologyContainer from '../TopologyContainer'
+import GridGroup from '../groups/GridGroup'
+
+function MapLayer() {
+ return (
+ <Layer>
+ <Group>
+ <Backdrop />
+ <TopologyContainer />
+ <GridGroup />
+ </Group>
+ </Layer>
+ )
+}
+
+export default MapLayer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js
new file mode 100644
index 00000000..47d9c992
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import { addRackToTile } from '../../../../redux/actions/topology/room'
+import { findTileWithPosition } from '../../../../util/tile-calculations'
+import HoverLayerComponent from './HoverLayerComponent'
+import TilePlusIcon from '../elements/TilePlusIcon'
+
+function ObjectHoverLayer() {
+ const isEnabled = useSelector((state) => state.construction.inRackConstructionMode)
+ const isValid = useSelector((state) => (x, y) => {
+ if (state.interactionLevel.mode !== 'ROOM') {
+ return false
+ }
+
+ const currentRoom = state.objects.room[state.interactionLevel.roomId]
+ const tiles = currentRoom.tiles.map((tileId) => state.objects.tile[tileId])
+ const tile = findTileWithPosition(tiles, x, y)
+
+ return !(tile === null || tile.rack)
+ })
+
+ const dispatch = useDispatch()
+ const onClick = (x, y) => dispatch(addRackToTile(x, y))
+ return (
+ <HoverLayerComponent onClick={onClick} isEnabled={isEnabled} isValid={isValid}>
+ <TilePlusIcon />
+ </HoverLayerComponent>
+ )
+}
+
+export default ObjectHoverLayer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js
new file mode 100644
index 00000000..59f83b2b
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import { toggleTileAtLocation } from '../../../../redux/actions/topology/building'
+import {
+ deriveValidNextTilePositions,
+ findPositionInPositions,
+ findPositionInRooms,
+} from '../../../../util/tile-calculations'
+import HoverLayerComponent from './HoverLayerComponent'
+
+function RoomHoverLayer() {
+ const dispatch = useDispatch()
+ const onClick = (x, y) => dispatch(toggleTileAtLocation(x, y))
+ const isEnabled = useSelector((state) => state.construction.currentRoomInConstruction !== '-1')
+ const isValid = useSelector((state) => (x, y) => {
+ const newRoom = { ...state.objects.room[state.construction.currentRoomInConstruction] }
+ const oldRooms = Object.keys(state.objects.room)
+ .map((id) => ({ ...state.objects.room[id] }))
+ .filter(
+ (room) =>
+ state.objects.topology[state.currentTopologyId].rooms.indexOf(room._id) !== -1 &&
+ room._id !== state.construction.currentRoomInConstruction
+ )
+
+ ;[...oldRooms, newRoom].forEach((room) => {
+ room.tiles = room.tiles.map((tileId) => state.objects.tile[tileId])
+ })
+ if (newRoom.tiles.length === 0) {
+ return findPositionInRooms(oldRooms, x, y) === -1
+ }
+
+ const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles)
+ return findPositionInPositions(validNextPositions, x, y) !== -1
+ })
+
+ return <HoverLayerComponent onClick={onClick} isEnabled={isEnabled} isValid={isValid} />
+}
+
+export default RoomHoverLayer