Understanding placing images in Kinetic.JS? - javascript

Below I have some code for an assignment I'm working on. Having been placed in a 2nd year course without taking foundations of JavaScript, I'm kind of in a rut.
I'm trying to place three images, and be able to call on them later with functions to change their opacity.
When I have the images placed, only one seems to want to appear at a time, and when I call to them, I'm told that they don't exist.
// Create the canvas based on the existing div for it in the HTML file
var stage = new Kinetic.Stage
({
container: 'canvasContainer',
width: 600,
height: 600
});
/* /////////////////////////////////////////////////////
C O D E F O R L O A D I N G U P I M A G E S
///////////////////////////////////////////////////// */
var characters = new Kinetic.Layer();
stage.add(characters);
window.onload = function()
{
var majoraCharacter = new Image();
majoraCharacter.src ="https://upload.wikimedia.org/wikipedia/commons/3/34/Red_star.svg"
majoraCharacter.onload = function()
{
character1= new Kinetic.Image({ x: 400, y: 300, width: 150, height: 150, offset: {x: 75, y: 75}, image: majoraCharacter});
characters.add(character1);
characters.draw();
}
}
window.onload = function()
{
var amaterasuCharacter = new Image();
amaterasuCharacter.src ="https://upload.wikimedia.org/wikipedia/commons/3/34/Red_star.svg"
amaterasuCharacter.onload = function()
{
character2= new Kinetic.Image({ x: 400, y: 200, width: 150, height: 150, offset: {x: 75, y: 75}, opacity:0.5, image: amaterasuCharacter});
characters.add(character2);
characters.draw();
}
}
window.onload = function()
{
var toothlessCharacter = new Image();
toothlessCharacter.src ="https://upload.wikimedia.org/wikipedia/commons/3/34/Red_star.svg"
toothlessCharacter.onload = function()
{
character3= new Kinetic.Image({ x: 400, y: 100, width: 150, height: 150, offset: {x: 75, y: 75}, image: toothlessCharacter});
characters.add(character3);
characters.draw();
}
}
/* /////////////////////////////////////////////////////
C A N V A S F U N C T I O N A L I T Y
///////////////////////////////////////////////////// */
// Create new layer for background images
// Create layer for character images
var character = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 100,
y: 100,
width: 150,
height: 150,
fill: 'grey',
strokeWidth: 4,
offset: {x: 75, y: 75},
});
// add the shape to the layer
character.add(rect);
// add the layer to the stage
stage.add(character);
Is there a way I can better add images to canvas?
And what is preventing them from co-existing, and being editable outside of their loading functions?
Any and all answers are greatly appreciated!

A Demo: http://jsfiddle.net/m1erickson/Bf88D/
Some KineticJS basics:
KineticJS starts with a stage.
The stage is a container for one or more layers which are added to the stage
Each layer is actually a canvas
Shapes (including images) are added to a layer.
Since you're new to javascript, here's an outline of how to structure your project
just use one window.onload and put all your javascript in that one window.onload
load all images in advance so they are available to draw on your canvas
When all the images are loaded, then create Kinetic.Image objects from them.
Here's an image loader that loads all your images in advance and then calls the start function when your images are fully loaded.
// image loader
var imageURLs=[]; // put the paths to your images here
var imagesOK=0;
var imgs=[];
imageURLs.push("");
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
callback();
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
function start(){
// the imgs[] array holds fully loaded images
// the imgs[] are in the same order as imageURLs[]
// use the images now!
}
After you have all your images loaded, you can use this reusable function to add Kinetic Images on the layer.
You send in one image that you've loaded in advance.
You also send in the x,y position where you want the image located.
You also send in the width,height that you want the image resized to.
This function adds one new image to the layer
function addKineticImage(image,x,y,w,h){
var image = new Kinetic.Image({
x:x,
y:y,
width:w,
height:h,
image:image,
draggable: true
});
layer.add(image);
layer.draw();
}

Related

KinetcJS: Drag Performance is very bad when using Sprites

