Wednesday, January 16, 2019

operator overload

Watching this Redux Crash Course video, Brad uses
  this.setState({[e.target.name]: e.target.value});
I could guess what that was doing, but had to ask what that syntax was called - "computed keys" or "computed property names"

In terms of JS, there's definitely a drive for conciseness. Which can pay some dividends in terms of letting experienced coders recognize a complex trope quickly, but also comes with potential ambiguity - sometimes i personally wish the language was a bit more verbose, even if function() { }s are ugly,  bar fat arrows or random floating {}s can be so hard to parse.

Anyhoo, a coworker recommended this guide to ES6 features - it's pretty cool in showing the old and busted after the new hotness.

Of all the new syntaxes, one sticks out as clunky, and the other sticks out as just plain bad and confusing.

Custom Interprolation:
new hotness:
get`http://example.com/foo?bar=${bar + baz}&quux=${quux}`
is the same as 
get([ "http://example.com/foo?bar=", "&quux=", "" ],bar + baz, quux);

Dividing a string that way seems very strange.
But Parameter Context Matching seems really ugly when it starts letting you declare a local variable from a totally different argument map entry....
I mean 
function f ([ name, val ]) {
    console.log(name, val)
}
and
function h ({ name, val }) {
    console.log(name, val)
}
make sense and are pretty easy to read, but the renaming that goes on with
function g ({ name: n, val: v }) {
    console.log(n, v)
}
is bizarre - it feels like it's messing with left / right operands, every else in js land the key / variable name you're changing is on the left...

