Alert not triggered when images touch each other - javascript

I am non-native English speaker and I am beginner of programming language. I understand that my explanation is not best but I am trying to explain better to people to understand what I am trying to do. So, please be patient with me and please not try to down vote (it hurt my feelings) instead of tell me why my explanation is bad. I appreciate your time to read this. Thank you.
I am working on canvas game called coin sorting game which is drag the coins to the correct piggy bank images. I am stuck with if condition right now. In the current state, alert will not trigger when specific image touch to other specific image. For example, when 1yen coin image touches with 1yen piggy bank image then trigger alert otherwise no event occur.
I thought adding images to if condition will set specific images but it did not work.
if (haveIntersection(obj.getClientRect(), targetRect)&& (ichiYenImg === ichiYenpiggyImg)) {
alert("Intersection");
}
Can anyone give me an advice how to attempt this problem?
Any help is greatly appreciated!
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)&& (ichiYenImg === ichiYenpiggyImg)) {
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>

Your code is mainly good - the issue is with the comparison of the objects in the 'if' statement copied below, where your intention is to decide if the user is dragging the correct value coin to the piggy bank. Comparing JavaScript objects is valid, but it can lead to unpredictable results - a more reliable & robust approach is to be more explicit, set a known attribute value on each object and compare those values.
if (haveIntersection(obj.getClientRect(), targetRect)&& (ichiYenImg === ichiYenpiggyImg)) {
alert("Intersection");
}
My answer in the code snippet is to modify the code to use the Konva 'name' variable to hold the coin and bank values. You can see I set them both to 1yen. Now in the dragMove() function I get the name attr from each of the objects being compared. When they match, we have a valid hit, and when no match the coin & bank combination are invalid.
I modified the code to put a red border around the bank when the correct coin is dragged.
See the Konva documentation for the name attr here.
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;
}
// capture the result of the intersection test.
var checkHit = haveIntersection(obj.getClientRect(), targetRect);
// get the objects name attribute
var nameDragged = e.target.attrs['name'];
var namePiggy = obj.attrs['name'];
// decide if they match
var checkNames = (nameDragged === namePiggy);
// finally decide if we have a valid hit
if (checkHit && checkNames) {
// hit ok !
obj.stroke('red');
obj.strokeWidth(2)
}
else {
// no hit or not matching name
obj.stroke(false);
obj.strokeWidth(0)
}
});
});
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,
name: '1yen' // use the name attribute to indicate the coin value
});
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,
name: '1yen' // use the name attribute to indicate the coin value
});
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>

Related

How trigger event listening for shapes on a layer when button clicked?

