import{loadModule}from"@3ddv/dvm";// ---- LOADING MODULE ----loadModule("map_viewer",{container:"viewer-container"// Container where the viewer will be appended}).then(function(viewer){console.log(`Module '${viewer.getModuleName()}' initialized:`,viewer);start(viewer);}).catch(function(err){console.error(err);});functionstart(viewer){// FLAGSvarselection=1;// How many seats are selected at oncevarfilter_single_seats=false;window.viewer=viewer;viewer.subscribe("click",onClick);viewer.subscribe("enter",onEnter);viewer.subscribe("leave",onLeave);// ---- LOADING ----viewer.loadMap({venue_id:"eu-es-00008-default"// Venue to be loaded. MMC will provide these IDs}).then(function(obj){// Disable automatic selection and hoverviewer.flags.automatic_selection=false;viewer.flags.automatic_hover=false;overrideStyles(viewer);// Get sections availabilityvaravailable_sections=getSectionAvailability();// Apply sections availabilitfyviewer.setAvailability("section",available_sections);// Get seats availabilityvaravailable_seats=getSeatAvailability();// Apply seats availabilityviewer.setAvailability("seat",available_seats);filterRows(selection,filter_single_seats);console.log("LOADED!");}).catch(function(err){// Error while loadingconsole.error(err);});// CALLBACKSfunctiononClick(obj){varnode=obj.nodes[0];if(node&&node.type==="seat"){if(node.state==="available"||node.state==="selected"){varnodes=obj.instance.getNeighbors(node,selection,filter_single_seats);if(nodes.length===selection){obj.instance.unselectAll();obj.instance.select(nodes);}}}}functiononEnter(obj){varnode=obj.nodes[0];if(node){// If there are neighbors that fulfill the requirements, we hover all the seats, otherwise we hover only the original node.if(node.type==="seat"&&(node.state==="available"||node.state==="selected")){varnodes=obj.instance.getNeighbors(node,selection,filter_single_seats);if(nodes.length===selection){obj.instance.hover(nodes);return;}}obj.instance.hover(node);}}// called on node mouse leavefunctiononLeave(obj){// reset hover nodesobj.instance.hover(null);}// ROWS/** * * This function will filter the nodes that cannot form part of a group of adjacent * nodes given a certain 'quantity' and previously applied availability. In addition, * we specify with 'filter_single_seats' if selections that leaves single seats * are allowed or not. * * In addition, the function will add the filtered nodes to a group ('filtered') * and assign them a tag with the same name to be able to paint them differently on the map. * * @param {number} quantity - Quantity of adjacent nodes to be selected. * @param {boolean} filter_single_seats - if the adjacent nodes may allow single seats (false) * or not (true). */functionfilterRows(quantity,filter_single_seats){// We make sure that there is no node selectedviewer.unselectAll();// Get all nodes in group 'filtered' from a previous filterRows callvarold_filtered_nodes=viewer.getNodesByGroups("seat","filtered",false);// Remove nodes from 'filtered' groupviewer.removeNodesFromGroup(old_filtered_nodes,"filtered");// Remove tag 'filtered' from nodesviewer.setNodesTag(old_filtered_nodes,null);// get the filter nodesvarfiltered_nodes=viewer.filterRows(quantity,filter_single_seats);// add nodes to 'filtered' groupviewer.addNodesToGroup(filtered_nodes,"filtered");// Apply 'filtered' tag to nodesviewer.setNodesTag(filtered_nodes,"filtered");}// INPUT ELEMENTSvarinput_selection=document.getElementById("selection_input");varinput_single_seats=document.getElementById("single_seats_input");if(input_selection&&input_single_seats){input_single_seats.addEventListener("change",function(e){filter_single_seats=input_single_seats.checked;filterRows(selection,filter_single_seats);});input_selection.addEventListener("input",function(e){varval=parseInt(input_selection.value);if(!isNaN(val)){selection=clamp(val,1,10);input_selection.value=selection;viewer.max_selection=selection;filterRows(selection,filter_single_seats);}});}// ---- AVAILABILITY FUNCTIONS ----// Get sections availability. For the purpose, we generate a RANDOM availability.functiongetSectionAvailability(){varsections=viewer.getNodesByType("section");varavailable_sections=[];for(vari=0;i<sections.length;++i){varsection=sections[i];if(Math.random()<0.7){available_sections.push(section.id);}}returnavailable_sections;}// Get seats availability. For the purpose, we generate a RANDOM availability.functiongetSeatAvailability(){// Only generate availability for seats with an AVAILABLE parent sectionvaravailable_sections=viewer.getNodesByState("section","available");varavailable_seats=[];for(vari=0;i<available_sections.length;++i){varsection=available_sections[i];varseats=viewer.getNodesByParent(section.id);for(varj=0;j<seats.length;++j){varseat=seats[j];if(Math.random()<0.7){available_seats.push(seat.id);}}}returnavailable_seats;}// HELPERS// The purpose of this function is just keep the default styles and add to them styles for 'filtered' tagfunctionoverrideStyles(instance){varstyles=instance.getStyles();for(vari=0;i<styles.length;++i){if(styles[i]&&styles[i].seat){if(styles[i].seat.available.normal&&styles[i].seat.available.normal.none){styles[i].seat.available.normal.filtered=JSON.parse(JSON.stringify(styles[i].seat.available.normal.none));styles[i].seat.available.normal.filtered.opacity=0.4;if(styles[i].seat.available.hover&&styles[i].seat.available.hover.none){styles[i].seat.available.hover.filtered=JSON.parse(JSON.stringify(styles[i].seat.available.normal.none));styles[i].seat.available.hover.filtered.opacity=0.4;}}}}instance.setStyles(styles);}functionclamp(a,b,c){returnMath.max(b,Math.min(c,a));}}