Highlighting Graph Points clicked on in HTML Canvas - html

I currently have an html page that produces a line graph inside a canvas element. I have also implemented a feature so that when you click on a point in the graph, a table below the canvas displays the information for that graph point, and clears if you click somewhere that isn't a graph point on the canvas. However, there is currently no indicator for what graph point you have selected.
I would like to make it so that the dot you click on either gets bigger, or highlighted, or something. Unfortunately, I don't think there's any way to do that on the one canvas without needing to redraw the entire graph afterwards. If I drew a bigger dot on top of the original, I would then need to erase it and replace it with the smaller one, as well as redrawing the segment of the line graph that was covered by the larger dot.
I was looking into using a second canvas on top of the first with identical dimensions, using a z-index to control which was on top. However, I don't know how this would affect the click event. If two canvasses are on top of each other, is it possible for the click event to register the lower canvas? Does it only register the higher one? I guess I could just change the click event to be for whichever canvas is on top, but keep all the code for drawing on the canvas the same.
Any advice for how to solve this problem?

Solved a few of my own questions.
Firstly, the click event will only recognize whichever canvas is on top. However, I did like I said, and changed my click event to be for the top canvas, while leaving all instructions on the inside to be for the top canvas. Thank goodness I didn't use the 'this' keyword, or the change would have been much more annoying.
To make the graph points highlight, I first added a second canvas on top of my first one, placing them on top of each other by making their positions "absolute" and giving them a z-index of 0 and 1 respectively. Then, inside the if statement where the original click event recognized that a point had been clicked on, I told the top canvas to draw a larger dot on the same coordinates as the first dot (which I had saved in an array). First, I had it clear the top canvas though, so any other highlighted dots would no longer be highlighted. If the canvas was clicked on somewhere other than a dot, nothing was highlighted.

Related

Drawing overlapping semi-transparent lines without visible overlap

I'm developing a painter program using HTML5 canvas. I have created a drawing tool where the user drags and moves the mouse.
I have a listener on mousemove event that draws short lines:
Painter.mainCanvas.beginPath();
Painter.mainCanvas.moveTo(Painter.lastX, Painter.lastY);
Painter.lastX = e.offsetX;
Painter.lastY = e.offsetY;
Painter.mainCanvas.lineTo(Painter.lastX, Painter.lastY);
Painter.mainCanvas.stroke();
Everything works well until I set the global Alpha to < 1. When using this method to draw, the end dot is also start dot. So the dot is drawn twice. And because we have transparent color, the dot now has different color with other dots in line.
I tried another method that when mousemove fires, it only uses lineTo() and stroke() when mouseup fires.
This solves the double drawing problem, but also introduces a new problem: when user intend to draw same dot twice, ie, cross line without mouseup, the dot won't be drawn twice. Because lineTo() function won't draw a dot twice without stroke between.
(Restating your problem) Your original problem was that by calling beginPath() and stroke() for each segment you had many overlapping semi-transparent paths. Your new "problem" is that by creating all your lineTo() commands as part of the same path and then calling stroke() once at the end any self-intersecting paths intended by the user do not show a visible overlap.
Here is an example showing the difference between making
many semi-transparent lines in a single path and stroking once (upper left), versus
many semi-transparent lines in distinct paths and stroking each (bottom right)
http://jsfiddle.net/jhyG5/2/
I would say that your current solution (a single path) is the correct way to do it, even though a single self-crossing path does not double-up in opacity. This is what you see in Adobe Photoshop and Illustrator when drawing semi-transparent paths: all drawing with the mouse down is part of the same, single, non-overlapping transparent object. Only when the user releases and re-presses the mouse button do you accumulate more transparency:
Two Photoshop paintbrush strokes at 50% opacity:
Two Illustrator paths at 50% opacity:
Notice in particular that the self-intersecting stroke and path do not show double the opacity during crossing, but that a separate new path does.
I recommend that you stick with your current solution given that this is how these traditional, well-thought-out applications behave. I say this both because you want your package to mimic user expectations, and also because if these packages do it like this, there's probably a very good reason for it: the exact problem you originally had! :)

