Please see my fiddle: http://jsfiddle.net/haiphong/BRjFE/
You can hold SHIFT and then drag and drop the rectangle to move it and the circle inside it around. You can hold SHIFT and zoom as well. This zoom/pan is done by d3.behavior.zoom(). Works well.
I want to zoom and pan the circle when NOT holding shift. So, I create another d3.behavior.zoom(). However, the circle can be zoomed but not panned. By debugging, I see that when I pan the circle, the handling code doesn't execute.
In sum, when binding a zoom to both the outer g element and the inner g element, the outer works well for zoom/pan; however, the inner only works for zoom. How to get it work for pan as well?
I found the solution for my answer. http://jsfiddle.net/haiphong/BRjFE/4/
When I pan the circle, its zoom event doesn't fire. However, its zoomstart event fires and it is fired before its parent's zoomstart. Somehow, when the parent's zoomstart fires, it eats the circle's event.
So, in the zoomstart of the circle, I force the event stop propagating when SHIFT isn't being hold. That makes the circle zoom fires.
Related
Alright, so I have a good deal of experience with HTML and CSS, and some experience with Javascript (I can write basic functions and have coded in similar languages).
I'm looking to start some visual projects and am specifically interested in getting into particle systems. I have an idea for something similar to Codecademy's name generator here (https://www.codecademy.com/courses/animate-your-name/0/1) where particles are mapped to a word and move if hovered over. It seems as though alphabet.js is what's really behind Codecademy's demo however I can't understand exactly how they mapped the particles to a word, etc.
I've done some basic tutorials just creating rudimentary particles in a canvas but I'm not sure a canvas is the best way to go - demos that utilize one of the many libraries available (such as http://soulwire.github.io/sketch.js/examples/particles.html) don't use a canvas.
So my question is - what is the best way for a beginner/intermediate in Javascript to start with particle systems? Specifically to accomplish the Codecademy name effect or similar? Should I try to use canvas or which library would be best to start with and how would you recommend starting?
The code for this project is achievable for your intermediate JS programmer status.
How the CodeAcademy project works ...
Start by building each letter out of circles and saving each circle's centerpoint in an array. The alphabet.js script holds that array of circle centerpoints.
On mousemove events, test which circles are within a specified radius of the mouse position. Then animate each of those discovered circles radially outward from the mouse position using simple trigonometry.
When the mouse moves again, test which circles are no longer within the specified radius of the current mouse position. Then animate each of those "outside" circles back towards their original positions.
You can also use native html5 canvas without any libraries...
Another approach allowing any text to be "dissolved" and reassembled
Start by drawing the text on the canvas. BTW, this approach will "dissolve" any drawing, not just text.
Use context.getImageData to fetch the opacity value of every pixel on the canvas. Determine which pixels on the canvas contain parts of the text. You can tell if a pixel is part of the text because it will be opaque rather than transparent.
Now do the same procedure that CodeAcademy did with their circles -- but use your pixels:
On mousemove events, test which pixels are within a specified radius of the mouse position. Then animate each of those discovered pixels radially outward from the mouse position using simple trigonometry.
When the mouse moves again, test which pixels are no longer within the specified radius of the current mouse position. Then animate each of those "outside" pixels back towards their original positions.
[Addition: mousemove event to test if circles are within mouse distance]
Note: You probably want to keep an animation frame running that moves circles closer or further from their original positions based on a flag (isInside) for each circle.
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calc the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// test each circle to see if it's inside or outside
// radius of 40px to current mouse position
// circles[] is an array of circle objects shaped like this
// {x:,y:,r:,originalX:,originalY:,isInside:}
var radius=40;
for(var i=0;i<circles.length;i++){
var c=circles[i];
var dx=c.x-mouseX;
var dy=c.y-mouseY;
if(dx*dx+dy*dy<radius*radius){
c.isInside=true;
// move c.x & c.y away from its originalX & originalY
}else{
c.isInside=false;
// if the circle is not already back at it's originalX, originalY
// then move c.x & c.y back towards its originalX, originalY
}
}
}
I have a transparent drag layer on top of a shape layer. Works great to make interaction distinct so I can toggle what dragging does (between scrolling the view or editing the shape positions). However, unless I turn off drag mode (by hiding the intervening transparent Rect), none of the other mouseover events fire on the shape layer beneath it. I need to propogate the non-drag mouse events to the layer below it. There are A LOT of shapes with mouse over events.
Is there an easy way to propogate the mouse over events to the layer beneath it or do I need to write a custom handler to fire events for every shape?
I managed to solve this without having to propagate events between layers. I put a draggable surface behind the shapes on the shape layer only if a shape isn't clicked. Then to cover if a shape is clicked, on the shape dragstart event, if a layerdraggable flag is set, I do a stopDrag() on the shape and a startDrag() on the layer. This allowed me to toggle with a simple flag whether I want the whole layer dragging, or just the shape.
I had to clean up a little of the shape position on the dragend event, but alternatively you can do that with a dragbounds on the shape.
shape.on('dragstart', function () {
if (layerDraggable) {
shape.stopDrag();
shapeLayer.startDrag();
}
}
I'm using Fabric.js and I'm looking to have the canvas.on('object:moving') event fired but not when a mouse drags it. I want to do it if I animate the position moving by itself. I could not achieve this by adding the listener and making object.left -= 2.
I added a jsFiddle for this. At first, you will be able to drag the circle and the line will follow. Then uncomment line 49 and watch the circle move and the line will stay still.
http://jsfiddle.net/P5UJM/
I'm making a game where the bubbles (circles) appear on the screen and move upwards and I'm using HTML5 and JavaScript only which means no frameworks like kinetic and no jQuery at all.
I've come to a point where I want to add an event listener to the bubble itself, now I understand that because the bubble is an object on the canvas, it has no method 'addEventListener' so I can't directly add a click event to the bubble, I was wondering if anybody could help me with this problem I'm having? Here is a fiddle of what happens so far...
Bubbles
I have tried to add the event listener to the bubble as specified before by doing this...
bubbles[i].addEventListener('click', function);
I have also tried adding mouseevents such as
bubbles[i].onmouseenter = function () { console.log("blah") }
But now, I'm seriously at a loss
Thanks in advance!
I have updated your sample on jsfiddle demonstrating hit-testing. This sample uses an onmousemove event handler bound to the canvas and performs the actual hit-test when this event occurs. The hit-test in your case is "Is the mouse coordinate with in the bubble's circle?"
Summary of changes:
A "bubble" has a color property to demonstrate the effect of a hit test.
function hitTest(x, y) { ... } used to test whether the passed in coordinates are within the bubble.
function getMouse(e, canvas) ... used to transform the mouse coordinates to canvas relative coordinates. i.e, the mouse coordinate needs to be relative to the upper left hand corner of the canvas to be accurate.
From the d3.js bubbles example I have added the zoom + pan functions. Now I want to allow users to select a bubble on desktops and touch-screens. The dblclick and touchstart seem to be consistent for this.
I know d3 provides a way to cancel an event from .zoom but then it is disabled and doesn't do anything.
.call(d3.behavior.zoom().on("zoom", zoom)).on("dblclick", null);
Link: http://bl.ocks.org/4163494
What I have above sort of works but you will notice that a dblclick doesn't zoom at first but then it is revealed if you cause another zoom event. I am looking for the right way to do this.
To fix I left the
.on("zoom", redraw)
function where it was but moved the dblclick down to the circle, text, and tspan elements. From there they call a function that first stops propagation and then selects the circle.
http://jsfiddle.net/nnzS9/