Refactor HTML5 Canvas
Key Takeaways
Refactoring HTML5 Canvas for better performance and user experience by utilizing separate drawing contexts for each remote user, implementing line drawing and storage of start points, and improving overall code structure and functionality.
Full Transcript
plan for today is we're going to make it good. We're going to make it good. We're going to build. So, we've got our shared canvas here and we've got some code cleanup that we need to have done. A lot of to-do items, a lot of toot items. Let's get this. This is where we left off was the context per remote user. And this fixes a lot of problems. This will fix a lot of problems. So, let's get right into it. Um, I'm going we're going to make this way better now. Okay. So we've got our context here and then we have got a currently drawing not drawing and this will allow us to set start and end point. So that way when the user uh starts the drawings the the line drawing process they'll be able to release and then stop it. And this is what the stop check will be for every one of those. We're going to make this multi-user canvas work way better than it was before. It was already working kind of okay. We're making way work way better. So we get our drawing and go. Okay. So right. So every time we get a user ID, we create a new [music] context or we get the existing context or we get a new one. Uh what we could do is instead of add and get context, [music] we could just say get context. I think that'll be better. I think that'll be way better because then it allows [music] us to by user ID and then we don't need to know whether so we can merge we can merge these functions. So what we can do we can we can merge these okay so we can say return this or [laughter] hey check this out uh this. Okay. So, I like this idea. So, context equals this or that. There we go. And we just return context. Oh, wait. Oh, wait. Even better. Even better. Oh, wait. No, we we we got to do it this way. We have to do it this way because if we don't then Wait, this is actually what we need. If we don't do it this way, then there's a problem. There we go. That's better. Okay. Here we go. Okay. And then so this gets us the context or it creates a context. I'm pretty sure that works. Let's see. We're we're we're going to get rid of this. So, we're going to say get context con uh context equals. And I don't know if we really need this part. I think we just needed to do that part [music] right there. So, this will return the context. Although, yeah, I think that's right. That's [music] right. So, context dot context, which is weird. Okay. Uh, we probably don't want to call this context. We could call this something else. We could call this user was what we should call this user.context. That's way things are things are showing up. We can even have this would be neat. This would be also neat. We could also transmit like cursor mouse movements. Why don't we do that too? Let's add that in to-do transmit cursor movement. So that so that way so we need to add we need we need to get our functions working over over here. So we don't need this information anymore. We don't need that. We don't need remote context. We're we're we're going to clean up. We're going to do a full rewrite. Is this 3JS? This is just 2D canvas. No framework. The browser is the framework. You don't need anything else. All right. All right. So, this is going to fill the background in dark mode because of Jenlu. Because of Jenlu. And then we need to set our U action our action. We need to define our actions guide on 3D like 3GS. Yep. 3GS. That's a good one. Other available languages those. So that's a nice framework that uses WebGL. Is it WebGL? Yeah, it's WebGL and it makes it really easy for you to render in the 3D canvas. It's really nice. It's actually pretty great. I've used it multiple times. All right. So, let me just kind of re-review this really quick. All right. So, we got a bunch of duplicate stuff in here that I want [music] to delete. So on mouse move if not drawing. So event. So what we need to do is add a what we need to do is add a function that will draw draw the line. Draw start draw end I think right. Draw start draw and draw end. I think we need I need we need three functions. I don't actually think we need full three functions. Hey Brandon I remembered your name. See you didn't have to tell me this. So let's see. We need a draw start function draw start and then likely we just need X Y. I think that's it right. We need X and Y for draw start. And then we need the user ID. I think yeah I think that's right. And then we need to we need to draw end end which will be similar. All right, let's get this. We're we're making we're making progress. We're making rapid progress. And then we need a draw draw p like a straight up draw draw path or draw two. Let's try say draw two. All right. So let's see here. So we could get So we've got we need to get our XY events. Should we should we just do we can't just straight up do an event though, right? We can't just straight do an event because we've got a broadcast. Where where what function are we doing here? So we've got our get XY which we do need. We do need that. And let me transmit it. Okay. So we've got a draw function here. Got it. All right. So this draw function is broken. We need to split this up. So this is the part that there's a bug for right now. This part is bugged out. XY. All right. So publish XY. How? Oh, broadcast. So where are we broadcasting? All right. Previous. Okay. So I we need to store an extra component of the previous coordinate positions, guys. So we're doing a refactor. We're doing a refactor. Draw start. Draw end. I don't know if these are the functions that I want. Uh I think they are because I need to abstract them from the event. I need to be able to paint them remotely and locally at the same time. So I can get user. All right. So we'll say const user equals get user ID, right? We will do get user user ID. That'll get the user. And so these are the these are coordinates. And then we will say user.d drawing equals true. [snorts] There we go. We're making progress. And then we got to do the same thing for the end except for drawing will be false here to do a draw function. And we just need user ID. Just the user ID. Oh, we do need we do need coordinate information though. Obviously, obviously we need coordinate information. So we need draw and then we need the context. So we need the user ID. So we we're good. So we definitely need the user ID and then we need [music] do we need the X and Y coordinates? I think we probably should have the X and Y coordinates. Although we could we could sort of tuck those coordinates inside the user object. So we can simplify this even further. We can delete all these things like this. We can delete everything. We don't need any of this. is is what I'm saying. So I think how about we just do this. We just draw and we just get the user and then we have the chords here and it will be X0 and then Y0. We should also add color. We need the current color of who's drawing. Yeah. See multiple. Wow. Isn't that Wow. Look at that. How How come multiple people are able to draw? I thought they couldn't. But look, y'all are doing it. Isn't that great? I don't know if the color selector is proper. We'll get that fixed though. We'll get it fixed. Stephen, you don't have Discord, Brandon. Oh, no. You don't have Discord. Oh. Oh, no. That's uh that's problematic. So, yeah, we host with Amazon and we deploy across all of their data centers, which gives you the fastest possible performance. You can see right now how fast it is. Isn't that great? We share the same brush. Yeah, I think that's what it is. We got to fix that. That's the something we're going to fix. See, guys. So, we'll be working on that. That we'll be fixing that now. That's what we'll be fixing next. All right. So, we got to fix that. All right. To do todo fix uh fix color per user cuz right now they're all the same color. Let's see. All right. So, I need to we need to do get begin path. So, we need to do user context. So, we could do is get con context equals user.context. So, that way we've got that in in the bag. We'll do local and remote. Abstractions are beautiful. Thank you for the party poppers, you guys. Abstracts are beautiful. They are. What's your opinion on love? Well, it's an emotion, isn't it? Isn't an emotion? I can tell you what it is. Are you? That's as far as I know. Uh, I've had it before and it has it programmers are not romantic. I [laughter] know just right. Exactly. All right. So, if user is not drawing, right? So this will be start, this will be end. Then we need to do context begin path and move to coordinates. Okay. And then so this this is okay. Let me think about this because the math needs to be based on so we need to transmit the raw coordinates of the user and then we need to transform the dimensions. That's what we got to do. We got chords move to chords. Okay. And then this will be separate so we don't need to worry about that anymore. And then on mouse down so mouse up drawing false. Okay. So, see, this is where I don't think we need I don't think we need to worry about this. I'm pretty sure we just don't need to worry about that cuz there's no like end statement. We just need begin, right? There's just begin and move to. And then there's Oh, there's also like a draw. So, where where's the context draw fill? Line two and stroke. There we go. That's what I'm looking for. Line two and stroke. Perfect. Perfect. You guys, is it possible for you to reset? Uh, yes. Cuz it's lagging a lot and I can't draw. Oh, is it? It shouldn't be lagging. I don't think it should be cuz it's uh it's just the it's just being blit. It's just pixels on the screen. You if you reload the page though on your side, it should it should stop lagging. If you reload it on your side, let me see here. Uh, this is if not drawing. If it is drawing, let me line just if user.drawing is true, draw a line. Okay, there we go. User start begin move to and then stroke and go. Perfect. Uh and the context. How do we change the context color? So we we also need to change the context color. That's something that we got to do. So we have mo each user have their own color. That's what we got to do. A style. There's got to be a style. Uh I tried but still no. Oh, is it really? I love to code. Made the canvas very green. All right. Const style equals userstyle. And we need we need to add we need to add the style here. So style is going to be red. Start off with red. There we go. Perfect. User style red. And then we need to update the context. I believe only if the user is not drawing. So, context dot what's it called? Is it line? No, it's not line. It's stroke. Stroke style style. There we go. Hey, now we're now we're into it. Let's go, team green. Right now, look at you guys are taking over the entire screen. Going to go grab lunch. Hello, world. Good to see you. I want to make it pretty. So, let's make this look nice. Align the equal signs. So start line. Okay. So only when we're starting otherwise otherwise we're just going to draw line two and we're going to stroke. There we go. I think that's it. Is that all it takes? Did we just simplify it? So drawing set the stroke style begin the path move to coordinates and then wait for the next coordinate to come in and then we need the chords.xy. There we go. That should do it. That's it. So now all we have to do is capture the events from the HTML uh event object and then transmit it. I think that's it. I think that's all we got to do. Draw simultaneously connects the points of two years. Yeah, that's what's happening. So it gets weird geometric patterns. Bingo. Yep, that's what we're fixing. That's what we're currently working on right now. We're fixing it. So we need to do prevent default on everything. Prevent default everywhere. Prevent the defaults. Okay, looking good. And then every single one of these. So I what I need to do is every event needs to so we need to do a start. Okay, function start capture event and then we'll have a function end capture event and then a function capture uh move oh start [music] mouse uh touch start end and move capture. There we go. I think those I think if we get those three then we can simply just have a list of event listeners and they all do the same thing. They all do the same thing. That's it. The Last Air Bender is totally better than The Legend of Kora. Is it? Oh, right. The sequel, right? The sequel. Yeah, I like the original better. It's so much better. It's too bright. So, we need to event.prevent default on all of these. And then we [music] need to get the coordinates. And then we don't need that. We need to just broadcast at that point. That's what we got to do. We got to broadcast. And the broadcast is only going to give you the X and Y coordinates. We don't need to have We don't need to double up anymore cuz we optimized it. We made it way better. I've got this looking good. I've got the chords. We always need to grab the chords every single time. Every time. Okay. Drawing. True. Get the chords. And let's see here. We are going to instead of this we're gonna we're gonna start we're gonna start getting these good. So now I want to double check. So got those. Looks good. Looks good. Uh touch prevent. And then where is the broadcast? Okay. So this is what we're going to do. We're going to broadcast every single time now in the draw function. Right. Every single time. Is this is this is this let me think about this for a second. Let me think about this for a second because I'm seeing a lot of repetition here. I'm seeing a lot of repetition, right? A lot of repetition. So, I think we can merge these also. So, I'm seeing a lot of repetition here. The only thing that's different is this. That's the only thing that's different is this draw true, draw false. Everything else is identical, right? It's all the same. It's prevent default user accords and then you're going to broadcast. And we're going to be broadcasting the user the user XY. So we'll say chords. We're going to delete these. And then we're going to say user ID. User ID. That's what we're going to broadcast. I think wait do wait. We need [music] we also need to pro we need to broadcast everything except for the ob the context. We can't broadcast the context. My typing is all broken. Is it? No. Uh, add an MCP server so the Claude can draw WITH US. OH, THAT WOULD be great. That would be fantastic to see the AI agent actually drawing. That would be fun. All right, that'll be a good one. That's a good one. All right, we need more than this. So, what else we got? What else we got? So, we have drawing coordinates and style. So, we need everything except for the context object. That's what we need. Uh, state. So, what I could do is make it easy and and put everything into like a state like this. So, that way all we have to do is broadcast the state. I think that'll be better. Okay. So, let me let's go user contact stroke return user. Looks good. And so, user and then we say user.state. state. Uh, no, not for context, but for the other things. State state here. There we go. Okay, perfect. And then that's it. We We made it better. We wait a drawing drawing user.state.drawing state.d drawing. Okay, let's go back over to our code. Let's get going on the code here. All right, so I think this is it. So we have the start, end, start, end, and move. Okay. Touch start, mouse start, up, down. All right, looks good. Then we capture get user. Do we get the XY? So we need the XY coordinates every time. And we need to update the user coordinates. So I would say the user.cords need to be replaced. All right. So we're making some adjustments, you guys. We're making some adjustments here. uh cord like that every time. Every time like this. Okay. Then we transmit the uh and this needs to be state state dot. Okay. Almost messed that up, you guys. Almost messed it up. We almost messed it up. I want So, I only have I have 14 minutes left, you guys. I have 14 minutes left. So, I really want to be able to finish this rewrite. I believe we got really close to the completed rewrite. So, we got user ID drawing false coordinates XY looks good to me. Get chords. I need to validate this real quick. Uh, this function right here or get XY is going to return XY. Perfect. One second. What's that going to be? It's going to be the state. Yeah, I think that actually is right. That is user ID. Perfect. And then we're going to get the user ID and then we're going to override it. Okay. User ID. get user user ID and then we're going to say user.state equals message and then we draw and then we draw. I think that's it. And we just draw based on the user ID. I hope this works, you guys. I hope this works. We're really close. Draw me uh user ID, right? Is that it? Let's see here. Where is this function? Draw user ID. Perfect. Okay. So, it gets it. It grabs the context. Uh, which we will have a new context. We'll get the state. It overrides the state here. The state is overwritten with the message. Uh, though I suppose what we could just say state like this. So that way we know what's going on. Uh, user ID const user ID, right? State user user get the user user.state state line on color. Color context. We have to change this. Okay, we have to change this. All right, here's the canvas. Oh, we got a bug. We got a bug. It's broken. Something's wrong. We got an error. We got an error. No worries. We'll fix it. We'll fix it. Syntax error on line 91. Okay. 91. Go. Go.
Original Description
Today we are making the shared canvas better. We have a lot of cleanup and to do items, but we left off at keeping a separate drawing context for each remote user, which fixes a bunch of problems. The goal is simple: when a user starts a line, we store a start point, draw as they move, and stop cleanly when they release.
To do that, we refactor the code so one getContext function returns an existing user context or creates a new one, based on user ID. Then we split drawing into clear steps like start, move, and end so local and remote drawing use the same logic. We also plan to transmit cursor movement, prevent default on mouse and touch events, and broadcast only the user state like drawing, coordinates, and color, never the actual canvas context. Right now everyone shares the same brush color, so we will fix color per user by setting strokeStyle when a stroke begins.
We are close, but we hit a syntax error near line 91, so the next step is to fix that and test the full rewrite.
More on: HTML & CSS
View skill →Related Reads
📰
📰
📰
📰
Frontend Storage: localStorage, sessionStorage & Cookies
Medium · JavaScript
How to add country icons to a React app
Dev.to · Rushan
Multi-Step Forms in Angular: Building Clean, Scalable, and User-Friendly Form Workflows
Medium · Programming
Why Angular Pages Sometimes Load Instantly… And Sometimes Don’t
Medium · JavaScript
🎓
Tutor Explanation
DeepCamp AI