(Random note: the video made use of http://jsonplaceholder.typicode.com/ which seems pretty hip.)

hungarian notation

I realized I was almost on the verge of forgetting the term "Hungarian Notation" - a now mostly rejected idea of prefixing variable names with the type of the object. It was probably rejected because it was misunderstood and misapplied - like you shouldn't call your incrementer iCounter just because it's an integer, but if you have, say, a screen dimension that might be in pixels or might be in em, it might make sense to have "pxWidth" or "emWidth".

For instance, I'm fooling around with a gimmicky 3D for my timeline data, and some of my dates are objects containing a y and m key for month and year, sometimes I'm using a "count of months" (i.e. y * 12 + m) and sometimes I've normalized it to a value between 0 and 1. Hungarian Notation kind of makes sense here.

(To google up the forgotten term I had to search "notation petzold" - ah, the old Petzold book "Programming Windows", what an artifact of my first programming job...)

Monday, January 14, 2019

timelines: trying to capture four and a half decades on a screen

Everyone who hits middle aged gets shocked at how quickly life seems to pass (maybe because each year is a smaller fraction of the number of years we've already lived through). Also it's easy to lose track of whole years or even longer stretches. I'm hoping a visual timeline that says "here's where you were" will help me reclaim some of those "lost years" - let me connect with my past self of that era, however distant. Also, it might be interesting to compare different timelines - where was I living, vs who was i working for? Which times of my life had more change, and which had more stability?
A lot of the initial design came from Your Life in Weeks. I sort of loved the macabre nature of seeing all the weeks I was likely to get, with a kind of "You Are Here" in the middle of it. (and not on the early side of the middle either).

Quickly I was reminded that a year doesn't go easily into weeks - neither 365 nor 366 is a multiple of seven! So so either you line up the week columns, but they stick out scruffily on the sides, or you let the weeks shift left and right and you lose your nice rows and columns. And as cool as the "here are all your weeks" idea was, I realized it was orthogonal to getting a sense of history. So I threw that code away.
DOM version (2018.12.09)
Built a "city I lived in history" seeing what happens if I keep everything in the DOM - kinda ugly! Realizing what I want to do with captions doesn't really make sense (i.e. it would be hard to put one caption over several blocks etc.) And I was clumsy with my choice of colors - the old school term for that was "angry fruit salad". I think only labeling every multiple of 5 year was the right idea/
blocks version (2018.12.11)
Switched to p5 and canvas where I have a lot more control over finessing how things are positioned. I figure out how to get colors more or less under control. I also put in the raw data for jobs and romances. I both figured out how to center the captions things that took multiple years were only labeled once, reducing clutter. (Also I added little triangles for things that were going on into the future)
I like how the stacked look gives me a sense of time repeating - like how high school and college summers had their own feel, a kind of central column.
I was a little coy with most of the romances, using initials for the most part. At somepoint I will put a disclaimer saying these aren't all romance-romances, some are "its complicated" or mere crushes on my part. But I consider it all a part of my history and want to claim it.
yearserve (2018.12.12)
Kind of a digression -- I was thinking about getting back to a flattened look, but wondering if I could still get that sense of the looping nature of time - 4 years ago I noticed that my sense of a week and a year are both circular, and so here I am trying to balance that loopiness with a sense of the inexorable forward progression of time - and the seasons, as they are in the New England-y bits of the Northern Hemisphere. I am reasonably pleased with the result, but I don't think it's very useful for marking stretches of time on.
flat (2018.12.21)
If I decided to "flatten" time, I wasn't sure if I wanted to go vertical (the way I kind of visualized time going forward, from left to right) or down (which is more natural for webpages and mobile apps, TBH). Decided to start with Horizontal.
Since it gets soooo wide and to the right, I decided to start with it scrunched, and then zoom in on click. Also I put back in the season colors in - that returns a better feel of the years, but kind of looks like a faded out African Flag, which wasn't a reference I was thinking of.
Overall I think the scrolling to the side gets pretty tedious. I suppose an update with embedded, zoomable photos, say, might might be more compelling, but I'm kind of meh about this one.
UPDATE: I just realized some of these weren't working on iPhone. The error is "Canvas area exceeds the maximum limit (width * height > 16777216)" even though I thought I was setting it to 16470 x 280 = 4611600 which is less than that, but I think it's because of Retina pixel scaling.
Bummer. This might influence what I try next. Either vertical, maybe with DOM elements (some of the frustrations I had with DOM bits might be lessened if I have a simpler, "linear" display) or maybe I should stick with the "blocks" style, which was compelling in its own way.
flatplus (2018.12.28)
One last attempt at full horizontal before I give it up.
Here the idea is that if we move the labels out of the line itself, we don't have to ensure that each span of time is as long as its label, and can compress the entire thing and not make it scroll so far to the side.
The routine to make sure label boxes don't overlap (pushing them to new rows as needed) is slightly complex.
I also took some additional care with the endcaps of the time spans, where one picks up where the last left off the circle is split.
I like how the lines are visually more lightweight than the blocks I've been using, but overall the effect is still a bit jumbled. And I'd say I think "blocks" is still winning in terms of taking in the information.
vert (2018.12.30)
Back to DOM. Using the more sophisticated colors was a big help - and since now each column is a simple chronology (vs the earlier DOM version and "blocks" where years went down but months went across) this one was very easy to code - I even added a gradiant fade to black for things going on now to an unknown point in the future.
skinny (2019.01.02)
Pretty much just vert, but making the lines skinner (but with the caption like a sign on a signpost). Also fixed the colors so that if there's a repeated label in a timeline it gets the same color each time.
I'm learning more and more that this doesn't need to be about "exactitude" in terms of dates. I started rounding off to the nearest month for convenience, and that has proven more than precise enough for my requirements. In fact, for reasons of legibility and design I may play even faster and looser with exact dates.
skinnyphoto / skinnybig (2019.01.04)
Adding in images - This is where shtuff gets real - or rather, really emotionally resonate for me. And I think far more visually compelling as well.
Before this, I hadn't given too much thought about where I'd put the thumbnails - but because the time dimension is vertical, putting small thumbnails to the side seemed to make more sense, now that I'm here.
But I realized I could do better, making the entire block a "cover" image. CSS has pretty cool "cover fit" cropping and stretching, and by using an alpha color for the caption background, I was able to make legible overlays for the caption, keeping the colors aligned.
I also added "big trips" as a column - which has the added bonus of providing lots of images. Not sure if they are showing up in all the old prototypes (though all prototypes so far rely on the same data file)
All the images I grabbed were already in galleries I put online, but seeing so many photos from so many contexts really gets me the effect I was looking for, of telling a story of a middle-aged guys life in one place.
I'm digging "skinnybig". I think I may need to add a cheat so you can have bigger minimum heights, even though most "big trips" are less than a month.
I also want to add a "projects and groups" column - I think I want to design so that it can hold different bars simultaneously (i.e. right now the program assumes I can't, say, have lived two places at once or held
beta1 (2019.01.06)
On the home stretch, maybe. I've started making it so each new version doesn't rely on the common dataset, but makes its own copy.
For beta1 I added the idea of "events" - things that occur on a single year/month - in this case, big vacations and trips I took. I refactored some stuff so that each event takes up 3 months worth of space, so you can get a better view of the photograph.
I also punted on complex logic to make sure images don't overlap, instead putting in a "tweakpos" parameter in the data to nudge an event up a bit. Again one of the takeaways of this is that precision doesn't matter that much - as long as most things that happened around the same time appear side by side, that hits the point I want to get across
beta2 (2019.01.08)
Made a new option so that one collection of date ranges can appear in a single column - so a little logic to place the vertical bars in different sub-columns. Used it to show what bands I've been in. (Hm. Maybe this behavior should be the default, so people don't have to be strict about non-overlapping date fields)
As the display is now larger horizontally, I realized my trick for keeping the column labels pinned is broken. For some reason I can't get the CSS property "sticky" (supposedly a mix of relative and fixed) to function at all.
I also added the same "tweakpos" logic to move any photo blocks around so they don't overlap, and then further tweaks so you can change the y-position of a photo in a short block (vs having it centered).
Also: fixed the headers with position:sticky and made code for seeing the full photo when you click on it less idiosyncratic yet stupid.
final (2019.01.14)
I realized that with all the vertical space I'm taking up, and making a viewer scroll through, the sense of proportionality is lost- part of the mission of this display is giving me a sense that a lot of time has passed, I was living life there, even if I don't have the best recollection of it. To help address that, I added a minimap - showing what the current viewport is showing relative to my whole life so far. I then tweaked it by putting the years, which reinforce that, hey, the 2010s were happening. And also a rough age indicator, of how old I was.
I also tweaked the display of the range blocks, putting a faded-out background behind the entire time range. This is to counteract a feeling that the vertical space occupied by a photo was where the time range was, and not where "popsicle stick" stretched to. (Actually I had to remove that effect for the "multibar" columns where I allow overlapping ranges)

So that's it! Again you can see the final result and if you want me to to make a version with your own life story (you have to provide the dates and photos, I can handle much of the rest) let me know!

Friday, January 11, 2019

scrolling minimaps with css and javascript

Remember the old arcade game Defender? And how they had a little minimap scanner at the top, that could show you where aliens were abducting your humanoids even as the screen was scrolling horizontally? For my timelines project, with a big vertical scroll, I wanted something similar - I want a generous amount of space to include images, but I wasn't liking losing the sense of "a whole life", so a small map seemed like the right idea, with a little frame on the map saying "you are here" (Kind of like a modern disappearing relative scrollbar, except it can hold a mini-me version of the whole thing.)

I might have cheated a little bit - I decided everything above the main content will be in a single block with an id of "header". The minimap and the frame moving in it then look like this:
<div id="minimap">
    <div id="frame"></div>
</div>

The CSS (fixed to one edge, and using opacity to let you see the real world beneath it)

#minimap {
    position:fixed;
    width:80px;
    border:1px black solid;
    height:400px;
    left:0px;
    top: 40px;
    background-color:rgba(255,255,255,.8);
    z-index: 100;
    overflow: hidden;
}
#frame {
    position: absolute;
    top:20px;
    border:3px red solid;
    height:80px;
    width:100%;
}