I use Kinetic Sprite like this
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var blob = new Kinetic.Sprite({
x: 250,
y: 40,
image: imageObj,
animation: 'idle',
animations: {
idle: [
// x, y, width, height (4 frames)
2,2,70,119,
71,2,74,119,
146,2,81,119,
226,2,76,119
],
punch: [
// x, y, width, height (3 frames)
2,138,74,122,
76,138,84,122,
346,138,120,122
]
},
frameRate: 7,
frameIndex: 0
});
// add the shape to the layer
layer.add(blob);
// add the layer to the stage
stage.add(layer);
// start sprite animation
blob.start();
var frameCount = 0;
blob.on('frameIndexChange', function(evt) {
if (blob.animation() === 'punch' && ++frameCount > 3) {
blob.animation('idle');
frameCount = 0;
}
});
document.getElementById('punch').addEventListener('click', function() {
alert("blob.width: "+blob.width());
}, false);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/blob-sprite.png';
The problem is that when using a sprite on mobile phone I get very poor drag performance. It is very slow to move or resize the sprite.
Is there a way to increase drag performance?
Edit: Here is an example with a Kinetic Image where dragging is very slow in Chrome for Android: http://jsfiddle.net/confile/brecmjzt/
Your performance problem is not the drag operation.
Refactor your code to not use frameIndexChange because it's extremely expensive to do a callback upon every sprite animation loop.

KineticJS: How do I get the Width and Height of a Sprite or Image?

I loaded a sprite from a URL and wanted to get the width and height of the sprite it turns out that the width and height is alway zero. I created the following example.
How do I get the real width and height of the sprite?
I use the sprite example and created a jsfiddle here: http://jsfiddle.net/confile/jVG9t/
This is the html code:
<div id="container"></div>
<div id="buttons">
<input type="button" id="punch" value="Width">
</div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>
Image <br>
<div id="mydiv" ></div>
This is the JS code:
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var blob = new Kinetic.Sprite({
x: 250,
y: 40,
image: imageObj,
animation: 'idle',
animations: {
idle: [
// x, y, width, height (4 frames)
2,2,70,119,
71,2,74,119,
146,2,81,119,
226,2,76,119
],
punch: [
// x, y, width, height (3 frames)
2,138,74,122,
76,138,84,122,
346,138,120,122
]
},
frameRate: 7,
frameIndex: 0
});
// add the shape to the layer
layer.add(blob);
// add the layer to the stage
stage.add(layer);
// start sprite animation
blob.start();
var frameCount = 0;
blob.on('frameIndexChange', function(evt) {
if (blob.animation() === 'punch' && ++frameCount > 3) {
blob.animation('idle');
frameCount = 0;
}
});
document.getElementById('punch').addEventListener('click', function() {
alert("blob.width: "+blob.width());
}, false);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/blob-sprite.png';
You can get the width/height of the whole imageObj by requesting its .width & .height properties:
var imageObj = new Image();
imageObj.onload = function() {
var width=imageObj.width;
var height=imageObj.height;
}
If the imageObj is a spritesheet then there is no way to programatically get the x, y, width, height of the individual sprites on that spritesheet. Often the spritesheet author will give you this information. You can often eyeball the spritesheet and see how its laid out.
Your KineticJS demo required the coder to know where the x,y,width,height of each sprite on the spritesheet.

Making JS "this" work in prototype function

