ETH-map/src/app.class.ts
2018-11-10 16:15:57 +01:00

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;
}
}