Wednesday, 26 February 2020

Pin Tweaks

A mate shared an article with me a little while back about Sci-Fi, one particular quote stood out:

Science fiction wasn’t about evading reality – it was a literary anthropology which made our own society into a foreign culture which we could stand back from, reflect on, and change.

I've always been a fan of this sort of thing, and you just need to take a squint at Star Trek to clock that the Klingons were thinly disguised Russians during the Cold War (a good read on this subject is here).

Along with the fun and critical thinking that is associated with the genre itself, the people who write about it are also clever wee buggers, not opposed to some critical thought on related subjects. This article on my RSS feed caught my eye this morning. If you've managed not to meet or love someone with Dementia or some other degenerative neurological condition which leaves the body there, but slowly erodes the brain, then count yourself blessed. Whether you have or not, this discussion of Twin Peaks is well worth a read.

Sunday, 23 February 2020

SVG Cube

My Dad and I share a love of op art and are forever sending across images we like. He recently sent me something from Pinterest, and I loved it, but what I loved more was a related image, and I got to thinking about how to replicate it using SVGs. Yesterday morning I took a stab at it and clocked it was quite a simple design made up of 3 skewed and rotated rectangles that were then arranged into a hexagon. The hexagons were then placed adjacent to each other and offset above and below.

What took some time this morning was figuring out how a hexagonal design could be placed within a rectangle - but after staring at the lino in our bathroom it came to me.

Anyway, I also took the time to refactor the image I created in Inkscape so that it is made up of a def and a couple of patterns. After all, the rectangular sides of the cubes have the same fill but are just rotated and skewed. So the fill could be a pattern, the cube could be a def, and then the arrangement of seven cubes (which are required to create a properly tessellating design, and all use the same cube, just arranged appropriately) could be another pattern. From many hundreds of lines of repeating XML I came up with this:

  <pattern id="side-fill"
    x="0"
    y="0"
    width="36"
    height="36"
    patternUnits="userSpaceOnUse">
    <path style="fill:#000000;stroke:none;"
      d="M 0,30 2,30 1,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 2,30 4,30 3,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 4,30 6,30 5,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 6,30 8,30 7,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 8,30 10,30 9,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 10,30 12,30 11,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 12,30 14,30 13,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 14,30 16,30 15,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 16,30 18,30 17,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 18,30 20,30 19,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 20,30 22,30 21,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 22,30 24,30 23,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 24,30 26,30 25,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 26,30 28,30 27,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 28,30 30,30 29,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 30,30 32,30 31,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 32,30 34,30 33,0 z" />
    <path style="fill:#000000;stroke:none;"
      d="M 34,30 36,30 35,0 z" />
  </pattern>
  <defs>
    <g id="cube">
      <rect x="0"
        y="0"
        width="36"
        height="36"
        transform="matrix(0.87,-0.5,1,0.58,0,0)"
        fill="url(#side-fill)" />
      <rect x="0"
        y="0"
        width="36"
        height="36"
        transform="matrix(-0.87,-0.5,0,-1.15,30,51.9)"
        fill="url(#side-fill)" />
      <rect x="0"
        y="0"
        width="36"
        height="36"
        transform="matrix(0,1,-1,0.58,60,0)"
        fill="url(#side-fill)" />
    </g>
  </defs>
  <pattern id="tile"
    x="0"
    y="0"
    width="125.28"
    height="108"
    patternUnits="userSpaceOnUse">
    <g transform="translate(-30,54.6)">
      <g transform="translate(93.96,-54)">
        <use xlink:href="#cube" />
      </g>
      <g transform="translate(31.32,-54)">
        <use xlink:href="#cube" />
      </g>
      <g>
        <use xlink:href="#cube" />
      </g>
      <g transform="translate(62.64)">
        <use xlink:href="#cube" />
      </g>
      <g transform="translate(125.28)">
        <use xlink:href="#cube" />
      </g>
      <g transform="translate(93.96,54)">
        <use xlink:href="#cube" />
      </g>
      <g transform="translate(31.32,54)">
        <use xlink:href="#cube" />
      </g>
    </g>
  </pattern>
