Mexican street art as pixel art

| Comments

I'm slowly working my way through ES6 for Everyone by Wes Bos. It's been almost 6 months since I did the #javascript30 thing and I have been trying to do little projects every now and then to keep what I learned a little current.

The ES6 course has a lot of things that I already know now - and that feels great actually. I understand it much better when I get it explained again and when I get to play with it a little.

Today I had the perfect combination of no plans all day, dreary weather, and acute lazyness, so I stayed on the couch all day playing around with arrays in ES6 and some pixel art. I have loved geometric art since I was a kid, so when I stubmled upon this photo I took of some street art in Oaxaca in the spring, I decided to recreate it for the browser with JavaScript. I am aware that there are libraries out there that lets you do this — or even editors, but I wanted to make sure I played with some good ole vanilla JS.

So here is a pen with my browser version of the street art frieze from Oaxaca that inspired me. The street artist was likely inspiered by the unique friezes at the Zapotec archaeological site Mitla.

See the Pen Copying street art frieze in pixel art by Camilla Krag Jensen (@naxoc) on CodePen.

It was good fun to write code for the fun of it and doing "art". I might stick with pixel art and friezes from Mitla for a while. This one just begs to be done with box shadows:

12-05oaxaca077.jpgBy en:User:Bobak Ha'Eri - English Wikipedia, CC BY 2.0, Link


JavaScript30 - Day 30

| Comments

The final day of #javascript30 is a whack a mole game. I'm not going to write about that, but just do a little bit of evaluation on the #javascript30 month.

For whatever reason, it took me forever to get to doing the last day of #javascript30. I have really enjoyed the course and I was going on 25 days streaks of publishing a blog post with it, and then suddenly it took me over 2 weeks to write the last blog post.

#javascript30 was really great. I learned at ton that I might have known already to some degree, but I had never used to make something where I got to put the things together. It felt great to admit that while I have been making a living as a (backend) programmer for well over 10 years, I was bad at Javascript. Admitting that made it easier for me to choose to follow a "simpler" course on JS instead of tripping myself up with trying to use a framework while pretending that I understood ES6, Webpack, and tons of other things at once. The course is really well put together and I enjoyed the tasks very much. It seems trivial, but I find that it can be really hard to come up with ideas for small projects to work on when learning, but the projects in the course were really useful and fun.

My favorites things about the course were:

  • The array workouts
  • The speech recognition stuff
  • Learning ES6 syntax (wow, I really like that).
  • Really understanding the events the browser fires.
  • Doing cool shit that looks cool.
  • Felling like I have something to blog about again.

So thank you very, very much for an awesome free course, @wesbos. I would recommend it to everybody that is either learning Javascript or someone like me who has been using frameworks that kinda hid the real understanding of the language. Doge recommends


JavaScript30 - Day 29

| Comments

Day 29 of #javascript30 creates a countdown timer in the browser.

setInterval()

This exercise has some clever use of setInterval(). Understanding timers is a little more tricky than it seems, so take a good look at the examples in the docs too.

Select with Element.name

This one is so cool! I did not know you could do that. If you have an element that has a name like an input element, a link anchor, or even an image, you can "select" it by it's name. The name is a property on the document and will give you the same as if you used a querySelector:

document.myFormElement;

Is the same as:

const myForm = document.querySelector('.form-class');

Pretty cool!

string.padStart()

It the exercise, the minutes in the timer are padded with zero using a small ternary if. That might be the tersest way to do it, but I just wanted to mention string.padStart(). It doesn't have great browser support yet, but I like functions like this. Just give it the length you are shooting for and what you want the string padded with. It needs to be called on a string, so I had to "cast" to string first like this:

const minutes = Math.floor(seconds / 60);
const remainderSecs = (seconds % 60).toString().padStart(2, '0');
const display = `${minutes}:${remainderSecs}`;
endTime.textContent = `Be back at ${hour}:${minutes}`;

Where Wes' solution is like this:

const end = new Date(timestamp);
const hour = end.getHours();
const adjustedHour = hour > 12 ? hour - 12 : hour;
const minutes = end.getMinutes();
endTime.textContent = `Be Back At ${adjustedHour}:${minutes < 10 ? '0' : ''}${minutes}`;

Both are perfectly readable, but I do like the pad functions. There is a padEnd() too.


JavaScript30 - Day 28

| Comments

Day 28 of #javascript30 is a UI for controlling the playback speed on a video.

There is a bit of math to calculate where the mouse is moved over a bar that will control the video speed. It is a good idea to practice lots of things that use this recording of where the mouse is or where something is clicked. The math is not rocket science, but understanding the tools that are needed to get positions are important. I have read the docs for MouseEvent.pageY, Element.offsetTop, and Element.offsetHeight quite a number of times now and while they are also not complicated, I feel like I can do with even more practice with this. I'll cook up some codepen at some point where I illustrate what they do so I can use that as reference.


JavaScript30 - Day 27

| Comments

Day 27 of #javascript30 makes a neat horizontal scroll click and drag accordion or carousel.

