09. April 2019

Bringing Sanity To Your Git Flow

Git is a great tool which enables teams to work together and deploy code, but it's not all happiness and ponies. What if you need to deploy a single hotfix into your prod build, without pushing in any more of the code that has been written since your last depoy? How can you roll back to an older version of your code? What if you want to deploy all the changes that exist in staging to production but the environments are so far apart at this point merging code is scary. With the right git flow this is a breeze, but with the wrong git flow this can be a nightmare, or my life for the past couple years.

In this post I will assume that you at least have a basic understanding of how git works, if not you can get a quick git tutorial.

A very slimmed down and common issue we used to run into is, we have our main development branch and a staging branch that updates the site our client can see. We are doing all our work in master and then every so often make merges into staging with all the changes so the client can see the updates. Then inevitably someone makes a minor hotfix change into staging so now master and staging have different code in them. Now we're ready to deploy all staging code to live, so now we need to pull our staging code into our production branch. But now what happens to that staging hotfix that happened, that's now gone in master and you're going to lose it your next deploy unless you cherry pick that back in. A visual representation of what you've made is this.

git tree
Because all the merges as this scales your git tree just continually gets messier.

A simple tool you can use to follow along or learn more of how git works, and what I've used to generate these git screenshots is here https://git-school.github.io/visualizing-git

We don't need to get too into the weeds about all the weird things and issues you can run into with git, I'm sure you've encountered them before. We at Code Koalas have moved all of our ongoing projects to follow the flow of, master branch, feature branches off a master, rebase your branch before merging and releases for staging and production are tags on master. It's as simple as that!

Here is the step by step process of the normal git flow you'd follow for everyday use.

  1. Pull down latest code on master
  2. Check out your new branch
    1. We follow a format where branch names should include the ticket number in them. CK-204
  3. Do all your work.
  4. Git add your code with a good commit message also including the ticket number
    1. CK-204: added new feature
  5. Check out master branch and pull latest code
  6. Go back to your branch and rebase it off latest master
    1. git rebase -i master
  7. Push up your code
  8. Make a merge request into master squashing commits if it is really just one feature change and closing out your branch on merge acceptance

Another git tree
You will notice here it’s mostly just one line with a lot less back and forth.

This flow helps your merge request from having phantom line adds or extra code you don't need. Also rebasing it means you will resolve all the conflicts locally before you push it up.

Great now you're ready to deploy this code to your staging environment, all you do is either create a tag based off master locally or in your remove git software (gitlab, github or whatever) and call it RC-v1.0.0 or whatever your version number is. We then have pipelines that build based off tags and if rc-* it will build and deploy to staging.

another git tree
Here you see the tag RC-v1.0.0 which is “live” on staging while the code keeps moving.

Deploying to production is the same as for staging. If everything in master needs to go live great, create a tag but this time call it release-v1.0.0 and same as before it auto deploys. If you only need a couple changes based off the last release or rc you will follow our hot fix flow which takes a previous tag and add just the commits you actually want.

  1. Create a branch off the tag you want to base this new tag off of.
    1. If it's a hot fix grab the last full release then we will just add the few extra lines needed. 
  2. You then pull in the code you need into that branch
    1. You could make a hotfix based off that branch and merge it in, then rebase it off master and merge it to master.
    2. You could cherry pick in just all the new commits that have happened into master and add those in. That's the good part about putting ticket numbers in your commit messages.
  3. Then create your new tag based off this branch.
    1. If it's a hotfix we do the same release tag we based it off of but add -hotfix-1
  4. That code will deploy based off the pipeline and tags.

another git tree
Here we have taken in the RC tag, added a hotfix then deployed that live.

That's really it, it's really simple but has made deploying code to prod no longer scary. It's cleaned up the difference between environments so getting your code into staging then into production isn't painful. Most importantly for us it's allowed us to have multiple features being built at the same time and putting one on pause and being able to deploy one of those features and not the other.

05. March 2019

Integrating The Color Module Into Your Drupal 8 Theme

Letting your user change the color of the theme can be a hassle, or downright scary. The color module built into Drupal 8 core allows administrators to change the color scheme of compatible themes. We are going to walk through the few steps that are required to get your custom theme up and running with the color module.

Possible Use Cases

  • Creating a theme that needs to work for multiple sites with different color schemes.
  • Creating a theme to contribute or resell.

What You Need

  • A Custom Theme
  • Install the Color Module (included in core)

Setting up your Theme

Once you have created your theme you will need to create the directory color and create at least one file named color.inc. There are more files that can be put here to make the preview for the admins better but they are not essential for this tutorial.

You will also need a CSS file with all of your color things that you are letting the admins control with Drupal.

Your directory structure should look like the following example. Where your CSS file is and what it is named isn’t a requirement of the Color Module, but you do need to properly link to them.

custom_theme
| -- custom_theme.info.yml
| -- custom_theme.libraries.yml
| -- color
|    |-- color.inc
| -- dist
|    |-- css
|        |-- color.css

The custom_theme.info.yml is a requirement of every theme, and the only thing worth mentioning here is that it must have a library that it is using so you can pull in your CSS changes. It should look like the following. I am sub-theming Bartik just for this sample, as it looks decent as a base to not have to write any extra HTML or CSS for this tutorial, and is not required.

