Selectable Shapes Part 2: Resizable, Movable Shapes on HTML5 Canvas

Wait! This tutorial is rather old and I’ve given part one a major overhaul. You should really read (or at least start with) the new one here instead.

In the first tutorial I showed how to create a basic data structure for shapes on an HTML5 canvas and how to make them selectable, draggable, and movable. In this second part we’ll be reorganizing the code a little bit and adding selection handles so we can resize our Canvas objects.

The finished canvas will look like this:

This text is displayed if your browser does not support HTML5 Canvas.

Click to select a box. Click on a selection handle to resize. Double click to add new boxes.

This article’s code is written primarily to be easy to understand. It isn’t optimized for performance because a little bit of the drawing is set up so that more complex shapes can easily be added in the future.

In this tutorial we will add:

  1. Code for drawing the eight boxes that make up the selection handles
  2. Some small adjustments to the draw code
  3. Code to be run on every mouse move event
  4. Code for changing the mouse cursor when it is over a selection handle
  5. Code for resizing

Drawing the selection handles

The eight selection handles are unique in that each one allows you to resize an object in a different way. For instance clicking on the top-middle one will only let you make it taller or shorter, but the top-right one will allow you to make it taller, shorter, as well as more wide or narrow.

Like all decidedly unique things, we’ll want to keep track of them.

// New, holds the 8 tiny boxes that will be our selection handles
// the selection handles will be in this order:
// 0  1  2
// 3     4
// 5  6  7
var selectionHandles = [];

Previously we had the variables mySelColor and mySelWidth for the selection’s color and width. Now we also add variables for selection box color and size:

var mySelBoxColor = 'darkred'; // New for selection boxes
var mySelBoxSize = 6;

Draw’s new home

Draw is still its own function but most of the code has been moved out of it. We’re going to make our Box class start to look a little more classy by letting boxes draw themselves. If you haven’t seen this syntax before, it adds the draw function to all instances of the Box class, creating a someBox.draw() we can call on boxes. To clear up confusion, our old draw loop will be renamed mainDraw.

