From cd0b45627f0d8da8c8dc4edde223f3c36e9bcfbf Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Sun, 25 Apr 2021 16:01:14 +0200 Subject: build: Migrate to flat project structure This change updates the project structure to become flattened. Previously, the simulator, frontend and API each lived into their own directory. With this change, all modules of the project live in the top-level directory of the repository. This should improve discoverability of modules of the project. --- .../opendc-web-ui/src/store/configure-store.js | 35 +++++++++++ .../src/store/middlewares/dummy-middleware.js | 3 + .../src/store/middlewares/viewport-adjustment.js | 73 ++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 opendc-web/opendc-web-ui/src/store/configure-store.js create mode 100644 opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js create mode 100644 opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js (limited to 'opendc-web/opendc-web-ui/src/store') diff --git a/opendc-web/opendc-web-ui/src/store/configure-store.js b/opendc-web/opendc-web-ui/src/store/configure-store.js new file mode 100644 index 00000000..d8f343ed --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/configure-store.js @@ -0,0 +1,35 @@ +import { applyMiddleware, compose, createStore } from 'redux' +import persistState from 'redux-localstorage' +import { createLogger } from 'redux-logger' +import createSagaMiddleware from 'redux-saga' +import thunk from 'redux-thunk' +import { authRedirectMiddleware } from '../auth/index' +import rootReducer from '../reducers/index' +import rootSaga from '../sagas/index' +import { dummyMiddleware } from './middlewares/dummy-middleware' +import { viewportAdjustmentMiddleware } from './middlewares/viewport-adjustment' + +const sagaMiddleware = createSagaMiddleware() + +let logger +if (process.env.NODE_ENV !== 'production') { + logger = createLogger() +} + +const middlewares = [ + process.env.NODE_ENV === 'production' ? dummyMiddleware : logger, + thunk, + sagaMiddleware, + authRedirectMiddleware, + viewportAdjustmentMiddleware, +] + +export let store = undefined + +export default function configureStore() { + const configuredStore = createStore(rootReducer, compose(persistState('auth'), applyMiddleware(...middlewares))) + sagaMiddleware.run(rootSaga) + store = configuredStore + + return configuredStore +} diff --git a/opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js b/opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js new file mode 100644 index 00000000..5ba35691 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js @@ -0,0 +1,3 @@ +export const dummyMiddleware = (store) => (next) => (action) => { + next(action) +} diff --git a/opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js b/opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js new file mode 100644 index 00000000..b4472c54 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js @@ -0,0 +1,73 @@ +import { SET_MAP_DIMENSIONS, setMapPosition, setMapScale } from '../../actions/map' +import { SET_CURRENT_TOPOLOGY } from '../../actions/topology/building' +import { + MAP_MAX_SCALE, + MAP_MIN_SCALE, + SIDEBAR_WIDTH, + TILE_SIZE_IN_PIXELS, + VIEWPORT_PADDING, +} from '../../components/app/map/MapConstants' +import { calculateRoomListBounds } from '../../util/tile-calculations' + +export const viewportAdjustmentMiddleware = (store) => (next) => (action) => { + const state = store.getState() + + let topologyId = '-1' + let mapDimensions = {} + if (action.type === SET_CURRENT_TOPOLOGY && action.topologyId !== '-1') { + topologyId = action.topologyId + mapDimensions = state.map.dimensions + } else if (action.type === SET_MAP_DIMENSIONS && state.currentTopologyId !== '-1') { + topologyId = state.currentTopologyId + mapDimensions = { width: action.width, height: action.height } + } + + if (topologyId !== '-1') { + const roomIds = state.objects.topology[topologyId].roomIds + const rooms = roomIds.map((id) => Object.assign({}, state.objects.room[id])) + rooms.forEach((room) => (room.tiles = room.tileIds.map((tileId) => state.objects.tile[tileId]))) + + let hasNoTiles = true + for (let i in rooms) { + if (rooms[i].tiles.length > 0) { + hasNoTiles = false + break + } + } + + if (!hasNoTiles) { + const viewportParams = calculateParametersToZoomInOnRooms(rooms, mapDimensions.width, mapDimensions.height) + store.dispatch(setMapPosition(viewportParams.newX, viewportParams.newY)) + store.dispatch(setMapScale(viewportParams.newScale)) + } + } + + next(action) +} + +function calculateParametersToZoomInOnRooms(rooms, mapWidth, mapHeight) { + const bounds = calculateRoomListBounds(rooms) + const newScale = calculateNewScale(bounds, mapWidth, mapHeight) + + // Coordinates of the center of the room, relative to the global origin of the map + const roomCenterCoordinates = { + x: bounds.center.x * TILE_SIZE_IN_PIXELS * newScale, + y: bounds.center.y * TILE_SIZE_IN_PIXELS * newScale, + } + + const newX = -roomCenterCoordinates.x + mapWidth / 2 + const newY = -roomCenterCoordinates.y + mapHeight / 2 + + return { newScale, newX, newY } +} + +function calculateNewScale(bounds, mapWidth, mapHeight) { + const width = bounds.max.x - bounds.min.x + const height = bounds.max.y - bounds.min.y + + const scaleX = (mapWidth - 2 * SIDEBAR_WIDTH) / (width * TILE_SIZE_IN_PIXELS + 2 * VIEWPORT_PADDING) + const scaleY = mapHeight / (height * TILE_SIZE_IN_PIXELS + 2 * VIEWPORT_PADDING) + const newScale = Math.min(scaleX, scaleY) + + return Math.min(Math.max(MAP_MIN_SCALE, newScale), MAP_MAX_SCALE) +} -- cgit v1.2.3