name: Custom Theme
type: theme
description: Custom Theme to show color module
package: Other
core: 8.x
base theme: bartik
libraries:
- custom_theme/color

The custom_theme.libraries.yml is needed to give the path to your CSS that the Color Module will be using. It should look like the following:

color:
  css:
    theme:
      dist/css/color.css: {}

The color.inc is the file that is doing all of the work, a minimum file would be like the following:

$info = [
  // Available colors and color labels used in theme.
  'fields' =--> [
    'primary' => t('Primary Color'),
    'secondary' => t('Secondary Color'),
    'text' => t('Text Color'),
    'background' => t('Background Color')
  ],
  // Pre-defined color schemes.
  'schemes' => [
    'default' => [
      'title' => t('Default'),
      'colors' => [
        'primary' => '#3f51b5',
        'secondary' => '#536dfe',
        'text' => '#3b3b3b',
        'background' => '#ffffff'
      ],
    ],
    'red' => [
      'title' => t('Red'),
      'colors' => [
        'primary' => '#f44336',
        'secondary' => '#ffcdd2',
        'text' => '#600000',
        'background' => '#ffffff'
      ]
    ]
  ]
];

// CSS files (excluding @import) to rewrite with new color scheme.
$info['css'] = ['dist/css/color.css'];

Once that file is there you can clear your site’s cache and go to the theme settings for your site /admin/appearance/settings/custom_theme and you will see the color form. The form should have all of the fields you defined and show a color wheel allowing people to pick whatever color they’d like for the form.

Admin form in D8
The admin settings form for our custom theme

Now admins can choose whatever colors they want, or from one of your pre-created schemes. If you change those and view the site, you will see that has happened yet. The next step needed is to create the CSS that Drupal will actually be using to color the site with the values entered in the admin form.

Setting Up Your CSS

There are, in my opinion, two approaches to how you could setup your CSS file to color your site.

  1. Create color classes that you apply to your HTML as needed that color things
    .primary_color {
      color: #3f51b5;
    }
    
    .primary_color_bg {
      background-color: #3f51b5
    }
    
    
  2. Take all of the selectors that need colors and move those into your CSS file.
    #header {
      background-color: #3ft1b5;
    }
    

I personally think the first approach is much cleaner and will save you time and headaches, but in this example I’m doing the second approach for simplicity. Below is what our dist/css/color.css file looks like.

#header {
  background-image: none;
  background-color: #3f51b5;
}

h1 {
  color: #536dfe;
}

body {
  color: #3b3b3b;
  background-color: #ffffff;
}

#page {
  background-color: #ffffff;
}

Something very important that you should take note of is how colors in your CSS map to the colors in the admin form. In Drupal 8 we are grabbing the HEX defined as the default in your color.inc and replacing that with the new value saved in the config form. In our default scheme, primary color is set to #3f51b5 so in our color.css file anywhere that hex exists, it will get overridden to be the new primary color set in the admin interface.

Results

Now that everything is setup, we are good to go to the admin interface again and change the color scheme. Once changed to the red scheme, if we reload the home page this is what it looks like:

website with red theme
Our Bartik based site with the Red color scheme

We can also head back into the theme settings and choose completely custom colors, disregarding predefined color schemes.

Admin settings with color wheel
The color settings as set using the color wheel

Once we save that and head back to the homepage, we’re greeted by this very ugly site.

our website but green

This obviously isn’t the ideal situation, and you should be able to create much better looking sites if you contact a designer to create your color schemes and consider what elements should allow color changes.

Quirks you might run into

  • If you added keys in the color.inc but you don’t see them in the theme settings form even after a cache clear you must clear out the color.theme.custom_theme config. You can do that with a drush command drush cdel color.theme.custom_theme
  • This seems weird, but for me I had to make my HEX values in both my color.inc and my color.css lowercase or they didn’t get overridden.

Conclusion

The Color Module just works, is simple to set up, and is a great tool to know how to use. At Code Koalas we have used it on a multiple sites for clients and will continue to use it when it is appropriate for the project.

02. June 2018

31. May 2018

Setting Up XDebug

Using Xdebug makes it feel like anything else is coding while blind pressing keys with a long stick. It's absolutely needed to build out things in PHP when you don't know exactly how everything is working. So getting it working in our setup is very important. Currently this guide will only explain how to get Xdebug working in PHPStorm with our docker setup. Hopefully from there you can figure out how to get it to work in other editors or other projects and when you do, please add it.

Turning on Xdebug in your docker container

To get it turned on in your docker container you just need to modify your docker-compose yaml file. In our Drupal projects the lines you need are already there, you just need to comment them back in. Your compose.yaml should look like the one we have in GitHub. In the file you'll see the following lines:

...
#LOCAL: "true"
...
...
extra_hosts:
# - "xdebug:192.168.237.237"

Those both need to be commented back in. The local true means xdebug gets enabled and configured when the container is booted up. The extra hosts lets the container and your computer talk to eachother over that IP as that's what xdebug needs to work.

Once you have done that you're good to boot up your container, once it's booted you have step 1 of getting xdebug done.

Adding Loopback

Now we need to add the loopback, so your computer and your container can talk to eachother. If you ran Kerry's setupdev.sh you should already have this but I'll outline what to do again so you have it.

Mac

Get the docker-compose repo downloaded locally if you don't have it already.

Once you have that go to that directory in terminal and type ./addloopback.sh that will output some things into your terminal so you know it works.