Then I just call setupMinimap. The code is a little wonky for IE support:

function setupMinimap(){
    if(window.addEventListener) {
        window.addEventListener('scroll', onScrollEventHandler, false);   
        window.addEventListener('resize', onScrollEventHandler, false);   
    }
    else if (window.attachEvent) {
        window.attachEvent('onscroll', onScrollEventHandler); 
        window.attachEvent('onresize', onScrollEventHandler); 
    }
}

function onScrollEventHandler() { 
    const main = document.getElementById('main');
    const frame = document.getElementById('frame');
    const header = document.getElementById('header');
    
    frame.style.height = (window.innerHeight / main.offsetHeight) * 100.0 +"%";
    let frameTopPercent = (100*((window.scrollY - header.offsetHeight) / (main.offsetHeight)));
    frame.style.top = frameTopPercent+"%";

    // DON'T NEED THIS CODE, NOW USING OVERFLOW:HIDDEN
    /*if(frameTopPercent < 0) {
        frame.style.display = 'none';    
    } else {
        frame.style.display = 'block';    
    }*/
}


FOLLOWUP: you can see the end result on my timelines page

Thursday, January 10, 2019

position: sticky not working ?

So, there's a cool position: sticky CSS style - the idea is that it behaves like position:relative; but then once its containing element is scrolled it is like position: fixed --  good for column headers so they're always visible even when the body of the table or whatnot is halfway off the screen.

