Dragging a Konva layer from empty areas - javascript

I'd like to drag a Konva layer even if empty. I see that I can drag the layer only where objects are present (the code shows that you can drag where the rectangle is but nowhere else).
How can I drag the layer dragging empty parts?
Moreover, I see that also the mouseenter and mousleave aren't respected if you are out of the objects of the layer.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<script src="js/modulePattern.js"></script>
<script src="https://unpkg.com/konva#2.4.2/konva.min.js"></script>
<div id="container"></div>
<script>
function demo() {
var stage = new Konva.Stage({
container: 'container',
width: 100,
height: 100
});
var layer = new Konva.Layer({draggable: true});
stage.add(layer);
layer.on("dragmove", function() {
console.log(this.x(), this.y())
});
layer.on("mouseenter", function() {
stage.container().style.cursor = 'pointer';
});
layer.on("mouseleave", function() {
stage.container().style.cursor = 'default';
});
var rect = new Konva.Rect({
width: 50,
height: 50,
fill: 'red',
stroke: 'black',
strokeWidth: 5
});
layer.add(rect);
stage.draw();
}
demo();
</script>
</body>
</html>

Konva does not detect events on empty space of layers. And it is unclear how can it do it if you have several layers on the stage.
If you still need to listen on empty layers and make a layer draggable at any space you can:
Make stage draggable instead and listen events on it (click will work on empty space too).
Add a transparent rectangle as a background, so it will be used to listen to events:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<script src="js/modulePattern.js"></script>
<script src="https://unpkg.com/konva#2.4.2/konva.min.js"></script>
<div id="container"></div>
<script>
function demo() {
var stage = new Konva.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Konva.Layer({draggable: true});
stage.add(layer);
layer.on("mouseenter", function() {
stage.container().style.cursor = 'pointer';
});
layer.on("mouseleave", function() {
stage.container().style.cursor = 'default';
});
var rect = new Konva.Rect({
width: 50,
height: 50,
fill: 'red',
stroke: 'black',
strokeWidth: 5
});
var back = new Konva.Rect({
fill: 'red',
width: stage.width(),
height: stage.height()
})
layer.add(back);
// move rectangle so it always stay on the screen, no matter where layer it
layer.on('dragend', function() {
back.setAbsolutePosition({x: 0, y: 0});
layer.draw();
});
layer.add(rect);
stage.draw();
}
demo();
</script>
</body>
</html>

Related

Is it possible in Konva.js to draw with the left mouse button and drag the stage with the right mouse button?

I'm trying to do an app in which you can draw custom rectangle shape objects and be able to drag your stage at the same time. Is it possible with Konva.js?
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
document.addEventListener('mousedown', (e) => {
switch (e.button) {
case 0:
stage.draggable(false);
break;
case 2:
stage.draggable(true);
break;
}
});
Use Konva.dragButtons like so:
import Konva from 'konva';
Konva.dragButtons = [2];
Where the list represents the buttons that can be used for dragging (0=left,1=middle,2=right)
Ok, so if you wondering how to do it this is a possible solution:
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
document.addEventListener('mousedown', (e) => {
if(e.button === 0) stage.draggable(false);
});
document.addEventListener('mouseup', (e) => {
if(e.button === 0) stage.draggable(true);
});
To achieve your goals you can use this:
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
draggable: true
});
const layer = new Konva.Layer();
stage.add(layer);
const circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 50,
fill: 'green'
});
layer.add(circle);
layer.draw();
stage.on('contextmenu', e => {
e.evt.preventDefault();
})
stage.on('mousedown', (e) => {
const isLeft = e.evt.button === 0;
stage.draggable(!isLeft);
});
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Konva demo">
<script src="https://unpkg.com/konva#^2/konva.min.js"></script>
<meta charset="utf-8">
</head>
<body>
<div id="container"></div>
</body>
</html>

KineticJS - Cannot add dynamic object