That's it.

Linux

On Linux we currently don't have an awesome bash script, and this you have to run everytime your network changes, but hopefully I can make this awesome and stay forever like the Mac one but for now you can run

sudo ip addr add 192.168.237.237/24 brd + dev wlp4s0 label wlp4s0:1

You will have to change wlp4s0 to be your network devices name, and you can change the IP address to be anything, but it just needs to match the IP in your compose.yaml file.

Configuring PHPStorm

As of PHPStorm 2017.x getting PHPStorm working with xdebug & docker is a lot easier. If you are on an old version you should update first before continuing.

Configuring Docker

Here is jetbrains info on how to do this but it's actually long and has a lot of old things you might not want or need. As of September 2017 what is below does work but if you run into issues please refer to jetbrains docs and update these to reflect the changes.

  1. Open the settings pane in PHPStorm (Control+Alt+S) or (Command+Alt+S) or File > Settings.
  2. Search for Docker (or find docker under the "Build, Execution, Deployment" section)
  3. Click the green plus to add a docker setup
    • If you get to this step and you already have a docker there continue to the 6th step
  4. You can name this configuration "Docker" or whatever, and tell it to connect with the Unix Socker or Docker for Mac depending on your system
  5. Click apply and ok.
  6. You should now have a Docker icon somewhere in the bottom left of your screen, maybe hidden behind a menu icon. Click that.
  7. That will have opened a pane just saying Docker, double click that docker icon.
  8. If after clicking it it says connected and shows that docker containers are currently running you have succeeded. If not please scream and run around and ask for help.
Configuring this project
  1. Now we need to configure Xdebug for this current project you have open in PHPStorm. To do this you will click a dropdown arrow on the top right of the window to the left of a green bug and play button.
  2. Form there you click the "edit configurations" option
  3. You will then click the green + on this pane and click the option "PHP Web Application" (for me I have to scroll to see that)
  4. This should get you a screen that looks like this:
  5. Click the ... next to the Server select list
  6. This will bring up a new pan to configure the server (docker container)
  7. From here you will name the server whatever (the name of the project)
  8. Your host will be whatever url you go to to access the site (mycoolsite.dev)
  9. Next you will want to use path mappings, so click that checkbox which will reveal new things on the pane.
  10. Next you will configure your path mappings.
    • On the left side of the pane will show your local file system of this project. The right column is your server's file system.
    • You will just take whatever is on the right and prepend /var/www/site to it.
    • The general rule is to map docroot and every directory you will be working out of.
  11. Click apply & ok.
  12. Go ahead and name you confiuration the name of your project as well.
  13. Click apply & ok.

Triggering it with PHPStorm

Now to actually use xdebug you will go any php file and to the left of the line and to the right of the number click and you will see a red circle appear, that's a breakpoint. A breakpoint is a spot that then the code is executing will stop at that point and show you everything that's happening. One trick is you can only place breakpoints in lines of actual code that will be executed, not just randomly at a spot in a file.

Once you have your breakpoints you want to see what is happening at, go ahead and click the green bug in the top right bar of the program. Clicking that will open a new page on PHPStorm and open your app in a browser window.

On that page it opens in the console, but that's probably not what you want, you'll want to go and click on the Debugger tab. If you're super lucky and your code executed already it's possible when you go to that tab you already see xdebug things!

If you didn't it's likely that your code doesn't run on the home page, that's fine just go to that page, but leave the ?XDEBUG_SESSION_START=XXXXXXX in the URL. If that still doesn't work then you most likely have to clear the cache.

If after that, it still doesn't work ask Josh.

:wq

15. August 2017

Using Docker for Local Drupal Development

docker-drupal-hero-image

This is also posted on Code Koalas's site.

Using Docker is great, it makes sure that every developer working on the project is using the same server and if it works on your machine it really should work on everyone's. It's also great because once you have it set up you can spin up aditional sites in a matter of seconds instead of trying to manage a local web server on your computer yourself. This blog should get you off the ground and get your first Drupal site spun up so you can get right into working on your site.

Prerequisites

  1. Have docker for installed for you computer. For Windows, for Mac, for Linux you know what to do.
  2. Install Docker Compose, for Mac & Windows will get it already installed with the bundles linked above, for linux you'll need to install it yourself.
  3. At Code Koalas we have a git repo for our docker compose templates, you don't need to pull in the whole thing but you can pull in the couple yaml files you need.
  4. Make sure you have no other servers running on port 80 or our docker containers won't run. If running Mac, it by default runs an Apache server sometimes, because why not. You can stop it like this: sudo apachectl stop.

Setting up local dev environment

The first thing we do is spin up a small container that's an nginx proxy. It will manage all the local network requests to docker and point them to the proper container. In the repo linked above, the yaml file we need for that is devenv.yaml The file is this:

version: '2'
services:
  nginx-proxy:
    image: codekoalas/nginx-proxy
    container_name: nginx-proxy
    ports:
    - "80:80"
    - "443:443"
    volumes:
    - /var/run/docker.sock:/tmp/docker.sock
    networks:
    - dockercompose
    restart: always
networks:
  dockercompose:
    driver: bridge

