Per ardua ad astra

-Translates into ‘through adversity to the stars’. Personal interpretation: ‘a task may seem hard or impossible, but you will accomplish it – and won’t that feel sweet!’

March 25th – April 5th 2019 were two of the busiest weeks I have ever experienced at university. I had more hours sleep on the night of April 5th than I had had in the entire week leading up to that Friday. At one point my ‘sleep:wake ratio’ was something crazy like 1 hour of sleep for every 3 hours of being awake, meaning that on average I was getting about 4-5 hours sleep per night. It was an extremely busy time, starting off with the launch of Storehouse 18 consuming three days of the week (read all about Storehouse in Year 2 of university here) and then followed by an intense period of coding the Broads web app prototype between Thursday March 28th and the very early hours of Friday April 5th, which was the day that the prototype was tested ethnographically. But it was also the best time I’ve ever had at university. In terms of course content and course satisfaction, no other time on my degree (so far) comes close.

Production of the Broads web app prototype technically began as far back as March 7th when I started to experiment with coding the 360 degree experience with the MarziPano JavaScript library. The code that I was working on back then was modified a little on March 22nd by Chloe and I when we redesigned the appearance of the icons and information dialogs, but after that it remained virtually unchanged for the finished piece.

Experimenting with solutions for coding a ‘website on a grid’ swiftly followed the experimentation made with the 360 degree viewer, with the first implementation of this being demonstrated on March 8th, followed by another implementation of the same idea on March 11th. The grid was altered considerably for the final prototype and eventually those two implementations would be combined to provide the best of both worlds, but with the basic mechanics and coding methods understood before production of the testing prototype began this left just the home page, map and the nature finder experience to code from scratch.

Production of the prototype generally followed this method:

  • The graphic communication students and Namii would spend time creating high-fidelity prototypes of individual experiences in Adobe XD before they would be coded.
  • The graphic communication students would be the ones to consider colour, visual identities and how the app’s UI would relate to the accompanying graphic design elements, e.g. posters, signage and interpretation boards.
  • Ameer would focus on implementing the designs that the graphics students had designed into the grid, then focus on coding animations for the other experiences using a mix of CSS keyframes and the CSS framework ‘animate.css’.
  • Namii would focus on creating the information architecture for the finder app and coding the theme selector and initial landing pages.
  • I was responsible for bringing Ameer’s and Namii’s work together as well as creating the map widget and supporting Ameer and Namii with any coding problems that they may have.

The roles were split fairly evenly between us, however the final two days where it was all about ‘concatenating’ Ameer’s, Namii’s and my own work a lot of the bull stopped with me. It felt like a lot of responsibility, but doing this task this is something that you understand and know before agreeing to do it. Being a keen coder and wanting this to work I wanted to step up to this challenge. And the feeling when it all worked at about 1.30am on the day of testing was phenomenal.

Read on to learn how it all came together.

Creating the individual components

This post describes work that was completed between March 28th and April 3rd. During this time myself and the other people working on this project designed and coded the individual components of the web app prototype.

The next post describes the final two days where the work was put together to make one web app and animations were applied.

The results from the usability testing are in another post.

…but first, an ‘ode to my software and hardware’

I don’t want this to turn into a ‘Why I love <insert name of software here> post’, but we often take our software and hardware for granted. I just want to take some time to point out a few pieces of software and one piece of hardware that really helped to make this project run smoothly for me.

Visual Studio 2019 Preview

Everybody has their preferred IDE. Jamie and my friend Callum favour Atom, Namii favours Visual Studio Code and Ameer has used everything from Brackets to PHPStorm. But for me, nothing will ever quite touch Visual Studio. Asides from being the first IDE that I ever used when I was learning to code, some 9 years ago now, I just love its interface and how simple it becomes to use with each and every release. Not to mention how helpful IntelliSense is (it’s code predictions and corrections are unmatched) and that you can run web pages on a local Microsoft IIS server directly from Visual Studio, negating the need to worry about using things like MAMP. Things like this make Visual Studio the ultimate editor.

When I was writing this project, 2019 Preview was the latest release and the changes from 2017 to 2019 make going back very difficult. The improved UI, speed, code collaboration tools and stability of 2019 makes it the best version of Visual Studio I have ever used. Visual Studio 2019 was released to manufacturing on April 2nd 2019 and I’ve still yet to upgrade from the Preview, but I am looking forward to it. Did I mention that it’s free?

That being said, for opening single files I do prefer using Visual Studio Code to the full version of Visual Studio – just because it is that little bit quicker and for looking at just one file the interface is a little less cluttered. But for dealing with multiple files (which I do, regularly) and for any kind of large-scale editing, Visual Studio 2019 is at the top of its game.

Visual Studio 2019 has been absolutely fantastic.

BitBucket and GitKraken

These two go together, though they are separate products.

BitBucket is a Git management solution and works in exactly the same way as GitHub, which we use at NUA to share code. GitHub is probably the world’s most famous Git solution, but honestly I prefer BitBucket for several key reasons:

  • The free version still allows you to have repositories that are up to 1GB in size.
  • The free version still allows you to have an unlimited number of files in a repo (GitHub will limit you to around 100).
  • The UI is so much tidier and looks a lot more modern than GitHub’s, it makes finding things much easier. I prefer looking back at old commits on BitBucket and it’s easier to see where changes have been made.
BitBucket’s pleasant UI makes it enjoyable and easy to use.

GitKraken is a program that can push and pull from various Git management systems, BitBucket and GitHub included. Even though GitKraken takes an age to load, I find its UI very easy to use and it’s so simple to push and pull from BitBucket using it. I’ve linked GitKraken to my BitBucket account meaning that when I make a new repo on BitBucket, it appears immediately in my list of repos that GitKraken can pull without the need to copy and paste links and set permissions from BitBucket to GitKraken (it can do the same with GitHub, too). GitKraken also displays the commits and who committed them in a nice visual way, not to mention that its dark UI looks very attractive. I’ve heard bad things about the in-built Git solutions in Visual Studio and desktop versions of GitHub’s own solution – for me, GitKraken has worked great. It’s also free.

I was introduced to both BitBucket and GitKraken whilst interning at Earthware over the summer of 2018, so perhaps that’s why I’ve become accustomed to using them.

GitKraken is my preferred software for source control.

Adobe Lightroom

