Kinetic.js Get position of a shape while undergoing a .move() - javascript

I was working on a little HTML5 game, a simple one using Kinetic.js, and I have never used it before. I am also pretty new to the HTML5 Canvas scene. My code runs so that as I press the right arrow key, a little spaceship I made moves across the screen. All the other buttons work the same way too, up moves it up, down moves it down, down and left pressed simultaneously move diagonally down and so forth. I have run into a problem where I want there to be obstacles to get around, but the way I have my code set up (using the .move() function, I'll include it below) I cannot get the coordinates of my ship as it moves, only right as the key is pressed, or right after it is released. Is there a way I can get my code to run so that I can cross reference it's coordinates with any obstacles that may exist in front of it.
Here's what I have as functions to move the ship. The 'rect' variable is the ship.
var velocity = 200;
//Move Animations
//Move Right Animations
var animRight = new Kinetic.Animation(function(frame) {
var dist = velocity * (frame.timeDiff / 1000);
rect.move(dist, 0);
}, layer);
//Move Left Animations
var animLeft = new Kinetic.Animation(function(frame) {
var dist = velocity * (frame.timeDiff / 1000);
rect.move(-dist, 0);
}, layer);
//Move Up Animations
var animUp = new Kinetic.Animation(function(frame) {
var dist = velocity * (frame.timeDiff / 1000);
rect.move(0, -dist);
}, layer);
//Move Down Animations
var animDown = new Kinetic.Animation(function(frame) {
var dist = velocity* (frame.timeDiff / 1000);
rect.move(0,dist);
}, layer);
//Key Listening Events
//Move Up Control
window.addEventListener('keypress', function(e) {
e.preventDefault();
if(e.keyCode==38) {
animUp.start();
}
});
window.addEventListener('keyup', function(e) {
e.preventDefault();
if(e.keyCode==38) {
animUp.stop();
}
});
//Move Right
window.addEventListener('keydown', function(e) {
e.preventDefault();
if(e.keyCode==39) {
animRight.start();
rect.setAnimation('accl');
}
});
window.addEventListener('keyup', function(e) {
e.preventDefault();
if(e.keyCode==39) {
animRight.stop();
rect.setAnimation('idle');
}
});
//Move Left
window.addEventListener('keydown', function(e) {
e.preventDefault();
if(e.keyCode==37) {
animLeft.start();
}
});
window.addEventListener('keyup', function(e) {
e.preventDefault();
if(e.keyCode==37) {
animLeft.stop();
}
});
//Move Up
window.addEventListener('keydown', function(e) {
e.preventDefault();
if(e.keyCode==38) {
animUp.start();
}
});
window.addEventListener('keyup', function(e) {
if(e.keyCode==38) {
e.preventDefault();
animUp.stop();
}
});
//Move Left
window.addEventListener('keydown', function(e) {
e.preventDefault();
if(e.keyCode==40) {
animDown.start();
}
});
window.addEventListener('keyup', function(e) {
e.preventDefault();
if(e.keyCode==40) {
animDown.stop();
}
});

Check for collisions inside the animation loops.
//Move Right Animations
var animRight = new Kinetic.Animation(function(frame) {
rect.move(1, 0);
if(rect.getX()+rect.getWidth()>stage.getWidth()){animRight.stop();}
}, layer);
Here's code and a Fiddle: http://jsfiddle.net/m1erickson/3CdBb/
<!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-v4.7.2.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 layer = new Kinetic.Layer();
stage.add(layer);
var rect = new Kinetic.Rect({
x:100,
y:100,
width: 100,
height:100,
fill: 'red',
stroke: 'black',
strokeWidth: 1,
draggable: true
});
layer.add(rect);
layer.draw();
//Move Right Animations
var animRight = new Kinetic.Animation(function(frame) {
rect.move(1, 0);
if(rect.getX()+rect.getWidth()>stage.getWidth()){animRight.stop();}
}, layer);
animRight.start();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

Related

Using Konva, how can I select and transform images?

I am quite new to javascript, and I have been following tutorials at https://konvajs.org/ to help me learn their library.
I am currently trying to make it so you can load and select local images to move, resize, and rotate them.
This is the code I have so far:
<head>
<!-- USE DEVELOPMENT VERSION -->
<script src="https://unpkg.com/konva#7.0.0/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Select and Transform Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/3.2.5/konva.min.js"></script>
<div>Render a local image without upload</div>
<div>
<input type="file" id="file_input">
</div>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
var layer = new Konva.Layer();
stage.add(layer);
//add images
// listen for the file input change event and load the image.
$("#file_input").change(function(e){
var URL = window.webkitURL || window.URL;
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.src = url;
img.onload = function() {
var img_width = img.width;
var img_height = img.height;
// calculate dimensions to get max 300px
var max = 300;
var ratio = (img_width > img_height ? (img_width / max) : (img_height / max))
// now load the Konva image
var theImg = new Konva.Image({
image: img,
x: 50,
y: 30,
width: img_width/ratio,
height: img_height/ratio,
draggable: true,
rotation: 0
});
layer.add(theImg);
layer.draw();
}
});
var tr = new Konva.Transformer();
layer.add(tr);
// by default select all shapes
// at this point basic demo is finished!!
// we just have several transforming nodes
layer.draw();
// add a new feature, lets add ability to draw selection rectangle
var selectionRectangle = new Konva.Rect({
fill: 'rgba(0,0,255,0.5)',
});
layer.add(selectionRectangle);
var x1, y1, x2, y2;
stage.on('mousedown touchstart', (e) => {
// do nothing if we mousedown on eny shape
if (e.target !== stage) {
return;
}
x1 = stage.getPointerPosition().x;
y1 = stage.getPointerPosition().y;
x2 = stage.getPointerPosition().x;
y2 = stage.getPointerPosition().y;
selectionRectangle.visible(true);
selectionRectangle.width(0);
selectionRectangle.height(0);
layer.draw();
});
stage.on('mousemove touchmove', () => {
// no nothing if we didn't start selection
if (!selectionRectangle.visible()) {
return;
}
x2 = stage.getPointerPosition().x;
y2 = stage.getPointerPosition().y;
selectionRectangle.setAttrs({
x: Math.min(x1, x2),
y: Math.min(y1, y2),
width: Math.abs(x2 - x1),
height: Math.abs(y2 - y1),
});
layer.batchDraw();
});
stage.on('mouseup touchend', () => {
// no nothing if we didn't start selection
if (!selectionRectangle.visible()) {
return;
}
// update visibility in timeout, so we can check it in click event
setTimeout(() => {
selectionRectangle.visible(false);
layer.batchDraw();
});
var shapes = stage.find('.rect').toArray();
var box = selectionRectangle.getClientRect();
var selected = shapes.filter((shape) =>
Konva.Util.haveIntersection(box, shape.getClientRect())
);
tr.nodes(selected);
layer.batchDraw();
});
// clicks should select/deselect shapes
stage.on('click tap', function (e) {
// if we are selecting with rect, do nothing
if (selectionRectangle.visible()) {
return;
}
// if click on empty area - remove all selections
if (e.target === stage) {
tr.nodes([]);
layer.draw();
return;
}
// do nothing if clicked NOT on our rectangles
if (!e.target.hasName('rect')) {
return;
}
// do we pressed shift or ctrl?
const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
const isSelected = tr.nodes().indexOf(e.target) >= 0;
if (!metaPressed && !isSelected) {
// if no key pressed and the node is not selected
// select just one
tr.nodes([e.target]);
} else if (metaPressed && isSelected) {
// if we pressed keys and node was selected
// we need to remove it from selection:
const nodes = tr.nodes().slice(); // use slice to have new copy of array
// remove node from array
nodes.splice(nodes.indexOf(e.target), 1);
tr.nodes(nodes);
} else if (metaPressed && !isSelected) {
// add the node into selection
const nodes = tr.nodes().concat([e.target]);
tr.nodes(nodes);
}
layer.draw();
});
</script>
Demo: https://www.w3schools.com/code/tryit.asp?filename=GG5QCXFMLFXJ
I am unsure how to make the selecting work on images, rather than rectangles.
Thank you
In the demo, you will see that "rect" names is used to detect selectable shapes. That is a useful approach, because you may have non-selectable shapes on the stage (like a background).
So to check a shape if it is selectable, we use:
e.target.hasName('rect')
So just remember to add "rect" name to new images on the stage:
// now load the Konva image
var theImg = new Konva.Image({
name: 'rect',
image: img,
x: 50,
y: 30,
width: img_width/ratio,
height: img_height/ratio,
draggable: true,
rotation: 0
});
The name itself is not very important. You can find a different way to detect "selectable" nodes.
https://www.w3schools.com/code/tryit.asp?filename=GG6XVLB39IKW

kinetic layer is not working on touch event in javascript

I am trying to draw a line when user touch the Screen of Android/Iphone Device. I am using kinetic-v4.7.2.min.js. It works perfect on DeskTop. But not working on Devic. So i just change the mouse click events to Touch events. But, still its not working on touch of Device. It trigger the function perfect but it does not draw any line & does not add the line to the layer. Any idea?
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<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>
<style>
#container {
border: solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
//create a stage and a layer
$(function() {
window.addEventListener('load', function(){ // on page load
document.body.addEventListener('touchstart', function(e){
// alert(e.changedTouches[0].pageX) // alert pageX coordinate of touch point
}, false)
}, false)
var isdrawing = false;
var stage;
var layer;
var background;
function InitLayer() {
stage = new Kinetic.Stage({
container : 'container',
width : 350,
height : 350
});
layer = new Kinetic.Layer();
stage.add(layer);
}
// an empty stage does not emit mouse-events
// so fill the stage with a background rectangle
// that can emit mouse-events
function drawRect() {
background = new Kinetic.Rect({
x : 0,
y : 0,
width : stage.getWidth(),
height : stage.getHeight(),
fill : 'white',
stroke : 'black',
strokeWidth : 1,
})
layer.add(background);
layer.draw();
// a flag we use to see if we're dragging the mouse
isMouseDown = false;
// a reference to the line we are currently drawing
newline;
// a reference to the array of points making newline
points = [];
}
//a flag we use to see if we're dragging the mouse
var isMouseDown;
// a reference to the line we are currently drawing
var newline;
// a reference to the array of points making newline
var points = [];
InitLayer();
drawRect();
// on the background
// listen for mousedown, mouseup and mousemove events
background.on('touchstart', function(e) {
//alert(e.changedTouches[0].pageX)
//onMousedown();
isdrawing = true;
isMouseDown = true;
points = [];
points.push(stage.getMousePosition());
var line = new Kinetic.Line({
points : points,
stroke : "green",
strokeWidth : 5,
lineCap : 'round',
lineJoin : 'round'
});
layer.add(line);
newline = line;
});
background.on('touchend', function() {
//onMouseup();
isMouseDown = false;
});
background.on('touchmove', function() {
//onMousemove();
if (!isMouseDown) {
return;
}
;
points.push(stage.getMousePosition());
newline.setPoints(points);
// use layer.drawScene
// this is faster since the "hit" canvas is not refreshed
layer.drawScene();
});
$('#clear').on('click', function() {
layer.removeChildren().add(background).draw();
isdrawing = false;
});
$('#save').on(
'click',
function() {
var img = $('.kineticjs-content').find('canvas').get(0)
.toDataURL("myimage/png");
if (isdrawing) {
$('body').prepend('<img src="' + img + '">');
}
});
});
</script>
</head>
<body>
<h3>Drag to sketch</h3>
<button id="save">SAVE as PNG</button>
<button id="clear">CLEAR</button>
<div id="container"></div>
</body>
</html>
Any Help would be appreciated!! Thanks.
You use stage.getMousePosition() to get the position in your touchmove event:
background.on('touchmove', function() {
//onMousemove();
if (!isMouseDown) {
return;
}
;
points.push(stage.getMousePosition());
newline.setPoints(points);
// use layer.drawScene
// this is faster since the "hit" canvas is not refreshed
layer.drawScene();
});
But you should use stage.getPointerPosition() instead.

get position of mouse inside interval to move a div with mouse

I'm trying to move a div with the movement of the mouse cursor, but can't understand how to get the newly updated mouse position within my timeout. Maybe there is a simpler way.
var t;
$(document).ready(function(){
$("body").on("mousedown", ".heading", function (e) {
$("body").data("header_click", true);
if ($("body").data("header_click")) {
var container = $("#dialog");
container.css("position", "absolute");
t = setInterval(function(){
//some way to get mouse position
var pos = container.position();
container.css({
top: "",//set based on mouse position
left: "",//set based on mouse position
});
}, 100);
}else{
document.clearInterval(t);
}
});
});
$("body").on("mousedown", ".heading", function (e) {
$("body").data("header_click", false);
});
The solution found here did not work for me.
You will need to bind to the mouse move event and update a document variable.
var currentMousePos = { x: -1, y: -1 };
$(document).on('mousemove', function(event) {
currentMousePos.x = event.pageX;
currentMousePos.y = event.pageY;
});
Then use those positions relative to the absolute positions of the element you are wanting to drag to calculate and update the elements new position.
$(document).ready(function(){
$("body").on("mousedown", ".heading", function (e) {
$("body").data("header_click", true);
if ($("body").data("header_click")) {
var container = $("#dialog");
container.css("position", "absolute");
var containerPos = container.pos();
var mouseTopOffset = containerPos.top - currentMousePos.y;
var mouseLeftOffset = containerPos.left - currentMousePos.x;
container.css("left", mouseTopOffset +"px");
container.css("top", mouseLeftOffset +"px");
}
}
}
I havent really tested this but in theory should do what you need.

Reduce radius of circle on mousemove kineticjs

I'm trying to create a html5 canvas painting application using kinetic.js where users can select various shapes and draw them on canvas .
When a user selects circle and tries to draw it , the radius of circle should depend on the distance the mouse has covered on the canvas , now the problem is when the radius of circle increase it works fine but when I decrease it the circle remain of same size .
It would be great if someone can point me to the right direction .
Here is the link to fiddle . http://jsfiddle.net/45fEn/
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<div id="container"></div>
<script src="kinetic.js"></script>
<script src="js/jquery.js"></script>
<script defer="defer">
$(document).ready(function() {
var stage = new Kinetic.Stage({
container:'container',
width:300,
height:400
});
var layer = new Kinetic.Layer();
function drawCircle() {
var circle = new Kinetic.Circle({
x:initialX, y:initialY , radius:tangant , fill:'green'
});
layer.add(circle) ;
stage.add(layer);
}
stage.add(layer);
var painting =false , clicking = false ;
var initialX , initialY , finalX , finalY , tangant , newTangant ,storeTime;
$("canvas").mousedown(function(ev) {
initialX = ev.clientX;
initialY = ev.clientY;
painting = true;
clicking = true;
});
$("canvas").mousemove(function(ev) {
finalX = ev.clientX ;
finalY = ev.clientY ;
var diffX = initialX - finalX ;
var diffY = initialY - finalY ;
tangant = Math.sqrt ( Math.pow(diffX,2) + Math.pow(diffY,2) ) ;
console.log(tangant);
storeTime = setTimeout(function() { newTangant = tangant },200) ;
if(newTangant < tangant) { console.log("new tan:"+newTangant);
circle.remove();
drawCircle();
}
if(clicking == true) {
drawCircle();
}
});
$("canvas").mouseup(function(ev) {
painting = false;
clicking = false;
});
});
</script>
</body>
</html>
You’re close!
BTW, you can also use stage.getContent to hook into stage mouse events.
stage.getContent()).on('mousedown', function (event) { …do mousedown stuff… }
Instead of removing and recreating the circle...
...just use circle.setRadius(newRadius) to resize the existing circle.
$(stage.getContent()).on('mousemove', function (event) {
if(!isDragging){return;}
var pos=stage.getMousePosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
var dx=mouseX-initialX;
var dy=mouseY-initialY;
var r=Math.sqrt(dx*dx+dy*dy);
// this will resize the circle that is currently being created/resized
draggedCircle.setRadius(r);
layer.draw();
});
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/KLcRc/
<!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-v4.7.0.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:400px;
height:400px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 400
});
var layer = new Kinetic.Layer();
stage.add(layer);
var draggedCircle,initialX,initialY;
var radius=25;
var isDragging=false;
function newCircle(mouseX,mouseY){
initialX=mouseX;
initialY=mouseY;
var circle = new Kinetic.Circle({
x:initialX,
y:initialY ,
radius:1,
fill:'green'
});
layer.add(circle) ;
layer.draw();
return(circle);
}
$(stage.getContent()).on('mousedown', function (event) {
var pos=stage.getMousePosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
draggedCircle=newCircle(mouseX,mouseY);
isDragging=true;
});
$(stage.getContent()).on('mousemove', function (event) {
if(!isDragging){return;}
var pos=stage.getMousePosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
var dx=mouseX-initialX;
var dy=mouseY-initialY;
var r=Math.sqrt(dx*dx+dy*dy);
draggedCircle.setRadius(r);
layer.draw();
});
$(stage.getContent()).on('mouseup', function (event) {
isDragging=false;
});
}); // end $(function(){});
</script>
</head>
<body>
<p>Drag to create a resizable circle</p>
<div id="container"></div>
</body>
</html>

