I'm trying to create a detailed animation using Raphael that has multiple scenes, but I've run into an issue; how can I delay the removal of elements if I want to move onto another scene? In my animation, the first "scene" is of four seals popping out of a body of water, after which I want them to be underwater, which would require the removal of unneeded elements from that scene. I'm not sure however how to remove those elements at the time that the first scene ends. The only way I can think of doing this at the moment is by cheating and animating them off the page. Also, is there a way to group elements together from the first scene and then remove that group instead of having to remove them all individually? Here's what I have so far:
window.onload = function (){
var paper = new Raphael( 0, 0, 800, 600);
var backGround = paper.rect(0,0,800,600).attr({ fill: "90-white:60-#9dc8f3", stroke : "none"});
var sun = paper.circle (400, 300, 60).attr({ fill: "90-orange-yellow", stroke : "none"})
var water1 = paper.rect(0,200,800,400).attr({ fill: "#2e659c", stroke : "none"});
var seal1 = paper.image("sealright.png", 190, 270, 140, 175);
var water2 = paper.rect(0,280,800,400).attr({ fill: "#2e659c", stroke : "none"});
var seal2 = paper.image("sealleft.png", 430, 350, 180, 225);
var water3 = paper.rect(0,360,800,400).attr({ fill: "#2e659c", stroke : "none"});
var seal3 = paper.image("sealright.png", 70, 430, 220, 275);
var water4 = paper.rect(0,440,800,400).attr({ fill: "#2e659c", stroke : "none"});
var seal4 = paper.image("shadeseal.png", 460, 510, 260, 327);
var water5 = paper.rect(0,520,800,400).attr({ fill: "#2e659c", stroke : "none"});
var iceright = paper.image("icerights.png", 584, 198, 276, 246.5);
var iceleft = paper.image("icelefts.png", -60, 198, 276, 246.5);
var opac = paper.rect(0,0,800,600).attr({ fill: "white", "fill-opacity": "0.4",stroke : "none"});
var playButton = paper.path("M 300 180 R 500 300 300 420 z");
playButton.attr({fill: '#eff', stroke: '#9df', 'stroke-width': 10});
playButton.hover(function () {
playButton.attr({"stroke": "#fff"});
},
function () {
playButton.attr({"stroke": "#9df"});
}
);
var sunanim = Raphael.animation({cy : 100, opacity: "0.4"}, 1000, "elastic");
var sealanim = Raphael.animation({y : 170}, 300, "backOut");
var sealanim2 = Raphael.animation({y : 210}, 300, "backOut");
var sealanim3 = Raphael.animation({y : 260}, 300, "backOut");
var sealanim4 = Raphael.animation({y : 310}, 300, "backOut");
var backgroundchange1 = Raphael.animation({ fill: "90-#0d0e46-#0b94da"}, 0);
function musicStart(){
opac.remove();
var clickSound = new Audio('Funk-tabulous.mp3');
clickSound.play();
};
function musicStart(){
opac.remove();
var clickSound = new Audio('Funk-tabulous.mp3');
clickSound.play();
};
function anim(){
sun.animate(sunanim.delay(1000))
seal1.animate(sealanim.delay(2000));
seal2.animate(sealanim2.delay(2400));
seal3.animate(sealanim3.delay(2800));
seal4.animate(sealanim4.delay(3200));
};
function remove(){
sun.remove();
};
function anim2(){
backGround.animate(backgroundchange1.delay(3800));
};
function animation(){
playButton.remove();
musicStart();
anim();
anim2();
};
playButton.click(function(){
animation();
});
};
Could you just hide the element (otherwise you could use this same principle and make the function actually remove the element, the 4th animate element is a callback). So here is a combination that sequences a move after another move followed by a hide. Fiddle here http://jsfiddle.net/Lmbvm/3/
var paper = new Raphael(100,0,2000,2000);
var rect = paper.rect(50,50,50,50);
var rect2 = paper.rect(100,100,100,100);
var set = paper.set();
set.push( rect, rect2 );
var animation = Raphael.animation({ x: 200 },200,"linear", animateCircle);
set.animate( animation );
var circle = paper.circle(50,50,50);
function animateCircle() {
circle.animate({ cx : 200 }, 200, "linear", hideCircle);
};
function hideCircle() {
set.hide();
}
Edit: I've updated a fiddle here http://jsfiddle.net/Lmbvm/8/ to move a set as well
Related
I am inspired with KonvaJS tutorial Modify Curves with Anchor Points to make my own example which is to create multiple custom arrows.
on click on the selectionBox create an anchor.
on the creation of the third anchor create the curved arrow.
on the fourth click reset all variables in order to draw a new curved arrow.
var width = window.innerWidth;
var height = window.innerHeight;
// globals
var selectionBoxLayer, curveLayer, lineLayer, anchorLayer, quad, bezier;
function updateDottedLines() {
var q = quad;
var quadLine = lineLayer.get('#quadLine')[0];
quadLine.setPoints([q.start.attrs.x, q.start.attrs.y, q.control.attrs.x, q.control.attrs.y, q.end.attrs.x, q.end.attrs.y]);
lineLayer.draw();
}
function buildAnchor(x, y) {
var anchor = new Konva.Circle({
x: x,
y: y,
radius: 20,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
draggable: true
});
// add hover styling
anchor.on('mouseover', function() {
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
anchorLayer.draw();
});
anchor.on('mouseout', function() {
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
anchorLayer.draw();
});
anchor.on('dragend', function() {
drawCurves();
updateDottedLines();
});
anchorLayer.add(anchor);
anchorLayer.draw();
return anchor;
}
function drawCurves() {
var context = curveLayer.getContext();
var arrowLine = new Konva.Shape({
sceneFunc: function(context){
debugger;
// draw quad
context.beginPath();
context.moveTo(quad.start.attrs.x, quad.start.attrs.y);
context.quadraticCurveTo(quad.control.attrs.x, quad.control.attrs.y, quad.end.attrs.x, quad.end.attrs.y);
//Draw Arrow Head
var headlen = 10; // length of head in pixels
var angle = Math.atan2(quad.end.attrs.y - quad.control.attrs.y, quad.end.attrs.x - quad.control.attrs.x);
context.lineTo(quad.end.attrs.x-headlen*Math.cos(angle-Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle-Math.PI/6));
context.moveTo(quad.end.attrs.x, quad.end.attrs.y);
context.lineTo(quad.end.attrs.x- headlen*Math.cos(angle+Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle+Math.PI/6));
context.fillStrokeShape(this);
},
stroke: 'black',
strokeWidth: 4
});
curveLayer.add(arrowLine);
curveLayer.draw();
}
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
selectionBoxLayer = new Konva.Layer();
anchorLayer = new Konva.Layer();
lineLayer = new Konva.Layer();
// curveLayer just contains a canvas which is drawn
// onto with the existing canvas API
curveLayer = new Konva.Layer();
var quadLine = new Konva.Line({
dash: [10, 10, 0, 10],
strokeWidth: 3,
stroke: 'black',
lineCap: 'round',
id: 'quadLine',
opacity: 0.3,
points: [0, 0]
});
// add dotted line connectors
lineLayer.add(quadLine);
quad = {};
// keep curves insync with the lines
anchorLayer.on('beforeDraw', function() {
if(quad.start && quad.control && quad.end){
drawCurves();
updateDottedLines();
}
});
var selectionBoxBackground = new Konva.Rect({
x: 0,
y: 0,
height:stage.height(),
width: stage.width(),
fill: 'transparent',
draggable: false,
name: 'selectionBoxBackground'
});
selectionBoxLayer.add(selectionBoxBackground);
var clickCounter = 0;
selectionBoxBackground.on("click", function(){
clickCounter +=1;
var mousePos = {};
switch(clickCounter){
case 1:
mousePos = stage.getPointerPosition();
quad.start = buildAnchor(mousePos.x, mousePos.y);
break;
case 2:
mousePos = stage.getPointerPosition();
quad.control = buildAnchor(mousePos.x, mousePos.y);
break;
case 3:
mousePos = stage.getPointerPosition();
quad.end = buildAnchor(mousePos.x, mousePos.y);
drawCurves();
updateDottedLines();
break;
default:
clickCounter = 0;
quad = {};
anchorLayer.destroyChildren();
anchorLayer.draw();
}
});
stage.add(curveLayer);
stage.add(lineLayer);
stage.add(selectionBoxLayer);
stage.add(anchorLayer);
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
<script src="https://cdn.rawgit.com/konvajs/konva/0.11.1/konva.min.js"></script>
<body>
<div id="container"></div>
</body>
P.S Please note when I write in the browser console curveLayer.children, it will bring all created curved arrows.
Hint: I think on the creation of new Shape() the values of all created shapes will be changed to the new one.
I don't know what I am missing.
Here is js code:
var cv = Snap('#cv').attr({height: '100%', width: '100%'});
var mskHide = cv.rect().attr({height: '100%', width: '100%', left:0, top:0, fill: '#666'});
var mskShow = cv.circle(200, 200, 150).attr({fill: '#fff'});
var mskG = cv.group(mskHide, mskShow);
var bg = cv.circle(200, 200, 150).attr({fill: '#aaa'});
var customImg = cv.image('http://placehold.it/500/990000').attr({mask: mskG});
//when I drag the customImg, I want mskG fixed position
customImg.drag();
You can preview here: http://codepen.io/rlog/pen/eKBlc
The question is: When I drag the customImg, how can I fix the position of mskG.
The mskG is no need move whit costomImg
this example is what I want: http://codepen.io/rlog/pen/bAImu
Thanks!
You could basically do what you have in the 2nd codepen.
var cv = Snap('#cv').attr({height: '100%', width: '100%'});
var mskHide = cv.rect().attr({height: '100%', width: '100%', left:0, top:0, fill: '#666'});
var mskShow = cv.circle(200, 200, 150).attr({fill: '#fff'});
var mskG = cv.group(mskHide, mskShow);
var bg = cv.circle(200, 200, 150).attr({fill: '#aaa'});
var customImg = cv.image('http://placehold.it/500/990000').attr({mask: mskG });
customImg.drag( myDrag );
function myDrag(dx,dy,x,y) {
customImg.attr({ x: dx, y: dy })
}
codepen
If you want a different drag from the example shown to include stored start drag location, you would amend it something like the following...
customImg.attr({ x: 0, y: 0})
var move = function(dx,dy) {
this.attr({
x: +this.data('ox') + +dx,
y: +this.data('oy') + +dy
})
}
var start = function(x,y) {
this.data('ox', this.attr('x'));
this.data('oy', this.attr('y'));
}
var end = function(x,y) {}
customImg.drag( move, start, end )
codepen
i'm working on a drag&drop-function for images. I've oriented myself on this example here:
http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/
The JS framework KineticJS is used there.
In this example the properties (x,y,width,height) of Kinetic.Group and Kinetic.Image are set with 'normal' number values.
my problem is that i need this properties as variables, because my uploaded images have different values for height, width etc.
I've tried to change the code from the example for my own drag&drop web application, but it doesn't work as i want...
I can load and display images correctly, but i can't move or resize them. With number values for x,y,width,height it works all.
Here is the code of the changed method "initStage()" (the other methods are unchanged):
function initStage(images) {
stage = new Kinetic.Stage({
container: 'wb_dropzone',
width: 500,
height: 400
});
var imageGroups = new Array();
var imageInstances = new Array();
var layer = new Kinetic.Layer();
for(var i=0; i<Object.size(images); i++)
{
imageGroups[i] = new Kinetic.Group({
x: fileInfos[i][2][0]/*0*/,
y: fileInfos[i][2][1]/*0*/,
draggable: true
});
layer.add(imageGroups[i]);
imageInstances[i] = new Kinetic.Image({
x: 0/*fileInfos[i][2][0]*/,
y: 0/*fileInfos[i][2][1]*/,
image: images[i],
width: fileInfos[i][1][0],
height: fileInfos[i][1][1],
name: 'image',
stroke: 'black',
strokeWidth: 2,
dashArray: [10, 2]
});
imageGroups[i].add(imageInstances[i]);
addAnchor(imageGroups[i], 0, 0, 'topLeft');
addAnchor(imageGroups[i], fileInfos[i][1][0], 0, 'topRight');
addAnchor(imageGroups[i], fileInfos[i][1][0], fileInfos[i][1][1], 'bottomRight');
addAnchor(imageGroups[i], 0, fileInfos[i][1][1], 'bottomLeft');
imageGroups[i].on('dragstart', function() {
this.moveToTop();
});
}
stage.add(layer);
stage.draw();
}
More informations about "fileInfos":
[imagePath, [width, height], [X-pos., Y-pos.]]
(all dropped images are uploaded in a folder. The properties of each image are saved in a database.
Default x- and y-position is "0".)
Does anybody have an idea, how i can solve this problem?
I'm grateful for any help!
How to create draggable/resizable images that are loaded from your fileInfos
Call a function that creates the group+image+anchors based on your fileInfos[i]:
// pull info supplied by fileInfos for this “i”
var imgWidth=fileInfos[i][1][0];
var imgHeight=fileInfos[i][1][1];
var groupX=fileInfos[i][2][0];
var groupY=fileInfos[i][2][1];
// call a function that creates the draggable/resizable group
addImageGroup( images[i], imgWidth,imgHeight, groupX,groupY );
Here’s that function that creates the draggable/resizable group element:
function addImageGroup(image,imageWidth,imageHeight,groupX,groupY){
// width and height are based on the images width/height
var w=imageWidth;
var h=imageHeight;
var kGroup = new Kinetic.Group({
x:groupX,
y:groupY,
width:w+20, // must allow 10+10=20 for anchors
height:h+20,
draggable:true
});
layer.add(kGroup);
kGroup.on('dragstart', function() {
this.moveToTop();
});
var kImage = new Kinetic.Image({
x: 0,
y: 0,
image: image,
width: w,
height: h,
name: 'image',
stroke: 'black',
strokeWidth: 2,
dashArray: [10, 2]
});
kGroup.add(kImage);
addAnchor(kGroup, 0, 0, 'topLeft');
addAnchor(kGroup, w, 0, 'topRight');
addAnchor(kGroup, w, h, 'bottomRight');
addAnchor(kGroup, 0, h, 'bottomLeft');
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/buCzH/
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#container{
border:1px solid red;
width:350px;
height:350px;
}
</style>
</head>
<body onmousedown="return false;">
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.2.min.js"></script>
<script>
// create the stage
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer=new Kinetic.Layer();
stage.add(layer);
// build a test fileInfos array
// width/height will be gotten from actual images, so leave width/height==0
var fileInfos=[];
function addFile(x,y,w,h,imgURL){
fileInfos.push([imgURL,[w,h],[x,y]]);
}
addFile(30,100,102,102,"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg");
addFile(200,100,102,102,"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg");
// load all the images
var images=[];
loadAllImages();
function loadAllImages(){
var imagesOK=0;
for (var i = 0; i < fileInfos.length; i++) {
var img = new Image();
images.push(img);
img.onload = function(){
if (++imagesOK==fileInfos.length ) {
// all images are loaded, so build the groups
for(var i=0;i<fileInfos.length;i++){
var imgWidth=fileInfos[i][1][0];
var imgHeight=fileInfos[i][1][1];
var groupX=fileInfos[i][2][0];
var groupY=fileInfos[i][2][1];
addImageGroup( images[i], imgWidth,imgHeight, groupX,groupY );
}
layer.draw();
}
};
img.src = fileInfos[i][0];
}
}
function addImageGroup(image,imageWidth,imageHeight,groupX,groupY){
// width and height are based on the images width/height
var w=imageWidth;
var h=imageHeight;
var kGroup = new Kinetic.Group({
x:groupX,
y:groupY,
width:w+20, // must allow 10+10=20 for anchors
height:h+20,
draggable:true
});
layer.add(kGroup);
kGroup.on('dragstart', function() {
this.moveToTop();
});
var kImage = new Kinetic.Image({
x: 0,
y: 0,
image: image,
width: w,
height: h,
name: 'image',
stroke: 'black',
strokeWidth: 2,
dashArray: [10, 2]
});
kGroup.add(kImage);
addAnchor(kGroup, 0, 0, 'topLeft');
addAnchor(kGroup, w, 0, 'topRight');
addAnchor(kGroup, w, h, 'bottomRight');
addAnchor(kGroup, 0, h, 'bottomLeft');
}
function update(activeAnchor) {
var group = activeAnchor.getParent();
var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];
var image = group.get('.image')[0];
var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case 'topLeft':
topRight.setY(anchorY);
bottomLeft.setX(anchorX);
break;
case 'topRight':
topLeft.setY(anchorY);
bottomRight.setX(anchorX);
break;
case 'bottomRight':
bottomLeft.setY(anchorY);
topRight.setX(anchorX);
break;
case 'bottomLeft':
bottomRight.setY(anchorY);
topLeft.setX(anchorX);
break;
}
image.setPosition(topLeft.getPosition());
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if(width && height) {
image.setSize(width, height);
}
}
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on('dragmove', function() {
update(this);
layer.draw();
});
anchor.on('mousedown touchstart', function() {
group.setDraggable(false);
this.moveToTop();
});
anchor.on('dragend', function() {
group.setDraggable(true);
layer.draw();
});
// add hover styling
anchor.on('mouseover', function() {
var layer = this.getLayer();
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
layer.draw();
});
anchor.on('mouseout', function() {
var layer = this.getLayer();
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
layer.draw();
});
group.add(anchor);
}
</script>
</body>
</html>
I feel I am being incredible stupid but for some reason am blind to being able to fix this issue.
I want 3 individual layers, each that can have multiple object/shapes on them and then on click I want the visible layer to be removed or hid and the next layer to appear.
I think my issue is dying in the logic and calling the function. Here is the function and the jsfiddle:
var version = 0;
function layerVersion() {
if (version === 1) {
stage.add(layerBlue);
layerBlue.on('click', function() {
layerOrange.hide;
version = 2;
});
} else if (version === 2) {
stage.add(layerOrange);
} else {
stage.add(layerPink);
layerpink.on('click', function() {
layerPink.hide;
version = 1;
});
}
}
Here is the jsFiddle link: http://jsfiddle.net/TJ96r/2/
Any help would be much appreciate I feel so dumb for not being able to figure it out.
Check this out.
http://jsfiddle.net/TJ96r/3/
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layerPink = new Kinetic.Layer();
layerPink.hide();
var layerBlue = new Kinetic.Layer();
var layerOrange = new Kinetic.Layer();
layerOrange.hide();
// pink box
var pink = new Kinetic.Rect({
x: 50,
y: 50,
width: 100,
height: 100,
fill: 'pink',
stroke: 'black',
strokeWidth: 2
});
// blue box
var blue = new Kinetic.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
fill: 'blue',
stroke: 'black',
strokeWidth: 2
});
// orange box
var orange = new Kinetic.Rect({
x: 150,
y: 150,
width: 100,
height: 100,
fill: 'orange',
stroke: 'black',
strokeWidth: 2
});
layerPink.add(pink);
layerBlue.add(blue);
layerOrange.add(orange);
var version = 0;
stage.add(layerBlue);
stage.add(layerOrange);
stage.add(layerPink);
layerBlue.on('click', function() {
layerBlue.hide();
layerOrange.show();
layerPink.hide();
stage.draw();
});
layerOrange.on('click', function() {
layerBlue.hide();
layerOrange.hide();
layerPink.show();
stage.draw();
});
layerPink.on('click', function() {
layerPink.hide();
layerOrange.hide();
layerBlue.show();
stage.draw();
});
The code below creates a scalable and draggable triangle with anchor points at its vertices. i want that the anchor points should only visible when mouse goes over them??
and also, how collision detection can be implemented to avoid drawing of other spaces inside the triangle?
<html>
<head>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.10.0.js"></script>
<script type="text/javascript">
// the circle anchor points
function buildAnchor(layer, x, y, name) {
var anchor = new Kinetic.Circle({
x: x,
y: y,
radius: 6,
stroke: "#666",
fill: "#ddd",
strokeWidth: 2,
draggable: true,
name : name
});
// add hover styling
anchor.on("mouseover", function() {
document.body.style.cursor = "pointer";
this.setStrokeWidth(4);
layer.draw();
});
anchor.on("mouseout", function() {
document.body.style.cursor = "default";
this.setStrokeWidth(2);
layer.draw();
});
layer.add(anchor);
return anchor;
}
function buildTriangle(layer, points, name) {
var triangle = new Kinetic.Polygon({
stroke : "red",
strokeWidth : 4,
name : name,
draggable : true
});
triangle.a = buildAnchor(layer, points[0], points[1], "anchor");
triangle.b = buildAnchor(layer, points[2], points[3], "anchor");
triangle.c = buildAnchor(layer, points[4], points[5], "anchor");
triangle.was = { x : 0, y : 0 };
layer.add(triangle);
return triangle;
}
function drawTriangle() {
var triangle = this.get(".triangle")[0];
if ( !triangle.isDragging() ) {
triangle.setPoints([ triangle.a.attrs.x - triangle.was.x,
triangle.a.attrs.y - triangle.was.y,
triangle.b.attrs.x - triangle.was.x,
triangle.b.attrs.y - triangle.was.y,
triangle.c.attrs.x - triangle.was.x,
triangle.c.attrs.y - triangle.was.y ]);
} else {
var anchors = this.get(".anchor");
for ( var i = 0; i < anchors.length; i ++ ) {
anchors[i].setX(anchors[i].getX() + (triangle.getX() - triangle.was.x));
anchors[i].setY(anchors[i].getY() + (triangle.getY() - triangle.was.y));
}
triangle.was.x = triangle.getX();
triangle.was.y = triangle.getY();
}
}
window.onload = function() {
var stage = new Kinetic.Stage({
container: "container",
height: 200
});
var layer = new Kinetic.Layer({
drawFunc : drawTriangle
});
var triangle = buildTriangle(layer, [60, 100, 90, 100, 90, 140], "triangle");
triangle.moveToBottom();
// add the layer to the stage
stage.add(layer);
}
</script>
<style>
#container {
border: 1px solid black;
}
</style>
</head>
<body onmousedown="return false;">
<div id="container"></div>
</body>
</html>
jsFiddle: http://jsfiddle.net/Y9AtR/
I like #Tomalak's solution, here is mine:
http://jsfiddle.net/Y9AtR/2/
triangle.on('mouseover', function(){
triangle.a.show();
triangle.b.show();
triangle.c.show();
layer.draw();
});
triangle.on('mouseout', function(){
//if( not near triangle ) // add some logic so that they don't disappear right away, maybe use distance formula?
triangle.a.hide();
triangle.b.hide();
triangle.c.hide();
layer.draw();
})