// New methods on the Box class
Box.prototype = {
  // we used to have a solo draw function
  // but now each box is responsible for its own drawing
  // draw() will call this with the normal canvas
  // myDown will call this with the ghost canvas with 'black'
  draw: function(context, optionalColor) {
    // ... (draw code) ...
  } // end draw


This draw code is lifted from the old draw method but with a few additions for the selection handles. We check to see if the current box is selected, and if it is, we draw the selection outline as well as the eight selection boxes, their places based on the selected object’s bounds.

In the Init() function we need to add the selectionHandles[] initialization as well as a new event. In the past, myMove was only activated if you pressed down with the mouse, and became deactivated as soon as the mouse was released. Now we need myMove to be active all the time.

// new code in init()
canvas.onmousemove = myMove;

// set up the selection handle boxes
for (var i = 0; i < 8; i ++) {
  var rect = new Box;

Our new main draw loop is now very slimmed down:

function mainDraw() {
  if (canvasValid == false) {
    // draw all boxes
    var l = boxes.length;
    for (var i = 0; i < l; i++) {
      boxes[i].draw(ctx); // we used to call drawshape, but now each box draws itself
    canvasValid = true;

Doing this reorganization isn't too important now, but it will be useful later on if we have many different types of objects draw themselves. After all, rectangles and (for instance) lines are not drawn in the same way, so if we can put all the custom drawing code in the object's own class we can keep things better organized.

myMove revisited

Before I talk about myMove lets take a look at two new variables added to the top of our code that signal whether or not a box is being dragged and if so, from which selection handle.

var isResizeDrag = false;
var expectResize = -1; // New, will save the # of the selection handle if the mouse is over one.

isResizeDrag seems simple enough, it works almost identically to isDrag. expectResize will be a number between 0 and 7 to indicate which selection handle is currently active. If none is active (the default), we'll set it to -1.

In most programs that have selection handles (such as the edges of your browser) it is nice to have the mouse cursor change to show that an action can be performed. To do this we are going to have to ask where the mouse is located all the time and see if it is over one of our eight selection handles. Remember that above we made myMove active all of the time and Now we have to add code to it:

// Happens when the mouse is moving inside the canvas
function myMove(e){
  if (isDrag) {
    mySel.x = mx - offsetx;
    mySel.y = my - offsety;   
    // something is changing position so we better invalidate the canvas!
  } else if (isResizeDrag) {
    // ... new code to talk about later.
  // if there's a selection see if we grabbed one of the selection handles
  if (mySel !== null && !isResizeDrag) {
    for (var i = 0; i < 8; i++) {
      // 0  1  2
      // 3     4
      // 5  6  7
      var cur = selectionHandles[i];
      // we dont need to use the ghost context because
      // selection handles will always be rectangles
      if (mx >= cur.x && mx <= cur.x + mySelBoxSize &&
          my >= cur.y && my <= cur.y + mySelBoxSize) {
        // we found one!
        expectResize = i;
        switch (i) {
          case 0:
          case 1:
          case 2:
          case 3:
          case 4:
          case 5:
          case 6:
          case 7:
    // not over a selection box, return to normal
    isResizeDrag = false;
    expectResize = -1;'auto';

So if there is something selected and we are not already dragging, we will execute some code to see if the mouse position is over one of the selection boxes. If it is, give the mouse cursor the correct arrow. If the mouse isn't over a selection box, make sure we change it back to the normal pointer.

You'll also notice that at the start, after "if (isDrag)" we have a new test, "else if (isResizeDrag)." isResizeDrag becomes true if two conditions are met:

  1. expectResize is set to one of the selection handle numbers (is not -1)
  2. we have pressed down the mouse

In other words, it only happens if the mouse is over a selection handle and has been pressed. We add a tiny bit of code to myDown to make this work.

// Happens when the mouse is clicked in the canvas
function myDown(e){
  //we are over a selection box
  if (expectResize !== -1) {
    isResizeDrag = true;

  // ... the rest of myDown


Anyway, getting back to myMove. We are looking for the "else if (isResizeDrag)" to see what happens when this is true.

function myMove(e){
  if (isDrag) {
    // ...

  } else if (isResizeDrag) {
    // time ro resize!
    var oldx = mySel.x;
    var oldy = mySel.y;
    // 0  1  2
    // 3     4
    // 5  6  7
    switch (expectResize) {
      case 0:
        mySel.x = mx;
        mySel.y = my;
        mySel.w += oldx - mx;
        mySel.h += oldy - my;
      case 1:
        mySel.y = my;
        mySel.h += oldy - my;
      case 2:
        mySel.y = my;
        mySel.w = mx - oldx;
        mySel.h += oldy - my;
      case 3:
        mySel.x = mx;
        mySel.w += oldx - mx;
      case 4:
        mySel.w = mx - oldx;
      case 5:
        mySel.x = mx;
        mySel.w += oldx - mx;
        mySel.h = my - oldy;
      case 6:
        mySel.h = my - oldy;
      case 7:
        mySel.w = mx - oldx;
        mySel.h = my - oldy;
  // ... rest of myMove

We see a bunch of arithmetic dealing with precisely how each handle will resize the box. Handle #6 is middle-bottom, so it only resizes the height of the box. Handle #1, on the other hand, is the middle top. It has to resize both the Y-axis co-ordinate as well as the height. If #1 only changed the Y-axis, then dragging it upwards would just look like the entire box is being dragged upwards. If it just resized the height, the top of the box would stay in the same position and we certainly don't want that if the top is what we intended to move!

That's pretty much everything. Try it out yourself above or see the demo and download the full source on this page.

So that wasn't too bad. A few long chunks were added but not because of complexity, just because each of the eight selection handles is uniquely placed and does a unique resizing task.

If you would like to see this code enhanced in future posts (or have any fixes), let me know how in the comments.

  • eris.discord

    Minor nitpick: JavaScript and its kin don’t have classes. Box is a constructor (hence why it’s declared as a function) and Box.prototype is its prototype, which gets cloned whenever you construct a new Box object. It’s mostly a matter of semantics in this case, but it can bite you on the ass when you assume other class-like behavior. 🙂

    Not trying to steal your thunder, though! This is a good tutorial. I’m gonna play with it myself.

    Apropos of nothing, there’s a neat trick you can use to make an object’s private data really private. If you add your methods within the constructor like so, you can use constructor-local variables since they will remain in scope. I’m using the dollar sign here as a convention; it doesn’t have any special syntactic meaning.

    function BlackBox() {
    	var $secret;
    	this.secret = "nice try, son"
    	this.newSecret = function() { $secret = Math.floor(100 * Math.random()) }
    	this.trySecret = function(guess) { return $secret === guess }

    • Ven

      HI Simon,

      Would it be possible to identify text on canvas. I would like to display length of each vertex and change length of a side of rectangle on double click on side of rectangle or text that shows length of a side. Please suggest if you have an idea


  • gmtosh

    Thank you again Simon.
    I started designing the resize functionality for a modified version of your initial tutorial. Your approach is cleaner than what I had in mind. Great job.

  • Tim


  • Pingback: Making and Moving Selectable Shapes on an HTML5 Canvas: A Simple Example -

  • Anonymous

    Great tutorial. Really helped me get a better feel for what the canvas can do. Do you have a starting point or any general info on what would need to be modified to be able to draw images with selectable handles on the canvas and perhaps other elements as well?


  • Esteban Martini

    Great tutorial!

  • Sanjeev Singh


  • Miccet

    Hi Simon,
    Would it be hard to implement this with circles instead of rectangles?

  • Wis Wxs

    hey…thank you v much that really helped
    but i wonder how can i add pngs and jpegs to the canvas rather than rectangles 😀

  • Tony66281


  • Brandon

    With StumbleUpon extension for chrome this causes a bad offset on the mouse (mx, my), making it unusable.

  • tina

    Hi there… excelent tutorial!!!

    However, I’ve been trying to draw lines as well but I can’t figure out how to calcule the selectionHandles for lines (for the resizing box).

    How can I do that? For rectangles I notice you use a 7 pointed box….


  • Galib Anwar

    I found this version of 2d elements handling very clear and elegant.

    I managed to grasp a little of the logic and extended it with lines joining/indicating a target item, and displaying some text. And to add the circle bit as well, with bugs though – they refuse to move but only resize.
    I am trying to fix the circle issue and add arrowheads at the end of the lines, but not making much progress.

    Dear Simon the Great, if your schedules would allow you to put any more time, than you already have spontaneously put into this wonderful piece, it will be a boon for many like me.

    Already am grateful. Looking forward to being more so.

  • IT-Student

    Thanks this is really a great tutorial!!!
    I’ll use some this stuff in an phonegap app with xui touchevents and draggable images.

  • Vijay Akkineni

     Thank you this is great stuff!!!

  • sai swaminathan

    amazing stuff ,this is exactly what i was looking for !!! 🙂

  • Pyter Alegrado-Isidro

    nice work, can this be modified and have an adjustable oval shape (or any other shapes) instead? please email me at I’m a big fan of html5 pro evolution!

  • Isaac Zepeda

    thanks, it was very useful, I had to modify it so it could be done through objects, thanks a lot

  • Steve Widom

    Good stuff.  I modified the code slightly for the getMouse(e) function so that it would take into consideration scrolling offsets.  I use a mix of jQuery and a method I have been using for quite some time that appears to work in all browsers.  Here is the new code:

            var position = getMouseXY(e);

            var offset = $(canvas).offset();

            mx = position[0] – offset.left;
            my = position[1] –;
    And here is the method for getMouseXY(e):

    function getMouseXY(e) {
        var tempX = 0;
        var tempY = 0;

        var evt = window.event || e;
        if (evt.pageX || evt.pageY) {
            tempX = evt.pageX;
            tempY = evt.pageY;
        else {
            tempX = evt.clientX +
              (document.documentElement.scrollLeft ||
               document.body.scrollLeft) –
            tempY = evt.clientY +
              (document.documentElement.scrollTop ||
               document.body.scrollTop) –

           if (tempX < 0) { tempX = 0; }
           if (tempY < 0) { tempY = 0; }

        return [tempX, tempY];

    Hope this helps others.  Your tutorial is excellent, and I think this just makes it all that much better.

  • Anouman Ain

    Thanks man really helpful script.

  • Pingback: JS exercise 9, day 5 – Drag Square | Software Studies for Media Designers()

  • Nikhil Dixit

    Great tutorial…!!
    Is it possible to use circle instead of rectangles?

  • K Saha

    its great

  • Oliver

    HI! Great stuff thx in dolby!
    Can you give me a hint, how i can create a new rect from outside the canvas like i.e. using a button?
    I tried:

    function createNewRect(){
    addRect(0, 0, 50, 50, ‘rgba(0,205,0,0.7)’);

    within the head area of my html

    try to call it with

    I think that i have to call it in relation to the window class?! Means the function
    is need to be part within your window clss and i should do something like window.createNewRect() ??
    Hope for a hint


    • Linda

      I would also be very interested in this feature – specifically so that a different image will be spawned on the canvas depending on which button you click.

      If you could help with this that would be fantastic, thanks

  • Alexander Mostovenko

    Just great!!! This is what i was looking for!!! Thanks man)

  • Vishal

    This is Good but I need a modification here I want a single image on canvas which will be resizable and move with this handler (same )
    Please help

  • Vishal

    This is Good but I need a modification here I want a single image on canvas which will be resizable and move with this handler (same )
    Please Reply

  • Kiran

    Why its not possible to draw images on canvas using boxes class. I have tried but its not working. Added below code in draw method but its not showing anything. neither there are any error

    var img = new Image();
    img.onload = function(){
    canvas.width = img.width;
    canvas.height = img.height;

    ctx.drawImage(img, 0, 0, 50, 50);
    img.src = ‘cottage.jpg’;

  • krisnarocks

    now, how to remove the block?

  • Tony Medina

    Very useful script, thanx, I’m looking for resizing selectable images too. Got to show and work with one image only, how to work with 3 or 4 images?

  • Kerry

    This is excellent; Donald Knuth would be proud.

  • Gustav

    I wondering if you could help me with a program. I going my last year at highschool and I have a project that includes javascript/canvas. One task is to draw a circle where you can make some rectangular shaped forms that change size and following the path around the circle.

    Is this possible to do? Please can U help me I’m stuck and can’t get so much help from the teachers.

  • Gromenawer

    It is possible to add some animation to the selection frame (for example, make it blink from red to green) that is not too much CPU consuming? I tried to modify myself and as soon you try to draw every t ms instead of the validating method the efficiency goes down significally.

  • Mahendra

    its great one but i have image on canvas while i want to draw angle/arrow over image and want redraw that angle/arrow ,how can i do this ,can you help regarding this

  • pera_nv

    can I add any figure and dimensioned ???? including amorphous figure?????

  • W Nirala

    How I get full code of this tutorial. Because I am new in Html5.

  • ihateiPhone4

    i tried this in OSX browser, i cannot move the items

  • mahendra

    Its very good tutorial,but how can we apply same functionality to line or arrow,angle
    if you any idea about this please reply me.

  • K

    How would you go about adding text, images and doing shape rotation?

  • Andrew

    This is great! I really like how clean the new code in part one is so I went ahead and merged the code for resizing with that code base:

    Hope someone finds that useful!

    • Jason Davis

      Thanks just want I wanted to do. Next step is to add more shapes like arrow, circles, and text along with selector for size and colors

  • Đàn Hiền

    Thanks for very great article. But I want to move and resize another shapes such as square, line, circle… Can you help me?

  • steve_davis

    I’ve been looking for this for some time now. However, what I REALLY need is an example of not only how to drag & drop with resizeable handles but also the ability to add text to the box and remove the box with the delete key. Finally, I need to combine all this with getting the coordinates of the drop location. The end result is the ability to create a box, drag it to a location, resize it, give it a name and save the name & coordinates to a variable that I could do something with later. I KNOW it’s possible, I just don’t know HOW – yet!!

    • David Miller

      Have you figured out how to do this yet? If so, are you willing to share the code? I’m looking to do the same thing.

  • Gnice!

    This is great!
    Can i ask you a question about Rotate item?

  • Joshua Raichur

    This is neat. Thanks for this!

  • Muthu

    Thanks. Really a good one for starter.

  • Sabih Khan Afridi

    can any body help me to rotate these divs on different angles by using mouse

  • swati

    Hi Simon,
    Thanks for this useful article.I want to add connectors to connect two shapes on runtime can u help me for that.

  • christian

    i would like for you to build something for me. Are you interested?

  • Niroshan Sathasivam

    is there any way of adding a handle to resize the canvas element itself. I’m finding it difficult to even find it on the internet

  • Yogesh Gupta

    Thanks for such a nice tutorial. Using this I am able to add, drag and re-size multiple images on canvas. In my project I am adding images on canvas using a function which get called on clicking on check box. Through that function I am creating the array of image url’s and then calling init() function which you have defined.

    Problem I am facing is that when I am saving the canvas using canvas.toDataURL function; added images are not being saved. Only canvas background is saving. Please help me.

  • Bhavin

    suppose two rectangle on canvas with one rectangle over another than how to select inner rectangle?

  • Azim

    Thanks for the great article. Could you please help me to rotate the rectangles?

  • romadhoni

    I want to ask about how to add textfill in a shape.
    I want to add some character at the center of the shape. Can you show me how to do that?

  • Henrique Augusto

    How can I make the squares to not overlap one another when moving, or at least prohibit to drop one square over another?