I was having trouble using it for my timelines project, it was seemingly ignored it - I resolved the problem by making sure its containing element had a height style explicitly set.

Monday, January 7, 2019

pretty css blockquotes

Literally probably a decade ago, a friend's blog had a neat bit of styling for quotes that I've always meant to emulate - it had a big ol' quote mark as background to the right. 10 Simple CSS Snippets for Creating Beautiful Blockquotes linked to this codepen that was in the ballpark of what I was thinking of:

<blockquote> and then a <footer> tag for the citation (some of the examples used a semantically better "cite" attribute on the blockquote but you can't really do more markup, such as links, in that.)

I don't use a CSS preprocessor for my blog, and so the code I ended up with looks like this:

blockquote.quote {
    position: relative;
}
blockquote.quote::before {
    content: '\201C';
    position: absolute;
    left: -0.3em;
    top: -0.2em;
    color:#ccc;
    font-size: 6em;
    z-index: -1;
}
blockquote.quote footer {
    font-size: 0.9em;
    color:#999;
    padding-left: 1em;
}
blockquote.quote footer::before {
    content: '\2015';  
}
 
So much of my blog is about quoting things, it's nice to have a flexible way of showing that it's not me speaking.

Saturday, January 5, 2019

capturing cmd-s and ctrl-s in browser

The homebrew backend for my personal blog is an ugly, aged, idiosyncratic mix of Perl and PHP
(to paraphrase yoda, "When 6580 days old you reach, look as good, you will not, hmm?") but I have total control and the editor I use has some features I like - 
  • convenience forms for "quick hits" vs longer pieces (the former auto translates linebreaks into <br> tags) along with a simple tab interface with back button support
  • scaling images taking care of iPhone rotation issues - but keeping the fullsize images around as well (wish I had done that years earlier, the blog really is my best archive of cool stuff) 
  • Relatedly, it's not really well integrated into the editor, but my new CSS-only thumbnail gallery system is still pretty keen.
  • a simple but slick way of saving me from typing up <a href> tags - I prefer to be in raw HTML mode rather than markdown, but still, the idea of "linkify this" using the highlighted text as the URL if it starts with "http" or as the clickable text if not works super well and doesn't require any other UI bits.
and now:
  • support for cmd-s to save
The code for that is a bit temperamental to setup: some similar variants don't do the job but this worked for me:
jQuery(document).ready(function(){
    setupCmdSIntercept('#maintext_titleplus','#submit_titleplus');
    setupCmdSIntercept('#maintext_normal','#submit_normal');
    setupCmdSIntercept('#maintext_raw','#submit_raw');
});

function setupCmdSIntercept(sel,clicksel) {
    jQuery(sel).keydown(function(event) {
            // If Control or Command key is pressed and the S key is pressed
            // run save function. 83 is the key code for S.
            if((event.ctrlKey || event.metaKey) && event.which == 83) {
                // Save Function
                jQuery(clicksel).click();
                event.preventDefault();
                return false;
            };
        }
    );
}

Code modified from Pascal Bajorat's sample...
(oh the embarrassment - not only is it jQuery, but I can't even use the $ short cut because of the way it's embedded in even older Perl)

Of course the more general "edit any file on any of my subsites" edit system I refreshed last spring is going great (and probably why I longed to put the cmd-S support in the blog system as well.) The UI is idiosyncratic, but it's removed like 85% of my need to use an FTP program or ssh to do work (file upload, file deletion, and making directories are where it goes above and beyond the normal bounds of a browser based text editor)