I am trying to create an EaselJS app that lets me drag unfilled circles around the canvas - so instead of calling beginFill when I am setting up the Shape I would call beginStroke. I am running into the problem that if I don't fill the shape, I can only drag it when I am selecting the top left corner of the shape. When the shape is filled I can drag it by selecting anywhere within the shape. Is there a way I can make the unfilled shape drag the same way as the filled shape?
Strokes and fills are necessary in EaselJS for masks. You could however assign an other Shape as hitArea:
var shape = new createjs.Shape();
shape.graphics.beginFill("#000000").drawCircle(0, 0, 40);
draggableCircle.hitArea = shape;
Keep in mind that the hitArea-Shape doesn't have to be added to the stage and thus won't be visible.
Related
I've been using easelJS within the createJS framework for a project and have enjoyed it a lot until recently hitting a roadblock. I have multiple objects that I'd like to move simultaneously when one of the group is dragged. Here is my current situation:
What I'd like to do is when the red circle is moved, the red crosshairs would also move so that they appear to be "locked" to the circle. The same with the green circle.
I have been able to accomplish something very close to this by adding the circles and crosshairs to a container, as mentioned in the answers to this question:
Easeljs Scrollable Container
But the issue I encounter is that the container is actually a rectangle, such that I can click anywhere between the circle and crosshairs to move the various objects contained within the container. Instead I would like for the objects to be moved only when I click on a circle.
Does anyone have any idea how to accomplish this? Am I correct in thinking this can be accomplished somehow with easelJS containers?
Containers should be fine. You can turn off mouseEnabled on the cross-hair in order to make it ignore the mouse.
You could also just store the offset for each cross-hair/circle, and just set the cross-hair position when the circle moves.
Here is a quick demo:
http://jsfiddle.net/lannymcnie/kah9of6e/
// Set the offset when the circle is pressed
circle.on("mousedown", function(e) {
circle.offset = new createjs.Point(crosshair.x-circle.x, crosshair.y-circle.y);
});
// Add drag and drop to each shape
circle.on("pressmove", handleDrag);
crosshair.on("pressmove", handleDrag);
function handleDrag(e) {
// Move the target to the mouse
e.target.x = e.stageX; e.target.y = e.stageY;
// If the target is the circle, also move the cross-hair
if (e.target == circle) {
// Move the cross-hair
crosshair.x = circle.x + circle.offset.x;
x.y = circle.y + circle.offset.y;
}
}
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 problem with canvas createPattern. I have two boxes, both will move after pressing a keyarrow:
Example:
http://jsfiddle.net/wA73R/1/
The problem is that the box background filled by createPattern also is moving. How to avoid that? Is there any solution? The big box is only an example (drawImage is not the good solution for me, I need something that will repeat background image).
Thank you for help
The problem is that the box background filled by createPattern also is moving.
Actually your problem is that the background is not moving - it is static, while you are drawing your rectangle to different positions.
How to avoid that?
The pattern will always be drawn at the coordinate origin, whose actual position is defined by the current transformation. In future you will be able to transform the pattern itself with the setTransform method, but since that currently is not implemented anywhere you instead will have to change the global transformation matrix.
In your case it means, that instead of drawing your rectangle at x/y, you translate the whole context to x/y and draw your rectangle at 0/0 then:
ctx.fillStyle=pattern;
ctx.save();
ctx.translate(boxes[i].x - left , boxes[i].y);
ctx.fillRect(0, 0, boxes[i].width, boxes[i].height);
ctx.restore();
(updated demo)
I just wonder how do the Canvas transformations work. Lets say i have a canvas with a circle drawn somewhere inside of it, and i want to scale the circle, so its center point will not move.
So i thought about doing the following:
translate(-circle.x, -circle.y);
scale(factor,factor);
translate(circle.x,circle.y);
// Now, Draw the circle by calling arc() and fill()
Is it the right way to do it? I just don't understand whether the canvas was designed to remember the order that i call the transformations.
Thanks.
Yes, you are correct.
The canvas accumulates all transforms and applies them to any future drawing.
So if you scale 2X, your circle will be drawn at 2X…and(!) every draw after that will be 2X.
That’s where saving the context is useful.
If you want to scale your circle by 2X but then have every subsequent drawing be at normal 1X you can use this pattern.
// save the current 1X context
Context.save();
// move (translate) to where you want your circle’s center to be
Context.translate(50,50)
// scale the context
Context.scale(2,2);
// draw your circle
// note: since we’re already translated to your circles center, we draw at [0,0].
Context.arc(0,0,25,0,Math.PI*2,false);
// restore the context to it’s beginning state: 1X and not-translated
Context.restore();
After Context.restore, your translate and scale will not apply to further drawings.
I wanted to know if Html5 supports shape translation in canvas..For instance I have a rectangle,is it possible to apply a transformation to it?
canvas = document.getElementById('Canvas');
context =canvas.getContext('2d');
context.rect(myRectangle.x,myRectangle.y,myRectangle.width,myRectangle.height);
There's a few different methods for animating and changing the position that you want to draw your thingy. Either way, if you're after an animation, you're going to need to clear your canvas and keep drawing - like a flip book if you will.
Choices for setting the newly drawn item include:
moveTo - to move to the new position of your thing
translate - to translate the centre point of the canvas and keep the drawing positions the same, but move the underlying coordinate system
.rect(newX, newY, height, width) - drawing the specific position
I mocked together a (contrived) example of using translate on a canvas - which will move the the animating box around the position of your cursor. It's done in a loop - and I'd suggest checking out Paul Irish's article on requestAnimFrame for better animation loops. Here's the example: http://jsbin.com/afofur/2/edit#preview
As the comments say in the previous answer - SVG maintains a object model, so you can reference objects on the page, canvas is a bitmap API (basically), and once the pixels are committed to the canvas, there's no reference to the method or shape behind the drawing, it's just pixels to the canvas API.
No, once it is drawn to the canvas you can't change it anymore, there is no in-memory representation of the shapes you draw on the canvas. However, you can transform the canvas before you draw the shape and reset transform (canvas.setTransform(1, 0, 0, 1, 0, 0)) after you've drawn the shape.
Edit
Remember that the canvas API doesn't keep track of which objects you draw. It just fills the pixels with a color where you ask it to draw a rectangle. If you want to make animations, you will have to keep track of which rectangle you drawn yourself (make an object with properties x, y, width, height). Then you will have to do the following in each animation step:
clear the canvas
update the objects for the new time frame
redraw the canvas
You can find a tutorial here.