In KonvaJS, is it possible to make a layer inactive (but not invisible) upon clicking a button, then active on clicking another button? I've tried "text_overlay.listening(false);" but it doesn't work. I can deactivate individual textNodes with "textNode0.listening(false);", which does prevent the user from editing that text, but these textNodes are positioned over polygons, some of which are quite small (e.g., Luxembourg on a map of Europe) and the textarea prevents the user from clicking the polygon underneath (e.g., to change its fill color). Also, there will be over 40 textNodes to deal with, so deactivating 1 layer is far preferable!
Here's the button section of the HTML file:
<script src="js/text-input21.js"></script>
<!-- button events -->
<script>
// button states on load
var btnLabelClicked = true;
var btnColorClicked = false;
var btnDrawLinesClicked = false;
//color chip buttons
var btnViolet = document.getElementById("fillViolet");
var btnOrange = document.getElementById("fillOrange");
var btnYellow = document.getElementById("fillYellow");
//color chip buttons' fill when btnLabelClicked = true
btnViolet.style.background = disableBtnFill;
btnOrange.style.background = disableBtnFill;
btnYellow.style.background = disableBtnFill;
var buttonID = 'btnLabel';
function replyClick(clickedID) {
buttonID = (clickedID);
if (buttonID === 'btnColor') {
textNode0.listening(false);
textNode15.listening(false);
textNode16.listening(false);
btnViolet.disabled = false;
btnViolet.style.background = '#842dce';
btnOrange.disabled = false;
btnOrange.style.background = '#ffa500';
btnYellow.disabled = false;
btnYellow.style.background = '#ffff00';
btnLabelClicked = false;
btnColorClicked = true;
btnDrawLinesClicked = false;
} else if (btnColorClicked && (buttonID === 'fillViolet' || buttonID === 'fillOrange' || buttonID === 'fillYellow')) {
//text_overlay.listening(false);
textNode0.listening(false);
textNode15.listening(false);
textNode16.listening(false);
newFill = document.getElementById(buttonID).style.background;
} else if (buttonID === 'btnLabel' || buttonID === 'btnDrawLines' || buttonID === 'btnEraseLines' || buttonID === 'btnExport') {
//disable color buttons
btnColorClicked = false;
btnViolet.disabled = true;
btnViolet.style.background = disableBtnFill;
btnOrange.disabled = true;
btnOrange.style.background = disableBtnFill;
btnYellow.disabled = true;
btnYellow.style.background = disableBtnFill;
if (buttonID === 'btnLabel') {
textNode0.listening(true);
textNode15.listening(true);
textNode16.listening(true);
btnLabelClicked = true;
btnDrawLinesClicked = false;
} else { //buttonID is not btnLabel or any of the color buttons
textNode0.listening(false);
textNode15.listening(false);
textNode16.listening(false);
btnLabelClicked = false;
btnDrawLinesClicked = true;
}
}
}
</script>
And here's the text-input21.js file containing the text_overlay layer:
var text_overlay = new Konva.Layer({
listening: true
});
stage.add(text_overlay);
var textNode0 = new Konva.Text({
text: 'X',
x: 80, // centered between Ireland & Great Britain
y: 125,
width: 150,
height: 15,
fontFamily: 'Arial, Helvetica, "sans-serif"',
fontSize: 14,
align: 'center',
listening: true
});
var textNode15 = new Konva.Text({
text: 'X',
x: 230, // Luxembourg
y: 225,
width: 100,
height: 15,
fontFamily: 'Arial, Helvetica, "sans-serif"',
fontSize: 14,
align: 'center',
listening: true
});
var textNode16 = new Konva.Text({
text: 'X',
x: 175, // France
y: 290,
width: 100,
height: 15,
fontFamily: 'Arial, Helvetica, "sans-serif"',
fontSize: 14,
align: 'center',
listening: true
});
text_overlay.add(textNode0);
text_overlay.add(textNode15);
text_overlay.add(textNode16);
text_overlay.draw();
console.log(text_overlay.getZIndex());
textNode0.on('click', () => {
// create textarea over canvas with absolute position
// first we need to find its position
var textPosition = textNode0.getAbsolutePosition();
var stageBox = stage.getContainer().getBoundingClientRect();
var areaPosition = {
x: textPosition.x + stageBox.left,
y: textPosition.y + stageBox.top
};
// create textarea and style it
var textarea = document.createElement('textarea');
document.body.appendChild(textarea);
textarea.value = textNode0.text();
textarea.style.textAlign = 'center';
textarea.style.resize = 'none';
textarea.style.position = 'absolute';
textarea.style.left = areaPosition.x + 'px'; //positioning needs work
textarea.style.top = areaPosition.y + 'px';
textarea.style.width = textNode0.width();
textarea.style.background = 'transparent';
textarea.style.border = 1; // final border = 0
textarea.style.outline = 'none';
textarea.style.fontFamily = 'Arial, Helvetica, "sans-serif"';
textarea.style.fontSize = 14;
textarea.focus();
textarea.addEventListener('keydown', function (e) {
// hide on enter
if (e.keyCode === 13) {
textNode0.text(textarea.value);
text_overlay.draw();
document.body.removeChild(textarea);
}
});
})
textNode15.on('click', () => {
// create textarea over canvas with absolute position
// first we need to find its position
var textPosition = textNode15.getAbsolutePosition();
var stageBox = stage.getContainer().getBoundingClientRect();
var areaPosition = {
x: textPosition.x + stageBox.left,
y: textPosition.y + stageBox.top
};
// create textarea and style it
var textarea = document.createElement('textarea');
document.body.appendChild(textarea);
textarea.value = textNode15.text();
textarea.style.textAlign = 'center';
textarea.style.resize = 'none';
textarea.style.position = 'absolute';
textarea.style.left = areaPosition.x - 20 + 'px'; //positioning needs work
textarea.style.top = areaPosition.y - 20 + 'px';
textarea.style.width = textNode15.width();
textarea.style.background = 'transparent';
textarea.style.border = 1; // final border = 0
textarea.style.outline = 'none';
textarea.style.fontFamily = 'Arial, Helvetica, "sans-serif"';
textarea.style.fontSize = 14;
textarea.focus();
textarea.addEventListener('keydown', function (e) {
// hide on enter
if (e.keyCode === 13) {
textNode15.text(textarea.value);
text_overlay.draw();
document.body.removeChild(textarea);
}
});
})
textNode16.on('click', () => {
// create textarea over canvas with absolute position
// first we need to find its position
var textPosition = textNode16.getAbsolutePosition();
var stageBox = stage.getContainer().getBoundingClientRect();
var areaPosition = {
x: textPosition.x + stageBox.left,
y: textPosition.y + stageBox.top
};
// create textarea and style it
var textarea = document.createElement('textarea');
document.body.appendChild(textarea);
textarea.value = textNode16.text();
textarea.style.textAlign = 'center';
textarea.style.resize = 'none';
textarea.style.position = 'absolute';
textarea.style.left = areaPosition.x - 45 + 'px'; //positioning needs work
textarea.style.top = areaPosition.y - 20 + 'px';
textarea.style.width = textNode16.width();
textarea.style.background = 'transparent';
textarea.style.border = 1; // final border = 0
textarea.style.outline = 'none';
textarea.style.fontFamily = 'Arial, Helvetica, "sans-serif"';
textarea.style.fontSize = 14;
textarea.focus();
textarea.addEventListener('keydown', function (e) {
// hide on enter
if (e.keyCode === 13) {
textNode16.text(textarea.value);
text_overlay.draw();
document.body.removeChild(textarea);
}
});
})
// add the layer to the stage
stage.add(text_overlay);
From experiment, layer.listening() sets listening on the layer but not its contents. Its not intuitive, but it makes sense because a layer is actually an HTML5 canvas. For example, you could want to toggle tracking of mouse movement over the layer background but have the layers child shapes still be listening continuously, so then you need this.
You can set listening on the children using the getchildren function
// get all children
var children = layer.getChildren();
Then iterate the list and use setListening() on each member. The getChildren() function can be combined with the className filter to create subsets of child objects, so you could toggle all text elements, or all polygons, or all circles, etc. It's quite funky.
As a side note, and don't take this as criticism, your coding style seems not to be DRY. What I mean is, your click events for the textNode0, textNode15 and textNode16 are repetitive - I guess each time you realise you need to make a change to one you have to make it manually to all. That leaves you open to bugs by cut & paste or omission. Better to make a standard myTextNode object and have it include all the functionality that you want in a textNode, then pass in the unique parameters when you create each object. That way making a change to the myTextNode 'class' affects all of them at once. The label for this is 'JS Objects', but if you Google that you will be overloaded with information. Have a read of this at W3 Schools for a 'way in' to the subject. Forgive me if you know all this but there are a lot of countries for your textNodes.