I need to create a kind of container to manage dynamic actions with KineticJS.
I have a simple object from which we will be able to add a circle by using a function.
Here's my code:
function Stage() {
var self = this;
self.stage = new Kinetic.Stage({
container: "museumMapContainer",
width: 500,
height: 500
});
self.layer = new Kinetic.Layer();
self.addCircle = function (x,y) {
var circle = new Kinetic.Circle({
x: x,
y: y,
radius: 40,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
});
self.layer.add(circle);
}
self.stage.add(self.layer);
}
stage = new Stage();
stage.addCircle(250,250);
Normally, if I don't put the code inside a function, I can easily create a circle without any problems. However, this code doesn't work and I really don't know why.
Here's a Plunker: http://plnkr.co/edit/E1fbCFMeZwGNAKhsArhm?p=preview
There are no errors in the console and nothing is showing and I don't know why...
Make sure you do layer.draw after creating your new circles:
<!DOCTYPE html>
<html>
<head>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
</head>
<body>
<h1>Hello Plunker!</h1>
<div id="museumMapContainer" style="width:500px;height:500px;border:1px solid black;"></div>
<script defer="defer">
function Stage() {
var self = this;
self.stage = new Kinetic.Stage({
container: "museumMapContainer",
width: 500,
height: 500
});
self.layer = new Kinetic.Layer();
self.stage.add(self.layer);
self.addCircle = function (x,y) {
var circle = new Kinetic.Circle({
x: x,
y: y,
radius: 40,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
});
self.layer.add(circle);
self.layer.draw();
}
}
stage = new Stage();
stage.addCircle(250,250);
</script>
</body>
</html>

How to vertically center text inside a KineticJS Wedge?