Fun eh? You can see it in my playground here, and with it being an SVG you can scale to your heart's content.

Wednesday, 11 December 2019

Gym in the Winter

It's cold in the UK at the minute, but I've rediscovered long johns. I used to wear them all the time when we lived aboard (in fact I used to put on more clothes than I took off for bed), but it's been a couple of years since I've felt the need.

They're lovely and warm, and my feet are warm more often than not these days, but going to the gym is becoming an issue. Quite apart from the looks I get from other people in the changing room when I get ready for my workout, the problem of getting dressed afterwards is a pain.

The thing is that I go not only to work out but to spend time in the steam room so when I do get ready, I change into trunks and shorts. When I finish my workout, I remove everything except the trunks, have a shower and then get hot and sweaty.

But when I get back, I shower and get changed and have to put on loads of layers without any of them getting any wetter then they got on my cycle to the gym, which is no mean feat! I've finally figured out the way to do it though. Once I've got my undies on I get my shoes, socks, long johns and trousers all in place beside me. Dry one foot thoroughly put on one sock, then long johns on one leg (the socks help stop the long johns disappearing up my leg while I cycle), then my trousers on the same leg. After the long johns and strides are put on, the remaining "leg" is bunched in my lap to keep dry. Finally, my shoe goes on, and my foot goes to the floor. Then the other foot is lifted and dried, and the same process is repeated for that leg, what a faff! But it does save the bottom half of my clothes from getting even wetter than usual!

Every once in a while I go to Yoga afterwards, and that process involves having a pair of shorts put on betwixt the undies and the long johns (no one wants to see long johns on underneath shorts at Yoga, I'd look like some geriatric superhero).

I'm not sure why I wrote this, except it tickles me.

Tuesday, 26 November 2019

VueJS Pagination

I've written about pagination before, and it's something I'm interested in so when the chance came to write a component that dealt with it at work I jumped at the chance. Rather than using any of the other techniques I've used in the past, this component was using VueJS, and I knew I'd get some data via a message bus. The data was in the form of an object with just three numbers: the current page selected, the total number of items and the number of items for display on each page.

The total number of items could range from one to many; the number of pages could also be massive depending upon the page size selected by the user.

As well as wanting to display a sensible number of page numbers to the user, I also wanted to decorate the pagination. The decoration needed to have the ability to jump three pages back and forth as well as a quick way of navigating to the first and last page.

So I did what I usually do and fired up JSFiddle to work up a quick prototype and came up with this. I've not included the message bus, but I'm instead using values within the data of the component. While I know it's not good form to alter the data within the component; I'm doing so here for illustration purposes.

Logic splits between the markup and the JS, but I quite like that for some reason.

HTML
<div id="app">
    <ol v-if="totalPages > 0" 
        aria-label="Pagination navigation">
        <li v-on:click="paginationOptions.page = 1" 
            aria-label="Go to the first page" 
            title="Go to the first page"
            v-bind:class="{
                'disabled': paginationOptions.page === 1
            }">
            <div class="content">&larr;</div>
        </li>
        <li v-if="totalPages > 3 && paginationOptions.page - 2 >= 1" 
            v-on:click="paginationOptions.page = (paginationOptions.page - 3 < 1) ? 1 : paginationOptions.page - 3" 
            aria-label="Jump three pages backward" 
            title="Jump three pages backward"><div class="content"></div></li>
        <li v-for="page in pages" 
            v-bind:key="page" 
            v-on:click="paginationOptions.page = page" 
            v-bind:aria-label="(page === paginationOptions.page) ? 'Current page, page ' + page : 'Go to page ' + page" 
            v-bind:aria-current="page === paginationOptions.page" 
            v-bind:title="(page === paginationOptions.page) ? 'Current page, page ' + page : 'Go to page ' + page"
            v-bind:class="{
                'active': page === paginationOptions.page
            }">
            <div class="content">{{page}}</div>
            <span v-if="page === paginationOptions.page" 
                  style="display: none">(current)</span>
        </li>
        <li v-if="totalPages > 3 && paginationOptions.page + 2 <= totalPages" 
            v-on:click="paginationOptions.page = (paginationOptions.page + 3 <= totalPages) ? paginationOptions.page + 3 : totalPages" 
            aria-label="Jump three pages forward" 
            title="Jump three pages forward"><div class="content"></div></li>
        <li v-on:click="paginationOptions.page = totalPages" 
            aria-label="Go to the last page" 
            title="Go to the last page"
            v-bind:class="{
                'disabled': paginationOptions.page === totalPages
            }">
            <div class="content">&rarr;</div>
        </li>
    </ol>