You'll want to save that file somewhere on your system where you can access it later, this is why personally I have that whole docker-compose repo in my ~/Code directory on my computer. To spin up this repo you run the following command docker-compose -f /path/to/file/devenv.yaml up -d. That's telling docker compose to up a file in daemon mode and using a file. It will output some things and the first time ran will have to download some container images.

Getting your Drupal install ready

To get your Drupal site ready to spin up, all you need is a simple Drupal 8 codebase downloaded, but you need the D8 install not in the root of your repo but in a sub-directory like docroot. We use a slight variant of the Drupal Composer - Drupal Project which lets you manage all of your contrib modules & themes and D8 itself using composer instead of clogging your own repo with other people's code. Code Koalas' version of the composer Drupal project adds a couple of extra modules and maps the drupal install to docroot instead of web but you can use either or neither. Your local directory just needs to look like the following:

drupal 8 install directory

It doesn't need everything I have in mine, but you will have your website's git repo, and inside of that will be the directory docroot which contains a full D8 install.

Setting up the docker-compose file

You'll see in my site I have a compose.yaml, that's the next step we will take one of our templates we have in our docker-compose repo and use it in our site.

Our D8 docker-compose file is drupal8blank.yaml

version: '2'
services:
  d8blank-mysql:
    container_name: d8blank-mysql
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: drupal
      MYSQL_USER: mysql
      MYSQL_PASSWORD: mysql
    volumes:
      - ~/Sites/sites-databases/d8blank:/var/lib/mysql
    networks:
      - dockercompose
    command: mysqld --max_allowed_packet=64M
    restart: always
  d8blank:
    container_name: d8blank
    image: codekoalas/drupal8
    environment:
      VIRTUAL_HOST: .d8blank.dev
      GIT_REPO: https://github.com/CodeKoalas/drupal-project.git
      GIT_BRANCH: master
      MYSQL_SERVER: mysql
      MYSQL_DATABASE: drupal
      MYSQL_USER: mysql
      MYSQL_PASSWORD: mysql
      DRUPAL_BASE_URL: http://d8blank.dev
      DRUPAL_TRUSTED_HOSTS: d8blank\.dev$$
      DRUPAL_HTTPS: "off"
      APACHE_DOCROOT: /var/www/site/docroot
      PRODUCTION: "false"
      LOCAL: "true"
    volumes:
      - ~/Sites/sites-files/d8blank:/mnt/sites-files
      - ~/Sites/d8blank:/var/www/site
    networks:
      - dockercompose
    extra_hosts:
      - "xdebug:192.168.237.237"
    links:
      - d8blank-mysql:mysql
    restart: always
networks:
  dockercompose:
    external:
      name: dockercompose_dockercompose

You'll need to take all the references to d8blank and change them to the name of your repo's directory. So instead of on line 3 it saying d8blank-mysql change it to mycoolsite-mysql and do that throughout the whole file. You'll also want to change the GIT_REPO to point to the http download of your git repo, if you don't have this in a git repo you can skip this and it will be okay.

Now, if this is a brand new site you can skip to the next section, but if you have an existing database we have a simple way to get that in. You will need to export that database and save the name as starter.sql, place that in the root of your project. Our Docker container looks for a starter.sql in the root of the repo and imports it, if there is not database loaded in mysql.

Spin up the site

Now your file system is all set up and ready to go, all we need to do now is in terminal go to the directory of your project and run docker-compose -f compose.yaml up -d this will output its starting containers. Though in the command prompt it will say it's done, it does actually take the containers themselves a minute or two to work on first boot.

Access your site locally

Our setup is built for you to access your sites on nameofcontainer.dev so in our example it'd be mycoolsite.dev. You can have many sites up at once and it will work just fine. The only issue is getting your computer to match that domain to your local computer. A simple way is to edit your host file for that single domain. The cool way on Mac is using dnsmasq to point all .dev to localhost, I'm sure you can find similar things for Windows, and the same tutorial I believe mostly works on Linux. If that's too much trouble you can edit your host file by typing the following into Terminal sudo vim /etc/hosts then adding this to the bottom of that file 127.0.0.1 mycoolsite.dev.

Things to know

When using a Docker setup you now have a layer between you and your code, it's just like the code running on your remote servers, which means command line tools are a little harder. Luckily you can just log into the container and run your command. To log into the container use the following command docker exec -ti nameofcontainer /bin/bash then you're in the root of your project on that server. From there you have drupal console, drush, composer, git and other normal command line tools. If that command is too much to remember or type you can add this to your .profile locally.


dlogin() {
  docker exec -ti $1 /bin/bash
}

With that locally you type dlogin nameofcontainer and you're in, which is what most people in the office here use.

When you're done working on your site and want to turn it off, go to the root of the project and run docker-compose -f compose.yaml down and that will turn off the servers. You can always spin it right back up whenever you'd like to get your site back.

Conclusion

Working with Docker is great. Since we've switched to it exclusively for Drupal projects, we can spin new people up on projects in a matter of a minute or two instead of 15 minutes for them to figure out local servers themselves. It also has decreased the quantity of bugs due to varying versions of php or server setup. We now run the same servers local, dev, staging and production and it's easy for any team member to help another dev on their project as they're all the same setup. I hope this is useful and if you run into issues following this tutorial let me know on twitter @joshfabean.

03. August 2017

Drunken JavaScript

This is also posted on Code Koalas's site.