Get z-index of selected object in fabric js

I am trying to get the z-index of selected object in fabric js. Is there a way to get that?
var z_index = 1;
$('#manage_index').change(function(){
var cur_value = $(this).val();
if(cur_value!='')
{
var object = canvas.getActiveObject();
if(cur_value=='up') // Means increase z-index
{
canvas.moveTo(object, z_index);
z_index = z_index + 1;
}
else if(cur_value=='back') //Means decrease z-index
{
//var temp_index = 0; // If set it to 0, it will goes into backward,
//But i am trying to implement something like below
var temp_index = canvas.get('z-index');// Get the z-index of selected object and then decrease it
canvas.moveTo(object, temp_index-1);
}
}
$(this).val('');
});
var canvas = new fabric.Canvas('a');
canvas.add(new fabric.Rect({
left:50,
top:50,
height:50,
width:50,
fill:'red'
}));
canvas.add(new fabric.Rect({
left:70,
top:70,
height:50,
width:50,
fill:'green'
}));
canvas.add(new fabric.Rect({
left:90,
top:90,
height:50,
width:50,
fill:'blue'
}));
canvas.renderAll();
function getIndex(){
var activeObj = canvas.getActiveObject();
console.log(activeObj && canvas.getObjects().indexOf(activeObj));
}
function bringToFront(){
var activeObj = canvas.getActiveObject();
activeObj && canvas.bringToFront(activeObj).discardActiveObject(activeObj).renderAll();
}
canvas {
border: 2px solid black;
}
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<button onclick='getIndex()'>Index</button>
<button onclick='bringToFront()'>bringToFront</button>
<canvas id="a" width="200" height="200"></canvas>
As fabric object stores in an array , you can get index using indexOf. to rearrange order you can use the bringToFront, bringForward, sendBackwards, sendToBack. And moveTo with to specified index.
I thought it was already implemented in recent Fabric.js versions but you can still extend Fabric objects prototype :
fabric.Object.prototype.getZIndex = function() {
return this.canvas.getObjects().indexOf(this);
}

