Office map

Open in CodeSandbox

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
    <script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
    <!-- To make the map appear, you must add your apikey -->
    <script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>

    <script
      data-plugins="transform-modules-umd"
      data-presets="typescript"
      type="text/babel"
      src="../data/office.ts"
    ></script>
    <script
      data-plugins="transform-modules-umd"
      data-presets="typescript"
      type="text/babel"
      src="../data/new-office.ts"
    ></script>
    <script
      data-plugins="transform-modules-umd"
      data-presets="typescript"
      type="text/babel"
      src="./common.ts"
    ></script>
    <script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
      import {type LngLat, type YMapContext, YMapMarker} from '@yandex/ymaps3-types';
      import {
          MARKERS_DATA_SOURCE,
          DATA,
          ROOMS_DATA_SOURCE,
          TABLES_DATA_SOURCE,
          getEntitiesProps,
          getFurnitureFeatureProps,
          getIcon,
          getRoomCardPopupProps,
          getRoomMarkerElement,
          getPersonCardPopupProps,
          getAvatar,
          source,
          getMenuControl,
          MenuState
      } from './common';
      import {Person, Table} from '../types';

      window.map = null;

      main();
      async function main() {
          const params = await fetch(`../params/${source}.json`).then((p) => p.json());
          await ymaps3.ready;

          const {
              YMap,
              YMapTileDataSource,
              YMapLayer,
              YMapControls,
              YMapControl,
              YMapFeatureDataSource,
              YMapContainer,
              YMapMarker,
              YMapFeature,
              YMapListener
          } = ymaps3;

          const {YMapZoomControl, YMapPopupMarker} = await ymaps3.import('@yandex/ymaps3-default-ui-theme');
          const {YMapHint, YMapHintContext} = await ymaps3.import('@yandex/ymaps3-hint');
          const {Cartesian} = await ymaps3.import('@yandex/ymaps3-cartesian-projection');

          const entitiesProps = getEntitiesProps(Cartesian, params);
          map = new YMap(document.getElementById('app'), entitiesProps.map);

          map.addChild(new YMapTileDataSource(entitiesProps.tileDataSource));
          map.addChild(new YMapLayer(entitiesProps.layer));

          map.addChild(new YMapControls({position: 'right'}).addChild(new YMapZoomControl({})));

          map.addChild(new YMapFeatureDataSource({id: TABLES_DATA_SOURCE}));
          map.addChild(new YMapLayer({source: TABLES_DATA_SOURCE, type: 'features', zIndex: 2100}));

          map.addChild(new YMapFeatureDataSource({id: ROOMS_DATA_SOURCE}));
          map.addChild(new YMapLayer({source: ROOMS_DATA_SOURCE, type: 'features', zIndex: 2000}));

          map.addChild(new YMapFeatureDataSource({id: MARKERS_DATA_SOURCE}));
          map.addChild(new YMapLayer({source: MARKERS_DATA_SOURCE, type: 'markers', zIndex: 2200}));

          let state: MenuState = {
              ROOMS: true,
              TABLES: true,
              FURNITURE: true
          };

          const tablesContainer = new YMapContainer({onElement: () => {}, onContext: () => {}});
          const roomsContainer = new YMapContainer({onElement: () => {}, onContext: () => {}});
          const furnitureContainer = new YMapContainer({onElement: () => {}, onContext: () => {}});

          const personsMarkers = new Map<YMapMarker, {table: Table; person: Person}>();
          DATA.TABLES.forEach((table) => {
              const person = DATA.PERSONS.find(({tableId}) => tableId === table.id);

              tablesContainer.addChild(
                  new YMapFeature(
                      getFurnitureFeatureProps(
                          table,
                          TABLES_DATA_SOURCE,
                          person ? DATA.TABLE_COLORS?.occupied : DATA.TABLE_COLORS?.default,
                          true
                      )
                  )
              );

              if (person) {
                  const coordinates: LngLat = [table.center[0], table.center[1] + table.size[1] / 2];

                  const marker = new YMapMarker(
                      {
                          id: `person-marker-${person.id}`,
                          coordinates,
                          source: MARKERS_DATA_SOURCE
                      },
                      getAvatar(person)
                  );

                  tablesContainer.addChild(marker);
                  personsMarkers.set(marker, {table, person});
              }
          });

          let openedPopup;
          tablesContainer.addChild(
              new YMapListener({
                  layer: `${MARKERS_DATA_SOURCE}:markers`,
                  onMouseEnter: (object) => {
                      if (openedPopup) {
                          map.removeChild(openedPopup);
                      }

                      if (object.type === 'marker' && personsMarkers.has(object.entity)) {
                          const {table, person} = personsMarkers.get(object.entity);
                          const coordinates: LngLat = [table.center[0], table.center[1] + table.size[1] / 2];

                          openedPopup = new YMapPopupMarker(getPersonCardPopupProps(person, coordinates));
                          map.addChild(openedPopup);
                      }
                  },
                  onMouseLeave: (o) => {
                      if (openedPopup) {
                          map.removeChild(openedPopup);
                      }
                  }
              })
          );

          if (state.TABLES) {
              map.addChild(tablesContainer);
          }

          DATA.ROOMS.forEach((room) => {
              roomsContainer.addChild(new YMapFeature(getFurnitureFeatureProps(room, ROOMS_DATA_SOURCE)));
              roomsContainer.addChild(
                  new YMapMarker(
                      {
                          id: `room-marker-${room.id}`,
                          coordinates: [room.center[0], room.center[1] - room.size[1] / 2],
                          source: MARKERS_DATA_SOURCE
                      },
                      getRoomMarkerElement(room)
                  )
              );

              if (room.capacity) {
                  tablesContainer.addChild(new YMapPopupMarker(getRoomCardPopupProps(room)));
              }
          });

          if (state.ROOMS) {
              map.addChild(roomsContainer);
          }

          DATA.FURNITURE.forEach((furniture) => {
              furnitureContainer.addChild(
                  new ymaps3.YMapMarker(
                      {
                          id: `furniture-marker-${furniture.id}`,
                          coordinates: furniture.center,
                          source: MARKERS_DATA_SOURCE,
                          properties: {hint: furniture.name}
                      },
                      getIcon(furniture.icon, furniture.circled ? ['icon', 'icon_circled'] : undefined)
                  )
              );
          });

          if (state.FURNITURE) {
              map.addChild(furnitureContainer);
          }

          map.addChild(
              new YMapListener({
                  onClick: (object) => {
                      if (object?.type !== 'marker' && openedPopup) {
                          map.removeChild(openedPopup);
                      }
                  }
              })
          );

          map.addChild(
              new YMapControls({position: 'top'}).addChild(
                  new YMapControl(
                      {},
                      getMenuControl(state, (nextState) => {
                          console.log(state, nextState);
                          if (state.ROOMS !== nextState.ROOMS) {
                              map[nextState.ROOMS ? 'addChild' : 'removeChild'](roomsContainer);
                              state.ROOMS = nextState.ROOMS;
                          }

                          if (state.TABLES !== nextState.TABLES) {
                              map[nextState.TABLES ? 'addChild' : 'removeChild'](tablesContainer);
                              state.TABLES = nextState.TABLES;
                          }

                          if (state.FURNITURE !== nextState.FURNITURE) {
                              map[nextState.FURNITURE ? 'addChild' : 'removeChild'](furnitureContainer);
                              state.FURNITURE = nextState.FURNITURE;
                          }
                      })
                  )
              )
          );

          const hint = new YMapHint({
              hint: (object) => object?.properties?.hint
          });
          map.addChild(hint);

          class Hint extends ymaps3.YMapComplexEntity<{}> {
              private _element: HTMLElement;
              private _detachDom: ReturnType<typeof ymaps3.useDomContext>;

              _onAttach() {
                  this._element = document.createElement('div');
                  this._element.className = 'hint';

                  this._detachDom = ymaps3.useDomContext(this, this._element, null);
                  this._watchContext(
                      YMapHintContext,
                      () => {
                          this._element.textContent = this._consumeContext(YMapHintContext as YMapContext<any>)?.hint;
                      },
                      {immediate: true}
                  );
              }
              _onDetach() {
                  this._detachDom();
                  this._detachDom = undefined;
              }
          }
          hint.addChild(new Hint({}));
      }
    </script>

    <!-- prettier-ignore -->
    <style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; }  </style>
    <link rel="stylesheet" href="./common.css" />
  </head>

  <body>
    <div id="app"></div>
  </body>