I’m a very keen photographer and usually when talking about Lightroom I talk about how amazing it is for photo editing and how quick and easy it is to make a dull RAW file from your D-SLR or even phone, these days, look incredible. Six or seven years after I first used Lightroom, I still love it for that reason, but in this project Lightroom really excelled because of its amazing export options. There are so many different formats and sizes and settings that Lightroom can save photos in, it’s crazy. This web app needed to be as tiny as possible, so just before I pushed the final commit of this to BitBucket, I imported every single image from the app into Lightroom and got it to export them all as JPEGs that were no larger than 90 KB in size. And it did it. In about a minute. Amazing!

Lightroom can export many files at once with specified width and heights or a maximum file size.

Surface Pro (4)

I mentioned in my post about Interchange how I had recently acquired a Surface Pro 4 because I felt that I needed to be taking more notes during seminars at university. You can read all about how it excelled as a note-taking device here, but for this project it has excelled from the other end – as a powerhouse. The Surface Pro 4 replaced my ThinkPad T440s in March 2019 and so far I haven’t looked back. The T440s was, and still is, an excellent machine – fast, reliable, comfortable to use, well-specced and very well-built – but the Surface Pro 4 has all of these qualities in a body about half the size and probably less than half the weight. For mobility, it’s a no-brainer! Only Surface owners feel this ‘Surface magic’, but to say that they are ‘pocket rockets’ is the best way to put it somebody who doesn’t own one.

The Surface Pro 4 is proving itself to be an extremely versatile machine and is becoming fundamental to my productivity at university. It replaced my ThinkPad T440s in March 2019.

 

It reminds me a lot of the original Surface Pro (which I still own) that I was using when I was an A level student.

Creating the final version of the grid

Directional buttons and CSS ScrollSnap compatibility

As mentioned earlier, there were two versions of the grid which were produced in early March:

  • A version that used jQuery smooth scrolling and directional buttons to move between the different cells.
    • The user could scroll, but the grid would not ‘snap’ to the next cell when the user scrolled or swiped.
    • The navigational buttons were compatible with a large range of web browsers because they just used jQuery to handle moving between divs.
  • A version that used CSS ScrollSnap to move between different cells.
    • The user could scroll or swipe and the grid would ‘snap’ into the next cell.
    • Only compatible with very modern browsers as this is a brand new bit of CSS.

We identified that we’d like to implement both directional buttons and some form of ‘snapping’ to a grid, however early attempts to amalgamate the two prototypes to create one that did both proved to be very difficult. The main problem was that the CSS ScrollSnap and the jQuery smooth scrolling method used the same kind of browser property to scroll, so either one or the other worked.

Eventually, I produced a solution that was a compromise between the two. It was apparent that using the jQuery smooth scrolling library explained in this post was not going to be compatible with the CSS ScrollSnap, so I altered the code of the navigational buttons to look a little like the below (downwards button code shown, the other directions are similar):

//Down
$('#down-button').click(function (e) {
    currentrow++;
    location.href = '#row' + currentrow.toString() + 'col' + currentcol.toString();
    freezeDownwardsRow();
    printInfo();
});

Before, the act of moving to the cell was done by running a method called ‘scrollVertical’ (or ‘scrollHorizontal’) that used jQuery to animate the smooth scrolling between the current div and the div to navigate to, using code like this:

$('#row' + currentrow + 'item' + currentcol).scrollVertical();

But since this interfered with the CSS ScrollSnap, by simply using the ‘location.href’ navigation method in jQuery, it is possible to move to another div. The same kind of code could be used to navigate to any website if you wanted to, ‘location.href = ‘ is the jQuery equivalent of:

<a href="link here">Link text here</a>

in HTML.

By default, this just navigates to the cell underneath the current one with no animations whatsoever. Since it’s not possible to use jQuery to animate the scroll (since this would affect the CSS ScrollSnap functionality), CSS must be used instead. Smooth scrolling used to be possible only with jQuery or a very long-winded vanilla JavaScript script, but is becoming possible with CSS with the use of the new ‘scroll-behavior’ property. By using the code below and applying it to the HTML, it is possible to apply smooth scrolling to any div ID or anchor point on your website without the need for JavaScript at all:

html {
    scroll-behavior: smooth;
}

This now means that the upwards and downwards directional arrows on the grid scroll the grid smoothly, but unfortunately it does not apply for left and right scrolling or for navigating to divs that require horizontal scrolling to reach. For those divs, the navigation still works using ‘location.href = ‘, but is not animated at all.

The other issue with this is that like CSS ScrollSnap, it is also only compatible with a handful of very up-to-date browsers. On older browsers this code will not execute at all. Like the ScrollSnap property, Visual Studio 2019 still doesn’t even recognise scroll-behavior being a CSS property.

The scroll-behavior CSS property is also not compatible with ScrollSnap (seems anything that is to do with browser scrolling is not compatible with ScrollSnap), so the ScrollSnap works when swiping or scrolling across the grid, but no longer works when scrolling or swiping up and down – because the scroll-behavior CSS property is active on this. If I had more time or if this was going to be a production piece I would have been interested in finding a workaround, but for the sake of a prototype this will work fine and is a compromise.

Ensuring that the horizontal directional buttons work when the user is scrolling

One problem with having the user being able to scroll/swipe and use directional buttons is that when the user is scrolling down the page, how is the current row and column recorded? My previous prototypes incremented or decremented an integer variable for the current row and/or current column depending on which button was pressed, but when the user is scrolling and not tapping on a button how is this done?

The reason why this is is an issue is because of scenarios like this: imagine you are scrolling down the grid rows and eventually reach the third row (the bottom row on our 3×4 grid). You then decide to tap on the ‘right’ button to move one cell to the right, but because this code is being executed when you tap this button:

currentcol++;
location.href = '#row' + currentrow.toString() + 'col' + currentcol.toString();

And the value of ‘currentrow’ is still 1 (it has not changed to 3 because you haven’t been using the buttons to navigate), instead of moving to ‘row3col2’ (as you’d expect, because you are currently in ‘row3col1’), you move back up to ‘row1col2’ because although the column value has incremented, the row value has not changed at all.

One way to alleviate this problem is to change the value of row depending on how far you have scrolled down the page. Easier said than done because remember, we are limited as to which scrolling events we can use with jQuery because of breaking compatibility with CSS ScrollSnap and vanilla JavaScript doesn’t seem to support figuring out how far you’ve scrolled down the screen terribly well.

Using no jQuery at all, this is the vanilla JavaScript way I used to combat this problem, explained step-by-step:

window.addEventListener("scroll", scrollDown);

    function scrollDown() {

        var windowHeight = window.innerHeight;
        var pageLength = windowHeight * 3;
        var firstThird = pageLength / 3; 
        var secondThird = firstThird * 2;
        var thirdThird = secondThird + firstThird;

The first thing to do is to add an event listener to the page window which listens specifically for ‘scroll’ events. You could also use ‘wheel’, but note that ‘wheel’ does not support swiping or touching or even dragging down the scrollbar on the browser – it only supports scrolling with the mouse wheel. ‘Scroll’ supports all methods of scrolling down the page.

Create a function that executes on page scroll, in this example I called mine ‘scrollDown’ and create the variables you see in the code above, explained below:

  • windowHeight = window.innerHeight: the ‘window.innerHeight’ method can be used in JavaScript to calculate the height of the current document in view. Example, if you have a document that is 2,160 pixels tall, but only 1,080 pixels are being displayed at the moment, then the value of ‘window.innerHeight’ will be 1,080.
  • pageLength = windowHeight * 3: take the value of ‘window.innerHeight’ that was assigned to the variable ‘windowHeight’ and multiply it by 3. This is multiplied by 3 because there are 3 rows in the grid. If there were 4, it would be multiplied by 4 and so on. This calculates the height of the entire grid. Store the value of this in a variable called ‘firstThird’.
  • firstThird = pageLength / 3: take the value of ‘pageLength’ and divide it by 3 to get the maximum height of the ‘first third’. This value will always be the same as the ‘windowHeight’ value. Again, if there were 4 rows in the grid it would be divided by 4 and so on.
  • secondThird = firstThird * 2: take the value of ‘firstThird’ and multiply it by two to get the maximum of the ‘second third of the page’ (or simply the height of two thirds of the page).
  • thirdThird = secondThird + firstThird: we know that the maximum height of the third and final ‘third’ is equivalent to the first and second added together, so add them. This value should always be the same as the ‘pageLength’ value.

You could shorten this code by writing this as one big expression that is calculated (or even removing some of the variables that will always have the same value as other variables in the code above), but to make the code more manageable and easier to explain I chose to break the expression into separate variables.

With these variables set, using simple if statements it’s possible to calculate which row the user is on:

var distanceFromTop = window.scrollY;

    if (distanceFromTop <= firstThird -5 ) { 
        currentrow = 1;
    }

    else if (distanceFromTop > firstThird -5 && distanceFromTop < secondThird -5 ) {
        currentrow = 2;
    }

    else {
        currentrow = 3;
    }

‘window.ScrollY’ is the JavaScript method that can be used to find out how many pixels from the top of the page the user has scrolled. This is vital because the if statements beneath this declaration work out which row the user is on based on how far down the page they have scrolled.

  • If the user has scrolled a fewer number of pixels down the page than the value of ‘firstThird’ (+5, more on this later), then row must be row 1.
  • If the number of pixels from the top is between the value of ‘firstThird’ (-5) and ‘secondThird’ (-5), then the row must be row 2.
  • Otherwise, the user must be on row 3.

The +/-5 leeway was added so that if the user hasn’t quite scrolled all the way up or down the page but the vast majority of the cell is visible on the screen, then the buttons still work.

That’s my solution to that problem. Now when this code is executed when you are on ‘row3col1’ having scrolled down the page:

currentcol++;
location.href = '#row' + currentrow.toString() + 'col' + currentcol.toString();

The value of ‘currentrow’ will be 3 because you have scrolled enough pixels from the top of the screen – and the code will execute correctly.

This code works, but it is not terribly fast. It’s generally not a great idea to use scroll listeners and execute code each time the user scrolls because this can severely impact on performance – imagine trying to execute big long scripts each time you scrolled! In this example it’s fine for several reasons:

  • The code is pretty minimal and not a lot of maths is being done – only basic operations.
  • This is for a prototype, not a production piece.
  • In the nicest possible way, it’s a university piece and was made on a very tight deadline.

But in the real world, this method would probably be frowned upon because of the potential performance impacts.

Everything explained about creating the final version of the grid up to this point is explained and demonstrated in the video below:

Hiding the directional buttons on cells where not all of them are needed

This was the final challenge when creating the grid with swipe/scroll and button navigation abilities. The majority of the cells in the 3×4 grid do not need all of the directional buttons, take the far right side for example (or the right-most column) – it does not need the right arrow directional buttons because it is not possible to go ‘righter’. The corner cells also do not require all of the buttons, nor do the up-most or bottom-most cells. Leaving these in could confuse the user and make them think that there is more to look at when actually there isn’t. They need to be removed.

Demonstration of the bottom arrow being hidden when the user reaches the bottom-most row.

The directional buttons on the grid are just HTML divs with background images and a set width and height to make them clickable. So removing them should be easy, right? Presumably each cell div (remember, each cell div represents a cell) has the HTML code for the buttons in it – just remove the ones from the cell divs that don’t need them.

Wrong! The buttons only work when there is one of each, so the buttons are divs that are fixed in position and thus are not unique to the cells. The reason why they only work when there is one of each is fairly simple, but I didn’t think about it at the time. I’ve explained the better solution later, but for now this essentially means that the four buttons appear on all cells because they are fixed elements and display above the grid.

I tried to come up with lots of elegant-ish solutions for hiding them on the unnecessary cells, including writing functions that checked the page height and width and integrated nicely with the buttons and scrolling, but nothing worked. In the end, due to time running short and this being a problem, I went for the fairly simple but un-elegant solution shown below.

/*Hide arrows based on cell ID -left is never hidden*/
function hideArrows() {

    //All row 1
    if (currentrow === 1) {
        $('#up-button').css('display', 'none');
    }

    //Row1Col1, Col2, Col3
    else if (currentrow === 1 && currentcol <= 3) {
        $('#left-button, #down-button, #right-button').css('display', 'block');
        $('#up-button').css('display', 'none');
    }

    //Row1Col4
    else if (currentrow === 1 && currentcol === 4) {
        $('#left-button, #down-button').css('display', 'block');
        $('#right-button, #up-button').css('display', 'none');
    }

…and so on (there is more, but the code gets quite long).

I went through and thought about which arrows needed to be shown on each grid and then used the jQuery CSS property to set the CSS display property to none or block depending on the row and column number. The good thing about this solution, despite it being a bit un-elegant and messy, is that since the row count is now checked each time the user scrolls this code works nicely with the scrolling/swiping and tapping on the directional buttons. Or rather, it would do if the function wasn’t executed like this:

$('.arrow-buttons').click(function () {
    hideArrows();
});

Unfortunately I didn’t think about this when coding this (admittedly it was probably late at night and very quickly), so the function is only run each time a button is pressed (the arrow buttons share the same CSS class of ‘.arrow-buttons’). To get it to work with scrolling to, it would need to have also been called in that ‘scrollDown’ function I described earlier.

But, it works for the most part and solves the problem.

Demonstration of the right arrow and downwards arrow being hidden when the user reaches the right-most column.

A more elegant solution to the problem just described

A better solution would have been to not have the arrows set out like this in the HTML:

<!--Fixed navigational buttons-->
<img src="img/ar.png" class="arrow-buttons" id="left-button">
<img src="img/ar.png" class="arrow-buttons" id="right-button">
<img src="img/ar.png" class="arrow-buttons" id="down-button">
<img src="img/ar.png" class="arrow-buttons" id="up-button">

Above the cell divs, rather have the buttons in each cell div, like below:

<!--ROW 1-->
<div id="row1col1">
    <div class="container">
        <header>
            <div class="nav-c">
                <img src="img/logo.png" alt="logo" class="logo">
            </div>
            <h1 class="title">Oulton Broad</h1>
            <h1 class="sub">Ancient Times</h1>
        </header>
    <div class="content">

        <!--ARROWS-->
         <img src="img/ar.png" class="arrow-buttons" id="left-button-row1col1">
         <img src="img/ar.png" class="arrow-buttons" id="right-button-row1col1">
         <img src="img/ar.png" class="arrow-buttons" id="down-button-row1col1">
         <img src="img/ar.png" class="arrow-buttons" id="up-button-row1col1">

        <!--CONTENT-->

        <p>Content goes here</p>
    </div>
</div>

Then in the code for the buttons, instead of getting just one ID (‘down-button’ in this case), get all of the relevant IDs:

//Down
$('#down-button-row1col1, #down-button-row1col2, #down-button-row1col3, #down-button-row1col4').click(function (e) {
    currentrow++;
    location.href = '#row' + currentrow.toString() + 'col' + currentcol.toString();
    freezeDownwardsRow();
});

That way you could easily hide the arrows from the cells where they weren’t necessary by… not having them there in the first place! And save the need for a function written specifically to hide arrows.

The reason why it wasn’t working for me when I had the arrows in the individual cell divs and trying to get the buttons to work based on getting an ID such as ‘left-button’ before is because there were multiple elements with the ID of ‘left-button’, which not only is poor programming, but also confusing for jQuery as it doesn’t know which called ‘left-button’ it needs to assign the click event to.

From the grid to the previous screen – the one challenge that I couldn’t complete

It was intended that on the left-most column of the grid, the left arrow button would take the user back to the previous page. However, on the other cells the left arrow button would need to navigate you back to the next cell to the left.

The left arrow on the left-most cells on the grid were supposed to take the user back to the previous page.

My initial solution to this problem was to change the ID of the left arrow button from ‘left-button’ to ‘left-button-back’ when the user was on any cell in column 1. The following function would have made this happen:

function checkId() {
    if (currentcol === 1) {
        document.getElementById("left-button").setAttribute("id", "left-button-back");
    }
    else {
        document.getElementById("left-button-back").setAttribute("id", "left-button");
    }
}

Then I could have used a function like this to go back to the previous page on the browser page stack when the user tapped on ‘left-button-back’:

function goBack() {
    window.history.back();
}

$('#left-arrow-back').click(function () {
    goBack();
});

Unfortunately, this didn’t work. It’s possibly because of the else statement in the first function not working correctly. Regardless, it was a clever thought, I felt.

With hindsight being the beautiful thing that it is, I’ve realised that had I not used static buttons and gone with the idea that I suggested earlier instead I could have given the left arrow buttons in all column 1 cells the ID of ‘left-arrow-back-row1col1’ and ‘left-arrow-back-row2col1’ (and so on) and that function shown above would have worked flawlessly and solved this problem!

Hindsight is a wonderful thing!

Adding content to the grid

Once I had this sorted and the grid template was perfected and working, I sent Ameer the files and he put his content design in that he had been coding. He also added a nice diagram to the grid showing the user were they were. He writes in his reflective journal from that week:

I’ve opened Jason’s grid system file and simply modified one of the rows to fit the design. This procedure was straightforward. It was just a matter of copy-pasting code, HTML and CSS. Then that was it, the design fit perfectly into one of the grid’s cells.

Ameer was able to write an additional stylesheet with the properties for content on the grid and put his code into the grid template and it all looked and worked correctly. Ameer didn’t need to understand any of the back-end bits I’ve explained here that make the grid function, rather just be able to put his work into it.

Ameer found adding his content to the grid template easy.

Reflections on creating the grid

The grid was by far the most complex and most annoying part of the entire web app prototype development to create. The battle between jQuery and CSS incompatibilities when it came to scrolling were a nightmare as the requirement was to have a grid system that worked with both scrolling and tapping buttons. I had to put a lot of time and effort into researching how to work around these issues and with nobody online trying the same thing as me, all I could do was try each solution that I could think of and hope that it worked.

Usability testing would tell me if it was worth the hassle of trying to marry scrolling to tapping buttons – with interesting results!

For the sake of a prototype, the grid is functional, but as a production piece this would fail because it doesn’t work 100% smoothly and there are some performance pitfalls. I did however enjoy thinking outside of the box to solve some of the problems that the grid posed.

By comparison, making everything else was a piece of cake.

Creating the map

The map was the first new piece of code that was made for the final prototype. Chloe and Zach designed the prototype on March 28th and 29th and I began to code it on April 1st.

The map allows the user to select one of 10 locations from a drop-down menu, or use left and right arrow buttons to cycle through the locations, as well as allowing the user to view places to eat, toilets, public transport and parking facilities.

Coding the map was more straight-forward than it sounds – certainly more straight-forward than fixing the endless issues with the grid. I’ll comment more about the design of the map (and the other elements) when it comes to the user testing, but for the time being this is about how it was coded.

Chloe and Zach’s design shown in Adobe XD on the right and my coded prototype running in Google Chrome, left.

Enabling the user to select a location to view on the map

This was relatively straight-forward. The map features a fairly basic drop-down menu which can be toggled by tapping on the place name at the top of the window. jQuery does include a ‘toggle’ method which I have had varied success with. For this reason, I prefer to write my own toggle functions which essentially just check the value of a variable and then hide or display an element based on that value.

var menuOpen = 0;

$('#current-location').click(function () {

    if (menuOpen === 0) {
        $('.location-picker').slideDown();
        menuOpen = 1;
    }

    else if (menuOpen === 1) {
        $('.location-picker').slideUp();
        menuOpen = 0;
    }
});

When the value of ‘menuOpen’ is 0, the software knows that the menu is hidden, so it must open the menu and vice-versa for when the value is 1.

The class ‘location-picker’ is just a div containing a list of locations and the ID ‘current-location’ is the element that the user taps on to open the menu.

To get the ‘slideUp’ and ‘slideDown’ jQuery methods to work, it’s important to first hide the element that you want to slide up or down using jQuery, like this:

//Hide the location picker by default
$('.location-picker').hide();

You can’t:

  • Set the visibility to ‘hidden’ in CSS.
  • Set the display to ‘none’ in CSS.
  • Use the jQuery CSS method to set either the visibility or the display property, e.g. you can’t use:
$('.location-picker').css('display', 'none');

You must use the jQuery ‘hide’ method.

As for the map itself, it’s a Google Map placed inside an iFrame, the source code for which looks like this:

<div class="map-holder">
<iframe id="map" width="100%" height="80%" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d9721.990926489985!2d1.6953492468776337!3d52.4701231983878!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da1b1d3e5e5a09%3A0x50e1ca8bbc26630!2sOulton+Broad%2C+Lowestoft+NR33+9JY!5e0!3m2!1sen!2suk!4v1554147550023!5m2!1sen!2suk"></iframe>
</div>

The iFrame is placed inside a container called ‘map-holder’ and has the ID of ‘map’.

After some thinking, I decided that the easiest way to get the map to change location was to get the URLs for each of the 10 sites and place them in an array. Then, when the user tapped on a location to visit in the drop-down menu, the URL would be loaded from the array and set as the source for the iFrame map.

This idea worked! The code is explained below.

//URLs for the different maps
var urls = [
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d9721.990926489985!2d1.6953492468776337!3d52.4701231983878!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da1b1d3e5e5a09%3A0x50e1ca8bbc26630!2sOulton+Broad%2C+Lowestoft+NR33+9JY!5e0!3m2!1sen!2suk!4v1554147550023!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2422.866616538652!2d1.7096507161081314!3d52.608181779830936!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da06a1d094d407%3A0xdf020d01096dde50!2sBroadland-Great+Yarmouth+Rugby+Club!5e0!3m2!1sen!2suk!4v1554148311879!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d19392.082932793597!2d1.6498948042351966!3d52.5875058089196!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da0390f3efe97b%3A0x816d72790f8ce753!2sBurgh+Castle%2C+Great+Yarmouth!5e0!3m2!1sen!2suk!4v1554148350225!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d9710.53075259774!2d1.6428272483841024!3d52.52198612703212!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da03304dbe4f31%3A0xc0bbbba3bd8be28e!2sHerringfleet%2C+Lowestoft+NR32+5QS!5e0!3m2!1sen!2suk!4v1554148397228!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2430.604820507463!2d1.6909699161038274!3d52.4681839798044!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da1b9aeeb8f487%3A0x4b04bcc70c90115f!2sCarlton+Marshes+Nature+Reserve!5e0!3m2!1sen!2suk!4v1554148443402!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2430.8307937007103!2d1.5634023161037234!3d52.46409177980365!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47d9f63b4afc9441%3A0x41cf0eb9d3940d48!2sFen+Ln%2C+Beccles!5e0!3m2!1sen!2suk!4v1554148491347!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2430.8554709761997!2d1.514997516103693!3d52.46364487980361!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47d9f6ecdc9ce26d%3A0xd07e3bb7ee3c8b8!2sLocks+Inn+Geldeston!5e0!3m2!1sen!2suk!4v1554148547044!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d9726.555740029213!2d1.6177732483486245!3d52.44945512681335!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da1c34f186d3ed%3A0xbf9c25ca5322ebf!2sNorth+Cove%2C+Beccles+NR34+7PP!5e0!3m2!1sen!2suk!4v1554148587729!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d9705.651521260277!2d1.633123248394905!3d52.544056127099054!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da031b0d55d175%3A0x85c9dedeeda48f3d!2sFritton%2C+Great+Yarmouth+NR31+9EZ!5e0!3m2!1sen!2suk!4v1554148668721!5m2!1sen!2suk",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d9705.650504143032!2d1.650258698394926!3d52.54406072709909!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47da036ad9a7bcef%3A0x47da033d206e7809!2sFritton+Decoy!5e0!3m2!1sen!2suk!4v1554148697934!5m2!1sen!2suk"
];

This array called ‘urls’ contains all of the Google Map links to the individual locations that the user can see. We also need to define an integer called ‘arrayIndex’ and set its value to 0 initially.

Remember, arrays in most C-based languages, including JavaScript, start with the first item in the array being given the index of 0. The ‘arrayIndex’ value will be used to index the array and retrieve items from the array later on in the program.

There is another array, called ‘locations’, which houses each of the locations that the user can navigate to on the map.

var locations = ["Oulton Broad", "Breydon Water", "Burgh Castle", "Herringfleet", "Peto's Marsh", "Beccles", "Geldeston", "North Cove", "Caldecott Mill", "Fritton Decoy"];

These two arrays are linked in that the URLs in the ‘urls’ array correspond with the index of the location in the ‘locations’ array. For example:

  • ‘Oulton Broad’ is the first item in the array ‘locations’ – it’s index is thus 0. The first item in the array ‘urls’ is the URL for the Oulton Broad map, it’s index is thus 0.
  • ‘Breydon Water’ is the second item in the array ‘locations’ – it’s index is thus 1. The second item in the array ‘urls’ is the URL for the Breydon Water map, it’s index is thus 1.
  • ‘Burgh Castle’ is the third item in the array ‘locations’ – it’s index is thus 2. The third item in the array ‘urls’ is the URL for Burgh Castle, it’s index is thus 2.

And so on.

The code to change the location of the map from the drop-down menu looks like this (Beccles used as an example):

$('#beccles').click(function () {
    $('#map').fadeOut(1000, function () {
        $('#map').attr('src', urls[5]);
        $('#map').fadeIn(1000);
    });
    document.getElementById("current-location").innerHTML = locations[5];
    arrayIndex = 5;
    closeMenu();
});

When the user taps on the link ID ‘beccles’, the ID ‘map’ (which remember is the ID of the iFrame containing the map) fades out. The source of the map is then changed to the 5th index of the array ‘urls’, as shown by this:

urls[5];

The 5th index in the ‘urls’ array is a link to the Beccles map. jQuery has a method called ‘attr’ which can be used to change attributes of HTML IDs and classes, so here we can change the ‘src’ attribute of the ‘map’ ID (the iFrame map) to the value of the 5th index of the array ‘urls’ – which sets the URL of the Beccles map as the source for the iFrame.

Then, the map fades back into view and the text in the ID ‘current-location’ is updated to reflect the change. The 5th index in the ‘locations’ array is ‘Beccles’, so the text in the current location title is updated to ‘Beccles’. The value of arrayIndex is set to 5 (more on this later) and a function called ‘closeMenu’ runs. This function just slides the menu back up and resets the value of ‘menuOpen’ to 0 so that the next time the user taps on the button to open the menu it opens, as per the function above.

Demonsration of the location picker in action.

The forwards and backwards buttons

These buttons allow the user to cycle through the locations without opening the menu. These are slightly more complex, but work in a similar way.

When the user taps on the ‘forwards’ button, the following code is activated:

function nextLocation() {
    closeMenu();
    arrayIndex++;
    checkArray();
    updateMap();
    updateLocation();
}

Asides from ‘arrayIndex++’ (which just increases the value of ‘arrayIndex’ by 1), this function just activates several other functions. The ‘closeMenu’ function just closes the menu and resets the value of ‘menuOpen’ to 0. The next function it runs is ‘checkArray’, shown below:

function checkArray() {
    if (arrayIndex > 9) {
        arrayIndex = 0; 
    }

    if (arrayIndex < 0) {
        arrayIndex = 9;
    }
}

We know that there are 10 items in each array, so there are 9 indexes (remember, the first item is assigned the index 0). Therefore, it is impossible for the value of ‘arrayIndex’ to be greater than 9 so if it ever exceeds 9 then it is reset back to 0. Likewise, it’s impossible for it to be less than 0, so it’s set back to 9 if it gets that low. The purpose of this is very similar to the ‘freeze row’ functions I wrote for the grid (explained here) – what we don’t want to happen is for the user to keep on tapping on the forwards button and increasing the value of ‘arrayIndex’ each time they do that. The problem this would create becomes clear when you look at the code for the next function, ‘updateMap’:

function updateMap() {
    $('#map').fadeOut(1000, function () {
        $('#map').attr('src', urls[arrayIndex]); 
        $('#map').fadeIn(1000);
    });
}

This is the function that changes the map itself. Much like the code shown for changing the location to Beccles, the map fades in and out and the attribute ‘src’ of the map is changed. However, this time it’s not changed to a set index, instead the value of ‘arrayIndex’ is used as the index. This is why it’s important to prevent the user from clicking on the buttons too many times and eventually inadvertently setting the value of ‘arrayIndex’ to something lower than 0 or higher than 9 – if they did this the following may happen:

  • They’d keep tapping on the forwards or backwards button and nothing would happen as the program would be trying to access an index that doesn’t exist in an array.
  • That may cause the whole web app to crash.
  • The user would keep tapping on the button and nothing would happen and to circumvent this they may tap on the opposite button (so tap on ‘forwards’ if they were tapping on ‘backwards’ and vice-versa) and still nothing would happen because the value of ‘arrayIndex’ would only be incrementing or decrementing by 1 each time they tapped that button and it may take a few taps before it reaches 0 or 9 again.

After this, the ‘updateLocation’ function is run:

function updateLocation() {
    document.getElementById("current-location").innerHTML = locations[arrayIndex];
}

This is exactly the same as the code used to change the location text before, the only difference is that we are now indexing the ‘locations’ array by the value of ‘arrayIndex’ rather than a set index.

And that’s how the forwards button works! The backwards button works in exactly the same way, the only difference is that the value of ‘arrayIndex’ is decremented by 1 each time that button is pressed.

Demonstration of the forwards and backwards buttons.

The facilities buttons

These were a lot easier to make than they sound! On the face of it, displaying all of the nearest cafes/pubs/coffee shops, toilets, railway stations, bus stops, taxi services and parking spaces sounds difficult, right? Luckily, Google has already spent a lot of time and effort working out where all of these are for us, so all we need to do is change the URL of the map to a map that displays those things and we are away!

I made an array for each facility that we wanted to show on the map. Below is the array for parking spaces:

var parkingurls = [
"https://maps.google.com/maps?q=parking%20in%20oulton%20broad&t=&z=15&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20great%20yarmouth&t=&z=13&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20burgh%20castle&t=&z=15&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20herringfleet&t=&z=15&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20carlton%20colville&t=&z=13&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20beccles&t=&z=15&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20geldeston&t=&z=13&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20north%20cove&t=&z=9&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20fritton&t=&z=11&ie=UTF8&iwloc=&output=embed",
"https://maps.google.com/maps?q=parking%20in%20fritton&t=&z=11&ie=UTF8&iwloc=&output=embed"
];

The way this works is exactly the same as the standard map. In this array (and the array for food, toilets and public transport) is a URL containing a map of the parking spaces in Oulton Broad as the 0th index, the parking spaces in Breydon Water as the 1st index, the parking spaces in Burgh Castle as the 2nd index and so on. The order of the URLs in these arrays is exactly as the same as the ‘urls’ and ‘locations’ arrays, meaning that the variable ‘arrayIndex’ is still valid for these.

That means that the code to view the parking spaces (in this example), is as simple as:

$('#parking-button').click(function () {
    $('#map').fadeOut(1000, function () {
        $('#map').attr('src', parkingurls[arrayIndex]);
        $('#map').fadeIn(1000);
    });
    closeMenu();
});

Look familiar? That’s because it is! When the user taps on the ‘parking’ button at the bottom of the map, the map fades out, the source of the map iFrame is changed to the value of ‘arrayIndex”s position in the array ‘parkingurls’ and the new map fades into view. We assumed that the user would be interested in seeing facilities only for the location that thy currently had open, in which case this code is perfect.

The facilities buttons on the map in action.

All of this code can be seen running and is explained visually in the video below:

Reflections on coding the map

First off, it is apparent to me now that this is something that wasn’t originally assigned to me. It turns out that Ameer was supposed to be the one that coded this. I guess I did it because I had the XD file that Chloe and Zach had been working on and I wanted the challenge, but this doesn’t necessarily show the best teamwork or delegation qualities. It seems that Ameer wasn’t too concerned about not doing this task, but in future I need to be careful that I don’t step in and do work that’s been assigned to other people. Perhaps the time that I spent making this could have been spent fixing the grid and getting that left button working, or resting. I need to get much better at letting people do work and trusting them to do it, something that I hope heading Storehouse magazine will enable me to do.

That aside, this was actually really fun to code and again, I thought I came up with a good solution. I didn’t do a lot of research into this, all I really needed to find out was how to change the ‘src’ attribute of an iFrame with jQuery. Once I had that, I was ready to go again! I haven’t used arrays in JavaScript since I coded the Stellardrive prototype – which was my first ever university piece! On a side note, it’s hard to believe that that was around 18 months ago now! This map component is definitely something that I feel proud about and I really like how it functions and actually does display the information that you ask from it. Too many times on prototypes we have to compromise with slightly more complex (and sometimes quite interesting) things like this and instead just use screenshots or mock-ups in prototyping software to show how something would look or function. This time we’ll be able to test out a fully-coded example which actually works. This should help us to get more meaningful results from usability testing.

Creating the nature finder experience

Namii’s nature finder experience was coded mainly by her, but I chipped in and helped where I could. Namii, being new to coding, asked for some support which I gave to her and she picked it up very quickly and understood it all. The nature finder has the simplest JavaScript of the three or four experiences (including the map), but arguably some fairly complex CSS (though not as complex or ‘cutting edge’ as the CSS ScrollSnap on the grid) and definitely the biggest and toughest information architecture. At 46 HTML pages big, Namii’s nature finder is definitely a piece of ‘IA in action’ and required extensive testing to ensure that each button went to the correct page.

The information architecture for Namii’s finder app is very extensive with there being well over 40 pages to link.

The JavaScript

The JavaScript is very simple, but at the same time writing it was a very ‘precise mission’ – meaning that we had to ensure that it was absolutely perfect. When writing code that does the same thing and copying and pasting it time and time again to write it, the room to make a mistake is massive.

The JavaScript runs on jQuery and just navigates to files when the corresponding button is tapped, see example below:

//stage1-2
$('#spring-button').click(function () {
    location.href = "stage2/spring.html";
});

$('#summer-button').click(function () {
    location.href = "stage2/summer.html";
});

$('#autumn-button').click(function () {
    location.href = "stage2/autumn.html";
});

$('#winter-button').click(function () {
    location.href = "stage2/winter.html";
});

//stage2-3 
$('#spring-plants-button').click(function () {
    location.href = "../stage3/spring-marginal-species.html";
});

$('#spring-animals-button').click(function () {
    location.href = "../stage3/spring-birds.html";
});

$('#summer-plants-button').click(function () {
    location.href = "../stage3/summer-marginal-aquatic-species.html";
});

The folder structure of the locations will make more sense when you read the next post about putting the experiences together.

The CSS

The JavaScript may have been fairly basic, but the CSS was more complex.

Initial designs for the finder app by Corrina and Namii experimented with the positioning of the trapzeium-shaped buttons. Trapzeium-shaped buttons were the brainchild of Corrina who designed them with the idea that the angular buttons fit the ‘Angles Way’ name in a rather literal way. The idea was received well by the team and we decided to go ahead with it.

Initially they began to design them looking a bit like the landing pages (more on this later) and then experimented with moving the buttons around the screen and see how they looked in various positions, shown below:

Initial prototypes for the finder made by Corrina and Namii on Adobe XD.

The final design chosen was very close to the one on the shown on the upper left, the only difference being that the images were changed and all of the buttons were the same length.

The final design for the theme selection page, shown running in Google Chrome.

The buttons for her finder app (and those for the the theme selector pages) use CSS polygons to create thier shape. They are divs with background images that are ‘clipped’ to the shape of a trapezium, using the CSS below:

.season-button {
    width: 100vw;
    height: 24vh;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    background-color: rgba(255, 0, 0, 0.5);
    -webkit-path-clip-path: polygon(20% 37%, 100% 12%, 100% 75%, 20% 100%);
    clip-path: polygon(20% 37%, 100% 12%, 100% 75%, 20% 100%);
    margin-bottom: -6vh;
    text-align: center;
}

The buttons on Namii’s finder app all share the class of ‘season-button’. The background is positioned to the center and set to cover the div and clip path cuts the div into the shape that you see below.

Each button has a unique ID where the source of the background image is set:

#spring-button {
    background-image: url('../img/options/spring.jpg');
}

The hero images on the individual screens also work in the same kind of way.

The animals that the finder finds are displayed in a grid which works using Flexbox to ensure mobile compatibility. This does mean that once again, old browser compatbility is not great, but generally modern browsers will render it fine.

The HTML markup is shown below:

<div class="boxes">
    <div class="info-box common-reed">
        <p>Common Reed</p>
    </div>
    <div class="info-box willow">
        <p>Willow</p>
    </div>
</div>

The individual boxes in the grid sit inside a div class called ‘boxes’ and content for each box sits inside a div class called ‘info-box’. The CSS properties for these is shown below:

/*Species search results boxes*/
.boxes {
    display: flex;
    flex-flow: row wrap;
}

.info-box {
    margin: 1vh;
    height: 13vh;
    width: calc( (100% / 2) - 20px );
    padding: 10px;
    border-radius: 10px 10px 10px 10px;
    background-repeat: no-repeat;
    background-size: cover;
    color: black !important;
}

By setting the display to flex and the flex-flow to row wrap it’s possible to make the tiles responsive. The properties for the individual tiles (the ‘info-box’ class) set the height of the tiles to 13% of the viewport and the width to 100% of the width divided by 2, minus 20 pixels. Inside padding is set to 20px to keep the contents away from the edfges and the margin is 1% of the viewport height to space out the individual tiles. The background image properties are also set here too, apart from the source of the image which is different for each tile. Each tile has a second CSS class attached to it, which is the name of the animal. The animal class dictates the source of the background image. Shown below is the class for ‘common-reed’, which is one of the classes used in the example HTML above.

.common-reed {
    background-image: url('../img/specimens/common-reed.jpg');
}

This is the easiest and most efficient method to have different background images for different buttons in CSS.

The information pages

The information pages in the final version of the nature finder app are very similar to the initial designs. The initial designs by Corrina and Namii are shown below:

Initial ideas for the information pages.

It was decided to use the design on the right, but make some adjustments for the final version. The final version features a backwards arrow to navigate to the previous page on the browser stack, the carousel indicators (more below) and the fixed button for the map which appears at the bottom of the window.

An example of one of the information screens from the final prototype.

The code for the information screen is fairly straight-forward. The hero image this time is specified in the HTML code and the div that is sits inside of, ‘hero’, has a CSS clipping path applied to it to make it the shape shown in the image above. The clipping path code is very similar to that from the buttons, shown earlier.

The information on the screens is held in a scrollable div, the HTML of which is shown below:

<div class="info-block">
    <h1>Yellow Water-Lily</h1>
    <p class="info">
        Scientific name: Nuphar iutea
        <br>
        <br>
        Look for the Yellow Water-lily in still and slow-moving water, such as ponds, ditches, lakes and canals. Its lily pads and cupped, yellow flowers float at the water's surface. The Yellow Water-lily is a common plant of still or slow-moving water and grows in ponds, lakes, canals and ditches. It has large, lily-pad leaves that are up to 40cm across and grows in water up to 3m deep; the leaves and flowers float at the surface, while the rest of the plant is submerged, growing from the mud at the bottom. It flowers during the summer, from June to September, and smells like the dregs of wine, hence other common names like 'Brandy Bottle'. Water-lilies are good plants to add to a wildlife-friendly pond, providing shelter for frogs and early nectar for insects.</p>
</div>

To make the information scrollable, the div class ‘info-block’ has the following CSS properties applied to it:

.info-block {
    width: 82vw;
    height: 38vh;
    overflow: scroll;
    margin-left: 13vw;
}

The position of the div itself is set using the margin-left property and the width and height properties sets the size and to make it scrollable, the overflow is set to ‘scroll’. With no CSS ScrollSnap to worry about on these screens, this code works perfectly. All of the content is now readable and does not go over any other elements on the screen.

Demonstration of the scrolling content in the div.

The ‘carousel’ (or ‘breadcrumb’) buttons on the nature finder

When they initially designed this on March 22nd, Corrina and Namii were keen to have some kind of visual representation showing the stage of the app that the user was currently at. With the user going through several screens, they felt it was a good idea to let the user know whereabouts they were in relation to the final stage where the app would list the wildlife that was available for them to see.

Several ideas were proposed by Corrina, seen below.

Ideas for ‘breadcrumbs’ proposed by Corrina

The left-most design is a ‘classic carousel’, featuring dots that change colour as you move screens. The second is a similar idea, but the shape of the square changes – the idea of the shape is that it is similar to the angles used in the buttons on the experience. The third idea is that the position of the shape moves from left to right across the bottom of the window as the user goes further into the app. The final idea was a slider one, where the shape would move across the slider and the user would be able to move the slider across to move further into the finder. Namii mentioned that the issue with this is that the user has to select options (such as the season and the type of animal or plant they are interested in), so the slider idea wouldn’t work.

It was decided to use the simple carousel buttons (but non-clickable) because they are conventional, clear to see, easy to understand and the easiest to code.

There is no JavaScript involved, just simple HTML and CSS. The following HTML appears on each page of the finder.

<div class="carousel-holder">
    <div class="carousel-circle carousel-active"></div>
    <div class="carousel-circle"></div>
    <div class="carousel-circle"></div>
    <div class="carousel-circle"></div>
    <div class="carousel-circle"></div>
</div>

The class ‘carousel-holder’ is just positioned at the bottom of the page and each ‘carousel-circle’ class is just a div with the following properties to make it a white circle.

.carousel-circle {
    position: relative;
    display: inline-block;
    width: 3vw;
    height: 3vw;
    border-radius: 100px;
    background-color: white;
    margin-left: 2vw;
    margin-top: 1vh;
}

By setting the border-radius to 100px the div becomes a circle – the width and height being the same also makes these divs a circle. Displaying them inline-block is an easy way to make them appear next to each other vertically as opposed to one on top of the other horizontally. The default colour is white, but by adding the class ‘carousel-active’ to the div class ‘carousel-circle’, the colour changes to the orange because that class just changes the background-color property from ‘white’ to #C25747.

Creating the 360 degree experience

Not much has changed since March 22nd at all. The only real change was the addition of the Oulton Broad 360 degree image and hotspots, putting the correct copy into those information hotspots and adding the Angles Way brand mark and the left arrow button on the experience that takes the user to the previous page, providing an escape route.

The 360 degree experience running with the Oulton Broad image and hotspots.

Creating the ‘core pages’

The ‘core pages’ are the introduction page, the ‘theme selector’ page and the landing pages for each of the themes which introduce the theme before the user can go to the experience. The code for these is very similar to the pages found in the nature app, which is why Namii coded these. She was able to be efficient and reuse a lot of the code, especially the CSS clipping paths which had been slightly problematic to create. The introduction page and the landing pages use exactly the same code as the information pages on the nature finder (without the scrollable div for the text, which was not needed) and the ‘theme selector’ page uses the same code as the season selector page on her nature finder, with slightly modified clipping paths to account for the slightly different design.

The core pages.

Website prototype

Zach and Chloe designed the website prototype, shown below. The design definitely fits the branding of the project using the same colours and the angles as suggested by Corrina and implemented in the app. However, Namii and I noted that from a usability perspective there may be the following shortcomings:

  • The text is largely on the right side of the screen. Most languages are read left-right so this doesn’t seem logical.
  • The text being on the right also means that neither the F or Z reading patterns fit this design terribly well (or at all).
  • The search bar could be placed in the header area at the top of the page, which would seem like a more logical position for it.
  • ‘News and events’ are repeated. They are shown at the bottom of the triangle and also in the blue centre bar.
  • The images in the carousel at the top of the page would need to be very carefully chosen with the focus being on the left of the frame – if the triangular section on the right is going to hold the text.
  • The headings seem too small or not obvious enough in that triangle – this could make it difficult for users to find information on the page.
  • The footer is extremely large. It could be half the height and the large Angles Way logo should be placed in the header instead, where the current logo is not big/obvious enough.

We haven’t started to design this further yet or code any prototypes, so this is just all ‘visionary’ at the moment.

Zach’s website design follows the identity very well, but does pose some usability issues.

Reflections

This was a busy few days in which I learned a lot. I felt that I worked alright as part of the team, but perhaps took on slightly too much work. It was interesting coding the different bits and it was nice to be able to teach Namii some coding techniques and then see her be able to do some of the coding herself and enjoy doing it. I feel that at this stage there wasn’t an awful lot for the graphic comms students to do once the different components of the web app had been designed and prototyped in XD, but they busied themselves by working on signage and coming up with a mock-up of the website.

Bibliography

Caniuse.com. (n.d.). Can I use… Support tables for HTML5, CSS3, etc. [online] Available at: https://caniuse.com/#feat=css-scroll-behavior [Accessed 15 Apr. 2019].

W3schools.com. (n.d.). CSS scroll-behavior property. [online] Available at: https://www.w3schools.com/cssref/pr_scroll-behavior.asp [Accessed 15 Apr. 2019].