Select all text objects on a Fabric.js canvas

var canvas = new fabric.Canvas();
// select all objects
function selectAllCanvasObjects(){
var objs = canvas.getObjects().map(function(o) {
return o.set('active', true);
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center'
});
canvas._activeObject = null;
canvas.setActiveGroup(group.setCoords()).renderAll();
}
I have a canvas and I need to select all text objects and skip others. This is the code to select all objects, how can I make it only select all text objects and skip others?
The following example only selects items with the type of 'text'.
In summary:
The Fabric JS get method allows us to inspect the type of the current item that we're iterating over
If the type is equal to 'text' then we return the item
N.B. We now use filter instead of map, as we now only want to return items that match the type of 'text', instead of every item
var canvas = new fabric.Canvas('c');
// Add some example shapes
var circle = new fabric.Circle({
radius: 20, fill: 'green', left: 100, top: 100
});
var triangle = new fabric.Triangle({
width: 20, height: 30, fill: 'blue', left: 50, top: 50
});
canvas.add(circle, triangle);
// Add some example text
var text1 = new fabric.Text('hello world', { left: 100, top: 100 });
var text2 = new fabric.Text('test', { left: 0, top: 0 });
canvas.add(text1, text2);
// Select all objects
function selectAllCanvasObjects(){
var objs = canvas.getObjects().filter(function(o) {
if (o.get('type') === 'text') {
return o.set('active', true);
}
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center'
});
canvas._activeObject = null;
canvas.setActiveGroup(group.setCoords()).renderAll();
}
selectAllCanvasObjects();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.8/fabric.min.js"></script>
<canvas id="c"></canvas>
You can use below code to select all text object.
var object_length = parseInt(canvas.getObjects().length) - 1;
for(var i = 0; i <= object_length; i++)
{
canvas.setActiveObject(canvas.item(i));
var obj = canvas.getActiveObject();
var object_type = obj.type;
if(object_type == "text")
{
//Write your code here
canvas.renderAll();
}
}
canvas.deactivateAllWithDispatch();
canvas.renderAll();
After completion of execution deselect all objects so it will not show you last selected object as selected.

Spring between two draggable surfaces in famo.us