Here in The Crossroads of Kansas City on the first Friday of every month people open their offices and art galleries to show off new art and have a party. It's called First Fridays. Not the most creative name, but at Code Koalas we wanted to do something a little more than just show off art and offer drinks and snacks. Since we're a development company, we figured we should teach people to code. I was the one tasked with figuring out what that would look like and ultimately the one teaching this class every month.

I ended up deciding to teach people JavaScript, but specifically using Canvas to make a ball bounce around the screen. I've already written the blog on the JavaScript teaching I give every First Friday, and I've taught Canvas at Texas Camp. This blog isn't a tutorial for how to write JavaScript, but more about what I've learned and experienced through teaching JavaScript to many people over the year, many of which were quite drunk.

Oh, the people you'll meet

Every First Friday I end up teaching 4-5 40-60 minute classes. Each one has around 5-7 people in it, and I've done it for at least a year. I've taught kids who were 6, and adults in their 40s who have no coding experience. I've also taught people who are JavaScript developers but don't know Canvas, so they still get something out of the class. I've also had people who have had too much to drink and sort of forgot how to type or even use a computer.

Common Errors

After all of the classes I've noticed some patterns of the issues that people seem to have. Not everyone has issues - a lot of people get it right on the first try - but when people get it wrong it's normally the same couple of things every time.

Spelling

Most people, I think even developers, just spell things wrong all the time or make typos. Most the time when someone says something doesn't work the answer is "background" isn't spelled "backgound", or something similar. Camel casing variables are also weird and hard for new people. They don't seem to understand that drawrect,DrawRect,drawRect, and drAwREct aren't actually the same thing. I always explain to people that spelling and capitalization are important, but this is still always where there are issues.

Putting Code in the wrong spot

People putting code in the wrong spot is one I knew would be an issue but it still surprises me how much of an issue is. I explain where we're putting code, including what function and around what line number that should be, but every time someone does it wrong. The best is when someone puts half of the code in one function then the other half in another, I haven't understood the thinking of that one yet. This seems to me to probably be because there's a lot going on and people don't understand how it all works together so don't understand why one line goes one place versus another.

Syntax errors

Syntax errors are almost a daily thing for me at work, whether me just making a mistake by deleting a closing tag on accident or me guessing how code should work so it's not surprising I see this a lot too. This sort of goes with putting code in the wrong spot, sometimes people will write if statements like this:

if (ball.x > c.width {
  ball.speedX = -ball.speedX;
})

If statements seem to be the hardest thing for people as far as syntax errors. Also in objects forgetting to put commas like so:

let ball = {
  color: 'white',
  x: 0
  y: 0
  radius: 10
}

Most of the time I see at least one comma, then they just leave the rest off. The biggest thing, when I actually watch people, is the editor's auto closing tags confuse people. When someone starts an object and they put { and the editor automatically puts } most of the time I see people delete it. Then their object is the whole function and the function never closes. I think for learning using something like notepad might actually be best since the hand holding IDEs do seem to confuse people.

What I've learned

From teaching all of these people, what I've learned the most is to have fun and be patient. People screwing up badly is often funny and perplexing, and it takes a lot of patience to teach a drunk person JavaScript...seriously, go try it! People like to learn new things - I figured this out shortly after graduating. I didn't like school but loved learning new challenging things. I've also learned programming isn't really that hard, and in teaching it I think I have made technology more approachable for people. Knowing how things go together and work is equal parts empowering and terrifying.

Teaching the classes on First Fridays at Code Koalas has been a lot of fun and a great choice. I've learned and grown a lot as a developer, leader and human in doing it - and maybe even am making the world a better place. If you have the chance you should give back and teach a kid or an adult how to do something you're passionate about.

11. July 2017

I Can't Even Canvas, But Now You Can!

This is also posted on Code Koalas's site.

If you're anything like me a couple years ago, you probably have avoided doing animations in Canvas because it's crazy complicated and you're just a person who can make websites, not a real programmer who can make games and things. But here's the thing: you're wrong. Making animations and games in Canvas is very easy and fun, I'd argue it's easier than writing JavaScript for sites. If you can make a mobile menu, a carousel, or even just an alert() you can make a small animation in Canvas. I've taught this to children and very drunk people who know nothing about coding at Code Koalas First Friday events we host.

First off, what are we building?

You will be building a ball bouncing around the screen, just like the old DVD screen saver. If you have no coding experience this will take about 30 minutes, if you have used JavaScript or other languages before you can probably tackle this in 15 minutes or less.

See the Pen Learning Canvas Teaching 2017 by Josh Fabean (@fabean) on CodePen.

Getting Started

I have created a starter pen with all boilerplate code required to get started. It has lots of comments explaining what everything is if you're not familiar with coding at all.

See the Pen Learning Canvas Teaching 2017 Starter by Josh Fabean (@fabean) on CodePen.

From here if you aren't familiar with programming or JavaScript you'll continue reading as normal and head to the Quick JavaScript Brush up section, but if you think you're good enough to just jump straight into the Time to Code section, go for it.

Quick JavaScript Brush up

As you probably noticed that starter Pen I gave you comes with a lot of code already. At the time of publishing this it's 49 lines of JavaScript and 1 line of HTML. Don't worry, it will all make sense soon enough - or not, but it's okay! You'll still be able to make a ball bounce over the screen even if you don't totally understand how it works.

HTML

(HyperText Markup Language) is the most basic building block of the Web. It describes and defines the content of a webpage.

