Adding objects into an array in javascript - javascript

I am trying to get the mouse pointer coordinates and store them into an array(tail) such that the array is limited only to 100 objects. If extra objects comes,the old one's are to be replaced with the new one's. Basically like a queue.
Basically i am trying to create a trail after the basic circle using a circle of smaller radius.
Here's my js:
$(document).ready(function() {
var tail = {
x:0,
y:0
};
var i = 0;
var stage = new Kinetic.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
listening: true
});
var layer = new Kinetic.Layer({
listening: true
});
var layer = new Kinetic.Layer();
var player = new Kinetic.Circle({
x: 20,
y: 20,
radius: 6,
fill: 'cyan',
stroke: 'black',
draggable: true
});
var pixel = new Kinetic.Circle({
x: 20,
y: 20,
radius: 2,
width: stage.getWidth(),
height: stage.getHeight(),
fill: "white"
});
layer.add(player);
stage.add(layer);
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.setPosition(stage.getPointerPosition());
console.log(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
}
tail[i].push(obj);
++i;
console.log(tail[i]);
// pixel.setPosition(tail[i], tail[i + 1]);
layer.draw();
});
});
And here's the html:
<!DOCTYPE html>
<html>
<head>
<title>Collision Detection</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="../css/style.css"/>
</head>
<body>
<div id="container" style=" background:#000; margin:auto; float:left;"></div>
<script src="../js/jquery.min.js"></script>
<script src="../js/kinetic-v5.0.0.min.js"></script>
<script src="../js/main_kinetic.js"></script>
</body>
</html>
Output:
Uncaught TypeError: Cannot call method 'push' of undefined main_kinetic.js:46
Object {x: 656, y: 175} --> console output which returns the cursor position.
Here's the fiddle: http://jsfiddle.net/BVeTH/

You could create your own container for your data points that handles only keeping 100 (or however many you want). Something like this:
var LimitedArray = function (upperLimit) {
var storage = [];
// default limit on length if none/invalid supplied;
upperLimit = +upperLimit > 0 ? upperLimit : 100;
this.push = function (item) {
storage.push(item);
if (storage.length > upperLimit) {
storage.shift();
}
return storage.length;
};
this.get = function (i) {
return storage[i];
};
this.iterateItems = function (iterator) {
var i, l = storage.length;
if (typeof iterator !== 'function') { return; }
for (i = 0; i < l; i++) {
iterator(storage[i]);
}
};
};
(see here: http://jsfiddle.net/Frm27/4/)
Then you can track your datapoints easily:
var trail = new LimitedArray(100);
// code...
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.setPosition(stage.getPointerPosition());
console.log(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
}
trail.push(obj);
trail.iterateItems(function (item) {
// Do something with each item.x and item.y
});
// pixel.setPosition(tail[i], tail[i + 1]);
layer.draw();
});

Unless you reassign it somewhere I am not seeing tail is not an array.
var tail = {
x:null,
y:0
};
If you wanted to store objects with x and y coordinates in it you would need
var tail = [{
x:null,
y:0
}];
tail.push(...);

Related

What are getClientRect(); method and layer.children.each do in JavaScript?

