202 lines
7.2 KiB
TypeScript
202 lines
7.2 KiB
TypeScript
import { Room } from "./room.class";
|
|
|
|
export class App {
|
|
static floorLabels = [
|
|
'Ground floor',
|
|
'1st floor',
|
|
'2nd floor',
|
|
'3rd floor',
|
|
'4th floor',
|
|
'5th floor',
|
|
'6th floor',
|
|
];
|
|
static removeClasses = ['active', 'lower', 'raise', 'hilite'];
|
|
|
|
private rooms: Array<Room> = [];
|
|
|
|
private roomsDataListElement: HTMLDataListElement;
|
|
private floorSelectElement: HTMLSelectElement;
|
|
private filterElement: HTMLInputElement;
|
|
private labelElement: HTMLHeadingElement;
|
|
private svgElements: Array<SVGSVGElement>;
|
|
private svgRooms: Array<Element>;
|
|
|
|
constructor(params: {rooms: Array<Room>}) {
|
|
this.rooms = params.rooms;
|
|
|
|
this.roomsDataListElement = <HTMLDataListElement>document.getElementById('roomList');
|
|
this.floorSelectElement = <HTMLSelectElement>document.getElementById('floorSelect');
|
|
this.filterElement = <HTMLInputElement>document.getElementById('filter');
|
|
this.labelElement = <HTMLHeadingElement>document.getElementById('label');
|
|
|
|
const mapContainer = <HTMLElement>document.getElementById('map-container');
|
|
this.svgElements = Array.from(mapContainer.getElementsByTagName('svg'));
|
|
this.svgRooms = Array.from(mapContainer.getElementsByClassName('room'));
|
|
}
|
|
|
|
run() {
|
|
// init floor selector and input datalist
|
|
this.initFloorSelect(App.floorLabels)
|
|
.populateDataList();
|
|
|
|
// add event listeners for restoring application state
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const hash = (<Location>document.location).hash;
|
|
return hash ? this.restoreState(hash.split('.')) : null;
|
|
});
|
|
window.addEventListener('popstate', event => this.restoreState(event.state));
|
|
|
|
// what happens when the floor selector is changed
|
|
this.floorSelectElement.addEventListener('change', event => this.applyFloorFilter(+(<HTMLInputElement>event.target).value));
|
|
|
|
// what happens when the room filter is changed
|
|
this.filterElement.addEventListener('change', event => {
|
|
const room = this.rooms.find(room => room.name.toLocaleLowerCase() === this.filterElement.value.toLocaleLowerCase());
|
|
this.selectFloor(room ? room.floor : 7).deselectAllRooms();
|
|
if (room) this.selectRoom(room.id).pushRoomState(room);
|
|
});
|
|
|
|
// what should happen when a floor is clicked on
|
|
this.svgElements.map(svg => svg.addEventListener('click', event => {
|
|
event.stopPropagation();
|
|
const svgRoom = this.svgRooms.find(svgRoom => svgRoom.classList.contains('hilite'));
|
|
if (svgRoom) this.setFloorLabel((<Room>this.rooms.find(room => room.id == svgRoom.id)).floor);
|
|
this.deselectAllRooms();
|
|
}));
|
|
|
|
// what should happen when a room is clicked on
|
|
this.svgRooms.map(svgRoom => svgRoom.addEventListener('click', event => {
|
|
event.stopPropagation();
|
|
const room = <Room>this.rooms.find(room => room.id === svgRoom.id);
|
|
if ((<HTMLElement>event.target).classList.contains('hilite')) {
|
|
this.deselectAllRooms().setFloorLabel(room.floor);
|
|
} else {
|
|
this.deselectAllRooms().selectRoom(room.id).pushRoomState(room);
|
|
}
|
|
}));
|
|
|
|
// add roomname as title to all rooms when user hovers mouse over the room
|
|
this.rooms.map(room => {
|
|
const titleElement = document.createElementNS("http://www.w3.org/2000/svg", "title");
|
|
titleElement.textContent = `${room.name}`;
|
|
const svgRoom = <HTMLElement>document.getElementById(room.id);
|
|
svgRoom.appendChild(titleElement);
|
|
svgRoom.classList.add(...Room.typeClassMap[room.type]);
|
|
});
|
|
}
|
|
|
|
genFloorHash(idx: number): string {
|
|
return `#f.${idx}`;
|
|
}
|
|
|
|
genRoomHash(room: Room): string {
|
|
return `#r.${room.floor}.${room.id}`;
|
|
}
|
|
|
|
initFloorSelect(labels: Array<string>): App {
|
|
labels.map((floor, idx) => this.floorSelectElement.appendChild(new Option(floor, idx.toLocaleString())));
|
|
return this;
|
|
}
|
|
|
|
populateDataList(floor: number = -1): App {
|
|
this.rooms.filter(room => floor == -1 ? true : room.floor == floor)
|
|
.map(room => room.name).sort()
|
|
.map(roomName => this.roomsDataListElement.appendChild(new Option(roomName)));
|
|
return this;
|
|
}
|
|
|
|
clearDataList(): App {
|
|
while(this.roomsDataListElement.lastChild) {
|
|
this.roomsDataListElement.removeChild(this.roomsDataListElement.lastChild);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
setLabel(label: string): App {
|
|
this.labelElement.innerHTML = label;
|
|
return this;
|
|
}
|
|
|
|
setFloorLabel(idx: number): App {
|
|
this.setLabel(App.floorLabels[idx]);
|
|
return this;
|
|
}
|
|
|
|
setRoomLabel(room: Room): App {
|
|
this.setLabel(`${App.floorLabels[room.floor]} - ${room.formattedName}`);
|
|
return this;
|
|
}
|
|
|
|
selectFloor(idx: number): App {
|
|
this.svgElements.map((svg, svgidx) => {
|
|
svg.classList.remove(...App.removeClasses);
|
|
svg.classList.add(idx == svgidx ? 'active' : (
|
|
svgidx > idx ? 'raise' : 'lower'
|
|
));
|
|
});
|
|
return this;
|
|
}
|
|
|
|
selectRoom(id: string): App {
|
|
const room = <Room>this.rooms.find(room => room.id === id);
|
|
this.setRoomLabel(room).filterElement.value = room.name;
|
|
(<HTMLElement>document.getElementById(id)).classList.add('hilite');
|
|
Array.from(document.getElementsByClassName(`floor-${room.floor}`))
|
|
.filter(floor => !floor.classList.contains('hilite'))
|
|
.map(floor => floor.classList.add('hilite'));
|
|
return this;
|
|
}
|
|
|
|
deselectAllRooms(): App {
|
|
this.svgElements.map(svg => svg.classList.remove('hilite'));
|
|
this.svgRooms.map(room => room.classList.remove('hilite'));
|
|
return this;
|
|
}
|
|
|
|
applyFloorFilter(idx: number): App {
|
|
this.filterElement.value = '';
|
|
this.deselectAllRooms().clearDataList().populateDataList(idx);
|
|
if (idx == -1) {
|
|
this.setLabel('').svgElements
|
|
.map(svg => svg.classList.remove(...App.removeClasses));
|
|
return this;
|
|
}
|
|
return this.setFloorLabel(idx).selectFloor(idx).pushFloorState(idx);
|
|
}
|
|
|
|
pushState(state: {}, title: string, url: string): App {
|
|
window.history.pushState(state, title, url);
|
|
return this;
|
|
}
|
|
|
|
pushFloorState(idx: number): App {
|
|
return this.pushState(
|
|
['#f', idx],
|
|
`ETH map - ${App.floorLabels[idx]}`,
|
|
this.genFloorHash(idx)
|
|
);
|
|
}
|
|
|
|
pushRoomState(room: Room): App {
|
|
return this.pushState(
|
|
['#r', room.floor, room.id],
|
|
`ETH map - ${App.floorLabels[room.floor]} / ${room.formattedName}`,
|
|
this.genRoomHash(room)
|
|
);
|
|
}
|
|
|
|
restoreState(params: Array<any>): App {
|
|
const [cmd,floor,roomId] = [...params];
|
|
this.deselectAllRooms();
|
|
switch(cmd) {
|
|
case '#r':
|
|
this.selectFloor(floor).selectRoom(roomId);
|
|
break;
|
|
case '#f':
|
|
this.selectFloor(floor);
|
|
break;
|
|
}
|
|
return this;
|
|
}
|
|
}
|