KineticJS - Drawing Lines with Mouse

I'm using KinectJS to draw lines based on mouse movement. When a user holds down the mouse button, I want it to be the 'start' point of the line, and when the user release, it will be the 'end' of the line, but as they are holding the mouse down I want to be able to dynamically redraw the line as my mouse moves. Is this possible?
Yes, its possible.
Basically, you has to redraw your layer during onMouseMove event. You'll need a flag to control when the line is moving or not.
When the script initialize, this flag should be false.
At onMouseDown, the line start should receive the current mouse coordinates and set the flag to true.
At onMouseMouve, if the flag is true, you should update the line end to receive the current mouse coordinates.
At onMouseUp, the flag should be set to false.
See the example below:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {
border: 1px solid #9C9898;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.0.1.js"></script>
<script>
window.onload = function() {
layer = new Kinetic.Layer();
stage = new Kinetic.Stage({
container: "container",
width: 320,
height: 320
});
background = new Kinetic.Rect({
x: 0,
y: 0,
width: stage.getWidth(),
height: stage.getHeight(),
fill: "white"
});
line = new Kinetic.Line({
points: [0, 0, 50, 50],
stroke: "red"
});
layer.add(background);
layer.add(line);
stage.add(layer);
moving = false;
stage.on("mousedown", function(){
if (moving){
moving = false;layer.draw();
} else {
var mousePos = stage.getMousePosition();
//start point and end point are the same
line.getPoints()[0].x = mousePos.x;
line.getPoints()[0].y = mousePos.y;
line.getPoints()[1].x = mousePos.x;
line.getPoints()[1].y = mousePos.y;
moving = true;
layer.drawScene();
}
});
stage.on("mousemove", function(){
if (moving) {
var mousePos = stage.getMousePosition();
var x = mousePos.x;
var y = mousePos.y;
line.getPoints()[1].x = mousePos.x;
line.getPoints()[1].y = mousePos.y;
moving = true;
layer.drawScene();
}
});
stage.on("mouseup", function(){
moving = false;
});
};
</script>
</head>
<body>
<div id="container" ></div>
</body>
</html>

Categories

Resources