How does the getClientRect(); method work in this code? Is that mean to get the sides of the rectangle?
Also, what is layer.children.each in the code below? Is that mean selecting each child of the node? Can anyone explain to me how these methods work? I checked the document but still not getting how they work.
Thank you so much for your help! I was able to solve this problem.
var stage = new Konva.Stage({
width: 400,
height: 200,
container: 'container'
});
var layer = new Konva.Layer();
stage.add(layer);
layer.on('dragmove', function(e) {
var target = e.target;
var targetRect = e.target.getClientRect();
layer.children.each(function(obj) {
if (obj === target) {
return;
}
if (haveIntersection(obj.getClientRect(), targetRect)) {
alert("Intersection")
}
});
});
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width/2 ||
r2.x + r2.width/2 < r1.x ||
r2.y > r1.y + r1.height/2 ||
r2.y + r2.height/2 < r1.y
);
}
// This will draw the image on the canvas.
function drawImage(source, konvaImage) {
layer.add(konvaImage);
var image = new Image();
image.src = source;
image.onload = function() {
konvaImage.image(image);
layer.draw();
}
}
//1yen
var ichiYenImg = new Konva.Image({
x: 20,
y: 20,
width: 100,
height: 100,
draggable: true
});
var sourceImg1 = "https://illustrain.com/img/work/2016/illustrain09-okane5.png";
drawImage(sourceImg1, ichiYenImg);
var goYenImg = new Konva.Image({
x: 120,
y: 20,
width: 100,
height: 100,
draggable: true
});
var sourceImg2 = "https://illustrain.com/img/work/2016/illustrain09-okane7.png";
drawImage(sourceImg2, goYenImg);
//piggy bank 1yen
var ichiYenpiggyImg = new Konva.Image({
x: 300,
y: 100,
width: 100,
height: 100,
draggable: false
});
var sourceImg7 = "https://user-images.githubusercontent.com/31402838/63416628-a322b080-c3b4-11e9-96e8-e709ace70ec1.png";
drawImage(sourceImg7, ichiYenpiggyImg);
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/konva#4.0.5/konva.min.js"></script>
</head>
<body>
<div id="stage-parent">
<div id="container"></div>
</div>
</body>
</html>
A layer may have several children elements. So layer.children is just an array with of such objects.
layer.children.each(func) is a function similar to Array.prototype.forEach()
. It allows to to executre a function for every element in children array.
node.getClientRect() is a function that calcualte absolute boudning box of any Konva.Node. Bounding box is just an object like this:
{
x: 10,
y: 10,
width: 60,
height: 60
}
It allows you to detect the position and the size of any object, even if it is scaled, rotate, etc. Usually, that function can be used to defined position f edges of the shapes.

How to replace image in canvas using kinetic js

I am developing canvas to create hotel floor view. I am drawing images on canvas from database. I am taking x,y co-ordinates from database and drawing image on that points. But i want to give touch event to those images. I want to replace image on touch or click event. I want to create same functionality as that of book my show .
this is my code.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.2.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:100%;
height:100%;
}
html,body,kineticjs-content {
width:100%;
height:100%;
margin: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://localhost/zoilo_admin/public/kinetic-v5.1.0.js"></script>
<script defer="defer">
function writeMessage(message) {
text.setText(message);
layer.draw();
}
function loadImages(sources, position, callback) {
var assetDir = '';
var images = {};
var loadedImages = 0;
var numImages = 0;
for (i = 0; i < sources.length; i++)
{
numImages++;
}
for (i = 0; i < sources.length; i++)
{
images[i] = new Image();
images[i].onload = function () {
if (loadedImages == (sources.length - 1)) {
callback(images, position);
}
loadedImages++;
};
images[i].src = assetDir + sources[i];
}
}
function buildStage(images, position) {
var positionIndex = 0;
var tableActual = {};
console.log(images);
for (var i = 0; i < sources.length; i++)
{
console.log("Here");
tableActual[i] = new Kinetic.Image({
image: images[i],
x: position[i].x,
y: position[i].y
});
// var tableName = src;
// var table1 = new Kinetic.Image({
// image: images[src],
// x: position[positionIndex].x,
// y: position[positionIndex].y
// });
tableActual[i].on('click', function () {
console.log(this.index);
var image = new Kinetic.Image({
image: '4top.png',
x: position[this.index].x,
y: position[this.index].y
});
drawImage(image);
switch (this.index)
{
case 0:
writeMessage('Click on Table ' + 0);
tableActual[positionIndex] = new Kinetic.Image({
image: images[positionIndex],
x: position[positionIndex].x,
y: position[positionIndex].y
});
this.setIm = "4top.png";
break;
case 1:
writeMessage('Click on Table ' + 1);
break;
case 2:
writeMessage('Click on Table ' + 2);
break;
case 3:
writeMessage('Click on Table ' + 3);
break;
case 4:
writeMessage('Click on Table ' + 4);
break;
}
writeMessage('mouseover ' + this[src]);
});
drawImage(tableActual[i]);
positionIndex++;
}
// finally, we need to redraw the layer hit graph
layer.drawHit();
}
var stage = new Kinetic.Stage({
container: 'container',
width: $(window).width(),
height: $(window).height()
});
var layer = new Kinetic.Layer();
var text = new Kinetic.Text({
x: 10,
y: 10,
fontFamily: 'Calibri',
fontSize: 24,
text: '',
fill: 'black'
});
var sources = [
'house204-2.jpg',
'house204-1.jpg',
'4top.png',
'house204-1.jpg',
'4top.png'
];
var position = [
{
x: 380,
y: 60
},
{
x: 180,
y: 60
}
,
{
x: 90,
y: 60
},
{
x: 260,
y: 60
},
{
x: 50,
y: 60
}
];
loadImages(sources, position, buildStage);
function drawImage(Image)
{
layer.add(Image);
layer.add(text);
stage.add(layer);
// in order to ignore transparent pixels in an image when detecting
// events, we first need to cache the image
Image.cache();
// next, we need to redraw the hit graph using the cached image
Image.drawHitFromCache();
}
</script>
</body>
</html>
Yes! you can change it on touch/click event by changing source of that java script image.
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.4.3.min.js"></script>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var yoda = new Kinetic.Image({
x: 140,
y: stage.getHeight() / 2 - 59,
image: imageObj,
width: 106,
height: 118
});
var filteredYoda = new Kinetic.Image({
x: 320,
y: stage.getHeight() / 2 - 59,
image: imageObj,
width: 106,
height: 118
});
// add the shape to the layer
layer.add(yoda);
layer.add(filteredYoda);
// add the layer to the stage
stage.add(layer);
stage.on('click',function(){
imageObj.src = 'http://crushlabs.com/wp-content/uploads/2013/01/jacee-terry-hello-card-business-card-design-back.jpg';
});
// apply grayscale filter to second image
filteredYoda.applyFilter(Kinetic.Filters.Grayscale, null, function() {
layer.draw();
});
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg';
</script>

