summaryrefslogtreecommitdiff
path: root/src/store/middlewares/viewport-adjustment.js
blob: 132391f3260d400743decf9757f597a5b2c3fc94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import {
  SET_MAP_DIMENSIONS,
  setMapPosition,
  setMapScale
} from "../../actions/map";
import { SET_CURRENT_DATACENTER } 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 datacenterId = -1;
  let mapDimensions = {};
  if (action.type === SET_CURRENT_DATACENTER && action.datacenterId !== -1) {
    datacenterId = action.datacenterId;
    mapDimensions = state.map.dimensions;
  } else if (
    action.type === SET_MAP_DIMENSIONS &&
    state.currentDatacenterId !== -1
  ) {
    datacenterId = state.currentDatacenterId;
    mapDimensions = { width: action.width, height: action.height };
  }

  if (datacenterId !== -1) {
    const roomIds = state.objects.datacenter[datacenterId].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);
}