I'm experimenting of using javascript to draw something in HTML5.
And I want the shape can be interactive.
I know that I can calc the current mouse's pos whether or not fall into the shape(any shape, maybe irregular shape.) by javascript.
But it's too trivial.
Is it there some api or lib to do this calc in some convinience.
Like, just for example.
var anyshape = new Shape();
anyshape.addEventListen('mousemove', onMouseMove);
or
var anyshape = new Shape();
anyshape.onMouseMove = function(){};
Fabric.js provides shape dragging out of the box. There's also support for event listening and detection of objects clicked/hovered/etc.
var myShape = /* any shape */;
canvas.observe('mouse:down', function(e) {
if (e.memo.target === myShape) {
/* mouse down on myShape */
}
});
Also take a look at event inspector demo.
You've gotta implement all that functionality yourself or else use a library.
If you don't want to use a library, I've written a few tutorials on making movable shapes.
I'd highly recommend taking a look at SVG and seeing if that would suit your needs better. Complex paths that have event listeners and hit testing built in are already there in SVG.
http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-path-tutorial/ kinetic gives you the best and most easy way. You can now simply add multiple svgs and event listeners in a for loop.
for{
create shape code
add event listener
console log - kinetic rocks
}
Related
I've gotten myself into a big and weird position.
I use VivaGraph JS for drawing Conceptual Graphs in the browser. The specific implementation I am using, relies on SVG, and thus my main graph DOM element is an SVG.
During the creation of Edges between nodes, I wrote a small piece of code using Paper.JS which uses canvas from HTML5. In fact, I hacked into the source code provided by vektor.js and simply changed it to listen to CTRL+MouseDown events.
Those two elements, the svg graph and canvas, overlap and have exactly the same dimensions. The graph has nodes and edges manipulated, which listen to mouse and keyboard events, and sadly so does my canvas.
In fact, the reason for using the canvas, was that I wanted to draw a line (a vector or edge or arc) during the mouse-movement, to show to the user what the edge being created would be, before I actually created that edge in the graph.
I could not do this using SVG (Yes, I know, it should be doable) and Paper.js made it extremely easy for me.
Sadly, depending of the order those DOM elements are displayed, either the canvas captures the events, leaving the graph useless, or the graph captures all events, leaving the canvas useless.
Is there some way to add transparency to both DOM elements?
The event listener for the graph, is built into VivaGraphJS, and the event listener for the Paper Vertex, is built into Paper.JS
Ideally, I would like to have the graph on-top, capture the events, and then propagate them back to the canvas, so that the arrows are drawn. I have the feeling that this should be doable, either via pure JavaScript, or by using jQuery.
So far, the events captured in the graph like this:
var graphics = Viva.Graph.View.svgGraphics();
/// some other stuff
graphics.node( function( node )
{
var ui = Viva.Graph.svg('g' ).attr('width', nodeSize )
.attr('height', nodeSize )
// Position the node, add its text, etc, etc...
$( ui ).mousedown( function( event )
{
event.preventDefault();
if ( event.ctrlKey )
{
if ( ctrl_mouse )
{
createEdge( ctrl_mouse, node.id );
ctrl_mouse = null;
// Remove the temporary arrow from canvas - the graph now has a permanent edge
}
else if ( !ctrl_mouse )
{
ctrl_mouse = node.id;
// Start drawing a temporary arrow on canvas
}
}
All this takes place in one file graph.js
In another file edge.js, I setup the event listeners and the way the vector is drawn. I've added it into jsfiddle but sadly it won't run there (I am guessing the keyboard events may not be propagated properly?).
The problem is that Paper.Js has its own event listeners:
function onMouseDown( event )
function onKeyUp( event )
function onMouseMove(event)
Obviously those events have their equivalent in pure JavaScript and jQuery, but the ones I capture in VivaGraphJS or jQuery cannot be propagated to PaperJS, since they are different objects.
So, can I somehow (preferably by using pure JavaScript, but jQuery will also work) emulate or send those events to Paper.JS?
Since nobody answered, and I am guessing this is due to the very specific nature of my question, I stumbled upon the correct answer on another post here in stack overflow. Weirdly enough it was not accepted as the correct answer.
The poster suggested the following:
quickDelegate = function(event, target) {
var eventCopy = document.createEvent("MouseEvents");
eventCopy.initMouseEvent(event.type, event.bubbles, event.cancelable, event.view, event.detail,
event.pageX || event.layerX, event.pageY || event.layerY, event.clientX, event.clientY, event.ctrlKey, event.altKey,
event.shiftKey, event.metaKey, event.button, event.relatedTarget);
target.dispatchEvent(eventCopy);
// ... and in webkit I could just dispath the same event without copying it. eh.
};
This worked for me, and it was the only thing that worked. I tried other libraries I found on github which supposedly forward events, but they didn't work.
How do I bind a mouseover or any event for that matter to a drawn object on the canvas? For instance, I tried this:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
//STEP ONE
var stepOneRec = ctx.rect(20, 60, 266, 50);
ctx.stroke();
stepOneRec.addEventListener("mouseover", function() { alert('it works!'); });
On one site I looked at it showed a method using Kinetic.js. If that's the only way, I'll use it, I just assume that there's a way to bind events to drawn elements without extra plug-ins. Sorry Canvas noob. I made a fiddle with my code here: http://jsfiddle.net/jyBSZ/2/
(I started this as a posted comment, then realized it's an actual answer.)
Unfortunately, in javascript on it's own, you can't. There are no canvas objects, just the canvas as a whole, and whatever you drew on to its context. Plugins like kinetic can make objects for you, but the whole point of canvas is that the browser can think of it as a single static image.
If you want to, you can bind mousemove events to the canvas, track its position and the position where you drew stuff, and imply on your own that it's over "that object" (effectively what the plugins do), but it's all mousemove events on a single canvas rather than mouseover events on components of it. (You could even make your event binding simulate a mouseover event for the "objects", but underneath, it's still based on checking movement and checking your own object setup.)
The objects drawn within a canvas element are not HTML elements, just pixels, and therefore will not throw DOM events the way that HTML elements would.
You would need to track the locations of your objects yourself and handle the canvas' onmousemove event in order to determine when the mouse is over one of your drawn objects.
you can use jCanvas, take a look here
i made a jsfiddle example for your problem.
just modify next callbacks for desired result
function mouseOut(layer){
$("#mouse-over-text").html('none options selected');
}
function mouseIn(layer){
$("#mouse-over-text").html(getTextForId(layer.name));
}
Is there a way i can make shape of a dialogue bubble and show the statistics inside that dialogue bubble in raphael js
Any help is appreciated
Rafael syntax seems similar to HTML5 canvas. You should be able to just create stroke coordinates to draw the shape of the bubble as you would like it to appear.
Graphael provides a few default methods for text bubbles:
Raphael.fn.g.tag(x,y,text,angle,r)
Raphael.fn.g.flag(x,y,text,angle)
Raphael.fn.g.label(x,y,text)
Raphael.fn.g.blob(x,y,text,angle,size)
Raphael.fn.g.popup(x,y,text,dir,size)
so, for example...
window.onload = function(){
var r = Raphael('graph');
var flag = r.flag(100,100,"Hello!",15);
}
If those don't cut the mustard, then you will want to create your own svg path. You might then want to check out some paths Dmitry has made available here: http://raphaeljs.com/icons/
Ideally there is a way to mimic the mouseover imagemap capabilities of the following javascript using touchstart and touchmove on the iphone/ipad:
http://www.netzgesta.de/mapper/
I wish to allow the iphone/ipad user to touch the map, have the country they've touched highlight, and when they drag their finger over other countries, those countries in turn light up, just as they would via a desktop browser using mouseover.
Ideas, thoughts? Is this even possible?
You might try using touchesBegan and touchesMoved to get the coordinates of your touch and then check to see if those are within the object on your map. To get these coordinates, use:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchedPoint = [touch locationInView:self.view];
//now you can use touchedPoint.x and touchedPoint.y for the coordiantes of the touched point.
}
Similarly, you can use
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchedPoint = [touch locationInView:self.view];
}
There also exists touchesEnded and touchesCancelled. You can use these to get the coordinates of the touch, afterwards it is up to you to interpret these points. You could approximate rectangles for each section to be rolled over which would make this rather simple, but if you have a map with the intended functionality as the javascript map, you would need more complex shapes and would have to use other methods to define the shape.
I am experimenting with html5 and I have a little image dropdown, the user selects and image and it draws it to the canvas using drawImage();
I can't seem to figure out how to add an event listener to the newly drawn image on the canvas.
I have tried putting it in a variable like so:
var newImg = ctx.drawImage(myImage, 200, 200);
and then adding an eventlistener to that, but it doesn't seem to work.
newImg.addEventListener('mousedown', onImgClick, false);
What is the correct way to do this.
If you're looking for this sort of interactivity, <canvas> is probably not what you want. You're looking for SVG. There is a fantastic library called Raphaël that makes working with SVG a piece of cake on all browsers, even on IE6. It's also completely compatible with jQuery, so you can do:
var paper = Raphael(10, 50, 320, 200);
var img = paper.image("/path/to/img.png", 10, 10, 80, 80);
$(img).click(onImgClick);
I'm pretty certain this will treat you better and be easier to use than <canvas>.
Note: Raphaël does come with some helpers for basic events like "click" and "mousedown", just do img.click(onImgClick), but if you're already using a library like jQuery, which you probably are, I'd recommend being consistent and using the library's event handling.
Canvas is not a retained-mode drawing surface. It's just a flat image; there is no object inside it to bind events to, and drawImage returns nothing.
You will have to detect clicks on the <canvas> and check if they are inside the [200, 200, 200+w, 200+h] rectangle manually. Or, if you want retained-mode drawing, consider using SVG instead of a canvas.
To do this without the help of JS:
Although you can't attach an event listener to the context on which you call drawImage(); you CAN attach event listeners to the Canvas itself.
myCanvasElement = document.getElementById('canvasElement');
myCanvasElement.addEventListener("click", someFunction, false);
If you need to have this per-image that you draw, you could probably stack the canvas objects and create a new one for each image you draw.