About Event Listen of Kinetic JS

Below is the code. My expectation is when I hover on the circles, they should show "Circle 0" and "Circle 1" respectively. But they all show "Circle 1".
Why is this and How to fix it.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.2.min.js"></script>
<script defer="defer">
function writeMessage(message) {
text.setText(message);
layer.draw();
}
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var text = new Kinetic.Text({
x: 10,
y: 10,
fontFamily: 'Calibri',
fontSize: 24,
text: '',
fill: 'black'
});
for (var n=0; n<2; ++n)
{
var circle = new Kinetic.Circle({
x: 100 + n * 100,
y: stage.height()/2,
radius: 30,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
var txt = 'Circle ' + n;
circle.on('mouseover', function() {
writeMessage(txt);
});
circle.on('mouseout', function() {
writeMessage('');
});
layer.add(circle);
}
layer.add(text);
stage.add(layer);
</script>
</body>
</html>
This is not a problem with Kinetic, it's related to JavaScript closures.
You're defining a function in a loop here:
for (var n=0; n<2; ++n) {
...
var txt = 'Circle ' + n;
circle.on('mouseover', function() {
writeMessage(txt);
});
...
}
The variable txt is not copied when you declare your function.
The problem is that when your anonymous function gets called, the value of txt is 'Circle 1' (because the for has finished and txt was modified during the loop).
You'll need an intermediate function:
var displayMessage = function (circleNumber) {
var txt = 'Circle ' + circleNumber;
return function () {
writeMessage(txt);
};
};
and your event binding is now :
circle.on('mouseover', displayMessage(n));
See this fiddle: http://jsfiddle.net/GApn7/
If you want to read more on what happens, read this post: How do JavaScript closures work?

Collision detection using kineticJS (getIntersection function not working)

I am trying to recreate the game http://www.sinuousgame.com/ and started studying html5 canvas and kineticJS.
Recently i came across the getIntersection function and coudnt find much details regarding it.But with what i had ,i did make a code to get the Collision detection done using getIntersection() function.
But it doesnt seem to be working.
As you can see, My Fiddle: http://jsfiddle.net/p9fnq/8/
//The working player code
var LimitedArray = function(upperLimit) {
var storage = [];
// default limit on length if none/invalid supplied;
upperLimit = +upperLimit > 0 ? upperLimit : 100;
this.push = function(item) {
storage.push(item);
if (storage.length > upperLimit) {
storage.shift();
}
return storage.length;
};
this.get = function(flag) {
return storage[flag];
};
this.iterateItems = function(iterator) {
var flag, l = storage.length;
if (typeof iterator !== 'function') {
return;
}
for (flag = 0; flag < l; flag++) {
iterator(storage[flag]);
}
};
};
var tail = new LimitedArray(50);
var flag = 0, jincr = 0;
var stage = new Kinetic.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
listening: true
});
var layer = new Kinetic.Layer({
listening: true
});
stage.add(layer);
var player = new Kinetic.Circle({
x: 20,
y: 20,
radius: 6,
fill: 'cyan',
stroke: 'black',
draggable: true
});
var line = new Kinetic.Line({
points: [],
stroke: 'cyan',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.add(player);
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.position(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
};
tail.push(obj);
var arr = [];
tail.iterateItems(function(p) {
arr.push(p.x, p.y);
});
line.points(arr);
});
var x = 0;
var y = 0;
var noOfEnemies = 200;
var enemyArmada = new Array();
createEnemy();
function createEnemy() {
for (var i = 0; i < noOfEnemies; i++) {
var enemy = new Kinetic.Circle({
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
radius: 4.5 + 1.5 * Math.random(),
fill: 'red',
stroke: 'black'
});
enemy.speedX = enemy.speedY = (0.5 + Math.random() * 50);
enemyArmada.push(enemy);
layer.add(enemy);
}
}
var checkCollide = function() {
var position = stage.getPointerPosition();
if(position == null)
position = player.position();
if(position == null)
position = {x:0,y:0};
var collided = stage.getIntersection(position);
console.log(position);
if (typeof collided !== 'Kinetic.Shape') {
console.log("not shape");
}
else {
console.log("BOOOM!!!");
}
};
var anim = new Kinetic.Animation(function(frame) {
checkCollide();
for (var i = 0; i < noOfEnemies; i++) {
var e = enemyArmada[i];
e.position({
x: e.position().x - e.speedX * (frame.timeDiff / 400),
y: e.position().y + e.speedY * (frame.timeDiff / 400)
});
if (e.position().y < 0 || e.position().x < 0) {
e.position({
x: (Math.random() * (window.innerWidth + 600)),
y: -(Math.random() * window.innerHeight)
});
}
}
}, layer);
anim.start();
I need the collision to be detected. The function i have written here is checkCollide and its called within the kinetic.Animation function.
Can anyone help me out with this??
(If you don't know the solution,please do like the post,i need the solution badly)
The source of the problem
getIntersection(point) means "is any object at this point".
Since the point you're using is the player's position, getIntersection will always return true because player is always at its own position !
One solution
Put your player on one layer and all enemies on a separate layer.
That way you can hit test the enemy layer without the interference of the player object.
Code and a Demo: http://jsfiddle.net/m1erickson/JCfW8/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var enemyLayer = new Kinetic.Layer();
stage.add(enemyLayer);
var playerLayer = new Kinetic.Layer();
stage.add(playerLayer);
var player = new Kinetic.Circle({
x:100,
y:100,
radius: 10,
fill: 'green',
draggable: true
});
player.on("dragmove",function(){
if(enemyLayer.getIntersection(player.position())){
this.fill("red");
playerLayer.draw();
}
});
playerLayer.add(player);
playerLayer.draw();
var enemy = new Kinetic.Circle({
x:200,
y:100,
radius: 20,
fill: 'blue',
draggable: true
});
enemyLayer.add(enemy);
enemyLayer.draw();
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag the green player<br>Player will turn red if it collides<br>with the blue enemy</h4>
<div id="container"></div>
</body>
</html>
Another solution
Mathematically test the player against every enemy:
Warning: untested code--some tweaking might be required
function playerEnemyCollide(){
var playerX=player.x();
var playerY=player.y();
var playerRadius=player.radius();
for(var i=0;i<enemyArmada.length;i++){
var e=enemyArmada[i];
if(circlesColliding(playerX,playerY,playerRadius,e.x,e.y,e.radius)){
return(true);
}
}
return(false);
}
function circlesColliding(cx1,cy1,radius1,cx2,cy2,radius2){
var dx=cx2-cx1;
var dy=cy2-cy1;
return(dx*dx+dy*dy<(radius1*2+radius2*2);
}

Anchor points should only visible when mouse goes over them

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();
})

Categories