HTML5 canvas - opacity problem with a paint app

I'm trying to program a paint application using Canvas.
the way it works is by connection lines when the mouse is pressed.
when the line is opaque it works well, but when I change the alpha parameter I get a problem.
I tried two options:
a. The path begins when the mouse is down for the first time and ends when the mouse is up again:
every move of the mouse calls the stroke() function. because the line is transparent the beginning of the whole path will become opaque and the end won't, because stroke() is called many times, and it drwas the whole path again and again.
b. The path begins and ends every move of the mouse:
the line is transparent through the whole way, but the matching point between every path and path are less transparent (because they're made of two lines). so the whole path is not solid.
the only way I get a good result is when I call stroke() only when the mouse is up again. then it strokes the whole path well, but I see nothing while actually drawing it.
what can I do?
thanks
I think your best bet is to create a second overlay canvas that is positioned (using absolute positioning) over your primary canvas.
During a mouse drag, for every mousemove event use a clearRect() to clear your overlay canvas and then draw the entire stroke-in-progress.
When you get a mouseup, clear the overlay and draw the entire stroke to the primary canvas.
Here's a live example:
http://jsfiddle.net/rnNFB/1/

Get Image src attribute value for HTML5 canvas element

I have been searching - am thinking what I want to do is not possible but thought I would check.
I have a few canvasses on an HTML page as follows: (these are IDs below)
canvasMain - this is going to display
a large version of an image
canvasThumbnail1 - this is going to
display a thumbnail image
canvasThumbnail2 - same as
above...etc
I have it working where I paint the canvasMain with the contents of the thumbnail. The problem is since the canvas is immediate it is copying the pixels as they are over to the canvasMain from canvasThumbnail. This is resulting in an enlarged pixelated image.
What I want to do is click on one of the canvasThumbnails and be able to grab the Image.src property as a string and then pull that into canvasMain instead of actually copying the pixels over from one canvas to another. Essentially just grab the address (local or say on Flickr) from where I can pull in the image. Pulling an image in to a canvas seems to scale it nicely.
From what I have seen I do not think that Image.src value is accessible through the 2d context. I enumerated through its properties and have only found nested objects or native code returns.
I figured that if I clicked on the canvasThumbnail, and then used (this) to get a reference to that canvas element and then grab the 2dcontext of that canvas I may be able to use a property of that context to get a string that represents the value of the Image.src.
Any ideas?
Thanks
Somehow you painted the image onto canvasThumbnail1, presumably from a (high resolution) Image element.
The canvasThumbnail1, or any canvas for that matter, has no memory on things painted on it. So if you paint a large Image onto a tiny canvasThumbnail, the high-resolution data does not exist on that tiny canvas. To get it you must use the original image again, or else you must paint to a larger canvas from the start.
In other words, instead of painting the thumbnail onto the main, you need to repaint Image element (that you used to make the thumbnail) onto the main.

Drag objects in canvas

Im looking for an easy to use method of assigning drag behavior to multiple objects (images, shapes etc) in canvas. Does anyone have a good way or know of any libraries for dragging objects around? Thanks
Creating your own mouse events takes a little work - ideally you should either create or use some kind of mini-library. I'm thinking of creating something like this in the near future. Anyway, I created a drag and drop demo on jsFiddle showing how to drag images - you can view it here.
You can create draggable images like this:
var myImage = new DragImage(sourcePath, x, y);
Let me know if you have any questions about this. Hope it helps.
EDIT
There was a bug when dragging multiple images. Here is a new version.
Another thing you might want to check out is easeljs it sort of in the style of AS3... mouseEvents dragging etc...
The HTML Canvas—unlike SVG or HTML—uses a non-retained (or immediate) graphics API. This means that when you draw something (like an image) to the canvas no knowledge of that thing remains. The only thing left is pixels on the canvas, blended with all the previous pixels. You can't really drag a subset of pixels; for one thing, the pixels that were 'under' them are gone. What you would have to do is:
Track the mousedown event and see if it's in the 'right' location for dragging. (You'll have to keep track of what images/objects are where and perform mouse hit detection.)
As the user drags the mouse, redraw the entire canvas from scratch, drawing the image in a new location each time based on the offset between the current mouse location and the initial mousedown location.
Some alternatives that I might suggest:
SVG
Pure HTML
Multiple layered canvases, and drag one transparent canvas over another.
The HTML Canvas is good for a lot of things. User interaction with "elements" that appear to be distinct (but are not) is not one of those things.
Update: Here are some examples showing dragging on the canvas:
http://developer.yahoo.com/yui/examples/dragdrop/dd-region.html
http://www.redsquirrel.com/dave/work/interactivecanvas/
http://langexplr.blogspot.com/2008/11/using-canvas-html-element.html
None of these have created a separate library for tracking your shapes for you, however.
KineticJS is one such Javascript Library that u can use exclusively for animations
Heres the Link html5canvastutorials
Canvas and jCanvas
You're definitely gonna want to check out jCanvas. It's a super clean wrapper for Canvas, which kicks open a lot of doors without adding code complexity. It makes things like this a breeze.
For example, here's a little sandbox of something close to what you're after, with dragging and redrawing built right in:
Drawing an Arrow Between Two Elements.
I ventured down the road of doing everything with DIVs and jQuery but it always fell short on interactivity and quality.
Hope that helps others, like me.
JP
As you create new objects whether they are windows, cards, shapes or images to be draggable, you can store them in an array of "objects currently not selected". When you click on them or select them or start dragging them you can remove them from the array of "objects not selected". This way you can control what can move in the event of a particular mousedown event or mousemove event by checking if it isn't selected. If it is selected it will not be in the "not selected" array and you can move the mouse pointer over other shapes while dragging shapes without them becoming dragged.
Creating arrays of objects you would like to drag also helps with hierarchy. Canvas draws the pixels belonging to the foremost object last. So if the objects are in an array you simply switch their instance as in element in the array say from objectArray[20] to objectArray[4] as you iterate through the array and draw the objects stored in the array elements you can change whether other objects are seen on top or behind other objects.

