diff options
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/app/map')
14 files changed, 164 insertions, 210 deletions
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js b/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js index 45799f70..4c3b2757 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js @@ -12,9 +12,6 @@ export const WALL_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 16 export const OBJECT_BORDER_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 16 export const TILE_PLUS_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 10 -export const SIDEBAR_WIDTH = 350 -export const VIEWPORT_PADDING = 50 - export const RACK_FILL_ICON_WIDTH = OBJECT_SIZE_IN_PIXELS / 3 export const RACK_FILL_ICON_OPACITY = 0.8 diff --git a/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js b/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js index 684ddf28..5d19b3ad 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js @@ -1,64 +1,81 @@ -import React, { useEffect, useRef, useState } from 'react' +import React, { useRef, useState } from 'react' import { HotKeys } from 'react-hotkeys' import { Stage } from 'react-konva' -import { MAP_MOVE_PIXELS_PER_EVENT } from './MapConstants' -import { Provider, useDispatch, useStore } from 'react-redux' +import { MAP_MAX_SCALE, MAP_MIN_SCALE, MAP_MOVE_PIXELS_PER_EVENT, MAP_SCALE_PER_EVENT } from './MapConstants' +import { Provider, useStore } from 'react-redux' import useResizeObserver from 'use-resize-observer' import { mapContainer } from './MapStage.module.scss' -import { useMapPosition } from '../../../data/map' -import { setMapDimensions, setMapPositionWithBoundsCheck, zoomInOnPosition } from '../../../redux/actions/map' import MapLayer from './layers/MapLayer' import RoomHoverLayer from './layers/RoomHoverLayer' import ObjectHoverLayer from './layers/ObjectHoverLayer' +import ScaleIndicator from './controls/ScaleIndicator' +import Toolbar from './controls/Toolbar' function MapStage() { const store = useStore() - const dispatch = useDispatch() + const { ref, width = 100, height = 100 } = useResizeObserver() + const stageRef = useRef(null) + const [[x, y], setPos] = useState([0, 0]) + const [scale, setScale] = useState(1) + + const clampScale = (target) => Math.min(Math.max(target, MAP_MIN_SCALE), MAP_MAX_SCALE) + const moveWithDelta = (deltaX, deltaY) => setPos(([x, y]) => [x + deltaX, y + deltaY]) + + const onZoom = (e) => { + e.evt.preventDefault() + + const stage = stageRef.current.getStage() + const oldScale = scale + + const pointer = stage.getPointerPosition() + const mousePointTo = { + x: (pointer.x - x) / oldScale, + y: (pointer.y - y) / oldScale, + } + + const newScale = clampScale(e.evt.deltaY > 0 ? oldScale * MAP_SCALE_PER_EVENT : oldScale / MAP_SCALE_PER_EVENT) + + setScale(newScale) + setPos([pointer.x - mousePointTo.x * newScale, pointer.y - mousePointTo.y * newScale]) + } + const onZoomButton = (zoomIn) => + setScale((scale) => clampScale(zoomIn ? scale * MAP_SCALE_PER_EVENT : scale / MAP_SCALE_PER_EVENT)) + const onDragEnd = (e) => setPos([e.target.x(), e.target.y()]) + const onExport = () => { + const download = document.createElement('a') + download.href = stageRef.current.getStage().toDataURL() + download.download = 'opendc-canvas-export-' + Date.now() + '.png' + download.click() + } - const stage = useRef(null) - const [pos, setPos] = useState([0, 0]) - const [x, y] = pos const handlers = { MOVE_LEFT: () => moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0), MOVE_RIGHT: () => moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0), MOVE_UP: () => moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT), MOVE_DOWN: () => moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT), } - const mapPosition = useMapPosition() - const { ref, width = 100, height = 100 } = useResizeObserver() - - const moveWithDelta = (deltaX, deltaY) => - dispatch(setMapPositionWithBoundsCheck(mapPosition.x + deltaX, mapPosition.y + deltaY)) - const updateMousePosition = () => { - if (!stage.current) { - return - } - - const mousePos = stage.current.getStage().getPointerPosition() - setPos([mousePos.x, mousePos.y]) - } - const updateScale = ({ evt }) => dispatch(zoomInOnPosition(evt.deltaY < 0, x, y)) - - useEffect(() => { - window['exportCanvasToImage'] = () => { - const download = document.createElement('a') - download.href = stage.current.getStage().toDataURL() - download.download = 'opendc-canvas-export-' + Date.now() + '.png' - download.click() - } - }, [stage]) - - useEffect(() => dispatch(setMapDimensions(width, height)), [width, height]) // eslint-disable-line react-hooks/exhaustive-deps return ( <HotKeys handlers={handlers} allowChanges={true} innerRef={ref} className={mapContainer}> - <Stage ref={stage} width={width} height={height} onMouseMove={updateMousePosition} onWheel={updateScale} draggable> + <Stage + ref={stageRef} + onWheel={onZoom} + onDragEnd={onDragEnd} + draggable + width={width} + height={height} + scale={{ x: scale, y: scale }} + x={x} + y={y} + > <Provider store={store}> <MapLayer /> - <RoomHoverLayer mouseX={x} mouseY={y} /> - <ObjectHoverLayer mouseX={x} mouseY={y} /> + <RoomHoverLayer /> + <ObjectHoverLayer /> </Provider> </Stage> + <ScaleIndicator scale={scale} /> + <Toolbar onZoom={onZoomButton} onExport={onExport} /> </HotKeys> ) } diff --git a/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js index 838aea5a..dbc26f14 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js @@ -3,10 +3,10 @@ import PropTypes from 'prop-types' import { useSelector } from 'react-redux' import RackFillBar from '../../../components/app/map/elements/RackFillBar' -const RackSpaceFillContainer = (props) => { - const state = useSelector((state) => { +function RackSpaceFillContainer({ tileId, ...props }) { + const fillFraction = useSelector((state) => { let energyConsumptionTotal = 0 - const rack = state.objects.rack[state.objects.tile[props.tileId].rack] + const rack = state.objects.rack[state.objects.tile[tileId].rack] const machineIds = rack.machines machineIds.forEach((machineId) => { if (machineId !== null) { @@ -22,12 +22,9 @@ const RackSpaceFillContainer = (props) => { } }) - return { - type: 'energy', - fillFraction: Math.min(1, energyConsumptionTotal / rack.powerCapacityW), - } + return Math.min(1, energyConsumptionTotal / rack.powerCapacityW) }) - return <RackFillBar {...props} {...state} /> + return <RackFillBar {...props} type="energy" fillFraction={fillFraction} /> } RackSpaceFillContainer.propTypes = { diff --git a/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js index 6791120e..7ca5c930 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js @@ -25,15 +25,9 @@ import PropTypes from 'prop-types' import { useSelector } from 'react-redux' import RackFillBar from '../../../components/app/map/elements/RackFillBar' -const RackSpaceFillContainer = (props) => { - const state = useSelector((state) => { - const machineIds = state.objects.rack[state.objects.tile[props.tileId].rack].machines - return { - type: 'space', - fillFraction: machineIds.filter((id) => id !== null).length / machineIds.length, - } - }) - return <RackFillBar {...props} {...state} /> +function RackSpaceFillContainer({ tileId, ...props }) { + const rack = useSelector((state) => state.objects.rack[state.objects.tile[tileId].rack]) + return <RackFillBar {...props} type="space" fillFraction={rack.machines.length / rack.capacity} /> } RackSpaceFillContainer.propTypes = { diff --git a/opendc-web/opendc-web-ui/src/components/app/map/elements/HoverTile.js b/opendc-web/opendc-web-ui/src/components/app/map/elements/HoverTile.js index 11bba0e1..0369bb79 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/elements/HoverTile.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/elements/HoverTile.js @@ -4,10 +4,10 @@ import { Rect } from 'react-konva' import { ROOM_HOVER_INVALID_COLOR, ROOM_HOVER_VALID_COLOR } from '../../../../util/colors' import { TILE_SIZE_IN_PIXELS } from '../MapConstants' -const HoverTile = ({ pixelX, pixelY, isValid, scale, onClick }) => ( +const HoverTile = ({ x, y, isValid, scale = 1, onClick }) => ( <Rect - x={pixelX} - y={pixelY} + x={x} + y={y} scaleX={scale} scaleY={scale} width={TILE_SIZE_IN_PIXELS} @@ -18,10 +18,10 @@ const HoverTile = ({ pixelX, pixelY, isValid, scale, onClick }) => ( ) HoverTile.propTypes = { - pixelX: PropTypes.number.isRequired, - pixelY: PropTypes.number.isRequired, + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired, isValid: PropTypes.bool.isRequired, - scale: PropTypes.number.isRequired, + scale: PropTypes.number, onClick: PropTypes.func.isRequired, } diff --git a/opendc-web/opendc-web-ui/src/components/app/map/elements/RackFillBar.js b/opendc-web/opendc-web-ui/src/components/app/map/elements/RackFillBar.js index 8c573a6f..aa284944 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/elements/RackFillBar.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/elements/RackFillBar.js @@ -16,7 +16,7 @@ import { } from '../MapConstants' import ImageComponent from './ImageComponent' -const RackFillBar = ({ positionX, positionY, type, fillFraction }) => { +function RackFillBar({ positionX, positionY, type, fillFraction }) { const halfOfObjectBorderWidth = OBJECT_BORDER_WIDTH_IN_PIXELS / 2 const x = positionX * TILE_SIZE_IN_PIXELS + diff --git a/opendc-web/opendc-web-ui/src/components/app/map/elements/TilePlusIcon.js b/opendc-web/opendc-web-ui/src/components/app/map/elements/TilePlusIcon.js index be3a00a8..186c2b3a 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/elements/TilePlusIcon.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/elements/TilePlusIcon.js @@ -4,19 +4,19 @@ import { Group, Line } from 'react-konva' import { TILE_PLUS_COLOR } from '../../../../util/colors' import { TILE_PLUS_MARGIN_IN_PIXELS, TILE_PLUS_WIDTH_IN_PIXELS, TILE_SIZE_IN_PIXELS } from '../MapConstants' -const TilePlusIcon = ({ pixelX, pixelY, mapScale }) => { +function TilePlusIcon({ x, y, scale = 1 }) { const linePoints = [ [ - pixelX + 0.5 * TILE_SIZE_IN_PIXELS * mapScale, - pixelY + TILE_PLUS_MARGIN_IN_PIXELS * mapScale, - pixelX + 0.5 * TILE_SIZE_IN_PIXELS * mapScale, - pixelY + TILE_SIZE_IN_PIXELS * mapScale - TILE_PLUS_MARGIN_IN_PIXELS * mapScale, + x + 0.5 * TILE_SIZE_IN_PIXELS * scale, + y + TILE_PLUS_MARGIN_IN_PIXELS * scale, + x + 0.5 * TILE_SIZE_IN_PIXELS * scale, + y + TILE_SIZE_IN_PIXELS * scale - TILE_PLUS_MARGIN_IN_PIXELS * scale, ], [ - pixelX + TILE_PLUS_MARGIN_IN_PIXELS * mapScale, - pixelY + 0.5 * TILE_SIZE_IN_PIXELS * mapScale, - pixelX + TILE_SIZE_IN_PIXELS * mapScale - TILE_PLUS_MARGIN_IN_PIXELS * mapScale, - pixelY + 0.5 * TILE_SIZE_IN_PIXELS * mapScale, + x + TILE_PLUS_MARGIN_IN_PIXELS * scale, + y + 0.5 * TILE_SIZE_IN_PIXELS * scale, + x + TILE_SIZE_IN_PIXELS * scale - TILE_PLUS_MARGIN_IN_PIXELS * scale, + y + 0.5 * TILE_SIZE_IN_PIXELS * scale, ], ] return ( @@ -27,7 +27,7 @@ const TilePlusIcon = ({ pixelX, pixelY, mapScale }) => { points={points} lineCap="round" stroke={TILE_PLUS_COLOR} - strokeWidth={TILE_PLUS_WIDTH_IN_PIXELS * mapScale} + strokeWidth={TILE_PLUS_WIDTH_IN_PIXELS * scale} listening={false} /> ))} @@ -36,9 +36,9 @@ const TilePlusIcon = ({ pixelX, pixelY, mapScale }) => { } TilePlusIcon.propTypes = { - pixelX: PropTypes.number, - pixelY: PropTypes.number, - mapScale: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + scale: PropTypes.number, } export default TilePlusIcon diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js index a88a8b34..2b1060c0 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js @@ -1,61 +1,52 @@ import PropTypes from 'prop-types' -import React, { useEffect, useState } from 'react' -import { Layer } from 'react-konva' +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({ mouseX, mouseY, mapPosition, mapScale, isEnabled, isValid, onClick, children }) { - const [pos, setPos] = useState([-1, -1]) - const [x, y] = pos - const [valid, setValid] = useState(false) +function HoverLayerComponent({ isEnabled, isValid, onClick, children }) { + const [[mouseWorldX, mouseWorldY], setPos] = useState([0, 0]) - useEffect(() => { - if (!isEnabled()) { + const layerRef = useEffectRef((layer) => { + if (!layer) { return } - const positionX = Math.floor((mouseX - mapPosition.x) / (mapScale * TILE_SIZE_IN_PIXELS)) - const positionY = Math.floor((mouseY - mapPosition.y) / (mapScale * TILE_SIZE_IN_PIXELS)) + const stage = layer.getStage() - if (positionX !== x || positionY !== y) { - setPos([positionX, positionY]) - setValid(isValid(positionX, positionY)) - } - }, [isEnabled, isValid, x, y, mouseX, mouseY, mapPosition, mapScale]) + // 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()) { + if (!isEnabled) { return <Layer /> } - const pixelX = mapScale * x * TILE_SIZE_IN_PIXELS + mapPosition.x - const pixelY = mapScale * y * TILE_SIZE_IN_PIXELS + mapPosition.y + const x = gridX * TILE_SIZE_IN_PIXELS + const y = gridY * TILE_SIZE_IN_PIXELS return ( - <Layer opacity={0.6}> - <HoverTile - pixelX={pixelX} - pixelY={pixelY} - scale={mapScale} - isValid={valid} - onClick={() => (valid ? onClick(x, y) : undefined)} - /> - {children - ? React.cloneElement(children, { - pixelX, - pixelY, - scale: mapScale, - }) - : undefined} + <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 = { - mouseX: PropTypes.number.isRequired, - mouseY: PropTypes.number.isRequired, - mapPosition: PropTypes.object.isRequired, - mapScale: PropTypes.number.isRequired, - isEnabled: PropTypes.func.isRequired, + isEnabled: PropTypes.bool.isRequired, isValid: PropTypes.func.isRequired, onClick: PropTypes.func.isRequired, children: PropTypes.node, diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js index badb9f68..c902532b 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js @@ -21,13 +21,21 @@ */ import React from 'react' -import MapLayerComponent from '../../../../components/app/map/layers/MapLayerComponent' -import { useMapPosition, useMapScale } from '../../../../data/map' +import { Group, Layer } from 'react-konva' +import Backdrop from '../elements/Backdrop' +import TopologyContainer from '../TopologyContainer' +import GridGroup from '../groups/GridGroup' -const MapLayer = (props) => { - const position = useMapPosition() - const scale = useMapScale() - return <MapLayerComponent {...props} mapPosition={position} mapScale={scale} /> +function MapLayer() { + return ( + <Layer> + <Group> + <Backdrop /> + <TopologyContainer /> + <GridGroup /> + </Group> + </Layer> + ) } export default MapLayer diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js deleted file mode 100644 index efe5b4e5..00000000 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js +++ /dev/null @@ -1,26 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' -import { Group, Layer } from 'react-konva' -import Backdrop from '../elements/Backdrop' -import GridGroup from '../groups/GridGroup' -import TopologyContainer from '../TopologyContainer' - -const MapLayerComponent = ({ mapPosition, mapScale }) => ( - <Layer> - <Group x={mapPosition.x} y={mapPosition.y} scaleX={mapScale} scaleY={mapScale}> - <Backdrop /> - <TopologyContainer /> - <GridGroup /> - </Group> - </Layer> -) - -MapLayerComponent.propTypes = { - mapPosition: PropTypes.shape({ - x: PropTypes.number, - y: PropTypes.number, - }), - mapScale: PropTypes.number, -} - -export default MapLayerComponent diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js index 9a087bd5..47d9c992 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js @@ -23,32 +23,31 @@ import React from 'react' import { useDispatch, useSelector } from 'react-redux' import { addRackToTile } from '../../../../redux/actions/topology/room' -import ObjectHoverLayerComponent from '../../../../components/app/map/layers/ObjectHoverLayerComponent' import { findTileWithPosition } from '../../../../util/tile-calculations' +import HoverLayerComponent from './HoverLayerComponent' +import TilePlusIcon from '../elements/TilePlusIcon' -const ObjectHoverLayer = (props) => { - const state = useSelector((state) => { - return { - mapPosition: state.map.position, - mapScale: state.map.scale, - isEnabled: () => state.construction.inRackConstructionMode, - isValid: (x, y) => { - if (state.interactionLevel.mode !== 'ROOM') { - return false - } +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) + 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) - }, - } + return !(tile === null || tile.rack) }) const dispatch = useDispatch() const onClick = (x, y) => dispatch(addRackToTile(x, y)) - return <ObjectHoverLayerComponent {...props} {...state} onClick={onClick} /> + return ( + <HoverLayerComponent onClick={onClick} isEnabled={isEnabled} isValid={isValid}> + <TilePlusIcon /> + </HoverLayerComponent> + ) } export default ObjectHoverLayer diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayerComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayerComponent.js deleted file mode 100644 index 661fc255..00000000 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayerComponent.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react' -import TilePlusIcon from '../elements/TilePlusIcon' -import HoverLayerComponent from './HoverLayerComponent' - -const ObjectHoverLayerComponent = (props) => ( - <HoverLayerComponent {...props}> - <TilePlusIcon {...props} /> - </HoverLayerComponent> -) - -export default ObjectHoverLayerComponent diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js index 87240813..59f83b2b 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js @@ -23,45 +23,39 @@ import React from 'react' import { useDispatch, useSelector } from 'react-redux' import { toggleTileAtLocation } from '../../../../redux/actions/topology/building' -import RoomHoverLayerComponent from '../../../../components/app/map/layers/RoomHoverLayerComponent' import { deriveValidNextTilePositions, findPositionInPositions, findPositionInRooms, } from '../../../../util/tile-calculations' +import HoverLayerComponent from './HoverLayerComponent' -const RoomHoverLayer = (props) => { +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 + ) - const state = useSelector((state) => { - return { - mapPosition: state.map.position, - mapScale: state.map.scale, - isEnabled: () => state.construction.currentRoomInConstruction !== '-1', - isValid: (x, y) => { - const newRoom = Object.assign({}, state.objects.room[state.construction.currentRoomInConstruction]) - const oldRooms = Object.keys(state.objects.room) - .map((id) => Object.assign({}, 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 - }, + ;[...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 <RoomHoverLayerComponent onClick={onClick} {...props} {...state} /> + + return <HoverLayerComponent onClick={onClick} isEnabled={isEnabled} isValid={isValid} /> } export default RoomHoverLayer diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayerComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayerComponent.js deleted file mode 100644 index 887e2891..00000000 --- a/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayerComponent.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react' -import HoverLayerComponent from './HoverLayerComponent' - -const RoomHoverLayerComponent = (props) => <HoverLayerComponent {...props} /> - -export default RoomHoverLayerComponent |
