Animated Drag & Drop – Dynamic Animations | Vanilla JavaScript [2021]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys today we're going to be building a sortable drag and drop list in javascript but the cool thing about this is that they actually animate so when you sort them as you can see look it actually animates rather than it just popping into existence like the other sortable lists on tutorials already out there on the internet so this one's a lot more interactive as you could see and it doesn't really matter how you move things around it works either way without errors so if this interests you then keep watching now before this tutorial begins i will point you to the finished projects codepen page so if you get stuck at any point in this tutorial you can go to here the link will be posted in the description box below and hopefully it will point you in the right direction but now we'll talk about this webpack boilerplate github repository that i've created for you i recommend that you use it for this tutorial because we are going to be using newer javascript code and i've already set up this uh this webpack project and what it does it comes with a webpack server another uh like post css stuff as well as babel and so it just compiles everything into a format that's compatible with older browsers uh even if we use like newer javascript features and newer css features etcetera so i'd recommend that you use this repository and clone it for that reason so inside the project of our choice and copy this uh obviously it comes from the the install uh instructions actually on the repository again the link will be posted to this repository as well and i'll just use a full stop to initiate to clone the project into the folder that we launched the terminal in and then once you've done that we don't need to cd into it because this terminal is already uh already in the project that we just cloned the repository into uh so we will however move the origin because we want to disconnect it from this remote repository and then we'll run npm install because we need to install the necessary dependencies and i want to cut to after i've installed all the dependencies and when i've got vs code open and running okay so i've now installed everything and now i've launched up vs code in the pod in the uh root project that we cloned the boilerplate repository into and it's also good factors to delete the readme markdown file because you don't want an exact replica of that from the uh boilerplate repository uh and what we'll do actually there's a there's a script that's um automatically been created so i just ignore that yeah but anyway there's a script that's automatically been created uh in this uh webpack boilerplate repository and it's called dev i'm running it we'll just run a webpack dev server and it will serve our project on localhost port 9000 so now if you go to localhost port 9000 as you can see we're already on it here we should get this um screen here but it might change at a later date but we should get some kind of of a boilerplate screen just so that we know that things are working i will delete this now because obviously we don't want a pretty ugly gray screen and we'll also delete this here as well in styles which gets applied because it's imported here and we're using something called star loader which allows us to import stylesheets into the main javascript file which eventually gets bundled in this file here which is incidentally the file that's linked to in the only html file that we have for this project um well we can import it either in the main one or or just any file that's that's derived off of the main one that's on its import tree but anyway that's how we got the gray background uh we should now nothing's obviously removed both the text and the styling um and what we will do is we will create a div called items and this will contain our item div inside here uh we'll have multiple these item devs by the way but inside of here we will create a hamburger div and this is to create a hamburger menu and we need one more div inside hamburger and we'll call it center because this isn't a application it's just a dummy application we will just have the text for the uh item div and which is after the hamburger div we'll just make it say list item and what we'll do we'll duplicate this line five times that we have five items in total or with our hamburgers to divide to them and that's good we'll now get down to styling this okay because the only thing that we're gonna have on the markup file is just that singular items div and that we want this items did to be centered both horizontally and vertically so in the direct center of the um of the screen we will make the body be a flex container and we'll set it to be we'll set its height to be 100 of the viewing height the actual viewport so that we can so that we can actually um center it vertically in the middle the items div and then yeah as i said display div and then both justify content and the line items to be center so that both axis are centered and then we'll give it some padding as well one a relative unit on all different sides as for the items div we will set it to be position relative because you want the individual item uh divs to be positioned absolute uh relative to this item's container and then we'll set its width to be 800 pixels which will be the exact same as the width of the item so as i mentioned before position absolute so that's based off of its parent which is relatively position background color we'll have a hex color for that and it will be e6 e6 e6 so e6 three times and again with 800 pixels reasons i already said left he wants his left edge to be aligned with the left edge of its container and basically we want so we just look at this now yeah they're all going to be in the exact same place because of what position absolute but if we what we need to do is we want to give it some vertical um some vertical height to them so we get pic 70 pixels it's important that we do it this way and not using padding however you may not want to do this because well you may think that you don't want to do this because uh it means that our text can't be centered vertically but to center it vertically we simply change the line change the line height 70 pixels same as the height and this will send to it uh in the middle of the text so mid in the middle vertically speaking anyway um so yeah that's that's how that's what we do again it's important that we do it this way instead of using padding for reasons that will become very clear later on uh and we'll set one size to be too well and we'll deal with the horizontal centering of the text like so with text line and make it so that our cursor changes to a point so we hover over these i these item divs in the items in the items container and we'll also make it so we can't actually highlight these this text here and you do that using a fairly new uh property called none and because we use post css on this this will automatically be rendered on the website it will use a vendor prefixes etc and lastly we want to set some transition for both the top property [Music] which have access to because of the position absolutes of these elements and we'll give it ease out and we'll also do the same for the left and these two properties will position we will offset the item div in question uh top with the vertical left obviously i was on to offset uh in addition to this what we'll need to do is it won't really come in useful at the moment because they haven't actually applied the selected property what's our attribute to any of these item elements uh however we will later on so if we have an item element an item div what i did with a class of a class name of item and as a selected attribute with value of yes so an example would be like this so yeah if we had a div like that which obviously we don't at the moment then what we would do is we will simply remove the transition we don't want the transition to be applied to this item oh it's this item and obviously well the last uh well we got two more really but we've got hamburger and center so what we'll do we will style the hamburger div like so and this will be position absolute and since its parent item is uh also position absolutely positioned in relation to its absolute container because remember it doesn't matter as long as long as its parent container is positioned or something other than static absolute will always be positioned in relation to that uh it will match its top left yeah sorry it matches top left edge it's top left edge for aligning with with with that top left edge of its container which is what i'm trying to say and i give 10 pixels all around widths will make it square of 70 pixels both in from both dimensions uh display will be flexed and the flex direction will go from top to bottom so column and then we'll say justify content [Music] space between so have the items starting at the top and then the last item in the flex container will end up what will be at the bottom of the flex container no matter what and then what we'll say we'll use a cedar element we'll use the before cedar element uh i'm also used after one as well because we will create two because currently although we created this a hamburger container here you know it doesn't actually have any representation on our web page and that's because we need to actually give give some children to it um to its uh to the containers the hamburger container and one way well we can do we can create two of those children just in plain css using these um pseudo elements and we need to say content to be nothing but both of them because we don't want any text for these uh pseudo elements what we will say though we'll make the background color to be a hex value and it'll be 80 uh three times this is just a darker shade of gray basically width 100 of its flex container heights and pixels and we'll actually copy the contents uh here and as well so because we want a third um at the moment this is all we have but we want another we want a third row in the middle and that will complete the hamburger which is the reason why we have the center div because because we've exhausted all of the pseudo elements both before and after so we need to do this one manually but it's not it's not a real problem because we've already got the properties that we need so paste them in like that and here we go here's a hamburger menu obviously we have five uh we have five item divs in total obviously you know it only looks like one because they're stacked on top of each other in the same place just the fact that we use absolute positioning so when i'll go on to our javascript file where we'll be spending the majority of this tutorial and we'll sort all of that out in here all right so the first thing that we will do is we will create a function called position items and we will call this immediately after we've declared it like so so that it gets called on a short document load and what we will do we will create a reference to all of the uh item divs and we'll do that using query selector or as is standard what is nowadays anyway maybe not back in the original version of javascript but it definitely is standard now uh for selecting multiple items and then obviously this will be a list this will be an array of dom elements so you can look through them we're using um using the 4-h method and then what we will do is we will works item dot style dot top so we will change the top offset and what we'll do actually we'll need a index um instead of using the index that's provided by the 4h method we'll just declare it ourselves uh because it will come in handy later on uh so yeah and then obviously we'll need to increment it we'll just increment at the end like so so it starts off at zero and then increments uh by one on each iteration of the loop and so we will offset it by 70 because remember because remember 70 is the height of the uh the item divs and we'll need to uh so yes obviously this will be initially this will be zero so it will just be zero so no offset basically ultimately and the second one i have an offset 70 so slightly below um and what we'll do oh yeah we need to add pixels on the ends of this as well to give it to give it uh some actual units so now if we save we go back as you can see just ignore the fact that they're not positioned correctly we'll sort that out later but yeah we are actually getting them as they are here but we do want some padding between them so add another plus and have a padding of 10 so we'll say index counter times 10 and so now yeah we get some padding between them again we'll solve this uh just shortly but another thing that we'll do is this is important for later on we will set an order attribute on each element and that will simply be the index counter plus one so that the very first one is instead of it being zero it'll be one and it will say one two and then you know it will go up by one each time starting at one uh so yeah that won't make any changes but if we look actually on these elements as you can see there is an order attribute so it's now time to solve or well you deal with the problem of that it's not actually centered and the reason being it's not it's not centered uh what is horizontally but not vertically and the reason being is because it's got a height the actual item the actual items there has got no height to it which is the reason why our uh body uh flexbox can't can't center it vertically because it doesn't know how high it is so we need to instantiate that height and so what we will do is we will get the number of items and this will be outside the method actually we'll just copy this but and then we'll say again we'll get the length of them that's how many do actually exist and then we'll say [Music] what we're doing and then we'll simply declare a reference to the items container div on its own and then we'll say we need to set its height so we'll do that like so and its height will be number of items times by times by the height of them so 70 and then money to plus the offset as well so we need to include we need to take it to cut the officer and finally we need to give it values to pixels and so now if you go back as you can see it's now centered both vertically and horizontally so there's a problem solved uh well that problem solved anyway okay so we'll now need to declare some global variables so mark them that someone mark what they are here uh the first one would be pos and this will be this will track the x and y coordinates of our of our cursor at all times uh on the page so we'll mark that here mouse mouse coordinates and what's it will also [Music] get the items la so instead of this we'll just use items only and we'll just declare it here because we will also be using that later on and we will declare a lot more of these global variables later on because this is quite a complicated effect and we need access to values uh in all sorts of functions and event listeners and stuff and we can't really do that with arguments so they do need to be globals unfortunately but anyway for now we will add an event listener to the window object which is the reason why we don't need to specify what it's actually applied to we can just write out about event listener like so and that will automatically get applied to the window object and we will very simply get access to the to the um the x and y offsets of our cursor that triggered the event listener from client x and client y respectively so let's start y equals e dot client y like so and then we can console.log pause to see our x and y coordinates every time we move the mouse obviously we need to log so yeah as you can see we are getting we are tracking our mouse movement like so that's very good unfortunately though we need to get our uh mouse pause we need to get it in relations to items only uh but you know you know this this items um container and this is because this is what the items are positioned uh in relation to and they're obviously precision absolute in relations their relative container and so to get to get our items be moved around we need to base our coordinates off of of off of the items early as well and so to do that it's very simple we simply get items la and then offset left for the x obviously and then as for the y that would be [Music] offset top and we'll also whilst the asset will also subtract word it like this just let me make things clear put these in parentheses and once i subtract um window.scroll wise take into account if we say we've got a really um short screen then we need to take into account the scroll as well so let's say because i'm putting it like this and we have a scroll bar we need to take into account how much we scrolled as well because obviously this is the top of the screen in this case but obviously it isn't the top of the screen in relation to items la which begins up here with the first items that's the reason why we include scroll why as well well now now that we have the event listener we need to we need to select all of the items so we can do that with crease actor alexa the items all of the item elements in the items container and again loop through them over for each and this time we'll get access to both the item and the index in our es6 hour function which you can use obviously because using babel so we don't have to worry about compatibility when we use these our functions and we'll add an event listener onto each item that we're leaping over the event will listen for a mouse down event uh so yeah that's what that's when this callback can be activated this one here um and also once the at it will also create a mouse up event listener as well and we'll say if parse.x hasn't been initialized say for example whoops if we haven't moved the mouse tour and this event callback has never been called then we'll return set the code below this uh never gets caught at all uh and what i need to do we now need to actually create more global variables we'll create mouse down which will determine whether our mouse is currently down uh is clicked down on a list item obviously it will be set to false by default because we can't really click anything on initial page load so we will say need to be true for logic in [Music] mouse move event listener to be activated and it does as well so what we'll go down to our event listener now and then below this line here we'll say if if it's false which it currently is at the moment then returns that none of the code below this will be activated if um if it is set to false and along with these um global variables we need to create some more as well so what we'll do we'll say let selected item equals null and this should be the item that we're currently clicked on so what we'll say allowed clicked on item to be tracked in mouse move event listener again we're declaring all these global variables now because it just makes more sense to us that we don't have to go back and forth and wanting to create uh diff as well and this will be a similar format to the past the only difference is that this allows us to actually drag around the items in relation to the spot that we actually clicked on again this will make more sense later on [Music] mouth and drag item on correct spot and along with selected item we need to declare a let reset transition again you won't be using this immediately but it's used to become more um clear later on [Music] and finally what's that see we'll be using this uh 400 milliseconds value which is what 400 means so 9.4 seconds we'll be using this multiple times an application so yeah that's all the global variables done and then i'll go back to our mouse down event listener and we'll add to this we'll say if reset transition is true and obviously it's up to false by default we also like because it's a cooldown period and we don't want this to be allowed to be activated uh so yeah the first thing that we'll do obviously if we can proceed as we'll set mouse down to retrieve because it now is because obviously our mouse is down which is what this event listener is all about and then we will initialize the item that we're currently mouse that currently that triggered this event listener we'll assign that to select items that we can access it in like the mouse move event listener etc and then what we'll do we'll initialize diff both of its uh y and x properties and it's obviously it's why property or we'll be we'll use puzzle y and it will minus item the you know obviously the item that triggered this event listener the offset top an offset top is basically just uh it's the difference between its uh its container obviously if it hasn't the element in question has no container then it will be the viewport the difference between its top edge and the top edge of its container and same thing for the left obviously just at four different axis so we'll do the same for the x property pause dot x minus i term dot offset left like so and then what we'll do we will then get access well then we'll then declare some local variables so offset y equals plus dot y minus diff.x and what this will do this will allow us to this is currently a difference between where we are and where the top edges of the element so what we're doing here is we are getting our um to getting where we are and we are minusing it by that amount and then with these offset values we will be able to um add them to oh you'll see in a second but let me just get this one done minus yeah so now you will become clear what we're actually doing and these are two variables uh offset y and up to x that's how we can declare multiple variables separate that with a comma like so so what we'll say will say item dot style dot top equals offset y uh plus pixels and then we'll do the same here [Music] for the other one um and then we'll also need to say we'll also need to set the yeah that should be left side yeah that makes more sense and then we also need to set the z index so that it appears above or element we'll set it to be a thousand uh and then we need to set its attributes this is very important now because we're now moving around the elements and we're moving it around but i'm based off of its top and left properties and so we need to set it selected to be yes so that this element that we're now dragging around won't have the animation applied to it which is the reason which is what all this was about oh yeah before i get ahead of myself i should also note that's a mistake there that should be a diff.y very important but yeah it at least take a point now if you click on these then nothing happens because of um [Music] because of the offset but i'll show you what happens if we don't use the offset and why it's important that we do so if you click on them now as you can see they get moved around to wherever our cursor is but they get moved around whoops yeah so i don't happen that they get moved around by the top left corner and we use the offsets so that they actually get moved around based on where we currently clicked on the item and because we haven't done anything on a mouse move that's the reason why when we click on them here nothing happens but they will happen very shortly uh in our mouse move event listener we're just getting the code that we need uh in here so basically in our mouse move we will copy this but instead of using the item obviously we don't have access to item anymore that's what i want you to do yeah we'll need to uh change this so it's because we don't have access to item anymore and so now if we test this out we should now be able to actually move stuff um again it won't we won't be able to release it but as you can see we are actually moving it when we move our mouse around and what we'll do in the mouse up we will simply set mouse down and then we'll set that back to false and so now when we release our mouse we should actually be able to leave it alone and now you know you can do all this stuff uh and move them around like that but yeah this is a basic gist of how how i get to items to around et cetera what i'll now do is because remember we on the item that we clicked on we gave it this um so not when we clicked on them but when we actually um position them all using this method here position items we gave them more a attribute of order we're going to extract this of the of the selected item now so we'll select order of selected item and we'll pass it to a number because we'll get it back because the get attribute method gets back its values as strings um and then we call it order so we get it back like that and then what we'll do we'll say we'll test for a new position and we'll say if order of selected item if it's not equal to one because if it is one then that means that it's this top item here which means that there's nothing above it ever so what we'll say is we will call the position items method again um no we want actually so i don't know what what we'll do is we will get access to let before item and before item will simply be the item uh that's before this one that's above it and obviously we know that it exists because it's not equal to one uh so what we'll say so document dot query selector like so and we'll use backticks because we can because uh i'm gonna have to worry about compatibility because the reason i already said because we're using babel and then we'll say order because remember the order attribute we're we're currently selecting by the order attribute here um which is the reason why we're not using crosstalk tool because we're only using we only want one and we'll put as found this in in uh quotes as well because we need to um order of selected let's copy it from here uh and then we'll say minus one so that we know that it's the one before and then we'll close off like so and then what we'll do we'll say we'll get a basically we'll get a boolean value before middle before middle will will be a billion value and we'll say pause dot y uh is less than before item dot offset top and we want the middle of this uh before item element so the way that we get that is we say before item dot client height divided by two so the offset tops the top edge plus half of its height and then that will give us the middle value so if our cursor is above the middle value because remember the closer that we get to the top of the viewport the lesser the value is the lesser the offset value is so that's how we know that it's above um the middle of the above element the item announce we can say if before middle if this building is set to true then your turns that nothing in this uh in this callback it is um it's met if this is made of this if condition but above this we will not only uh change the select selected item dot set actually because now it's now moved to a new position uh or will be the right it will be because we've clearly it's plenty of moved above so we'll need to change its order to be the order of selected item minus one because it's now been moved that's not minus one and then what we'll do we'll say position items order of selected item minus one and we don't have a way to take this in at the moment so we need to have a way to take it in here so we will say insert index as an argument and then what you equal that to know because you need to give it initial value because we didn't uh initialize the value here so we will get an error otherwise with what we're about to do um and what i'll say we'll say if uh well actually first of all what we need to do is we need to get access to uh we need to change the yes we need to change the items list that it filters out uh all of the selected all of the items with the select element i'll show you more about this in a second but first of all this is actually a a special type of array called a dom and we don't want this we want it just to be a normal array and the way that we can do this is we can use array.prototype.slice.core and i can't really explain this at the moment because it takes me it will take me too long but essentially this will turn if we pass items list here then this will return an array containing the values of this dom array so now items list will just be a normal array and this allows us to [Music] use the filter method on this uh now array and what we can do is we can filter out all of the elements that uh don't don't have to select attribute equal to yes so in other words are not the element that is currently selected that and that we're currently moving around to a mouse so get attribute selected if that is an equal to yes then return it so now um started one line just truncate it a bit so now items list will contain all of the elements other than the one that we're currently moving about of our mouse and yeah again remember because we did this here on the item that we're currently moving about with our mouse so what we'll now do is we'll say if the uh insert index is equal to index counter plus one so in other words because with plus one in here when we actually assign a value to these order attributes if we're currently on the element that uh that we have moved above because remember minus one we moved above this element and we we passed it in here yes this is the element that we are checking for and we currently moved above it let's define race billion here and now we pass the elements order in there so if that is the case then we'll say index counter plus plus and so now what this will do is it will mean that on this loop this index counts we plus which means that we have extra spacing as well as extra padding and so now if i show you what happens let me just show you move it up and as you can see again let me show you that again it's now actually working again it won't uh so yeah it's actually working now again we won't get the uh release or any release won't work if we release it won't go back into its correct position but we will get a situation where we can actually do this and we can move we can move them up um so now we need to do a situation where we can move them down so we'll do that very quick we'll say if order of selected item is not equal to um we'll say we'll get the what's it called again the number of items so if it's not equal to number item then we will get access to the then we know that it's basically not the bottom item and we can get access to the element that is below the item which we know there's an element below because it's not it's not a bottom item so it's either one of these items above in which case there will be a bottom item so we'll say instead of let before item say the after item and then this is plus one instead it's the one that's below the order of this one and then we'll say let after middle equal parts dot y greater than after i turn the offset top so if it's uh if it's below the middle of this and again we'll use the same method after they sign up not officer height client height divided by two so if it's below the middle of this and if this billion is true then we will again we'll do all this but instead of plus we'll do it with minus so now if we refresh as you can see we are getting a situation uh where this is happening however again if you release it's not going to work and also again this isn't going to work anymore if we just if we mess up to such a high degree so what we need to do is we need to create one more function uh chord position items in order and this will not only uh rebuild the list once everything's back to normal it'll also make the element go back to normal the one that we're hovering over when we release our mouse on it so what we need to do is um well first of all we will do what we did here and we'll get access to the items list as an array not not a special dom array which means that we don't have access to methods that are on array methods by default like the filter method so we'll just copy it from there and then we'll paste it here so items list uh we have access to that now and then what we'll do is we'll say items list equals items list dot sort so now we'll sort we'll sort through the order um the orders have done by default so that all the elements in this array start off with the first uh the very first one with that with the order attribute of one and then it ends the last item in the survey is the order actually of five because remember there's five list items in total so open it up like that and then we'll say return number a dot get attribute uh order so so let's get this what would be a string value is instead a number is passed as a number value because of what we did here so if this is greater than the number of b if it is uh we just turn it operator here then wartime one if it isn't then we'll turn minus one and doing this again you can look up the uh the sort method how it works four ways but this will order them based on the criteria that i just described and so now we will loop through this now ordered items list and again we'll get access to ite7 index like so and we'll say if item dot get attribute is selected and if that is equal to yes which uh so if we currently loop it i if the item that we're currently looping through is the one that we're currently hovering over then first of all we'll move that selected actually so we no longer have it because by this by the times if condition is over uh this will no longer be the selected item and i'll be back in its place uh and then we'll set the style dot left oh yeah and also moving this will mean that the transition gets applied to it again because remember it no longer has this so therefore transition starts to work which means that when we set the left back to zero it will transition back to its uh back to this value uh it will transition back to this and then what we'll do basically the transition time as set here is 400 milliseconds or 0.5 seconds same thing so what's that we'll set a timeout here [Music] and the timeout it will the code in in the callback record when the transition time is over and the transition time will be over as set here again 400 milliseconds exactly the same time and when this happens what we will do we'll set the z index back to zero so that it's no longer a thousand and that when we when we drag other elements they will be above this element which is now back into its correct place uh we're not at the moment yet sorry i bet it will be when we've completely finished with this function in question so that's all good as for the other items well we can literally just copy what we're going to do with them uh from here [Music] and we'll change the index counter with the actual index because we can just use that now and then what we'll say we'll say reset transition is equal equal to true because we're now going to rebuild the grid once this loop is over [Music] once all these are positioned back in the correct place um including including the element that we hovered over because remember we didn't use the filter here on items list anymore so it does actually pick up the element that we're hoving over unlike this top method here we'll set when reset transition is true are we set back to false when we when the transition is over because remember this gets activated immediately but we still have to wait 400 seconds before this element is back into its place and we'll set it back to false then uh so we'll say when transition is over and actually we'll copy this here just we'll use different code because the timing will be exactly the same and we'll say um what we'll do we'll get access oh we've already got access to actually but we'll say while items la dot first child so whilst that has a actual child element we will simply remove child so by the time this wild loop is over by the time this wildlife is over items only will have no more chart the children and then we'll do we'll loop through items list again yeah so we'll loop through that and then we'll say items la dot append which means uh add item as a child to items early after the items are already in items early so basically what we're doing here we're moving and then we adding the um re-adding the items elements but just in the ways that they're ordered uh so the other actually ordered now and then add it back and then finally we will set reset transition back to false so now this is set back to false so that we can mouse down my elements again and do all this stuff and finally so that this actually works we'll call this method here like so and this should be the end now hopefully so yeah we release as you can see this is this is what we this is the finished result um and if we're ready quick then we can't actually select the items to mess things up because transition hasn't hasn't completed yet but yeah this is the finished result uh if you got stuck at any point in this time then then look at the codepen project but if you still stuck after that then of course don't hesitate to um query me in the comments section below i'll be more than happy to answer any of your questions but more importantly guys peace out i hope you enjoyed this video and have a great day peace out guys
Info
Channel: Qixotl LFC
Views: 239
Rating: 5 out of 5
Keywords: qixotl_lfc, Qixotl, LFC, animated drag and drop javascript tutorial, drag and drop with animations, dynamic drag and drop list in javascript, how to create an animated drag and drop list with transitions, html css javascript, java, css, dynamic animated drag and drop list transition animation tutorial, animated drag & drop in javascript html css, dynamic drag and drop list javascript
Id: PJYFQYyzRgg
Channel Id: undefined
Length: 45min 35sec (2735 seconds)
Published: Mon Aug 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.