-- MDN's definition

HTML is in every website you go to everyday. It's what defines what is a big header, a navigation link, an image or a paragraph. It's the backbone of websites. Since it's a markup language and not a programming language it's pretty easy to wrap your head around the basic concepts of this and it's not super important for what we're working on here.

In the starter code you have you'll see you only have one HTML tag.

<canvas id="canvas"></canvas>

What you have there is a HTML tag of canvas with an id of canvas. The canvas element was added in HTML5 in late 2014 and can be used to draw graphics, you can learn more about canvas on MDN

JavaScript

JavaScript is a cross-platform, object-oriented scripting language. It is a small and lightweight language. Inside a host environment (for example, a web browser), JavaScript can be connected to the objects of its environment to provide programmatic control over them.

--MDN's definition<

Variables

Anytime you want to use the same bit of information multiple times through your program, you'll use a variable. In JavaScript variables are defined with let, var, or const. In our code you'll see right at the top the following lines:

let c;
let ctx;
const fps = 60;

The first two lines we're declaring variables named c and ctx but we're not setting their value to anything. On the third line we are using const to define fps to 60 for 60 frames per second. We're using cost instead of let because this is a constant meaning - we're not ever going to change that value.

Functions

Just like variables are anytime you want to access the same bit of information multiple times, functions are anytime you want to run the same couple lines of code multiple times. Functions are sort of like paragraphs, they contain a lot of different words and sentences but generally do a single cohesive thing when put together.

In JavaScript you create functions with the following syntax

let functionName = (variablesPassedIn) => {
 // code you want to run
}

You can see it's similar to how we define a variable starting with let and the variable/function name. But then we add () => to make it a function and {} wraps all the code that belongs to that function.

In our code we first define the following function:

// if you want to draw lots of circles you'll use this function
let drawCircle = (circle) => {
  ctx.fillStyle = circle.color; // set the color
  ctx.beginPath(); // telling canvas we're about to define a path.
  ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2, true);
  // x&y coordinates, the size, ..?, pi*2 for radius, true? defines we are drawing a cirlce. You can draw all sorts of curves with .arc
  ctx.fill(); // fill defines it's colored in, instead of just an outline or something like that.
}

This function is important to know because it shows what Canvas actually needs to render circles onto the page. In the function drawCircle we first pass in the object of circle. The circle object will need to look like the following:

let myCoolCircle = {
  color: '#FFF',
  x: 100,
  y: 100,
  radius: 20,
};

The circle object has 4 properties we care about for drawing on that screen, color, x, y, and radius. We pass those into the drawCircle function and then that function draws it. The first line of the function is ctx.fillStyle = circle.color which tells the ctx we created earlier in the code that we are setting the current fillStyle to be the color of the circle object, in this example thats #FFF or white. The next line is ctx.beginPath() which simply tells ctx we will be drawing a path which you can learn more about .beginPath on MDN like always. With beginPath you can draw any type of path including a straight line or in our case a circle. The following line ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2, true); tells canvas what we're doing with that path we just started, learn about .arc on MDN. That line says where to start drawing with the circle.x and circle.y then defines how large of a circle we're drawing with the circle.radius. The next parts are the start angle of 0 then the end angle of Math.PI*2.

If Statements

The if statement executes a statement if a specified condition is true. If the condition is false, another statement can be executed.

-- MDN's definition

If statements are one of the main building blocks of programming. This is what allows programs to respond to situations and "think". They're very simple: if something is true we do one thing, if it's not true we do another. The syntax for an if statement is as follows:

if (your condition goes here) {
 // run code on true
}
else {
 // run code on false
}

Inside the () is where we put our conditional statement. A very simple example would be (1 > 2) which of course would be false and run the else, or we can do (1 < 2) which would be true and run the code in the if. We can also have or or and statements in our conditions. A condition with an or looks like (1 > 2 || 3 < 4) that would return true since one of those statements are true even though one is false. A condition with an and looks like (1 < 2 && 4 < 5) that would also return true since both conditions are true.

Time to Code!

Draw the background

The first thing we need to do is draw our background. With canvas each frame you draw over what already existed so if we don't redraw that background every frame over time we'll have a line instead of a ball. We will create our background inside of our render function, it will look like the following:

let background = {
  color: '#000',
  x: 0,
  y: 0,
  width: c.width,
  height: c.height
};

All rectangles have a color, x & y starting coordinates, width & height of the rectangle. A few things worth noting: on canvas x & y start on the top left of your element so 0,0 is the top left of the screen. That height & width we're pulling off of previous code used to set the canvas element to the full width & height of the screen.

Once you have that background defined we just now need to tell our program to draw it on the page by putting the following below it.

drawRect(background);

