HTML5 Canvas Drag, Drop, and Resize Images

Posted on July 24th, 2011 by Eric Rowell

Open in new window

Code Editor

85 Comments

  1. Sitex says:

    wow… it is great..
    thank you..

  2. Jun.Cao says:

    nice job.

  3. Jun.Cao says:

    context.translate(thisRect.x, thisRect.y);
    Is this words make image reverse?It resemble “context.rotate()”?

  4. Eric Rowell says:

    @Jun.Cao – the translate() method translates the canvas context to the position that the image will be drawn. The images can be inverted with the scale() method. When either the x or y is negative, the image will flip.

  5. Richard says:

    I’m new to canvas and trying to figure out how this will work with a touch device, like ipad. When i run the examples usinge drag and drop on my ipad it just wont work and the ipad wil just select the entire canvas as an element on dragging. However i have seen apps that do not have this behaviour, like a small paint program. Is drag and drop impossible on an ipad this way, if so whould you know a good work-around?

  6. Eric Rowell says:

    @Richard this is certainly possible, I just need to add touch support to KineticJS as soon as I get the time. I’ll let you know when it’s ready!

  7. seba says:

    Please, tell me why scaling don’t work if I call drawResizeBox() like this:

    context.translate(thisRect.x, thisRect.y);
    drawResizeBox(0,0,thisRect, TOP_LEFT);
    context.translate(-thisRect.x, – thisRect.y);

    or like this:
    context.save();
    context.translate(thisRect.x,thisRect.y); drawResizeBox(0,0, thisRect, TOP_LEFT); context.restore();

    ?
    I this needs to rotate.

  8. munge83 says:

    WOW this i great. Thanks

  9. Hi Eric
    I am new to this area (i.e.HTML5 / Javascript) and your tutorials have been VERY helpful. Thanks a million!

    I am wanting to be able to increase the size of the images in the above example by a set percentage when someone hovers over them and to return to the original size when they mouseout.

    If you add that please let me know.
    Also what book or books etc would you recommend for someone starting?
    Cheers
    Richard

  10. Eric Rowell says:

    @Richard no problem! I’ll create a lab for you that shows how you can do that and I’ll post the link here (should have it done within a couple days or so).

    To answer your question about a good HTML5 canvas book, it just so happens that I’m wrapping up my own book called “HTML5 Canvas Cookbook” by Packt. It’l be published on Dec 11th of this year. Check it out:

    http://www.html5canvastutorials.com/cookbook

  11. Eric….that is SO helpful.
    I wish you every success…..and of course I will be oredering your book. Thanks again.
    Richard

  12. Eric Rowell says:

    @Richard thanks!

  13. Eric Rowell says:

    @Richard here you go:

    http://www.html5canvastutorials.com/labs/html5-canvas-expand-image-on-hover/

    In order to keep the functionality relevant to other readers, the demo only focuses on expanding images as you mouse over them. You could easily combine the logic from both demos to create a project that let’s you drag and drop, resize, invert, and expand on hover.

  14. Eric, that’s excellent!! Thanks.
    What a fabulous set of resources you have provided here.
    Greetings from Scotland! Richard

  15. Eric Rowell says:

    @Richard glad it was helpful!!

  16. Hi Eric

    I have begun working with the kinetic 2D environment and have successfully trapped events like mouseover, mouseup etc with syntax like…….
    kin.addRegionEventListener(“mouseup”, ……

    Is it also possible to trap rightclick, leftclick, or doubleclick ?

  17. Eric Rowell says:

    @Richard absolutely. KineticJS was designed to support fundamental events so that developers can extend it anyway that they like. You can detect a click by detecting a mouseup event, and you can detect a right click by accessing the which or button property of the event object once a mouseup event has occured. You can detect double clicks by detecting two mouseup events that occured within a defined amount of time, say 200ms. The fundamental JavaScript events are:

    mousedown
    mouseup
    mouseover
    mouseout
    mousemove

    and the following events are derived from the fundamental events (not included in KineticJS)

    click
    double click
    right click

    I may be adding these in with a later version of KineticJS because I’ve gotten a lot of requests to do so! Stay tuned

  18. Excellent Eric. Thanks!

  19. Chuck Weger says:

    Excellent tutorial and library, Eric! I look forward to your book. I’d like to +1 the request for a version of this that works on iOS devices. Thanks!

  20. Eric Rowell says:

    @Chuck awesome! Btw, all of the tutorials on this site that use KineticJS can also work on mobile devices if you map the mouse events to touch events. In other words, change the following mouse events to gesture events:

    mousedown –> touchstart
    mouseup –> touchend
    mousemove –> touchmove

  21. jorge says:

    Please.. one question … Can I Drag and Drop from one canvas to another canvas??

    Please.. thanks.

  22. Eric Rowell says:

    @jorge I would think that’s certainly possible (although probably a huge pain to implement). Why does your app need to drag stuff from one canvas to another?

  23. Larry says:

    Eric,

    Love the framework. I would have thought one can achieve double click mouse support via ondblclick for a Canvas. I’ve tried adding it to KineticJS and it didn’t work :), but I’ve seen another demo that does it directly on the canvas element.

    I can add it to canvas element and it works, but of course it response no matter where on the canvas I double click.

    When you add it in KineticJS, would you be really using two mouse up events 200 apart, or is there not a simpler way with the canvas ondblclick? Thank you!

  24. Eric Rowell says:

    @Larry I’ve had numerous requests to include click and doubleclick event listeners, so I think I’ll go ahead and add them in. Currently, this lab is actually out of date because it’s using Kinetic v1, and I just released v2 last week. Here’s an example:

    http://www.html5canvastutorials.com/advanced/html5-canvas-drag-and-drop-an-image-tutorial/

    I’ll let you know when I’ve added the two new events to Kinetic (will probably be in v2.0.2)

  25. Larry says:

    Eric,

    Thanks, that would be great….and thanks for such a quick response to my post. I’ll watch for 2.0.2.

  26. jake says:

    hi when I’m trying to use my own image for this to work it won’t nothing happens is there any chance you can give us a step by step on how to implement?
    cheers

  27. kaushik says:

    Eric,

    This tutorial has been of great help to me.Im completely new to html5 and jquery.my boss wants me create a demo which involves copying an image from one canvas to another through drag and drop and also i must be able to resize and move the image.i have some how managed to do the drag and drop from one canvas to another but im not able to resize and move it around.is it possible to do that?actually what im trying to do is something similar to what happens in http://www.lucidchart.com,Thank you.

  28. Eric Rowell says:

    @jake can you provide us with a jsfiddle demo link so we can see what’s happening? Are you getting JavaScript errors?

  29. Eric Rowell says:

    @kaushik sure it’s possible (this lab does it). Perhaps you could show us a jsfiddle demo?

  30. kaushik says:

    Eric,

    yes sure ,please take a look .im lost on what to do next.i have uploaded my file in this following link… http://www.mediafire.com/?avcvam15wa5blss

  31. Larry says:

    Eric,

    Do you have any recommendation as to how many regions can be supported from a scaling perspective, ie. if I had X number of items i want to draw on one screen, and I want all of them to have mouse listeners, is there some maximum you recommend?

  32. Eric Rowell says:

    @Larry it turns out that KineticJS v1 didn’t perform very well with a large number of regions, so I rebuilt KineticJS (v2) to handle thousands of regions if need be. This lab has not yet been updated to use KineticJS v2. For the time being, check out the following lab which is very similar but uses KineticJS v2:

    http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-multiple-shapes-with-kineticjs/

  33. Eric Rowell says:

    @Larry I just added support for click and dblclick event listeners to KineticJS v2.1.0

  34. Arek says:

    Hi,
    is there a possibility to add rotation effect to this script? Did anybody manage to do it?

    Arek

  35. Eric Rowell says:

    @Arek as soon as I get a chance, I’ll create a lab that shows how you can do it. Stay tuned!

  36. Alvin says:

    Hi, this is awesome! But any idea how to save the whole kinetic object into an image? I used stage.getCanvas() and it return me an empty picture …

  37. Eric Rowell says:

    @Alvin thanks! I’m currently working on a new site for KineticJS to help with some confusion people are having about the different canvases that are generated. KineticJS generates 4 canvases for performance reasons:

    1) backstage canvas – used for event detection
    2) stage canvas – used for elements of the drawing that don’t require attached events
    3) static shapes canvas – used for shapes which have attached events but don’t move around
    4) dynamic shapes canvas – used for shapes which have attached events and do move around

    To get the resulting canvas image, you’ll have to combine the stage, static shapes, and dynamic shapes context. In the next release, I’ll provide a method called getCompositeContext() which takes those three contexts and combines them into one. You could then use that context to generate the data url.

  38. Alvin says:

    Oh I see, thanks Eric :) looking forward to your next release.

  39. Don says:

    Hi,

    How can make it working for IPad using two finger touch event?
    I tried changing following events
    mousedown –> touchstart
    mouseup –> touchend
    mousemove –> touchmove

    but still no luck.

    Can you please give me some help on rotating, scaling, moving images inside the canvas on Ipad using multiple touch events (2 finger touch events).

    Please suggest/help.

    Thanks

  40. Eric Rowell says:

    @Don hiya! Currently KineticJS only supports single touch events (it does not yet support multi-touch gestures). Although I do have plans to add this in asap, it won’t become available for a few version because there are some higher priority features that need to be added. Stay tuned!

  41. How bout this.
    In the canvas fb app thing I’ve been building forever now, there is a sort of force directed graph thing, where image nodes come out from a center node/image with varying line lengths to show strength in relation to the center node, right.

    Well, we need to build a way for there to be more than just what is able to fit in the viewport. In otherwords, think about how google maps is, you can zoom in, zoom out, pan around etc. zooming zooms you straight into the center point, the map and all.

    Would it be possible or even relatively conceivable to create a zoomScale that when zoomed in or out more image node connections are then shown when more exist that are weaker connections to the center…? Make sense-ish?

    (I mean, the app is by no means basic. There’s so many things that are all intertwined and just tied from one thing to the other yet it is very modularized.)

  42. Eric Rowell says:

    @Jared absolutely. For mapping applications like the one you’ve described, you’ll need to constantly lazy load the nodes (or tiles) around the view port using AJAX so that when the user moves around or zooms out, they are already available.

  43. Purdy says:

    This is a great sample project that ties together a lot of concepts from some of your other examples. Very helpful!

    I am trying to extend this example by adding an ‘Add Yoda’ button that would add another picture onto the canvas. I rewrote the code slightly to have an addImagetoCanvas function that uses an anonymous function to add a new shape with the appropriate image and event handlers. This works great when I call it from within initStage.

    My problem is that when I call the addImagetoCanvas function from the button (as opposed to from within the initStage function) I get a type mismatch error on the last line of this block of code:

    var box = new Kinetic.Shape(function(){
    var context = this.getContext();
    context.drawImage(box.imageObj, 0, 0);
    …

    I am guessing this is because the previous line (var context = this.getContext();) failed to get the context of the newly created shape. I suspect I can fix this by ‘refocusing’ to the existing stage, but I don’t seem to be able to figure that part out. Any suggestions?

    (And please delete the previous post of mine. I hit submit by accident.)

    Thanks!

  44. Alex MacDonald says:

    Hi there,

    First of all, thanks for the brilliant tutorials and library you have written. It’s brilliant.

    I hope you can point me in the right direction.

    I’ve been trying to implement a method which removes the handles for resizing images? Currently, i am adding images dynamically to a canvas. This allows the user to build up an image from other images, making a collage in effect. Obviously i want to remove the handles before saving the created collage.

    Do you have any ideas?

    Thanks,
    Alex

  45. Eric Rowell says:

    @Purdy can you put your code into a jsfiddle demo so that we can take a look it?

  46. Eric Rowell says:

    @Alex sure, here’s a couple of options that come to mind:

    1) you could physically remove the handle shapes from the stage with stage.remove(handle)
    2) you could hide the handles using handle.hide() and then reshow them with handle.show()

    Let me know if this helps!

  47. Alex MacDonald says:

    Thanks Eric!

    I’ve chosen to use stage.remove() passing the shapes handles to it. This is what I was wanting.

    Thanks very much for the speedy reply!

    Alex

  48. Eric Rowell says:

    @Alex great!

  49. Oleg says:

    Hi Eric, in old versions if you move handle to one side it stretches in correct way to the same side, but now it stretches in two directions (ie I move left handle and image stretches both to the left and right, looks like trying to save proportion) how can I make it act as it was in old version?

  50. Eric Rowell says:

    @Oleg sure, I actually changed the logic in the newer version of this lab to simplify the example in order to better highlight the KineticJS API. For the functionality you’re looking for, it would just require some extra logic to position the anchors a bit differently depending on which anchor is active. For example, if you’re dragging the top right anchor, you’ll want to keep the bottom left anchor stationary, move the bottom right anchor only horizontally, and move the top left anchor only vertically. You can create a similar set of conditions for the other three anchors (as you can see, this is quite a bit of code that was overshadowing the purpose of the lab). Hope this helps!

  51. GB says:

    Hi Eric,
    i tried to incorporate same kind of functionality. but the mouse movement as not as smooth as they appear over here. Do you know the reason behind this behaviour??

  52. Eric Rowell says:

    @GB can you put your code into a jsfiddle demo so I can see it running?

  53. Alex says:

    Hi, Eric!

    This is a wonderful library, and it’s fun to be working on trying to learn it at the exact moment you’re making updates to the code and documentation. I feel very… cutting-edge.

    However, one thing I don’t understand is how scaling dimensions works. On this example, you alter the Image.width, and then alter the Image.scale.x to the newwidth/origwidth. My questions are as follow:

    1) What is the purpose/effect of changing the Image.width, since that in itself doesn’t seem to change anything?

    2) What is the interactivity between the Kinetic.Image declaration of x and y (which I notice are 0 minus image dimensions divided by 2), and the scale.x/scale.y properties? My own attempts have scaled the image correctly, but also offset it by some difficult-to-determine algorithm.

  54. Oleg says:

    If anybody have good math skills please help:

    If I rotate object and trying to resize it goes crazy, how can I calculate rotated object newWidth and newHeight

  55. Eric Rowell says:

    Thanks! Someone else (maybe it was you?) had a very similar question on the KineticJS Forum. Here it is:

    http://kineticjs.com/forum/viewtopic.php?f=5&t=5

    Let me know if that helps

  56. James says:

    Thank! Eric

  57. NathCim says:

    Hi Eric.

    I noticed a little problem with several Canvas gadgets (with my own ones too *g*):

    If you click to drag/scale/interact with objects an move the cursor out of the Canvas area, let go the click and return, it’s stuck on the point you’ve clicked before.

    Sure, it releases when you click again inside the canvas areal, but in some cases it causes heavy bugs and you’re forced to reload.

    Got any solution? :)

  58. Eric Rowell says:

    @NathCim well, It actually works that way be design. When a drag and drop operation is going on, if the user mouses out of the stage KineticJS is ending the drag and drop on purpose. Otherwise, if you mouseup outside of the stage, and then return your mouse to the stage, the drag and drop operation will continue even though your mouse is up. This is certainly not the behavior that users would expect.

    You mentioned that the current functionality “causes heavy bugs”, could you perhaps post your code into a jsfiddle demo so I can see what you’re referring to?

  59. Adam Winn says:

    Is it possible to load more images after window.onload concludes? Example:

    1. How would you create a duplicate of Darth Vader each time a user clicks on him?

    2. How would you allow the user to load a new image by providing a URL?

    Thanks!

  60. Schrene says:

    Is there a way to set the z-index of each image?

  61. Schrene says:

    I figured out how to accomplish what I wanted I just removed the “this.moveToTop();” from the objects I did not want on top.

  62. Eric Rowell says:

    @Schrene great!

  63. Fred says:

    @eric, can u make the image flip if you give it an negative width or height?

  64. Trash says:

    Did any 1 try to use this with fxcanvas?

  65. Eric Rowell says:

    @Fred are you using firefox? Firefox’s implementation of drawImage() breaks when using negative values, and I haven’t had a chance to add some defensive code for this yet. When I get a chance I’ll add that in.

    Cheers!

  66. Fred says:

    Testing in both FF and Chrome,

    What did you change to the .draw() in 3.8.1? it is throwing errors at me, but cannot find the problem?

  67. Eric Rowell says:

    @Fred the most likely problem that you’re seeing is that there was a change to the Kinetic.Shape() API. warning is at the top of the change log here:

    http://kineticjs.com/change-log.php

    Take a look at this Kinetic.Shape tutorial and make sure you’re instantiating a Shape correctly:

    http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-shape-tutorial/

  68. Nando says:

    Hi Eric ! wonderful job, thank you !!

    Do you have any prompt for saving the page structure in a file on the server, in order to restore it at a later time ?

    many thanks, have a nice day.

  69. Marcin says:

    This is very helpful, Thanks!
    How one would modify the code to scale image proportionally?

  70. Francesco says:

    This tutorial among others on this website helped me create a canvas project and a little pseudo-framework, “CanvaMap”, for maps/images in canvas. The work is here: http://blog.fdev.eu/canvamap

  71. chris says:

    Thank you very much for this example, is it possible to add text to this example
    http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images and make the text draggable and resizable?

    Thanks Again

  72. Eric Rowell says:

    @chris sure can. Here’s a text tutorial with KineticJS

    http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-text-tutorial/

    just use Kinetic.Text instead of Kinetic.Image

  73. chris says:

    Hi Eric Thank you I managed to do it, is it possible to add images by onclick i am trying to make a image editor
    Thank you Chris

  74. Eric Rowell says:

    @chris sure is. you can add images dynamically by just adding them to a group or layer and then redrawing the layer

    var image = new Kinetic.image({…});

    group.add(image);

    layer.draw();

  75. chris says:

    Thank you i worked it out, joined the forum so i will ask questions on there

    Thanks for the Labs

    Chris

  76. Jesus says:

    as I can resize an image but limit it to reach a minimum point

  77. Jesus says:

    in Chrome works good bat in firefox a can’t resize completly the imagen, may some bady help me

  78. Bouguima says:

    this example work fine in all navigator but isn’t compatible IOS and Android I have compiled it but It doesn’t work!!!!!!!!!!!!!!!!

  79. Eric Rowell says:

    @Bouguima woah! That’s a lot of exclamation marks! It must be really broken. :)

    Actually, you can just update one line of code to make this lab mobile friendly, line 64 (just updated it)

    Here’s a tutorial on desktop and mobile support with KineticJS:

    http://www.html5canvastutorials.com/kineticjs/html5-canvas-desktop-and-mobile-support/

    Cheers!

  80. chris says:

    is it possible to stop this

    (“Index or size is negative or greater than the allowed amount
    [Break On This Error]

    context.drawImage(this.image, 0, 0, width, height);”)

    when the circle anchor points cross

    Thank you

  81. Ricardo says:

    Hi, I am exploring the benefits of this library and so far it has been great.

    But I have come to one problem, when you are resizing and image or a shape, is there a way to prevent the shape to get negative value, so the page does not freeze while using Firefox?

    Thanks

  82. Eric Rowell says:

    @Ricardo yes, this isn’t a bug with KineticJS, it’s just a lazy implementation :)

    You can simply add defensive logic to prevent it from going negative. i.e.

    if (newVal < 0) {
    newVal = 0;
    }

    or something similar.

  83. Arsh says:

    Excellent example. I’ve two questions
    1. how can i hide/show the anchors (the circles on the edge of the images) when mouseover/mouseout on the image?

    2. I’m trying to set a transparent background so like when the smaller image has a white background and moving on top of the larger image it should HIDE the white background.

Leave a Comment