How to drag and drop from one HTML5 canvas to another

I'm trying to figure out how to drag and drop an image from one canvas to another canvas. Assuming the canvases are next to each other, would it be possible to seamlessly drag something across the border? If not, is it a better idea to drag a div over the canvas, get its ID, and place it by responding to the mouseup location on the canvas?
You don't drag items on a canvas. A canvas is a non-retained mode (or immediate mode) graphics API. You issue draw commands and you get pixels. Simulating dragging is comprised of tracking the user's mouse movements and choosing to repeatedly clear and re-draw the canvas with different parameters to make some subset of the pixels appear to move as a cohesive object.
Contrast this with HTML or SVG where you actually change position/transform properties of a real DOM object and the watch as the visual representation of your document updates automatically.
If you have two canvases and want to drag something from one to the other, what I would do is:
On mouse down on the 'menu' canvas, create a new canvas programmatically just as large as the object, and (using absolute CSS positioning) place it over top of the item the user clicked on.
Draw the item onto that canvas.
Track the mousemove event on the document, and update the position of the canvas relative to the mouse.
When the user releases the mouse over the destination canvas, throw away (or hide) your tiny 'dragging' canvas, and re-draw the main canvas with the item that was dragged in the appropriate location.
Though, what I'd probably really do here is use SVG. ;)
Check this answer.
It is for multiple select drag & drop, but maybe will be useful.
Why does this need to be 2 canvases? The canvas is your drawing area, you control it. Why do you need 2?