If everything was done correctly you should now have a black background on your screen (you can replace that color with any HEX value or most color names instead of black if you'd like, you can find a full list of colors available on MDN) and it should look like the following:

See the Pen Learning Canvas Teaching 2017: Background Done by Josh Fabean (@fabean) on CodePen.

Draw the circle

Drawing the circle is very similar to the background, but this time it's a circle instead of a rectangle so we change just a few things. Also since we will be wanting to move this circle we need it's values always available. This means we will need to define ball up on the top of our file next to where c & ctx are defined. It should look like the following:

let ball = {
  color: '#FFF',
  x: 20,
  y: 20,
  radius: 10
}

That's very similar to the rectangle with a couple of difference. We use radius to describe circles instead of height & width, and in Canvas they draw circles from the center so we didn't want to start x & y at 0 or it'd be mostly off screen.

But that doesn't do anything yet, we now need to tell Canvas to render that object onto the page. To do that go down to the render function right below where you put the drawRect(background) and add the line drawCircle(ball). If done right you should get a white ball. If everything worked right you'll have the following:

See the Pen
Learning Canvas Teaching 2017: Circle Done
by Josh Fabean (@fabean)
on CodePen.

Move the circle

Now that you have a circle, making it move is just a couple more lines of code. The first thing I do is update the ball object on the top of the file to define the speed at which we will move it both on the x & y values. To do that your object will now look like this:

let ball = {
  color: '#FFF',
  x: 20,
  y: 20,
  radius: 10,
  speedX: 10,
  speedY: 4
}

You'll notice we just added two lines. Those two lines are speedX & speedY the letters Y & X being capitalized is called camel case and is how people write things in JavaScript to be readable. You can set your values to something else if you'd like, but we are defining how many pixels the ball will move per frame so if you go much higher than 10 it will fly across the screen really fast.

Now that you have defined how it should move, we need to actually make it move. The logic for this will go in our render function. What we'll tell it to do is every frame take what the X & Y values are, and add the speed to them. It will look like the following:

ball.x = ball.x + ball.speedX;
ball.y = ball.y + ball.speedY;

drawCircle(ball);

Now your ball should start moving and eventually fly off the screen like the following: (Very likely it's been off the screen for a long time in this example)

See the Pen
Learning Canvas Teaching 2017: Circle Moves
by Josh Fabean (@fabean)
on CodePen.

Make the circle bounce

Fix flying off right side of screen

Great! The ball moves, but now it disappears because we aren't yet stopping it from flying off of the screen. We will handle this by adding checks before we move the ball to see if it's at a wall, if it is we will reverse the direction it's going. In my example it flies of off the right side of the screen first. To fix that it will look like the following:

if (ball.x > c.width) {
  ball.speedX = - ball.speedX;
}

That will if ball.x is greater than c.width the canvas's width take the ball.speedX value of 10 and make it -10 which reverses it to the left. In action it looks like this:

See the Pen
Learning Canvas Teaching 2017: Bounce Right Side
by Josh Fabean (@fabean)
on CodePen.

Fix flying off bottom of screen

Now it falls off of the bottom of the screen, so how do we fix that? (It might not fall off the bottom based on your values and screen size and dimensions but for me it's the bottom next). We can do almost the same thing as before but this time on the y value of our ball.

if (ball.y > c.height) {
  ball.speedY = - ball.speedY;
}

Now when it hits the bottom it bounces back up like this:

See the Pen
Learning Canvas Teaching 2017: Bounce Bottom
by Josh Fabean (@fabean)
on CodePen.

Finally get it bouncing off all sides of the screen

Now we run into the issue where the same thing happens but for the left & top. We can just modify our already existing if statements to allow them to also check the left & top sides like this:

if (ball.x > c.width || ball.x < 0) {
  ball.speedX = - ball.speedX;
}
if (ball.y > c.height || ball.y < 0) {
  ball.speedY = - ball.speedY;
}

The || means OR so now our statement says, if ball.x is greater than c.width OR ball.x is less than 0 reverse the direction of ball.speedX and the same thing for the y value. When all put together you have a fully bouncing ball!

See the Pen
Learning Canvas Teaching 2017: Bounce All Sides
by Josh Fabean (@fabean)
on CodePen.

Bonus

There are a lot of cool things you can do from here:

  • Change color on bounce
  • Add extra balls when clicked
  • Have ball change size on bounce
  • Add extra balls on bounce (dangerous as this gets out of hand quick and can crash your browser)

I recently gave this talk at Drupal Camp and you can watch the video for step by steps for all of this and some of the fun bonuses.

07. September 2016

100 Days of Code - Day 7

I just finished day 7! Where did the other days go you say... well I did them but only on github without blogs. I've been busy :) This in 7-10 hours is actually becoming a real thing. At this point here's some key features I have done:

  • Fly around the screen with turning and when you hit the edge of the screen you go to the other side of the screen
  • You can shoot lasers by pressing the space key
  • Randomly generated asteroids appear and fly across the screen
  • You can shoot the asteroids and they disappear and you get a point
  • You can get hit by an asteroid and they disappear and you lose a point
  • I just today fixed my words which weren't showing up. Turns out they were alwasy there... just black instead of white.

Most of the things in that list don't work great but they work, I'm honestly impressed with how little I've worked on this.

So today my commit is first my updated log file and the actual code I wrote.

Here's my current hit detection code, which I believe would work if things weren't rotated on the screen.

// calculate if you hit an asteroid
let calcLaserHits = () => {
  // for each laser current on screen
  for (let i = 0; i < player.ship.lasers.active.length; i++) {
    let laser = player.ship.lasers.active[i];
    // for each asteroid currently on the screen
    for (let a = 0; a < asteroids.length; a++) {
      if (laser.x >= asteroids[a].x && // if your x is greater than the asteroid
          laser.x <= (asteroids[a].x + asteroids[a].width) && // and less that the asteroids x+the width you should be between it on the x axis
          laser.y <= asteroids[a].y && // if your y is less (above) the asteroid I actually feel like this is wrong...
          laser.y >= (asteroids[a].y - asteroids[a].height) // and you are greaterthan it's y and up.
         ) {
        // you should be between this asteroid
        console.log('you hit an asteroid!');
        asteroids.splice(a, 1);
        player.score++;
      }
    }
  }
}

Now that I've commented that if I'm confused by this and I think my if is wrong and that's why the hit detection is bad. Maybe looking that over again and fixing that will make things better. Hopefully that's the case and I don't have to do some crazy math based on rectangles being rotated.

Here is my code in CodePen as it currently stands, you can use the arrow keys and space to play with it. Like I said above collision detection could use some help

 

See the Pen 100 Days of Code day 7 by Josh Fabean (@fabean) on CodePen.

 

:wq

03. September 2016

100 Days of Code - Day 3

Day 3 and I've hit my first big struggle! Turns out math is hard, or I'm just using it wrong. It's probably me just using it wrong. I don't know the equation to calculate your movement on a grid based on your current rotation, so I'm trying to make one up. I know all numbers I have to play with and what answer I'm looking for, it's just trying to manuplulate those numbers to produce that answer is where I'm having the issue.

So today my commit is first my updated log file and the actual code I wrote.

Here is a list of what I accomplished:

  • I got gulp live reloaded working on js & css changes instead of just html changes. Pretty simple.
  • I made it so you can rotate your square (ship) both left and right.
  • Where I've gotten stuck is calculating how your ship moves when you press up and down based on rotation. I'm trying to take your rotation divided by either 360 or 180 (I keep swithing back and forth trying to see which one is more accurate) then with that calculate your moves on the x/y grid. So far it's a total failure.
  • I also just noticed I somehow broke the words from showing up... YAY

The figuring out how to properly rotate things did take me awhile, and a couple different Stack Overflow posts and reading MDN's post on CanvasRenderingContext2D.rotate(). While trying to do that I did break things in fun ways

This is the time I made the entire screen glitch out badly:

Then the other time where I got sort of better but created a weird snaking trail.

I ended up having to make an entirely new drawShip() instead of using my existing drawRect() as it turns out if you want to rotate things it requires a lot more things to calculate and I didn't want to update my background to cancel out all the rotating I was doing.

let drawShip = (rectangle, rotation = 0) => {
  ctx.save();
  ctx.beginPath();
  ctx.translate((rectangle.x + rectangle.width / 2), (rectangle.y + rectangle.height / 2)); // this is supposed to rotate it around the center point
  ctx.rotate(rotation * Math.PI / 180); // this is used to rotate the object
  ctx.rect(-rectangle.width/2, -rectangle.height/2, rectangle.width, rectangle.height);
  ctx.fillStyle = rectangle.color;
  ctx.fill();
  ctx.restore();
};

So the new things are setting a ctx.translate() which is changing where the center point that we're rotating around is, this is so the ship will rotate off it's center instead of a corner which would look goofy to the user. Then a simple ctx.rotate() which is just telling it the rotation. Looking at that now I might need Math.PI to help with my path I'm stuck on. The rest of that code is similar to what we had before instead before and after we now are .save() and .restore(), not 100% sure but I believe that is to keep you from rotating the entire context of the app and only this single element.

Here is my code in CodePen as it currently stands, you can use the arrow keys to play with it, it's fairly broken.

See the Pen 100 Days of Code day 3 by Josh Fabean (@fabean) on CodePen.

:wq

02. September 2016

100 Days of Code - Day 2

Great, it's day two of 100 days of code. Guess what!? I sort of already failed... I got to work at 7:30am and left at 11:40pm. In that time I was able to get 45 minutes throughout the day where I worked on this code. I'm going to count it because I'll make it up tomorrow and I coded the whole time and taught classes on how to code from 6pm-11pm so you cannot be too made at me.

 

So today my commit is first my updated log file and the actual code I wrote.

Here is a list of what I accomplished:

  • Removed screen wiggle when pressing the down arrow
  • Made my gulp server actually work
    • This involves moving around the file structure a bit
  • Moved health indicator to the right of the screen
  • You can now fly off one side of the screen and appear on the other side

The screen wiggle was a simple e.preventDefault() which was so simple it made me wonder why I didn't realize that was the issue with previous canvas projects I've made. The flying off the screen is pretty simple but much cooler than a preventDefault(). Below is sample code of what I do when someone is pressing the down arrow.

if (38 in keysDown) { // Player holding up
  if (10 <= player.ship.y) {
    player.ship.y += -(player.ship.speed.y);
    // going to check if they've hit the top, if they have, put them on the bottom
  if (player.ship.y <= 0) {
    player.ship.y = c.height;
  }
}

The only part of that code that is new is the if player.ship.y <= 0 we make their new y be the height of the element which is the bottom. It's a pretty simple concept and took me a couple of minutes to come up with how I would do this and get it down. It's only an addition because someone from work complained they couldn't go off the screen and I realized that'd be a cool idea.

Like I said, today was a lighter day tomorrow I plan on trying to get something bigger done so we'll see what happens.

Here is my code in CodePen as it currently stands, you can use the arrow keys to play with it.

 

See the Pen 100DaysOfCode day 2 by Josh Fabean (@fabean) on CodePen.

 

:wq