Being new to Javascript, my understanding of this is a bit shaky. I've read a few articles and SO posts and learned quite a bit, but I'm having issues implementing some code. I'm using the KineticJS library to implement some canvas functions. I was working with a fiddle and was able to get an image to resize with the mouse control, however, when I put the code into a prototype function, resizing no longer works.
Canvas.prototype.addImg = function(){
var self = this;
var image;
var imageObj = new Image();
imageObj.onload = function() {
image = new Kinetic.Image({
x: 200,
y: 50,
image: imageObj,
width: 106,
height: 118,
draggable: false
});
self.backgroundLayer.add(image);
self.stage.add(self.backgroundLayer);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg';
var circle1 = new Kinetic.Circle({
x: 150,
y: 150,
radius: 10,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: false
});
circle1.isResizing = false;
circle1.on("click", function (e) {
// toggle resizing true/false
var isResizing = !this.isResizing;
this.setDraggable(isResizing);
self.backgroundLayer.setDraggable(!isResizing);
this.setFill((isResizing ? "green" : "red"));
this.isResizing = isResizing;
self.backgroundLayer.draw();
});
circle1.on("dragmove", function () {
if (this.isResizing) {
var pos = this.getPosition();
var x = pos.x;
var y = pos.y;
var rectX = image.getX();
var rectY = image.getY();
image.setSize(x - rectX, y - rectY);
self.backgroundLayer.draw();
}
});
self.backgroundLayer.add(circle1);
self.backgroundLayer.draw();
}
I am assuming the problem lies within the use of this in the function, but I'm not sure how to fix the problem. Could somebody tell me what the problem is and how I would fix this?
I can see a problem with the line that is setting the size of image:
image.setSize(x - rectX, y - rectY);
For example if x is 100 and rectX is 200, you end up with a width of '-100', which is not legal.
In the fiddle you provided, when I use constant values, the image re-sizes perfectly:
rect.setSize(200, 200);
Modified fiddle.
The solution I've come upon, is that it is not an issue of this, but the setSize() method. For some reason or another, it is not working in my local application. When I replace this for setWidth() and setHeight(), everything works the way that it should.

Layer.remove(Image); not working in Kinetic.js

I am using the latest kineticjs.(v.3.10)
Here is the problem
I am using a single function to send images to the canvas which are outside the canvas on click.
I am making the images draggable and all..
I have also added a remove image function on double click.
when I double click on any image..
the last added image gets removed and after that if I try to click on some other image..
I get this error: TypeError: this.children[child.index] is undefined
Here is a little code.:
Using this function to fetch the path from another file using ajax
function loadajax(imgpath,imgid){
sources = {
yoda1 : imgpath,
};
loadImages(sources,initStage1);
};
Sources function:----
function loadImages(sources, callback){
var images = {};
var loadedImages = 0;
var numImages = 0;
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function(){
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
Here is the function that I'm using to remove/drag and drop/etc..
function initStage1(images){
yodaGroup1 = new Kinetic.Group({
x: 100,
y: 110,
draggable: true,
});
layery = new Kinetic.Layer();
layery.add(yodaGroup1);
stage.add(layery);
var yoda1 = new Kinetic.Image({
image: images.yoda1,
x: 0,
y: 0,
width: 100,
height: 120,
name:"image",
detectionType:"Pixel"
});
yodaGroup1.add(yoda1);
yodaGroup1.on("dragstart", function() {
yodaGroup1.moveToTop();
layery.draw();
});
yodaGroup1.on("dblclick dbltap", function() {
layery.remove(yodaGroup1);
layery.draw();
});
yodaGroup1.on("dragend", function() {
layery.draw();
yoda1.saveImageData();
});
addAnchor(yodaGroup1,0, 0, "topLeft");
addAnchor(yodaGroup1, 100, 0, "topRight");
addAnchor(yodaGroup1, 100, 120, "bottomRight");
addAnchor(yodaGroup1, 0, 120, "bottomLeft");
stage.draw();
yoda1.saveImageData();
}
NOW according to this function
I should be able to add the images to the canvas(which is working fine)
Should be able to move one image over another when I drag it (.ie.moveToTop function)_Not working
Should be able to remove the images on double click(working only for the latest added image)
Please help
Thanks
layery.remove(yodaGroup1);
refers to this function :
remove() remove layer from stage
http://www.kineticjs.com/docs/symbols/Kinetic.Layer.php#remove
There is no function to remove only one node contained in the layer :/
To remove a node contained in a layer just use this:
node.remove();
So in your case you would do:
yodaGroup1.remove();
layery.draw();
http://kineticjs.com/docs/Kinetic.Image.html

How can i load an array of images in html5 canvas and swap one of the images on button click

i'm trying to build a bike configurator. This is my problem.
How can i load and array of images to construct the bike and another array with parts on the right from which when the user click i take the part and load it on the left where is the bike without preloading the entire canvas again. the new image will be the same width and height and should be on the same x/y position. This is how i load and array of images, but then i don't know how to swap them. I know that i can't clear the image that is loaded on the canvas and i have to draw the new one on top but i don't know how.
<script type="text/javascript" charset="utf-8">
function loadImages(sources, callback){
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function(){
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
window.onload = function(images){
var canvas = document.getElementById("config");
var context = canvas.getContext("2d");
var sources = {
one: "one.jpg",
two: "two.jpg"
};
loadImages(sources, function(images){
context.drawImage(images.one, 100, 100, 180, 200);
context.drawImage(images.two, 280, 100, 180, 200);
});
};
</script>
How can i change image two.jpg on button click. The button should be outside the canvas.
button.addEventListener('click', function () {
canvas.width = canvas.width; // redraws canvas
sources.two = 'three.jpg';
// fyi, you are drawing the images as many times as there are sources.
loadImages(sources, function(images){
context.drawImage(images.one, 100, 100, 180, 200);
context.drawImage(images.two, 280, 100, 180, 200);
});
}, false);

Categories