Office map
vanilla.html
common.css
common.ts
data.ts
data.ts
params.json
params.json
types.ts
<!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;
}