There are a number of event listeners in use to achieve this. mousedown, mouseleave, mouseup, and mousemove. They keep a boolean that keeps track of whether the mouse is down or up, and they set the Element.scrollLeft property to the number of pixels the user dragged the element.

let vs var

I understand const completely now, but I was fuzzy on let vs var. They are quite similar, but they differ in scope. Once again, MDN's docs has a great explanation and example:

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

So var has scope in the entire function, while let has function in the block it is in (and all sub-blocks in that block).


JavaScript30 - Day 26

| Comments

Day 26 of #javascript30 is making a dropdown menu that follows you along.

This lesson takes what I learned on day 22 about getBoundingClientRect() and uses it to move around a box behind the contents in a dropdown menu. We use mouseenter and mouseleave to react to the items hovered over.

Using opacity for "animation"

I learned a really cool trick from this lesson. To get a cool "animated" feel, first add a class that displays block on the hovered item, and then a setTimeout() with about 150 ms delay that adds another class that sets opacity to 1. The item should have a transition set in CSS too to make it really look good.

A gotcha when using this approach is that on mouseleave, when you remove classes that keeps a list item open — you might get there "early" because of the timeout in the mouseenter function. So in the mouseenter function, you can simply check if the other classes that don't use the timeout are present before adding it.


JavaScript30 - Day 25

| Comments

Day 25 of #javascript30 explains what happens when (DOM) events are triggered.

I made a pen based on the lesson to try to illustrate and understand better. It's at the bottom of this post.

Bubbling

Is when an event "bubbles" up the DOM. In the example with 3 nested divs with an event listener on all of them, a click on the inner one will trigger the click listener on all of them. Note that this is the item the listener is on, but event.target is always the item that was clicked.

Propagation

In JS this means that the event will keep bubbling up (or capturing). If you call e.stopPropagation() the propagation stops.

Event listener parameters

The addEventListener() function takes an optional options object. Of these, capture and once are interesting.

once

Will allow the event to fire once and then remove the event listener.

capture

I think the easiest way for me to understand this is that when this is true, the events bubble backwards. Try playing around with the pen example to try and make sense of it :)

See the Pen Event options and propagation by Camilla Krag Jensen (@naxoc) on CodePen.


JavaScript30 - Day 24

| Comments

Day 24 of #javascript30 is making a navigation bar that sticks to the top of the window.

This is something I have done more than once before. With some frustration, though. The same effect can be achieved with CSS's position: fixed, but you still need JS to slap on the class or property at the right time.

scrollX and scrollY

Keep in mind that that IE does not supprt these two at all. Edge does, but to be safe, use pageYOffset or pageXOffset - these are aliases for scrollX and scrollY. See the docs for scrollY for an explanation.


JavaScript30 - Day 23

| Comments

Day 23 of #javascript30 is having fun with speech synthesis and new tricks for passing arguments to a callback function.

Speech synthesis in the browser

I could not make the lesson example work with the voices dropdown in Firefox. I like Firefox and I have recently switched back to using it as my default browser. I switch back and forth at least a couple of times every year. I even blog about it sometimes. Anyway. To make it work in Firefox (and Chrome), I did this:

function populateVoices() {
  voices = speechSynthesis.getVoices();
  voicesDropdown.innerHTML = voices
    .map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
    .join('');
}
if (speechSynthesis.onvoiceschanged !== undefined) {
  speechSynthesis.onvoiceschanged = populateVoices;
}

instead of using an event listener like this:

speechSynthesis.addEventListener('voiceschanged', populateVoices);

I kinda stole it from the MDN docs for SpeechSynthesis.

Passing arguments to a callback function

I also learned some new tricks when it comes to passing arguments to a callback function in JavaScript. I made a pen with them:

See the Pen Passing arguments to a callback function by Camilla Krag Jensen (@naxoc) on CodePen.

Not only will the first one not work. It will set the text "I should be an animal" to "nope" when then page loads. Try commenting out the last line where I set textDiv.textContent. I guess you can say it works once - just not the way you want it to :)


JavaScript30 - Day 22

| Comments

Day 22 of #javascript30 makes a link hover highlight that follows you around on the page. I try to understand the difference between mouseover and mouseenter.

mouseenter vs mouseover

Using transition and translate in CSS we can make the hover look like it is following you. We listen for the mouseenter event and then the highlight is moved with CSS' translate. I didn't know the mouseenter event, so I tried to read up on the difference between that and mouseover. The docs are really not crystal clear, so I must say that I didn't get all that much wiser from that. I found this demo on JSFiddle:

That helps a little, but I think the choice between the events depends a lot on the DOM you are working with. So maybe test with both and see which one gives you the most relevant amount of events. No reason to slam the browser because you are not using the optimal event.

Element.getBoundingClientRect()

Here is a method I would have like to have known about in the past. I've found myself working with position and size a lot and never really knowing which properties to use. getBoundingClientRect() gives you a DOMRect object that has height, width, top, and left. There are a couple of other properties, but be careful because not all of them are available in all browsers.