</div>
JS
new Vue({
    el: "#app",
    data: {
        paginationOptions: {
            page: 2,
            total: 55,
            pageSize: 10
        }
    },
    computed: {
        totalPages() {
            return Math.ceil(this.paginationOptions.total / this.paginationOptions.pageSize);
        },
        pages: function () {
            const returnArray = [];
            if(this.paginationOptions.page === 1){
                for(i = 1, count = 0; i <= this.totalPages && count < 3; i++, count++){
                    returnArray.push(i)
                }
            } else {
                if(this.paginationOptions.page === this.totalPages){
                    for(let i = this.totalPages, count = 0; i >= 1 && count < 3; i--, count++){
                        returnArray.push(i)
                    }
                    returnArray.reverse();
                } else {
                    returnArray.push(this.paginationOptions.page);
                    if(this.paginationOptions.page < this.totalPages){
                        returnArray.push(this.paginationOptions.page + 1)
                    }
                    if(this.paginationOptions.page >= 1){
                        returnArray.unshift(this.paginationOptions.page - 1)
                    }
                }
            }
            return returnArray;
        },
    }
});
SCSS
#app{
    margin: 1em;
}
ol {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin: 0;
    padding: 0;
    list-style-type: none;
    width: 100%;
    text-align: right;
    li{
        display: inline-block;
        &.disabled {
            cursor: not-allowed;
        }
        .content {
            text-decoration: none;
            font-weight: bold;
            background-color: #fff;
            color: #7f8c8d;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 40px;
            height: 40px;
            margin: 0 3px;
            border: 1px solid #e5e5e5;
        }
        &.active {
            .content {
                border-color: #2c3e50;
                background-color: #2c3e50;
                color: #fff;
                text-decoration: none;
            }
        }
    }
}

Friday, 27 September 2019

The Tea Set

The Tea Set recently released their latest album Back in Time for Tea, and I thought I'd have a play with one of their old logos. I spent ages working out the SCSS mixin, but I'm pleased with the result.

This is the mixin and its usage:

$main-duration: 10s;
$base-percentage: 3%;

@mixin animate_movement($initial, $id, $main-duration, $delay, $duration) {
    $animation-name: unique-id() !global;
    @keyframes #{$animation-name} {
    
        0%, 
        #{$delay * $base-percentage} {
            transform: $initial;
        }
    
        #{($delay + $duration) * $base-percentage}, 
        100% {
            transform: translate(0px, 0px);
        }
    }
    ##{$id} {
        transform: $initial;
        animation: $animation-name  $main-duration linear infinite alternate;
    }
}

@keyframes scale-in-top {
    0% {
        transform: scale(0);
        transform-origin: 50% 0%;
        opacity: 1;
    }
    100% {
        transform: scale(3);
        transform-origin: 50% 0%;
        opacity: 1;
    }
}


.icon-holder {
    text-align: center;
    margin-top: 1em;
    svg {
        animation: scale-in-top 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
    }
    @include animate_movement(translateY(-88px), TheTeaSet, $main-duration, 1, 5);
    @include animate_movement(translateX(-16px), tHe, $main-duration, 9, 3);
    @include animate_movement(translateX(-32px), thE, $main-duration, 6, 6);
    @include animate_movement(translateX(-16px), tEa, $main-duration, 15, 3);
    @include animate_movement(translateX(-32px), teA, $main-duration, 12, 6);
    @include animate_movement(translateX(32px), Set, $main-duration, 18, 6);
    @include animate_movement(translateX(16px), sEt, $main-duration, 21, 3);
}