I've got the following code:
var text = new Kinetic.Text({
text: carNames,
fontFamily: 'Calibri',
fontSize: 17,
fill: 'black',
align: 'center'
});
text.toImage({
width: text.getWidth(),
height: text.getHeight(),
callback: function (img) {
var cachedText = new Kinetic.Image({
image: img,
x: 180,
y: 0
});
wedge.add(cachedText);
layer.draw();
}
});
Which produces wedges and text that look like this:
But I need the text to be centered inside the wedge, like this:
Does anyone know of a way to achieve this? I've tried several things but I just can't get the text to align as in the second image.
Thanks in advance for your trouble.
One way to do it is using the text's offset in combination with the text's rotationDeg:
Demo: http://jsfiddle.net/m1erickson/mqsY3/
Here's 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);
var cx=175;
var cy=175;
var wedgeRadius=120;
var accumAngle=0;
var center = new Kinetic.Circle({
x:cx,
y:cy,
radius:5,
fill: 'red'
});
layer.add(center);
for(var i=0;i<12;i++){
newTextWedge(30,"Element # "+i);
}
function newTextWedge(angle,text){
var wedge = new Kinetic.Wedge({
x: cx,
y: cy,
radius: wedgeRadius,
angleDeg: angle,
stroke: 'gray',
strokeWidth: 1,
rotationDeg:-accumAngle+angle/2
});
layer.add(wedge);
if(accumAngle>90 && accumAngle<270){
var offset=[wedgeRadius-10,7];
var textAngle=accumAngle-180;
}else{
var offset=[-50,7];
var textAngle=accumAngle;
}
var text = new Kinetic.Text({
x:cx,
y:cy,
text:text,
fill: 'red',
offset:offset,
rotationDeg:textAngle
});
layer.add(text);
layer.draw();
accumAngle+=angle;
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

KineticJS - How draw repeat line like ruler?

I am new to KineticJS, I want to make a repeated line like a ruler. Is there any other way making line without call line1, line2, line3, etc? I try to make that with for, but error happen. Anyone could help?
Ruler I want make :
My error code :
for (int i = 0; i < 10; i++) {
var rects = new Kinetic.Rect({
x: 70,
y: 75,
width: 3,
height: 10,
fill: 'grey'
});
layer.add(rects);
}
JsFiddle
Thanks
You can make your ruler like this:
Start with a group.
Add a Rect with gradient background.
Add a custom Shape with markings.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/UcZ9H/
<!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 ruler=new Kinetic.Group({
x:50,
y:50,
width:265,
height:70,
draggable:true
});
layer.add(ruler);
var rulerBG=new Kinetic.Rect({
x:0,
y:0,
width:265,
height:70,
fillLinearGradientStartPoint: [107, 0],
fillLinearGradientEndPoint: [107, 70],
fillLinearGradientColorStops: [0,'white', .75,"rgba(236,247,252,1)", 1,"rgba(204,234,246,1)"],
stroke:"rgba(204,234,246,1)",
strokeWidth:.5
});
ruler.add(rulerBG);
var rulerMarks = new Kinetic.Shape({
x:0,
y:0,
drawFunc: function(context) {
context.beginPath();
for(var i=0;i<5;i++){
context.moveTo(10+i*50,50);
context.lineTo(10+i*50,30);
context.fillText((i*20),10+i*50-5,20);
for(var j=0;j<5;j++){
context.moveTo(10+i*50+j*10,45);
context.lineTo(10+i*50+j*10,35);
}
}
context.moveTo(5*50,50);
context.lineTo(5*50,30);
context.fillText((5*20),5*50-8,20);
context.fillStrokeShape(this);
},
stroke: 'black',
strokeWidth:2
});
ruler.add(rulerMarks);
layer.draw();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

Dragging and dropping images within multiple boundries in HTML5 canvas

I am new with HTML5.
I have to implement such a functionality that I want images to be dropped within a canvas from outside, then there are visible boundaries within canvas and the images can be moved from one boundary to another. It is the same as in the following link,
http://custom.case-mate.com/diy?bypassLandingPage=true
As, in the site, user selects the pattern and drags images into that. Then he can drag the images between the boundaries. please give some solution for implementing such a functionality.
Here is what I have tried,
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {position:relative;
left:150%;
border: 10px solid #9C9898;
background-color: grey;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.10.0.js"></script>
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: "container",
width: 300,
height: 400,
});
var layer = new Kinetic.Layer();
var redLine = new Kinetic.Line({
points: [150, 0, 150, 400],
stroke: "white",
strokeWidth: 2,
});
var blueLine = new Kinetic.Line({
points: [150, 0, 150, 120, 300, 120],
stroke: "white",
strokeWidth: 2,
});
var thirdLine = new Kinetic.Line({
points: [300, 120, 150, 120, 150, 400],
stroke: "white",
strokeWidth: 2,
});
var imageObj = new Image();
imageObj.onload = function() {
var image = new Kinetic.Image({
x: stage.getWidth() / 2 - 50,
y: stage.getHeight() / 2 - 60,
image: imageObj,
width: 100,
height: 120,
});
image.draggable(true);
layer.add(image);
// add the layer to the stage
stage.add(layer);
};
imageObj.src = "images/212.png";
layer.add(redLine);
layer.add(blueLine);
layer.add(thirdLine);
stage.add(layer);
};
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Here's a nice tutorial on HTML5 native drag'n'drop:
http://www.html5rocks.com/en/tutorials/dnd/basics/
Basically you can declare an item as draggable in HTML5 with the draggable attribute
<div class="draggable" draggable="true">A</div>
<div class="draggable" draggable="true">B</div>
...and then use Javascript to handle some events like:
var items = document.querySelectorAll('.draggable');
[].forEach.call(items, function(item) {
item.addEventListener('dragstart', function(){ /*handle drag start*/ }, false);
item.addEventListener('dragenter', function(){ /*handle drag enter*/ }, false)
item.addEventListener('dragover', function(){ /*handle drag over*/ }, false);
item.addEventListener('dragleave', function(){ /*handle drag leave*/ }, false);
item.addEventListener('drop', function(){ /*handle drop*/ }, false);
item.addEventListener('dragend', function(){ /*handle drag end*/ }, false);
});

Categories