import { loadModule } from "@3ddv/dvm";
loadModule("map_viewer", {
container: "viewer-container",
styles_by_groups: true,
instanced_nodes: true,
})
.then((viewer) => {
window.viewer = viewer;
start(viewer);
})
.catch((err) => {
console.error(err);
});
function start(viewer) {
// Just for the example purpose
viewer.flags.scroll_with_mod_key = true;
const venue_id = "nam-us-00096-chicagocubs";
const map_id = "main";
let sections = null;
let section_index = -1;
let seats = null;
let seat_index = -1;
viewer.subscribe("load_success", (_obj) => {
// Set a random availability to have some unavailable nodes
setSectionSeatAvailability(viewer);
// Create a list of ordered and available sections. Unavailable sections are ignored
sections = naturalSort(viewer.getNodesByState("section", "available").map(n => n.id));
section_index = -1;
});
viewer.subscribe("reset", (_obj) => {
resetAll();
});
viewer.subscribe("keydown", (obj) => {
const event = obj.original_event;
// Layer level 0 is section view, Layer level 1 is seat view. Depending on the current layer level, we'll do different actions
const current_level = viewer.layers.getLayerLevel();
console.log(event.key, event.keyCode);
switch (event.keyCode) {
case 37: // arrow left
current_level === 0 ? prevSection() : prevSeat();
break;
case 39: // arrow right
current_level === 0 ? nextSection() : nextSeat();
break;
// case 32: // space
case 13: // enter
current_level === 0 ? enterCurrentSection() : selectCurrentSeat();
break;
case 27: // Escape
exitSection(true);
}
});
function nextSection() {
if (sections?.length) {
section_index = (section_index + 1) % sections.length;
hoverAndGoCurrentSection();
}
}
function prevSection() {
if (sections?.length) {
--section_index;
if (section_index < 0) section_index = sections.length - 1;
hoverAndGoCurrentSection();
}
}
function nextSeat() {
if (seats?.length) {
seat_index = (seat_index + 1) % seats.length;
hoverAndGoCurrentSeat();
}
}
function prevSeat() {
if (seats?.length) {
--seat_index;
if (seat_index < 0) seat_index = seats.length - 1;
hoverAndGoCurrentSeat();
}
}
// Hover the current section. If it's not on screen, focus on it
function hoverAndGoCurrentSection() {
const section = viewer.getNodeById(sections?.[section_index]);
if (section) {
console.log("Hover section:", section.id);
viewer.hover(section);
if (!section.on_screen) viewer.focusOn(section, viewer.scaling_factor);
}
}
// Hover the current seat. If it's not on screen, focus on it
function hoverAndGoCurrentSeat() {
const seat = viewer.getNodeById(seats?.[seat_index]);
if (seat) {
console.log("Hover seat:", seat.id);
viewer.hover(seat);
if (!seat.on_screen) viewer.focusOn(seat, viewer.scaling_factor);
}
}
// Select the current seat. If it's not on screen, focus on it
function selectCurrentSeat() {
const seat = viewer.getNodeById(seats?.[seat_index]);
if (seat) {
console.log("Select seat:", seat.id);
if (!seat.on_screen) viewer.goTo(seat);
viewer.select(seat);
}
}
// Zoom-in in with an animation the current section and make a list of its seats
function enterCurrentSection() {
const section = viewer.getNodeById(sections?.[section_index]);
if (section) {
console.log("Enter section:", section.id);
viewer.goTo(section);
seats = naturalSort(viewer.getNodesByState("seat", "available", section.id).map(n => n.id));
seat_index = -1;
}
}
function exitSection() {
// Just zoom out
viewer.goTo([0, 0], viewer.min_scaling_factor);
resetSeats();
}
function resetSections() {
sections = null;
section_index = -1;
}
function resetSeats() {
// Remove current seats data
seats = null;
seat_index = -1;
}
function resetAll() {
resetSections();
resetSeats();
}
// Load the map
viewer.loadMap({ venue_id, map_id })
.then(() => {
// Successfully loaded
console.log("LOADED!");
})
.catch((err) => {
// Error while loading
console.error(err);
});
function setSectionSeatAvailability(instance, prob = 0.6) {
if (instance && instance.isLoaded()) {
const section_availability = [];
const seat_availability = [];
viewer.getNodesByType("section").forEach((section) => {
if (Math.random() < prob) {
section_availability.push(section.id);
section.children?.forEach((seat_id) => {
if (Math.random() < prob) {
seat_availability.push(seat_id);
}
});
}
});
viewer.setAvailability("section", section_availability);
viewer.setAvailability("seat", seat_availability);
}
}
// https://stackoverflow.com/a/4373238
function naturalSort(ary, fullNumbers) {
var re = fullNumbers ? /[\d\.\-]+|\D+/g : /\d+|\D+/g;
// Perform a Schwartzian transform, breaking each entry into pieces first
for (let i = ary.length; i--;)
ary[i] = [ary[i]].concat((ary[i] + "").match(re).map(function(s) {
return isNaN(s) ? [s, false, s] : [s * 1, true, s];
}));
// Perform a cascading sort down the pieces
ary.sort(function(a, b) {
var al = a.length, bl = b.length, e = al > bl ? al : bl;
for (let i = 1; i < e; ++i) {
// Sort "a" before "a1"
if (i >= al) return -1; else if (i >= bl) return 1;
else if (a[i][0] !== b[i][0])
return (a[i][1] && b[i][1]) ? // Are we comparing numbers?
(a[i][0] - b[i][0]) : // Then diff them.
(a[i][2] < b[i][2]) ? -1 : 1; // Otherwise, lexicographic sort
}
return 0;
});
// Restore the original values into the array
for (let i = ary.length; i--;) ary[i] = ary[i][0];
return ary;
}
}