Monday, 23 September 2019

She said, he thought

This has been rattling around in my head for a while so I thought I'd best get it written. It's basically the reason why I shouldn't try relaxation.

She said, “Breath in,” then waited for my huge inhalation to finish and paused for a beat before saying, “breath out”. Again she waited for my chest to shrink, then my belly to implode, before again saying, “Breath in”, waiting while I inhaled and again pausing for a beat before telling me to exhale.

This repeated for about half a dozen times before she said, “Breath normally”. I did as I was told, but noted that my breathing was much deeper and slower than before.

She said, “Empty your mind”. Nice idea but utterly impossible. Or maybe not even a nice idea… where would I be without the whirling maelstrom of chaos rolling around in my head?

She said, “Imagine you’re walking through the grass...” So I did and wondered what the weather was like.

“It’s a warm and sunny day and you’re barefoot” Okay, I can live with that. I can live with it as long as there’s no dog shit on the grass… I guess there isn’t or this wouldn’t be relaxing… trying to avoid stepping in shit and then going for a Burton and landing on my arse would be a pain, especially if I managed to land in the shite.

“You step from the grass onto the sand by the sea.” Ah, bugger. It’s the grass like pampas grass, isn’t it? The stuff on dunes which is sharp as anything and likely to lacerate my feet, still, thankfully I’m in the sand now. Let’s hope there’s no dog shit or broken glass or some slimy seaweed in the sand now. That’d be just my luck, wouldn’t it? Perhaps I could slide on the seaweed and then manage to land in dogshit… and broken glass! When did I have my last Tetanus injection again?

“You step into the warm sea.” Where is this? It’s not local if the sea is warm… are there jellyfish or sea urchins here? Do I need sunscreen? She said it was warm before… I’ll get a burnt head!

“You see a rock standing in the sea.” A rock? How big is the rock? Are we looking at a pebble here or something more substantial? Am I gonna have to avoid it with my bare feet, as well as avoiding the jellyfish and sea urchins? It’s warm though, isn’t it? I’m sure she said it was warm… happen it’s Australia where everything is trying to kill you! There could be sharks or a manta ray - I’ll end up getting stuck on the tail of the manta ray, bleeding and then the sharks will come and I’ll be buggered! All while being covered in dog shit with a broken bottle stuck out my back!

“You climb the roc.k” Ah, it’s not a pebble, it’s a bit bigger! Wonder how big? Am I gonna be climbing for a while? I do hope not: I’m not as young as I once was and I’m not sure my belly will allow for any major climbing elegance… perhaps it’s the South China seas and the rock is like the island where Goldfinger had his super, secret weapon? That was huge though wasn’t it? I’ll be climbing all bloody day!

“You sit on the top of the rock.” OK, guess it’s not that big… something like that lass was marooned on when the sharks started circling… are the sharks here now, did I manage to cut my feet on the razor grass or broken glass, or are they attracted by dog shit in the water? Also, rocks aren’t all that comfortable, this is gonna kill my arse after a while. Am I even gonna be here a while, should I ask if I can put my hat on?

Monday, 29 July 2019

Been a busy boy

I've just had a busy old weekend and managed to get my digital counter working with CSS animations. I have been wanting to do this for ages but haven't had the time to research the technique correctly. It's here, and I'm quite pleased with the result despite it taking a shed load of tweaking to get right.

I've also caught up some on updated p5 implementations from WireFrame, and I've added three projects to the site hosted by GitHub, all to do with mazes. The first uses an algorithm to generate a maze, and I got lost in the C implementation but found a set of videos from The Coding Train that went through the steps required. I've pretty much stolen them but made them a little more ES6y. The second draws the view of a character navigating a maze, and I'm impressed with the cheating in terms of the images used to illustrate the perspective required. The third and final one also cheats by using images to build up a semi-3D illustration of a landscape and was lots of fun (you can navigate using the arrow keys)!