Swipeable Cards: Live Code Session – Supercharged


[MUSIC PLAYING] PAUL LEWIS: Hello, and
welcome to Supercharged. I guess it’s the live edition. I don’t even know
what that means, but we’re stood here nonetheless
on the set of Supercharged. I’m Paul. Well, last time I
did a Livestream, I did an image
zoomer element, and I said at the end of that, what
do you want me to do next? And you all went,
swipeable cards. I actually put up a
little poll, and you voted for swipeable
cards, so that’s awesome. So that’s what I’m
going to do in this one, or at least attempt to do. And I have a little bit of
help in the form of Surma. SURMA: The form of
Surma, that is me. I’m here basically to monitor
the chats that we have. We’re going to have a chat
on the Livestream on YouTube, but mostly I would like
to ask you to move over to the Slack Channel that I
created on the Chromium Dev Slack. Slack is a little
bit more comfortable, and we have actually an archived
version of the chat afterwards. So if you want to chat
with us, and actually influence the way that we do
this, join us and talk to us. PAUL LEWIS: Influence it. That was a good idea. Swipeable cards, then. SURMA: Yeah, before we
start, I wanted to ask you, what even is exactly
a swipeable card? Because the term itself is
not a really self-explanatory. PAUL LEWIS: No, no. Actually, when I put
the poll together, I was like, I’m not sure what
I’m actually asking here. But I thought, swipeable cards
seems like something decent. Then it turns out
that Polymer actually has a swipeable card element. SURMA: Oh, that one. PAUL LEWIS: So it’s
like dismissible cards, I think is the way– SURMA: It’s the thing we have
in Google now, for example? PAUL LEWIS: Yeah,
that’s the one. All right, that’s what
I’m going to go for. Right. Well, enough chatter, let’s
get on with some code, because that’s why
we’re all here. So what I’m going to,
I’ll dive straight in. I’ve got my editor
open and, to be honest, all I’ve done so far is
just fire a little server. Unleashed a little server there. A little server. Get that right. Right. Let’s make an index HTML. So doot. There we go. Swipeable cards. Why not? Let’s just do some HTML
to begin with, why not? Div class equals card. I’m going to put them
in a container, I think. Yeah. That means I can have something
that’s a bit more responsive, I think. Let’s do that. Div class equals card. There we go, one, two, three. Right, let’s pop in– we
don’t need the manifest, because I’m not
using that today. So link rel=”stylesheet.”
href=”cards.” That’ll do it. SURMA: So I mean, with the
goal that you have in mind, my immediate idea would be to
have listen to touch events, use transforms,
and then animations to do the dismissible thing. Is that what you’re going for? PAUL LEWIS: Yeah, totally. SURMA: All right. PAUL LEWIS: I’m totally
going to go for that. Let’s see what happens. You never know. HTML body. Let’s see. Margin, zero. Padding, zero. Background, need one of those. Let’s have it do a card–
whoa, where did that come from? A card container. With width 100%. Oh, let’s see. Max width 450 pixels. We want some padding
on the sides. And I’ve got a border
bos, so that’ll be OK. Padding of 16 pixels. So that’ll be–
then in the card. Let’s say background white. And do border,
radius three pixels, because what’s that like? Box shutter, that’s what I want. I want a box shutter,
because I want these cards to feel like they
sit off the page a little bit. So we’ll do 0 in x. I will do 3 pixels and
we’ll blur it by 4 pixels and we’ll do an
RGB of 0.0.0.0.3. And let’s put a margin of
20 pixels, and then nothing to the side. Is that going to work? SURMA: Take a look. PAUL LEWIS: No. Oh, I didn’t put a height on it. SURMA: There you go. PAUL LEWIS: Height, 200 or 300? 200. 200 pixels. Yay! We’ve got cards. We have cards. Good, all right. We’ll put a margin on
the center line for now. Margin zero auto. Cool. We have cards. Let’s label them. SURMA: You’ve really
memorized the material styles, didn’t you? PAUL LEWIS: Well, you know. Card one. Hang on, we can do
some friendly names. Oh, lets just do Das Surma. Areotwist. SURMA: Who gets the
last card, then? Want to go with
a Kinlan or bond? PAUL LEWIS: I’m going to
go to with the Kinlan. Kinlanimus Maximus. Let’s do display flex,
align-item center. Justify-content, space around. That should put the text
right in the middle. SURMA: Nice. PAUL LEWIS: And– SURMA: I want a font. PAUL LEWIS: So do I. I looked
at that, and I was like, oh. Ariel. Font size 30 pixels? Color– we should have a
color on there as well. Yeah. Hey. SURMA: So we’ve got cards. We’re halfway there. PAUL LEWIS: Yeah, because
that’s the hard bit. SURMA: Nice try. Nice try. PAUL LEWIS: Well done. Write new file. Let’s do cards.js. Now, I will need to
put that in here. Script source equals cards.js. SURMA: And this is where
the juicy bits come. This is the JavaScript. PAUL LEWIS: Yeah, this is
the bit where I probably get it really wrong. So let’s say use strict. And I’m going to class
Cards, because I like that. And I’m going to the
window.addEventListener. I’m just going to do this
the lazy way for now. new Cards. All right, I will
do a constructor that says console.log. “Hello world.” “Hello
o-world.” “Hello world.” There we are. Ta-da. SURMA: And the nice
thing is, we don’t even need Babel or anything,
because Chrome has support for [INAUDIBLE] at this point. That’s so convenient. PAUL LEWIS: There we go, OK. You know, what I should’ve
done at the start. You know, I’ve been
really thinking I could have done js and hit tab. See, I’ve already
done all that before. Oh, I’m so dim sometimes. There we are. There we go. OK, right. So let’s think about this. this.cards. I want to pick up a
reference to all the cards, because I’m guaranteed I’m
going to want them later on. So document.querySelector(). Anybody asking any
interesting questions over on? SURMA: So far, we got nothing. PAUL LEWIS: We got quiet. SURMA: People are
watching, though. PAUL LEWIS: Hello everybody, hi. SURMA: Thanks for joining us. PAUL LEWIS: If you’re
just tuning in, because you might have
been a few minutes behind, we’re doing swipeable cards. I’m doing the coding,
he’s doing the chats stuff and making sure that I get
interrupted every so often so I lose my train of thought. That’s his gift, to me, to you. SURMA: You’re just in time for
the actual interesting part. PAUL LEWIS: Yeah, because I
have done a bit of styling. You see over here, this
is what it looks like. Some cards. How exciting, some cards. But what we need
to do is obviously make them behave properly,
which as Surma says, the fun and interesting bits. I’m actually going to go
into the device mode emulator here in the tools,
because what I want to do is I want to switch on–
actually, do we have touch? We do, under here,
I think you can do. Or is it not in there? SURMA: They moved it,
I don’t know where. PAUL LEWIS: You
don’t know where? I tell you what I’m going to do. SURMA: Just go for a phone, it
will automatically enable it. PAUL LEWIS: OK, I’ll do 6P. Now everybody’s got touch
here, which is cool. So that’s good. Because that’s what I wanted. So normally what I do when I– SURMA: You have been corrected,
you want querySelectorAll. PAUL LEWIS: Oh, yeah. SURMA: Bug caught
by the audience. Yeah, thanks guys. PAUL LEWIS: That saves me a
lot of heartache later on. So I’m going to do onStart,
because later on I’m going to want these to be
reused for touch and mouse, so I want to be
like onTouchStart. onMove, because I’ll be
on mouse move as well. And onEnd. And I know what I’m like. I’m going to want to
defer these with a request animation for them, so I’m
just going to have an Update function here. Why can’t I type today, Surma? I say today. I’m often, I’m just like
typo, the king of typos. If such a rule existed,
I would inhabit it. onStart. I do this quite a lot. I rebind these, because only
inside of the callbacks, this would refer to the
element, the target, and I don’t want that often. I want to kind of
operate on the function, or in this case, the class. So I tend to rebind them. So I’ll say this.onStart. Take it from the
prototype, which is where this would exist, and
bind it to the actual instance. It’s just a foible
of how I do my code. SURMA: Advanced js trickery. PAUL LEWIS: It’s not really. It’s just how we roll. All right, so we’ve got that. I want to update as
well, this.update=this .update.bind(this). There we are. Awesome. So these will all be
bound to an instance, and I’m guaranteed I’m
going to want to do that. And addEventListeners. I tend to do this pattern
as well, where I basically normally have to
remove eventListeners and add eventListeners as
well, so that I can just do that all in one place. So I’ll say document. When I’m doing stuff
like this, I always touch the document
rather than the thing that I’m moving, because often
I’ll want to kind of delegate and have just one listener
that I’d do an early exit from, if it wasn’t the right thing. But everyone is a bit different. Everyone’s a bit different. And, document.addEventListener
(‘touchstart’). this.onStart. Document.addEven
tListener(‘touchmove’). SURMA: I mean, that’s the point. Usually you don’t
listen to one event, you have like a whole collection
of things you need to bind to. That’s kind of nice to have
a function that contains all the these binding actions. PAUL LEWIS: Yes, exactly. I like how you’re the voice
of reasoning amongst this, because I’m trying to
talk, and code, and think, and I can only at
least do one of them, and normally none of them. So that’s fine, so let’s see. Now it’s a touchmove–
so a touchstart, we’re going to have to do
event.preventDefault here. Because otherwise, we
get throttled back, and we’re going to want
to get all of those. Oh yeah, OK. So, if event.target.– this
would be my early exit. classList.contains(‘card’). Yeah, so if it doesn’t, return. So we only– Console, let’s
just check how it works. Card. That didn’t work. Why did that not work? OK. Let’s do console.log. There we go. That didn’t work. All right, oh, because I
didn’t call addEventListeners. SURMA: That’s what
I was about to say. Also, we just got to asked
why querySelector and not getElementsByClassName. And I think that’s
really more a question of taste than anything else. It might be a little bit
more performant to use getElementsByClassName,
because you don’t need to parse the CSS selector. But apart from that– PAUL LEWIS: I wouldn’t
bet against any of the vendors, any of the
browsers at this point, on that topic. SURMA: That is a good call. PAUL LEWIS: Because,
you could probably find one situation where
one’s faster than the other. I think I would say this is
just a convenience thing. SURMA: I agree. PAUL LEWIS: If you
did anything else, it would be like, you just
got possibly a micro benchmark ahead. SURMA: Personally, I
prefer, just prefer, the very terse syntax
of CSS selectors. Where a hash tag is an
ID, the period is a class. PAUL LEWIS: It kind
of works for me. This would work in
the situation as well. So right, we’ve got a card. If I tap outside it, is that
going to work down here? Yes. The event is there, but only
that one registers the card. SURMA: You should zoom
in on the dev tools. PAUL LEWIS: I’m going to
zoom in on the dev tools. It doesn’t want
me– there we go. So let’s do that again. Let’s get a card. Down there– not a card. Card, not card. Card, not card. We know we’ve got a card. SURMA: Well done, Paul. PAUL LEWIS: Thank you. SURMA: Well done. PAUL LEWIS: Thank you. Right. So we know we’ve got that. So what I’ll do
is I want to keep a reference to whichever
card we’ve got, so I’ll call that target. I’ll initialized that to null. And I’m going to say onStart. So if we’ve got
past this, we can say that we know that
it’s event.target. And that’s good. And I think what we can do
is, we can also track the– because we want to
track the x position. So let’s say this.startX=0. And we’ll do the
current x as well, which will be what
we keep up to date. I’ll explain myself in a moment. My thoughts are ahead
of my explanation. Right. What you want to do is
you want to say evt.pageX, or evt.touches zero.pageX. So we know where we started,
because what we want to do is we want to move the card an
absolutely amount each time, from the marked
starting position. So we can start by saying well
the currentX is definitely the startX. SURMA: Because we are on start? PAUL LEWIS: Yeah. Because we’re going on start. But, during this, on move, we
say the currentX is now that. And we want to say, if we’ve
not got a target, return. And onEnd, if we’ve
not got a target, we want to return there too, so
we don’t bother with anything. So let’s see this. We got startX, we’ve
got a currentX. And I’ll tell you what we’ll
do is we’ll just call– no, we don’t need to call. I’ll tell you what we’ll
do, what I’m going to do. I’m going to go into
a permanent loop. So, I don’t want to
say permanent loop. I mean normally, and I
might get time to do this, depending on how
everything goes. Normally, I wouldn’t just
go into like this kind of permanent request animation
frameloop for something like this. I’d do it for, as soon
as you start twitching and start the animation
frame looping. And then when it
finishes its animation, it either dismisses, or it
reset back to the middle. I would then kill
the animation frame. But in this case
just for convenience, I’m just going to keep
going and do this. SURMA: So this
means we will always be in sync with the frames,
and not miss repositioning? PAUL LEWIS: Yes. That’s the one. Right, so in here,
what I’m going to do is I’m going to say– SURMA: Shouldn’t you be
saying, if not this target? [GASP] PAUL LEWIS: Yeah. What that from– was that you? SURMA: It was me, but someone
just said it in the chat as well. PAUL LEWIS: So you can claim it
though, because they can’t see. So you can claim that. And you can be like, oh– SURMA: I’m so smart. I saw it after. const. Let’s see, like screenX. We’ll call it that. Is the currentX,
minus the startX, And then we can
say this.target– in fact, what we want to do. If this is going to
run from the start, we’ll need to say if
there’s no target, return. All right. So we can do style.transform
equals, and then I’m going to translate x, and
then stream x to px, bop. See what happens. Nothing. Why do nothing? It’s doing nothing,
that’s not good. All right, let’s find out why. Well that’s going
to fire in there. SURMA: Every frame. PAUL LEWIS: That’s why, because
we fire it and it early exits, but it doesn’t request
the next frame. Hey, there we go. So we’ve got something
that actually animates, which is brilliant. Let’s have a look. What I want to do is I
want to check the painting. So it’s, yeah, this is what I
thought was going to happen. Every time we move, we
just update the transform. And that means
that this by itself doesn’t qualify
for its own life. We show lab orders. There’s no orange box
around this, right? SURMA: And we love
our orange boxes. PAUL LEWIS: Especially
for something that’s going to
transform, we want to have its own orange box. So here’s what we’ll
do, is on start, if we’ve got ourselves
a target, we will say, this.target.style.willChange
equals transform. And that will give
it its own layer. And we could do it
for every single– SURMA: Why don’t you just
do it in the styles, though? PAUL LEWIS: Right, because
if I have 1,000 cards, then I’m going to create
1,000 layers. SURMA: Good point. PAUL LEWIS: So you could
definitely put this in the CSS, but I would say– SURMA: So you’re just promoting
it at the touch event once, then while the
touch is going on, you keep it in its
own layer afterwards. PAUL LEWIS: Yeah,
and this would be something I’d keep an eye on. If I felt like this was
becoming an issue when you tap on mobile,
particularly, if it took a while before you got that
new layer, then I would consider pre
promoting the ones that are on screen kind of thing. SURMA: That makes sense. PAUL LEWIS: But at this
point this will be– SURMA: That is, like, a
version 2 kind of feature. PAUL LEWIS: Right. So now, all being
well, you can see it’s got its own layer there. Because as soon as I tap on
it, it gets its own layer. And you can see now,
we’re not painting at all. SURMA: And that is important,
because performance. PAUL LEWIS: It is called
Supercharged, so are the clue’s in the name, buddy. Yeah, so we’ll move
that, and there we go. Now, if, let’s see. On end, oh, what
do you want to do? SURMA: I think you
want to unset target. PAUL LEWIS: No I don’t,
I actually don’t. Because this update requires
that the target exists, right? If it’s got no target
this will early exit. But when we let
go, we might want it to slide back to the middle. SURMA: Yeah, right. PAUL LEWIS: OK, I
want to do is I’m going to say, I’m
going to turn this, because I know where
this is going to go. This is going to go to the
easy, easy version of the world. Here we go. Right. If this.draggingCard– yeah,
OK, let’s call it that. Yeah, fine. I know, right? Let’s see, so at
this point we’re going to say you’re
not dragging the card. But on start, we will say that
you are dragging the card, and we know definitely
that the end here, you’re not dragging the card anymore. So that’s OK,
that’s all working. WIA, working as intended. Right, if you’re
dragging this, this will need to become
this.screenX. So we’ll do this.screenX
equals zero. This is fine. So what we want to do is,
so this should still work. All being well, they
should still work. Yeah, it does. When we let go, we want to
say this.screenX plus equals– so this is, you come
across this season before, this is where you
want to be minus where you are all over some value. And it basically eases,
slows down all the time. So that’s cool. So I’ll do zero,
because that’s where we want to be, minus
this, all over ten, and I’ll put that in– SURMA: Parentheses. PAUL LEWIS: Parens. Brackets, I call them. So I initialized it to zero. Did I Initialize it to zero? I did. SURMA: We have been asked
if your should reset all change when we are done. PAUL LEWIS: Yes, yes. So at the moment, everything
see actually at the moment that everything gets. The card gets
promoted, and what I do is I’d wait until this
animation finished like, that slide in at the end. I’d get rid of that. OK. But for now,
because basically, I need to detect when
that’s finished, and then I’d get
rid of it there. SURMA: That makes sense. PAUL LEWIS: That
little [POPPING SOUND], that’s me adding a sound effect. It doesn’t actually do that. SURMA: It’s an upcoming feature. PAUL LEWIS: Yeah, it’s
an upcoming feature. OK, so the screenX is going to
move itself back to the middle. However, what else
do you want to do? SURMA: I think you need
to implement, like, the hump that you have
to move the card over so it continues going out and is
been removed afterwards, right? PAUL LEWIS: All right,
so in which case, the way I would do that is this. We’re going to need to
know this.targetBCR, bounding client rect. I’m going take some measurements
of the target when we first pick it up. So on start, this
target is that, and it is this.target.getB
oundingClientRect(). SURMA: And in case
someone doesn’t know, target get bounding
client rect is a particularly expensive operation. So it’s good to do it once, but
not every frame or something. That’s why we do it on start,
and not in the update function. PAUL LEWIS: Yeah, wouldn’t
want to do it every time. But it basically uses
the layout information that the browser already has. So you can call it at
the start of the frame, and it would be cheaper
there, but you’re right. And there’s no reason
for us to do this. SURMA: The card doesn’t
change its dimentions. PAUL LEWIS: No, exactly, it
doesn’t change dimensions. That’s all we
actually want it for. You could use offset
width and offset height, I just prefer this because I
get an object back with them all in rather than separate things. But you could be like,
you know, offsetWidth and put that as my new. But I’m not going to do that. So what we need to
do is, let’s see. So be on end, I think. Yeah, OK. So we are assuming that you
want to go back to zero here, but you might not want
to go back to zero, you might want to
go somewhere else. And we’re going to decide
that in the on-end. We’ll do that here
if the– right. targetBCR.width. So we need to know
how far you’ve moved. So let’s say we’re going to
repeat ourselves a little bit. So what we’ll do is when you
release, we’ll say the– ooh, interesting. We need to grab this. So well grab this again,
so we’ll update this. And we’ll say, blah blah blah. And if the Math.abs of screenX. So if you’re
negative or positive, we just want to know how far. So we just want the
kind of absolute value. Some people like to do screenX. They do like, a
binary or with 0, and that’s the equivalent
apparently to– SURMA: Oh, the
bit-level hackery to– PAUL LEWIS: Yeah, I just use
Math.abs because then I can– SURMA: I prefer the more
expressive version as well. PAUL LEWIS: Because if
I read it in six months, I’m going to be like,
Paul, what are you doing? You’re not making
any more sense. Like, by 0.4. So if you’ve gone more than
4/10 of the width, 2/5 of width, then we’ll consider that one. That’s completely random. I’m just guessing. SURMA: So if it’s
a constant, you could move it to the top
of the class and something. But for now– PAUL LEWIS: For now, no. SURMA: We don’t. PAUL LEWIS: No, no. Why would I do that? So what we need to do is we
need to do this.targetX, which is going to be where we’re
going to actually aim to send the card. And we will say that
we assume that you want to go back to the middle. So, in fact, this
should still work if I need to initialize
it up here, don’t I? Yeah. So this should work still. Doesn’t pageX is undefined. OK, oh yes. Because funnily enough, when
you on end in the event, there is not a touches,
there’s something else there is– let me
find out what it is, but it’s not the
same as the others. SURMA: And that’s when
the good old console law comes in to help– PAUL LEWIS: I know, some
people like debugger and stuff like that– SURMA: No, we don’t. PAUL LEWIS: Yeah,
so that’s the thing. There is something you come
query to find out what changed, if it makes sense. I’m going to assume that the
last known value from the on move is good
enough at this point. SURMA: That’ll be fine. PAUL LEWIS: Yeah,
it should be fine. And even if it’s
not, it will be fine. So that goes back to the middle. So now we’re just deciding
to actually send it off to the left or to the right. So we can do that with,
if you’re over that, we’re going to set the target
to be screenX is less than 0, or no, it’s still over there. If you’re over 0, we
want to send you– and I know what I’m going
to do in a minute, I think. I’m going to make it fade out. SURMA: That seems sensible. PAUL LEWIS: Yeah,
so let’s do that. So if you go past
there, boop, yeah. Then it can go that way. Oh, OK. It’s interesting. It’s quite far, isn’t it? Feels like I have
to go a bit too far, so I’m going to make
that down to, like, 0.25. Yeah, that seems good. I’m going to switch off this,
because I don’t need this anymore. Yeah, that feels– and then
if you don’t go far enough. Don’t like it. Going to say about 0.35. Number fishing, there we go. That feels better. SURMA: Magic numbers
are best numbers. PAUL LEWIS: Yeah. I know, right? So how– oh, I’ll tell
you what we can do. We can, because we’ve got the
width up here from target BCR. So we can basically say
this.screenX over the width, and that would
normalize this now. So we can then say– that,
in fact, could be a const, couldn’t it? Opacity equals one minus, and
then, so as the screenX hits the width, it should be one. So this would be– SURMA: The fraction tells
us what fraction of the card is still visible on screen. PAUL LEWIS: Kind of. It’s how much, yeah. SURMA: Or how much, yeah. And we turn that
into opacity, so when it reaches its
endpoint, it’s going to be completely
transparent, translucent. Whatever the word is. PAUL LEWIS: That’s all of that. Opacity, right. Style target opacity is
opacity, so that didn’t work. That’s depressing. There it is. OK, so you can see how it goes
transparent, comes back in. Oh, yeah. SURMA: I think you absolutely- PAUL LEWIS: Oh, yeah. It’s not– Math.abs again. You know I’m going to
do as well in a moment? You see how it’s got quite
a linear feel, right? SURMA: Yeah. PAUL LEWIS: Yeah, well– SURMA: You might want to
curve it a little bit. PAUL LEWIS: Yeah. So what I’m going
to do is I’m going to call that const normalized. How’s everybody
doing on the chat? SURMA: They’re fine. PAUL LEWIS: They’re good? SURMA: Right now they don’t
seem to have any questions. But if you have any– PAUL LEWIS: You can ask. SURMA: And as I say that, will
we publish the code afterwards? Yes, we will. PAUL LEWIS: Yes. The last livestream, the
code went up onto GitHub. And it’s
github.com/googlechrome, and get maybe get you to find
this and shove it in the– SURMA: Yes, I’ll
put it in the chat. We’ll also– PAUL LEWIS: But it’s
git– sorry, dude. github.com/googl
echrome/uielementsamples, I think this hyphenates. SURMA: Yes, you’re right. PAUL LEWIS: So
that has currently got the image zoomer in there. Which, incidentally, Adios Mana
used in his smaller pictures app. So if you actually
want to see it in a more production context,
you can actually see it. He and I sort of
threw it into that app after the last livestream. Don’t know what we’ll do with
the cards today, but anyway. Surma’s posted it,
so that’s good. But anyway, back
to where we were. So I’ve got normalize
drag distance. So what I want to do is instead
of one minus one, what I’ll do is if I do Math.pow, and
let’s say if I squared it, then if it was at 0.5, it
would actually become 0.25. So you take one
minus 0.25, so you’re going to give it this
kind of curve like that. SURMA: The parabola curve. PAUL LEWIS: The
parabola curve, exactly. And the stronger the power,
the more it’s going to go poof, like that, which would be nice. In fact, let’s do it to quad? No, cube it. And then you can see
it hold, and hold, and it holds, and it goes just
at the end there, you see? So now it holds and
holds and holds, and it just looks a
little bit nicer, I’d say. Right, so actually now, we
have something that– yeah. The only thing I
don’t like is that. That’s not going fast enough. So if I divide it by four, it
should be a little bit faster. There you go. That’s cool. Ta-da. How are we doing? What else do we
need to– oh yeah. When you get rid of one, we need
the rest to shunt up, don’t we? and get it out of the way. Actually, you know what? I want to say– if
we’ve got a target, then we don’t want another
card kicking in yet. We kind of want to deal with one
before the next one kicks in. SURMA: That makes sense. PAUL LEWIS: Because
what we’re going to do is when we move them
up, we kind of want that animation to have completed
before we allow interactions again. So this now becomes
important for me to figure out how to actually
release the target back. OK. Let me see. Well, I’ll tell you what we can
do is, if not dragging anymore, so if we’re not dragging the
cart, that’s a good start. And opacity const
is nearly invisible. [SURMA LAUGHS] It’s all good. Opacity is less than that. OK, so if they’re not
dragging the card. If this is nearly
invisible, yeah. Then we can say this.target
equals null, right? And we can say this dot–
oh, before we do that, I’ll tell you what, let’s
just try this first. this.target.parent ta– SURMA: Tartet? PAUL LEWIS: Tartet. And then we have
Target.parentNod e.removeChild(this.target). With one t, Paul, one t. SURMA: So this is probably going
to jump, but it’s a good step. Also, we’ve been asked to
enable the FPC meter so people can see it’s actually 60 FPS,
which I think is a good call. It’s not visible, though. PAUL LEWIS: It’s not visible. Why’s that not visible? SURMA: I don’t know. PAUL LEWIS: Do I
have Canary on here? Google Chrome Canary. SURMA: Is it maybe
the responsive mode that hides it for some reason? PAUL LEWIS: Localhost
9.3.3.0, wasn’t it? SURMA: I think so. PAUL LEWIS: Let’s see. I’ll tell you what
we’re going to do. We got it responsive. I was hoping that we’d actually
get– oh, we get to touch then? SURMA: You have to go in
phone mode again, I think. PAUL LEWIS: No, I
didn’t want to do that. I wanted to– where’s
the device type? Mobile. Now I’ve got it, right? SURMA: Yeah, that
is very touchy. PAUL LEWIS: OK that seems gone. What were you saying? SURMA: FPS meter, and
zoom in on the dev tools. Provided we can actually
see the FPS meter. PAUL LEWIS: Yeah. Again, that seems OK. Right, let’s see if this works. Too far. Where– there we go. FPS meter. Doesn’t show. SURMA: It is responsive mode. Interesting. PAUL LEWIS: All right, tell
you what we’ll do then. Let’s add in mouse events. So mouse down, mouse
move, mouse up. Yeah. I think that should work. SURMA: For the people
who have just joined us or maybe came a little
late, what we’re doing is we’re implementing
swipable cards. Basically, we want to
use some JavaScript and some vanilla CSS–
the other way around. Some vanilla JS and some CSS
to implement dismissable cards on the web in a performant
and kind of pretty way. And that’s what you
can see on screen, and what we’re
developing right now. PAUL LEWIS: So kind
of we get the 60 frams a second pretty much. So there you go. Tell you what we could do,
it might be slightly easier to see if we take a
timeline recording of a bit of an animation. There we go, stop. So these bits here where we got
a dip will be probably, yeah. See, we’re actually seeing
animation frame five, so I think there’s an issue
with Canary not picking up the frames per second here. Because you can see
there’s a regular tick here of animation frames. Animation frame fired. Animation frame fired. Animation frame fired. So I think I’m more
inclined to say– SURMA: The frames might
actually be there, just dev tools may be missing them. PAUL LEWIS: Yeah, I think– SURMA: This is Canary,
so there could very well be a very weird– PAUL LEWIS: Well,
you can see that it is doing the right thing. Anyway, right. So yeah. So we need to release back– I’m
actually going to switch back to stable, because I’d rather. Because that was working
just fine for us. The thing is, when
this card comes back, I’m not releasing the– SURMA: Right, we’re not
releasing the target. So we can’t move anything else. PAUL LEWIS: So if it’s
nearly invisible, right. So yeah, I know what
I’m going to do. Const is nearly
at start equals– I know that is less than– SURMA: Take notes, people. PAUL LEWIS: I know. It’s nearly at the start. And if it’s nearly
the start, then we can say this.target equals null. I’m going to have a think
if there’s a better way to do that. Hm, nope. SURMA: Beautiful. PAUL LEWIS: All right. So that’s working. Like it. Do you know what
I’m going to do? When you get rid of one
of these cards like that, I feel like the other cards
should slide up into place. SURMA: Definitely, that
would be very nice. PAUL LEWIS: And similarly, oh,
do you know what I didn’t do? Since we’ve released the target
for this case, by the way, we should be saying
this.target.style.willChange equals initial. SURMA: They are some demotion
we’ve been waiting for. PAUL LEWIS: Yeah. target.style.transform
equals null as well. So we’ll put that back. So first thing we can
check, what we can do is in here, we will
go to your card. And you can see that,
yeah, we’re doing fine. And pop the transform
norm opacity one, could get rid of that opacity
as well, if you wanted. Layer borders,
you’ve been demoted. Pop. SURMA: Nice. PAUL LEWIS: OK, so that’s good. Here’s what we’ll do, is we’ll
switch off those for now. And so if you’re not
dragging the card– actually, no, if we did get rid of
your card, what we want to do is we want to say
this.cards cards for each, and you know it’s going
to need the cards. Card. And what I want to do
is I want to say let is after current
target equals false. And what I’m going to
do is I’m going to say, if card equals this,
the target, then I’m going to say that’s
true, I’m going to return. And then if it’s not after
the current target, done single like returns
everywhere else, why not here? All right. So now we know for any card,
when we get to this point, we know we’re after
the current target. So we can say
card.style.transform equals
this.targetBCR.height, yeah. Transform equals
translateY, and it without. So we’re going to translate
it to– there we are. Translate it down. That working? No, there’s errors. It doesn’t like it. What’s the error? This cards for each
is not a function, because it’s not an array. OK. SURMA: Array.transform
is your friend. Array.from is your friend. PAUL LEWIS: Do I have to? SURMA: Yes, you have to. PAUL LEWIS: Array.from
start cards. SURMA: I think in Canary,
you can now actually call for each on the
select all results. PAUL LEWIS: So it’s pushing all
these cards down by 200 pixels, which is correct,
except for the margin. And the margins are
collapsing because web. SURMA: Yes. PAUL LEWIS: So we need to
add in the margin I added, which would be 20 pixels. And I’ll hard code it, but I
guess you would do something a little bit fancier here. There you go. So now all our cards and– SURMA: Oh, that was interesting. PAUL LEWIS: Yeah, I think I
know what’s going on here. SURMA: Oh, you’re
resetting the transform. PAUL LEWIS: And I’m
also releasing this. And I don’t want to
release this yet, because– SURMA: You have to
animate this later. PAUL LEWIS: We have
to animate them. On the end of that animation,
we’ll release the target. OK. So card.style.transition
equals transform– actually, I’m going to do it slow. Three seconds. cubic bezier, why not? 0.311. That’ll be a decent curve. SURMA: You just pulled
that right out your sleeve, didn’t you? PAUL LEWIS: I did, really. card.addEventListener
on transition end, because I want to
unhook it afterwards, so I have to make
it a named function. So I will say, const on
transition, and equals. SURMA: You were just asked, as
you’re typing the word const, would you suggest using const
whenever possible, and not only when the variable
actually changes over time? PAUL LEWIS: Yes. So I’ve gone full circle
recently to– not full circle, but I’ve sort of
iterated on my thinking. I don’t know how you feel
about it, but basically, yes. Const, I kind of go well. If I didn’t intend
for this to change, and I know when
I’m declaring it, actually, I think
this thing should, for the life of this
function, or whatever, it should remain the same value. So if so, yeah, constant. And I initially made
a mistake, because I used to think that if
you had, like, const x equals some object,
then you could mutate a property on that object. But that’s not true, it’s just
a reference to that object. And then so, yes,
and fall back to let you know if the value’s
going to change, and then fall back to va. I haven’t used va
in a good long time. SURMA: Me neither. PAUL LEWIS: So I’ve
found that const and let gets me all the
way for the stuff I’m writing at the moment. SURMA: In case
people don’t know, let declares a variable
in the block scope. It means it’s only valid
between the surrounding two curly braces. Var, however, is
function scope and will be valid throughout
the entire function, even if it crosses
curly braces boundaries. PAUL LEWIS: Yes, right. So, basically we’re going to
say– because these are all going to happen pretty much–
don’t want to do that, do we? We want to get rid of
that straight away. So all these cards will
get the same transition, and I guess you could basically
do it to one of them, maybe. I want to do it for all of them. SURMA: Yeah, I think so, too. PAUL LEWIS: It’s OK,
it’s really fine. I mean, it’s just going to
overwrite null a few times, but chances are it’s going to be
fine because all the cards are going to move in a block. So all being well,
we’ll see them– ooh. What’s going on there? OK, yes, oh, I know what it is. We set them there, and then
we tell them to transition, but we don’t want to do that. What we want to do is
we transform them down. We want to request an
animation frame, so that style, that transform takes hold. And then we’re going to
switch on transition, and then we’re going
to set.style.transform equals none, like that. So we assigned them 220
pixels, in this case, down. And then we wait a
frame so that takes hold, switch on transitions,
and transform them up. SURMA: So we wait
for the browser to realize that there
are actually now is a transform being applied. PAUL LEWIS: Remove
child of null. So it doesn’t like remove child
of null, which is interesting. I wouldn’t know why. Doesn’t like it. Does not like. Well, it’s close to there. So it’s doing it
on every single– SURMA: [INAUDIBLE] property. So that means that parent
node is not defined. PAUL LEWIS: I have no idea why. So hang on. If you’re not dragging
the card, there’s not any visible
cause for each card. This seems OK. Because of this, right? Because it’s the only
place where we call– SURMA: It has to be. PAUL LEWIS: I
wonder if it’s this? Let’s just comment that
out, see what happens. Nope, not that. Just check it’s this, then. It’s definitely that. SURMA: Interesting. PAUL LEWIS: OK. Because once it’s
been detached, why would that run more than once? It’s nearly invisible. Oh, because it’s still– OK. This is going to
run multiple times. So there’s a point where we say,
right you’re nearly invisible. But we still have a target. And so I guess, then,
it’s this parent node. After it’s been removed once,
there’s no parent node anymore. That’s null. So you can’t be child of null. So I need to say if it’s got a
parent node, like so, you can now tell it to remove child. And maybe the level will just
be super uptight about it. There you go. Now we can’t do anything
here until that’s finished, and then, oh, can we? Yeah, then we can grab that. Those are really slow now. OK, so that means that on
here, when this is finished, we need to say
card.style.transition is none, all being well. So all being well, that
goes, can’t do anything. And now that one goes, right. SURMA: Nice. PAUL LEWIS: Speed it up. 0.15. SURMA: We have no cards anymore. PAUL LEWIS: We have
dismissible cards, sir. Look at that. Oh, there was a jitter then. There, did you see it? SURMA: Yeah, I did. What happened there? PAUL LEWIS: One, two. SURMA: Is it because
of the third card? PAUL LEWIS: Let’s find out. Slow it down. SURMA: Slow it down. PAUL LEWIS: So that goes. Mm. There’s one. See, that’s weird. Why is that doing that? SURMA: The transition
is still set. It shouldn’t be. PAUL LEWIS: It isn’t. It’s because– it’s not
the block scoping, is it? Do you know what
I’m going to do? I’m actually going to
do for let i equals 0, i is less than
this.cards.length, i plus plus. SURMA: Good old for loop. PAUL LEWIS: I know, right? And then I’m going to do
const card equals this.cards. Now the reason this
is going to work is because the let is scoped
to this particular iteration of the for loop, which old
school var would actually update the var to
the nearest function. So when the
callback’s fired, this would refer to a different
card or something. Anyway. SURMA: Very intricate detail
of ES 6 let and for loops. PAUL LEWIS: Oh, unexpected. What did I do? SURMA: 40. PAUL LEWIS: It’s,
yeah, there we go. OK. Now it’s broken, it’s
really broken again. I wonder why. Interesting. It thinks it’s– no, OK. Let’s have a look. How’s everybody
doing on the chat? Everybody OK? SURMA: Yes. PAUL LEWIS: Everybody happy? SURMA: People are learning about
ES 6 and CSS and everything. PAUL LEWIS: Oh, cool, good. SURMA: People have
been asking if there are similar sessions
for Android, which I think we should forward to our
colleagues on the Android team. PAUL LEWIS: You know what,
if you enjoy that, you know, why not? SURMA: Let them know. PAUL LEWIS: Let them know. We can do that. I mean, they’re
the just out there. So we can do that, can’t we? SURMA: I thought you were saying
we can do the Android session. I certainly don’t– PAUL LEWIS: No, it’s been
a while since I wrote Java. So there we go. Right, so where we? We were saying, if this is–
I’ve lost my train of thought. SURMA: You had an error that
you want to investigate. You mean that the cards didn’t
slide up anymore, right? PAUL LEWIS: Yeah, right. So we know that it should nearly
be invisible at this point, or is it? So let’s have a check. Cause this can’t just, oh,
it’s because of the return. Continue. It should be
continue, not return. SURMA: That is one of the
dangers of refactoring– PAUL LEWIS: Yeah. [INAUDIBLE] SURMA: Suddenly it
all makes sense again. PAUL LEWIS: Here it goes. SURMA: No jitter. PAUL LEWIS: No jitter this time. SURMA: Look at that. PAUL LEWIS: Yeah, I think
it was a scoping thing. Last one was strange, though. Let’s make it a
little bit faster, because that’s just pretty– SURMA: It’s painful. All right, looks good. PAUL LEWIS: See,
now that’s not good. SURMA: The transformer’s
still set, apparently. PAUL LEWIS: Yep. SURMA: That transition, I mean. PAUL LEWIS: Yep. So let’s think
about why this is. I think it’s to do
with the card, I think. SURMA: Well, yeah,
the card variable is bind to a const that changes
on every for loop, right? So you only remove
transition on– PAUL LEWIS: But it
should be doing it for every single one of those. SURMA: But this is a closure
that only binds this, it doesn’t bind card, right? PAUL LEWIS: Card should
be fine, this should work. Well, it should work
but it doesn’t work. So since it doesn’t work,
let’s have a look at what console.log(). We should see at least two
cards, and then one card. So what do we got? SURMA: That is a lot of cards. PAUL LEWIS: That’s
a lot of cards. SURMA: We should
maybe add a class so we can distinguish
them from one of these. PAUL LEWIS: You
can see the text. SURMA: It’s all the Kinlan. It’s all the last card. PAUL LEWIS: Yeah, OK. We need to get to the
bottom of why this is. Why, why, why? SURMA: Well, my
theory was that you’re looping over all your cards. PAUL LEWIS: You’re
my rubber duck. SURMA: I am your rubber duck. PAUL LEWIS: But you’re my
rubber duck that talks back. OK, if you never come across
the idea of the rubber duck, this was a blog post, wasn’t it? A few years ago. SURMA: I think so, yeah. PAUL LEWIS: Somebody
was like, that I keep a rubber duck on my desk. And the reason I keep a
rubber duck on my desk is because when I get stuck, I
just talk to the rubber duck. And talking to the rubber duck
helps me solve my problems. And I guess he’s my rubber duck. SURMA: Usually you have to
introduce yourself politely to the rubber duck first. PAUL LEWIS: He does not
quack when you squeeze him. What a disappointing duck he is. SURMA: I’ll buy the
upgrade for the next time. PAUL LEWIS: Quack quack. Could’ve just done that. Quack, quack. Is this so hard? Unbelievable. SURMA: I’m sorry. PAUL LEWIS: OK, we need
to figure out this one. All right. What is the cause? Why are we seeing so many cards? OK, let’s– oh,
hang on, hang on. Right, this should be
declared outside the for loop. We don’t need to
have so many of them. That’s one thing, right? Card is not defined,
of course it isn’t. SURMA: How could it be when
it’s all outside the for loop? PAUL LEWIS: Yeah. However, we can do function
evt, and we can say evt.target. Where’s the card? Oh, come on, Paul. OK. Now we got the
other problem, which is that this no
longer refers to, OK. So we’re just going
to do this, then. SURMA: That is usually the
beauty of different arrow functions, to bind this
for you automatically. PAUL LEWIS: Well,
they don’t bind it, it just falls
through the– anyway. Yeah, I’m going to be pedantic. Me, pedantic? Strange. Still not right, is it? Why is that not right? See at this point,
we shouldn’t have a transition on this, right? Because we set transition
evt.target.style.transition. That should have been
totally, totally resolved. Card.addEventListener, and
I spelt that correctly. Transitionend. You know, it is firing. SURMA: It’s been
called, right, yeah? PAUL LEWIS: OK, so here’s
what we’re going to say. card.innerText– this is
exactly how I debug, by the way, in case anybody’s wondering. With a lot of– SURMA: This is how you
and also I actually work. It’s not very glamorous. PAUL LEWIS: No, it’s really not,
but we get there in the end. Oh dear. card.innerText,
adding event listening. And then I’m going to just go. Fired. Oh, that was no good. Right, this is the problem. This is the problem here. Why are we getting
so many of these? So oh, it’s, yes, ahh. It’s exactly the same
problem as before. So we need to say around this. Every time it comes into
this nearly invisible, it’s executing this block. Which means we’re getting
lots, and lots, and lots of event listeners– SURMA: Oh yeah, of course. PAUL LEWIS: And only the
first one is being removed. Yeah, I know, right? SURMA: Now it makes sense. PAUL LEWIS: Right. So what we need to do is we need
to say, if this is like this. So if you finished dragging, OK. User has finished
dragging, there we go. Think we got it to the
bottom of this one, dude. If the card is nearly
invisible, nearly gone– SURMA: If Paul starts
commenting his own code, now you know he’s being serious. PAUL LEWIS: In six
months, I’m going to look back at
this code, and I’m going to be like,
what was I thinking? I don’t believe in
self-documenting code. Not my code, anyway. Maybe yours does, maybe
you’re all smarter than me. SURMA: I think nobody
should believe in that. I’ve seen very few examples that
actually are so good in terms that it don’t need
documentation after a while. PAUL LEWIS: So if there
is still a target, and the target is still attached
to the DOM, ooh, that’s close. I’m going to, boop, there we go. If it’s still attached to the
DOM, we execute this code. Oh, Paul, Did that work? No, I didn’t. There you go. Right. Tell you what we’re going to do. That’s just bad code. So what we’re going
to do– yeah, I know. I’m going to return, OK? So if we going to
target, and the target has a parent who would return. And what we’re going to do is
we are going to– actually, I’m going to bring that back in. If there is no target– oh,
you can invert it that way, can’t you? I’ll just do it the obvious way. SURMA: Going to de
Morgan, or what? PAUL LEWIS: Not and is the same
as or if you’ve got multiple– SURMA: Yeah, de Morgan law. PAUL LEWIS: OK, there you go. And I know how to
use it, I think. SURMA: Can be very helpful
with long if expressions. PAUL LEWIS: Yep. Right, so if it’s
nearly invisible, if we haven’t got a target or
we haven’t got a target parent node, then basically
what we’re going to do is we’re going to
say I’m going to go through this whole rigmarole
here, and that may be enough. So we only added
two event listeners. Card is not defined. Where’s the card? Oh, it’s on the transition end. There we go. I think we’ve got it. SURMA: We might have it. PAUL LEWIS: We might have it. I think we might have it. Wow, what a debug. SURMA: Let’s speed
up the transition and see if it feels right. Maybe add some more
cards, as well. PAUL LEWIS: Zip, zip, zip. You have to make
that sound effect. It works! SURMA: Nicely done. PAUL LEWIS: Sorry. It’s very exciting. SURMA: We have written
code that works. PAUL LEWIS: I know. Dear diary, wrote
code, it worked. Let us add some more. Let’s just add– SURMA: Let’s add our
colleagues from– PAUL LEWIS: That’s a bad idea. What am I doing? Right, go on. Add a colleague– no. They didn’t come into
the room here with me. SURMA: That’s true. No, I mean like the
Totally Tooling guys. PAUL LEWIS: Oh. The Addyooooo, and
Guanty McGaunty Gaunt. Those are technically correct. SURMA: Yes. That is their legal names. PAUL LEWIS: There’s some guy I
worked with, Jack Archibungle. Think he does something
to do with streams. SURMA: I don’t think
I’ve ever heard of him. PAUL LEWIS: No? Sam “The Dutts”
Dutton, there we are. Right, we have more, and now you
can see that this is working. We can even scroll
down, get rid of Addy, and then you can see the
page is actually collapsing, which is really kind of handy,
it is kind of what we want. SURMA: I like how we
said get rid of Addy. PAUL LEWIS: Oh, I didn’t mean
that– I mean only on the page. I mean, I’m not just–
anyway, so good. I’m glad we had this chat. Right, so there you go. What we’re going to
do is, let me ask, are there any final
questions from the chat? Anything anybody wants to know? SURMA: No, we had a few
volunteer helpers answer a lot of the questions already. PAUL LEWIS: Well, in
which case, let me say thank you to those people. We really appreciate
you chiming in and being part of this
little setup we’ve had today. OK, here’s what’s going
to happen next, then. We’re going to push this
code up onto the GitHub repo. What are we going
to do after that? Well, we’ll probably
run a poll to see which ones you want next. SURMA: Because this is
going to be happening again at some point. PAUL LEWIS: You know–
still doesn’t quack. SURMA: I still have to
buy the upgrade first. Next time it’s going
to work, I promise. PAUL LEWIS: Fine. OK, well, in which
case, I guess all is left to say is thank you
very much for tuning in, and I’ve been Paul Lewis. SURMA: I am Da Surma. PAUL LEWIS: Yeah, he really is. He finds us on Twitter
@aerotwist, @dasurma. Don’t forget to subscribe
to the YouTube channel, it’s
youtube.com/chromedevelopers, and I guess we’ll see
you on the flip side. Toodle-oo. SURMA: Thank you for being here.

Leave a Reply

Your email address will not be published. Required fields are marked *