</html>
html,
body,
#app {
  width: 100%;
  height: 100%;

  font-family: Helvetica, Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

.icon {
  position: absolute;

  transform: translate(-50%, -50%);
}

.icon_circled {
  padding: 5px;

  border: 1px solid #000;
  border-radius: 100%;
  background: #fff;
}

.clickable {
  cursor: pointer;
}

.room {
  position: absolute;

  padding: 10px;

  font-size: 14px;
  text-align: center;
  white-space: nowrap;

  color: #fff;
  border: 1px solid #000;
  border-radius: 4px;
  background: #181b22;

  transform: translate(-50%, -50%);
}

.hint {
  position: absolute;
  top: 25px;

  padding: 4px;

  font-size: 14px;
  white-space: nowrap;

  border-radius: 4px;
  background: #fff;

  transform: translate(8px, -50%);
}

.avatar {
  position: absolute;

  border: 2px solid #fff;
  border-radius: 4px;
  box-shadow: 0 -0.8px 2px 0 rgba(95, 105, 131, 0.08), 0 2px 4px 0 rgba(95, 105, 131, 0.2);

  transform: translate(-50%, -50%);
}

.card {
  padding: 6px 3px;

  text-align: center;
}

.card-name {
  display: inline-block;

  width: 100%;

  font-size: 16px;
  font-weight: 600;
  white-space: nowrap;

  color: #181b22;
}

