Centric connect.engage.succeed

Building an interactive floor plan using out-of-the-box SharePoint components (and some JavaScript) – Part 3

Geschreven door Erik Nell - 28 maart 2017

Erik Nell
This is the third and final chapter of my description of this project.

You’ll find the links for the first and second installments here: Part 1, Part 2.

In parts 1 and 2 we laid the groundwork for the solution. All lists and libraries are in place and all necessary data is already loaded on the page. The only thing that we still need to get right is the interactive part. The floorplan is visible, but nothing happens when you click on a conference room. What we want is a popup with the relevant information for that room. Let’s see how we can do that.

Making it interactive

The conference rooms on the floor plan need to respond to a mouse click within the room boundaries. The simplest solution is to layer invisible <DIV>s on top of the image. This is where the hotspots that were mentioned in part 2 come in. The Mustache template that loads the floor plan image creates a series of these hotspot tags right after the image:

{{#Hotspots}}
    <div class="buildingHotspot" data-roomName="room{{RoomID}}"  
        style="cursor:pointer;position:absolute; left:{{left}}%;
        top:{{top}}%; height:{{height}}%; 
        width:{{width}}%; z-index: 10"
        onclick="javascript:openRoomPopup('room{{RoomID}}')">
    </div>
{{/Hotspots}}                                                                                                                                                                                                                                                                                                                                                                                                              

This results in the following HTML:

<div class="buildingHotspot" 
    style="left: 0%; top: 0%; width: 17.83%; height: 10.26%; 
    position: absolute; z-index: 10; cursor: pointer;" 
    onclick="javascript:openRoomPopup('roomConferenceRoom1')" 
    data-roomname="roomConferenceRoom1">
</div>
<div class="buildingHotspot" style="left: 0%; top: 77.96%; 
    width: 16.93%; height: 8.03%; position: absolute; z-index: 10; 
    cursor: pointer;"
    onclick="javascript:openRoomPopup('roomConferenceRoom2')" 
    data-roomname="roomConferenceRoom2">
</div>
<div class="buildingHotspot" style="left: 83.47%; top: 0%; 
    width: 16.53%; height: 17.36%; position: absolute; z-index: 10; 
    cursor: pointer;"
    onclick="javascript:openRoomPopup('roomConferenceRoom3')" 
    data-roomname="roomConferenceRoom3">
</div>                                                                                                                                                                                                                                                                                                                                                                                            

You may notice that, in the style attribute, percentages are used for height, width, top and left. This came about in response to an interesting issue we had while testing. I was initially working with absolute values. Then, when I showed the preliminary results on a big screen during a demonstration, the image, which was not scaled to the big screen, appeared tiny. Conversely, trying to display it using a lower resolution resulted in a huge image where only parts of the floor plan were visible. So, I resorted to using relative values. Now, percentages of the complete floor plan image are used to define the size of the hotspots.

By using the z-index attribute, I ensure that the <DIV>s will be on top of the image; otherwise the onclick event might not be triggered.

Floor plan

How to store hotspot information

Storing the hotspot information posed a problem. In classical relational database terms, the relation between a floor plan and the hotspots can be described as a one-to-many relationship. Unfortunately, you cannot really model this directly into SharePoint lists. What I could have done was create another list containing only the hotspot information and include an additional lookup column containing the ID of the parent Conference Room Layout item. But that would have meant time-consuming looping through an additional list when compiling all information.

So, instead I resorted to a trick I have used before: use a multiline column to store a JSON-like structure that contains all the information. That way, you can still store a one-to-many relationship and it won’t make too many SOAP/REST calls to the server. In code, this can be easily read by a JSON.parse() call.

[
{"RoomID":"ConferenceRoom1","left":"0","top":"0","height":"10.26","width":"17.83"},{"RoomID":"ConferenceRoom2","left":"0","top":"77.96","height":"8.03","width":"16.93"},
{"RoomID":"ConferenceRoom3","left":"83.47","top":"0","height":"17.36","width":"16.53"}
]                                                                                                                                                                                                                                                                                                                                                                                                  
The storage structure for hotspots in the Conference Room Layout list.

Getting it on screen

To show the room information of the room that has been clicked on, the function openRoomPopup() is used.

function openRoomPopup(roomID){
    var roomElementID = "#" + roomID;
    var element = $(roomElementID);
    $("#roomInfo").html(element.html());
    
    $("#roomPopup").reveal({
        animation: 'fade',
        animationspeed: 100,
        closeonbackgroundclick: true,
        dismissmodalclass: 'close-reveal-modal'
    });
}                                                                                                                                                                                                                                                                                                                                                                              

To get the information in a modal form on top of the image, I used a plugin called Reveal. It is now part of a great responsive framework, Foundation, but I only used the now deprecated standalone version.

The function looks for an HTML element which has an ID tag equal to the roomID in its function call parameter. The room information is stored in the HTML of the page in a structure like this:

<div class="roomDescriptions" id="RoomDescriptions">
    <div id="roomConferenceRoom1">
      <div class="roomDescription">
        <div class="roomName">
          <div class="roomTitle">
            Conference room 1
          </div>
          <div class="roomOutlookName">
            Conference Room 1 - Building 1
          </div>
        </div>
        <div class="roomPictures">
          <img class="roomPicture"
            src="/FloorPlanDemo/ConferenceRoomPictures/Room 1.JPG">
          <img class="roomPicture"
            src="/FloorPlanDemo/ConferenceRoomPictures/R1_Picture 2.JPG">
        </div>
        <div class="roomText">
          <div class="roomSeats">
            <div class="roomColumn">Capacity:</div>
            <div class="roomValue">8</div>
          </div>
          <div class="roomEquipment">
            <div class="roomColumn">Equipment:</div>
            <div class="roomValue">Big screen, Telephone, Whiteboard</div>
          </div>
          <div class="roomPhoneNumber">
            <div class="roomColumn">Phone Number:</div>
            <div class="roomValue">123</div>
          </div>
          <div class="roomRemarks">
            <div class="roomColumn">Remarks:</div>
            <div class="roomValue">No airco. </div>
          </div>
        </div>
      </div>
    </div>  
    <div id="roomConferenceRoom2">
      ...
    </div>
</div>                                                                                                                                                                                                                                                                                                                               

It will then copy the HTML over into the <DIV> with the ID ‘RoomInfo’. That part of the HTML looks like this:

<div class="reveal-modal" id="roomPopup">
    <a class="close-reveal-modal">×</a>
    <div id="roomInfo"></div>
</div>

Then, by calling the reveal() function on the parent <DIV> the modal dialog is displayed.

Conclusion

So, there you have it. A (relatively) easy way to have conference room information displayed in a graphical and interactive form. And the nice thing is, it didn’t cost a thing (apart from the time spent, of course). Everything I used was either available out of the box or through open source javascript/JQuery plugins.

Personally, I really enjoyed building this as it was a way to creatively combine several techniques to achieve something that people love to use. And I can assure you, people really do love this feature. What’s more, just a couple of days ago, when we were forced to rearrange the conference rooms in our buildings yet again due to internal moves, changing the site proved to be a simple affair. So, the goals were achieved on that front too.

Things to improve

Of course, it’s not all sunshine: there’s always room for improvement. In the first place, I still think that storing one-to-many relationships in a data structure in a multi-line column is a hack. It’s ugly and very error prone: one simple typo will ruin everything. However, I really don’t know of any alternative right now. Secondly, I am convinced that the visual aspect of the site can be greatly improved; but like I said in the intro, I am not a graphic designer and there was no budget to hire one.

Craft Expert Erik Nell is part of Team Office 365 within Craft, the development programme for IT professionals (powered by Centric). If you would like to follow his blog, sign up for Craft updates.

Tags:SharePoint

     
Schrijf een reactie
  • Captcha image
  • Verzenden