I'm trying to implement two surfaces, connected with a spring, that would react to drag in famo.us. So far I have setup the surfaces, can drag those, have a spring that interacts during the loading of the page, but not on drag. So the questions are a) how should I connect two surfaces with a spring and b) how do I update the physics when I drag one surface so that the other surface would follow the dragged surface?
The code I so far have is this
define(function(require) {
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var StateModifier = require('famous/modifiers/StateModifier');
var PhysicsEngine = require('famous/physics/PhysicsEngine');
var Circle = require('famous/physics/bodies/Circle');
var Draggable = require('famous/modifiers/Draggable');
var Spring = require('famous/physics/forces/Spring');
var Vector = require('famous/math/Vector');
var context = Engine.createContext();
var physicsEngine = new PhysicsEngine();
var ball = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'red',
borderRadius: '50px'
}
});
var ball2 = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'blue',
borderRadius: '50px'
}
});
var draggable = new Draggable();
var draggable2 = new Draggable();
ball.state = new StateModifier({origin:[0.2,0.2]});
ball2.state = new StateModifier({origin:[0.3,0.3]});
ball.particle = new Circle({radius:100});
ball2.particle = new Circle({radius:100});
var spring = new Spring({
anchor: ball.particle,
period: 400, // <= Play with these values :-)
dampingRatio: 0.07, // <=
length: 50
});
// var spring2 = new Spring({anchor: ball2.particle});
// physicsEngine.attach(spring, ball2.particle);
// physicsEngine.attach(spring2, ball.particle);
draggable.subscribe(ball);
draggable2.subscribe(ball2);
draggable.on('update', function() {
console.info('update');
ball2.particle.applyForce(new Vector(0, 0, -0.005 * 100));
// ball.state.setTransform(ball.particle.getTransform())
// ball.state.setTransform(ball.particle.getTransform())
// ball.particle.setVelocity([0.001,0,0]);
// physicsEngine.wake();
// physicsEngine.step();
});
draggable2.on('update', function() {
// ball2.particle.setVelocity([0.001,0,0]);
// console.info('update');
// physicsEngine.wake();
// physicsEngine.step();
});
physicsEngine.attach(spring, ball2.particle);
// spring.applyForce(ball.particle);
physicsEngine.addBody(ball.particle);
physicsEngine.addBody(ball2.particle);
// ball.on("click",function(){
// ball.particle.setVelocity([10,0,0]);
// });
//
// ball2.on("click",function(){
// ball2.particle.setVelocity([0,10,0]);
// });
context.add(draggable).add(ball.state).add(ball);
context.add(draggable2).add(ball2.state).add(ball2);
Engine.on('prerender', function(){
ball.state.setTransform(ball.particle.getTransform());
ball2.state.setTransform(ball2.particle.getTransform());
});
});
It seems like you have a pretty good understanding of the PE thus far. I can still see a few places you can improve. Here is a working example of dragging with a spring attached. Although this implementation is not perfect yet, it should get you started.. If you start with dragging the red circle, everything works as expected.. Draggable has its own position, and so does particle. So when you grab the blue circle, there remains an offset in particle. Here is what will get you 95%..
Hope it helps..
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var Modifier = require('famous/core/Modifier');
var Draggable = require('famous/modifiers/Draggable');
var PhysicsEngine = require('famous/physics/PhysicsEngine');
var Circle = require('famous/physics/bodies/Circle');
var Spring = require('famous/physics/forces/Spring');
var context = Engine.createContext();
var physicsEngine = new PhysicsEngine();
var ball = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'red',
borderRadius: '50px'
}
});
var ball2 = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'blue',
borderRadius: '50px',
}
});
ball.mod = new Modifier({origin:[0.5,0.5]});
ball.draggable = new Draggable();
ball.pipe(ball.draggable);
ball.particle = new Circle({radius:100});
ball.mod.transformFrom(function(){ return Transform.translate(0,0,0) });
ball.spring = new Spring({
anchor: ball.particle,
period: 400,
dampingRatio: 0.07,
length: 50
});
ball2.mod = new Modifier({origin:[0.5,0.5]});
ball2.draggable = new Draggable();
ball2.pipe(ball2.draggable);
ball2.particle = new Circle({radius:100});
ball2.mod.transformFrom(function(){ return ball2.particle.getTransform()});
ball2.spring = new Spring({
anchor: ball2.particle,
period: 400,
dampingRatio: 0.07,
length: 50
});
ball.draggable.on('start',function(){
ball2.setProperties({pointerEvents:'none'});
if (ball2.springID) physicsEngine.detach(ball2.springID);
if (ball.springID) physicsEngine.detach(ball.springID);
ball.springID = physicsEngine.attach(ball.spring, ball2.particle);
ball2.springID = null;
ball.mod.transformFrom(function(){ return Transform.translate(0,0,0) });
ball2.mod.transformFrom(function(){ return ball2.particle.getTransform()});
})
ball.draggable.on('update', function() {
pos = ball.draggable.getPosition();
ball.particle.setPosition(pos);
});
ball.draggable.on('end', function() {
ball2.setProperties({pointerEvents:'all'});
});
ball2.draggable.on('start',function(){
ball.setProperties({pointerEvents:'none'});
if (ball2.springID) physicsEngine.detach(ball2.springID);
if (ball.springID) physicsEngine.detach(ball.springID);
ball2.springID = physicsEngine.attach(ball2.spring, ball.particle);
ball.springID = null;
ball2.mod.transformFrom(function(){ return Transform.translate(0,0,0) });
ball.mod.transformFrom(function(){ return ball.particle.getTransform()});
})
ball2.draggable.on('update', function() {
pos = ball2.draggable.getPosition();
ball2.particle.setPosition(pos);
});
ball2.draggable.on('end', function() {
ball.setProperties({pointerEvents:'all'});
});
ball.springID = physicsEngine.attach(ball.spring, ball2.particle);
physicsEngine.addBody(ball.particle);
physicsEngine.addBody(ball2.particle);
context.add(ball.mod).add(ball.draggable).add(ball);
context.add(ball2.mod).add(ball2.draggable).add(ball2);