.card-info {
  font-size: 14px;
  white-space: nowrap;

  color: #7b7d85;
}

.menu {
  display: inline-flex;
  align-items: center;

  padding: 12px;
  gap: 16px;
}

.menu__title {
  padding: 8px 12px;

  font-size: 20px;
  font-weight: 500;
}

.menu__checkbox {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.menu__checkbox_input {
  width: 20px;
  height: 20px;

  border-radius: 6px;
  -webkit-appearance: none;
  appearance: none;
}

.menu__checkbox_input::after {
  display: none;
}

.menu__checkbox_input:checked::after {
  position: relative;
  top: 10px;
  left: 10px;

  display: block;

  width: 11px;
  height: 8px;

  content: '';

  background-image: url('data:image/svg+xml;utf8,<svg width="11" height="8" viewBox="0 0 11 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.70711 3.29289C1.31658 2.90237 0.683418 2.90237 0.292893 3.29289C-0.0976311 3.68342 -0.0976311 4.31658 0.292893 4.70711L3.29289 7.70711C3.68342 8.09763 4.31658 8.09763 4.70711 7.70711L10.7071 1.70711C11.0976 1.31658 11.0976 0.683418 10.7071 0.292893C10.3166 -0.0976311 9.68342 -0.0976311 9.29289 0.292893L4 5.58579L1.70711 3.29289Z" fill="%23F5F6F7"/></svg>');

  transform: translate(-50%, -50%);
}

.menu__checkbox_title {
  margin-left: 12px;
}
import type {Cartesian} from '@yandex/ymaps3-cartesian-projection';
import type {YMapPopupMarkerProps} from '@yandex/ymaps3-default-ui-theme';
import type {LngLat, LngLatBounds, YMap, YMapFeatureProps, YMapMarker} from '@yandex/ymaps3-types';
import type {EntitiesProps, Furniture, Room, Person, Table} from './types';

import * as officeData from './data/office';
import * as newOfficeData from './data/new-office';

const dataBySource = {
  office: officeData,
  'new-office': newOfficeData
};

const query = new URLSearchParams(location.search);
export const source =
  query.has('source') && ['office', 'new-office'].includes(query.get('source')) ? query.get('source') : 'office';

export const DATA = dataBySource[source];

function convertPixelsToMeters(bounds: LngLatBounds): LngLatBounds {
  return bounds.map<LngLat>(([lng, lat]) => [
    (lng + DATA.CENTER_PX_OFFSET[0]) / DATA.PX_TO_METERS[0],
    (lat + DATA.CENTER_PX_OFFSET[1]) / DATA.PX_TO_METERS[1]
  ]) as LngLatBounds;
}

export function getEntitiesProps(CartesianProjection: typeof Cartesian, params): EntitiesProps {
  const projection = new CartesianProjection(convertPixelsToMeters(params.projection.bounds));

  return {
    map: {
      ...params.map,
      restrictMapArea: convertPixelsToMeters(params.map.restrictMapArea),
      projection: projection,
      zoomRounding: 'smooth'
    },
    tileDataSource: {
      id: 'image',
      copyrights: params.COPYRIGHTS,
      raster: {
        type: 'tile',
        fetchTile: `${DATA.TILES_PATH}/${params.tiles.pathTemplate}`
      }
    },
    layer: {source: 'image', type: 'tile'}
  };
}

function getImage(path: string, size: number, classNames?: string[]): HTMLImageElement {
  const img = document.createElement('img');
  img.src = path;
  img.width = size;
  img.height = size;
  img.classList.add(...classNames);

  return img;
}

export function getIcon(icon: string, classNames = ['icon']): HTMLImageElement {
  return getImage(`${DATA.ICONS_PATH}/${icon}.svg`, 32, classNames);
}

export function getAvatar(person: Person, classNames = ['avatar']): HTMLImageElement {
  return getImage(`${DATA.AVATARS_PATH}/${person.avatar}.jpg`, 40, classNames);
}

export function getRoomMarkerElement(room: Room): HTMLElement {
  const div = document.createElement('div');
  div.innerText = room.name;
  div.classList.add('room');

  return div;
}

export const TABLES_DATA_SOURCE = 'tables';
export const ROOMS_DATA_SOURCE = 'rooms';
export const MARKERS_DATA_SOURCE = 'markers';

export function getFurnitureFeatureProps(
  furniture: Table | Room | Furniture,
  source: string,
  fill?: string,
  withHint?: boolean
): YMapFeatureProps {
  fill = fill || furniture.fill;

  return {
    id: `${source}-${furniture.id}`,
    geometry: calculateFeatureGeometry(furniture.center, furniture.size),
    source,
    style: {
      fill,
      fillOpacity: furniture.fillOpacity ?? 0.4,
      stroke: [{color: furniture.stroke ?? fill, width: furniture.strokeWidth ?? 3, opacity: furniture.strokeOpacity}]
    },
    properties: withHint ? {hint: furniture.name} : undefined
  };
}

function calculateFeatureGeometry(center: LngLat, size: LngLat): YMapFeatureProps['geometry'] {
  const halfSize = [size[0] / 2, size[1] / 2];

  return {
    type: 'Polygon',
    coordinates: [
      [
        [center[0] - halfSize[0], center[1] - halfSize[1]],
        [center[0] + halfSize[0], center[1] - halfSize[1]],
        [center[0] + halfSize[0], center[1] + halfSize[1]],
        [center[0] - halfSize[0], center[1] + halfSize[1]]
      ]
    ]
  };
}

export function getPersonCardPopupProps(person: Person, coordinates: LngLat): YMapPopupMarkerProps {
  return {
    id: `person-popup-${person.id}`,
    coordinates,
    zIndex: ymaps3.YMapMarker.defaultProps.zIndex + 1_000,
    source: MARKERS_DATA_SOURCE,
    offset: 26,
    content: () => {
      const element = document.createElement('div');
      element.classList.add('card');

      const nameElement = document.createElement('div');
      nameElement.className = 'card-name';
      nameElement.innerText = person.name;
      element.append(nameElement);

      const infoElement = document.createElement('div');
      infoElement.className = 'card-info';
      element.append(infoElement);

      const positionElement = document.createElement('div');
      positionElement.textContent = person.position;
      infoElement.append(positionElement);

      if (person.workingHours) {
        const workingHoursElement = document.createElement('div');
        workingHoursElement.textContent = 'Working hours: ' + person.workingHours;
        infoElement.append(workingHoursElement);
      }

      return element;
    }
  };
}

export function getRoomCardPopupProps(room: Room): YMapPopupMarkerProps {
  return {
    id: `room-popup-${room.id}`,
    coordinates: room.center,
    zIndex: ymaps3.YMapMarker.defaultProps.zIndex + 1_000,
    source: MARKERS_DATA_SOURCE,
    content: () => {
      const element = document.createElement('div');
      element.classList.add('card');

      const nameElement = document.createElement('div');
      nameElement.className = 'card-name';
      nameElement.innerText = room.name;
      element.append(nameElement);

      const infoElement = document.createElement('div');
      infoElement.className = 'card-info';
      element.append(infoElement);

      if (room.capacity) {
        const capacityElement = document.createElement('div');
        capacityElement.textContent = room.capacity + ' seats';
        infoElement.append(capacityElement);
      }

      return element;
    }
  };
}

export interface MenuState {
  ROOMS: boolean;
  TABLES: boolean;
  FURNITURE: boolean;
}
const menuLabels: Record<keyof MenuState, string> = {
  ROOMS: 'Rooms',
  TABLES: 'Desks',
  FURNITURE: 'Equipment'
};
export function getMenuControl(state: MenuState, onChange: (state: MenuState) => void) {
  const element = document.createElement('div');
  element.classList.add('menu');

  for (const key in state) {
    const checkboxElement = document.createElement('div');
    checkboxElement.classList.add('menu__checkbox');

    const inputElement = document.createElement('input');
    inputElement.type = 'checkbox';
    inputElement.checked = state[key];
    inputElement.style.backgroundColor = inputElement.checked ? '#2e4ce5' : '#5c5e6624';
    inputElement.addEventListener('change', () => {
      onChange({...state, [key]: inputElement.checked});
      inputElement.style.backgroundColor = inputElement.checked ? '#2e4ce5' : '#5c5e6624';
    });
    inputElement.classList.add('menu__checkbox_input');
    checkboxElement.append(inputElement);
    const labelElement = document.createElement('label');
    labelElement.classList.add('menu__checkbox_title');
    labelElement.htmlFor = key;
    labelElement.textContent = menuLabels[key];
    checkboxElement.append(labelElement);
    element.append(checkboxElement);
  }

  return element;
}

declare module '@yandex/ymaps3-types/import' {
  interface Import {
    (pkg: '@yandex/ymaps3-cartesian-projection'): Promise<typeof import('@yandex/ymaps3-cartesian-projection')>;
    (pkg: '@yandex/ymaps3-default-ui-theme'): Promise<typeof import('@yandex/ymaps3-default-ui-theme')>;
    (pkg: '@yandex/ymaps3-hint'): Promise<typeof import('@yandex/ymaps3-hint')>;
  }
}

ymaps3.ready.then(() => {
  ymaps3.import.registerCdn('https://cdn.jsdelivr.net/npm/{package}', [
    '@yandex/ymaps3-cartesian-projection@0.0',
    '@yandex/ymaps3-default-ui-theme@0.0',
    '@yandex/ymaps3-hint@0.0'
  ]);
});
import type {LngLat} from '@yandex/ymaps3-types';
import {Furniture, Room, Person, Table} from '../types';

const IMAGES_PATH = 'https://yastatic.net/s3/front-maps-static/maps-front-jsapi-3/examples/images/office-map/new';
export const AVATARS_PATH = `${IMAGES_PATH}/avatars`;
export const ICONS_PATH = `${IMAGES_PATH}/icons`;
export const TILES_PATH = `${IMAGES_PATH}/tiles`;

const DEFAULT_TABLE_SIZE: LngLat = [1.8, 2.05];
const SEAT_SIZE: LngLat = [0.75, 0.75];
export const TABLES: Table[] = [
  {id: 1, name: 'Table #1', center: [-1.4, -1.9], size: DEFAULT_TABLE_SIZE, fill: '#ffb700', fillOpacity: 0.3},
  {id: 2, name: 'Table #2', center: [0.4, -1.9], size: DEFAULT_TABLE_SIZE, fill: '#ffb700', fillOpacity: 0.3},
  {
    id: 3,
    name: 'Seat #3',
    center: [3.96, 2.04],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 4,
    name: 'Seat #4',
    center: [2.74, 1.1],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 5,
    name: 'Seat #5',
    center: [2.74, 0.28],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 6,
    name: 'Seat #6',
    center: [2.74, -0.55],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 7,
    name: 'Seat #7',
    center: [5.18, 1.1],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 8,
    name: 'Seat #8',
    center: [5.18, 0.28],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 9,
    name: 'Seat #9',
    center: [5.18, -0.55],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  },
  {
    id: 10,
    name: 'Seat #10',
    center: [3.96, -1.49],
    size: SEAT_SIZE,
    fill: '#00ffdd',
    fillOpacity: 0.34,
    stroke: '#34d9a2',
    strokeOpacity: 0.8
  }
];

export const PERSONS: Person[] = [
  {
    id: 1,
    name: 'John Makinski',
    position: 'Co-founder, analyst',
    workingHours: '12:00-22:00',
    tableId: 1,
    avatar: 'john'
  },
  {
    id: 2,
    name: 'George Wolf',
    position: 'Co-founder, developer',
    workingHours: '12:00-22:00',
    tableId: 2,
    avatar: 'george'
  }
];

export const ROOMS: Room[] = [
  {
    id: 1,
    name: 'Main office',
    center: [-2.34, 0],
    size: [7.7, 6.17],
    fill: '#eefd7d',
    fillOpacity: 0.38,
    strokeWidth: 0
  },
  {
    id: 2,
    name: 'Conference room',
    capacity: 8,
    center: [3.92, 0],
    size: [4.63, 6.2],
    fill: '#34d9a2',
    fillOpacity: 0.3,
    strokeWidth: 0
  }
];

export const FURNITURE: Furniture[] = [
  {id: 1, name: 'Sofa', icon: 'sofa', center: [-3.85, 1.7]},
  {id: 2, name: 'Cooler', icon: 'cooler', center: [-1.54, 2.19]},
  {id: 3, name: 'Plant', icon: 'plant', center: [-5.41, -0.44]},
  {id: 4, name: 'Plant', icon: 'plant', center: [5.7, 2.53]},
  {id: 5, name: 'Coffee table', icon: 'star', center: [-3.9, -0.06]},
  {id: 6, name: 'Filing cabinet', icon: 'filing', center: [-5.42, -2.3]},
  {id: 7, name: 'Camera', icon: 'camera', center: [3.92, -2.45]},
  {id: 8, name: 'Printer', icon: 'printer', center: [5.7, -2.45]}
];

export const CENTER_PX_OFFSET = [9, 0];
export const PX_TO_METERS = [350, 350];

export const COPYRIGHTS = [];
import type {LngLat} from '@yandex/ymaps3-types';
import {Furniture, Room, Person, Table} from '../types';

const IMAGES_PATH = 'https://yastatic.net/s3/front-maps-static/maps-front-jsapi-3/examples/images/office-map';
export const AVATARS_PATH = `${IMAGES_PATH}/avatars`;
export const ICONS_PATH = `${IMAGES_PATH}/icons`;
export const TILES_PATH = `${IMAGES_PATH}/tiles`;

const DEFAULT_TABLE_SIZE: LngLat = [1.6, 1.7];
const BIG_TABLE_SIZE: LngLat = [1.7, 1.9];
export const TABLES: Table[] = [
  {id: 1, name: 'Table #1', center: [3.07, 7.17], size: DEFAULT_TABLE_SIZE},
  {id: 2, name: 'Table #2', center: [4.7, 5.35], size: DEFAULT_TABLE_SIZE},
  {id: 3, name: 'Table #3', center: [7.1, -6.45], size: [2.2, 3.9]},
  {id: 4, name: 'Table #4', center: [7.8, 0.25], size: DEFAULT_TABLE_SIZE},
  {id: 5, name: 'Table #5', center: [7.8, 2.02], size: DEFAULT_TABLE_SIZE},
  {id: 6, name: 'Table #6', center: [3.07, 5.35], size: DEFAULT_TABLE_SIZE},
  {id: 7, name: 'Table #7', center: [9.43, 6.9], size: BIG_TABLE_SIZE},
  {id: 8, name: 'Table #8', center: [4.7, 7.17], size: DEFAULT_TABLE_SIZE},
  {id: 9, name: 'Table #9', center: [9.43, 0.25], size: DEFAULT_TABLE_SIZE},
  {id: 10, name: 'Table #10', center: [9.43, 2.02], size: DEFAULT_TABLE_SIZE},
  {id: 11, name: 'Table #11', center: [7.7, 6.9], size: BIG_TABLE_SIZE},
  {id: 12, name: 'Table #12', center: [8.3, 4.95], size: BIG_TABLE_SIZE},
  {id: 13, name: 'Table #13', center: [4.88, 2], size: BIG_TABLE_SIZE},
  {id: 14, name: 'Table #14', center: [3.15, 2], size: BIG_TABLE_SIZE},
  {id: 15, name: 'Table #15', center: [3.75, 0.05], size: BIG_TABLE_SIZE}
];

export const TABLE_COLORS = {
  occupied: '#00c1ff',
  default: '#777777'
};

export const PERSONS: Person[] = [
  {id: 1, name: 'Dan', position: 'CTO', tableId: 14, avatar: 'Dan'},
  {id: 2, name: 'Claire', position: 'Developer', tableId: 13, avatar: 'Claire'},
  {id: 3, name: 'Ann', position: 'Designer', tableId: 15, avatar: 'Ann'},
  {id: 4, name: 'Matthew', position: 'QA', tableId: 5, avatar: 'Matthew'},
  {id: 5, name: 'Stephen', position: 'Developer', tableId: 10, avatar: 'Stephen'},
  {id: 6, name: 'Tina', position: 'Manager', tableId: 9, avatar: 'Tina'}
];

export const ROOMS: Room[] = [
  {
    id: 1,
    name: 'Conference hall',
    capacity: 8,
    center: [-8.68, -3.75],
    size: [4.62, 9.63],
    fill: '#e39f5b'
  },
  {
    id: 2,
    name: 'Room with TV',
    capacity: 2,
    center: [-3.34, -5.42],
    size: [6.03, 6.31],
    fill: '#3c9f5b'
  }
];

export const FURNITURE: Furniture[] = [
  {id: 1, name: 'Kitchen', icon: 'tea-cup', center: [-7.95, 5.05], circled: true},
  {id: 2, name: 'WC', icon: 'wc', center: [-1.8, 7.3], circled: true},
  {id: 3, name: 'WC', icon: 'wc', center: [10.8, -5.8], circled: true},
  {id: 4, name: 'Water cooler', icon: 'water-drop', center: [0.44, -5.5], circled: true},
  {id: 5, name: 'Water cooler', icon: 'water-drop', center: [0.09, 4.53], circled: true},
  {id: 6, name: 'MFP', icon: 'printer', center: [0.65, -3.4], circled: true}
];

export const CENTER_PX_OFFSET = [53, -3];
export const PX_TO_METERS = [140.08, 130.2];

export const COPYRIGHTS = ['@ Designed by macrovector / Freepik'];
{
  "image": {
    "width": 4416,
    "height": 2224
  },
  "projection": {
    "bounds": [
      [-4096, -4096],
      [4096, 4096]
    ],
    "cycled": [false, false]
  },
  "map": {
    "zoomRange": {
      "min": 2,
      "max": 4
    },
    "mode": "raster",
    "restrictMapArea": [
      [-4800, -2000],
      [4800, 2000]
    ],
    "worldOptions": {
      "cycledX": false
    },
    "location": {"center": [0, 0], "zoom": 2}
  },
  "tiles": {
    "pathTemplate": "z/y-x.png"
  }
}
{
  "image": {
    "width": 4500,
    "height": 3848
  },
  "projection": {
    "bounds": [
      [-2250, -6268],
      [5942, 1924]
    ],
    "cycled": [false, false]
  },
  "map": {
    "zoomRange": {
      "min": 2,
      "max": 5
    },
    "mode": "raster",
    "restrictMapArea": [
      [-2250, -1924],
      [2250, 1924]
    ],
    "worldOptions": {
      "cycledX": false
    },
    "location": {"center": [0, 0], "zoom": 3}
  },
  "tiles": {
    "pathTemplate": "z/y-x.png"
  }
}
import type {LngLat, YMapLayerProps, YMapProps, YMapTileDataSourceProps} from '@yandex/ymaps3-types';

export interface Table {
  id: number;
  name: string;
  center: LngLat;
  size: LngLat;
  fill?: string;
  fillOpacity?: number;
  stroke?: string;
  strokeWidth?: number;
  strokeOpacity?: number;
}

export interface Person {
  id: number;
  name: string;
  position: string;
  workingHours?: string;
  tableId: Table['id'];
  avatar: string;
}

export interface Room {
  id: number;
  name: string;
  capacity?: number;
  center: LngLat;
  size: LngLat;
  fill?: string;
  fillOpacity?: number;
  stroke?: string;
  strokeWidth?: number;
  strokeOpacity?: number;
}

export interface Furniture {
  id: number;
  name: string;
  icon: string;
  center: LngLat;
  size?: LngLat;
  fill?: string;
  fillOpacity?: number;
  stroke?: string;
  strokeWidth?: number;
  strokeOpacity?: number;
  circled?: boolean;
}

export interface EntitiesProps {
  map: YMapProps;
  tileDataSource: YMapTileDataSourceProps;
  layer: YMapLayerProps;
}