i have following code to drag a smaller rect in a bigger rect.
it is almost working, but its possible to move the orange rect out of the white one.
Is there any solution for this behavior?? that the bigger rect is the dragborder for the small rect??
And another question... would it be possible to do it for a rect in any polygon as border?
<!DOCTYPE HTML>
<html>
<head>
<style>
body {margin: 0px; padding: 20px;}
canvas {border: 1px solid #777;}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.2.js"></script>
<script>
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
// White box
var white = new Kinetic.Rect({
x: 100,
y: 50,
width: 150,
height: 100,
fill: 'white',
stroke: 'black',
strokeWidth: 2
});
// orange box
var orange = new Kinetic.Rect({
x: 150,
y: 100,
width: 50,
height: 30,
fill: 'orange',
stroke: 'black',
strokeWidth: 2,
draggable: true,
// this causes orange box to be stopped if try to leave white box
dragBoundFunc: function(pos){
if(theyAreColliding(orange,white)){
// orange box is touching white box
// let it move ahead
return ({ x:pos.x, y:pos.y });
} else{
// orange box is not touching white box
// don't let orange box move outside
if (white.getY() > orange.getY()){
return({x: pos.x, y: white.getY()+1});
}
else if (white.getY() + white.getHeight() - orange.getHeight() < orange.getY()){
return({x: pos.x, y: white.getY() + white.getHeight() - orange.getHeight() -1});
}
else if (white.getX() > orange.getX()){
return({x: white.getX() +1, y: pos.y})
}
else if (white.getX() + white.getWidth() - orange.getWidth() < orange.getX()){
return({x: white.getX() +white.getWidth() - orange.getWidth() -1, y: pos.y})
}
}
}
});
function theyAreColliding(rect1, rect2) {
return !(rect2.getX() > rect1.getX() ||
rect2.getX() + rect2.getWidth() - rect1.getWidth() < rect1.getX() ||
rect2.getY() > rect1.getY() ||
rect2.getY() + rect2.getHeight() - rect1.getHeight() < rect1.getY());
}
layer.add(white);
layer.add(orange);
stage.add(layer);
</script>
</body>
</html>
and also the jsfiddle link: http://jsfiddle.net/dNfjM/
This is an improved way of setting your dragBoundFunc
The secret with dragBoundFunc is to allow it to execute fast. Remember that it is being executed with every mousemove.
So, pre-calculate all the minimum and maximum boundaries before and outside dragBoundFunc, like this:
// pre-calc some bounds so dragBoundFunc has less calc's to do
var height=orangeRect.getHeight();
var minX=white.getX();
var maxX=white.getX()+white.getWidth()-orangeRect.getWidth();
var minY=white.getY();
var maxY=white.getY()+white.getHeight()-orangeRect.getHeight();
That way your dragBoundFunc can just test the current position against these pre-calc’ed bounds like this:
dragBoundFunc: function(pos) {
var X=pos.x;
var Y=pos.y;
if(X<minX){X=minX;}
if(X>maxX){X=maxX;}
if(Y<minY){Y=minY;}
if(Y>maxY){Y=maxY;}
return({x:X, y:Y});
}
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/n5xMs/
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 10px;
}
canvas{border:1px solid red;}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.4.1.min.js"></script>
<script>
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 400
});
var layer = new Kinetic.Layer();
var white = new Kinetic.Rect({
x: 20,
y: 20,
width: 300,
height: 300,
fill: 'white',
stroke: 'black',
strokeWidth: 2
});
var orangeGroup = new Kinetic.Group({
x: stage.getWidth() / 2,
y: 70,
draggable: true,
dragBoundFunc: function(pos) {
var X=pos.x;
var Y=pos.y;
if(X<minX){X=minX;}
if(X>maxX){X=maxX;}
if(Y<minY){Y=minY;}
if(Y>maxY){Y=maxY;}
return({x:X, y:Y});
}
});
var orangeText = new Kinetic.Text({
fontSize: 26,
fontFamily: 'Calibri',
text: 'boxed in',
fill: 'black',
padding: 10
});
var orangeRect = new Kinetic.Rect({
width: orangeText.getWidth(),
height: orangeText.getHeight(),
fill: 'orange',
stroke: 'blue',
strokeWidth: 4
});
orangeGroup.add(orangeRect).add(orangeText);
layer.add(white);
layer.add(orangeGroup);
stage.add(layer);
// pre-calc some bounds so dragBoundFunc has less calc's to do
var height=orangeRect.getHeight();
var minX=white.getX();
var maxX=white.getX()+white.getWidth()-orangeRect.getWidth();
var minY=white.getY();
var maxY=white.getY()+white.getHeight()-orangeRect.getHeight();
</script>
</body>
</html>
Related
In my application I use KonvaJS extensively, but I reached a step where I need to create a Bootstrap Popover on KonvaJS Image click, is that possible?
Please note that I have more than 50 images in this app and I need to create a popover for each.
If you want to have PopOver only for canvas images then I would suggest to use Konva.Label. You can set the pointer in whichever direction you want and set the position of label. Here's the plunkr which I have created.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.rawgit.com/konvajs/konva/0.15.0/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Label Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var stage = new Konva.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Konva.Layer();
// label with left pointer
var tooltip = new Konva.Label({
x: 170,
y: 75,
opacity: 0.75
});
tooltip.add(new Konva.Tag({
fill: 'black',
pointerDirection: 'down',
pointerWidth: 10,
pointerHeight: 10,
lineJoin: 'round',
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: 10,
shadowOpacity: 0.5
}));
tooltip.add(new Konva.Text({
text: 'Yoda has powers...',
fontFamily: 'Calibri',
fontSize: 18,
padding: 5,
fill: 'white'
}));
var image = new Image();
image.onload = function() {
var lion = new Konva.Image({
image: image,
x: 70,
y: 75,
draggable: true
});
layer.add(lion);
// add the labels to layer
layer.add(tooltip);
layer.draw();
};
image.src = 'http://konvajs.github.io/assets/yoda.jpg';
// add the layer to the stage
stage.add(layer);
</script>
</body>
</html>
Ok, so I have an animated diagram that animates multiple lines and shapes at the same time. Once the user plays the animation, I want he/she to be able to hit pause and the whole thing stop, then start again when the user hits the play button once more. I shouldn't need a loop to do this as it should do it with each mouse click. Here's a sample of the code.
var tween = new Kinetic.Tween({
node: lineTween,
points: [563.965, 258.163, 604.272, 258.163],
duration: 2
});
var tween3 = new Kinetic.Tween({
node: path3,
points: [582.81, 257.901, 582.81, 214.216],
duration: 2,
onFinish: function(){
tween3a.play();
}
});
document.getElementById('play').addEventListener('click', function(){
tween.play(
setTimeout(function(){
tween3.play();
}, 1000)
);
}, false);
document.getElementById('pause').addEventListener('click', function(){
tween.pause();
}, false);
Anyone have any suggestions?
You will have to store all tweens and turn them off/on:
Demo: http://jsfiddle.net/m1erickson/rF3Mm/
Code:
<!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);
$(stage.getContent()).on('click', function (event) {
var pos = stage.getMousePosition();
var mouseX = parseInt(pos.x);
var mouseY = parseInt(pos.y);
});
var tweens = [];
var circle1 = new Kinetic.Circle({
x: 30,
y: 100,
radius: 20,
fill: 'blue',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
layer.add(circle1);
var circle2 = new Kinetic.Circle({
x: 30,
y: 30,
radius: 15,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
layer.add(circle2);
layer.draw();
var tween1 = new Kinetic.Tween({
node: circle1,
duration: 15,
x: 250,
y: 250,
});
tweens.push(tween1);
var tween2 = new Kinetic.Tween({
node: circle2,
duration: 15,
x: 250,
y: 250,
});
tweens.push(tween2);
tween1.play();
tween2.play();
isPaused = false;
$("#toggle").click(function () {
if (isPaused) {
for (var i = 0; i < tweens.length; i++) {
tweens[i].play();
}
} else {
for (var i = 0; i < tweens.length; i++) {
tweens[i].pause();
}
}
isPaused = !isPaused
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="toggle">Toggle:Pause/Resume</button>
<div id="container"></div>
</body>
</html>
I have JS object with 3 JSON entries, as JavaScript loops through the 3 it creates shapes on the canvas using KineticJS. I'm trying to make it so that when I pass a pixel threshold, in this case 400px, It creates an alert box with the JSON jstext tied to the shape. Here's the code
var tools = [{'title':'method', 'jstext':'function newMethod() {'},
{'title':'var', 'jstext':'var'},
{'title':'end', 'jstext':'}'},
]
var startX = 20;
var startY = 30;
for (var i=0; i<tools.length; i++) {
alert(tools[i].jstext)
var x = new Kinetic.Rect({
x: startX,
y: startY,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 3,
draggable: true,
offset:10,
});
startY = startY + 65;
layer.add(x);
x.on('dragend', function() {
if (x.getAttr('x')>=400) {
console.log(tools[i].jstext)
};
}
It creates the rectangles, it just only logs if the last shape is moved and I want it to pull that text if any shape is moved. Any Ideas? Thanks!
You can:
Create new rectangle inside a function,
Add .originalX and originalY properties so each rect saves its original XY position,
Add a dragend handler that calculates if .getX/.getY are further than 400 px from original XY.
The code would be something like this:
<!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 startX = 20;
var startY = 30;
// create 5 test rects
for (var i=0; i<5; i++) {
newRect(startX,startY,i);
startY = startY + 65;
}
// function to create a new rect
function newRect(x,y,id){
var rect = new Kinetic.Rect({
id:id,
x: startX,
y: startY,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 3,
draggable: true,
offset:10,
});
// have the rect save its original XY
rect.originalX=x;
rect.originalY=y;
// on dragend, calc if the rect has moved >400px
rect.on("dragend",function(){
var dx=this.getX()-this.originalX;
var dy=this.getY()-this.originalY;
var id=this.getId();
if(dx*dx+dy*dy>400*400){
alert(id+" is currently beyond 400px of original XY");
}else{
console.log(id+" is currently inside 400px of original XY");
}
});
layer.add(rect);
layer.draw();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
I have a draggable circle shape that the user drags to another circle shape [static, non-draggable]. When the draggable circle overlaps the static circle, I need to display a "Success" text. How can I do so ?
When the user drags the circle, you can handle the “dragmove” events.
In "dragmove": test whether the circles are colliding. If so, then declare success!
Circle1.on("dragmove",function(){
if(theyAreColliding(Circle1,Circle2)){
// Success!
}
});
The test for collision looks like this:
function theyAreColliding(c1,c2){
var dx=c1.getX()-c2.getX();
var dy=c1.getY()-c2.getY();
var radiiSum=c1.getRadius()+c2.getRadius();
console.log(dx+"/"+dy+": "+radiiSum);
return((dx*dx+dy*dy)<radiiSum*radiiSum);
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/3dQpL/
<!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://www.html5canvastutorials.com/libraries/kinetic-v4.3.3-beta.js"></script>
<style>
canvas{
border:solid 1px #ccc;
}
</style>
<script>
$(function(){
var layer = new Kinetic.Layer();
var stage = new Kinetic.Stage({
container: "container",
width: 400,
height: 400
});
stage.add(layer);
// mouse events don't fire on the empty part of the stage
// so fill the stage with a rect to get events on entire stage
// now stage.on("mouse... will work
var background = new Kinetic.Rect({
x: 0,
y: 0,
width: 400, //stage.getWidth(),
height: 400, //stage.getHeight(),
fill: "#eee"
});
layer.add(background);
var Radius1=50;
var Circle1=new Kinetic.Circle({
x: 225,
y: 125,
radius: Radius1,
fill: 'green',
stroke: 'orange',
strokeWidth: 2,
draggable:true
});
layer.add(Circle1);
var Radius2=50;
var Circle2=new Kinetic.Circle({
x: 75,
y: 175,
radius: Radius2,
fill: 'blue',
stroke: 'black',
strokeWidth: 2
});
layer.add(Circle2);
var message = new Kinetic.Text({
x: 10,
y: 15,
text: "",
fontSize: 30,
fontFamily: 'Calibri',
fill: 'green'
});
layer.add(message);
var instructions = new Kinetic.Text({
x: 10,
y: 285,
text: "Drag green on top of blue",
fontSize: 18,
fontFamily: 'Calibri',
fill: 'green'
});
layer.add(instructions);
layer.draw();
Circle1.on("dragmove",function(){
if(theyAreColliding(Circle1,Circle2)){
message.setText("Collision Detected!");
Circle1.setFill("red");
layer.draw();
}else{
}
});
function theyAreColliding(c1,c2){
var dx=c1.getX()-c2.getX();
var dy=c1.getY()-c2.getY();
var radiiSum=c1.getRadius()+c2.getRadius();
console.log(dx+"/"+dy+": "+radiiSum);
return((dx*dx+dy*dy)<radiiSum*radiiSum);
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
I have little issue here (i obviously miss something). I simplified it from my bigger application:
When i click blue rectangle, i add another layer to the stage that includes red rectangle (clickable), when i click this red rectangle, it removes second layer with red rect.
Problem: When i click blue rect second time, nothing happens :( i.e. app works only once, and i need to add/remove second layer(with red rect) repeatedly. What's wrong? :)
You can see it here, Fiddle http://jsfiddle.net/mAX8r/
Code:
<!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.3.js">
</script>
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layerBlue = new Kinetic.Layer();
var layerRed = new Kinetic.Layer();
var rectBlue = new Kinetic.Rect({
x: 100,
y: 75,
width: 100,
height: 50,
fill: 'blue',
stroke: 'black',
strokeWidth: 4
});
var rectRed = new Kinetic.Rect({
x: 300,
y: 75,
width: 100,
height: 50,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
// mouse events
rectBlue.on('click', function() {
stage.add(layerRed);
stage.draw();
});
rectRed.on('click', function() {
layerRed.remove();
stage.draw();
});
// add the shape to the layer
layerBlue.add(rectBlue);
layerRed.add(rectRed);
// add the layer to the stage
stage.add(layerBlue);
};
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
To hide and show a shape, we can the hide() and show() methods. Try this JSFIDDLE http://jsfiddle.net/mAX8r/5/. and You can see the sample code 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.3.js"></script>
<script>
var layerBlue;
var layerRed;
var rectBlue;
var rectRed;
window.onload = function() {
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
layerBlue = new Kinetic.Layer();
layerRed = new Kinetic.Layer();
rectBlue = new Kinetic.Rect({
x: 100,
y: 75,
width: 100,
height: 50,
fill: 'blue',
stroke: 'black',
strokeWidth: 4
});
rectRed = new Kinetic.Rect({
x: 300,
y: 75,
width: 100,
height: 50,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
// mouse events
rectBlue.on('click', function() {
rectRed.show();
stage.draw();
});
rectRed.on('click', function() {
rectRed.hide();
stage.draw();
});
// add the shape to the layer
layerBlue.add(rectBlue);
layerRed.add(rectRed);
// add the layer to the stage
stage.add(layerBlue);
stage.add(layerRed);
rectRed.hide();
stage.draw();
};
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Refer this url http://www.html5canvastutorials.com/kineticjs/html5-canvas-hide-and-show-shape-with-kineticjs/ for HTML5 Canvas Hide and Show a Shape