Kineticjs Object Handling & Event Listener

I sell custom equipment and on my site, I have a flash tool where customers can assign colors to glove parts and see what it will look like.
I've been working on a HTML5 version of this tool, so the iPad crowd can do the same thing. Click here for what I've done,
I took kineticjs multiple picture loader and hacked it to load all the pics necessary to stage and the color buttons, which are multiple instances of the same image. In their example, it was only 2 images, so they var name each image, which were manipulative. My goal is to dynamically create variable, based on image name.
I'm using a for loop and if statements to position the parts according to their type. If the image being loaded is a button, the original instance is not added to the stage, but another for loop, with a counter, creates instances and put on the stage. The variable is part string+n (wht0). From here I initiate an eventlistener, when clicked is suppose to hide all glove parts pertaining to the option and show the appropriate color. That code I have already in my AS.
I created an eventlistener on the white buttons (first button) that when clicked, I set it to hide one of the white leather part of glove. But when I click the button, I get the error in console that the glove part (ex wlt_wht), I get an error stating that the object is not defined. But when the image was loaded the variable name came from the current array object being loaded.
I added another variable before the callback call, to convert the content of the array to a string and used the document.write to confirm that the object name is correct, but after creating the object its now [object object]. In flash, you manually assign the movie clip name and target.name is available if you call it.
How can I write the Image obj so I can control the object? In the doc there is a reference for id and name as properties of the object, but when I set these, it did not work with me. Sure, I could have manually created each Kinetic.Image(), but there's no fun in that.. especially with 191 images. Any tip on how I can get around this problem?
Checkout http://jsfiddle.net/jacobsultd/b2BwU/6/ to examine and test script.
function loadImages(sources, callback) {
var assetDir = 'http://dev.nystixs.com/test/inf/';
var fileExt = '.png';
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 () {
var db = sources[src].toString();
var dbname = db.slice(-0, -4);
if (++loadedImages >= numImages) {
callback(images, dbname);
}
};
images[src].src = assetDir + sources[src];
//images[src].src = assetDir+sources[src]+".png";
}
}
function initStage(images, db) {
var shapesLayer = new Kinetic.Layer();
var messageLayer = new Kinetic.Layer();
//Loading Images
var xpos = 0;
var ypos = 200;
for (var i in images) {
var glvP = i.slice(0, 3);
db = new Kinetic.Image({
image: images[i],
x: xpos,
y: ypos
});
if (glvP == "wlt") {
shapesLayer.add(db);
db.setPosition(186.95, 7.00);
//db.hide();
shapesLayer.draw();
} else if (glvP == "lin") {
shapesLayer.add(db);
db.setPosition(204.95, 205.00);
} else if (glvP == "plm") {
shapesLayer.add(db);
db.setPosition(311.95, 6.00);
} else if (glvP == "web") {
shapesLayer.add(db);
db.setPosition(315.95, 7.00);
} else if (glvP == "lce") {
shapesLayer.add(db);
db.setPosition(162.95, 3.00);
} else if (glvP == "thb") {
shapesLayer.add(db);
db.setPosition(63.00, 28.60);
} else if (glvP == "bfg") {
shapesLayer.add(db);
db.setPosition(167.95, 7.00);
} else if (glvP == "wst") {
shapesLayer.add(db);
db.setPosition(208.95, 234.00);
} else if (glvP == "fpd") {
shapesLayer.add(db);
db.setPosition(252.95, 82.00);
} else if (glvP == "bac") {
shapesLayer.add(db);
db.setPosition(0, 0);
} else if (glvP == "bnd") {
shapesLayer.add(db);
db.setPosition(196.95, 164.00);
} else {}
var rect = new Kinetic.Rect({
x: 710,
y: 6,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 200,
height: 325,
shadowColor: 'white',
shadowBlur: 10,
shadowOffset: [5, 5],
shadowOpacity: 0.2,
cornerRadius: 10
});
shapesLayer.add(rect);
// End of Glove Parts Tabs
//Load Color Buttons
if (glvP == "wht") {
xpos = -5.00;
bpos = 375;
var zpos = -5.00;
var tpos = -5.00;
db.setPosition(xpos, bpos);
//shapesLayer.add(db);
var n = 0;
for (n = 0; n < 12; n++) {
if (n < 4) {
var glvB = "wht" + n;
var btn = glvB;
glvB = new Kinetic.Image({
image: images[i],
width: 18,
height: 18,
id: 'wht0'
});
glvB.on('mouseout', function () {
blankText('');
});
glvB.on('mouseover', function () {
writeColors('White', btn);
});
glvB.on('click', function () {
console.log(glvB + " clicked");
wht.hide();
shapesLayer.draw();
});
glvB.setPosition((xpos + 20), bpos);
shapesLayer.add(glvB);
xpos = (xpos + 230);
}
You can use your .png image filenames to automate your color-button coding efforts.
No need to manually code 10 glove components X 21 colors per component (210 color buttons).
Assume you’ve split the each image URL (filename) to get the color and glove-type.
Then you can create all 210 color buttons with one piece of reusable code.
Demo: http://jsfiddle.net/m1erickson/H5FDc/
Example Code:
// Usage:
addColorButton(100,100,"red","fingers");
// 1 function to add 210 color-buttons
function addColorButton(x,y,color,component){
// create this button
var button=new Kinetic.Image({
x:x,
y:y,
image: imageArray[ color+"-color-button" ],
});
// save the color as a property on this button
button.gloveColor=color;
// save the glove component name as a property on this button
button.gloveComponent=component; // eg, "fingers"
// resuable click handler
// Will change the gloves "#fingers" to "red-fingers-image"
button.on("click",function(){
// eg. get the image "red-fingers-image"
var newImage = imageArray[this.gloveColor+"-"+this.gloveComponent+"-image"];
// eg. get the Kinetic.Image with id:”finger”
var glovePart = layer.find("#"+this.gloveComponent”][0];
// change the Kinetic id:finger’s image
// to the red-fingers-image
glovePart.setImage(newImage);
layer.draw();
});
layer.add(button);
}

Categories

Resources